From 053a18ab1640f552e3f3e8bcf23db6d9b8bccc35 Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Thu, 11 Feb 2016 18:43:45 -0800 Subject: [PATCH 01/87] JCLOUDS-664 Azurecompute-arm ResourceGroupApi --- providers/azurecompute-arm/README.md | 109 +++++++++++ providers/azurecompute-arm/pom.xml | 177 ++++++++++++++++++ .../azurecompute.arm/AzureComputeApi.java | 43 +++++ .../AzureComputeProviderMetadata.java | 94 ++++++++++ .../AzureManagementApiMetadata.java | 86 +++++++++ .../config/AzureComputeHttpApiModule.java | 57 ++++++ .../config/AzureComputeParserModule.java | 29 +++ .../config/AzureComputeProperties.java | 34 ++++ .../domain/ResourceGroup.java | 51 +++++ .../azurecompute.arm/features/JobApi.java | 41 ++++ .../features/ResourceGroupApi.java | 96 ++++++++++ .../functions/ParseJobStatus.java | 54 ++++++ .../azurecompute.arm/functions/URIParser.java | 39 ++++ .../handlers/AzureComputeErrorHandler.java | 86 +++++++++ .../AzureComputeProviderMetadataTest.java | 28 +++ .../features/JobApiMockTest.java | 62 ++++++ .../features/ResourceGroupApiLiveTest.java | 137 ++++++++++++++ .../features/ResourceGroupApiMockTest.java | 150 +++++++++++++++ .../functions/URIParserTest.java | 51 +++++ .../AbstractAzureComputeApiLiveTest.java | 69 +++++++ .../internal/AzureLiveTestUtils.java | 34 ++++ .../internal/BaseAzureComputeApiLiveTest.java | 65 +++++++ .../internal/BaseAzureComputeApiMockTest.java | 134 +++++++++++++ .../src/test/resources/resourcegroup.json | 11 ++ .../src/test/resources/resourcegroups.json | 22 +++ .../test/resources/resourcegroupupdated.json | 9 + 26 files changed, 1768 insertions(+) create mode 100644 providers/azurecompute-arm/README.md create mode 100644 providers/azurecompute-arm/pom.xml create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/AzureComputeApi.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/AzureComputeProviderMetadata.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/AzureManagementApiMetadata.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/config/AzureComputeHttpApiModule.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/config/AzureComputeParserModule.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/config/AzureComputeProperties.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/domain/ResourceGroup.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/features/JobApi.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/features/ResourceGroupApi.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/functions/ParseJobStatus.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/functions/URIParser.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/handlers/AzureComputeErrorHandler.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/AzureComputeProviderMetadataTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/features/JobApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/features/ResourceGroupApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/features/ResourceGroupApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/functions/URIParserTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/internal/AbstractAzureComputeApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/internal/AzureLiveTestUtils.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/internal/BaseAzureComputeApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/internal/BaseAzureComputeApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/resources/resourcegroup.json create mode 100644 providers/azurecompute-arm/src/test/resources/resourcegroups.json create mode 100644 providers/azurecompute-arm/src/test/resources/resourcegroupupdated.json diff --git a/providers/azurecompute-arm/README.md b/providers/azurecompute-arm/README.md new file mode 100644 index 0000000000..a3abe63c85 --- /dev/null +++ b/providers/azurecompute-arm/README.md @@ -0,0 +1,109 @@ +jclouds Labs - Azure Compute ARM Provider +============ + +Build status for azurecomputearm module: +[![Build Status](http://devopsfunjenkins.westus.cloudapp.azure.com:8080/buildStatus/icon?job=jclouds-labs-azurecompute-arm/org.apache.jclouds.labs:azurecomputearm)](http://devopsfunjenkins.westus.cloudapp.azure.com:8080/job/jclouds-labs-azurecompute-arm/org.apache.jclouds.labs$azurecomputearm/) + + +## Setting Up Test Credentials + +### Create a Service Principal + +Install and configure Azure CLI following these [steps](http://azure.microsoft.com/en-us/documentation/articles/xplat-cli/). + +Using the Azure CLI, run the following commands to create a service principal + +```bash +# Set mode to ARM +azure config mode arm + +# Enter your Microsoft account credentials when prompted +azure login + +# Set current subscription to create a service principal +azure account set + +# Create an AAD application with your information. +azure ad app create --name --password --home-page --identifier-uris + +# For example: azure ad app create --name "jcloudsarm" --password abcd --home-page "https://jcloudsarm" --identifier-uris "https://jcloudsarm" + +# Output will include a value for `Application Id`, which will be used for the live tests + +# Create a Service Principal +azure ad sp create + +# Output will include a value for `Object Id` + +``` + +Run the following commands to assign roles to the service principal + +```bash +# Assign roles for this service principal +azure role assignment create --objectId -o Contributor -c /subscriptions// + +``` + +Verify service principal + +```bash +azure login -u -p --service-principal --tenant + +``` + +## Run Live Tests + + +Use the following to run the live tests + +```bash +# ResourceGroupApiLiveTest: + +mvn -Dtest=ResourceGroupApiLiveTest -Dtest.azurecompute-arm.identity= -Dtest.azurecompute-arm.subscriptionid= -Dtest.azurecompute-arm.credential= -Dtest.azurecompute-arm.endpoint="https://management.azure.com" -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test + +# AuthorizationApiLiveTest: + +mvn -Dtest=AuthorizationApiLiveTest -Dtest.oauth.identity= -Dtest.oauth.credential= -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" -Dtest.jclouds.oauth.audience="https://management.azure.com/" test + +# LocationApiLiveTest: + +mvn -Dtest=LocationApiLiveTest -Dtest.azurecompute-arm.identity= -Dtest.azurecompute-arm.subscriptionid= -Dtest.azurecompute-arm.credential= -Dtest.azurecompute-arm.endpoint="https://management.azure.com" -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test + +# StorageAccountApiLiveTest: + +mvn -Dtest=StorageAccountApiLiveTest -Dtest.azurecompute-arm.identity= -Dtest.azurecompute-arm.subscriptionid= -Dtest.azurecompute-arm.credential= -Dtest.azurecompute-arm.endpoint="https://management.azure.com" -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test + +# VirtualNetworkApiLiveTest: + +mvn -Dtest=VirtualNetworkApiLiveTest -Dtest.azurecompute-arm.identity= -Dtest.azurecompute-arm.subscriptionid= -Dtest.azurecompute-arm.credential= -Dtest.azurecompute-arm.resourcegroup="jcloudstest" -Dtest.azurecompute-arm.endpoint="https://management.azure.com" -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test + +# SubnetApiLiveTest + +mvn -Dtest=SubnetApiLiveTest -Dtest.azurecompute-arm.identity= -Dtest.azurecompute-arm.subscriptionid= -Dtest.azurecompute-arm.credential= -Dtest.azurecompute-arm.resourcegroup="jcloudstest" -Dtest.azurecompute-arm.endpoint="https://management.azure.com" -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test + +# NetworkInterfaceCardApiLiveTest + +mvn -Dtest=NetworkInterfaceCardApiLiveTest -Dtest.azurecompute-arm.identity= -Dtest.azurecompute-arm.subscriptionid= -Dtest.azurecompute-arm.credential= -Dtest.azurecompute-arm.resourcegroup="jcloudstest" -Dtest.azurecompute-arm.endpoint="https://management.azure.com" -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test + +# VirtualMachineApiLiveTest: + +mvn -Dtest=VirtualMachineApiLiveTest -Dtest.azurecompute-arm.identity= -Dtest.azurecompute-arm.subscriptionid= -Dtest.azurecompute-arm.credential= -Dtest.azurecompute-arm.endpoint="https://management.azure.com" -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test + +# VMSizeApiLiveTest: + +mvn -Dtest=VMSizeApiLiveTest -Dtest.azurecompute-arm.identity= -Dtest.azurecompute-arm.subscriptionid= -Dtest.azurecompute-arm.credential= -Dtest.azurecompute-arm.endpoint="https://management.azure.com" -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test + +# PublicIPAddressApiLiveTest + +mvn -Dtest=PublicIPAddressApiLiveTest -Dtest.azurecompute-arm.identity= -Dtest.azurecompute-arm.subscriptionid= -Dtest.azurecompute-arm.credential= -Dtest.azurecompute-arm.endpoint="https://management.azure.com" -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test + +# OSImageApiLiveTest: + +mvn -Dtest=OSImageApiLiveTest -Dtest.azurecompute-arm.identity= -Dtest.azurecompute-arm.subscriptionid= -Dtest.azurecompute-arm.credential= -Dtest.azurecompute-arm.endpoint="https://management.azure.com" -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test + +# DeploymentApiLiveTest: + +mvn -Dtest=DeploymentApiLiveTest -Dtest.azurecompute-arm.identity= -Dtest.azurecompute-arm.subscriptionid= -Dtest.azurecompute-arm.credential= -Dtest.azurecompute-arm.endpoint="https://management.azure.com/" -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test + +``` \ No newline at end of file diff --git a/providers/azurecompute-arm/pom.xml b/providers/azurecompute-arm/pom.xml new file mode 100644 index 0000000000..807ab2066e --- /dev/null +++ b/providers/azurecompute-arm/pom.xml @@ -0,0 +1,177 @@ + + + + + 4.0.0 + + org.apache.jclouds.labs + jclouds-labs + 2.0.0-SNAPSHOT + + azurecompute-arm + jclouds Azure Compute ARM API + jclouds components to access an implementation of Azure's ARM Compute Service + bundle + + + FIXME_subscription-id + FIXME_tenant-id + https://management.azure.com/subscriptions/${test.jclouds.azurecompute-arm.subscription-id} + 2014-04-01-preview + + app id + app password + org.jclouds.azurecompute-arm*;version="${project.version}" + org.jclouds*;version="${project.version}",* + + + + + org.apache.jclouds + jclouds-compute + ${project.parent.version} + + + com.google.auto.service + auto-service + provided + + + com.google.auto.value + auto-value + provided + + + org.apache.jclouds + jclouds-core + ${project.version} + + + org.apache.jclouds.api + oauth + ${project.version} + jar + + + org.apache.jclouds.api + oauth + ${project.version} + test-jar + test + + + org.apache.jclouds + jclouds-compute + ${project.version} + + + org.apache.jclouds + jclouds-compute + ${project.version} + test-jar + test + + + org.apache.jclouds + jclouds-core + ${project.version} + test-jar + test + + + org.apache.jclouds.driver + jclouds-slf4j + ${project.version} + test + + + org.apache.jclouds.driver + jclouds-sshj + ${project.version} + test + + + org.apache.jclouds.driver + jclouds-slf4j + ${project.parent.version} + test + + + ch.qos.logback + logback-classic + test + + + org.apache.jclouds.driver + jclouds-okhttp + ${project.version} + + + com.squareup.okhttp + mockwebserver + test + + + + org.bouncycastle + bcprov-jdk15on + + + + + + + + live + + + clean verify + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration + integration-test + + test + + + + ${test.azurecompute-arm.endpoint} + ${test.azurecompute-arm.api-version} + ${test.azurecompute-arm.build-version} + ${test.azurecompute-arm.identity} + ${test.azurecompute-arm.credential} + ${test.jclouds.azurecompute-arm.subscription-id} + ${test.jclouds.azurecompute-arm.tenant-id} + + + + + + + + + + + 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 new file mode 100644 index 0000000000..a897c9af10 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/AzureComputeApi.java @@ -0,0 +1,43 @@ +/* + * 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; + +import java.io.Closeable; + +import org.jclouds.azurecompute.arm.features.JobApi; +import org.jclouds.azurecompute.arm.features.ResourceGroupApi; +import org.jclouds.rest.annotations.Delegate; + +/** + * The Azure Resource Manager API is a REST API for managing your services and deployments. + *

+ * + * @see doc + */ +public interface AzureComputeApi extends Closeable { + + /** + * The Azure Resource Manager API includes operations for managing resource groups in your subscription. + * + * @see docs + */ + @Delegate + ResourceGroupApi getResourceGroupApi(); + + @Delegate + JobApi getJobApi(); +} 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 new file mode 100644 index 0000000000..68d7a869fe --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/AzureComputeProviderMetadata.java @@ -0,0 +1,94 @@ +/* + * 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; + +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.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 java.net.URI; +import java.util.Properties; +import org.jclouds.providers.ProviderMetadata; +import org.jclouds.providers.internal.BaseProviderMetadata; + +import com.google.auto.service.AutoService; + +@AutoService(ProviderMetadata.class) +public class AzureComputeProviderMetadata extends BaseProviderMetadata { + + public static Builder builder() { + return new Builder(); + } + + @Override + public Builder toBuilder() { + return builder().fromProviderMetadata(this); + } + + public AzureComputeProviderMetadata() { + super(builder()); + } + + public static Properties defaultProperties() { + final Properties properties = AzureManagementApiMetadata.defaultProperties(); + properties.setProperty(OPERATION_TIMEOUT, "60000"); + 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("oauth.endpoint", "https://login.microsoftonline.com/oauth2/token"); + properties.put(RESOURCE, "https://management.azure.com"); + properties.put(CREDENTIAL_TYPE, CLIENT_CREDENTIALS_SECRET.toString()); + return properties; + } + + public AzureComputeProviderMetadata(final Builder builder) { + super(builder); + } + + public static class Builder extends BaseProviderMetadata.Builder { + + protected Builder() { + super(); + + id("azurecompute-arm") + .name("Azure Resource Management ") + .apiMetadata(new AzureManagementApiMetadata()) + .endpoint("https://management.azure.com/subscriptions/SUBSCRIPTION_ID") + .homepage(URI.create("https://www.windowsazure.com/")) + .console(URI.create("https://windows.azure.com/default.aspx")) + .linkedServices("azureblob") + .defaultProperties(AzureComputeProviderMetadata.defaultProperties()); + } + + @Override + public AzureComputeProviderMetadata build() { + return new AzureComputeProviderMetadata(this); + } + + @Override + public Builder fromProviderMetadata(final ProviderMetadata providerMetadata) { + super.fromProviderMetadata(providerMetadata); + return this; + } + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/AzureManagementApiMetadata.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/AzureManagementApiMetadata.java new file mode 100644 index 0000000000..9a3292c57b --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/AzureManagementApiMetadata.java @@ -0,0 +1,86 @@ +/* + * 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; + +import static org.jclouds.reflect.Reflection2.typeToken; + +import java.net.URI; +import java.util.Properties; + +import org.jclouds.apis.ApiMetadata; +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 com.google.common.collect.ImmutableSet; +import com.google.inject.Module; +import org.jclouds.http.okhttp.config.OkHttpCommandExecutorServiceModule; + +/** + * Implementation of {@link ApiMetadata} for Microsoft Azure Resource Manager REST API + */ +public class AzureManagementApiMetadata extends BaseHttpApiMetadata { + + @Override + public Builder toBuilder() { + return new Builder().fromApiMetadata(this); + } + + public AzureManagementApiMetadata() { + this(new Builder()); + } + + protected AzureManagementApiMetadata(final Builder builder) { + super(builder); + } + + public static Properties defaultProperties() { + final Properties properties = BaseHttpApiMetadata.defaultProperties(); + return properties; + } + + public static class Builder extends BaseHttpApiMetadata.Builder { + + protected Builder() { + super(); + + id("azurecompute-arm") + .name("Microsoft Azure Resource Manager REST API") + .identityName("Azure Service Principal Application Id") + .credentialName("Azure Service Principal Application Password") + .endpointName("Resource Manager Endpoint ending in your Subscription Id") + .documentation(URI.create("https://msdn.microsoft.com/en-us/library/azure/dn790568.aspx")) + .defaultProperties(AzureManagementApiMetadata.defaultProperties()) + .view(typeToken(ComputeServiceContext.class)) + .defaultModules(ImmutableSet.>builder() + .add(OAuthModule.class) + .add(OkHttpCommandExecutorServiceModule.class) + .add(AzureComputeHttpApiModule.class).build()); + } + + @Override + public AzureManagementApiMetadata build() { + return new AzureManagementApiMetadata(this); + } + + @Override + protected Builder self() { + return this; + } + } +} 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 new file mode 100644 index 0000000000..9041d960aa --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/config/AzureComputeHttpApiModule.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.config; +import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.handlers.AzureComputeErrorHandler; +import org.jclouds.http.HttpErrorHandler; +import org.jclouds.http.annotation.ClientError; +import org.jclouds.http.annotation.Redirection; +import org.jclouds.http.annotation.ServerError; +import org.jclouds.location.suppliers.ImplicitLocationSupplier; +import org.jclouds.location.suppliers.implicit.OnlyLocationOrFirstRegionOptionallyMatchingRegionId; + +import org.jclouds.rest.ConfiguresHttpApi; +import org.jclouds.rest.config.HttpApiModule; +import org.jclouds.oauth.v2.config.OAuthScopes; + +import com.google.inject.Scopes; + +@ConfiguresHttpApi +public class AzureComputeHttpApiModule extends HttpApiModule { + + @Override + protected void bindErrorHandlers() { + bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(AzureComputeErrorHandler.class); + bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(AzureComputeErrorHandler.class); + bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(AzureComputeErrorHandler.class); + } + + @Override + protected void installLocations() { + super.installLocations(); + bind(ImplicitLocationSupplier.class). + to(OnlyLocationOrFirstRegionOptionallyMatchingRegionId.class). + in(Scopes.SINGLETON); + } + + @Override + protected void configure() { + install(new AzureComputeParserModule()); + super.configure(); + bind(OAuthScopes.class).toInstance(OAuthScopes.ReadOrWriteScopes.create("read", "read write")); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/config/AzureComputeParserModule.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/config/AzureComputeParserModule.java new file mode 100644 index 0000000000..396f5be6ed --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/config/AzureComputeParserModule.java @@ -0,0 +1,29 @@ +/* + * 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.config; + +import org.jclouds.json.config.GsonModule; + +import com.google.inject.AbstractModule; + +public class AzureComputeParserModule extends AbstractModule { + + @Override + protected void configure() { + bind(GsonModule.DateAdapter.class).to(GsonModule.Iso8601DateAdapter.class); + } +} 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 new file mode 100644 index 0000000000..e16b5da44e --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/config/AzureComputeProperties.java @@ -0,0 +1,34 @@ +/* + * 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.config; + +/** + * Configuration properties and constants used in Azure Resource Manager connections. + */ +public class AzureComputeProperties { + + 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"; + + public static final String OPERATION_POLL_MAX_PERIOD = "jclouds.azurecompute.arm.operation.poll.max.period"; + + public static final String TCP_RULE_FORMAT = "jclouds.azurecompute.arm.tcp.rule.format"; + + public static final String TCP_RULE_REGEXP = "jclouds.azurecompute.arm.tcp.rule.regexp"; + +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/domain/ResourceGroup.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/domain/ResourceGroup.java new file mode 100644 index 0000000000..1be93abd43 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/domain/ResourceGroup.java @@ -0,0 +1,51 @@ +/* + * 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 java.util.Map; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; +import com.google.common.collect.ImmutableMap; + + +@AutoValue +public abstract class ResourceGroup { + + @AutoValue + public abstract static class ResourceGroupProperties{ + @Nullable + public abstract String provisioningState(); + + @SerializedNames({"provisioningState"}) + public static ResourceGroupProperties create(final String provisioningState) { + return new AutoValue_ResourceGroup_ResourceGroupProperties(provisioningState); + } + } + + public abstract String id(); + public abstract String name(); + public abstract String location(); + @Nullable + public abstract Map tags(); + public abstract ResourceGroupProperties properties(); + + @SerializedNames({"id", "name", "location", "tags", "properties"}) + public static ResourceGroup create(String id, String name, String location, @Nullable Map tags, ResourceGroupProperties properties) { + return new AutoValue_ResourceGroup(id, name, location, tags == null ? ImmutableMap.builder().build() : ImmutableMap.copyOf(tags), properties); + } +} 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 new file mode 100644 index 0000000000..7dd75a9620 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/features/JobApi.java @@ -0,0 +1,41 @@ +/* + * 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.io.Closeable; +import java.net.URI; +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.GET; +import org.jclouds.oauth.v2.filters.OAuthFilter; +import org.jclouds.rest.annotations.EndpointParam; +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; + +/** + * The Azure Resource Manager API checks for job status and progress. + */ + +@RequestFilters(OAuthFilter.class) +@Consumes(MediaType.APPLICATION_JSON) +public interface JobApi extends Closeable{ + @GET + @ResponseParser(ParseJobStatus.class) + JobStatus jobStatus(@EndpointParam URI jobURI); +} + 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 new file mode 100644 index 0000000000..1ad47d941c --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/features/ResourceGroupApi.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.features; +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 org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.azurecompute.arm.domain.ResourceGroup; +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.ResponseParser; +import org.jclouds.azurecompute.arm.functions.URIParser; + + +import org.jclouds.rest.binders.BindToJsonPayload; + +/** + * The Azure Resource Manager API includes operations for managing resource groups in your subscription. + * + * @see docs + */ +@Path("/resourcegroups") + +@QueryParams(keys = "api-version", values = "2015-01-01") +@RequestFilters(OAuthFilter.class) +@Consumes(MediaType.APPLICATION_JSON) +public interface ResourceGroupApi extends Closeable{ + + @Named("resourcegroup:list") + @SelectJson("value") + @GET + @Fallback(EmptyListOnNotFoundOr404.class) + List list(); + + @Named("resourcegroup:create") + @PUT + @Path("/{name}") + @Produces(MediaType.APPLICATION_JSON) + @MapBinder(BindToJsonPayload.class) + ResourceGroup create(@PathParam("name") String name, @PayloadParam("location") String location, @Nullable @PayloadParam("tags")Map tags); + + @Named("resourcegroup:get") + @GET + @Path("/{name}") + @Fallback(NullOnNotFoundOr404.class) + @Nullable + ResourceGroup get(@PathParam("name") String name); + + @Named("resourcegroup:update") + @PATCH + @Produces(MediaType.APPLICATION_JSON) + @Path("/{name}") + @MapBinder(BindToJsonPayload.class) + ResourceGroup update(@PathParam("name") String name, @Nullable @PayloadParam("tags")Map tags); + + @Named("resourcegroup:delete") + @DELETE + @ResponseParser(URIParser.class) + @Path("/{name}") + @Fallback(NullOnNotFoundOr404.class) + URI delete(@PathParam("name") String name); +} + diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/functions/ParseJobStatus.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/functions/ParseJobStatus.java new file mode 100644 index 0000000000..f39db90646 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/functions/ParseJobStatus.java @@ -0,0 +1,54 @@ +/* + * 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 com.google.common.base.Function; +import org.jclouds.http.HttpResponse; + +import javax.inject.Singleton; +/** + * Parses job status from http response + */ +@Singleton +public class ParseJobStatus implements Function { + public enum JobStatus { + + DONE, + IN_PROGRESS, + FAILED, + UNRECOGNIZED; + + public static JobStatus fromString(final String text) { + if (text != null) { + for (JobStatus status : JobStatus.values()) { + if (text.equalsIgnoreCase(status.name())) { + return status; + } + } + } + return UNRECOGNIZED; + } + } + public JobStatus apply(final HttpResponse from) { + if (from.getStatusCode() == 202 ){ + return JobStatus.IN_PROGRESS; + } else if (from.getStatusCode() == 200 ){ + return JobStatus.DONE; + } else { + return JobStatus.FAILED; + } + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/functions/URIParser.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/functions/URIParser.java new file mode 100644 index 0000000000..78fd10dadb --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/functions/URIParser.java @@ -0,0 +1,39 @@ +/* + * 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 com.google.common.base.Function; +import org.jclouds.http.HttpResponse; + +import javax.inject.Singleton; + +import java.net.URI; +/** + * Parses job status from http response + */ +@Singleton +public class URIParser implements Function { + public URI apply(final HttpResponse from) { + if (from.getStatusCode() == 202 && from.getHeaders().containsKey("Location")){ + String uri = from.getFirstHeaderOrNull("Location"); + return URI.create(uri); + + } else if (from.getStatusCode() == 200){ + return null; + } + throw new IllegalStateException("did not receive expected response code and header in: " + from); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/handlers/AzureComputeErrorHandler.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/handlers/AzureComputeErrorHandler.java new file mode 100644 index 0000000000..d5a2d6917a --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/handlers/AzureComputeErrorHandler.java @@ -0,0 +1,86 @@ +/* + * 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.handlers; + +import java.io.IOException; + +import javax.inject.Singleton; + +import org.jclouds.http.HttpCommand; +import org.jclouds.http.HttpErrorHandler; +import org.jclouds.http.HttpResponse; +import org.jclouds.http.HttpResponseException; +import org.jclouds.rest.AuthorizationException; +import org.jclouds.rest.ResourceNotFoundException; +import org.jclouds.util.Closeables2; +import org.jclouds.util.Strings2; + +/** + * This will parse and set an appropriate exception on the command object. + */ +@Singleton +public class AzureComputeErrorHandler implements HttpErrorHandler { + + @Override + public void handleError(final HttpCommand command, final HttpResponse response) { + // it is important to always read fully and close streams + String message = parseMessage(response); + Exception exception = message == null + ? new HttpResponseException(command, response) + : new HttpResponseException(command, response, message); + try { + message = message == null + ? String.format("%s -> %s", command.getCurrentRequest().getRequestLine(), response.getStatusLine()) + : message; + switch (response.getStatusCode()) { + case 400: + exception = new IllegalArgumentException(message, exception); + break; + case 401: + case 403: + exception = new AuthorizationException(message, exception); + break; + + case 404: + if (!command.getCurrentRequest().getMethod().equals("DELETE")) { + exception = new ResourceNotFoundException(message, exception); + } + break; + + case 409: + exception = new IllegalStateException(message, exception); + break; + + default: + } + } finally { + Closeables2.closeQuietly(response.getPayload()); + command.setException(exception); + } + } + + public String parseMessage(final HttpResponse response) { + if (response.getPayload() == null) { + return null; + } + try { + return Strings2.toStringAndClose(response.getPayload().openStream()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/AzureComputeProviderMetadataTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/AzureComputeProviderMetadataTest.java new file mode 100644 index 0000000000..2003f9a63a --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/AzureComputeProviderMetadataTest.java @@ -0,0 +1,28 @@ +/* + * 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; + +import org.jclouds.providers.internal.BaseProviderMetadataTest; +import org.testng.annotations.Test; + +@Test(groups = "unit", testName = "AzureManagementProviderMetadataTest") +public class AzureComputeProviderMetadataTest extends BaseProviderMetadataTest { + + public AzureComputeProviderMetadataTest() { + super(new AzureComputeProviderMetadata(), new AzureManagementApiMetadata()); + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/features/JobApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/features/JobApiMockTest.java new file mode 100644 index 0000000000..ba87ca59fd --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/features/JobApiMockTest.java @@ -0,0 +1,62 @@ +/* + * 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.io.IOException; +import java.net.URI; +import org.jclouds.azurecompute.arm.functions.ParseJobStatus.JobStatus; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; + +@Test(groups = "unit", testName = "JobApiMockTest", singleThreaded = true) +public class JobApiMockTest extends BaseAzureComputeApiMockTest { + + final String requestUrl = "/operationresults/eyJqb2JJZCI6IlJFU09VUkNFR1JPVVBERUxFVElPTkpPQi1SVEVTVC1DRU5UUkFMVVMiLCJqb2JMb2NhdGlvbiI6ImNlbnRyYWx1cyJ9?api-version=2014-04-01"; + + public void testGetJobStatus() throws IOException, InterruptedException { + server.enqueue(response200()); + + JobStatus status = api.getJobApi().jobStatus(URI.create(requestUrl)); + + assertEquals(status, JobStatus.DONE); + + assertSent(server, "GET", requestUrl); + } + + public void testGetJobStatusInProgress() throws InterruptedException { + server.enqueue(response202WithHeader()); + + JobStatus status = api.getJobApi().jobStatus(URI.create(requestUrl)); + + assertEquals(status, JobStatus.IN_PROGRESS); + + assertSent(server, "GET", requestUrl); + } + + public void testGetJobStatusFailed() throws InterruptedException { + server.enqueue(jsonResponse("/resourcegroup.json").setStatus("HTTP/1.1 204 No Content")); + + JobStatus status = api.getJobApi().jobStatus(URI.create(requestUrl)); + + assertEquals(status, JobStatus.FAILED); + + assertSent(server, "GET", requestUrl); + } + +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/features/ResourceGroupApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/features/ResourceGroupApiLiveTest.java new file mode 100644 index 0000000000..1ad8bf3986 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/features/ResourceGroupApiLiveTest.java @@ -0,0 +1,137 @@ +/* + * 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 com.google.common.base.Predicate; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; + +import java.net.URI; +import java.util.List; + +import org.jclouds.azurecompute.arm.domain.ResourceGroup; +import org.jclouds.azurecompute.arm.functions.ParseJobStatus.JobStatus; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; + +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertEquals; +import org.jclouds.util.Predicates2; + + +@Test(groups = "live", testName = "ResourceGroupApiLiveTest") +public class ResourceGroupApiLiveTest extends BaseAzureComputeApiLiveTest { + private String resourcegroup; + + @BeforeClass + @Override + public void setup(){ + super.setup(); + resourcegroup = getResourceGroupName(); + } + + private ResourceGroupApi api() { + return api.getResourceGroupApi(); + } + + @Test(dependsOnMethods = "testCreate") + public void testList() { + final List resourceGroups = api().list(); + + assertTrue(resourceGroups.size() > 0); + + assertTrue(Iterables.any(resourceGroups, new Predicate() { + + @Override + public boolean apply(final ResourceGroup group) { + return resourcegroup.equals(group.name()); + } + })); + } + + @Test(dependsOnMethods = "testCreate") + public void testRead() { + final ResourceGroup group = api().get(resourcegroup); + assertNotNull(group); + assertEquals(group.name(), resourcegroup); + assertEquals(group.location(), LOCATION); + } + + public void testCreate() { + + final ResourceGroup resourceGroup = api().create("jcloudstest", LOCATION, null); + assertEquals(resourceGroup.name(), "jcloudstest"); + assertEquals(resourceGroup.location(), LOCATION); + assertEquals(resourceGroup.tags().size(), 0); + assertTrue(resourceGroup.id().contains("jcloudstest")); + assertEquals(resourceGroup.properties().provisioningState(), "Succeeded"); + } + + @Test(dependsOnMethods = "testCreate") + public void testUpdateWithEmptyTag() { + ImmutableMap tags = ImmutableMap.builder().build(); + + final ResourceGroup resourceGroup = api().update("jcloudstest", tags); + + assertEquals(resourceGroup.tags().size(), 0); + assertEquals(resourceGroup.properties().provisioningState(), "Succeeded"); + } + + @Test(dependsOnMethods = "testCreate") + public void testUpdateWithTag() { + ImmutableMap tags = ImmutableMap.builder().put("test1", "value1").build(); + + final ResourceGroup resourceGroup = api().update("jcloudstest", tags); + + assertEquals(resourceGroup.tags().size(), 1); + assertEquals(resourceGroup.properties().provisioningState(), "Succeeded"); + } + + @AfterClass(alwaysRun = true) + public void testDelete() throws Exception { + URI uri = api().delete(resourcegroup); + + if (uri != null){ + assertTrue(uri.toString().contains("api-version")); + assertTrue(uri.toString().contains("operationresults")); + + boolean jobDone = Predicates2.retry(new Predicate() { + @Override public boolean apply(URI uri) { + return JobStatus.DONE == api.getJobApi().jobStatus(uri); + } + }, 60 * 1 * 1000 /* 1 minute timeout */).apply(uri); + assertTrue(jobDone, "delete operation did not complete in the configured timeout"); + } + + uri = api().delete("jcloudstest"); + if (uri != null){ + assertTrue(uri.toString().contains("api-version")); + assertTrue(uri.toString().contains("operationresults")); + + boolean jobDone = Predicates2.retry(new Predicate() { + @Override public boolean apply(URI uri) { + return JobStatus.DONE == api.getJobApi().jobStatus(uri); + } + }, 60 * 1 * 1000 /* 1 minute timeout */).apply(uri); + assertTrue(jobDone, "delete operation did not complete in the configured timeout"); + } + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/features/ResourceGroupApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/features/ResourceGroupApiMockTest.java new file mode 100644 index 0000000000..91cb2b1f3d --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/features/ResourceGroupApiMockTest.java @@ -0,0 +1,150 @@ +/* + * 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 static com.google.common.collect.Iterables.isEmpty; +import static com.google.common.collect.Iterables.size; +import static org.testng.Assert.assertNotNull; + +import java.net.URI; +import java.util.List; +import com.google.common.collect.ImmutableMap; + +import org.jclouds.azurecompute.arm.domain.ResourceGroup; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; +import org.testng.annotations.Test; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertEquals; + +@Test(groups = "unit", testName = "ResourceGroupApiMockTest", singleThreaded = true) +public class ResourceGroupApiMockTest extends BaseAzureComputeApiMockTest { + + final String subscriptionid = "12345678-1234-1234-1234-123456789012"; + final String requestUrl = "/subscriptions/" + subscriptionid + "/resourcegroups"; + final String version = "?api-version=2015-01-01"; + + public void testListResourceGroups() throws InterruptedException { + server.enqueue(jsonResponse("/resourcegroups.json")); + + List resourceGroups = api.getResourceGroupApi().list(); + + assertEquals(size(resourceGroups), 2); + + assertSent(server, "GET", requestUrl + version); + } + + public void testListResourceGroupsReturns404() throws InterruptedException { + server.enqueue(response404()); + + List resourceGroups = api.getResourceGroupApi().list(); + + assertTrue(isEmpty(resourceGroups)); + + assertEquals(server.getRequestCount(), 1); + assertSent(server, "GET", requestUrl + version); + } + + public void testCreateResourceGroup() throws InterruptedException { + server.enqueue(jsonResponse("/resourcegroup.json").setStatus("HTTP/1.1 201 Created")); + + ImmutableMap tags = ImmutableMap.builder().put("tagname1", "tagvalue1").build(); + + ResourceGroup resourceGroup = api.getResourceGroupApi().create("jcloudstest", "West US", tags); + + assertEquals(resourceGroup.name(), "jcloudstest"); + assertEquals(resourceGroup.location(), "westus"); + assertEquals(resourceGroup.tags().size(), 1); + assertTrue(resourceGroup.id().contains("jcloudstest")); + + assertEquals(server.getRequestCount(), 1); + assertSent(server, "PUT", requestUrl + "/jcloudstest" + version, String.format("{\"location\":\"%s\", \"tags\":{\"tagname1\":\"tagvalue1\"}}", "West US")); + } + + public void testCreateResourceGroupWithNoTag() throws InterruptedException { + server.enqueue(jsonResponse("/resourcegroup.json").setStatus("HTTP/1.1 201 Created")); + + ResourceGroup resourceGroup = api.getResourceGroupApi().create("jcloudstest", "West US", null); + + assertEquals(resourceGroup.name(), "jcloudstest"); + assertEquals(resourceGroup.location(), "westus"); + assertTrue(resourceGroup.id().contains("jcloudstest")); + + assertEquals(server.getRequestCount(), 1); + assertSent(server, "PUT", requestUrl + "/jcloudstest" + version, String.format("{\"location\":\"%s\"}", "West US")); + } + + public void testGetResourceGroup() throws InterruptedException { + server.enqueue(jsonResponse("/resourcegroup.json")); + + ResourceGroup resourceGroup = api.getResourceGroupApi().get("jcloudstest"); + + assertEquals(resourceGroup.name(), "jcloudstest"); + + assertEquals(server.getRequestCount(), 1); + assertSent(server, "GET", requestUrl + "/jcloudstest" + version); + } + + public void testGetResourceGroupReturns404() throws InterruptedException { + server.enqueue(response404()); + + ResourceGroup resourceGroup = api.getResourceGroupApi().get("jcloudstest"); + + assertNull(resourceGroup); + + assertEquals(server.getRequestCount(), 1); + assertSent(server, "GET", requestUrl + "/jcloudstest" + version); + } + + public void testUpdateResourceGroupTags() throws InterruptedException { + server.enqueue(jsonResponse("/resourcegroupupdated.json")); + + ImmutableMap tags = ImmutableMap.builder().build(); + + ResourceGroup resourceGroup = api.getResourceGroupApi().update("jcloudstest", tags); + + + assertEquals(resourceGroup.tags().size(), 0); + assertEquals(resourceGroup.properties().provisioningState(), "Succeeded"); + + assertEquals(server.getRequestCount(), 1); + assertSent(server, "PATCH", requestUrl + "/jcloudstest" + version, "{\"tags\":{}}"); + } + + public void testDeleteResourceGroup() throws InterruptedException { + server.enqueue(response202WithHeader()); + + URI uri = api.getResourceGroupApi().delete("jcloudstest"); + + assertEquals(server.getRequestCount(), 1); + assertSent(server, "DELETE", requestUrl + "/jcloudstest" + version); + assertNotNull(uri); + + assertTrue(uri.toString().contains("api-version")); + assertTrue(uri.toString().contains("operationresults")); + } + + public void testDeleteResourceGroupReturns404() throws InterruptedException { + server.enqueue(response404()); + + URI uri = api.getResourceGroupApi().delete("jcloudstest"); + assertNull(uri); + assertEquals(server.getRequestCount(), 1); + assertSent(server, "DELETE", requestUrl + "/jcloudstest" + version); + } + +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/functions/URIParserTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/functions/URIParserTest.java new file mode 100644 index 0000000000..f7b234d3aa --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/functions/URIParserTest.java @@ -0,0 +1,51 @@ +/* + * 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.testng.Assert.assertNull; +import static org.testng.Assert.assertNotNull; + +import java.net.URI; + +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; +import com.google.common.collect.Multimap; +import com.google.common.collect.LinkedHashMultimap; + +@Test(groups = "unit", testName = "URIParserTest") +public class URIParserTest { + + public void testApply() { + URIParser parser = new URIParser(); + Multimap headers = LinkedHashMultimap. create(); + + URI uri = parser.apply(HttpResponse.builder().statusCode(200).build()); + assertNull(uri); + + try { + uri = parser.apply(HttpResponse.builder().statusCode(202).build()); + } catch (IllegalStateException ex){ + assertNotNull(ex); + } + + headers.put("Location", "https://someuri"); + + uri = parser.apply(HttpResponse.builder().statusCode(202).headers(headers).build()); + assertNotNull(uri); + + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/internal/AbstractAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/internal/AbstractAzureComputeApiLiveTest.java new file mode 100644 index 0000000000..aa0663ab15 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/internal/AbstractAzureComputeApiLiveTest.java @@ -0,0 +1,69 @@ +/* + * 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.internal; + +import static com.google.common.base.Preconditions.checkNotNull; +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 java.util.Properties; +import java.util.Random; + +import org.jclouds.apis.BaseApiLiveTest; +import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; +import org.jclouds.compute.config.ComputeServiceProperties; +import org.jclouds.providers.ProviderMetadata; + +public abstract class AbstractAzureComputeApiLiveTest extends BaseApiLiveTest { + + protected static final int RAND = new Random().nextInt(999); + + public AbstractAzureComputeApiLiveTest() { + provider = "azurecompute-arm"; + } + + @Override protected Properties setupProperties() { + Properties properties = super.setupProperties(); + properties.put(ComputeServiceProperties.POLL_INITIAL_PERIOD, 1000); + properties.put(ComputeServiceProperties.POLL_MAX_PERIOD, 10000); + properties.setProperty(OPERATION_TIMEOUT, "60000"); + 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}"); + + // for oauth + AzureLiveTestUtils.defaultProperties(properties); + checkNotNull(setIfTestSystemPropertyPresent(properties, "jclouds.oauth.resource"), "test.jclouds.oauth.resource"); + checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); + return properties; + } + + @Override + protected ProviderMetadata createProviderMetadata() { + AzureComputeProviderMetadata pm = AzureComputeProviderMetadata.builder().build(); + String endpoint = null; + if (System.getProperty("test.azurecompute-arm.endpoint") != null){ + endpoint = System.getProperty("test.azurecompute-arm.endpoint"); + pm.toBuilder().endpoint(endpoint); + } + return pm; + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/internal/AzureLiveTestUtils.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/internal/AzureLiveTestUtils.java new file mode 100644 index 0000000000..c578e84a44 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/internal/AzureLiveTestUtils.java @@ -0,0 +1,34 @@ +/* + * 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.internal; + +import java.util.Properties; +import static org.jclouds.oauth.v2.config.OAuthProperties.CREDENTIAL_TYPE; +import static org.jclouds.oauth.v2.config.CredentialType.CLIENT_CREDENTIALS_SECRET; + +public class AzureLiveTestUtils { + + public static Properties defaultProperties(Properties properties) { + properties = properties == null ? new Properties() : properties; + properties.put("oauth.identity", "foo"); + properties.put("oauth.credential", "password"); + properties.put("oauth.endpoint", "https://login.microsoftonline.com/oauth2/token"); + properties.put(CREDENTIAL_TYPE, CLIENT_CREDENTIALS_SECRET.toString()); + return properties; + } +} + diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/internal/BaseAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/internal/BaseAzureComputeApiLiveTest.java new file mode 100644 index 0000000000..fb2e42a3a3 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/internal/BaseAzureComputeApiLiveTest.java @@ -0,0 +1,65 @@ +/* + * 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.internal; +import static org.testng.Assert.assertNotNull; + +import com.google.common.collect.ImmutableMap; +import org.jclouds.azurecompute.arm.domain.ResourceGroup; + +import org.testng.annotations.AfterClass; + +public class BaseAzureComputeApiLiveTest extends AbstractAzureComputeApiLiveTest { + public static final String LOCATION = "westeurope"; + private String resourceGroupName = null; + + protected String getEndpoint() { + String endpoint = null; + if (System.getProperty("test.azurecompute-arm.endpoint") != null) { + endpoint = System.getProperty("test.azurecompute-arm.endpoint"); + } + assertNotNull(endpoint); + return endpoint; + } + + protected String getResourceGroupName() { + if (resourceGroupName == null) { + resourceGroupName = String.format("%3.24s", + System.getProperty("user.name") + RAND + "groupjclouds"); + createResourceGroup(resourceGroupName); + } + return resourceGroupName; + } + + private void createResourceGroup(String name) { + ImmutableMap tags = ImmutableMap.builder().build(); + + final ResourceGroup resourceGroup = api.getResourceGroupApi().create( + name, LOCATION, tags); + } + + private void deleteResourceGroup(String name) { + api.getResourceGroupApi().delete(name); + } + + + @AfterClass(alwaysRun = true) + @Override + protected void tearDown() { + super.tearDown(); + deleteResourceGroup(getResourceGroupName()); + } +} 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 new file mode 100644 index 0000000000..fdbdf7036e --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/internal/BaseAzureComputeApiMockTest.java @@ -0,0 +1,134 @@ +/* + * 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.internal; +import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor; +import static org.testng.Assert.assertEquals; +import static org.jclouds.oauth.v2.config.CredentialType.BEARER_TOKEN_CREDENTIALS; +import static org.jclouds.oauth.v2.config.OAuthProperties.CREDENTIAL_TYPE; + +import java.io.IOException; +import java.util.Properties; +import java.util.Set; + +import org.jclouds.ContextBuilder; +import org.jclouds.concurrent.config.ExecutorServiceModule; +import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; +import org.jclouds.json.Json; +import org.jclouds.rest.ApiContext; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; + +import com.google.common.base.Charsets; +import com.google.common.base.Throwables; +import com.google.common.collect.ImmutableSet; +import com.google.common.io.Resources; +import com.google.gson.JsonParser; +import com.google.inject.Module; +import com.squareup.okhttp.mockwebserver.MockResponse; +import com.squareup.okhttp.mockwebserver.MockWebServer; +import com.squareup.okhttp.mockwebserver.RecordedRequest; + +public class BaseAzureComputeApiMockTest { + + private static final String MOCK_BEARER_TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1uQ19WWmNBVGZNNXBPWWlKSE1iYTlnb0VLWSIsImtpZCI6Ik1uQ19WWmNBVGZNNXBPWWlKSE1iYTlnb0VLWSJ9"; + private static final String DEFAULT_ENDPOINT = new AzureComputeProviderMetadata().getEndpoint(); + + private final Set modules = ImmutableSet. of(new ExecutorServiceModule(sameThreadExecutor())); + + protected MockWebServer server; + protected AzureComputeApi api; + private Json json; + + // So that we can ignore formatting. + private final JsonParser parser = new JsonParser(); + + @BeforeMethod + public void start() throws IOException { + server = new MockWebServer(); + server.play(); + Properties properties = new Properties(); + properties.put(CREDENTIAL_TYPE, BEARER_TOKEN_CREDENTIALS.toString()); + AzureComputeProviderMetadata pm = AzureComputeProviderMetadata.builder().build(); + ApiContext ctx = ContextBuilder.newBuilder(pm) + .credentials("", MOCK_BEARER_TOKEN) + .endpoint(server.getUrl("/").toString() + "subscriptions/12345678-1234-1234-1234-123456789012") + .modules(modules) + .overrides(properties) + .build(); + json = ctx.utils().injector().getInstance(Json.class); + api = ctx.getApi(); + } + + @AfterMethod(alwaysRun = true) + public void stop() throws IOException { + server.shutdown(); + api.close(); + } + + protected String url(String path) { + return server.getUrl(path).toString(); + } + + protected MockResponse jsonResponse(String resource) { + return new MockResponse().addHeader("Content-Type", "application/json").setBody(stringFromResource(resource)); + } + + protected MockResponse response404() { + return new MockResponse().setStatus("HTTP/1.1 404 Not Found"); + } + + protected MockResponse response200() { + return new MockResponse().setStatus("HTTP/1.1 200 OK"); + } + + protected MockResponse response202() { + return new MockResponse().setStatus("HTTP/1.1 202 Accepted"); + } + + protected MockResponse response202WithHeader() { + return new MockResponse() + .setStatus("HTTP/1.1 202 Accepted") + .addHeader("Location", "https://management.azure.com/subscriptions/12345678-1234-1234-1234-123456789012/operationresults/eyJqb2JJZCI6IlJFU09VUkNFR1JPVVBERUxFVElPTkpPQi1SVEVTVC1DRU5UUkFMVVMiLCJqb2JMb2NhdGlvbiI6ImNlbnRyYWx1cyJ9?api-version=2014-04-01"); + } + + protected String stringFromResource(String resourceName) { + try { + return Resources.toString(getClass().getResource(resourceName), Charsets.UTF_8) + .replace(DEFAULT_ENDPOINT, url("")); + } catch (IOException e) { + throw Throwables.propagate(e); + } + } + + protected RecordedRequest assertSent(MockWebServer server, String method, String path) throws InterruptedException { + RecordedRequest request = server.takeRequest(); + assertEquals(request.getMethod(), method); + assertEquals(request.getPath(), path); + assertEquals(request.getHeader("Accept"), "application/json"); + assertEquals(request.getHeader("Authorization"), "Bearer " + MOCK_BEARER_TOKEN); + return request; + } + + protected RecordedRequest assertSent(MockWebServer server, String method, String path, String json) + throws InterruptedException { + RecordedRequest request = assertSent(server, method, path); + assertEquals(request.getHeader("Content-Type"), "application/json"); + assertEquals(parser.parse(new String(request.getBody(), Charsets.UTF_8)), parser.parse(json)); + return request; + } +} diff --git a/providers/azurecompute-arm/src/test/resources/resourcegroup.json b/providers/azurecompute-arm/src/test/resources/resourcegroup.json new file mode 100644 index 0000000000..1d0cc68ac9 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/resourcegroup.json @@ -0,0 +1,11 @@ +{ + "id": "/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/jcloudstest", + "name": "jcloudstest", + "location": "westus", + "tags": { + "tagname1": "tagvalue1" + }, + "properties": { + "provisioningState": "Succeeded" + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/resourcegroups.json b/providers/azurecompute-arm/src/test/resources/resourcegroups.json new file mode 100644 index 0000000000..bde3a9d215 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/resourcegroups.json @@ -0,0 +1,22 @@ +{ + "value": [ + { + "id": "/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/test1", + "name": "test1", + "location": "westus", + "properties": { + "provisioningState": "Succeeded" + } + }, + { + "id": "/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/test2", + "name": "test2", + "location": "eastus", + "tags": {}, + "properties": { + "provisioningState": "Succeeded" + } + } + ], + "nextLink": "https://management.azure.com/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups?api-version=2015-11-01&%24top=2&%24skiptoken=eyJuZXh0UGFydGl0aW9uS2V5IjoiMSE4IVJVTkJNalEtIiwibmV4dFJvd0tleSI6IjEhNjghTURSR04wVkRPRGc0UlRJNE5ERkZSRGcxTXpjMVJURTNOelkyTURBeFJqVmZRVTVRVWtsRFJWUkZVMVF0VjBWVFZGVlQifQ%3d%3d" +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/resourcegroupupdated.json b/providers/azurecompute-arm/src/test/resources/resourcegroupupdated.json new file mode 100644 index 0000000000..3d54d030e9 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/resourcegroupupdated.json @@ -0,0 +1,9 @@ +{ + "id": "/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/jcloudstest", + "name": "jcloudstest", + "location": "westus", + "tags": {}, + "properties": { + "provisioningState": "Succeeded" + } +} \ No newline at end of file From 397b0c9ba4267ce991ea4ad2118f40d800e9888b Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Wed, 6 Apr 2016 23:16:46 +0200 Subject: [PATCH 02/87] Azure ARM fixes --- providers/azurecompute-arm/README.md | 58 +++---------------- providers/azurecompute-arm/pom.xml | 12 ++-- .../arm}/AzureComputeApi.java | 0 .../arm}/AzureComputeProviderMetadata.java | 4 +- .../arm}/AzureManagementApiMetadata.java | 0 .../config/AzureComputeHttpApiModule.java | 2 +- .../arm}/config/AzureComputeParserModule.java | 0 .../arm}/config/AzureComputeProperties.java | 0 .../arm}/domain/ResourceGroup.java | 0 .../arm}/features/JobApi.java | 0 .../arm}/features/ResourceGroupApi.java | 0 .../arm}/functions/ParseJobStatus.java | 0 .../arm}/functions/URIParser.java | 0 .../handlers/AzureComputeErrorHandler.java | 0 .../AzureComputeProviderMetadataTest.java | 0 .../arm}/features/JobApiMockTest.java | 0 .../features/ResourceGroupApiLiveTest.java | 0 .../features/ResourceGroupApiMockTest.java | 0 .../arm}/functions/URIParserTest.java | 0 .../AbstractAzureComputeApiLiveTest.java | 0 .../arm}/internal/AzureLiveTestUtils.java | 0 .../internal/BaseAzureComputeApiLiveTest.java | 0 .../internal/BaseAzureComputeApiMockTest.java | 14 ++--- 23 files changed, 20 insertions(+), 70 deletions(-) rename providers/azurecompute-arm/src/main/java/org/jclouds/{azurecompute.arm => azurecompute/arm}/AzureComputeApi.java (100%) rename providers/azurecompute-arm/src/main/java/org/jclouds/{azurecompute.arm => azurecompute/arm}/AzureComputeProviderMetadata.java (96%) rename providers/azurecompute-arm/src/main/java/org/jclouds/{azurecompute.arm => azurecompute/arm}/AzureManagementApiMetadata.java (100%) rename providers/azurecompute-arm/src/main/java/org/jclouds/{azurecompute.arm => azurecompute/arm}/config/AzureComputeHttpApiModule.java (95%) rename providers/azurecompute-arm/src/main/java/org/jclouds/{azurecompute.arm => azurecompute/arm}/config/AzureComputeParserModule.java (100%) rename providers/azurecompute-arm/src/main/java/org/jclouds/{azurecompute.arm => azurecompute/arm}/config/AzureComputeProperties.java (100%) rename providers/azurecompute-arm/src/main/java/org/jclouds/{azurecompute.arm => azurecompute/arm}/domain/ResourceGroup.java (100%) rename providers/azurecompute-arm/src/main/java/org/jclouds/{azurecompute.arm => azurecompute/arm}/features/JobApi.java (100%) rename providers/azurecompute-arm/src/main/java/org/jclouds/{azurecompute.arm => azurecompute/arm}/features/ResourceGroupApi.java (100%) rename providers/azurecompute-arm/src/main/java/org/jclouds/{azurecompute.arm => azurecompute/arm}/functions/ParseJobStatus.java (100%) rename providers/azurecompute-arm/src/main/java/org/jclouds/{azurecompute.arm => azurecompute/arm}/functions/URIParser.java (100%) rename providers/azurecompute-arm/src/main/java/org/jclouds/{azurecompute.arm => azurecompute/arm}/handlers/AzureComputeErrorHandler.java (100%) rename providers/azurecompute-arm/src/test/java/org/jclouds/{azurecompute.arm => azurecompute/arm}/AzureComputeProviderMetadataTest.java (100%) rename providers/azurecompute-arm/src/test/java/org/jclouds/{azurecompute.arm => azurecompute/arm}/features/JobApiMockTest.java (100%) rename providers/azurecompute-arm/src/test/java/org/jclouds/{azurecompute.arm => azurecompute/arm}/features/ResourceGroupApiLiveTest.java (100%) rename providers/azurecompute-arm/src/test/java/org/jclouds/{azurecompute.arm => azurecompute/arm}/features/ResourceGroupApiMockTest.java (100%) rename providers/azurecompute-arm/src/test/java/org/jclouds/{azurecompute.arm => azurecompute/arm}/functions/URIParserTest.java (100%) rename providers/azurecompute-arm/src/test/java/org/jclouds/{azurecompute.arm => azurecompute/arm}/internal/AbstractAzureComputeApiLiveTest.java (100%) rename providers/azurecompute-arm/src/test/java/org/jclouds/{azurecompute.arm => azurecompute/arm}/internal/AzureLiveTestUtils.java (100%) rename providers/azurecompute-arm/src/test/java/org/jclouds/{azurecompute.arm => azurecompute/arm}/internal/BaseAzureComputeApiLiveTest.java (100%) rename providers/azurecompute-arm/src/test/java/org/jclouds/{azurecompute.arm => azurecompute/arm}/internal/BaseAzureComputeApiMockTest.java (95%) diff --git a/providers/azurecompute-arm/README.md b/providers/azurecompute-arm/README.md index a3abe63c85..85e39e5f82 100644 --- a/providers/azurecompute-arm/README.md +++ b/providers/azurecompute-arm/README.md @@ -2,7 +2,8 @@ jclouds Labs - Azure Compute ARM Provider ============ Build status for azurecomputearm module: -[![Build Status](http://devopsfunjenkins.westus.cloudapp.azure.com:8080/buildStatus/icon?job=jclouds-labs-azurecompute-arm/org.apache.jclouds.labs:azurecomputearm)](http://devopsfunjenkins.westus.cloudapp.azure.com:8080/job/jclouds-labs-azurecompute-arm/org.apache.jclouds.labs$azurecomputearm/) +[![Build Status](https://jclouds.ci.cloudbees.com/buildStatus/icon?job=jclouds-labs/org.apache.jclouds.labs$azurecompute-arm)](https://jclouds.ci.cloudbees.com/buildStatus/icon?job=jclouds-labs/org.apache.jclouds.labs$azurecompute-arm) + ## Setting Up Test Credentials @@ -42,68 +43,23 @@ Run the following commands to assign roles to the service principal ```bash # Assign roles for this service principal azure role assignment create --objectId -o Contributor -c /subscriptions// - ``` Verify service principal ```bash azure login -u -p --service-principal --tenant - ``` ## Run Live Tests - Use the following to run the live tests ```bash -# ResourceGroupApiLiveTest: - -mvn -Dtest=ResourceGroupApiLiveTest -Dtest.azurecompute-arm.identity= -Dtest.azurecompute-arm.subscriptionid= -Dtest.azurecompute-arm.credential= -Dtest.azurecompute-arm.endpoint="https://management.azure.com" -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test - -# AuthorizationApiLiveTest: - -mvn -Dtest=AuthorizationApiLiveTest -Dtest.oauth.identity= -Dtest.oauth.credential= -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" -Dtest.jclouds.oauth.audience="https://management.azure.com/" test - -# LocationApiLiveTest: - -mvn -Dtest=LocationApiLiveTest -Dtest.azurecompute-arm.identity= -Dtest.azurecompute-arm.subscriptionid= -Dtest.azurecompute-arm.credential= -Dtest.azurecompute-arm.endpoint="https://management.azure.com" -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test - -# StorageAccountApiLiveTest: - -mvn -Dtest=StorageAccountApiLiveTest -Dtest.azurecompute-arm.identity= -Dtest.azurecompute-arm.subscriptionid= -Dtest.azurecompute-arm.credential= -Dtest.azurecompute-arm.endpoint="https://management.azure.com" -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test - -# VirtualNetworkApiLiveTest: - -mvn -Dtest=VirtualNetworkApiLiveTest -Dtest.azurecompute-arm.identity= -Dtest.azurecompute-arm.subscriptionid= -Dtest.azurecompute-arm.credential= -Dtest.azurecompute-arm.resourcegroup="jcloudstest" -Dtest.azurecompute-arm.endpoint="https://management.azure.com" -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test - -# SubnetApiLiveTest - -mvn -Dtest=SubnetApiLiveTest -Dtest.azurecompute-arm.identity= -Dtest.azurecompute-arm.subscriptionid= -Dtest.azurecompute-arm.credential= -Dtest.azurecompute-arm.resourcegroup="jcloudstest" -Dtest.azurecompute-arm.endpoint="https://management.azure.com" -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test - -# NetworkInterfaceCardApiLiveTest - -mvn -Dtest=NetworkInterfaceCardApiLiveTest -Dtest.azurecompute-arm.identity= -Dtest.azurecompute-arm.subscriptionid= -Dtest.azurecompute-arm.credential= -Dtest.azurecompute-arm.resourcegroup="jcloudstest" -Dtest.azurecompute-arm.endpoint="https://management.azure.com" -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test - -# VirtualMachineApiLiveTest: - -mvn -Dtest=VirtualMachineApiLiveTest -Dtest.azurecompute-arm.identity= -Dtest.azurecompute-arm.subscriptionid= -Dtest.azurecompute-arm.credential= -Dtest.azurecompute-arm.endpoint="https://management.azure.com" -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test - -# VMSizeApiLiveTest: - -mvn -Dtest=VMSizeApiLiveTest -Dtest.azurecompute-arm.identity= -Dtest.azurecompute-arm.subscriptionid= -Dtest.azurecompute-arm.credential= -Dtest.azurecompute-arm.endpoint="https://management.azure.com" -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test - -# PublicIPAddressApiLiveTest - -mvn -Dtest=PublicIPAddressApiLiveTest -Dtest.azurecompute-arm.identity= -Dtest.azurecompute-arm.subscriptionid= -Dtest.azurecompute-arm.credential= -Dtest.azurecompute-arm.endpoint="https://management.azure.com" -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test - -# OSImageApiLiveTest: - -mvn -Dtest=OSImageApiLiveTest -Dtest.azurecompute-arm.identity= -Dtest.azurecompute-arm.subscriptionid= -Dtest.azurecompute-arm.credential= -Dtest.azurecompute-arm.endpoint="https://management.azure.com" -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test - -# DeploymentApiLiveTest: - -mvn -Dtest=DeploymentApiLiveTest -Dtest.azurecompute-arm.identity= -Dtest.azurecompute-arm.subscriptionid= -Dtest.azurecompute-arm.credential= -Dtest.azurecompute-arm.endpoint="https://management.azure.com/" -Dtest.jclouds.oauth.resource="https://management.azure.com/" -Dtest.oauth.endpoint="https://login.microsoftonline.com//oauth2/token" test +mvn clean verify -Plive \ + -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 ``` \ No newline at end of file diff --git a/providers/azurecompute-arm/pom.xml b/providers/azurecompute-arm/pom.xml index 807ab2066e..33251fded1 100644 --- a/providers/azurecompute-arm/pom.xml +++ b/providers/azurecompute-arm/pom.xml @@ -31,10 +31,10 @@ bundle - FIXME_subscription-id - FIXME_tenant-id - https://management.azure.com/subscriptions/${test.jclouds.azurecompute-arm.subscription-id} - 2014-04-01-preview + https://management.azure.com/ + https://login.microsoftonline.com/FIXME_tenant-id/oauth2/token + https://management.azure.com/subscriptions/FIXME_subscription-id + app id app password @@ -162,8 +162,8 @@ ${test.azurecompute-arm.build-version} ${test.azurecompute-arm.identity} ${test.azurecompute-arm.credential} - ${test.jclouds.azurecompute-arm.subscription-id} - ${test.jclouds.azurecompute-arm.tenant-id} + ${test.jclouds.oauth.resource} + ${test.oauth.endpoint} 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 similarity index 100% rename from providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/AzureComputeApi.java rename to providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeApi.java 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 similarity index 96% rename from providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/AzureComputeProviderMetadata.java rename to providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureComputeProviderMetadata.java index 68d7a869fe..958a6ddfee 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 @@ -55,7 +55,6 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { 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("oauth.endpoint", "https://login.microsoftonline.com/oauth2/token"); properties.put(RESOURCE, "https://management.azure.com"); properties.put(CREDENTIAL_TYPE, CLIENT_CREDENTIALS_SECRET.toString()); return properties; @@ -69,9 +68,8 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { protected Builder() { super(); - id("azurecompute-arm") - .name("Azure Resource Management ") + .name("Azure Resource Management") .apiMetadata(new AzureManagementApiMetadata()) .endpoint("https://management.azure.com/subscriptions/SUBSCRIPTION_ID") .homepage(URI.create("https://www.windowsazure.com/")) diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/AzureManagementApiMetadata.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java similarity index 100% rename from providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/AzureManagementApiMetadata.java rename to providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java 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 similarity index 95% rename from providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/config/AzureComputeHttpApiModule.java rename to providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeHttpApiModule.java index 9041d960aa..eb6a6d6d71 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 @@ -52,6 +52,6 @@ public class AzureComputeHttpApiModule extends HttpApiModule { protected void configure() { install(new AzureComputeParserModule()); super.configure(); - bind(OAuthScopes.class).toInstance(OAuthScopes.ReadOrWriteScopes.create("read", "read write")); + bind(OAuthScopes.class).toInstance(OAuthScopes.NoScopes.create()); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/config/AzureComputeParserModule.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeParserModule.java similarity index 100% rename from providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/config/AzureComputeParserModule.java rename to providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeParserModule.java 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 similarity index 100% rename from providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/config/AzureComputeProperties.java rename to providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeProperties.java diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/domain/ResourceGroup.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceGroup.java similarity index 100% rename from providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/domain/ResourceGroup.java rename to providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceGroup.java 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 similarity index 100% rename from providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/features/JobApi.java rename to providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/JobApi.java 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 similarity index 100% rename from providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/features/ResourceGroupApi.java rename to providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ResourceGroupApi.java diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/functions/ParseJobStatus.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/ParseJobStatus.java similarity index 100% rename from providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/functions/ParseJobStatus.java rename to providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/ParseJobStatus.java diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/functions/URIParser.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/URIParser.java similarity index 100% rename from providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/functions/URIParser.java rename to providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/URIParser.java diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/handlers/AzureComputeErrorHandler.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/handlers/AzureComputeErrorHandler.java similarity index 100% rename from providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute.arm/handlers/AzureComputeErrorHandler.java rename to providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/handlers/AzureComputeErrorHandler.java diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/AzureComputeProviderMetadataTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/AzureComputeProviderMetadataTest.java similarity index 100% rename from providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/AzureComputeProviderMetadataTest.java rename to providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/AzureComputeProviderMetadataTest.java diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/features/JobApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/JobApiMockTest.java similarity index 100% rename from providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/features/JobApiMockTest.java rename to providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/JobApiMockTest.java diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/features/ResourceGroupApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiLiveTest.java similarity index 100% rename from providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/features/ResourceGroupApiLiveTest.java rename to providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiLiveTest.java diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/features/ResourceGroupApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiMockTest.java similarity index 100% rename from providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/features/ResourceGroupApiMockTest.java rename to providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiMockTest.java diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/functions/URIParserTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/functions/URIParserTest.java similarity index 100% rename from providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/functions/URIParserTest.java rename to providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/functions/URIParserTest.java diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/internal/AbstractAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AbstractAzureComputeApiLiveTest.java similarity index 100% rename from providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/internal/AbstractAzureComputeApiLiveTest.java rename to providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AbstractAzureComputeApiLiveTest.java diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/internal/AzureLiveTestUtils.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java similarity index 100% rename from providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/internal/AzureLiveTestUtils.java rename to providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/internal/BaseAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java similarity index 100% rename from providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/internal/BaseAzureComputeApiLiveTest.java rename to providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java 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 similarity index 95% rename from providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute.arm/internal/BaseAzureComputeApiMockTest.java rename to providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiMockTest.java index fdbdf7036e..f6dbee3d51 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 @@ -16,20 +16,18 @@ */ package org.jclouds.azurecompute.arm.internal; import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor; -import static org.testng.Assert.assertEquals; import static org.jclouds.oauth.v2.config.CredentialType.BEARER_TOKEN_CREDENTIALS; import static org.jclouds.oauth.v2.config.OAuthProperties.CREDENTIAL_TYPE; +import static org.testng.Assert.assertEquals; import java.io.IOException; import java.util.Properties; import java.util.Set; import org.jclouds.ContextBuilder; -import org.jclouds.concurrent.config.ExecutorServiceModule; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; -import org.jclouds.json.Json; -import org.jclouds.rest.ApiContext; +import org.jclouds.concurrent.config.ExecutorServiceModule; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; @@ -52,7 +50,6 @@ public class BaseAzureComputeApiMockTest { protected MockWebServer server; protected AzureComputeApi api; - private Json json; // So that we can ignore formatting. private final JsonParser parser = new JsonParser(); @@ -63,15 +60,14 @@ public class BaseAzureComputeApiMockTest { 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(); - ApiContext ctx = ContextBuilder.newBuilder(pm) + api = ContextBuilder.newBuilder(pm) .credentials("", MOCK_BEARER_TOKEN) .endpoint(server.getUrl("/").toString() + "subscriptions/12345678-1234-1234-1234-123456789012") .modules(modules) .overrides(properties) - .build(); - json = ctx.utils().injector().getInstance(Json.class); - api = ctx.getApi(); + .buildApi(AzureComputeApi.class); } @AfterMethod(alwaysRun = true) From ac57c72f3a000b3a6f964ce81d50ff87ff1bfbeb Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Thu, 7 Apr 2016 12:15:35 +0200 Subject: [PATCH 03/87] Updated azurecompute-arm build status link --- providers/azurecompute-arm/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/providers/azurecompute-arm/README.md b/providers/azurecompute-arm/README.md index 85e39e5f82..fc8bb545af 100644 --- a/providers/azurecompute-arm/README.md +++ b/providers/azurecompute-arm/README.md @@ -2,7 +2,7 @@ jclouds Labs - Azure Compute ARM Provider ============ Build status for azurecomputearm module: -[![Build Status](https://jclouds.ci.cloudbees.com/buildStatus/icon?job=jclouds-labs/org.apache.jclouds.labs$azurecompute-arm)](https://jclouds.ci.cloudbees.com/buildStatus/icon?job=jclouds-labs/org.apache.jclouds.labs$azurecompute-arm) +[![Build Status](https://jclouds.ci.cloudbees.com/buildStatus/icon?job=jclouds-labs/org.apache.jclouds.labs$azurecompute-arm)](https://jclouds.ci.cloudbees.com/job/jclouds-labs/org.apache.jclouds.labs$azurecompute-arm/) @@ -62,4 +62,4 @@ mvn clean verify -Plive \ -Dtest.azurecompute-arm.credential= \ -Dtest.azurecompute-arm.endpoint=https://management.azure.com/subscriptions/ \ -Dtest.oauth.endpoint=https://login.microsoftonline.com//oauth2/token -``` \ No newline at end of file +``` From 8d21b5eca62fa173b207de4c7f3a7e56897a30e5 Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Mon, 11 Apr 2016 17:00:13 -0700 Subject: [PATCH 04/87] JCLOUDS-664 Azurecompute-arm LocationApi --- .../azurecompute/arm/AzureComputeApi.java | 9 ++ .../arm/AzureComputeProviderMetadata.java | 2 + .../compute/functions/LocationToLocation.java | 62 +++++++++++++ .../azurecompute/arm/domain/Location.java | 58 ++++++++++++ .../azurecompute/arm/domain/Region.java | 90 +++++++++++++++++++ .../arm/features/LocationApi.java | 57 ++++++++++++ .../arm/features/LocationApiLiveTest.java | 39 ++++++++ .../arm/features/LocationApiMockTest.java | 50 +++++++++++ .../features/ResourceGroupApiMockTest.java | 2 +- .../internal/BaseAzureComputeApiMockTest.java | 4 +- .../src/test/resources/locations.json | 10 +++ .../src/test/resources/resourcegroup.json | 2 +- .../src/test/resources/resourcegroups.json | 6 +- .../test/resources/resourcegroupupdated.json | 2 +- 14 files changed, 385 insertions(+), 8 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToLocation.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Location.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/LocationApi.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LocationApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LocationApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/resources/locations.json 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 a897c9af10..1e7cb912f7 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 @@ -19,6 +19,7 @@ package org.jclouds.azurecompute.arm; import java.io.Closeable; import org.jclouds.azurecompute.arm.features.JobApi; +import org.jclouds.azurecompute.arm.features.LocationApi; import org.jclouds.azurecompute.arm.features.ResourceGroupApi; import org.jclouds.rest.annotations.Delegate; @@ -40,4 +41,12 @@ public interface AzureComputeApi extends Closeable { @Delegate JobApi getJobApi(); + + /** + * This Azure Resource Manager API provides all of the locations that are available for resource providers + * + * @see docs + */ + @Delegate + LocationApi getLocationApi(); } 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 958a6ddfee..39defdca59 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 @@ -27,6 +27,7 @@ import static org.jclouds.oauth.v2.config.OAuthProperties.CREDENTIAL_TYPE; import java.net.URI; import java.util.Properties; +import org.jclouds.azurecompute.arm.domain.Region; import org.jclouds.providers.ProviderMetadata; import org.jclouds.providers.internal.BaseProviderMetadata; @@ -75,6 +76,7 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { .homepage(URI.create("https://www.windowsazure.com/")) .console(URI.create("https://windows.azure.com/default.aspx")) .linkedServices("azureblob") + .iso3166Codes(Region.iso3166Codes()) .defaultProperties(AzureComputeProviderMetadata.defaultProperties()); } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToLocation.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToLocation.java new file mode 100644 index 0000000000..a4d4b1ec1d --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToLocation.java @@ -0,0 +1,62 @@ +/* + * 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.collect.Iterables.getOnlyElement; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.azurecompute.arm.domain.Location; +import org.jclouds.azurecompute.arm.domain.Region; +import org.jclouds.domain.LocationBuilder; +import org.jclouds.domain.LocationScope; +import org.jclouds.location.suppliers.all.JustProvider; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableSet; + +/** + * Converts an Location into a Location. + */ +@Singleton +public class LocationToLocation implements Function { + + private final JustProvider justProvider; + + @Inject + LocationToLocation(JustProvider justProvider) { + this.justProvider = justProvider; + } + + @Override + public org.jclouds.domain.Location apply(final Location location) { + final LocationBuilder builder = new LocationBuilder(); + builder.id(location.id()); + builder.description(location.displayName()); + builder.parent(getOnlyElement(justProvider.get())); + + builder.scope(LocationScope.REGION); + final Region region = Region.byName(location.name()); + if (region != null) { + builder.iso3166Codes(ImmutableSet.of(region.iso3166Code())); + } + + return builder.build(); + } + +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Location.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Location.java new file mode 100644 index 0000000000..a597a61f9b --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Location.java @@ -0,0 +1,58 @@ +/* + * 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 org.jclouds.json.SerializedNames; + +/** + * A data center location that is valid for your subscription. + */ +@AutoValue +public abstract class Location { + /** + * The id of the data center. + */ + public abstract String id(); + + /** + * The name of the data center location. Ex. {@code West Europe}. + */ + public abstract String name(); + + /** + * The localized name of the data center location. + */ + public abstract String displayName(); + + /** + * The longitude of the datacenter + */ + public abstract double longitude(); + + /** + * The latitude of the datacenter + */ + public abstract double latitude(); + + @SerializedNames({"id", "name", "displayName", "longitude", "latitude"}) + public static Location create(final String id, final String name, final String displayName, final double longitude, + final double latitude) { + + return new AutoValue_Location(id, name, displayName, longitude, latitude); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.java new file mode 100644 index 0000000000..5c8549392c --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.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.domain; + +import com.google.common.base.Function; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import java.util.Arrays; +import java.util.Set; + +/** + * Regions used in Azure. + * + * @see this page + */ +public enum Region { + + CENTRAL_US("Central US", "US-IA"), + EAST_US("East US", "US-VA"), + EAST_US_2("East US 2", "US-VA"), + US_GOV_IOWA("US Gov Iowa", "US-IA"), + US_GOV_VIRGINIA("US Gov Virginia", "US-VA"), + NORTH_CENTRAL_US("North Central US", "US-IL"), + SOUTH_CENTRAL_US("South Central US", "US-TX"), + WEST_US("West US", "US-CA"), + NORTH_EUROPE("North Europe", "IE"), + WEST_EUROPE("West Europe", "NL"), + EAST_ASIA("East Asia", "HK"), + SOUTH_EAST_ASIA("Southeast Asia", "SG"), + JAPAN_EAST("Japan East", "JP-11"), + JAPAN_WEST("Japan West", "JP-27"), + BRAZIL_SOUTH("Brazil South", "BR"), + AUSTRALIA_EAST("Australia East", "AU-NSW"), + AUSTRALIA_SOUTH_EAST("Australia Southeast", "AU-VIC"); + + private final String name; + + private final String iso3166Code; + + Region(final String name, final String iso3166Code) { + this.name = name; + this.iso3166Code = iso3166Code; + } + + public String getName() { + return name; + } + + public String iso3166Code() { + return iso3166Code; + } + + public static Region byName(final String name) { + Preconditions.checkNotNull(name); + + Region result = null; + for (Region region : values()) { + if (name.equals(region.name)) { + result = region; + } + } + + return result; + } + + public static Set iso3166Codes() { + return ImmutableSet.copyOf(Iterables.transform(Arrays.asList(values()), new Function() { + + @Override + public String apply(final Region region) { + return region.iso3166Code; + } + })); + } +} 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 new file mode 100644 index 0000000000..772b3cbdb7 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/LocationApi.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 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.Produces; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; +import org.jclouds.azurecompute.arm.domain.Location; +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; + +/** + * This Azure Resource Manager API provides all of the locations that are available for resource providers + *

+ * + * @see docs + */ +@Path("/locations") +@RequestFilters(OAuthFilter.class) +@QueryParams(keys = "api-version", values = "2015-11-01") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public interface LocationApi { + + /** + * The List Locations operation lists all of the data center locations that are valid for your subscription. + */ + @Named("ListLocations") + @GET + @SelectJson("value") + @Fallback(EmptyListOnNotFoundOr404.class) + List list(); +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LocationApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LocationApiLiveTest.java new file mode 100644 index 0000000000..2c63a701df --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LocationApiLiveTest.java @@ -0,0 +1,39 @@ +/* + * 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.azurecompute.arm.domain.Location; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertTrue; + +@Test(groups = "live", testName = "LocationApiLiveTest") +public class LocationApiLiveTest extends BaseAzureComputeApiLiveTest { + + @Test + public void testList() { + for (Location location : api().list()) { + assertTrue(!location.id().isEmpty()); + } + assertTrue(!api().list().isEmpty()); + } + + private LocationApi api() { + return api.getLocationApi(); + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LocationApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LocationApiMockTest.java new file mode 100644 index 0000000000..5ea60d478f --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LocationApiMockTest.java @@ -0,0 +1,50 @@ +/* + * 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 com.google.common.collect.ImmutableList; +import com.squareup.okhttp.mockwebserver.MockResponse; +import org.jclouds.azurecompute.arm.domain.Location; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +@Test(groups = "unit", testName = "LocationApiMockTest", singleThreaded = true) +public class LocationApiMockTest extends BaseAzureComputeApiMockTest { + + public void testList() throws Exception { + server.enqueue(jsonResponse("/locations.json")); + final LocationApi locationAPI = api.getLocationApi(); + assertEquals(locationAPI.list(), ImmutableList.of( + Location.create("/subscriptions/SUBSCRIPTIONID/locations/eastasia", + "eastasia", "East Asia", 114.188, 22.267) + )); + assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/locations?api-version=2015-11-01"); + } + + public void testEmptyList() throws Exception { + server.enqueue(new MockResponse().setResponseCode(404)); + + final LocationApi locationAPI = api.getLocationApi(); + + assertTrue(locationAPI.list().isEmpty()); + + assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/locations?api-version=2015-11-01"); + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiMockTest.java index 91cb2b1f3d..0c03c756aa 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiMockTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiMockTest.java @@ -34,7 +34,7 @@ import static org.testng.Assert.assertEquals; @Test(groups = "unit", testName = "ResourceGroupApiMockTest", singleThreaded = true) public class ResourceGroupApiMockTest extends BaseAzureComputeApiMockTest { - final String subscriptionid = "12345678-1234-1234-1234-123456789012"; + final String subscriptionid = "SUBSCRIPTIONID"; final String requestUrl = "/subscriptions/" + subscriptionid + "/resourcegroups"; final String version = "?api-version=2015-01-01"; 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 f6dbee3d51..5a228f4ca0 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 @@ -64,7 +64,7 @@ public class BaseAzureComputeApiMockTest { AzureComputeProviderMetadata pm = AzureComputeProviderMetadata.builder().build(); api = ContextBuilder.newBuilder(pm) .credentials("", MOCK_BEARER_TOKEN) - .endpoint(server.getUrl("/").toString() + "subscriptions/12345678-1234-1234-1234-123456789012") + .endpoint(server.getUrl("/").toString() + "subscriptions/SUBSCRIPTIONID") .modules(modules) .overrides(properties) .buildApi(AzureComputeApi.class); @@ -99,7 +99,7 @@ public class BaseAzureComputeApiMockTest { protected MockResponse response202WithHeader() { return new MockResponse() .setStatus("HTTP/1.1 202 Accepted") - .addHeader("Location", "https://management.azure.com/subscriptions/12345678-1234-1234-1234-123456789012/operationresults/eyJqb2JJZCI6IlJFU09VUkNFR1JPVVBERUxFVElPTkpPQi1SVEVTVC1DRU5UUkFMVVMiLCJqb2JMb2NhdGlvbiI6ImNlbnRyYWx1cyJ9?api-version=2014-04-01"); + .addHeader("Location", "https://management.azure.com/subscriptions/SUBSCRIPTIONID/operationresults/eyJqb2JJZCI6IlJFU09VUkNFR1JPVVBERUxFVElPTkpPQi1SVEVTVC1DRU5UUkFMVVMiLCJqb2JMb2NhdGlvbiI6ImNlbnRyYWx1cyJ9?api-version=2014-04-01"); } protected String stringFromResource(String resourceName) { diff --git a/providers/azurecompute-arm/src/test/resources/locations.json b/providers/azurecompute-arm/src/test/resources/locations.json new file mode 100644 index 0000000000..a4a15bc997 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/locations.json @@ -0,0 +1,10 @@ +{"value": [ + { + "id":"/subscriptions/SUBSCRIPTIONID/locations/eastasia", + "name":"eastasia", + "displayName":"East Asia", + "longitude":"114.188", + "latitude":"22.267" + } + ] +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/resourcegroup.json b/providers/azurecompute-arm/src/test/resources/resourcegroup.json index 1d0cc68ac9..6ca47cfb0f 100644 --- a/providers/azurecompute-arm/src/test/resources/resourcegroup.json +++ b/providers/azurecompute-arm/src/test/resources/resourcegroup.json @@ -1,5 +1,5 @@ { - "id": "/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/jcloudstest", + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/jcloudstest", "name": "jcloudstest", "location": "westus", "tags": { diff --git a/providers/azurecompute-arm/src/test/resources/resourcegroups.json b/providers/azurecompute-arm/src/test/resources/resourcegroups.json index bde3a9d215..e21fdb7f44 100644 --- a/providers/azurecompute-arm/src/test/resources/resourcegroups.json +++ b/providers/azurecompute-arm/src/test/resources/resourcegroups.json @@ -1,7 +1,7 @@ { "value": [ { - "id": "/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/test1", + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/test1", "name": "test1", "location": "westus", "properties": { @@ -9,7 +9,7 @@ } }, { - "id": "/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/test2", + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/test2", "name": "test2", "location": "eastus", "tags": {}, @@ -18,5 +18,5 @@ } } ], - "nextLink": "https://management.azure.com/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups?api-version=2015-11-01&%24top=2&%24skiptoken=eyJuZXh0UGFydGl0aW9uS2V5IjoiMSE4IVJVTkJNalEtIiwibmV4dFJvd0tleSI6IjEhNjghTURSR04wVkRPRGc0UlRJNE5ERkZSRGcxTXpjMVJURTNOelkyTURBeFJqVmZRVTVRVWtsRFJWUkZVMVF0VjBWVFZGVlQifQ%3d%3d" + "nextLink": "https://management.azure.com/subscriptions/SUBSCRIPTIONID/resourceGroups?api-version=2015-11-01&%24top=2&%24skiptoken=eyJuZXh0UGFydGl0aW9uS2V5IjoiMSE4IVJVTkJNalEtIiwibmV4dFJvd0tleSI6IjEhNjghTURSR04wVkRPRGc0UlRJNE5ERkZSRGcxTXpjMVJURTNOelkyTURBeFJqVmZRVTVRVWtsRFJWUkZVMVF0VjBWVFZGVlQifQ%3d%3d" } \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/resourcegroupupdated.json b/providers/azurecompute-arm/src/test/resources/resourcegroupupdated.json index 3d54d030e9..19c366b78f 100644 --- a/providers/azurecompute-arm/src/test/resources/resourcegroupupdated.json +++ b/providers/azurecompute-arm/src/test/resources/resourcegroupupdated.json @@ -1,5 +1,5 @@ { - "id": "/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/jcloudstest", + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/jcloudstest", "name": "jcloudstest", "location": "westus", "tags": {}, From f85646f2594f5872a8243c5033338b73e08e010c Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Mon, 11 Apr 2016 17:00:13 -0700 Subject: [PATCH 05/87] JCLOUDS-664 Update live tests for Azurecompute-arm LocationApi --- .../jclouds/azurecompute/arm/domain/Region.java | 5 ++--- .../azurecompute/arm/features/LocationApi.java | 2 +- .../arm/features/LocationApiLiveTest.java | 17 ++++++++++++++--- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.java index 5c8549392c..feffa7bbac 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.java @@ -68,14 +68,13 @@ public enum Region { public static Region byName(final String name) { Preconditions.checkNotNull(name); - Region result = null; for (Region region : values()) { if (name.equals(region.name)) { - result = region; + return region; } } - return result; + return null; } public static Set iso3166Codes() { 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 772b3cbdb7..8f31d31626 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 @@ -49,7 +49,7 @@ public interface LocationApi { /** * The List Locations operation lists all of the data center locations that are valid for your subscription. */ - @Named("ListLocations") + @Named("location:list") @GET @SelectJson("value") @Fallback(EmptyListOnNotFoundOr404.class) diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LocationApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LocationApiLiveTest.java index 2c63a701df..fbfa88e26f 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LocationApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LocationApiLiveTest.java @@ -20,6 +20,7 @@ import org.jclouds.azurecompute.arm.domain.Location; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; import org.testng.annotations.Test; +import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; @Test(groups = "live", testName = "LocationApiLiveTest") @@ -27,13 +28,23 @@ public class LocationApiLiveTest extends BaseAzureComputeApiLiveTest { @Test public void testList() { - for (Location location : api().list()) { - assertTrue(!location.id().isEmpty()); - } assertTrue(!api().list().isEmpty()); + + for (Location location : api().list()) { + assertTrue(!location.id().isEmpty()); + checkLocation(location); + } } private LocationApi api() { return api.getLocationApi(); } + + private void checkLocation(final Location location) { + assertNotNull(location.name(), "Name cannot be null for a Location."); + assertNotNull(location.displayName(), "DisplayName cannot be null for: " + location.name()); + assertNotNull(location.id(), "Id cannot be null for: " + location.name()); + assertNotNull(location.latitude(), "Latitude cannot be null for: " + location.name()); + assertNotNull(location.longitude(), "Longitude cannot be null for: " + location.name()); + } } From cadc43cbbc9787ddfc7a193e6026211b44d468ce Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Wed, 13 Apr 2016 15:07:19 -0700 Subject: [PATCH 06/87] JCLOUDS-664 Azurecompute-arm StorageAccountApi --- .../azurecompute/arm/AzureComputeApi.java | 12 + .../azurecompute/arm/domain/Availability.java | 32 ++ .../arm/domain/ResourceGroup.java | 4 +- .../arm/domain/StorageService.java | 183 +++++++++ .../arm/domain/StorageServiceKeys.java | 39 ++ .../domain/StorageServiceUpdateParams.java | 64 ++++ .../arm/features/StorageAccountApi.java | 166 +++++++++ .../arm/functions/FalseOn204.java | 40 ++ .../arm/functions/ParseJobStatus.java | 12 +- .../azurecompute/arm/util/GetEnumValue.java | 36 ++ .../features/StorageAccountApiLiveTest.java | 133 +++++++ .../features/StorageAccountApiMockTest.java | 347 ++++++++++++++++++ .../internal/BaseAzureComputeApiLiveTest.java | 60 +++ .../internal/BaseAzureComputeApiMockTest.java | 5 + .../resources/isavailablestorageservice.json | 3 + .../src/test/resources/storageAccounts.json | 90 +++++ .../test/resources/storageCreateResponse.json | 9 + .../test/resources/storageaccountkeys.json | 4 + .../test/resources/storageaccountupdate.json | 7 + .../src/test/resources/storageservices.json | 30 ++ 20 files changed, 1265 insertions(+), 11 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Availability.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageService.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageServiceKeys.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageServiceUpdateParams.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/StorageAccountApi.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/FalseOn204.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/GetEnumValue.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/resources/isavailablestorageservice.json create mode 100644 providers/azurecompute-arm/src/test/resources/storageAccounts.json create mode 100644 providers/azurecompute-arm/src/test/resources/storageCreateResponse.json create mode 100644 providers/azurecompute-arm/src/test/resources/storageaccountkeys.json create mode 100644 providers/azurecompute-arm/src/test/resources/storageaccountupdate.json create mode 100644 providers/azurecompute-arm/src/test/resources/storageservices.json 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 1e7cb912f7..4204328a91 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 @@ -21,8 +21,11 @@ import java.io.Closeable; import org.jclouds.azurecompute.arm.features.JobApi; import org.jclouds.azurecompute.arm.features.LocationApi; import org.jclouds.azurecompute.arm.features.ResourceGroupApi; +import org.jclouds.azurecompute.arm.features.StorageAccountApi; import org.jclouds.rest.annotations.Delegate; +import javax.ws.rs.PathParam; + /** * The Azure Resource Manager API is a REST API for managing your services and deployments. *

@@ -49,4 +52,13 @@ public interface AzureComputeApi extends Closeable { */ @Delegate LocationApi getLocationApi(); + + /** + * The Azure Resource Manager API includes operations for managing the storage accounts in your subscription. + * + * @see docs + */ + @Delegate + StorageAccountApi getStorageAccountApi(@PathParam("resourceGroup") String resourceGroup); + } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Availability.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Availability.java new file mode 100644 index 0000000000..eb8c341555 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Availability.java @@ -0,0 +1,32 @@ +/* + * 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 org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class Availability { + + public abstract String nameAvailable(); + + @SerializedNames({"nameAvailable"}) + public static Availability create(final String nameAvailable) { + return new AutoValue_Availability(nameAvailable); + } + +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceGroup.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceGroup.java index 1be93abd43..08c41857b1 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceGroup.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceGroup.java @@ -40,12 +40,12 @@ public abstract class ResourceGroup { public abstract String id(); public abstract String name(); public abstract String location(); - @Nullable + public abstract Map tags(); public abstract ResourceGroupProperties properties(); @SerializedNames({"id", "name", "location", "tags", "properties"}) - public static ResourceGroup create(String id, String name, String location, @Nullable Map tags, ResourceGroupProperties properties) { + public static ResourceGroup create(String id, String name, String location, Map tags, ResourceGroupProperties properties) { return new AutoValue_ResourceGroup(id, name, location, tags == null ? ImmutableMap.builder().build() : ImmutableMap.copyOf(tags), properties); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageService.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageService.java new file mode 100644 index 0000000000..08709d8f68 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageService.java @@ -0,0 +1,183 @@ +/* + * 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 java.util.Date; +import java.util.Map; + +import com.google.common.collect.ImmutableMap; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import org.jclouds.azurecompute.arm.util.GetEnumValue; + +@AutoValue +public abstract class StorageService { + + public enum AccountType { + + Standard_LRS, + Standard_ZRS, + Standard_GRS, + Standard_RAGRS, + Premium_LRS, + UNRECOGNIZED; + + public static AccountType fromValue(final String text) { + return (AccountType) GetEnumValue.fromValueOrDefault(text, AccountType.UNRECOGNIZED); + } + } + + public enum RegionStatus { + + Available, + Unavailable, + UNRECOGNIZED; + + public static RegionStatus fromValue(final String text) { + return (RegionStatus) GetEnumValue.fromValueOrDefault(text, RegionStatus.UNRECOGNIZED); + } + + } + + public enum Status { + + Creating, + Created, + Deleting, + Deleted, + Changing, + ResolvingDns, + Succeeded, + UNRECOGNIZED; + + public static Status fromValue(final String text) { + return (Status) GetEnumValue.fromValueOrDefault(text, Status.UNRECOGNIZED); + } + } + + @AutoValue + public abstract static class StorageServiceProperties { + + /** + * Specifies whether the account supports locally-redundant storage, geo-redundant storage, zone-redundant + * storage, or read access geo-redundant storage. + */ + public abstract AccountType accountType(); + + /** + * Specifies the time that the storage account was created. + */ + public abstract Date creationTime(); + + /** + * Specifies the endpoints of the storage account. + */ + public abstract Map primaryEndpoints(); + + /** + * A primaryLocation for the storage account. + */ + @Nullable + public abstract String primaryLocation(); + + /** + * provisioningState for the storage group + */ + @Nullable + public abstract Status provisioningState(); + + /** + * Specifies the secondary endpoints of the storage account. + */ + public abstract Map secondaryEndpoints(); + + /** + * Secondary location for the storage group + */ + @Nullable + public abstract String secondaryLocation(); + + /** + * The status of primary endpoints + */ + @Nullable + public abstract RegionStatus statusOfPrimary(); + + /** + * The secondary status of the storage account. + */ + @Nullable + public abstract RegionStatus statusOfSecondary(); + + + @SerializedNames({"accountType", "creationTime", "primaryEndpoints", "primaryLocation", + "provisioningState", "secondaryEndpoints", "secondaryLocation", "statusOfPrimary", "statusOfSecondary"}) + public static StorageServiceProperties create(final AccountType accountType, final Date creationTime, + final Map primaryEndpoints, final String primaryLocation, final Status provisioningState, + final Map secondaryEndpoints, final String secondaryLocation, + final RegionStatus statusOfPrimary, final RegionStatus statusOfSecondary) { + + return new AutoValue_StorageService_StorageServiceProperties(accountType, creationTime, + primaryEndpoints == null ? ImmutableMap.builder().build() : ImmutableMap.copyOf(primaryEndpoints), primaryLocation, provisioningState, + secondaryEndpoints == null ? ImmutableMap.builder().build() : ImmutableMap.copyOf(secondaryEndpoints), secondaryLocation, statusOfPrimary, statusOfSecondary); + } + } + + /** + * Specifies the id of the storage account. + */ + @Nullable + public abstract String id(); + + /** + * Specifies the name of the storage account. This name is the DNS prefix name and can be used to access blobs, + * queues, and tables in the storage account. + */ + @Nullable + public abstract String name(); + + /** + * Specifies the location of the storage account. + */ + public abstract String location(); + + /** + * Specifies the tags of the storage account. + */ + public abstract Map tags(); + + /** + * Specifies the type of the storage account. + */ + @Nullable + public abstract String type(); + + /** + * Specifies the properties of the storage account. + */ + public abstract StorageServiceProperties storageServiceProperties(); + + + @SerializedNames({"id", "name", "location", "tags", "type", "properties"}) + public static StorageService create(final String id, final String name, final String location, + final Map tags, final String type, + final StorageServiceProperties storageServiceProperties) { + return new AutoValue_StorageService(id, name, location, tags == null ? ImmutableMap.builder().build() : ImmutableMap.copyOf(tags), type, storageServiceProperties); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageServiceKeys.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageServiceKeys.java new file mode 100644 index 0000000000..63cb70bdb5 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageServiceKeys.java @@ -0,0 +1,39 @@ +/* + * 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 org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class StorageServiceKeys { + + /** + * The primary access key for the storage account. + */ + public abstract String key1(); + + /** + * The secondary access key for the storage account. + */ + public abstract String key2(); + + @SerializedNames({"key1", "key2"}) + public static StorageServiceKeys create(final String key1, final String key2) { + return new AutoValue_StorageServiceKeys(key1, key2); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageServiceUpdateParams.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageServiceUpdateParams.java new file mode 100644 index 0000000000..85b8b6da8f --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageServiceUpdateParams.java @@ -0,0 +1,64 @@ +/* + * 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.ImmutableMap; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; +import java.util.Map; + +@AutoValue +public abstract class StorageServiceUpdateParams { + + @AutoValue + public abstract static class StorageServiceUpdateProperties { + + /** + * Specifies whether the account supports locally-redundant storage, geo-redundant storage, zone-redundant + * storage, or read access geo-redundant storage. + * Note: This implementation is for version 2015-10-01 and earlier. + * For version 2016-01-01 or later, refer to https://msdn.microsoft.com/en-us/library/mt163639.aspx + */ + @Nullable + public abstract StorageService.AccountType accountType(); + + + @SerializedNames({"accountType"}) + public static StorageServiceUpdateProperties create(final StorageService.AccountType accountType) { + + return new AutoValue_StorageServiceUpdateParams_StorageServiceUpdateProperties(accountType); + } + } + + /** + * Specifies the tags of the storage account. + */ + public abstract Map tags(); + + /** + * Specifies the properties of the storage account. + */ + public abstract StorageServiceUpdateProperties storageServiceProperties(); + + + @SerializedNames({"tags", "properties"}) + public static StorageServiceUpdateParams create(final Map tags, + final StorageServiceUpdateProperties storageServiceProperties) { + return new AutoValue_StorageServiceUpdateParams(tags == null ? ImmutableMap.builder().build() : ImmutableMap.copyOf(tags), storageServiceProperties); + } +} 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 new file mode 100644 index 0000000000..8ebfc821ff --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/StorageAccountApi.java @@ -0,0 +1,166 @@ +/* + * 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 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.PathParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks; +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.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.binders.BindToJsonPayload; + +import java.util.List; +import java.util.Map; +import java.net.URI; + +/** + * 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 = "2015-06-15") +@Consumes(MediaType.APPLICATION_JSON) +public interface StorageAccountApi { + + /** + * The List Storage Accounts operation lists the storage accounts that are available in the specified subscription + * and resource group. + * https://msdn.microsoft.com/en-us/library/mt163559.aspx + */ + @Named("storageaccount:list") + @Path("/resourcegroups/{resourceGroup}/providers/Microsoft.Storage/storageAccounts") + @GET + @SelectJson("value") + @Fallback(Fallbacks.EmptyListOnNotFoundOr404.class) + List list(); + + /** + * The Create Storage Account asynchronous operation creates a new storage account in Microsoft Azure. + * https://msdn.microsoft.com/en-us/library/mt163564.aspx + * PUT + */ + @Named("storageaccount:create") + @Payload("%7B\"location\":\"{location}\",\"tags\":{tags},\"properties\":{properties}%7D") + @Path("/resourcegroups/{resourceGroup}/providers/Microsoft.Storage/storageAccounts/{storageAccountName}") + @Produces(MediaType.APPLICATION_JSON) + @ResponseParser(URIParser.class) + @MapBinder(BindToJsonPayload.class) + @PUT + URI create(@PathParam("storageAccountName") String storageAccountName, + @PayloadParam("location") String location, + @Nullable @PayloadParam("tags") Map tags, + @PayloadParam("properties") Map properties); + + /** + * The Check Storage Account Name Availability operation checks to see if the specified storage account name is + * available, or if it has already been taken. https://msdn.microsoft.com/en-us/library/mt163642.aspx + * POST + */ + @Named("CheckStorageAccountNameAvailability") + @POST + @Payload("%7B\"name\":\"{name}\",\"type\":\"Microsoft.Storage/storageAccounts\"%7D") + @Path("/providers/Microsoft.Storage/checkNameAvailability") + @Produces(MediaType.APPLICATION_JSON) + Availability isAvailable(@PayloadParam("name") String storageAccountName); + + /** + * The Get Storage Account Properties operation returns system properties for the specified storage account. + * https://msdn.microsoft.com/en-us/library/mt163553.aspx + */ + @Named("storageaccountproperty:get") + @GET + @Path("/resourcegroups/{resourceGroup}/providers/Microsoft.Storage/storageAccounts/{storageAccountName}") + @Fallback(Fallbacks.NullOnNotFoundOr404.class) + StorageService get(@PathParam("storageAccountName") String storageAccountName); + + /** + * The Get Storage Keys operation returns the primary and secondary access keys for the specified storage account. + * https://msdn.microsoft.com/en-us/library/mt163589.aspx + * POST + */ + @Named("storageaccountkey:get") + @POST + @Path("/resourcegroups/{resourceGroup}/providers/Microsoft.Storage/storageAccounts/{storageAccountName}/listKeys") + @Produces(MediaType.APPLICATION_JSON) + @Fallback(Fallbacks.NullOnNotFoundOr404.class) + StorageServiceKeys getKeys(@PathParam("storageAccountName") String storageAccountName); + + /** + * https://msdn.microsoft.com/en-us/library/mt163567.aspx + * POST + */ + @Named("RegenerateStorageAccountKeys") + @POST + @Payload("%7B\"keyName\":\"{keyName}\"%7D") + @Path("/resourcegroups/{resourceGroup}/providers/Microsoft.Storage/storageAccounts/{storageAccount}/regenerateKey") + @Produces(MediaType.APPLICATION_JSON) + StorageServiceKeys regenerateKeys(@PathParam("storageAccount") String storageAccount, + @PayloadParam("keyName") String keyName); + + /** + * The Update Storage Account asynchronous operation updates the label, the description, and enables or disables the + * geo-replication status for the specified storage account. https://msdn.microsoft.com/en-us/library/mt163639.aspx + * PATCH + */ + @Named("storageaccount:update") + @PATCH + @Payload("%7B\"tags\":{tags},\"properties\":{properties}%7D") + @MapBinder(BindToJsonPayload.class) + @Path("/resourcegroups/{resourceGroup}/providers/Microsoft.Storage/storageAccounts/{storageAccountName}") + @Produces(MediaType.APPLICATION_JSON) + StorageServiceUpdateParams update( + @PathParam("storageAccountName") String storageAccountName, + @Nullable @PayloadParam("tags") Map tags, + @PayloadParam("properties") StorageServiceUpdateParams.StorageServiceUpdateProperties properties); + + /** + * https://msdn.microsoft.com/en-us/library/mt163652.aspx + * DELETE + */ + @Named("storageaccount:delete") + @DELETE + @ResponseParser(FalseOn204.class) + @Path("/resourcegroups/{resourceGroup}/providers/Microsoft.Storage/storageAccounts/{storageAccountName}") + boolean delete(@PathParam("storageAccountName") String storageAccountName); + +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/FalseOn204.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/FalseOn204.java new file mode 100644 index 0000000000..34c6d56ee1 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/FalseOn204.java @@ -0,0 +1,40 @@ +/* + * 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 com.google.common.base.Function; +import org.jclouds.http.HttpResponse; + +import javax.inject.Singleton; + +import static org.jclouds.http.HttpUtils.releasePayload; +/** + * Parses an http response code from http responser + */ +@Singleton +public class FalseOn204 implements Function { + public Boolean apply(final HttpResponse from) { + releasePayload(from); + final int statusCode = from.getStatusCode(); + if (statusCode == 200) { + return true; + } + if (statusCode == 204) { + return false; + } + throw new IllegalStateException("not expected response from: " + from); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/ParseJobStatus.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/ParseJobStatus.java index f39db90646..5770582ae7 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/ParseJobStatus.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/ParseJobStatus.java @@ -16,6 +16,7 @@ */ package org.jclouds.azurecompute.arm.functions; import com.google.common.base.Function; +import org.jclouds.azurecompute.arm.util.GetEnumValue; import org.jclouds.http.HttpResponse; import javax.inject.Singleton; @@ -31,15 +32,8 @@ public class ParseJobStatus implements Function> Enum fromValueOrDefault(String text, Enum defaultValue) { + if (text != null) { + EnumSet elements = EnumSet.allOf(defaultValue.getDeclaringClass()); + for (Enum element : elements) { + if (text.equalsIgnoreCase(element.name())) { + return element; + } + } + } + return defaultValue; + } + +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiLiveTest.java new file mode 100644 index 0000000000..9a13d77a18 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiLiveTest.java @@ -0,0 +1,133 @@ +/* + * 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 com.google.common.base.Predicate; +import com.google.common.collect.ImmutableMap; +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.functions.ParseJobStatus; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; +import org.jclouds.util.Predicates2; +import org.testng.annotations.Test; + +import java.net.URI; +import java.util.List; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +@Test(groups = "live", testName = "StorageAccountApiLiveTest") +public class StorageAccountApiLiveTest extends BaseAzureComputeApiLiveTest { + + private static final String NAME = String.format("%3.24s", + RAND + StorageAccountApiLiveTest.class.getSimpleName().toLowerCase()); + + private void check(final StorageService storage) { + assertNotNull(storage.id()); + assertNotNull(storage.name()); + assertNotNull(storage.storageServiceProperties()); + assertNotNull(storage.storageServiceProperties().accountType()); + assertFalse(storage.storageServiceProperties().primaryEndpoints().isEmpty()); + assertNotNull(storage.storageServiceProperties().creationTime()); + } + + @Test(dependsOnMethods = "testCreate") + public void testList() { + List storages = api().list(); + assertTrue(storages.size() > 0); + for (StorageService storage : storages) { + check(storage); + } + } + + @Test() + public void testIsAvailable() { + assertTrue(api().isAvailable(NAME).nameAvailable().equals("true")); + } + + @Test(dependsOnMethods = "testIsAvailable") + public void testCreate() { + URI uri = api().create(NAME, LOCATION, ImmutableMap.of("property_name", + "property_value"), ImmutableMap.of("accountType", StorageService.AccountType.Standard_LRS.toString())); + if (uri != null){ + assertTrue(uri.toString().contains("api-version")); + + boolean jobDone = Predicates2.retry(new Predicate() { + @Override public boolean apply(URI uri) { + return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri); + } + }, 60 * 1 * 1000 /* 1 minute timeout */).apply(uri); + assertTrue(jobDone, "create operation did not complete in the configured timeout"); + } + final StorageService service = api().get(NAME); + assertNotNull(service); + assertEquals(service.location(), LOCATION); + assertNotNull(service.storageServiceProperties().creationTime()); + } + + @Test(dependsOnMethods = "testCreate") + public void testGet() { + final StorageService service = api().get(NAME); + assertNotNull(service); + assertEquals(service.name(), NAME); + assertEquals(service.storageServiceProperties().primaryLocation(), LOCATION); + assertEquals(service.storageServiceProperties().accountType(), StorageService.AccountType.Standard_LRS); + } + + @Test(dependsOnMethods = "testCreate") + public void testGetKeys() { + final StorageServiceKeys keys = api().getKeys(NAME); + assertNotNull(keys); + assertNotNull(keys.key1()); + assertNotNull(keys.key2()); + } + + @Test(dependsOnMethods = "testCreate") + public void testRegenerateKeys() { + StorageServiceKeys keys = api().regenerateKeys(NAME, "key1"); + assertFalse(keys.key1().isEmpty()); + assertFalse(keys.key2().isEmpty()); + } + + @Test(dependsOnMethods = "testCreate") + public void testUpdateTags() { + StorageServiceUpdateParams.StorageServiceUpdateProperties props = + StorageServiceUpdateParams.StorageServiceUpdateProperties.create(null); + final StorageServiceUpdateParams params = api().update(NAME, + ImmutableMap.of("another_property_name", "another_property_value"), props); + assertTrue(params.tags().containsKey("another_property_name")); + assertNull(params.storageServiceProperties().accountType()); + } + @Test(dependsOnMethods = "testCreate") + public void testUpdateAccountType() { + StorageServiceUpdateParams.StorageServiceUpdateProperties props = + StorageServiceUpdateParams.StorageServiceUpdateProperties.create(StorageService.AccountType.Standard_GRS); + final StorageServiceUpdateParams params = api().update(NAME, + null, props); + assertTrue(params.tags().isEmpty()); + assertEquals(params.storageServiceProperties().accountType(), StorageService.AccountType.Standard_GRS); + } + + private StorageAccountApi api() { + return api.getStorageAccountApi(getResourceGroupName()); + } +} 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 new file mode 100644 index 0000000000..39ecd2babc --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiMockTest.java @@ -0,0 +1,347 @@ +/* + * 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 com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +import org.jclouds.azurecompute.arm.domain.StorageService; +import org.jclouds.azurecompute.arm.domain.Availability; +import org.jclouds.azurecompute.arm.domain.StorageServiceKeys; +import org.jclouds.azurecompute.arm.domain.StorageServiceUpdateParams; +import com.squareup.okhttp.mockwebserver.MockResponse; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; +import org.jclouds.date.DateService; +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.testng.annotations.Test; + +import java.net.MalformedURLException; +import java.net.URI; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.google.common.collect.Iterables.isEmpty; + +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertFalse; + + +@Test(groups = "unit", testName = "StorageAccountApiMockTest", singleThreaded = true) +public class StorageAccountApiMockTest extends BaseAzureComputeApiMockTest { + + private String subsriptionId = "SUBSCRIPTIONID"; + private String resourceGroup = "resourceGroup"; + + public void testList() throws Exception { + server.enqueue(jsonResponse("/storageAccounts.json")); + + final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup); + + List list = storageAPI.list(); + assertEquals(list, expected()); + + assertSent(server, "GET", "/subscriptions/" + subsriptionId + + "/resourcegroups/resourceGroup/providers/Microsoft.Storage/storageAccounts?api-version=2015-06-15"); + } + + public void testListReturns404() throws InterruptedException { + server.enqueue(response404()); + + final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup); + + List list = storageAPI.list(); + + assertTrue(isEmpty(list)); + + assertEquals(server.getRequestCount(), 1); + assertSent(server, "GET", "/subscriptions/" + subsriptionId + + "/resourcegroups/resourceGroup/providers/Microsoft.Storage/storageAccounts?api-version=2015-06-15"); + } + + public void testCreate() throws Exception { + final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup); + + server.enqueue(response202WithHeader()); + + URI uri = storageAPI.create("name-of-storage-account", "westus", + ImmutableMap.of("property_name", "property_value"), + ImmutableMap.of("accountType", StorageService.AccountType.Premium_LRS.toString())); + assertNotNull(uri); + + assertSent(server, "PUT", "/subscriptions/" + subsriptionId + + "/resourcegroups/resourceGroup/providers/Microsoft.Storage/" + + "storageAccounts/name-of-storage-account?api-version=2015-06-15", String.format("{\"location\":\"westus\",\"tags\":{\"property_name\":\"property_value\"},\"properties\":{\"accountType\":\"Premium_LRS\"}}")); + } + + public void testCreateWithNullTag() throws Exception { + final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup); + + server.enqueue(response202WithHeader()); + + URI uri = storageAPI.create("name-of-storage-account", "westus", + null, + ImmutableMap.of("accountType", StorageService.AccountType.Premium_LRS.toString())); + assertNotNull(uri); + + assertSent(server, "PUT", "/subscriptions/" + subsriptionId + + "/resourcegroups/resourceGroup/providers/Microsoft.Storage/" + + "storageAccounts/name-of-storage-account?api-version=2015-06-15", String.format("{\"location\":\"westus\",\"properties\":{\"accountType\":\"Premium_LRS\"}}")); + } + + public void testIsAvailable() throws Exception { + server.enqueue(jsonResponse("/isavailablestorageservice.json")); + + final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup); + + assertEquals(storageAPI.isAvailable("TESTSTORAGE"), + Availability.create("true")); + + assertSent(server, "POST", "/subscriptions/" + subsriptionId + + "/providers/Microsoft.Storage/checkNameAvailability?api-version=2015-06-15", String.format("{\"name\":\"TESTSTORAGE\",\"type\":\"Microsoft.Storage/storageAccounts\"}")); + } + + public void testGet() throws Exception { + server.enqueue(jsonResponse("/storageservices.json")); + + final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup); + + assertEquals(storageAPI.get("TESTSTORAGE"), expected().get(0)); + + assertSent(server, "GET", "/subscriptions/" + subsriptionId + "/resourcegroups/" + resourceGroup + + "/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE?api-version=2015-06-15"); + } + + public void testNullGet() throws Exception { + server.enqueue(new MockResponse().setResponseCode(404)); + + final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup); + + assertNull(storageAPI.get("TESTSTORAGE")); + + assertSent(server, "GET", "/subscriptions/" + subsriptionId + "/resourcegroups/" + resourceGroup + + "/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE?api-version=2015-06-15"); + } + + public void testGetKeys() throws Exception { + server.enqueue(jsonResponse("/storageaccountkeys.json")); + + final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup); + + assertEquals(storageAPI.getKeys("TESTSTORAGE"), StorageServiceKeys.create( + "bndO7lydwDkMo4Y0mFvmfLyi2f9aZY7bwfAVWoJWv4mOVK6E9c/exLnFsSm/NMWgifLCfxC/c6QBTbdEvWUA7w==", + "/jMLLT3kKqY4K+cUtJTbh7pCBdvG9EMKJxUvaJJAf6W6aUiZe1A1ulXHcibrqRVA2RJE0oUeXQGXLYJ2l85L7A==")); + + assertSent(server, "POST", "/subscriptions/" + subsriptionId + "/resourcegroups/" + resourceGroup + + "/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE/listKeys?api-version=2015-06-15"); + } + + public void testNullGetKeys() throws Exception { + server.enqueue(new MockResponse().setResponseCode(404)); + + final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup); + + assertNull(storageAPI.getKeys("TESTSTORAGE")); + + assertSent(server, "POST", "/subscriptions/" + subsriptionId + "/resourcegroups/" + resourceGroup + + "/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE/listKeys?api-version=2015-06-15"); + } + + public void testRegenerateKeys() throws Exception { + server.enqueue(jsonResponse("/storageaccountkeys.json")); + + final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup); + + assertEquals(storageAPI.regenerateKeys("TESTSTORAGE", "key1"), StorageServiceKeys.create( + "bndO7lydwDkMo4Y0mFvmfLyi2f9aZY7bwfAVWoJWv4mOVK6E9c/exLnFsSm/NMWgifLCfxC/c6QBTbdEvWUA7w==", + "/jMLLT3kKqY4K+cUtJTbh7pCBdvG9EMKJxUvaJJAf6W6aUiZe1A1ulXHcibrqRVA2RJE0oUeXQGXLYJ2l85L7A==")); + + assertSent(server, "POST", "/subscriptions/" + subsriptionId + "/resourcegroups/" + resourceGroup + + "/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE/regenerateKey?api-version=2015-06-15", String.format("{\"keyName\":\"key1\"}")); + } + + public void testUpdate() throws Exception { + server.enqueue(jsonResponse("/storageaccountupdate.json")); + + final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup); + + StorageServiceUpdateParams.StorageServiceUpdateProperties props = + StorageServiceUpdateParams.StorageServiceUpdateProperties.create(StorageService.AccountType.Standard_LRS); + + final StorageServiceUpdateParams params = storageAPI.update("TESTSTORAGE", + ImmutableMap.of("another_property_name", "another_property_value"), props); + + assertTrue(params.tags().containsKey("another_property_name")); + + assertSent(server, "PATCH", "/subscriptions/" + subsriptionId + "/resourcegroups/" + resourceGroup + + "/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE?api-version=2015-06-15", String.format("{\"properties\":{ \"accountType\": \"Standard_LRS\" },\"tags\":{\"another_property_name\":\"another_property_value\"}}")); + } + + public void testUpdateWithNullTagAndNullProperty() throws Exception { + server.enqueue(jsonResponse("/storageaccountupdate.json")); + + final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup); + + StorageServiceUpdateParams.StorageServiceUpdateProperties props = + StorageServiceUpdateParams.StorageServiceUpdateProperties.create(null); + + final StorageServiceUpdateParams params = storageAPI.update("TESTSTORAGE", null, props); + + assertTrue(params.tags().containsKey("another_property_name")); + + assertSent(server, "PATCH", "/subscriptions/" + subsriptionId + "/resourcegroups/" + resourceGroup + + "/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE?api-version=2015-06-15", String.format("{\"properties\":{}}")); + } + + public void testDelete() throws Exception { + server.enqueue(new MockResponse().setResponseCode(200)); + + final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup); + + boolean status = storageAPI.delete("TESTSTORAGE"); + assertTrue(status); + + assertSent(server, "DELETE", "/subscriptions/" + subsriptionId + "/resourcegroups/" + resourceGroup + + "/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE?api-version=2015-06-15"); + } + + public void testDelete204() throws Exception { + + server.enqueue(new MockResponse().setResponseCode(204)); + + final StorageAccountApi storageAPI = api.getStorageAccountApi(resourceGroup); + + boolean status = storageAPI.delete("TESTSTORAGE"); + assertFalse(status); + + assertSent(server, "DELETE", "/subscriptions/" + subsriptionId + "/resourcegroups/" + resourceGroup + + "/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(); + 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/"); + Map endpoints2 = new HashMap(); + endpoints2.put("blob", "https://TESTSTORAGE2.blob.core.windows.net/"); + endpoints2.put("file", "https://TESTSTORAGE2.file.core.windows.net/"); + endpoints2.put("queue", "https://TESTSTORAGE2.queue.core.windows.net/"); + endpoints2.put("table", "https://TESTSTORAGE2.table.core.windows.net/"); + Map secondaryEndpoints2 = new HashMap(); + secondaryEndpoints2.put("blob", "https://TESTSTORAGE2-secondary.blob.core.windows.net/"); + secondaryEndpoints2.put("queue", "https://TESTSTORAGE2-secondary.queue.core.windows.net/"); + secondaryEndpoints2.put("table", "https://TESTSTORAGE2-secondary.table.core.windows.net/"); + Map endpoints3 = new HashMap(); + endpoints3.put("blob", "https://TESTSTORAGE3.blob.core.windows.net/"); + endpoints3.put("file", "https://TESTSTORAGE3.file.core.windows.net/"); + endpoints3.put("queue", "https://TESTSTORAGE3.queue.core.windows.net/"); + endpoints3.put("table", "https://TESTSTORAGE3.table.core.windows.net/"); + Map secondaryEndpoints3 = new HashMap(); + secondaryEndpoints3.put("blob", "https://TESTSTORAGE3-secondary.blob.core.windows.net/"); + secondaryEndpoints3.put("queue", "https://TESTSTORAGE3-secondary.queue.core.windows.net/"); + secondaryEndpoints3.put("table", "https://TESTSTORAGE3-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 StorageService.StorageServiceProperties props2 = StorageService.StorageServiceProperties.create( + StorageService.AccountType.Standard_RAGRS, + DATE_SERVICE.iso8601DateOrSecondsDateParse("2016-02-24T13:11:43.8265672Z"), + endpoints2, location, + StorageService.Status.Succeeded, secondaryEndpoints2, secondaryLocation, + StorageService.RegionStatus.Available, + StorageService.RegionStatus.Available); + final StorageService.StorageServiceProperties props3 = StorageService.StorageServiceProperties.create( + StorageService.AccountType.Standard_RAGRS, + DATE_SERVICE.iso8601DateOrSecondsDateParse("2016-02-24T14:12:59.5223315Z"), + endpoints3, location, + StorageService.Status.Succeeded, secondaryEndpoints3, secondaryLocation, + StorageService.RegionStatus.Available, + StorageService.RegionStatus.Available); + + final Map tags = ImmutableMap.of( + "key1", "value1", + "key2", "value2"); + + return ImmutableList.of(StorageService.create( + "/subscriptions/SUBSCRIPTIONID/resourceGroups/resourceGroup/" + + "providers/Microsoft.Storage/storageAccounts/TESTSTORAGE", + "TESTSTORAGE", location, tags, "Microsoft.Storage/storageAccounts", props), + StorageService.create( + "/subscriptions/SUBSCRIPTIONID/resourceGroups/resourceGroup/" + + "providers/Microsoft.Storage/storageAccounts/TESTSTORAGE2", + "TESTSTORAGE2", location, tags, "Microsoft.Storage/storageAccounts", props2), + StorageService.create( + "/subscriptions/SUBSCRIPTIONID/resourceGroups/resourceGroup/" + + "providers/Microsoft.Storage/storageAccounts/TESTSTORAGE3", + "TESTSTORAGE3", location, tags, "Microsoft.Storage/storageAccounts", props3)); + } + +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java index fb2e42a3a3..657ebf7e2b 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java @@ -16,16 +16,41 @@ */ package org.jclouds.azurecompute.arm.internal; import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; +import com.google.common.base.Predicate; import com.google.common.collect.ImmutableMap; import org.jclouds.azurecompute.arm.domain.ResourceGroup; +import org.jclouds.azurecompute.arm.domain.StorageService; +import org.jclouds.azurecompute.arm.features.StorageAccountApi; +import org.jclouds.azurecompute.arm.functions.ParseJobStatus; +import org.jclouds.util.Predicates2; +import org.testng.Assert; import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; + +import java.net.URI; +import java.util.logging.Level; +import java.util.logging.Logger; public class BaseAzureComputeApiLiveTest extends AbstractAzureComputeApiLiveTest { public static final String LOCATION = "westeurope"; private String resourceGroupName = null; + protected StorageService storageService; + + + private String storageServiceName = null; + + protected String getStorageServiceName() { + if (storageServiceName == null) { + storageServiceName = String.format("%3.24s", + System.getProperty("user.name") + RAND + this.getClass().getSimpleName()).toLowerCase(); + } + return storageServiceName; + } + protected String getEndpoint() { String endpoint = null; if (System.getProperty("test.azurecompute-arm.endpoint") != null) { @@ -56,10 +81,45 @@ public class BaseAzureComputeApiLiveTest extends AbstractAzureComputeApiLiveTest } + @BeforeClass + @Override + public void setup() { + super.setup(); + + storageService = getOrCreateStorageService(getStorageServiceName()); + } + @AfterClass(alwaysRun = true) @Override protected void tearDown() { super.tearDown(); + Boolean status = api.getStorageAccountApi(getResourceGroupName()).delete(getStorageServiceName()); + assertTrue(status.booleanValue()); deleteResourceGroup(getResourceGroupName()); } + + protected StorageService getOrCreateStorageService(String storageServiceName) { + StorageAccountApi storageApi = api.getStorageAccountApi(getResourceGroupName()); + StorageService ss = storageApi.get(storageServiceName); + if (ss != null) { + return ss; + } + URI uri = storageApi.create(storageServiceName, LOCATION, ImmutableMap.of("property_name", + "property_value"), ImmutableMap.of("accountType", StorageService.AccountType.Standard_LRS.toString())); + if (uri != null){ + assertTrue(uri.toString().contains("api-version")); + + boolean jobDone = Predicates2.retry(new Predicate() { + @Override public boolean apply(URI uri) { + return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri); + } + }, 60 * 1 * 1000 /* 1 minute timeout */).apply(uri); + assertTrue(jobDone, "create operation did not complete in the configured timeout"); + } + ss = storageApi.get(storageServiceName); + Assert.assertEquals(ss.location(), LOCATION); + + Logger.getAnonymousLogger().log(Level.INFO, "created storageService: {0}", ss); + return ss; + } } 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 5a228f4ca0..82af9789a7 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 @@ -96,6 +96,11 @@ public class BaseAzureComputeApiMockTest { return new MockResponse().setStatus("HTTP/1.1 202 Accepted"); } + + protected MockResponse response204() { + return new MockResponse().setStatus("HTTP/1.1 204 No Content"); + } + protected MockResponse response202WithHeader() { return new MockResponse() .setStatus("HTTP/1.1 202 Accepted") diff --git a/providers/azurecompute-arm/src/test/resources/isavailablestorageservice.json b/providers/azurecompute-arm/src/test/resources/isavailablestorageservice.json new file mode 100644 index 0000000000..b6f2459b07 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/isavailablestorageservice.json @@ -0,0 +1,3 @@ +{ + "nameAvailable": true +} diff --git a/providers/azurecompute-arm/src/test/resources/storageAccounts.json b/providers/azurecompute-arm/src/test/resources/storageAccounts.json new file mode 100644 index 0000000000..3b7402e09e --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/storageAccounts.json @@ -0,0 +1,90 @@ +{ + "value": [{ + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/resourceGroup/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE", + "location": "westus", + "name": "TESTSTORAGE", + "properties": { + "accountType": "Standard_RAGRS", + "creationTime": "2016-02-24T13:04:45.0890883Z", + "primaryEndpoints": { + "blob": "https://TESTSTORAGE.blob.core.windows.net/", + "file": "https://TESTSTORAGE.file.core.windows.net/", + "queue": "https://TESTSTORAGE.queue.core.windows.net/", + "table": "https://TESTSTORAGE.table.core.windows.net/" + }, + "primaryLocation": "westus", + "provisioningState": "Succeeded", + "secondaryEndpoints": { + "blob": "https://TESTSTORAGE-secondary.blob.core.windows.net/", + "queue": "https://TESTSTORAGE-secondary.queue.core.windows.net/", + "table": "https://TESTSTORAGE-secondary.table.core.windows.net/" + }, + "secondaryLocation": "eastus", + "statusOfPrimary": "available", + "statusOfSecondary": "available" + }, + "tags": { + "key1": "value1", + "key2": "value2" + }, + "type": "Microsoft.Storage/storageAccounts" + }, { + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/resourceGroup/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE2", + "location": "westus", + "name": "TESTSTORAGE2", + "properties": { + "accountType": "Standard_RAGRS", + "creationTime": "2016-02-24T13:11:43.8265672Z", + "primaryEndpoints": { + "blob": "https://TESTSTORAGE2.blob.core.windows.net/", + "file": "https://TESTSTORAGE2.file.core.windows.net/", + "queue": "https://TESTSTORAGE2.queue.core.windows.net/", + "table": "https://TESTSTORAGE2.table.core.windows.net/" + }, + "primaryLocation": "westus", + "provisioningState": "Succeeded", + "secondaryEndpoints": { + "blob": "https://TESTSTORAGE2-secondary.blob.core.windows.net/", + "queue": "https://TESTSTORAGE2-secondary.queue.core.windows.net/", + "table": "https://TESTSTORAGE2-secondary.table.core.windows.net/" + }, + "secondaryLocation": "eastus", + "statusOfPrimary": "available", + "statusOfSecondary": "available" + }, + "tags": { + "key1": "value1", + "key2": "value2" + }, + "type": "Microsoft.Storage/storageAccounts" + }, { + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/resourceGroup/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE3", + "location": "westus", + "name": "TESTSTORAGE3", + "properties": { + "accountType": "Standard_RAGRS", + "creationTime": "2016-02-24T14:12:59.5223315Z", + "primaryEndpoints": { + "blob": "https://TESTSTORAGE3.blob.core.windows.net/", + "file": "https://TESTSTORAGE3.file.core.windows.net/", + "queue": "https://TESTSTORAGE3.queue.core.windows.net/", + "table": "https://TESTSTORAGE3.table.core.windows.net/" + }, + "primaryLocation": "westus", + "provisioningState": "Succeeded", + "secondaryEndpoints": { + "blob": "https://TESTSTORAGE3-secondary.blob.core.windows.net/", + "queue": "https://TESTSTORAGE3-secondary.queue.core.windows.net/", + "table": "https://TESTSTORAGE3-secondary.table.core.windows.net/" + }, + "secondaryLocation": "eastus", + "statusOfPrimary": "available", + "statusOfSecondary": "available" + }, + "tags": { + "key1": "value1", + "key2": "value2" + }, + "type": "Microsoft.Storage/storageAccounts" + }] +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/storageCreateResponse.json b/providers/azurecompute-arm/src/test/resources/storageCreateResponse.json new file mode 100644 index 0000000000..21813fc0b2 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/storageCreateResponse.json @@ -0,0 +1,9 @@ +{ + "location": "westus", + "tags": { + "property_name": "property_value" + }, + "properties": { + "accountType": "Premium_LRS" + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/storageaccountkeys.json b/providers/azurecompute-arm/src/test/resources/storageaccountkeys.json new file mode 100644 index 0000000000..bc90a40ca5 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/storageaccountkeys.json @@ -0,0 +1,4 @@ +{ + "key1": "bndO7lydwDkMo4Y0mFvmfLyi2f9aZY7bwfAVWoJWv4mOVK6E9c/exLnFsSm/NMWgifLCfxC/c6QBTbdEvWUA7w==", + "key2": "/jMLLT3kKqY4K+cUtJTbh7pCBdvG9EMKJxUvaJJAf6W6aUiZe1A1ulXHcibrqRVA2RJE0oUeXQGXLYJ2l85L7A==" +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/storageaccountupdate.json b/providers/azurecompute-arm/src/test/resources/storageaccountupdate.json new file mode 100644 index 0000000000..84f6028fa4 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/storageaccountupdate.json @@ -0,0 +1,7 @@ +{ + "properties": { + }, + "tags": { + "another_property_name": "another_property_value" + } +} diff --git a/providers/azurecompute-arm/src/test/resources/storageservices.json b/providers/azurecompute-arm/src/test/resources/storageservices.json new file mode 100644 index 0000000000..b56a67b547 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/storageservices.json @@ -0,0 +1,30 @@ +{ + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/resourceGroup/providers/Microsoft.Storage/storageAccounts/TESTSTORAGE", + "location": "westus", + "name": "TESTSTORAGE", + "properties": { + "accountType": "Standard_RAGRS", + "creationTime": "2016-02-24T13:04:45.0890883Z", + "primaryEndpoints": { + "blob": "https://TESTSTORAGE.blob.core.windows.net/", + "file": "https://TESTSTORAGE.file.core.windows.net/", + "queue": "https://TESTSTORAGE.queue.core.windows.net/", + "table": "https://TESTSTORAGE.table.core.windows.net/" + }, + "primaryLocation": "westus", + "provisioningState": "Succeeded", + "secondaryEndpoints": { + "blob": "https://TESTSTORAGE-secondary.blob.core.windows.net/", + "queue": "https://TESTSTORAGE-secondary.queue.core.windows.net/", + "table": "https://TESTSTORAGE-secondary.table.core.windows.net/" + }, + "secondaryLocation": "eastus", + "statusOfPrimary": "available", + "statusOfSecondary": "available" + }, + "tags": { + "key1": "value1", + "key2": "value2" + }, + "type": "Microsoft.Storage/storageAccounts" +} \ No newline at end of file From 8c7573164f26a3b7a75375e2ca4451074c4f38ac Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Thu, 21 Apr 2016 15:15:36 -0700 Subject: [PATCH 07/87] JCLOUDS-664 Azurecompute-arm VNetApi and SubnetApi --- .../azurecompute/arm/AzureComputeApi.java | 18 +++ .../arm/domain/ResourceGroup.java | 3 +- .../arm/domain/StorageService.java | 3 +- .../domain/StorageServiceUpdateParams.java | 3 +- .../azurecompute/arm/domain/Subnet.java | 97 ++++++++++++ .../arm/domain/VirtualNetwork.java | 111 ++++++++++++++ .../azurecompute/arm/features/SubnetApi.java | 75 ++++++++++ .../arm/features/VirtualNetworkApi.java | 76 ++++++++++ .../arm/functions/FalseOn204.java | 2 +- .../arm/features/SubnetApiLiveTest.java | 104 +++++++++++++ .../arm/features/SubnetApiMockTest.java | 140 ++++++++++++++++++ .../features/VirtualNetworkApiLiveTest.java | 102 +++++++++++++ .../features/VirtualNetworkApiMockTest.java | 137 +++++++++++++++++ .../internal/BaseAzureComputeApiLiveTest.java | 47 ++++++ .../src/test/resources/createsubnet.json | 5 + .../test/resources/createsubnetresponse.json | 14 ++ .../test/resources/createvirtualnetwork.json | 20 +++ .../src/test/resources/getonesubnet.json | 14 ++ .../listsubnetswithinvirtualnetwork.json | 18 +++ .../test/resources/listvirtualnetworks.json | 79 ++++++++++ .../src/test/resources/virtualnetwork.json | 20 +++ 21 files changed, 1084 insertions(+), 4 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Subnet.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualNetwork.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/SubnetApi.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApi.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/SubnetApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/SubnetApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/resources/createsubnet.json create mode 100644 providers/azurecompute-arm/src/test/resources/createsubnetresponse.json create mode 100644 providers/azurecompute-arm/src/test/resources/createvirtualnetwork.json create mode 100644 providers/azurecompute-arm/src/test/resources/getonesubnet.json create mode 100644 providers/azurecompute-arm/src/test/resources/listsubnetswithinvirtualnetwork.json create mode 100644 providers/azurecompute-arm/src/test/resources/listvirtualnetworks.json create mode 100644 providers/azurecompute-arm/src/test/resources/virtualnetwork.json 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 4204328a91..5b4d600e86 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 @@ -22,6 +22,8 @@ import org.jclouds.azurecompute.arm.features.JobApi; import org.jclouds.azurecompute.arm.features.LocationApi; import org.jclouds.azurecompute.arm.features.ResourceGroupApi; import org.jclouds.azurecompute.arm.features.StorageAccountApi; +import org.jclouds.azurecompute.arm.features.SubnetApi; +import org.jclouds.azurecompute.arm.features.VirtualNetworkApi; import org.jclouds.rest.annotations.Delegate; import javax.ws.rs.PathParam; @@ -60,5 +62,21 @@ public interface AzureComputeApi extends Closeable { */ @Delegate StorageAccountApi getStorageAccountApi(@PathParam("resourceGroup") String resourceGroup); + /** + * The Subnet API includes operations for managing the subnets in your virtual network. + * + * @see docs + */ + @Delegate + SubnetApi getSubnetApi(@PathParam("resourcegroup") String resourcegroup, + @PathParam("virtualnetwork") String virtualnetwork); + + /** + * The Virtual Network API includes operations for managing the virtual networks in your subscription. + * + * @see docs + */ + @Delegate + VirtualNetworkApi getVirtualNetworkApi(@PathParam("resourcegroup") String resourcegroup); } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceGroup.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceGroup.java index 08c41857b1..936b813a89 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceGroup.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceGroup.java @@ -41,11 +41,12 @@ public abstract class ResourceGroup { public abstract String name(); public abstract String location(); + @Nullable public abstract Map tags(); public abstract ResourceGroupProperties properties(); @SerializedNames({"id", "name", "location", "tags", "properties"}) public static ResourceGroup create(String id, String name, String location, Map tags, ResourceGroupProperties properties) { - return new AutoValue_ResourceGroup(id, name, location, tags == null ? ImmutableMap.builder().build() : ImmutableMap.copyOf(tags), properties); + return new AutoValue_ResourceGroup(id, name, location, tags == null ? null : ImmutableMap.copyOf(tags), properties); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageService.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageService.java index 08709d8f68..a151aec6ca 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageService.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageService.java @@ -160,6 +160,7 @@ public abstract class StorageService { /** * Specifies the tags of the storage account. */ + @Nullable public abstract Map tags(); /** @@ -178,6 +179,6 @@ public abstract class StorageService { public static StorageService create(final String id, final String name, final String location, final Map tags, final String type, final StorageServiceProperties storageServiceProperties) { - return new AutoValue_StorageService(id, name, location, tags == null ? ImmutableMap.builder().build() : ImmutableMap.copyOf(tags), type, storageServiceProperties); + return new AutoValue_StorageService(id, name, location, tags == null ? null : ImmutableMap.copyOf(tags), type, storageServiceProperties); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageServiceUpdateParams.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageServiceUpdateParams.java index 85b8b6da8f..692565c44c 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageServiceUpdateParams.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageServiceUpdateParams.java @@ -48,6 +48,7 @@ public abstract class StorageServiceUpdateParams { /** * Specifies the tags of the storage account. */ + @Nullable public abstract Map tags(); /** @@ -59,6 +60,6 @@ public abstract class StorageServiceUpdateParams { @SerializedNames({"tags", "properties"}) public static StorageServiceUpdateParams create(final Map tags, final StorageServiceUpdateProperties storageServiceProperties) { - return new AutoValue_StorageServiceUpdateParams(tags == null ? ImmutableMap.builder().build() : ImmutableMap.copyOf(tags), storageServiceProperties); + return new AutoValue_StorageServiceUpdateParams(tags == null ? null : ImmutableMap.copyOf(tags), storageServiceProperties); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Subnet.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Subnet.java new file mode 100644 index 0000000000..b195b7daeb --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Subnet.java @@ -0,0 +1,97 @@ +/* + * 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 static com.google.common.collect.ImmutableList.copyOf; + +import java.util.List; + +import org.jclouds.javax.annotation.Nullable; +import com.google.auto.value.AutoValue; +import org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class Subnet { + + @AutoValue + public abstract static class IpConfiguration { + + public abstract String id(); + + @SerializedNames({"id"}) + public static IpConfiguration create(final String id) { + return new AutoValue_Subnet_IpConfiguration(id); + } + } + + @AutoValue + public abstract static class SubnetProperties { + + @Nullable + public abstract String provisioningState(); + + @Nullable + public abstract String addressPrefix(); + + @Nullable + public abstract List ipConfigurations(); + + @SerializedNames({"provisioningState", "addressPrefix", "ipConfigurations"}) + public static SubnetProperties create(final String provisioningState, final String addressPrefix, final List ipConfigurations) { + return builder() + .provisioningState(provisioningState) + .addressPrefix(addressPrefix) + .ipConfigurations(ipConfigurations != null ? copyOf(ipConfigurations) : null) + .build(); + } + + public static Builder builder() { + return new AutoValue_Subnet_SubnetProperties.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder provisioningState(String provisioningState); + + public abstract Builder addressPrefix(String addressPrefix); + + public abstract Builder ipConfigurations(List ipConfigurations); + + public abstract SubnetProperties build(); + } + } + + @Nullable + public abstract String name(); + + @Nullable + public abstract String id(); + + @Nullable + public abstract String etag(); + + @Nullable + public abstract SubnetProperties properties(); + + @SerializedNames({"name", "id", "etag", "properties"}) + public static Subnet create(final String name, + final String id, + final String etag, + final SubnetProperties properties) { + return new AutoValue_Subnet(name, id, etag, properties); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualNetwork.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualNetwork.java new file mode 100644 index 0000000000..a7af6ec0ec --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualNetwork.java @@ -0,0 +1,111 @@ +/* + * 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 static com.google.common.collect.ImmutableList.copyOf; + +import java.util.Map; +import java.util.List; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableMap; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class VirtualNetwork { + + @AutoValue + public abstract static class AddressSpace { + + public abstract List addressPrefixes(); + + @SerializedNames({"addressPrefixes"}) + public static AddressSpace create(final List addressPrefixes) { + return new AutoValue_VirtualNetwork_AddressSpace(copyOf(addressPrefixes)); + } + } + + @AutoValue + public abstract static class VirtualNetworkProperties { + + @Nullable + public abstract String provisioningState(); + + @Nullable + public abstract String resourceGuid(); + + public abstract AddressSpace addressSpace(); + + @Nullable + public abstract List subnets(); + + + @SerializedNames({"provisioningState", "resourceGuid", "addressSpace", "subnets"}) + public static VirtualNetworkProperties create(final String provisioningState, final String resourceGuid, final AddressSpace addressSpace, final List subnets) { + return builder() + .provisioningState(provisioningState) + .resourceGuid(resourceGuid) + .addressSpace(addressSpace) + .subnets(subnets != null ? copyOf(subnets) : null) + .build(); + } + + public static Builder builder() { + return new AutoValue_VirtualNetwork_VirtualNetworkProperties.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder provisioningState(String provisioningState); + + public abstract Builder resourceGuid(String resourceGuid); + + public abstract Builder addressSpace(AddressSpace addressSpace); + + public abstract Builder subnets(List subnets); + + public abstract VirtualNetworkProperties build(); + } + } + + @Nullable + public abstract String name(); + + @Nullable + public abstract String id(); + + @Nullable + public abstract String etag(); + + public abstract String location(); + + public abstract VirtualNetworkProperties properties(); + + @Nullable + public abstract Map tags(); + + @SerializedNames({"name", "id", "etag", "location", "properties", "tags"}) + public static VirtualNetwork create(final String name, + final String id, + final String etag, + final String location, + final VirtualNetworkProperties properties, + final Map tags) { + return new AutoValue_VirtualNetwork(name, id, etag, location, properties, tags == null ? null : ImmutableMap.copyOf(tags)); + } +} 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 new file mode 100644 index 0000000000..1ac38d8b99 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/SubnetApi.java @@ -0,0 +1,75 @@ +/* + * 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.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 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.core.MediaType; +import java.util.List; + +@Path("/resourcegroups/{resourcegroup}/providers/Microsoft.Network/virtualNetworks/{virtualnetwork}/subnets") + +@QueryParams(keys = "api-version", values = "2015-06-15") +@RequestFilters(OAuthFilter.class) +@Consumes(MediaType.APPLICATION_JSON) +public interface SubnetApi { + + @Named("subnet:list") + @SelectJson("value") + @GET + @Fallback(EmptyListOnNotFoundOr404.class) + List list(); + + @Named("subnet:create_or_update") + @Path("/{subnetname}") + @MapBinder(BindToJsonPayload.class) + @PUT + Subnet createOrUpdate(@PathParam("subnetname") String name, + @PayloadParam("properties") Subnet.SubnetProperties properties); + + @Named("subnet:get") + @Path("/{subnetname}") + @GET + @Fallback(NullOnNotFoundOr404.class) + Subnet get(@PathParam("subnetname") String subnetname); + + @Named("subnet:delete") + @Path("/{subnetname}") + @DELETE + @ResponseParser(FalseOn204.class) + boolean delete(@PathParam("subnetname") String subnetname); +} 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 new file mode 100644 index 0000000000..0acbdeeca1 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApi.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.azurecompute.arm.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 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.core.MediaType; +import java.util.List; + +@Path("/resourcegroups/{resourcegroup}/providers/Microsoft.Network/virtualNetworks") +@QueryParams(keys = "api-version", values = "2015-06-15") +@RequestFilters(OAuthFilter.class) +@Consumes(MediaType.APPLICATION_JSON) +public interface VirtualNetworkApi { + + @Named("virtualnetwork:list") + @SelectJson("value") + @GET + @Fallback(EmptyListOnNotFoundOr404.class) + List list(); + + @Named("virtualnetwork:create_or_update") + @Path("/{virtualnetworkname}") + @MapBinder(BindToJsonPayload.class) + @PUT + VirtualNetwork createOrUpdate(@PathParam("virtualnetworkname") String virtualnetworkname, + @PayloadParam("location") String location, + @PayloadParam("properties")VirtualNetwork.VirtualNetworkProperties properties); + + @Named("virtualnetwork:get") + @Path("/{virtualnetworkname}") + @GET + @Fallback(NullOnNotFoundOr404.class) + VirtualNetwork get(@PathParam("virtualnetworkname") String virtualnetworkname); + + @Named("virtualnetwork:delete") + @Path("/{virtualnetworkname}") + @DELETE + @ResponseParser(FalseOn204.class) + boolean delete(@PathParam("virtualnetworkname") String virtualnetworkname); +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/FalseOn204.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/FalseOn204.java index 34c6d56ee1..6b73260215 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/FalseOn204.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/FalseOn204.java @@ -29,7 +29,7 @@ public class FalseOn204 implements Function { public Boolean apply(final HttpResponse from) { releasePayload(from); final int statusCode = from.getStatusCode(); - if (statusCode == 200) { + if (statusCode == 200 || statusCode == 202) { return true; } if (statusCode == 204) { diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/SubnetApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/SubnetApiLiveTest.java new file mode 100644 index 0000000000..9eaf990544 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/SubnetApiLiveTest.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.features; + +import org.jclouds.azurecompute.arm.domain.Subnet; + +import org.jclouds.azurecompute.arm.domain.VirtualNetwork; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.util.List; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertNotNull; + +@Test(groups = "live", singleThreaded = true) +public class SubnetApiLiveTest extends BaseAzureComputeApiLiveTest { + + private final String subscriptionid = "subscriptionid"; + private String resourcegroup; + + @BeforeClass + @Override + public void setup() { + super.setup(); + resourcegroup = getResourceGroupName(); + + // Subnets belong to a virtual network so that needs to be created first + // VN will be deleted when resource group is deleted + VirtualNetwork vn = getOrCreateVirtualNetwork(VIRTUAL_NETWORK_NAME); + assertNotNull(vn); + } + + @Test(groups = "live") + public void deleteSubnetResourceDoesNotExist() { + + final SubnetApi subnetApi = api.getSubnetApi(resourcegroup, VIRTUAL_NETWORK_NAME); + + boolean status = subnetApi.delete(DEFAULT_SUBNET_NAME); + assertFalse(status); + + } + + @Test(groups = "live", dependsOnMethods = "deleteSubnetResourceDoesNotExist") + public void createSubnet() { + + final SubnetApi subnetApi = api.getSubnetApi(resourcegroup, VIRTUAL_NETWORK_NAME); + + //Create properties object + //addressPrefix must match Virtual network address space! + Subnet.SubnetProperties properties = Subnet.SubnetProperties.builder().addressPrefix(DEFAULT_SUBNET_ADDRESS_SPACE).build(); + + Subnet subnet = subnetApi.createOrUpdate(DEFAULT_SUBNET_NAME, properties); + + assertEquals(subnet.name(), DEFAULT_SUBNET_NAME); + assertEquals(subnet.properties().addressPrefix(), DEFAULT_SUBNET_ADDRESS_SPACE); + } + + @Test(groups = "live", dependsOnMethods = "createSubnet") + public void getSubnet() { + + final SubnetApi subnetApi = api.getSubnetApi(resourcegroup, VIRTUAL_NETWORK_NAME); + Subnet subnet = subnetApi.get(DEFAULT_SUBNET_NAME); + + assertNotNull(subnet.name()); + assertNotNull(subnet.properties().addressPrefix()); + } + + @Test(groups = "live", dependsOnMethods = "createSubnet") + public void listSubnets() { + + final SubnetApi subnetApi = api.getSubnetApi(resourcegroup, VIRTUAL_NETWORK_NAME); + List subnets = subnetApi.list(); + + assertTrue(subnets.size() > 0); + } + + @Test(groups = "live", dependsOnMethods = {"listSubnets", "getSubnet"}, alwaysRun = true) + public void deleteSubnet() { + + final SubnetApi subnetApi = api.getSubnetApi(resourcegroup, VIRTUAL_NETWORK_NAME); + boolean status = subnetApi.delete(DEFAULT_SUBNET_NAME); + assertTrue(status); + } + +} 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 new file mode 100644 index 0000000000..bfcf188dc5 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/SubnetApiMockTest.java @@ -0,0 +1,140 @@ +/* + * 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 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; + + +@Test(groups = "unit", testName = "SubnetApiMockTest", singleThreaded = true) +public class SubnetApiMockTest extends BaseAzureComputeApiMockTest { + + private final String subscriptionid = "SUBSCRIPTIONID"; + private final String resourcegroup = "myresourcegroup"; + private final String virtualNetwork = "myvirtualnetwork"; + private final String subnetName = "mysubnet"; + private final String apiVersion = "api-version=2015-06-15"; + + public void createSubnet() throws InterruptedException { + + server.enqueue(jsonResponse("/createsubnetresponse.json").setResponseCode(200)); + + final SubnetApi subnetApi = api.getSubnetApi(resourcegroup, virtualNetwork); + + Subnet.SubnetProperties properties = Subnet.SubnetProperties.builder().addressPrefix("10.2.0.0/24").build(); + + Subnet subnet = subnetApi.createOrUpdate(subnetName, properties); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/virtualNetworks/%s/subnets/%s?%s", subscriptionid, resourcegroup, virtualNetwork, subnetName, apiVersion); + String json = "{ \"properties\":{\"addressPrefix\":\"10.2.0.0/24\"}}"; + assertSent(server, "PUT", path, json); + + assertEquals(subnet.name(), subnetName); + assertEquals(subnet.properties().addressPrefix(), "10.2.0.0/24"); + } + + public void getSubnet() throws InterruptedException { + + server.enqueue(jsonResponse("/getonesubnet.json").setResponseCode(200)); + + final SubnetApi subnetApi = api.getSubnetApi(resourcegroup, virtualNetwork); + + Subnet subnet = subnetApi.get(subnetName); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/virtualNetworks/%s/subnets/%s?%s", subscriptionid, resourcegroup, virtualNetwork, subnetName, apiVersion); + assertSent(server, "GET", path); + + assertEquals(subnet.name(), subnetName); + assertEquals(subnet.properties().addressPrefix(), "10.2.0.0/24"); + } + + public void getSubnetReturns404() throws InterruptedException { + server.enqueue(response404()); + + final SubnetApi subnetApi = api.getSubnetApi(resourcegroup, virtualNetwork); + + Subnet subnet = subnetApi.get(subnetName); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/virtualNetworks/%s/subnets/%s?%s", subscriptionid, resourcegroup, virtualNetwork, subnetName, apiVersion); + assertSent(server, "GET", path); + + assertNull(subnet); + } + + public void listSubnets() throws InterruptedException { + + server.enqueue(jsonResponse("/listsubnetswithinvirtualnetwork.json").setResponseCode(200)); + + final SubnetApi subnetApi = api.getSubnetApi(resourcegroup, virtualNetwork); + + List subnets = subnetApi.list(); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/virtualNetworks/%s/subnets?%s", subscriptionid, resourcegroup, virtualNetwork, apiVersion); + assertSent(server, "GET", path); + + assertTrue(subnets.size() > 0); + } + + public void listSubnetsReturns404() throws InterruptedException { + server.enqueue(response404()); + + final SubnetApi subnetApi = api.getSubnetApi(resourcegroup, virtualNetwork); + + List subnets = subnetApi.list(); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/virtualNetworks/%s/subnets?%s", subscriptionid, resourcegroup, virtualNetwork, apiVersion); + assertSent(server, "GET", path); + + assertTrue(isEmpty(subnets)); + } + + public void deleteSubnet() throws InterruptedException { + + server.enqueue(response202()); + + final SubnetApi subnetApi = api.getSubnetApi(resourcegroup, virtualNetwork); + + boolean status = subnetApi.delete(subnetName); + assertTrue(status); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/virtualNetworks/%s/subnets/%s?%s", subscriptionid, resourcegroup, virtualNetwork, subnetName, apiVersion); + assertSent(server, "DELETE", path); + } + + public void deleteSubnetResourceDoesNotExist() throws InterruptedException { + + server.enqueue(response204()); + + final SubnetApi subnetApi = api.getSubnetApi(resourcegroup, virtualNetwork); + + boolean status = subnetApi.delete(subnetName); + 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); + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApiLiveTest.java new file mode 100644 index 0000000000..71ad0b030b --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApiLiveTest.java @@ -0,0 +1,102 @@ +/* + * 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.azurecompute.arm.domain.VirtualNetwork; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertNotNull; + +@Test(groups = "live", singleThreaded = true) +public class VirtualNetworkApiLiveTest extends BaseAzureComputeApiLiveTest { + + private final String subscriptionid = "subscriptionid"; + private String resourcegroup; + + @BeforeClass + @Override + public void setup() { + super.setup(); + resourcegroup = getResourceGroupName(); + } + + @Test(groups = "live") + public void deleteVirtualNetworkResourceDoesNotExist() { + + final VirtualNetworkApi vnApi = api.getVirtualNetworkApi(resourcegroup); + + boolean status = vnApi.delete(VIRTUAL_NETWORK_NAME); + assertFalse(status); + + } + + @Test(groups = "live", dependsOnMethods = "deleteVirtualNetworkResourceDoesNotExist") + public void createVirtualNetwork() { + + final VirtualNetworkApi vnApi = api.getVirtualNetworkApi(resourcegroup); + + //Create properties object + + final VirtualNetwork.VirtualNetworkProperties virtualNetworkProperties = + VirtualNetwork.VirtualNetworkProperties.builder().addressSpace( + VirtualNetwork.AddressSpace.create(Arrays.asList(DEFAULT_VIRTUALNETWORK_ADDRESS_PREFIX))).build(); + + VirtualNetwork vn = vnApi.createOrUpdate(VIRTUAL_NETWORK_NAME, LOCATION, virtualNetworkProperties); + + assertEquals(VIRTUAL_NETWORK_NAME, vn.name()); + assertEquals(LOCATION, vn.location()); + } + + @Test(groups = "live", dependsOnMethods = "createVirtualNetwork") + public void getVirtualNetwork() { + + final VirtualNetworkApi vnApi = api.getVirtualNetworkApi(resourcegroup); + VirtualNetwork vn = vnApi.get(VIRTUAL_NETWORK_NAME); + + assertNotNull(vn.name()); + assertNotNull(vn.location()); + assertNotNull(vn.properties().addressSpace().addressPrefixes()); + } + + @Test(groups = "live", dependsOnMethods = "createVirtualNetwork") + public void listVirtualNetworks() { + + final VirtualNetworkApi vnApi = api.getVirtualNetworkApi(resourcegroup); + List vnList = vnApi.list(); + + assertTrue(vnList.size() > 0); + } + + @Test(groups = "live", dependsOnMethods = {"listVirtualNetworks", "getVirtualNetwork"}, alwaysRun = true) + public void deleteVirtualNetwork() { + + final VirtualNetworkApi vnApi = api.getVirtualNetworkApi(resourcegroup); + + boolean status = vnApi.delete(VIRTUAL_NETWORK_NAME); + assertTrue(status); + } + +} 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 new file mode 100644 index 0000000000..99b0b57e77 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApiMockTest.java @@ -0,0 +1,137 @@ +/* + * 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.azurecompute.arm.domain.VirtualNetwork; + +import org.testng.annotations.Test; + +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; + +import java.util.Arrays; +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; + +@Test(groups = "unit", testName = "VirtualNetworkApiMockTest", singleThreaded = true) +public class VirtualNetworkApiMockTest extends BaseAzureComputeApiMockTest { + + private final String subscriptionid = "SUBSCRIPTIONID"; + private final String resourcegroup = "myresourcegroup"; + private final String virtualNetwork = "mockvirtualnetwork"; + private final String apiVersion = "api-version=2015-06-15"; + private final String location = "westeurope"; + + public void getVirtualNetwork() throws InterruptedException { + server.enqueue(jsonResponse("/virtualnetwork.json")); + + final VirtualNetworkApi vnApi = api.getVirtualNetworkApi(resourcegroup); + VirtualNetwork vn = vnApi.get(virtualNetwork); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/virtualNetworks/%s?%s", subscriptionid, resourcegroup, virtualNetwork, apiVersion); + assertSent(server, "GET", path); + assertEquals(vn.name(), "mockvirtualnetwork"); + assertEquals(vn.properties().resourceGuid(), "1568c76a-73a4-4a60-8dfb-53b823197ccb"); + assertEquals(vn.properties().addressSpace().addressPrefixes().get(0), "10.2.0.0/16"); + assertEquals(vn.tags().get("tagkey"), "tagvalue"); + } + + public void getVirtualNetworkReturns404() throws InterruptedException { + server.enqueue(response404()); + + final VirtualNetworkApi vnApi = api.getVirtualNetworkApi(resourcegroup); + VirtualNetwork vn = vnApi.get(virtualNetwork); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/virtualNetworks/%s?%s", subscriptionid, resourcegroup, virtualNetwork, apiVersion); + assertSent(server, "GET", path); + + assertNull(vn); + } + + public void listVirtualNetworks() throws InterruptedException { + server.enqueue(jsonResponse("/listvirtualnetworks.json")); + + final VirtualNetworkApi vnApi = api.getVirtualNetworkApi(resourcegroup); + List vnList = vnApi.list(); + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/virtualNetworks?%s", subscriptionid, resourcegroup, apiVersion); + + assertSent(server, "GET", path); + assertEquals(vnList.size(), 3); + } + + public void listVirtualNetworkReturns404() throws InterruptedException { + server.enqueue(response404()); + + final VirtualNetworkApi vnApi = api.getVirtualNetworkApi(resourcegroup); + List vnList = vnApi.list(); + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/virtualNetworks?%s", subscriptionid, resourcegroup, apiVersion); + + assertSent(server, "GET", path); + + assertTrue(isEmpty(vnList)); + } + + public void createVirtualNetwork() throws InterruptedException { + + server.enqueue(jsonResponse("/createvirtualnetwork.json").setStatus("HTTP/1.1 201 Created")); + + final VirtualNetworkApi vnApi = api.getVirtualNetworkApi(resourcegroup); + + final VirtualNetwork.VirtualNetworkProperties virtualNetworkProperties = + VirtualNetwork.VirtualNetworkProperties.create(null, null, + VirtualNetwork.AddressSpace.create(Arrays.asList("10.2.0.0/16")), null); + + + VirtualNetwork vn = 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"); + assertSent(server, "PUT", path, json); + } + + public void deleteVirtualNetwork() throws InterruptedException { + + server.enqueue(response202()); + + final VirtualNetworkApi vnApi = api.getVirtualNetworkApi(resourcegroup); + + boolean status = vnApi.delete(virtualNetwork); + assertTrue(status); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/virtualNetworks/%s?%s", subscriptionid, resourcegroup, virtualNetwork, apiVersion); + assertSent(server, "DELETE", path); + + } + + public void deleteVirtualNetworkResourceDoesNotExist() throws InterruptedException { + + server.enqueue(response204()); + + final VirtualNetworkApi vnApi = api.getVirtualNetworkApi(resourcegroup); + + boolean status = vnApi.delete(virtualNetwork); + assertFalse(status); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/virtualNetworks/%s?%s", subscriptionid, resourcegroup, virtualNetwork, apiVersion); + assertSent(server, "DELETE", path); + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java index 657ebf7e2b..b1d97b8b03 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java @@ -23,7 +23,11 @@ import com.google.common.collect.ImmutableMap; import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.domain.StorageService; +import org.jclouds.azurecompute.arm.domain.Subnet; +import org.jclouds.azurecompute.arm.domain.VirtualNetwork; import org.jclouds.azurecompute.arm.features.StorageAccountApi; +import org.jclouds.azurecompute.arm.features.SubnetApi; +import org.jclouds.azurecompute.arm.features.VirtualNetworkApi; import org.jclouds.azurecompute.arm.functions.ParseJobStatus; import org.jclouds.util.Predicates2; import org.testng.Assert; @@ -31,11 +35,21 @@ import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import java.net.URI; +import java.util.Arrays; import java.util.logging.Level; import java.util.logging.Logger; public class BaseAzureComputeApiLiveTest extends AbstractAzureComputeApiLiveTest { public static final String LOCATION = "westeurope"; + + public static final String DEFAULT_SUBNET_ADDRESS_SPACE = "10.2.0.0/23"; + + public static final String VIRTUAL_NETWORK_NAME = "jclouds-virtual-network-live-test"; + + public static final String DEFAULT_SUBNET_NAME = "jclouds-1"; + + public static final String DEFAULT_VIRTUALNETWORK_ADDRESS_PREFIX = "10.2.0.0/16"; + private String resourceGroupName = null; protected StorageService storageService; @@ -122,4 +136,37 @@ public class BaseAzureComputeApiLiveTest extends AbstractAzureComputeApiLiveTest Logger.getAnonymousLogger().log(Level.INFO, "created storageService: {0}", ss); return ss; } + + protected VirtualNetwork getOrCreateVirtualNetwork(final String virtualNetworkName) { + + VirtualNetworkApi vnApi = api.getVirtualNetworkApi(getResourceGroupName()); + VirtualNetwork vn = vnApi.get(virtualNetworkName); + + if (vn != null) { + return vn; + } + + final VirtualNetwork.VirtualNetworkProperties virtualNetworkProperties = + VirtualNetwork.VirtualNetworkProperties.create(null, null, + VirtualNetwork.AddressSpace.create(Arrays.asList(DEFAULT_VIRTUALNETWORK_ADDRESS_PREFIX)), null); + + + vn = vnApi.createOrUpdate(VIRTUAL_NETWORK_NAME, LOCATION, virtualNetworkProperties); + return vn; + } + + protected Subnet getOrCreateSubnet(final String subnetName, final String virtualNetworkName){ + + SubnetApi subnetApi = api.getSubnetApi(getResourceGroupName(), virtualNetworkName); + Subnet subnet = subnetApi.get(subnetName); + + if (subnet != null){ + return subnet; + } + + Subnet.SubnetProperties properties = Subnet.SubnetProperties.builder().addressPrefix(DEFAULT_SUBNET_ADDRESS_SPACE).build(); + subnet = subnetApi.createOrUpdate(subnetName, properties); + + return subnet; + } } diff --git a/providers/azurecompute-arm/src/test/resources/createsubnet.json b/providers/azurecompute-arm/src/test/resources/createsubnet.json new file mode 100644 index 0000000000..2be56235bf --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/createsubnet.json @@ -0,0 +1,5 @@ +{ + "properties":{ + "addressPrefix":"10.2.0.0/24" + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/createsubnetresponse.json b/providers/azurecompute-arm/src/test/resources/createsubnetresponse.json new file mode 100644 index 0000000000..d88579c67f --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/createsubnetresponse.json @@ -0,0 +1,14 @@ +{ + "name": "mysubnet", + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/azurearmtesting/providers/Microsoft.Network/virtualNetworks/myvirtualnetwork/subnets/mysubnet", + "etag": "W/\"b68ab7a3-38d5-4690-a978-20149a6a0994\"", + "properties": { + "provisioningState": "Succeeded", + "addressPrefix": "10.2.0.0/24", + "ipConfigurations": [ + { + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/azurearmtesting/providers/Microsoft.Network/networkInterfaces/myNic/ipConfigurations/myip1" + } + ] + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/createvirtualnetwork.json b/providers/azurecompute-arm/src/test/resources/createvirtualnetwork.json new file mode 100644 index 0000000000..4ad5ec2aa8 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/createvirtualnetwork.json @@ -0,0 +1,20 @@ +{ + "name": "mockvirtualnetwork", + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/azurearmtesting/providers/Microsoft.Network/virtualNetworks/mockvirtualnetwork", + "etag": "W/\"bb0f3bf7-381e-424b-8e00-8f813c61956c\"", + "type": "Microsoft.Network/virtualNetworks", + "location": "westeurope", + "tags": { + "key": "value" + }, + "properties": { + "provisioningState": "Updating", + "resourceGuid": "5192bdb3-f6ed-44ad-bf4c-059cff905791", + "addressSpace": { + "addressPrefixes": [ + "10.2.0.0/16" + ] + }, + "subnets": [] + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/getonesubnet.json b/providers/azurecompute-arm/src/test/resources/getonesubnet.json new file mode 100644 index 0000000000..6044ddfebd --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/getonesubnet.json @@ -0,0 +1,14 @@ +{ + "name": "mysubnet", + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/azurearmtesting/providers/Microsoft.Network/virtualNetworks/myvirtualnetwork/subnets/mysubnet", + "etag": "W/\"bc7e1d77-eec0-4b91-ae80-afc33cf3c867\"", + "properties": { + "provisioningState": "Succeeded", + "addressPrefix": "10.2.0.0/24", + "ipConfigurations": [ + { + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/azurearmtesting/providers/Microsoft.Network/networkInterfaces/myNic/ipConfigurations/myip1" + } + ] + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/listsubnetswithinvirtualnetwork.json b/providers/azurecompute-arm/src/test/resources/listsubnetswithinvirtualnetwork.json new file mode 100644 index 0000000000..82f52ceed1 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/listsubnetswithinvirtualnetwork.json @@ -0,0 +1,18 @@ +{ + "value": [ + { + "name": "mysubnet", + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/azurearmtesting/providers/Microsoft.Network/virtualNetworks/myvirtualnetwork/subnets/mysubnet", + "etag": "W/\"bc7e1d77-eec0-4b91-ae80-afc33cf3c867\"", + "properties": { + "provisioningState": "Succeeded", + "addressPrefix": "10.2.0.0/24", + "ipConfigurations": [ + { + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/azurearmtesting/providers/Microsoft.Network/networkInterfaces/myNic/ipConfigurations/myip1" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/listvirtualnetworks.json b/providers/azurecompute-arm/src/test/resources/listvirtualnetworks.json new file mode 100644 index 0000000000..d71cf33608 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/listvirtualnetworks.json @@ -0,0 +1,79 @@ +{ + "value": [ + { + "name": "mockvirtualnetwork", + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/azurearmtesting/providers/Microsoft.Network/virtualNetworks/mockvirtualnetwork", + "etag": "W/\"0dcd223f-670c-49ca-abe7-5978d127c131\"", + "type": "Microsoft.Network/virtualNetworks", + "location": "westeurope", + "tags": { + "key": "value" + }, + "properties": { + "provisioningState": "Succeeded", + "resourceGuid": "1568c76a-73a4-4a60-8dfb-53b823197ccb", + "addressSpace": { + "addressPrefixes": [ + "10.2.0.0/16" + ] + }, + "subnets": [] + } + }, + { + "name": "anothervirtualnetworks", + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/azurearmtesting/providers/Microsoft.Network/virtualNetworks/anothervirtualnetworks", + "etag": "W/\"7604d8fe-f3b8-4fd4-ae52-ab503cc29097\"", + "type": "Microsoft.Network/virtualNetworks", + "location": "westeurope", + "tags": { + "key": "value" + }, + "properties": { + "provisioningState": "Succeeded", + "resourceGuid": "5192bdb3-f6ed-44ad-bf4c-059cff905791", + "addressSpace": { + "addressPrefixes": [ + "10.2.0.0/16" + ] + }, + "subnets": [] + } + }, + { + "name": "myvirtualnetwork", + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/azurearmtesting/providers/Microsoft.Network/virtualNetworks/myvirtualnetwork", + "etag": "W/\"bc7e1d77-eec0-4b91-ae80-afc33cf3c867\"", + "type": "Microsoft.Network/virtualNetworks", + "location": "westeurope", + "tags": { + "key": "value" + }, + "properties": { + "provisioningState": "Succeeded", + "resourceGuid": "8da85637-833c-4445-a681-81ca3fb90044", + "addressSpace": { + "addressPrefixes": [ + "10.2.0.0/16" + ] + }, + "subnets": [ + { + "name": "mysubnet", + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/azurearmtesting/providers/Microsoft.Network/virtualNetworks/myvirtualnetwork/subnets/mysubnet", + "etag": "W/\"bc7e1d77-eec0-4b91-ae80-afc33cf3c867\"", + "properties": { + "provisioningState": "Succeeded", + "addressPrefix": "10.2.0.0/24", + "ipConfigurations": [ + { + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/azurearmtesting/providers/Microsoft.Network/networkInterfaces/myNic/ipConfigurations/myip1" + } + ] + } + } + ] + } + } + ] +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/virtualnetwork.json b/providers/azurecompute-arm/src/test/resources/virtualnetwork.json new file mode 100644 index 0000000000..73bd45ca02 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/virtualnetwork.json @@ -0,0 +1,20 @@ +{ + "name": "mockvirtualnetwork", + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/azurearmtesting/providers/Microsoft.Network/virtualNetworks/mockvirtualnetwork", + "etag": "W/\"0dcd223f-670c-49ca-abe7-5978d127c131\"", + "type": "Microsoft.Network/virtualNetworks", + "location": "northeurope", + "tags": { + "tagkey": "tagvalue" + }, + "properties": { + "provisioningState": "Succeeded", + "resourceGuid": "1568c76a-73a4-4a60-8dfb-53b823197ccb", + "addressSpace": { + "addressPrefixes": [ + "10.2.0.0/16" + ] + }, + "subnets": [] + } + } \ No newline at end of file From a266511f18edb1043ab7f8b4b2664d96cfea63c8 Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Wed, 27 Apr 2016 16:36:14 -0700 Subject: [PATCH 08/87] JCLOUDS-664 Azurecompute-arm NicApi PublicIPApi and VMApi --- .../azurecompute/arm/AzureComputeApi.java | 35 ++- .../arm/domain/AvailabilitySet.java | 104 ++++++++ .../domain/AvailabilitySetVirtualMachine.java | 37 +++ .../azurecompute/arm/domain/DataDisk.java | 80 ++++++ .../arm/domain/DiagnosticsProfile.java | 68 +++++ .../azurecompute/arm/domain/DnsSettings.java | 57 ++++ .../arm/domain/HardwareProfile.java | 45 ++++ .../azurecompute/arm/domain/IdReference.java | 34 +++ .../arm/domain/ImageReference.java | 80 ++++++ .../arm/domain/IpConfiguration.java | 66 +++++ .../arm/domain/IpConfigurationProperties.java | 72 +++++ .../arm/domain/NetworkInterfaceCard.java | 56 ++++ .../NetworkInterfaceCardProperties.java | 78 ++++++ .../arm/domain/NetworkProfile.java | 55 ++++ .../azurecompute/arm/domain/OSDisk.java | 85 ++++++ .../azurecompute/arm/domain/OSProfile.java | 236 +++++++++++++++++ .../arm/domain/PublicIPAddress.java | 52 ++++ .../arm/domain/PublicIPAddressProperties.java | 83 ++++++ .../arm/domain/StorageProfile.java | 78 ++++++ .../azurecompute/arm/domain/Subnet.java | 10 +- .../jclouds/azurecompute/arm/domain/VHD.java | 45 ++++ .../arm/domain/VirtualMachine.java | 69 +++++ .../arm/domain/VirtualMachineInstance.java | 72 +++++ .../arm/domain/VirtualMachineProperties.java | 133 ++++++++++ .../arm/domain/VirtualNetwork.java | 12 +- .../arm/features/NetworkInterfaceCardApi.java | 78 ++++++ .../arm/features/PublicIPAddressApi.java | 78 ++++++ .../arm/features/VirtualMachineApi.java | 135 ++++++++++ .../NetworkInterfaceCardApiLiveTest.java | 139 ++++++++++ .../NetworkInterfaceCardApiMockTest.java | 150 +++++++++++ .../features/PublicIPAddressApiLiveTest.java | 129 +++++++++ .../features/PublicIPAddressApiMockTest.java | 179 +++++++++++++ .../features/VirtualMachineApiLiveTest.java | 245 +++++++++++++++++ .../features/VirtualMachineApiMockTest.java | 249 ++++++++++++++++++ .../AbstractAzureComputeApiLiveTest.java | 2 +- .../internal/BaseAzureComputeApiLiveTest.java | 48 +++- .../test/resources/PublicIPAddressCreate.json | 20 ++ .../PublicIPAddressCreateDnsRecordInUse.json | 7 + .../resources/PublicIPAddressGetInfo.json | 24 ++ .../test/resources/PublicIPAddressList.json | 80 ++++++ .../resources/createnetworkinterfacecard.json | 35 +++ .../createvirtualmachineresponse.json | 47 ++++ .../resources/getnetworkinterfacecard.json | 35 +++ .../test/resources/listnetworkinterfaces.json | 68 +++++ .../src/test/resources/resourcegroups.json | 1 - .../src/test/resources/virtualmachine.json | 47 ++++ .../resources/virtualmachineInstance.json | 40 +++ .../src/test/resources/virtualmachines.json | 57 ++++ 48 files changed, 3625 insertions(+), 10 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/AvailabilitySet.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/AvailabilitySetVirtualMachine.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DataDisk.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DiagnosticsProfile.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DnsSettings.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/HardwareProfile.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IdReference.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IpConfiguration.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IpConfigurationProperties.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCard.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCardProperties.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkProfile.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSProfile.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/PublicIPAddress.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/PublicIPAddressProperties.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageProfile.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VHD.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachine.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineInstance.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineProperties.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApi.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApi.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualMachineApi.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/resources/PublicIPAddressCreate.json create mode 100644 providers/azurecompute-arm/src/test/resources/PublicIPAddressCreateDnsRecordInUse.json create mode 100644 providers/azurecompute-arm/src/test/resources/PublicIPAddressGetInfo.json create mode 100644 providers/azurecompute-arm/src/test/resources/PublicIPAddressList.json create mode 100644 providers/azurecompute-arm/src/test/resources/createnetworkinterfacecard.json create mode 100644 providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json create mode 100644 providers/azurecompute-arm/src/test/resources/getnetworkinterfacecard.json create mode 100644 providers/azurecompute-arm/src/test/resources/listnetworkinterfaces.json create mode 100644 providers/azurecompute-arm/src/test/resources/virtualmachine.json create mode 100644 providers/azurecompute-arm/src/test/resources/virtualmachineInstance.json create mode 100644 providers/azurecompute-arm/src/test/resources/virtualmachines.json 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 5b4d600e86..f8ac6e9ba0 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,21 +16,23 @@ */ package org.jclouds.azurecompute.arm; -import java.io.Closeable; - 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.PublicIPAddressApi; import org.jclouds.azurecompute.arm.features.ResourceGroupApi; 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.rest.annotations.Delegate; import javax.ws.rs.PathParam; +import java.io.Closeable; /** * The Azure Resource Manager API is a REST API for managing your services and deployments. - *

+ *

* * @see doc */ @@ -62,6 +64,7 @@ public interface AzureComputeApi extends Closeable { */ @Delegate StorageAccountApi getStorageAccountApi(@PathParam("resourceGroup") String resourceGroup); + /** * The Subnet API includes operations for managing the subnets in your virtual network. * @@ -79,4 +82,30 @@ public interface AzureComputeApi extends Closeable { @Delegate VirtualNetworkApi getVirtualNetworkApi(@PathParam("resourcegroup") String resourcegroup); + + /** + * The Network Interface Card API includes operations for managing the NICs in your subscription. + * + * @see docs + */ + @Delegate + NetworkInterfaceCardApi getNetworkInterfaceCardApi(@PathParam("resourcegroup") String resourcegroup); + + /** + * The Public IP Address API includes operations for managing public ID Addresses for NICs in your subscription. + * + * @see docs + */ + @Delegate + PublicIPAddressApi getPublicIPAddressApi(@PathParam("resourcegroup") String resourcegroup); + + + /** + * The Virtual Machine API includes operations for managing the virtual machines in your subscription. + * + * @see docs + */ + @Delegate + VirtualMachineApi getVirtualMachineApi(@PathParam("resourceGroup") String resourceGroup); + } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/AvailabilitySet.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/AvailabilitySet.java new file mode 100644 index 0000000000..cb903074c1 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/AvailabilitySet.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.domain; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; +import java.util.Map; +import java.util.List; + +/** + * AvailabilitySet for subscription + */ +@AutoValue +public abstract class AvailabilitySet { + + @AutoValue + public abstract static class AvailabilitySetProperties { + + /** + * A platform Update Domain Count + */ + public abstract int platformUpdateDomainCount(); + + /** + * A platform Fault Domain Count + */ + public abstract int platformFaultDomainCount(); + + /** + * A list of virtual machines in availability set + */ + @Nullable + public abstract List virtualMachines(); + + @SerializedNames({"platformUpdateDomainCount", "platformFaultDomainCount", "virtualMachines"}) + public static AvailabilitySetProperties create(final int platformUpdateDomainCount, + final int platformFaultDomainCount, + List virtualMachines) { + return new AutoValue_AvailabilitySet_AvailabilitySetProperties(platformUpdateDomainCount, + platformFaultDomainCount, + virtualMachines == null ? null : ImmutableList.copyOf(virtualMachines)); + } + } + + /** + * The id of the availability set + */ + public abstract String id(); + + /** + * The name of the availability set. + */ + @Nullable + public abstract String name(); + + /** + * The name of the availability set. + */ + @Nullable + public abstract String type(); + + /** + * The location of the availability set + */ + @Nullable + public abstract String location(); + + /** + * Specifies the tags of the availability set + */ + @Nullable + public abstract Map tags(); + + /** + * Specifies the properties of the availability set + */ + @Nullable + public abstract AvailabilitySetProperties properties(); + + + @SerializedNames({"id", "name", "type", "location", "tags", "properties"}) + public static AvailabilitySet create(final String id, final String name, final String type, final String location, + final Map tags, AvailabilitySetProperties properties) { + return new AutoValue_AvailabilitySet(id, name, type, location, tags == null ? null : ImmutableMap.copyOf(tags), properties); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/AvailabilitySetVirtualMachine.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/AvailabilitySetVirtualMachine.java new file mode 100644 index 0000000000..3837ff2ec6 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/AvailabilitySetVirtualMachine.java @@ -0,0 +1,37 @@ +/* + * 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 org.jclouds.json.SerializedNames; + +/** + * The virtual machine id + */ +@AutoValue +public abstract class AvailabilitySetVirtualMachine { + + /** + * The id of the virtual machine. + */ + public abstract String id(); + + @SerializedNames({"id"}) + public static AvailabilitySetVirtualMachine create(final String id) { + return new AutoValue_AvailabilitySetVirtualMachine(id); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DataDisk.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DataDisk.java new file mode 100644 index 0000000000..de1fa366fa --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DataDisk.java @@ -0,0 +1,80 @@ +/* + * 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 org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class DataDisk { + + /** + * The name of the data disk + */ + public abstract String name(); + + /** + * The size of the data disk + */ + public abstract String diskSizeGB(); + + /** + * The lun value of the data disk + */ + public abstract int lun(); + + /** + * The vhd of the data disk + */ + public abstract VHD vhd(); + + /** + * The create option of the data disk + */ + public abstract String createOption(); + + @SerializedNames({"name", "diskSizeGB", "lun", "vhd", "createOption"}) + public static DataDisk create(final String name, final String diskSizeGB, final int lun, + final VHD vhd, final String createOption) { + return builder() + .name(name) + .diskSizeGB(diskSizeGB) + .lun(lun) + .createOption(createOption) + .vhd(vhd) + .build(); + } + + public static Builder builder() { + return new AutoValue_DataDisk.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder name(String name); + + public abstract Builder diskSizeGB(String diskSizeGB); + + public abstract Builder createOption(String createOption); + + public abstract Builder lun(int lun); + + public abstract Builder vhd(VHD vhd); + + public abstract DataDisk build(); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DiagnosticsProfile.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DiagnosticsProfile.java new file mode 100644 index 0000000000..6097e595f6 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DiagnosticsProfile.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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class DiagnosticsProfile { + + @AutoValue + public abstract static class BootDiagnostics{ + + public abstract boolean enabled(); + + @Nullable + public abstract String storageUri(); + + @SerializedNames({"enabled", "storageUri"}) + public static BootDiagnostics create(final boolean enabled, final String storageUri) { + return builder() + .enabled(enabled) + .storageUri(storageUri) + .build(); + } + + public static Builder builder() { + return new AutoValue_DiagnosticsProfile_BootDiagnostics.Builder(); + } + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder enabled(boolean enabled); + public abstract Builder storageUri(String storageUri); + public abstract BootDiagnostics build(); + } + } + + public abstract BootDiagnostics bootDiagnostics(); + + @SerializedNames({"bootDiagnostics"}) + public static DiagnosticsProfile create(final BootDiagnostics bootDiagnostics) { + return builder().bootDiagnostics(bootDiagnostics).build(); + } + public static Builder builder() { + return new AutoValue_DiagnosticsProfile.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder bootDiagnostics(BootDiagnostics bootDiagnostics); + public abstract DiagnosticsProfile build(); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DnsSettings.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DnsSettings.java new file mode 100644 index 0000000000..a527eb0592 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DnsSettings.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.domain; + +import com.google.auto.value.AutoValue; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class DnsSettings { + + public abstract String domainNameLabel(); + + @Nullable + public abstract String fqdn(); + + @Nullable + public abstract String reverseFqdn(); + + @SerializedNames({"domainNameLabel", "fqdn", "reverseFqdn"}) + public static DnsSettings create(final String domainNameLabel, final String fqdn, final String reverseFqdn) { + return builder() + .domainNameLabel(domainNameLabel) + .fqdn(fqdn) + .reverseFqdn(reverseFqdn) + .build(); + } + + public static Builder builder() { + return new AutoValue_DnsSettings.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder domainNameLabel(String domainNameLabel); + + public abstract Builder fqdn(String fqdn); + + public abstract Builder reverseFqdn(String reverseFqdn); + + public abstract DnsSettings build(); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/HardwareProfile.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/HardwareProfile.java new file mode 100644 index 0000000000..ee9a5f1a87 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/HardwareProfile.java @@ -0,0 +1,45 @@ +/* + * 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 org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class HardwareProfile { + + /** + * The vm size of the virtual machine. + */ + public abstract String vmSize(); + + @SerializedNames({"vmSize"}) + public static HardwareProfile create(final String vmSize) { + return builder().vmSize(vmSize).build(); + } + + public static Builder builder() { + return new AutoValue_HardwareProfile.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder vmSize(String vmSize); + + public abstract HardwareProfile build(); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IdReference.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IdReference.java new file mode 100644 index 0000000000..1854897e65 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IdReference.java @@ -0,0 +1,34 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +// Simple helper class to serialize / deserialize id reference. + +@AutoValue +public abstract class IdReference { + @Nullable + public abstract String id(); + + @SerializedNames({"id"}) + public static IdReference create(final String id) { + return new AutoValue_IdReference(id); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java new file mode 100644 index 0000000000..9cc67478af --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java @@ -0,0 +1,80 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class ImageReference { + + /** + * The publisher of the image reference. + */ + @Nullable + public abstract String publisher(); + + /** + * The offer of the image reference. + */ + @Nullable + public abstract String offer(); + + /** + * The sku of the image reference. + */ + @Nullable + public abstract String sku(); + + /** + * The version of the image reference. + */ + @Nullable + public abstract String version(); + + @SerializedNames({"publisher", "offer", "sku", "version"}) + public static ImageReference create(final String publisher, + final String offer, + final String sku, + final String version) { + + return builder() + .publisher(publisher) + .offer(offer) + .sku(sku) + .version(version) + .build(); + } + + public static Builder builder() { + return new AutoValue_ImageReference.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder publisher(String publisher); + + public abstract Builder offer(String offer); + + public abstract Builder sku(String sku); + + public abstract Builder version(String version); + + public abstract ImageReference build(); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IpConfiguration.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IpConfiguration.java new file mode 100644 index 0000000000..bb49a77a1e --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IpConfiguration.java @@ -0,0 +1,66 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class IpConfiguration { + + @Nullable + public abstract String name(); + + @Nullable + public abstract String id(); + + @Nullable + public abstract String etag(); + + @Nullable + public abstract Boolean primary(); + + @Nullable + public abstract IpConfigurationProperties properties(); + + @SerializedNames({"name", "id", "etag", "primary", "properties"}) + public static IpConfiguration create(final String name, final String id, final String etag, final Boolean primary, final IpConfigurationProperties properties) { + return builder() + .name(name) + .id(id) + .etag(etag) + .primary(primary) + .properties(properties) + .build(); + } + + public static Builder builder() { + return new AutoValue_IpConfiguration.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder name(String name); + public abstract Builder id(String id); + public abstract Builder etag(String etag); + public abstract Builder primary(Boolean primary); + public abstract Builder properties(IpConfigurationProperties properties); + public abstract IpConfiguration build(); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IpConfigurationProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IpConfigurationProperties.java new file mode 100644 index 0000000000..8e3bd5341e --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IpConfigurationProperties.java @@ -0,0 +1,72 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class IpConfigurationProperties { + + @Nullable + public abstract String provisioningState(); + + @Nullable + public abstract String privateIPAddress(); + + @Nullable + public abstract String privateIPAllocationMethod(); + + @Nullable + public abstract IdReference subnet(); + + @Nullable + public abstract IdReference publicIPAddress(); + + @SerializedNames({"provisioningState", "privateIPAddress", "privateIPAllocationMethod", "subnet", "publicIPAddress"}) + public static IpConfigurationProperties create(final String provisioningState, final String privateIPAddress, final String privateIPAllocationMethod, final IdReference subnet, final IdReference publicIPAddress) { + + return builder() + .provisioningState(provisioningState) + .privateIPAddress(privateIPAddress) + .privateIPAllocationMethod(privateIPAllocationMethod) + .subnet(subnet) + .publicIPAddress(publicIPAddress) + .build(); + } + + public static Builder builder() { + return new AutoValue_IpConfigurationProperties.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder provisioningState(String provisioningState); + + public abstract Builder privateIPAddress(String privateIPAddress); + + public abstract Builder privateIPAllocationMethod(String privateIPAllocationMethod); + + public abstract Builder subnet(IdReference subnet); + + public abstract Builder publicIPAddress(IdReference publicIPAddress); + + public abstract IpConfigurationProperties build(); + } +} + diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCard.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCard.java new file mode 100644 index 0000000000..567addc553 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCard.java @@ -0,0 +1,56 @@ +/* + * 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.ImmutableMap; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import java.util.Map; + +@AutoValue +public abstract class NetworkInterfaceCard { + + @Nullable + public abstract String name(); + + @Nullable + public abstract String id(); + + @Nullable + public abstract String etag(); + + @Nullable + public abstract String location(); + + @Nullable + public abstract NetworkInterfaceCardProperties properties(); + + @Nullable + public abstract Map tags(); + + @SerializedNames({"name", "id", "etag", "location", "properties", "tags"}) + public static NetworkInterfaceCard create(final String name, + final String id, + final String etag, + final String location, + final NetworkInterfaceCardProperties properties, + final Map tags) { + return new AutoValue_NetworkInterfaceCard(name, id, etag, location, properties, tags == null ? null : ImmutableMap.copyOf(tags)); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCardProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCardProperties.java new file mode 100644 index 0000000000..e6f2de7dac --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCardProperties.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.domain; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import java.util.List; + +@AutoValue +public abstract class NetworkInterfaceCardProperties { + + @Nullable + public abstract String provisioningState(); + + @Nullable + public abstract String resourceGuid(); + + @Nullable + public abstract Boolean enableIPForwarding(); + + @Nullable + public abstract List ipConfigurations(); + + @SerializedNames({"provisioningState", "resourceGuid", "enableIPForwarding", "ipConfigurations"}) + public static NetworkInterfaceCardProperties create(final String provisioningState, final String resourceGuid, final Boolean enableIPForwarding, final List ipConfigurations) { + NetworkInterfaceCardProperties.Builder builder = NetworkInterfaceCardProperties.builder() + .provisioningState(provisioningState) + .resourceGuid(resourceGuid) + .enableIPForwarding(enableIPForwarding) + .ipConfigurations(ipConfigurations == null ? null : ImmutableList.copyOf(ipConfigurations)); + + return builder.build(); + } + + public static Builder builder() { + + return new AutoValue_NetworkInterfaceCardProperties.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder provisioningState(String provisioningState); + + public abstract Builder resourceGuid(String resourceGuid); + + public abstract Builder enableIPForwarding(Boolean enableIPForwarding); + + public abstract Builder ipConfigurations(List ipConfigurations); + + abstract List ipConfigurations(); + + abstract NetworkInterfaceCardProperties autoBuild(); + + public NetworkInterfaceCardProperties build() { + ipConfigurations(ipConfigurations() != null ? ImmutableList.copyOf(ipConfigurations()) : null); + return autoBuild(); + } + } +} + + diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkProfile.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkProfile.java new file mode 100644 index 0000000000..ffcf9ee405 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkProfile.java @@ -0,0 +1,55 @@ +/* + * 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 NetworkProfile { + + /** + * List of network interfaces + */ + public abstract List networkInterfaces(); + + @SerializedNames({"networkInterfaces"}) + public static NetworkProfile create(final List networkInterfaces) { + return builder().networkInterfaces(networkInterfaces).build(); + } + + public static Builder builder() { + return new AutoValue_NetworkProfile.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder networkInterfaces(List networkInterfaces); + + abstract List networkInterfaces(); + + abstract NetworkProfile autoBuild(); + + public NetworkProfile build() { + networkInterfaces(networkInterfaces() != null ? ImmutableList.copyOf(networkInterfaces()) : ImmutableList.of()); + return autoBuild(); + } + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java new file mode 100644 index 0000000000..a9f7349ce5 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java @@ -0,0 +1,85 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class OSDisk { + /** + * The OS type of the os disk + */ + @Nullable + public abstract String osType(); + + /** + * The name of the os disk + */ + @Nullable + public abstract String name(); + + /** + * The vhd of the os disk + */ + @Nullable + public abstract VHD vhd(); + + /** + * The caching mode of the os disk + */ + @Nullable + public abstract String caching(); + + /** + * The create options of the os disk + */ + @Nullable + public abstract String createOption(); + + @SerializedNames({"osType", "name", "vhd", "caching", "createOption"}) + public static OSDisk create(final String osType, final String name, final VHD vhd, + final String caching, final String createOption) { + return builder() + .osType(osType) + .name(name) + .vhd(vhd) + .caching(caching) + .createOption(createOption) + .build(); + } + + public static Builder builder() { + return new AutoValue_OSDisk.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder osType(String osType); + + public abstract Builder name(String name); + + public abstract Builder caching(String caching); + + public abstract Builder createOption(String createOption); + + public abstract Builder vhd(VHD vhd); + + public abstract OSDisk build(); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSProfile.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSProfile.java new file mode 100644 index 0000000000..9240824cf1 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSProfile.java @@ -0,0 +1,236 @@ +/* + * 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.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import java.util.List; +import java.util.Map; +import com.google.common.collect.ImmutableMap; + +@AutoValue +public abstract class OSProfile { + + @AutoValue + public abstract static class LinuxConfiguration { + + @AutoValue + public abstract static class SSH { + + @AutoValue + public abstract static class SSHPublicKey { + + @Nullable + public abstract String path(); + + @Nullable + public abstract String keyData(); + + @SerializedNames({"path", "keyData"}) + public static SSHPublicKey create(final String path, final String keyData) { + + return new AutoValue_OSProfile_LinuxConfiguration_SSH_SSHPublicKey( + path, keyData); + } + } + + /** + * The list of public keys and paths + */ + @Nullable + public abstract List publicKeys(); + + @SerializedNames({"publicKeys"}) + public static SSH create(final List publicKeys) { + + return new AutoValue_OSProfile_LinuxConfiguration_SSH( + publicKeys); + } + } + + /** + * The authentication method password or ssh + */ + public abstract String disablePasswordAuthentication(); + + /** + * ssh keys + */ + @Nullable + public abstract SSH ssh(); + + @SerializedNames({"disablePasswordAuthentication", "ssh"}) + public static LinuxConfiguration create(final String disablePasswordAuthentication, + final SSH ssh) { + + return new AutoValue_OSProfile_LinuxConfiguration(disablePasswordAuthentication, + ssh); + } + } + + @AutoValue + public abstract static class WindowsConfiguration { + + @AutoValue + public abstract static class WinRM { + + /** + * Map of different settings + */ + public abstract Map listeners(); + + @SerializedNames({"listeners"}) + public static WinRM create(final Map listeners) { + return new AutoValue_OSProfile_WindowsConfiguration_WinRM(listeners == null ? ImmutableMap.of() : ImmutableMap.copyOf(listeners)); + } + } + + @AutoValue + public abstract static class AdditionalUnattendContent { + + public abstract String pass(); + + public abstract String component(); + + public abstract String settingName(); + + public abstract String content(); + + @SerializedNames({"pass", "component", "settingName", "content"}) + public static AdditionalUnattendContent create(final String pass, final String component, + final String settingName, + final String content) { + + return new AutoValue_OSProfile_WindowsConfiguration_AdditionalUnattendContent( + pass, component, settingName, content); + } + } + + /** + * The provision VM Agent true of false. + */ + public abstract boolean provisionVMAgent(); + + /** + * winR + */ + @Nullable + public abstract WinRM winRM(); + + /** + * unattend content + */ + @Nullable + public abstract AdditionalUnattendContent additionalUnattendContent(); + + /** + * is automatic updates enabled + */ + public abstract boolean enableAutomaticUpdates(); + + /** + * list of certificates + */ + @Nullable + public abstract List secrets(); + + @SerializedNames({"provisionVMAgent", "winRM", "additionalUnattendContent", "enableAutomaticUpdates", + "secrets"}) + public static WindowsConfiguration create(final boolean provisionVMAgent, final WinRM winRM, + final AdditionalUnattendContent additionalUnattendContent, + final boolean enableAutomaticUpdates, final List secrets) { + + return new AutoValue_OSProfile_WindowsConfiguration(provisionVMAgent, winRM, + additionalUnattendContent, enableAutomaticUpdates, secrets == null ? null : ImmutableList.copyOf(secrets)); + } + } + + /** + * The computer name of the VM + */ + @Nullable + public abstract String computerName(); + + /** + * The admin username of the VM + */ + @Nullable + public abstract String adminUsername(); + + /** + * The admin password of the VM + */ + @Nullable + public abstract String adminPassword(); + + /** + * The custom data of the VM + */ + @Nullable + public abstract String customData(); + + /** + * The linux configuration of the VM + */ + @Nullable + public abstract LinuxConfiguration linuxConfiguration(); + + /** + * The windows configuration of the VM + */ + @Nullable + public abstract WindowsConfiguration windowsConfiguration(); + + @SerializedNames({"computerName", "adminUsername", "adminPassword", "customData", "linuxConfiguration", + "windowsConfiguration"}) + public static OSProfile create(final String computerName, final String adminUsername, final String adminPassword, + final String customData, final LinuxConfiguration linuxConfiguration, + final WindowsConfiguration windowsConfiguration) { + return builder() + .computerName(computerName) + .adminUsername(adminUsername) + .adminPassword(adminPassword) + .customData(customData) + .linuxConfiguration(linuxConfiguration) + .windowsConfiguration(windowsConfiguration) + .build(); + } + + public static Builder builder() { + return new AutoValue_OSProfile.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder computerName(String computerName); + + public abstract Builder adminUsername(String adminUsername); + + public abstract Builder adminPassword(String adminPassword); + + public abstract Builder customData(String customData); + + public abstract Builder linuxConfiguration(LinuxConfiguration linuxConfiguration); + + public abstract Builder windowsConfiguration(WindowsConfiguration windowsConfiguration); + + public abstract OSProfile build(); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/PublicIPAddress.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/PublicIPAddress.java new file mode 100644 index 0000000000..a08faddf63 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/PublicIPAddress.java @@ -0,0 +1,52 @@ +/* + * 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.ImmutableMap; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import java.util.Map; + +@AutoValue +public abstract class PublicIPAddress { + + public abstract String name(); + + public abstract String id(); + + public abstract String etag(); + + public abstract String location(); + + @Nullable + public abstract Map tags(); + + public abstract PublicIPAddressProperties properties(); + + @SerializedNames({"name", "id", "etag", "location", "tags", "properties"}) + public static PublicIPAddress create(final String name, + final String id, + final String etag, + final String location, + final Map tags, + final PublicIPAddressProperties properties) { + return new AutoValue_PublicIPAddress(name, id, etag, location, tags == null ? null : ImmutableMap.copyOf(tags), properties); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/PublicIPAddressProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/PublicIPAddressProperties.java new file mode 100644 index 0000000000..2fc7fb5d47 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/PublicIPAddressProperties.java @@ -0,0 +1,83 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class PublicIPAddressProperties { + + @Nullable // needs to be nullable to create the payload for create request + public abstract String provisioningState(); + + @Nullable // only set in succeeded provisioningState for Static IP and for Dynamic when attached to a NIC + public abstract String ipAddress(); + + public abstract String publicIPAllocationMethod(); + + @Nullable + public abstract Integer idleTimeoutInMinutes(); + + @Nullable // only if attached to NIC + public abstract IdReference ipConfiguration(); + + @Nullable // only if DNS name is set + public abstract DnsSettings dnsSettings(); + + @SerializedNames({"provisioningState", "ipAddress", "publicIPAllocationMethod", "idleTimeoutInMinutes", "ipConfiguration", "dnsSettings"}) + public static PublicIPAddressProperties create(final String provisioningState, + final String ipAddress, + final String publicIPAllocationMethod, + final Integer idleTimeoutInMinutes, + final IdReference ipConfiguration, + final DnsSettings dnsSettings) { + return builder() + .provisioningState(provisioningState) + .ipAddress(ipAddress) + .publicIPAllocationMethod(publicIPAllocationMethod) + .idleTimeoutInMinutes(idleTimeoutInMinutes) + .ipConfiguration(ipConfiguration) + .dnsSettings(dnsSettings) + .publicIPAllocationMethod(publicIPAllocationMethod) + .dnsSettings(dnsSettings) + .build(); + } + + public static Builder builder() { + return new AutoValue_PublicIPAddressProperties.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder provisioningState(String provisioningState); + + public abstract Builder ipAddress(String ipAddress); + + public abstract Builder publicIPAllocationMethod(String publicIPAllocationMethod); + + public abstract Builder idleTimeoutInMinutes(Integer idleTimeoutInMinutes); + + public abstract Builder ipConfiguration(IdReference ipConfiguration); + + public abstract Builder dnsSettings(DnsSettings dnsSettings); + + public abstract PublicIPAddressProperties build(); + } + +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageProfile.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageProfile.java new file mode 100644 index 0000000000..7c693ef2e0 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageProfile.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.domain; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import java.util.List; + +@AutoValue +public abstract class StorageProfile { + + /** + * The image reference of the storage profile + */ + public abstract ImageReference imageReference(); + + /** + * The image reference of the storage profile + */ + public abstract OSDisk osDisk(); + + /** + * The list of the data disks of the storage profile + */ + @Nullable + public abstract List dataDisks(); + + @SerializedNames({"imageReference", "osDisk", "dataDisks"}) + public static StorageProfile create(final ImageReference imageReference, + final OSDisk osDisk, final List dataDisks) { + StorageProfile.Builder builder = StorageProfile.builder() + .imageReference(imageReference) + .osDisk(osDisk) + .dataDisks(dataDisks != null ? ImmutableList.copyOf(dataDisks) : null); + + return builder.build(); + } + + public static Builder builder() { + return new AutoValue_StorageProfile.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder imageReference(ImageReference imageReference); + + public abstract Builder osDisk(OSDisk osDisk); + + public abstract Builder dataDisks(List dataDisks); + + abstract List dataDisks(); + + abstract StorageProfile autoBuild(); + + public StorageProfile build() { + dataDisks(dataDisks() != null ? ImmutableList.copyOf(dataDisks()) : null); + return autoBuild(); + } + } + +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Subnet.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Subnet.java index b195b7daeb..e4024df93a 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Subnet.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Subnet.java @@ -20,6 +20,7 @@ import static com.google.common.collect.ImmutableList.copyOf; import java.util.List; +import com.google.common.collect.ImmutableList; import org.jclouds.javax.annotation.Nullable; import com.google.auto.value.AutoValue; import org.jclouds.json.SerializedNames; @@ -71,7 +72,14 @@ public abstract class Subnet { public abstract Builder ipConfigurations(List ipConfigurations); - public abstract SubnetProperties build(); + abstract List ipConfigurations(); + + abstract SubnetProperties autoBuild(); + + public SubnetProperties build() { + ipConfigurations(ipConfigurations() != null ? ImmutableList.copyOf(ipConfigurations()) : null); + return autoBuild(); + } } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VHD.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VHD.java new file mode 100644 index 0000000000..3b1421a3af --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VHD.java @@ -0,0 +1,45 @@ +/* + * 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 org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class VHD { + + /** + * The uri of the vhd. + */ + public abstract String uri(); + + @SerializedNames({"uri"}) + public static VHD create(final String uri) { + return builder().uri(uri).build(); + } + + public static Builder builder() { + return new AutoValue_VHD.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder uri(String uri); + + public abstract VHD 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 new file mode 100644 index 0000000000..71387e6712 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachine.java @@ -0,0 +1,69 @@ +/* + * 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.ImmutableMap; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import java.util.Map; + +/** + * A virtual machine that is valid for your subscription. + */ +@AutoValue +public abstract class VirtualMachine { + + /** + * The id of the virtual machine. + */ + public abstract String id(); + + /** + * The name of the virtual machine + */ + public abstract String name(); + + /** + * The type of the virtual machine . + */ + public abstract String type(); + + /** + * The localized name of the virtual machine . + */ + public abstract String location(); + + /** + * Specifies the tags of the vm + */ + @Nullable + public abstract Map tags(); + + /** + * Specifies the properties of the vm + */ + public abstract VirtualMachineProperties properties(); + + @SerializedNames({"id", "name", "type", "location", "tags", "properties"}) + public static VirtualMachine create(final String id, final String name, final String type, final String location, + @Nullable final Map tags, VirtualMachineProperties properties) { + + return new AutoValue_VirtualMachine(id, name, location, type, tags == null ? null : ImmutableMap.copyOf(tags), properties); + } +} 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 new file mode 100644 index 0000000000..b0ed6d5ea3 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineInstance.java @@ -0,0 +1,72 @@ +/* + * 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 java.util.List; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import java.util.Date; + +/** + * A virtual machine instance view that is valid for your subscription. + */ +@AutoValue +public abstract class VirtualMachineInstance { + + @AutoValue + public abstract static class VirtualMachineStatus { + + @Nullable + public abstract String code(); + + @Nullable + public abstract String level(); + + @Nullable + public abstract String displayStatus(); + + @Nullable + public abstract Date time(); + + @SerializedNames({"code", "level", "displayStatus", "time"}) + public static VirtualMachineStatus create(final String code, final String level, final String displayStatus, + final Date time) { + + return new AutoValue_VirtualMachineInstance_VirtualMachineStatus(code, level, displayStatus, time); + } + } + + @Nullable + public abstract String platformUpdateDomain(); + + @Nullable + public abstract String platformFaultDomain(); + + @Nullable + public abstract List statuses(); + + + @SerializedNames({"platformUpdateDomain", "platformFaultDomain", "statuses"}) + public static VirtualMachineInstance create(final String platformUpdateDomain, final String platformFaultDomain, + final List statuses) { + + return new AutoValue_VirtualMachineInstance(platformUpdateDomain, platformFaultDomain, statuses == null ? null : ImmutableList.copyOf(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 new file mode 100644 index 0000000000..73afd14678 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineProperties.java @@ -0,0 +1,133 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +/** + * A virtual machine properties for the virtual machine. + */ +@AutoValue +public abstract class VirtualMachineProperties { + + /** + * The id of the virtual machine. + */ + @Nullable + public abstract String vmId(); + + /** + * The license type of the virtual machine. + */ + @Nullable + public abstract String licenseType(); + + /** + * The availability set of the virtual machine + */ + @Nullable + public abstract AvailabilitySet availabilitySet(); + + /** + * The hardware Profile of the virtual machine . + */ + @Nullable + public abstract HardwareProfile hardwareProfile(); + + /** + * The Storage Profile of the virtual machine . + */ + @Nullable + public abstract StorageProfile storageProfile(); + + /** + * The OS Profile of the virtual machine . + */ + @Nullable + public abstract OSProfile osProfile(); + + /** + * The network profile of the VM + */ + @Nullable + public abstract NetworkProfile networkProfile(); + + /** + * The diagnostics profile of the VM + */ + @Nullable + public abstract DiagnosticsProfile diagnosticsProfile(); + + /** + * The provisioning state of the VM + */ + @Nullable + public abstract String provisioningState(); + + @SerializedNames({"vmId", "licenseType", "availabilitySet", "hardwareProfile", "storageProfile", "osProfile", + "networkProfile", "diagnosticsProfile", "provisioningState"}) + public static VirtualMachineProperties create(final String vmId, + final String licenseType, + final AvailabilitySet availabilitySet, + final HardwareProfile hardwareProfile, + final StorageProfile storageProfile, + final OSProfile osProfile, + final NetworkProfile networkProfile, + final DiagnosticsProfile diagnosticsProfile, + final String provisioningState) { + return builder() + .vmId(vmId) + .licenseType(licenseType) + .availabilitySet(availabilitySet) + .hardwareProfile(hardwareProfile) + .storageProfile(storageProfile) + .osProfile(osProfile) + .networkProfile(networkProfile) + .diagnosticsProfile(diagnosticsProfile) + .provisioningState(provisioningState) + .build(); + } + + public static Builder builder() { + return new AutoValue_VirtualMachineProperties.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder vmId(String vmId); + + public abstract Builder licenseType(String licenseType); + + public abstract Builder availabilitySet(AvailabilitySet availabilitySet); + + public abstract Builder hardwareProfile(HardwareProfile hardwareProfile); + + public abstract Builder storageProfile(StorageProfile storageProfile); + + public abstract Builder osProfile(OSProfile osProfile); + + public abstract Builder networkProfile(NetworkProfile networkProfile); + + public abstract Builder diagnosticsProfile(DiagnosticsProfile diagnosticsProfile); + + public abstract Builder provisioningState(String provisioningState); + + public abstract VirtualMachineProperties build(); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualNetwork.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualNetwork.java index a7af6ec0ec..d5eddf03e4 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualNetwork.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualNetwork.java @@ -20,6 +20,7 @@ import static com.google.common.collect.ImmutableList.copyOf; import java.util.Map; import java.util.List; +import com.google.common.collect.ImmutableList; import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableMap; @@ -36,7 +37,7 @@ public abstract class VirtualNetwork { @SerializedNames({"addressPrefixes"}) public static AddressSpace create(final List addressPrefixes) { - return new AutoValue_VirtualNetwork_AddressSpace(copyOf(addressPrefixes)); + return new AutoValue_VirtualNetwork_AddressSpace(addressPrefixes == null ? ImmutableList.of() : ImmutableList.copyOf(addressPrefixes)); } } @@ -79,7 +80,14 @@ public abstract class VirtualNetwork { public abstract Builder subnets(List subnets); - public abstract VirtualNetworkProperties build(); + abstract List subnets(); + + abstract VirtualNetworkProperties autoBuild(); + + public VirtualNetworkProperties build() { + subnets(subnets() != null ? ImmutableList.copyOf(subnets()) : null); + return autoBuild(); + } } } 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 new file mode 100644 index 0000000000..c7c665d78f --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApi.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.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.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 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.core.MediaType; +import java.util.List; +import java.util.Map; + +@Path("/resourcegroups/{resourcegroup}/providers/Microsoft.Network/networkInterfaces") +@QueryParams(keys = "api-version", values = "2015-06-15") +@RequestFilters(OAuthFilter.class) +@Consumes(MediaType.APPLICATION_JSON) + +public interface NetworkInterfaceCardApi { + + @Named("networkinterfacecard:list") + @SelectJson("value") + @GET + @Fallback(EmptyListOnNotFoundOr404.class) + List list(); + + @Named("networkinterfacecard:create_or_update") + @Path("/{networkinterfacecardname}") + @MapBinder(BindToJsonPayload.class) + @PUT + NetworkInterfaceCard createOrUpdate(@PathParam("networkinterfacecardname") String networkinterfacecardname, + @PayloadParam("location") String location, + @PayloadParam("properties") NetworkInterfaceCardProperties properties, + @PayloadParam("tags") Map tags); + + @Named("networkinterfacecard:get") + @Path("/{networkinterfacecardname}") + @GET + @Fallback(NullOnNotFoundOr404.class) + NetworkInterfaceCard get(@PathParam("networkinterfacecardname") String networkinterfacecardname); + + @Named("networkinterfacecard:delete") + @Path("/{networkinterfacecardname}") + @DELETE + @ResponseParser(FalseOn204.class) + boolean delete(@PathParam("networkinterfacecardname") String networkinterfacecardname); +} 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 new file mode 100644 index 0000000000..2e19fe2d04 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApi.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.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 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.core.MediaType; +import java.util.List; +import java.util.Map; + +@Path("/resourcegroups/{resourcegroup}/providers/Microsoft.Network/publicIPAddresses") +@QueryParams(keys = "api-version", values = "2015-06-15") +@RequestFilters(OAuthFilter.class) +@Consumes(MediaType.APPLICATION_JSON) + +public interface PublicIPAddressApi { + + @Named("publicipaddress:list") + @SelectJson("value") + @GET + @Fallback(EmptyListOnNotFoundOr404.class) + List list(); + + @Named("publicipaddress:create_or_update") + @Path("/{publicipaddressname}") + @MapBinder(BindToJsonPayload.class) + @PUT + PublicIPAddress createOrUpdate(@PathParam("publicipaddressname") String publicipaddressname, + @PayloadParam("location") String location, + @PayloadParam("tags") Map tags, + @PayloadParam("properties") PublicIPAddressProperties properties); + + @Named("publicipaddress:get") + @Path("/{publicipaddressname}") + @GET + @Fallback(NullOnNotFoundOr404.class) + PublicIPAddress get(@PathParam("publicipaddressname") String publicipaddressname); + + @Named("publicipaddress:delete") + @Path("/{publicipaddressname}") + @DELETE + @ResponseParser(FalseOn204.class) + boolean delete(@PathParam("publicipaddressname") String publicipaddressname); +} 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 new file mode 100644 index 0000000000..468906485e --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualMachineApi.java @@ -0,0 +1,135 @@ +/* + * 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; +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.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.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; +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") +@Consumes(MediaType.APPLICATION_JSON) +public interface VirtualMachineApi { + + /** + * The Get Virtual Machine details + */ + @Named("GetVirtualMachine") + @GET + @Path("/{name}") + @Fallback(Fallbacks.NullOnNotFoundOr404.class) + VirtualMachine get(@PathParam("name") String name); + + /** + * The Get Virtual Machine details + */ + @Named("GetVirtualMachineInstance") + @GET + @Path("/{name}/instanceView") + @Fallback(Fallbacks.NullOnNotFoundOr404.class) + VirtualMachineInstance getInstanceDetails(@PathParam("name") String name); + + /** + * The Create Virtual Machine + */ + @Named("CreateVirtualMachine") + @PUT + @Payload("%7B\"location\":\"{location}\",\"tags\":%7B%7D,\"properties\":{properties}%7D") + @MapBinder(BindToJsonPayload.class) + @Path("/{vmname}") + @QueryParams(keys = "validating", values = "false") + @Produces(MediaType.APPLICATION_JSON) + VirtualMachine create(@PathParam("vmname") String vmname, + @PayloadParam("location") String location, + @PayloadParam("properties") VirtualMachineProperties properties); + + /** + * The List Virtual Machines operation + */ + @Named("ListVirtualMachines") + @GET + @SelectJson("value") + @Fallback(Fallbacks.EmptyListOnNotFoundOr404.class) + List list(); + + /** + * The Delete Virtual Machine operation + */ + @Named("DeleteVirtualMachine") + @DELETE + @Path("/{name}") + @ResponseParser(URIParser.class) + @Fallback(Fallbacks.NullOnNotFoundOr404.class) + URI delete(@PathParam("name") String name); + + /** + * The Restart Virtual Machine operation + */ + @Named("RestartVirtualMachine") + @POST + @Path("/{name}/restart") + void restart(@PathParam("name") String name); + + /** + * The start Virtual Machine operation + */ + @Named("StartVirtualMachine") + @POST + @Path("/{name}/start") + void start(@PathParam("name") String name); + + /** + * The stop Virtual Machine operation + */ + @Named("StopVirtualMachine") + @POST + @Path("/{name}/powerOff") + void stop(@PathParam("name") String name); + +} + diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiLiveTest.java new file mode 100644 index 0000000000..c1e77a203e --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiLiveTest.java @@ -0,0 +1,139 @@ +/* + * 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 com.google.common.collect.ImmutableMap; +import org.jclouds.azurecompute.arm.domain.IdReference; +import org.jclouds.azurecompute.arm.domain.IpConfiguration; +import org.jclouds.azurecompute.arm.domain.IpConfigurationProperties; +import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; +import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCardProperties; +import org.jclouds.azurecompute.arm.domain.Subnet; +import org.jclouds.azurecompute.arm.domain.VirtualNetwork; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; + +@Test(groups = "live", singleThreaded = true) +public class NetworkInterfaceCardApiLiveTest extends BaseAzureComputeApiLiveTest { + + private String resourcegroup; + private String subnetID; + + @BeforeClass + @Override + public void setup() { + super.setup(); + + resourcegroup = getResourceGroupName(); + + //Subnets belong to a virtual network so that needs to be created first + VirtualNetwork vn = getOrCreateVirtualNetwork(VIRTUAL_NETWORK_NAME); + assertNotNull(vn); + + //Subnet needs to be up & running before NIC can be created + Subnet subnet = getOrCreateSubnet(DEFAULT_SUBNET_NAME, VIRTUAL_NETWORK_NAME); + assertNotNull(subnet); + assertNotNull(subnet.id()); + subnetID = subnet.id(); + } + + + @Test(groups = "live") + public void deleteNetworkInterfaceCardResourceDoesNotExist() { + + final NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(resourcegroup); + boolean status = nicApi.delete(NETWORKINTERFACECARD_NAME); + assertFalse(status); + } + + @Test(groups = "live", dependsOnMethods = "deleteNetworkInterfaceCardResourceDoesNotExist") + public void createNetworkInterfaceCard() { + + final NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(resourcegroup); + + + //Create properties object + //Create properties object + final NetworkInterfaceCardProperties networkInterfaceCardProperties = + NetworkInterfaceCardProperties.builder().ipConfigurations( + Arrays.asList(IpConfiguration.builder() + .name("myipconfig") + .properties(IpConfigurationProperties.builder() + .privateIPAllocationMethod("Dynamic") + .subnet(IdReference.create(subnetID)).build() + ).build() + )).build(); + + final Map tags = ImmutableMap.of("jclouds", "livetest"); + NetworkInterfaceCard nic = nicApi.createOrUpdate(NETWORKINTERFACECARD_NAME, LOCATION, networkInterfaceCardProperties, tags); + + assertEquals(nic.name(), NETWORKINTERFACECARD_NAME); + assertEquals(nic.location(), LOCATION); + assertTrue(nic.properties().ipConfigurations().size() > 0); + assertEquals(nic.properties().ipConfigurations().get(0).name(), "myipconfig"); + assertEquals(nic.properties().ipConfigurations().get(0).properties().privateIPAllocationMethod(), "Dynamic"); + assertEquals(nic.properties().ipConfigurations().get(0).properties().subnet().id(), subnetID); + assertEquals(nic.tags().get("jclouds"), "livetest"); + + } + + @Test(groups = "live", dependsOnMethods = "createNetworkInterfaceCard") + public void getNetworkInterfaceCard() { + + final NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(resourcegroup); + + NetworkInterfaceCard nic = nicApi.get(NETWORKINTERFACECARD_NAME); + + assertEquals(nic.name(), NETWORKINTERFACECARD_NAME); + assertEquals(nic.location(), LOCATION); + assertTrue(nic.properties().ipConfigurations().size() > 0); + assertEquals(nic.properties().ipConfigurations().get(0).name(), "myipconfig"); + assertEquals(nic.properties().ipConfigurations().get(0).properties().privateIPAllocationMethod(), "Dynamic"); + assertEquals(nic.properties().ipConfigurations().get(0).properties().subnet().id(), subnetID); + } + + @Test(groups = "live", dependsOnMethods = "createNetworkInterfaceCard") + public void listNetworkInterfaceCards() { + + final NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(resourcegroup); + + List nicList = nicApi.list(); + + assertTrue(nicList.contains(nicApi.get(NETWORKINTERFACECARD_NAME))); + } + + + @Test(groups = "live", dependsOnMethods = {"listNetworkInterfaceCards", "getNetworkInterfaceCard"}, alwaysRun = true) + public void deleteNetworkInterfaceCard() { + + final NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(resourcegroup); + + boolean status = nicApi.delete(NETWORKINTERFACECARD_NAME); + assertTrue(status); + } + +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiMockTest.java new file mode 100644 index 0000000000..179a4ab38c --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiMockTest.java @@ -0,0 +1,150 @@ +/* + * 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 com.google.common.collect.ImmutableMap; +import com.squareup.okhttp.mockwebserver.MockResponse; +import org.jclouds.azurecompute.arm.domain.IdReference; +import org.jclouds.azurecompute.arm.domain.IpConfiguration; +import org.jclouds.azurecompute.arm.domain.IpConfigurationProperties; +import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; +import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCardProperties; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; +import org.testng.annotations.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; + +@Test(groups = "unit", testName = "NetworkInterfaceCardApiMockTest", singleThreaded = true) +public class NetworkInterfaceCardApiMockTest extends BaseAzureComputeApiMockTest { + + private final String subscriptionid = "SUBSCRIPTIONID"; + private final String resourcegroup = "myresourcegroup"; + private final String apiVersion = "api-version=2015-06-15"; + private final String location = "northeurope"; + private final String nicName = "myNic"; + + public void getNetworkInterfaceCard() throws InterruptedException { + server.enqueue(jsonResponse("/getnetworkinterfacecard.json")); + + final NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(resourcegroup); + NetworkInterfaceCard nic = nicApi.get(nicName); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkInterfaces/%s?%s", subscriptionid, resourcegroup, nicName, apiVersion); + assertSent(server, "GET", path); + assertNotNull(nic); + assertEquals(nic.name(), nicName); + assertEquals(nic.properties().ipConfigurations().get(0).name(), "myip1"); + assertEquals(nic.tags().get("mycustomtag"), "foobar"); + } + + public void getNetworkInterfaceCardEmpty() throws Exception { + server.enqueue(new MockResponse().setResponseCode(404)); + + final NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(resourcegroup); + + assertNull(nicApi.get(nicName)); + + assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourcegroups/myresourcegroup/providers/Microsoft.Network/networkInterfaces/myNic?api-version=2015-06-15"); + } + + public void listNetworkInterfaceCards() throws InterruptedException { + server.enqueue(jsonResponse("/listnetworkinterfaces.json")); + + final NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(resourcegroup); + List nicList = nicApi.list(); + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkInterfaces?%s", subscriptionid, resourcegroup, apiVersion); + + assertSent(server, "GET", path); + assertTrue(nicList.size() == 2); + assertTrue(nicList.get(0).properties().ipConfigurations().size() > 0); + assertEquals(nicList.get(0).properties().ipConfigurations().get(0).properties().privateIPAllocationMethod(), "Dynamic"); + assertTrue(nicList.get(1).properties().ipConfigurations().size() > 0); + assertEquals(nicList.get(1).properties().ipConfigurations().get(0).properties().privateIPAllocationMethod(), "Static"); + } + + public void listNetworkInterfaceCardsEmpty() throws Exception { + server.enqueue(new MockResponse().setResponseCode(404)); + + final NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(resourcegroup); + + assertTrue(nicApi.list().isEmpty()); + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkInterfaces?%s", subscriptionid, resourcegroup, apiVersion); + + assertSent(server, "GET", path); + } + + public void createNetworkInterfaceCard() throws InterruptedException { + + server.enqueue(jsonResponse("/createnetworkinterfacecard.json").setStatus("HTTP/1.1 201 Created")); + + final NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(resourcegroup); + + + final String SubnetID = "/subscriptions/" + subscriptionid + "/resourceGroups/azurearmtesting/providers/Microsoft.Network/virtualNetworks/myvirtualnetwork/subnets/mysubnet"; + //Create properties object + final NetworkInterfaceCardProperties networkInterfaceCardProperties = + NetworkInterfaceCardProperties.create(null, null, null, + Arrays.asList(IpConfiguration.create("myipconfig", null, null, null, + IpConfigurationProperties.create(null, null, "Dynamic", IdReference.create(SubnetID), null)) + ) + ); + + final Map tags = ImmutableMap.of("mycustomtag", "foobar"); + + NetworkInterfaceCard nic = nicApi.createOrUpdate(nicName, location, networkInterfaceCardProperties, tags); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkInterfaces/%s?%s", subscriptionid, resourcegroup, nicName, apiVersion); + String json = String.format("{ \"location\":\"%s\", \"tags\": { \"mycustomtag\": \"foobar\" }, \"properties\":{ \"ipConfigurations\":[ { \"name\":\"%s\", \"properties\":{ \"subnet\":{ \"id\": \"%s\" }, \"privateIPAllocationMethod\":\"%s\" } } ] } }", location, "myipconfig", SubnetID, "Dynamic"); + assertSent(server, "PUT", path, json); + assertEquals(nic.tags().get("mycustomtag"), "foobar"); + } + + public void deleteNetworkInterfaceCard() throws InterruptedException { + + server.enqueue(response202()); + + final NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(resourcegroup); + + boolean status = nicApi.delete(nicName); + assertTrue(status); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkInterfaces/%s?%s", subscriptionid, resourcegroup, nicName, apiVersion); + assertSent(server, "DELETE", path); + + } + + public void deleteNetworkInterfaceCardResourceDoesNotExist() throws InterruptedException { + + server.enqueue(response204()); + + final NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(resourcegroup); + + boolean status = nicApi.delete(nicName); + assertFalse(status); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkInterfaces/%s?%s", subscriptionid, resourcegroup, nicName, apiVersion); + assertSent(server, "DELETE", path); + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApiLiveTest.java new file mode 100644 index 0000000000..544323532d --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApiLiveTest.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.features; + +import com.google.common.collect.ImmutableMap; +import org.jclouds.azurecompute.arm.domain.PublicIPAddress; +import org.jclouds.azurecompute.arm.domain.PublicIPAddressProperties; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; +import org.jclouds.util.Predicates2; +import com.google.common.base.Predicate; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.util.List; +import java.util.Map; + +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; + + +@Test(groups = "live", singleThreaded = true) +public class PublicIPAddressApiLiveTest extends BaseAzureComputeApiLiveTest { + + private final String publicIpAddressName = "myipaddress"; + private final String subscriptionid = getSubscriptionId(); + private String resourcegroup; + + @BeforeClass + @Override + public void setup() { + super.setup(); + resourcegroup = getResourceGroupName(); + } + + @Test(groups = "live") + public void deletePublicIPAddressResourceDoesNotExist() { + final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourcegroup); + boolean status = ipApi.delete(publicIpAddressName); + assertFalse(status); + } + + @Test(groups = "live", dependsOnMethods = "deletePublicIPAddressResourceDoesNotExist") + public void createPublicIPAddress() { + + final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourcegroup); + + final Map tags = ImmutableMap.of("testkey", "testvalue"); + + PublicIPAddressProperties properties = + PublicIPAddressProperties.builder() + .publicIPAllocationMethod("Static") + .idleTimeoutInMinutes(4) + .build(); + + PublicIPAddress ip = ipApi.createOrUpdate(publicIpAddressName, LOCATION, tags, properties); + + assertNotNull(ip); + assertEquals(ip.name(), publicIpAddressName); + assertEquals(ip.location(), LOCATION); + assertEquals(ip.id(), String.format("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/publicIPAddresses/%s", subscriptionid, resourcegroup, publicIpAddressName)); + assertEquals(ip.tags().get("testkey"), "testvalue"); + assertNotNull(ip.properties()); + assertEquals(ip.properties().provisioningState(), "Updating"); + assertNull(ip.properties().ipAddress()); // as we don't get IP address until Succeeded state + assertEquals(ip.properties().publicIPAllocationMethod(), "Static"); + assertEquals(ip.properties().idleTimeoutInMinutes().intValue(), 4); + } + + @Test(groups = "live", dependsOnMethods = "createPublicIPAddress") + public void getPublicIPAddress() { + + final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourcegroup); + + //Poll until resource is ready to be used + boolean jobDone = Predicates2.retry(new Predicate() { + @Override public boolean apply(String name) { + return ipApi.get(name).properties().provisioningState().equals("Succeeded"); + } + }, 10 * 1000).apply(publicIpAddressName); + assertTrue(jobDone, "get operation did not complete in the configured timeout"); + + PublicIPAddress ip = ipApi.get(publicIpAddressName); + assertNotNull(ip); + assertEquals(ip.name(), publicIpAddressName); + assertEquals(ip.location(), LOCATION); + assertEquals(ip.id(), String.format("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/publicIPAddresses/%s", subscriptionid, resourcegroup, publicIpAddressName)); + assertEquals(ip.tags().get("testkey"), "testvalue"); + assertNotNull(ip.properties()); + assertEquals(ip.properties().provisioningState(), "Succeeded"); + assertNotNull(ip.properties().ipAddress()); // by this time we should have IP address already + assertEquals(ip.properties().publicIPAllocationMethod(), "Static"); + assertEquals(ip.properties().idleTimeoutInMinutes().intValue(), 4); + } + + @Test(groups = "live", dependsOnMethods = "createPublicIPAddress") + public void listPublicIPAddresses() { + + final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourcegroup); + + List ipList = ipApi.list(); + + assertTrue(ipList.size() > 0); + } + + @Test(groups = "live", dependsOnMethods = {"listPublicIPAddresses", "getPublicIPAddress"}, alwaysRun = true) + public void deletePublicIPAddress() { + final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourcegroup); + boolean status = ipApi.delete(publicIpAddressName); + assertTrue(status); + } + +} 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 new file mode 100644 index 0000000000..436cb91f81 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApiMockTest.java @@ -0,0 +1,179 @@ +/* + * 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 com.google.common.collect.ImmutableMap; +import com.squareup.okhttp.mockwebserver.MockResponse; +import org.jclouds.azurecompute.arm.domain.DnsSettings; +import org.jclouds.azurecompute.arm.domain.PublicIPAddress; +import org.jclouds.azurecompute.arm.domain.PublicIPAddressProperties; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; +import org.testng.annotations.Test; + +import java.util.List; +import java.util.Map; + +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; + + +@Test(groups = "unit", testName = "NetworkInterfaceCardApiMockTest", singleThreaded = true) +public class PublicIPAddressApiMockTest extends BaseAzureComputeApiMockTest { + + private final String subscriptionid = "SUBSCRIPTIONID"; + private final String resourcegroup = "myresourcegroup"; + private final String apiVersion = "api-version=2015-06-15"; + private final String location = "northeurope"; + private final String publicIpName = "mypublicaddress"; + + public void getPublicIPAddressInfo() throws InterruptedException { + server.enqueue(jsonResponse("/PublicIPAddressGetInfo.json")); + + final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourcegroup); + PublicIPAddress ip = ipApi.get(publicIpName); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/publicIPAddresses/%s?%s", subscriptionid, resourcegroup, publicIpName, apiVersion); + assertSent(server, "GET", path); + + assertNotNull(ip); + assertEquals(ip.name(), "mypublicaddress"); + assertEquals(ip.location(), "northeurope"); + assertEquals(ip.id(), "/subscriptions/fakeb2f5-4710-4e93-bdf4-419edbde2178/resourceGroups/myresourcegroup/providers/Microsoft.Network/publicIPAddresses/mypublicaddress"); + assertEquals(ip.tags().get("testkey"), "testvalue"); + assertNotNull(ip.properties()); + assertEquals(ip.properties().provisioningState(), "Succeeded"); + assertEquals(ip.properties().ipAddress(), "12.123.12.123"); + assertEquals(ip.properties().publicIPAllocationMethod(), "Static"); + assertEquals(ip.properties().idleTimeoutInMinutes().intValue(), 4); + assertNotNull(ip.properties().dnsSettings()); + assertEquals(ip.properties().dnsSettings().domainNameLabel(), "foobar"); + assertEquals(ip.properties().dnsSettings().fqdn(), "foobar.northeurope.cloudapp.azure.com"); + assertNotNull(ip.properties().ipConfiguration()); + assertEquals(ip.properties().ipConfiguration().id(), "/subscriptions/fakeb2f5-4710-4e93-bdf4-419edbde2178/resourceGroups/myresourcegroup/providers/Microsoft.Network/networkInterfaces/myNic/ipConfigurations/myip1"); + } + + public void getPublicIPAddressInfoEmpty() throws Exception { + server.enqueue(new MockResponse().setResponseCode(404)); + + final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourcegroup); + PublicIPAddress ip = ipApi.get(publicIpName); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/publicIPAddresses/%s?%s", subscriptionid, resourcegroup, publicIpName, apiVersion); + assertSent(server, "GET", path); + + assertNull(ip); + } + + public void listPublicIPAddresses() throws InterruptedException { + server.enqueue(jsonResponse("/PublicIPAddressList.json")); + + final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourcegroup); + List ipList = ipApi.list(); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/publicIPAddresses?%s", subscriptionid, resourcegroup, apiVersion); + assertSent(server, "GET", path); + assertEquals(ipList.size(), 4); + } + + public void listPublicIPAddressesEmpty() throws InterruptedException { + server.enqueue(new MockResponse().setResponseCode(404)); + + final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourcegroup); + List ipList = ipApi.list(); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/publicIPAddresses?%s", subscriptionid, resourcegroup, apiVersion); + assertSent(server, "GET", path); + assertEquals(ipList.size(), 0); + } + + public void createPublicIPAddress() throws InterruptedException { + + server.enqueue(jsonResponse("/PublicIPAddressCreate.json").setStatus("HTTP/1.1 201 Created")); + + final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourcegroup); + + final Map tags = ImmutableMap.of("testkey", "testvalue"); + + 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); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/publicIPAddresses/%s?%s", subscriptionid, resourcegroup, publicIpName, apiVersion); + String json = String.format("{ \"location\": \"%s\", \"tags\": { \"testkey\": \"testvalue\" }, \"properties\": { \"publicIPAllocationMethod\": \"Static\", \"idleTimeoutInMinutes\": 4, \"dnsSettings\": { \"domainNameLabel\": \"foobar\", \"fqdn\": \"foobar.northeurope.cloudapp.azure.com\" } } }", location); + assertSent(server, "PUT", path, json); + + assertNotNull(ip); + assertEquals(ip.name(), "mypublicaddress"); + assertEquals(ip.location(), "northeurope"); + assertEquals(ip.id(), "/subscriptions/fakeb2f5-4710-4e93-bdf4-419edbde2178/resourceGroups/myresourcegroup/providers/Microsoft.Network/publicIPAddresses/mypublicaddress"); + assertEquals(ip.tags().get("testkey"), "testvalue"); + assertNotNull(ip.properties()); + assertEquals(ip.properties().provisioningState(), "Updating"); + assertNull(ip.properties().ipAddress()); // as we don't get IP address until Succeeded state + assertEquals(ip.properties().publicIPAllocationMethod(), "Static"); + assertEquals(ip.properties().idleTimeoutInMinutes().intValue(), 4); + assertNotNull(ip.properties().dnsSettings()); + assertEquals(ip.properties().dnsSettings().domainNameLabel(), "foobar"); + assertEquals(ip.properties().dnsSettings().fqdn(), "foobar.northeurope.cloudapp.azure.com"); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void createPublicIPAddressDnsRecordInUse() throws IllegalArgumentException, InterruptedException { + + server.enqueue(jsonResponse("/PublicIPAddressCreateDnsRecordInUse.json").setStatus("HTTP/1.1 400 Bad Request")); + + final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourcegroup); + + final Map tags = ImmutableMap.of("testkey", "testvalue"); + + 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); + + } + + public void deletePublicIPAddress() throws InterruptedException { + + server.enqueue(response202()); + + final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourcegroup); + boolean status = ipApi.delete(publicIpName); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/publicIPAddresses/%s?%s", subscriptionid, resourcegroup, publicIpName, apiVersion); + assertSent(server, "DELETE", path); + + assertTrue(status); + } + + public void deletePublicIPAddressResourceDoesNotExist() throws InterruptedException { + + server.enqueue(response204()); + + final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourcegroup); + boolean status = ipApi.delete(publicIpName); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/publicIPAddresses/%s?%s", subscriptionid, resourcegroup, publicIpName, apiVersion); + assertSent(server, "DELETE", path); + + assertFalse(status); + } +} 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 new file mode 100644 index 0000000000..87b84d86a9 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineApiLiveTest.java @@ -0,0 +1,245 @@ +/* + * 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 com.google.common.base.Predicate; +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.NetworkInterfaceCard; +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.StorageProfile; +import org.jclouds.azurecompute.arm.domain.StorageService; +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.functions.ParseJobStatus; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; +import org.jclouds.util.Predicates2; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertNotNull; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import static org.testng.Assert.assertTrue; + +@Test(groups = "live", testName = "VirtualMachineApiLiveTest") +public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { + + private String subscriptionid = getSubscriptionId(); + private String vmName = null; + private String nicName = null; + + @BeforeClass + public void Setup() { + NetworkInterfaceCard nic = getOrCreateNetworkInterfaceCard(NETWORKINTERFACECARD_NAME); + assertNotNull(nic); + nicName = nic.name(); + } + + private String getName() { + if (vmName == null) { + vmName = String.format("%3.24s", + System.getProperty("user.name") + RAND + this.getClass().getSimpleName()).toLowerCase().substring(0, 15); + } + return vmName; + } + + @Test + public void testCreate(){ + + StorageAccountApi storageApi = api.getStorageAccountApi(getResourceGroupName()); + StorageService storageAccount = storageApi.get(getStorageServiceName()); + String blob = storageAccount.storageServiceProperties().primaryEndpoints().get("blob"); + + VirtualMachine vm = api().create(getName(), LOCATION, getProperties(blob, nicName)); + assertTrue(!vm.name().isEmpty()); + + //Poll until resource is ready to be used + boolean jobDone = Predicates2.retry(new Predicate() { + @Override public boolean apply(String name) { + return !api().get(name).properties().provisioningState().equals("Creating"); + } + }, 60 * 20 * 1000).apply(getName()); + assertTrue(jobDone, "create operation did not complete in the configured timeout"); + + String 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")); + } + + @Test(dependsOnMethods = "testCreate") + public void testGet() { + VirtualMachine vm = api().get(getName()); + assertTrue(!vm.name().isEmpty()); + } + + @Test(dependsOnMethods = "testCreate") + public void testGetInstanceView() { + VirtualMachineInstance vmi = api().getInstanceDetails(getName()); + assertTrue(!vmi.statuses().isEmpty()); + } + + @Test(dependsOnMethods = "testStart") + public void testStop() { + api().stop(getName()); + //Poll until resource is ready to be used + boolean jobDone = Predicates2.retry(new Predicate() { + @Override public boolean apply(String name) { + String status = ""; + List statuses = api().getInstanceDetails(name).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"); + } + }, 60 * 4 * 1000).apply(getName()); + assertTrue(jobDone, "stop operation did not complete in the configured timeout"); + + } + + @Test(dependsOnMethods = "testGet") + public void testStart() { + api().start(getName()); + + //Poll until resource is ready to be used + boolean jobDone = Predicates2.retry(new Predicate() { + @Override public boolean apply(String name) { + String status = ""; + List statuses = api().getInstanceDetails(name).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 running"); + } + }, 60 * 4 * 1000).apply(getName()); + assertTrue(jobDone, "start operation did not complete in the configured timeout"); + + } + + @Test(dependsOnMethods = "testStop") + public void testRestart() { + api().start(getName()); + + //Poll until resource is ready to be used + boolean jobDone = Predicates2.retry(new Predicate() { + @Override public boolean apply(String name) { + String status = ""; + List statuses = api().getInstanceDetails(name).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 running"); + } + }, 60 * 4 * 1000).apply(getName()); + assertTrue(jobDone, "start operation did not complete in the configured timeout"); + + api().restart(getName()); + + //Poll until resource is ready to be used + jobDone = Predicates2.retry(new Predicate() { + @Override public boolean apply(String name) { + String status = ""; + List statuses = api().getInstanceDetails(name).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 running"); + } + }, 60 * 4 * 1000).apply(getName()); + assertTrue(jobDone, "restart operation did not complete in the configured timeout"); + } + + @Test(dependsOnMethods = "testCreate") + public void testList() { + List list = api().list(); + VirtualMachine vm = api().get(getName()); + assertTrue(list.contains(vm)); + } + + @Test(dependsOnMethods = {"testRestart", "testList", "testGet"}, alwaysRun = true) + public void testDelete() throws Exception { + URI uri = api().delete(getName()); + + if (uri != null) { + assertTrue(uri.toString().contains("api-version")); + + boolean jobDone = Predicates2.retry(new Predicate() { + @Override + public boolean apply(URI uri) { + return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri); + } + }, 60 * 8 * 1000 /* 2 minutes timeout */).apply(uri); + assertTrue(jobDone, "delete operation did not complete in the configured timeout"); + } + } + + private VirtualMachineApi api() { + return api.getVirtualMachineApi(getResourceGroupName()); + } + + private VirtualMachineProperties getProperties(String blob, String nic) { + + HardwareProfile hwProf = HardwareProfile.create("Standard_D1"); + ImageReference imgRef = ImageReference.create("MicrosoftWindowsServerEssentials", + "WindowsServerEssentials", "WindowsServerEssentials", "latest"); + VHD vhd = VHD.create(blob + "vhds/" + getName() + ".vhd"); + VHD vhd2 = VHD.create(blob + "vhds/" + getName() + "data.vhd"); + DataDisk dataDisk = DataDisk.create(getName() + "data", "100", 0, vhd2, "Empty"); + OSDisk osDisk = OSDisk.create(null, getName(), vhd, "ReadWrite", "FromImage"); + StorageProfile storageProfile = StorageProfile.create(imgRef, osDisk, null); + OSProfile.WindowsConfiguration windowsConfig = OSProfile.WindowsConfiguration.create(false, null, null, true, + null); + OSProfile osProfile = OSProfile.create(getName(), "azureuser", "RFe3&432dg", null, null, windowsConfig); + IdReference networkInterface = + IdReference.create("/subscriptions/" + subscriptionid + + "/resourceGroups/" + getResourceGroupName() + "/providers/Microsoft.Network/networkInterfaces/" + + nic); + List networkInterfaces = + new ArrayList(); + networkInterfaces.add(networkInterface); + NetworkProfile networkProfile = NetworkProfile.create(networkInterfaces); + DiagnosticsProfile.BootDiagnostics bootDiagnostics = + DiagnosticsProfile.BootDiagnostics.create(true, blob); + DiagnosticsProfile diagnosticsProfile = DiagnosticsProfile.create(bootDiagnostics); + VirtualMachineProperties properties = VirtualMachineProperties.create(null, + null, null, hwProf, storageProfile, osProfile, networkProfile, diagnosticsProfile, "Creating"); + return properties; + } +} 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 new file mode 100644 index 0000000000..a2be833e76 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineApiMockTest.java @@ -0,0 +1,249 @@ +/* + * 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 com.google.common.collect.ImmutableList; +import com.squareup.okhttp.mockwebserver.MockResponse; +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.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.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 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.assertTrue; + +@Test(groups = "unit", testName = "VirtualMachineApiMockTest", singleThreaded = true) +public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { + + public void testGet() throws Exception { + server.enqueue(jsonResponse("/virtualmachine.json")); + 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"); + } + 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"); + } + + public void testGetInstanceDetails() throws Exception { + server.enqueue(jsonResponse("/virtualmachineInstance.json")); + final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); + VirtualMachineInstance actual = vmAPI.getInstanceDetails("windowsmachine"); + VirtualMachineInstance expected = getVMInstance(); + + assertEquals(actual.statuses().get(0).code(), expected.statuses().get(0).code()); + assertEquals(actual.statuses().get(0).displayStatus(), expected.statuses().get(0).displayStatus()); + 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"); + } + + public void testGetInstanceDetailsEmpty() throws Exception { + server.enqueue(new MockResponse().setResponseCode(404)); + 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"); + } + + public void testList() throws Exception { + server.enqueue(jsonResponse("/virtualmachines.json")); + final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); + assertEquals(vmAPI.list(), getVMList()); + assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines?api-version=2015-06-15"); + } + public void testListEmpty() throws Exception { + server.enqueue(new MockResponse().setResponseCode(404)); + final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); + assertTrue(isEmpty(vmAPI.list())); + assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines?api-version=2015-06-15"); + } + + public void testCreate() throws Exception { + server.enqueue(jsonResponse("/createvirtualmachineresponse.json")); + + final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); + 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", + "{\"location\":\"westus\",\"properties\":" + + "{\"vmId\":\"27ee085b-d707-xxxx-yyyy-2370e2eb1cc1\"," + + "\"hardwareProfile\":{\"vmSize\":\"Standard_D1\"}," + + "\"storageProfile\":{\"imageReference\":{\"publisher\":\"publisher\",\"offer\":\"offer\",\"sku\":\"sku\",\"version\":\"ver\"}," + + "\"osDisk\":{\"osType\":\"Windows\",\"name\":\"windowsmachine\"," + + "\"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\"}}"); + + } + + public void testDeleteReturns404() throws Exception { + server.enqueue(response404()); + + final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); + + URI uri = vmAPI.delete("windowsmachine"); + + assertEquals(server.getRequestCount(), 1); + assertNull(uri); + + assertSent(server, "DELETE", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines/windowsmachine?api-version=2015-06-15"); + } + public void testDelete() throws Exception { + server.enqueue(response202WithHeader()); + + final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); + + URI uri = vmAPI.delete("windowsmachine"); + + assertEquals(server.getRequestCount(), 1); + assertNotNull(uri); + + assertSent(server, "DELETE", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines/windowsmachine?api-version=2015-06-15"); + } + + public void testStart() throws Exception { + server.enqueue(new MockResponse().setResponseCode(204)); + + final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); + + vmAPI.start("windowsmachine"); + + assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines/windowsmachine/start?api-version=2015-06-15"); + } + + public void testRestart() throws Exception { + server.enqueue(new MockResponse().setResponseCode(204)); + + final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); + + vmAPI.restart("windowsmachine"); + + assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines/windowsmachine/restart?api-version=2015-06-15"); + } + + public void testStop() throws Exception { + server.enqueue(new MockResponse().setResponseCode(204)); + + final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); + + vmAPI.stop("windowsmachine"); + + assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines/windowsmachine/powerOff?api-version=2015-06-15"); + } + + private VirtualMachineProperties getProperties() { + HardwareProfile hwProf = HardwareProfile.create("Standard_D1"); + ImageReference imgRef = ImageReference.create("publisher", "offer", "sku", "ver"); + VHD vhd = VHD.create("https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd"); + List dataDisks = new ArrayList(); + OSDisk osDisk = OSDisk.create("Windows", "windowsmachine", vhd, "ReadWrite", "FromImage"); + StorageProfile storageProfile = StorageProfile.create(imgRef, osDisk, dataDisks); + OSProfile.WindowsConfiguration windowsConfig = OSProfile.WindowsConfiguration.create(false, null, null, true, + null); + OSProfile osProfile = OSProfile.create("windowsmachine", "azureuser", null, null, null, windowsConfig); + IdReference networkInterface = + IdReference.create("/subscriptions/SUBSCRIPTIONID" + + "/resourceGroups/groupname/providers/Microsoft.Network/networkInterfaces/" + + "windowsmachine167"); + List networkInterfaces = new ArrayList(); + networkInterfaces.add(networkInterface); + NetworkProfile networkProfile = NetworkProfile.create(networkInterfaces); + DiagnosticsProfile.BootDiagnostics bootDiagnostics = DiagnosticsProfile.BootDiagnostics.create(true, + "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"); + return properties; + } + + private VirtualMachine getVM() { + VirtualMachineProperties properties = getProperties(); + VirtualMachine machine = VirtualMachine.create("/subscriptions/SUBSCRIPTIONID/" + "" + + "resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", "windowsmachine", + "Microsoft.Compute/virtualMachines", "westus", null, properties); + return machine; + } + + private VirtualMachineInstance getVMInstance() { + List statuses = new ArrayList(); + String testDate = "Wed May 04 01:38:52 PDT 2016"; + DateFormat formatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy"); + Date date = null; + try { + date = formatter.parse(testDate); + } catch (Exception e) { + e.printStackTrace(); + } + VirtualMachineInstance.VirtualMachineStatus vmStatus = + VirtualMachineInstance.VirtualMachineStatus.create("ProvisioningState/succeeded", "Info", "Provisioning succeeded", date); + statuses.add(vmStatus); + VirtualMachineInstance.VirtualMachineStatus vmStatus1 = + VirtualMachineInstance.VirtualMachineStatus.create("PowerState/running", "Info", "VM running", null); + statuses.add(vmStatus1); + + VirtualMachineInstance machineInstance = + VirtualMachineInstance.create(null, null, ImmutableList.copyOf(statuses)); + return machineInstance; + } + + private List getVMList() { + VirtualMachineProperties properties = getProperties(); + VirtualMachine machine = VirtualMachine.create("/subscriptions/SUBSCRIPTIONID/" + "" + + "resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", + "windowsmachine", "Microsoft.Compute/virtualMachines", "westus", null, properties); + List list = new ArrayList(); + list.add(machine); + return list; + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AbstractAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AbstractAzureComputeApiLiveTest.java index aa0663ab15..bd55694815 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AbstractAzureComputeApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AbstractAzureComputeApiLiveTest.java @@ -22,9 +22,9 @@ import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATI 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 java.util.Properties; import java.util.Random; - import org.jclouds.apis.BaseApiLiveTest; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java index b1d97b8b03..0768daba7a 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java @@ -20,11 +20,17 @@ import static org.testng.Assert.assertTrue; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableMap; +import org.jclouds.azurecompute.arm.domain.IdReference; +import org.jclouds.azurecompute.arm.domain.IpConfiguration; +import org.jclouds.azurecompute.arm.domain.IpConfigurationProperties; +import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; +import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCardProperties; import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.domain.StorageService; import org.jclouds.azurecompute.arm.domain.Subnet; import org.jclouds.azurecompute.arm.domain.VirtualNetwork; +import org.jclouds.azurecompute.arm.features.NetworkInterfaceCardApi; import org.jclouds.azurecompute.arm.features.StorageAccountApi; import org.jclouds.azurecompute.arm.features.SubnetApi; import org.jclouds.azurecompute.arm.features.VirtualNetworkApi; @@ -36,6 +42,7 @@ import org.testng.annotations.BeforeClass; import java.net.URI; import java.util.Arrays; +import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; @@ -50,13 +57,15 @@ public class BaseAzureComputeApiLiveTest extends AbstractAzureComputeApiLiveTest public static final String DEFAULT_VIRTUALNETWORK_ADDRESS_PREFIX = "10.2.0.0/16"; + public static final String NETWORKINTERFACECARD_NAME = "jcloudsNic"; + private String resourceGroupName = null; protected StorageService storageService; - private String storageServiceName = null; + protected String getStorageServiceName() { if (storageServiceName == null) { storageServiceName = String.format("%3.24s", @@ -74,6 +83,17 @@ public class BaseAzureComputeApiLiveTest extends AbstractAzureComputeApiLiveTest return endpoint; } + protected String getSubscriptionId() { + String subscriptionid = null; + String endpoint = null; + endpoint = getEndpoint(); + if (endpoint != null) { + subscriptionid = endpoint.substring(endpoint.lastIndexOf("/") + 1); + } + assertNotNull(subscriptionid); + return subscriptionid; + } + protected String getResourceGroupName() { if (resourceGroupName == null) { resourceGroupName = String.format("%3.24s", @@ -99,7 +119,6 @@ public class BaseAzureComputeApiLiveTest extends AbstractAzureComputeApiLiveTest @Override public void setup() { super.setup(); - storageService = getOrCreateStorageService(getStorageServiceName()); } @@ -169,4 +188,29 @@ public class BaseAzureComputeApiLiveTest extends AbstractAzureComputeApiLiveTest return subnet; } + + protected NetworkInterfaceCard getOrCreateNetworkInterfaceCard(final String networkInterfaceCardName){ + + NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(getResourceGroupName()); + NetworkInterfaceCard nic = nicApi.get(networkInterfaceCardName); + + if (nic != null){ + return nic; + } + + VirtualNetwork vn = getOrCreateVirtualNetwork(VIRTUAL_NETWORK_NAME); + + Subnet subnet = getOrCreateSubnet(DEFAULT_SUBNET_NAME, VIRTUAL_NETWORK_NAME); + + //Create properties object + final NetworkInterfaceCardProperties networkInterfaceCardProperties = + NetworkInterfaceCardProperties.builder() + .ipConfigurations(Arrays.asList(IpConfiguration.create("myipconfig", null, null, null, + IpConfigurationProperties.create(null, null, "Dynamic", IdReference.create(subnet.id()), null)) + )).build(); + + final Map tags = ImmutableMap.of("jclouds", "livetest"); + nic = nicApi.createOrUpdate(NETWORKINTERFACECARD_NAME, LOCATION, networkInterfaceCardProperties, tags); + return nic; + } } diff --git a/providers/azurecompute-arm/src/test/resources/PublicIPAddressCreate.json b/providers/azurecompute-arm/src/test/resources/PublicIPAddressCreate.json new file mode 100644 index 0000000000..d9e06aabb3 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/PublicIPAddressCreate.json @@ -0,0 +1,20 @@ +{ + "name": "mypublicaddress", + "id": "/subscriptions/fakeb2f5-4710-4e93-bdf4-419edbde2178/resourceGroups/myresourcegroup/providers/Microsoft.Network/publicIPAddresses/mypublicaddress", + "etag": "W/\"f0bdaf62-456b-4338-8f65-05417b1a55e9\"", + "type": "Microsoft.Network/publicIPAddresses", + "location": "northeurope", + "tags": { + "testkey": "testvalue" + }, + "properties": { + "provisioningState": "Updating", + "resourceGuid": "ebe3f160-2484-447a-8980-c587b214b16f", + "publicIPAllocationMethod": "Static", + "idleTimeoutInMinutes": 4, + "dnsSettings": { + "domainNameLabel": "foobar", + "fqdn": "foobar.northeurope.cloudapp.azure.com" + } + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/PublicIPAddressCreateDnsRecordInUse.json b/providers/azurecompute-arm/src/test/resources/PublicIPAddressCreateDnsRecordInUse.json new file mode 100644 index 0000000000..16a52c899f --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/PublicIPAddressCreateDnsRecordInUse.json @@ -0,0 +1,7 @@ +{ + "error": { + "code": "DnsRecordInUse", + "message": "DNS record foobar.northeurope.cloudapp.azure.com is already used by another public IP.", + "details": [] + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/PublicIPAddressGetInfo.json b/providers/azurecompute-arm/src/test/resources/PublicIPAddressGetInfo.json new file mode 100644 index 0000000000..00ca98956d --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/PublicIPAddressGetInfo.json @@ -0,0 +1,24 @@ +{ + "name": "mypublicaddress", + "id": "/subscriptions/fakeb2f5-4710-4e93-bdf4-419edbde2178/resourceGroups/myresourcegroup/providers/Microsoft.Network/publicIPAddresses/mypublicaddress", + "etag": "W/\"0b020646-202f-4ac6-b1a7-f9645db7c371\"", + "type": "Microsoft.Network/publicIPAddresses", + "location": "northeurope", + "tags": { + "testkey": "testvalue" + }, + "properties": { + "provisioningState": "Succeeded", + "resourceGuid": "eb0da01e-2a30-4e84-b7a4-0ce9dde019f5", + "ipAddress": "12.123.12.123", + "publicIPAllocationMethod": "Static", + "idleTimeoutInMinutes": 4, + "dnsSettings": { + "domainNameLabel": "foobar", + "fqdn": "foobar.northeurope.cloudapp.azure.com" + }, + "ipConfiguration": { + "id": "/subscriptions/fakeb2f5-4710-4e93-bdf4-419edbde2178/resourceGroups/myresourcegroup/providers/Microsoft.Network/networkInterfaces/myNic/ipConfigurations/myip1" + } + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/PublicIPAddressList.json b/providers/azurecompute-arm/src/test/resources/PublicIPAddressList.json new file mode 100644 index 0000000000..2b78b3797e --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/PublicIPAddressList.json @@ -0,0 +1,80 @@ +{ + "value": [ + { + "name": "my2ndpublicaddress", + "id": "/subscriptions/fakeb2f5-4710-4e93-bdf4-419edbde2178/resourceGroups/myresourcegroup/providers/Microsoft.Network/publicIPAddresses/my2ndpublicaddress", + "etag": "W/\"b83fa879-46ee-48a9-8120-26572449788f\"", + "type": "Microsoft.Network/publicIPAddresses", + "location": "northeurope", + "tags": { + "testkey": "testvalue" + }, + "properties": { + "provisioningState": "Succeeded", + "resourceGuid": "ebe3f160-2484-447a-8980-c587b214b16f", + "publicIPAllocationMethod": "Dynamic", + "idleTimeoutInMinutes": 4, + "dnsSettings": { + "domainNameLabel": "foobar123", + "fqdn": "foobar123.northeurope.cloudapp.azure.com" + } + } + }, + { + "name": "my3rdpublicaddress", + "id": "/subscriptions/fakeb2f5-4710-4e93-bdf4-419edbde2178/resourceGroups/myresourcegroup/providers/Microsoft.Network/publicIPAddresses/my3rdpublicaddress", + "etag": "W/\"17d2cf9a-7aa8-4c53-a5b8-ebc2ccb7bf93\"", + "type": "Microsoft.Network/publicIPAddresses", + "location": "northeurope", + "tags": { + "testkey": "testvalue" + }, + "properties": { + "provisioningState": "Succeeded", + "resourceGuid": "e1107240-79c5-4829-ba16-f7a00c2763df", + "ipAddress": "12.12.123.123", + "publicIPAllocationMethod": "Static", + "idleTimeoutInMinutes": 4 + } + }, + { + "name": "my4thpublicaddress", + "id": "/subscriptions/fakeb2f5-4710-4e93-bdf4-419edbde2178/resourceGroups/myresourcegroup/providers/Microsoft.Network/publicIPAddresses/my4thpublicaddress", + "etag": "W/\"c32275e9-e1fc-465a-a5de-728c1359e123\"", + "type": "Microsoft.Network/publicIPAddresses", + "location": "northeurope", + "tags": { + "testkey": "testvalue" + }, + "properties": { + "provisioningState": "Succeeded", + "resourceGuid": "dbde9a83-8c1a-43f4-8d81-0fa469703e8a", + "ipAddress": "12.12.123.124", + "publicIPAllocationMethod": "Static", + "idleTimeoutInMinutes": 4 + } + }, + { + "name": "mypublicaddress", + "id": "/subscriptions/fakeb2f5-4710-4e93-bdf4-419edbde2178/resourceGroups/myresourcegroup/providers/Microsoft.Network/publicIPAddresses/mypublicaddress", + "etag": "W/\"0b020646-202f-4ac6-b1a7-f9645db7c371\"", + "type": "Microsoft.Network/publicIPAddresses", + "location": "northeurope", + "tags": {}, + "properties": { + "provisioningState": "Succeeded", + "resourceGuid": "eb0da01e-2a30-4e84-b7a4-0ce9dde019f5", + "ipAddress": "12.123.12.125", + "publicIPAllocationMethod": "Static", + "idleTimeoutInMinutes": 4, + "dnsSettings": { + "domainNameLabel": "foobar", + "fqdn": "foobar.northeurope.cloudapp.azure.com" + }, + "ipConfiguration": { + "id": "/subscriptions/fakeb2f5-4710-4e93-bdf4-419edbde2178/resourceGroups/myresourcegroup/providers/Microsoft.Network/networkInterfaces/myNic/ipConfigurations/myip1" + } + } + } + ] +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/createnetworkinterfacecard.json b/providers/azurecompute-arm/src/test/resources/createnetworkinterfacecard.json new file mode 100644 index 0000000000..d08b8f6a9f --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/createnetworkinterfacecard.json @@ -0,0 +1,35 @@ +{ + "name": "myNic", + "id": "/subscriptions/12345678-2749-4e68-9dcf-123456789abc/resourceGroups/azurearmtesting/providers/Microsoft.Network/networkInterfaces/myNic", + "etag": "W/\"6b51f6e7-232b-4289-b740-04a996929f5e\"", + "type": "Microsoft.Network/networkInterfaces", + "location": "northeurope", + "tags": { + "mycustomtag": "foobar" + }, + "properties": { + "provisioningState": "Succeeded", + "resourceGuid": "f3465472-536f-49e7-9e9c-fa91b971a618", + "ipConfigurations": [ + { + "name": "myip1", + "id": "/subscriptions/12345678-2749-4e68-9dcf-123456789abc/resourceGroups/azurearmtesting/providers/Microsoft.Network/networkInterfaces/myNic/ipConfigurations/myip1", + "etag": "W/\"6b51f6e7-232b-4289-b740-04a996929f5e\"", + "properties": { + "provisioningState": "Succeeded", + "privateIPAddress": "10.2.0.4", + "privateIPAllocationMethod": "Dynamic", + "subnet": { + "id": "/subscriptions/12345678-2749-4e68-9dcf-123456789abc/resourceGroups/azurearmtesting/providers/Microsoft.Network/virtualNetworks/myvirtualnetwork/subnets/mysubnet" + }, + "primary": true + } + } + ], + "dnsSettings": { + "dnsServers": [], + "appliedDnsServers": [] + }, + "enableIPForwarding": false + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json b/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json new file mode 100644 index 0000000000..ae16bdb1e9 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json @@ -0,0 +1,47 @@ +{ + "properties": { + "vmId": "27ee085b-d707-xxxx-yyyy-2370e2eb1cc1", + "hardwareProfile": { + "vmSize": "Standard_D1" + }, + "storageProfile": { + "imageReference": { + "publisher": "publisher", + "offer": "offer", + "sku": "sku", + "version": "ver" + }, + "osDisk": { + "osType": "Windows", + "name": "windowsmachine", + "createOption": "FromImage", + "vhd": { + "uri": "https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd" + }, + "caching": "ReadWrite" + }, + "dataDisks": [] + }, + "osProfile": { + "computerName": "windowsmachine", + "adminUsername": "azureuser", + "windowsConfiguration": { + "provisionVMAgent": false, + "enableAutomaticUpdates": true + }, + "secrets": [] + }, + "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" + }, + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", + "name": "windowsmachine", + "type": "Microsoft.Compute/virtualMachines", + "location": "westus" +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/getnetworkinterfacecard.json b/providers/azurecompute-arm/src/test/resources/getnetworkinterfacecard.json new file mode 100644 index 0000000000..f6132911fe --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/getnetworkinterfacecard.json @@ -0,0 +1,35 @@ +{ + "name": "myNic", + "id": "/subscriptions/12345678-2749-4e68-9dcf-123456789abc/resourceGroups/azurearmtesting/providers/Microsoft.Network/networkInterfaces/myNic", + "etag": "W/\"3dff0c55-a7a7-434f-837b-0cad946b755f\"", + "type": "Microsoft.Network/networkInterfaces", + "location": "northeurope", + "tags": { + "mycustomtag": "foobar" + }, + "properties": { + "provisioningState": "Succeeded", + "resourceGuid": "f3465472-536f-49e7-9e9c-fa91b971a618", + "ipConfigurations": [ + { + "name": "myip1", + "id": "/subscriptions/12345678-2749-4e68-9dcf-123456789abc/resourceGroups/azurearmtesting/providers/Microsoft.Network/networkInterfaces/myNic/ipConfigurations/myip1", + "etag": "W/\"3dff0c55-a7a7-434f-837b-0cad946b755f\"", + "properties": { + "provisioningState": "Succeeded", + "privateIPAddress": "10.2.0.4", + "privateIPAllocationMethod": "Dynamic", + "subnet": { + "id": "/subscriptions/12345678-2749-4e68-9dcf-123456789abc/resourceGroups/azurearmtesting/providers/Microsoft.Network/virtualNetworks/myvirtualnetwork/subnets/mysubnet" + }, + "primary": true + } + } + ], + "dnsSettings": { + "dnsServers": [], + "appliedDnsServers": [] + }, + "enableIPForwarding": false + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/listnetworkinterfaces.json b/providers/azurecompute-arm/src/test/resources/listnetworkinterfaces.json new file mode 100644 index 0000000000..de4b1e30fb --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/listnetworkinterfaces.json @@ -0,0 +1,68 @@ +{ + "value": [ + { + "name": "AnotherNIC", + "id": "/subscriptions/12345678-2749-4e68-9dcf-123456789abc/resourceGroups/azurearmtesting/providers/Microsoft.Network/networkInterfaces/AnotherNIC", + "etag": "W/\"e4ed4253-64b6-4184-bfaa-554f470d20c5\"", + "type": "Microsoft.Network/networkInterfaces", + "location": "northeurope", + "properties": { + "provisioningState": "Succeeded", + "resourceGuid": "7fcf6704-21c5-4983-bd9f-017e0873f22f", + "ipConfigurations": [ + { + "name": "ipconfig1", + "id": "/subscriptions/12345678-2749-4e68-9dcf-123456789abc/resourceGroups/azurearmtesting/providers/Microsoft.Network/networkInterfaces/AnotherNIC/ipConfigurations/ipconfig1", + "etag": "W/\"e4ed4253-64b6-4184-bfaa-554f470d20c5\"", + "properties": { + "provisioningState": "Succeeded", + "privateIPAddress": "10.2.1.4", + "privateIPAllocationMethod": "Dynamic", + "subnet": { + "id": "/subscriptions/12345678-2749-4e68-9dcf-123456789abc/resourceGroups/armlivetesting/providers/Microsoft.Network/virtualNetworks/jclouds-virtual-network-live-test/subnets/anothersubnet" + }, + "primary": true + } + } + ], + "dnsSettings": { + "dnsServers": [], + "appliedDnsServers": [] + }, + "enableIPForwarding": false + } + }, + { + "name": "MyNic", + "id": "/subscriptions/12345678-2749-4e68-9dcf-123456789abc/resourceGroups/azurearmtesting/providers/Microsoft.Network/networkInterfaces/MyNic", + "etag": "W/\"a37d25ff-3f62-4ee2-a111-f355beb5ff69\"", + "type": "Microsoft.Network/networkInterfaces", + "location": "northeurope", + "properties": { + "provisioningState": "Succeeded", + "resourceGuid": "35908409-a081-4411-86a9-51f9ea99321f", + "ipConfigurations": [ + { + "name": "ipconfig1", + "id": "/subscriptions/12345678-2749-4e68-9dcf-123456789abc/resourceGroups/azurearmtesting/providers/Microsoft.Network/networkInterfaces/MyNic/ipConfigurations/ipconfig1", + "etag": "W/\"a37d25ff-3f62-4ee2-a111-f355beb5ff69\"", + "properties": { + "provisioningState": "Succeeded", + "privateIPAddress": "10.2.0.100", + "privateIPAllocationMethod": "Static", + "subnet": { + "id": "/subscriptions/12345678-2749-4e68-9dcf-123456789abc/resourceGroups/armlivetesting/providers/Microsoft.Network/virtualNetworks/jclouds-virtual-network-live-test/subnets/default" + }, + "primary": true + } + } + ], + "dnsSettings": { + "dnsServers": [], + "appliedDnsServers": [] + }, + "enableIPForwarding": false + } + } + ] +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/resourcegroups.json b/providers/azurecompute-arm/src/test/resources/resourcegroups.json index e21fdb7f44..56c2196d7c 100644 --- a/providers/azurecompute-arm/src/test/resources/resourcegroups.json +++ b/providers/azurecompute-arm/src/test/resources/resourcegroups.json @@ -12,7 +12,6 @@ "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/test2", "name": "test2", "location": "eastus", - "tags": {}, "properties": { "provisioningState": "Succeeded" } diff --git a/providers/azurecompute-arm/src/test/resources/virtualmachine.json b/providers/azurecompute-arm/src/test/resources/virtualmachine.json new file mode 100644 index 0000000000..4dda519705 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/virtualmachine.json @@ -0,0 +1,47 @@ +{ + "properties": { + "vmId": "27ee085b-d707-xxxx-yyyy-2370e2eb1cc1", + "hardwareProfile": { + "vmSize": "Standard_D1" + }, + "storageProfile": { + "imageReference": { + "publisher": "publisher", + "offer": "offer", + "sku": "sku", + "version": "ver" + }, + "osDisk": { + "osType": "Windows", + "name": "windowsmachine", + "createOption": "FromImage", + "vhd": { + "uri": "https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd" + }, + "caching": "ReadWrite" + }, + "dataDisks": [] + }, + "osProfile": { + "computerName": "windowsmachine", + "adminUsername": "azureuser", + "windowsConfiguration": { + "provisionVMAgent": false, + "enableAutomaticUpdates": true + }, + "secrets": [] + }, + "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" + }, + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", + "name": "windowsmachine", + "type": "Microsoft.Compute/virtualMachines", + "location": "westus" +} diff --git a/providers/azurecompute-arm/src/test/resources/virtualmachineInstance.json b/providers/azurecompute-arm/src/test/resources/virtualmachineInstance.json new file mode 100644 index 0000000000..f73cab6982 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/virtualmachineInstance.json @@ -0,0 +1,40 @@ +{ + "vmAgent": { + "vmAgentVersion": "2.7.1198.766", + "statuses": [ + { + "code": "ProvisioningState/succeeded", + "level": "Info", + "displayStatus": "Ready", + "message": "GuestAgent is running and accepting new configurations.", + "time": "2016-05-04T08:42:15+00:00" + } + ] + }, + "disks": [ + { + "name": "windowsmachine", + "statuses": [ + { + "code": "ProvisioningState/succeeded", + "level": "Info", + "displayStatus": "Provisioning succeeded", + "time": "2016-05-04T08:31:45.2525129+00:00" + } + ] + } + ], + "statuses": [ + { + "code": "ProvisioningState/succeeded", + "level": "Info", + "displayStatus": "Provisioning succeeded", + "time": "2016-05-04T08:38:52.4310433+00:00" + }, + { + "code": "PowerState/running", + "level": "Info", + "displayStatus": "VM running" + } + ] +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/virtualmachines.json b/providers/azurecompute-arm/src/test/resources/virtualmachines.json new file mode 100644 index 0000000000..cd0e24b5ec --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/virtualmachines.json @@ -0,0 +1,57 @@ +{ + "value": [ + { + "properties": { + "vmId": "27ee085b-d707-xxxx-yyyy-2370e2eb1cc1", + "hardwareProfile": { + "vmSize": "Standard_D1" + }, + "storageProfile": { + "imageReference": { + "publisher": "publisher", + "offer": "offer", + "sku": "sku", + "version": "ver" + }, + "osDisk": { + "osType": "Windows", + "name": "windowsmachine", + "createOption": "FromImage", + "vhd": { + "uri": "https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd" + }, + "caching": "ReadWrite" + }, + "dataDisks": [] + }, + "osProfile": { + "computerName": "windowsmachine", + "adminUsername": "azureuser", + "windowsConfiguration": { + "provisionVMAgent": false, + "enableAutomaticUpdates": true + }, + "secrets": [] + }, + "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" + }, + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", + "name": "windowsmachine", + "type": "Microsoft.Compute/virtualMachines", + "location": "westus" + } + ] +} From f2b5c15566f2292ba9737db8cff37d5c95a605e7 Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Mon, 16 May 2016 18:55:01 -0700 Subject: [PATCH 09/87] JCLOUDS-664 Azurecompute-arm DeploymentApi OSImageApi VMSizeApi --- .../azurecompute/arm/AzureComputeApi.java | 32 ++ .../arm/config/AzureComputeHttpApiModule.java | 4 + .../arm/config/AzureComputeProperties.java | 2 + .../azurecompute/arm/domain/ComputeNode.java | 31 ++ .../azurecompute/arm/domain/Deployment.java | 254 ++++++++++++ .../arm/domain/DeploymentBody.java | 42 ++ .../arm/domain/DeploymentProperties.java | 31 ++ .../arm/domain/DeploymentTemplate.java | 105 +++++ .../azurecompute/arm/domain/Offer.java | 51 +++ .../azurecompute/arm/domain/Publisher.java | 52 +++ .../arm/domain/ResourceDefinition.java | 103 +++++ .../jclouds/azurecompute/arm/domain/SKU.java | 51 +++ .../arm/domain/StorageService.java | 48 ++- .../azurecompute/arm/domain/VMDeployment.java | 29 ++ .../azurecompute/arm/domain/VMSize.java | 67 ++++ .../azurecompute/arm/domain/Version.java | 49 +++ .../arm/features/DeploymentApi.java | 109 +++++ .../arm/features/NetworkInterfaceCardApi.java | 8 +- .../azurecompute/arm/features/OSImageApi.java | 84 ++++ .../arm/features/StorageAccountApi.java | 4 +- .../azurecompute/arm/features/VMSizeApi.java | 45 +++ .../arm/functions/ParseJobStatus.java | 3 + .../arm/util/DeploymentTemplateBuilder.java | 375 ++++++++++++++++++ .../arm/features/DeploymentApiLiveTest.java | 226 +++++++++++ .../arm/features/DeploymentApiMockTest.java | 154 +++++++ .../DeploymentTemplateBuilderTest.java | 224 +++++++++++ .../arm/features/JobApiMockTest.java | 13 +- .../NetworkInterfaceCardApiLiveTest.java | 29 +- .../NetworkInterfaceCardApiMockTest.java | 11 +- .../arm/features/OSImageApiLiveTest.java | 69 ++++ .../arm/features/OSImageApiMockTest.java | 123 ++++++ .../features/ResourceGroupApiLiveTest.java | 7 +- .../features/StorageAccountApiLiveTest.java | 4 +- .../TemplateToDeploymentTemplateLiveTest.java | 186 +++++++++ .../arm/features/VMSizeApiLiveTest.java | 40 ++ .../arm/features/VMSizeApiMockTest.java | 57 +++ .../features/VirtualMachineApiLiveTest.java | 19 +- .../arm/functions/URIParserTest.java | 4 +- .../internal/BaseAzureComputeApiLiveTest.java | 23 +- .../resources/createdeploymentaccepted.json | 33 ++ .../resources/createdeploymentsucceeded.json | 36 ++ .../src/test/resources/listdeployments.json | 99 +++++ .../src/test/resources/offers.json | 7 + .../src/test/resources/publishers.json | 12 + .../src/test/resources/skus.json | 12 + .../src/test/resources/versions.json | 12 + .../src/test/resources/vmsizes.json | 28 ++ 47 files changed, 2969 insertions(+), 38 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ComputeNode.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Deployment.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DeploymentBody.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DeploymentProperties.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DeploymentTemplate.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Offer.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Publisher.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceDefinition.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/SKU.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMDeployment.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMSize.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Version.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/DeploymentApi.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/OSImageApi.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VMSizeApi.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/DeploymentTemplateBuilder.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DeploymentApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DeploymentApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DeploymentTemplateBuilderTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/OSImageApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/OSImageApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/TemplateToDeploymentTemplateLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VMSizeApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VMSizeApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/resources/createdeploymentaccepted.json create mode 100644 providers/azurecompute-arm/src/test/resources/createdeploymentsucceeded.json create mode 100644 providers/azurecompute-arm/src/test/resources/listdeployments.json create mode 100644 providers/azurecompute-arm/src/test/resources/offers.json create mode 100644 providers/azurecompute-arm/src/test/resources/publishers.json create mode 100644 providers/azurecompute-arm/src/test/resources/skus.json create mode 100644 providers/azurecompute-arm/src/test/resources/versions.json create mode 100644 providers/azurecompute-arm/src/test/resources/vmsizes.json 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 f8ac6e9ba0..4e10089d45 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,17 +16,22 @@ */ package org.jclouds.azurecompute.arm; +import org.jclouds.azurecompute.arm.features.DeploymentApi; 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.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.rest.annotations.Delegate; +import com.google.inject.Provides; import javax.ws.rs.PathParam; import java.io.Closeable; @@ -108,4 +113,31 @@ public interface AzureComputeApi extends Closeable { @Delegate VirtualMachineApi getVirtualMachineApi(@PathParam("resourceGroup") String resourceGroup); + /** + * This Azure Resource Manager API lists all available virtual machine sizes for a subscription in a given region + * + * @see docs + */ + @Delegate + VMSizeApi getVMSizeApi(@PathParam("location") String location); + + /** + * The Azure Resource Manager API gets all the OS images in your subscription. + * + * @see docs + */ + @Delegate + OSImageApi getOSImageApi(@PathParam("location") String location); + + /** + * The Deployment API allows for the management of Azure Resource Manager resources through the use of templates. + * + * @see docs + */ + @Delegate + DeploymentApi getDeploymentApi(@PathParam("resourcegroup") String resourceGroup); + + @Provides + DeploymentTemplateBuilder.Factory deploymentTemplateFactory(); + } 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 eb6a6d6d71..30cbc1e127 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 @@ -17,6 +17,8 @@ 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; @@ -28,6 +30,7 @@ import org.jclouds.rest.ConfiguresHttpApi; import org.jclouds.rest.config.HttpApiModule; import org.jclouds.oauth.v2.config.OAuthScopes; +import com.google.inject.assistedinject.FactoryModuleBuilder; import com.google.inject.Scopes; @ConfiguresHttpApi @@ -51,6 +54,7 @@ public class AzureComputeHttpApiModule extends HttpApiModule { @Override protected void configure() { install(new AzureComputeParserModule()); + 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 e16b5da44e..48188c41d7 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 @@ -31,4 +31,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"; + } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ComputeNode.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ComputeNode.java new file mode 100644 index 0000000000..516bbf62a7 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ComputeNode.java @@ -0,0 +1,31 @@ +/* + * 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 org.jclouds.azurecompute.arm.util.GetEnumValue; + +public class ComputeNode { + public enum Status { + GOOD, + BAD, + UNRECOGNIZED; + + public static Status fromValue(final String text) { + return (Status) GetEnumValue.fromValueOrDefault(text, Status.UNRECOGNIZED); + } + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Deployment.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Deployment.java new file mode 100644 index 0000000000..2fc85bc36f --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Deployment.java @@ -0,0 +1,254 @@ +/* + * 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 static com.google.common.collect.ImmutableList.copyOf; + +import java.util.List; +import java.util.Map; + +import com.google.common.collect.ImmutableMap; +import org.jclouds.azurecompute.arm.util.GetEnumValue; +import org.jclouds.domain.JsonBall; +import org.jclouds.javax.annotation.Nullable; + +import com.google.auto.value.AutoValue; +import org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class Deployment { + + public enum ProvisioningState { + ACCEPTED, + READY, + CANCELED, + FAILED, + DELETED, + SUCCEEDED, + RUNNING, + UNRECOGNIZED; + + public static ProvisioningState fromValue(final String text) { + return (ProvisioningState) GetEnumValue.fromValueOrDefault(text, ProvisioningState.UNRECOGNIZED); + } + } + + public enum DeploymentMode { + INCREMENTAL, + COMPLETE, + UNRECOGNIZED; + + public static DeploymentMode fromValue(final String text) { + return (DeploymentMode) GetEnumValue.fromValueOrDefault(text, DeploymentMode.UNRECOGNIZED); + } + } + + @AutoValue + public abstract static class TypeValue { + public abstract String type(); + + public abstract String value(); + + @SerializedNames({"type", "value"}) + public static TypeValue create(final String type, final String value) { + return new AutoValue_Deployment_TypeValue(type, value); + } + } + + @AutoValue + public abstract static class ProviderResourceType { + @Nullable + public abstract String resourceType(); + + @Nullable + public abstract List locations(); + + @Nullable + public abstract List apiVersions(); + + @Nullable + public abstract Map properties(); + + @SerializedNames({"resourceType", "locations", "apiVersions", "properties"}) + public static ProviderResourceType create(final String resourceType, + final List locations, + final List apiVersions, + @Nullable final Map properties) { + return new AutoValue_Deployment_ProviderResourceType(resourceType, + locations == null ? null : copyOf(locations), + apiVersions == null ? null : copyOf(apiVersions), + properties == null ? ImmutableMap.builder().build() : ImmutableMap.copyOf(properties)); + } + } + + @AutoValue + public abstract static class Provider { + @Nullable + public abstract String id(); + + @Nullable + public abstract String namespace(); + + @Nullable + public abstract String registrationState(); + + @Nullable + public abstract List resourceTypes(); + + @SerializedNames({"id", "namespace", "registrationState", "resourceTypes"}) + public static Provider create(final String id, + final String namespace, + final String registrationState, + final List resourceTypes) { + return new AutoValue_Deployment_Provider(id, namespace, registrationState, resourceTypes == null ? null : copyOf(resourceTypes)); + } + } + + @AutoValue + public abstract static class Dependency { + @Nullable + public abstract List dependencies(); + + @Nullable + public abstract List dependsOn(); + + @Nullable + public abstract String id(); + + @Nullable + public abstract String resourceType(); + + @Nullable + public abstract String resourceName(); + + @SerializedNames({"dependencies", "dependsOn", "id", "resourceType", "resourceName"}) + public static Dependency create(final List dependencies, + final List dependsOn, + final String id, + final String resourceType, + final String resourceName) { + return new AutoValue_Deployment_Dependency(dependencies == null ? null : copyOf(dependencies), + dependsOn == null ? null : copyOf(dependsOn), id, resourceType, resourceName); + } + } + + @AutoValue + public abstract static class ContentLink { + public abstract String uri(); + + @Nullable + public abstract String contentVersion(); + + @SerializedNames({"uri", "contentVersion"}) + public static ContentLink create(final String uri, final String contentVersion) { + return new AutoValue_Deployment_ContentLink(uri, contentVersion); + } + } + + @AutoValue + public abstract static class DeploymentProperties { + @Nullable + public abstract String provisioningState(); + + @Nullable + public abstract String correlationId(); + + @Nullable + public abstract String timestamp(); + + @Nullable + public abstract Map outputs(); + + @Nullable + public abstract List providers(); + + @Nullable + public abstract List dependencies(); + + @Nullable + public abstract Map template(); + + @Nullable + public abstract ContentLink templateLink(); + + @Nullable + public abstract Map parameters(); + + @Nullable + public abstract ContentLink parametersLink(); + + public abstract String mode(); + + // The entries below seem to be dynamic/not documented in the specification + @Nullable + public abstract String duration(); + + @Nullable + public abstract List> outputResources(); + + @SerializedNames({"provisioningState", "correlationId", "timestamp", "outputs", "providers", "dependencies", "template", "templateLink", "parameters", "parametersLink", "mode", "duration", "outputResources"}) + public static DeploymentProperties create(final String provisioningState, + final String correlationId, + final String timestamp, + @Nullable final Map outputs, + final List providers, + final List dependencies, + final Map template, + final ContentLink templateLink, + final Map parameters, + final ContentLink parametersLink, + final String mode, + final String duration, + final List> outputResources) { + return new AutoValue_Deployment_DeploymentProperties(provisioningState, + correlationId, + timestamp, + outputs == null ? ImmutableMap.builder().build() : ImmutableMap.copyOf(outputs), + providers == null ? null : copyOf(providers), + dependencies == null ? null : copyOf(dependencies), + template == null ? ImmutableMap.builder().build() : ImmutableMap.copyOf(template), + templateLink, + parameters == null ? ImmutableMap.builder().build() : ImmutableMap.copyOf(parameters), + parametersLink, + mode, + duration, + outputResources == null ? null : copyOf(outputResources)); + } + } + + /** + * The ID associated with the template deployment. + */ + @Nullable + public abstract String id(); + + /** + * The name associated with the template deployment. + */ + public abstract String name(); + + /** + * Properties of the deployment. + */ + @Nullable + public abstract DeploymentProperties properties(); + + @SerializedNames({"id", "name", "properties"}) + public static Deployment create(final String id, final String name, final DeploymentProperties properties) { + return new AutoValue_Deployment(id, name, properties); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DeploymentBody.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DeploymentBody.java new file mode 100644 index 0000000000..0f91360a14 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DeploymentBody.java @@ -0,0 +1,42 @@ +/* + * 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 org.jclouds.azurecompute.arm.domain.DeploymentTemplate.Parameters; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class DeploymentBody { + + @Nullable + public abstract DeploymentTemplate template(); + + @Nullable + public abstract String mode(); + + @Nullable + public abstract Parameters parameters(); + + @SerializedNames({"template", "mode", "parameters"}) + public static DeploymentBody create(final DeploymentTemplate template, + final String mode, + final Parameters parameters) { + return new AutoValue_DeploymentBody(template, mode, parameters); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DeploymentProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DeploymentProperties.java new file mode 100644 index 0000000000..94b53c58f5 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DeploymentProperties.java @@ -0,0 +1,31 @@ +/* + * 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 org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class DeploymentProperties { + + public abstract DeploymentBody properties(); + + @SerializedNames({"properties"}) + public static DeploymentProperties create(final DeploymentBody properties) { + return new AutoValue_DeploymentProperties(properties); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DeploymentTemplate.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DeploymentTemplate.java new file mode 100644 index 0000000000..848000ddae --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DeploymentTemplate.java @@ -0,0 +1,105 @@ +/* + * 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 com.google.common.collect.ImmutableMap; +import org.jclouds.javax.annotation.Nullable; + +import java.util.List; +import java.util.Map; +import org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class DeploymentTemplate { + + //Empty placeholders as we want to generate the empty JSON object + @AutoValue + public abstract static class Parameters { + public static Parameters create() { + return new AutoValue_DeploymentTemplate_Parameters(); + } + } + + public abstract String schema(); + + public abstract String contentVersion(); + + public abstract Parameters parameters(); + + public abstract Map variables(); + + public abstract List resources(); + + @Nullable + public abstract List outputs(); + + @SerializedNames({"$schema", "contentVersion", "parameters", "variables", "resources" , "outputs"}) + public static DeploymentTemplate create(final String schema, + final String contentVersion, + final Parameters parameters, + final Map variables, + final List resources, + final List outputs) { + + DeploymentTemplate.Builder builder = DeploymentTemplate.builder() + .schema(schema) + .contentVersion(contentVersion) + .parameters(parameters); + + if (variables != null) + builder.variables(variables); + + if (resources != null) + builder.resources(resources); + + builder.outputs(outputs == null ? null : ImmutableList.copyOf(outputs)); + + return builder.build(); + } + + public static Builder builder() { + return new AutoValue_DeploymentTemplate.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder schema(String schema); + + public abstract Builder contentVersion(String type); + + public abstract Builder parameters(Parameters parameters); + + public abstract Builder variables(Map variables); + + public abstract Builder resources(List resources); + + public abstract Builder outputs(List outputs); + + abstract Map variables(); + abstract List resources(); + + abstract DeploymentTemplate autoBuild(); + + public DeploymentTemplate build() { + variables(variables() != null ? ImmutableMap.copyOf(variables()) : null); + resources(resources() != null ? ImmutableList.copyOf(resources()) : null); + return autoBuild(); + } + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Offer.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Offer.java new file mode 100644 index 0000000000..d44c8f8c85 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Offer.java @@ -0,0 +1,51 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +/** + * Offer + */ +@AutoValue +public abstract class Offer { + /** + * The location of the Offer + */ + @Nullable + public abstract String location(); + + /** + * The name of the Offer + */ + @Nullable + public abstract String name(); + + /** + * The id of the Offer + */ + @Nullable + public abstract String id(); + + @SerializedNames({"location", "name", "id"}) + public static Offer create(final String location, final String name, final String id) { + + return new AutoValue_Offer(location, name, id); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Publisher.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Publisher.java new file mode 100644 index 0000000000..4f5c53fb21 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Publisher.java @@ -0,0 +1,52 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +/** + * Publisher + */ +@AutoValue +public abstract class Publisher { + + /** + * The location of the publisher + */ + @Nullable + public abstract String location(); + + /** + * The name of the publisher + */ + @Nullable + public abstract String name(); + + /** + * The id of the publisher + */ + @Nullable + public abstract String id(); + + @SerializedNames({"location", "name", "id"}) + public static Publisher create(final String location, final String name, final String id) { + + return new AutoValue_Publisher(location, name, id); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceDefinition.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceDefinition.java new file mode 100644 index 0000000000..7c68e8007c --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceDefinition.java @@ -0,0 +1,103 @@ +/* + * 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 com.google.common.collect.ImmutableMap; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import java.util.List; +import java.util.Map; + +@AutoValue +public abstract class ResourceDefinition { + + public abstract String name(); + + public abstract String type(); + + public abstract String location(); + + public abstract String apiVersion(); + + @Nullable + public abstract List dependsOn(); + + @Nullable + public abstract Map tags(); + + @Nullable + public abstract Object properties(); + + @SerializedNames({"name", "type", "location", "apiVersion", "dependsOn", "tags", "properties"}) + public static ResourceDefinition create(final String name, + final String type, + final String location, + final String apiVersion, + final List dependsOn, + final Map tags, + final Object properties) { + ResourceDefinition.Builder builder = ResourceDefinition.builder() + .name(name) + .type(type) + .location(location) + .apiVersion(apiVersion) + .properties(properties); + + builder.dependsOn(dependsOn == null ? null : ImmutableList.copyOf(dependsOn)); + + builder.tags(tags == null ? null : ImmutableMap.copyOf(tags)); + + return builder.build(); + } + + public static Builder builder() { + return new AutoValue_ResourceDefinition.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder name(String name); + + public abstract Builder type(String type); + + public abstract Builder location(String location); + + public abstract Builder apiVersion(String apiVersion); + + public abstract Builder dependsOn(List dependencies); + + public abstract Builder tags(Map tags); + + public abstract Builder properties(Object properties); + + abstract List dependsOn(); + abstract Map tags(); + + abstract ResourceDefinition autoBuild(); + + public ResourceDefinition build() { + dependsOn(dependsOn() != null ? ImmutableList.copyOf(dependsOn()) : null); + tags(tags() != null ? ImmutableMap.copyOf(tags()) : null); + return autoBuild(); + } + } + +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/SKU.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/SKU.java new file mode 100644 index 0000000000..4c414e54d6 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/SKU.java @@ -0,0 +1,51 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +/** + * SKU + */ +@AutoValue +public abstract class SKU { + /** + * The location of the SKU + */ + @Nullable + public abstract String location(); + + /** + * The name of the SKU + */ + @Nullable + public abstract String name(); + + /** + * The id of the SKU + */ + @Nullable + public abstract String id(); + + @SerializedNames({"location", "name", "id"}) + public static SKU create(final String location, final String name, final String id) { + + return new AutoValue_SKU(location, name, id); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageService.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageService.java index a151aec6ca..a97117fd33 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageService.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageService.java @@ -19,7 +19,6 @@ package org.jclouds.azurecompute.arm.domain; import com.google.auto.value.AutoValue; import java.util.Date; import java.util.Map; - import com.google.common.collect.ImmutableMap; import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; @@ -83,11 +82,13 @@ public abstract class StorageService { /** * Specifies the time that the storage account was created. */ + @Nullable public abstract Date creationTime(); /** * Specifies the endpoints of the storage account. */ + @Nullable public abstract Map primaryEndpoints(); /** @@ -105,6 +106,7 @@ public abstract class StorageService { /** * Specifies the secondary endpoints of the storage account. */ + @Nullable public abstract Map secondaryEndpoints(); /** @@ -133,9 +135,47 @@ public abstract class StorageService { final Map secondaryEndpoints, final String secondaryLocation, final RegionStatus statusOfPrimary, final RegionStatus statusOfSecondary) { - return new AutoValue_StorageService_StorageServiceProperties(accountType, creationTime, - primaryEndpoints == null ? ImmutableMap.builder().build() : ImmutableMap.copyOf(primaryEndpoints), primaryLocation, provisioningState, - secondaryEndpoints == null ? ImmutableMap.builder().build() : ImmutableMap.copyOf(secondaryEndpoints), secondaryLocation, statusOfPrimary, statusOfSecondary); + StorageServiceProperties.Builder builder = StorageServiceProperties.builder() + .accountType(accountType) + .creationTime(creationTime) + .primaryLocation(primaryLocation) + .provisioningState(provisioningState) + .secondaryLocation(secondaryLocation) + .statusOfPrimary(statusOfPrimary) + .statusOfSecondary(statusOfSecondary); + + + builder.primaryEndpoints(primaryEndpoints != null ? ImmutableMap.copyOf(primaryEndpoints) : null); + builder.secondaryEndpoints(secondaryEndpoints != null ? ImmutableMap.copyOf(secondaryEndpoints) : null); + + return builder.build(); + } + public static Builder builder() { + return new AutoValue_StorageService_StorageServiceProperties.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder accountType(AccountType accountType); + public abstract Builder creationTime(Date creationTime); + public abstract Builder primaryEndpoints(Map primaryEndpoints); + public abstract Builder primaryLocation(String primaryLocation); + public abstract Builder provisioningState(Status provisioningState); + public abstract Builder secondaryEndpoints(Map secondaryEndpoints); + public abstract Builder secondaryLocation(String secondaryLocation); + public abstract Builder statusOfPrimary(RegionStatus statusOfPrimary); + public abstract Builder statusOfSecondary(RegionStatus statusOfSecondary); + + abstract Map primaryEndpoints(); + abstract Map secondaryEndpoints(); + + abstract StorageServiceProperties autoBuild(); + + public StorageServiceProperties build() { + primaryEndpoints(primaryEndpoints() != null ? ImmutableMap.copyOf(primaryEndpoints()) : null); + secondaryEndpoints(secondaryEndpoints() != null ? ImmutableMap.copyOf(secondaryEndpoints()) : null); + return autoBuild(); + } } } 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 new file mode 100644 index 0000000000..2504409319 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMDeployment.java @@ -0,0 +1,29 @@ +/* + * 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 java.util.List; + +public class VMDeployment { + + public Deployment deployment; + + public List ipAddressList; + + public VirtualMachineInstance vm; +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMSize.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMSize.java new file mode 100644 index 0000000000..6794735e39 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMSize.java @@ -0,0 +1,67 @@ +/* + * 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 org.jclouds.json.SerializedNames; + +/** + * A VM Size that is available in a region for a given subscription. + * + * @see api + */ +@AutoValue +public abstract class VMSize { + + /** + * The name of the VM size. + */ + public abstract String name(); + + /** + * The number of cores that are available in the VM size. + */ + public abstract Integer numberOfCores(); + + /** + * Specifies the size in MB of the OS Disk. + */ + public abstract Integer osDiskSizeInMB(); + + /** + * The size of the resource disk. + */ + public abstract Integer resourceDiskSizeInMB(); + + /** + * Specifies the available RAM in MB. + */ + public abstract Integer memoryInMB(); + + /** + * Specifies the maximum number of data disks that can be attached to the VM size. + */ + public abstract Integer maxDataDiskCount(); + + @SerializedNames({ "name", "numberOfCores", "osDiskSizeInMB", "resourceDiskSizeInMB", "memoryInMB", "maxDataDiskCount"}) + public static VMSize create(final String name, final Integer numberOfCores, final Integer osDiskSizeInMB, + final Integer resourceDiskSizeInMB, final Integer memoryInMB, final Integer maxDataDiskCount) { + + return new AutoValue_VMSize(name, numberOfCores, osDiskSizeInMB, resourceDiskSizeInMB, memoryInMB, maxDataDiskCount); + } + +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Version.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Version.java new file mode 100644 index 0000000000..63d7e11fb0 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Version.java @@ -0,0 +1,49 @@ +/* + * 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 org.jclouds.json.SerializedNames; + +/** + * Version + */ +@AutoValue +public abstract class Version { + + /** + * The location of the Version + */ + public abstract String location(); + + /** + * The name of the Version + */ + public abstract String name(); + + /** + * The id of the Version + */ + public abstract String id(); + + @SerializedNames({"location", "name", "id"}) + public static Version create(final String location, final String name, final String id) { + + return new AutoValue_Version(location, name, id); + } +} + 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 new file mode 100644 index 0000000000..550f8ea860 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/DeploymentApi.java @@ -0,0 +1,109 @@ +/* + * 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 javax.inject.Named; +import javax.ws.rs.DELETE; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Consumes; +import javax.ws.rs.PUT; +import javax.ws.rs.GET; +import javax.ws.rs.Produces; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.MediaType; + +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.functions.URIParser; +import org.jclouds.oauth.v2.filters.OAuthFilter; +import org.jclouds.rest.annotations.QueryParams; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.Payload; +import org.jclouds.rest.annotations.PayloadParam; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SelectJson; + +import java.net.URI; +import java.util.List; + +/** + * - create deployment + * - delete deployment + * - get information about deployment + */ +@Path("/resourcegroups/{resourcegroup}/providers/microsoft.resources/deployments") +@QueryParams(keys = "api-version", values = "2016-02-01") +@RequestFilters(OAuthFilter.class) +@Consumes(MediaType.APPLICATION_JSON) +public interface DeploymentApi { + + /** + * The Create Template Deployment operation starts the process of an ARM Template deployment. + * It then returns a Deployment object. + */ + @Named("deployment:create") + @Path("/{deploymentname}") + @Payload("{properties}") + @PUT + @Produces(MediaType.APPLICATION_JSON) + Deployment create(@PathParam("deploymentname") String deploymentname, + @PayloadParam("properties") String properties); + + /** + * Get Deployment Information returns information about the specified deployment. + */ + @Named("deployment:get") + @Path("/{deploymentname}") + @GET + @Fallback(NullOnNotFoundOr404.class) + Deployment get(@PathParam("deploymentname") String deploymentname); + + /** + * Validate Deployment validates deployment template before deployment + */ + @Named("deployment:validate") + @Path("/{deploymentname}/validate") + @Payload("{properties}") + @POST + @Produces(MediaType.APPLICATION_JSON) + Deployment validate(@PathParam("deploymentname") String deploymentname, + @PayloadParam("properties") String properties); + + /** + * List all deployments in a resource group + */ + @Named("deployment:list") + @GET + @SelectJson("value") + @Fallback(EmptyListOnNotFoundOr404.class) + List list(); + + /** + * The Delete Template Deployment operation starts the process of an ARM Template removal. + */ + @Named("deployment:delete") + @DELETE + @ResponseParser(URIParser.class) + @Path("/{deploymentname}") + @Fallback(Fallbacks.NullOnNotFoundOr404.class) + URI delete(@PathParam("deploymentname") String deploymentname); +} 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 c7c665d78f..2f19996901 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 @@ -20,7 +20,7 @@ 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.FalseOn204; +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; @@ -41,6 +41,7 @@ import javax.ws.rs.PathParam; import javax.ws.rs.core.MediaType; import java.util.List; import java.util.Map; +import java.net.URI; @Path("/resourcegroups/{resourcegroup}/providers/Microsoft.Network/networkInterfaces") @QueryParams(keys = "api-version", values = "2015-06-15") @@ -73,6 +74,7 @@ public interface NetworkInterfaceCardApi { @Named("networkinterfacecard:delete") @Path("/{networkinterfacecardname}") @DELETE - @ResponseParser(FalseOn204.class) - boolean delete(@PathParam("networkinterfacecardname") String networkinterfacecardname); + @ResponseParser(URIParser.class) + @Fallback(NullOnNotFoundOr404.class) + URI delete(@PathParam("networkinterfacecardname") String networkinterfacecardname); } 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 new file mode 100644 index 0000000000..96dce6b92e --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/OSImageApi.java @@ -0,0 +1,84 @@ +/* + * 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 static javax.ws.rs.core.MediaType.APPLICATION_JSON; + +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.PathParam; + +import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; +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.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") +@Consumes(APPLICATION_JSON) +public interface OSImageApi { + + /** + * List Publishers in location + */ + @Named("publisher:list") + @GET + @Path("/publishers") + @Fallback(EmptyListOnNotFoundOr404.class) + List listPublishers(); + + /** + * List Offers in publisher + */ + @Named("offer:list") + @GET + @Path("/publishers/{publisher}/artifacttypes/vmimage/offers") + @Fallback(EmptyListOnNotFoundOr404.class) + List listOffers(@PathParam("publisher") String publisher); + + /** + * List SKUs in offer + */ + @Named("sku:list") + @GET + @Path("/publishers/{publisher}/artifacttypes/vmimage/offers/{offer}/skus") + @Fallback(EmptyListOnNotFoundOr404.class) + List listSKUs(@PathParam("publisher") String publisher, @PathParam("offer") String offer); + + /** + * List Versions in SKU + */ + @Named("version:list") + @GET + @Path("/publishers/{publisher}/artifacttypes/vmimage/offers/{offer}/skus/{sku}/versions") + @Fallback(EmptyListOnNotFoundOr404.class) + List listVersions(@PathParam("publisher") String publisher, @PathParam("offer") String offer, + @PathParam("sku") String sku); +} 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 8ebfc821ff..fd75fcab37 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 @@ -51,6 +51,8 @@ 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. * @@ -58,7 +60,7 @@ import java.net.URI; */ @Path("/") @RequestFilters(OAuthFilter.class) -@QueryParams(keys = "api-version", values = "2015-06-15") +@QueryParams(keys = "api-version", values = STORAGE_API_VERSION) @Consumes(MediaType.APPLICATION_JSON) public interface StorageAccountApi { 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 new file mode 100644 index 0000000000..345e08c40e --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VMSizeApi.java @@ -0,0 +1,45 @@ +/* + * 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.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 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; + +@Path("/providers/Microsoft.Compute/locations/{location}/vmSizes") +@QueryParams(keys = "api-version", values = "2015-06-15") +@RequestFilters(OAuthFilter.class) +@Consumes(MediaType.APPLICATION_JSON) +public interface VMSizeApi { + + @Named("vmSizes:list") + @GET + @SelectJson("value") + @Fallback(EmptyListOnNotFoundOr404.class) + List list(); +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/ParseJobStatus.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/ParseJobStatus.java index 5770582ae7..045431caaa 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/ParseJobStatus.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/ParseJobStatus.java @@ -30,6 +30,7 @@ public class ParseJobStatus implements Function resources; + private Map variables; + private String loginUser; + private String loginPassword; + private String location; + + public static final String DEFAULT_LOGIN_USER = "jclouds"; + public static final String DEFAULT_LOGIN_PASSWORD = "Password1!"; + private static final String DEPLOYMENT_MODE = "Incremental"; + private static final String DEFAULT_DATA_DISK_SIZE = "1023"; + + private static final String DEFAULT_vnAddresSpacePrefix = "10.0.0.0/16"; + private static final String DEFAULT_subnetAddressPrefix = "10.0.0.0/24"; + + @Inject + DeploymentTemplateBuilder(Json json, @Assisted("group") String group, @Assisted("name") String name, @Assisted Template template) { + this.name = name; + this.group = group; + this.template = template; + this.options = template.getOptions().as(TemplateOptions.class); + this.variables = new HashMap(); + this.resources = new ArrayList(); + this.loginUser = options.getLoginUser() == null ? DEFAULT_LOGIN_USER : options.getLoginUser(); + this.loginPassword = options.getLoginPassword() == null ? DEFAULT_LOGIN_PASSWORD : options.getLoginPassword(); + this.location = template.getLocation().getId(); + this.json = json; + } + + public String getLoginUserUsername() { + return loginUser; + } + + public String getLoginPassword() { + return loginPassword; + } + + public Template getTemplate() { + return template; + } + + public DeploymentBody getDeploymentTemplate() { + + addStorageResource(); + addVirtualNetworkResource(); + addPublicIpAddress(); + addNetworkInterfaceCard(); + addVirtualMachine(); + + 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(DeploymentTemplate.Parameters.create()) + .build(); + + DeploymentBody body = DeploymentBody.create(template, DEPLOYMENT_MODE, DeploymentTemplate.Parameters.create()); + + return body; + } + + public String getDeploymentTemplateJson(DeploymentProperties properties){ + return json.toJson(properties); + } + + private void addStorageResource() { + String storageAccountName = name.replaceAll("[^A-Za-z0-9 ]", "") + "storage"; + + 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 addVirtualNetworkResource() { + String virtualNetworkName = group + "virtualnetwork"; + + String subnetName = group + "subnet"; + variables.put("virtualNetworkName", virtualNetworkName); + variables.put("virtualNetworkReference", "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]"); + variables.put("subnetName", subnetName); + variables.put("subnetReference", "[concat(variables('virtualNetworkReference'),'/subnets/',variables('subnetName'))]"); + + VirtualNetworkProperties properties = VirtualNetworkProperties.builder() + .addressSpace( + AddressSpace.create(Arrays.asList(DEFAULT_vnAddresSpacePrefix)) + ) + .subnets( + Arrays.asList( + Subnet.create("[variables('subnetName')]", null, null, + SubnetProperties.builder() + .addressPrefix(DEFAULT_subnetAddressPrefix).build() + )) + ) + .build(); + + + ResourceDefinition virtualNetwork = ResourceDefinition.builder() + .name("[variables('virtualNetworkName')]") + .type("Microsoft.Network/virtualNetworks") + .location(location) + .apiVersion(STORAGE_API_VERSION) + .properties(properties) + .build(); + + resources.add(virtualNetwork); + } + + private void addPublicIpAddress() { + String publicIPAddressName = name + "publicip"; + String dnsLabelPrefix = name; //TODO: read from Azure template properties + + PublicIPAddressProperties.Builder properties = PublicIPAddressProperties.builder(); + + if (!dnsLabelPrefix.isEmpty()) { + 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"; + variables.put("ipConfigurationName", ipConfigurationName); + + 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); + + NetworkInterfaceCardProperties networkInterfaceCardProperties = NetworkInterfaceCardProperties.builder() + .ipConfigurations(ipConfigurations) + .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(Arrays.asList("[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]", + "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]")) + .properties(networkInterfaceCardProperties) + .build(); + + resources.add(networkInterfaceCard); + } + + private void addVirtualMachine() { + + //Build OS Profile + final String computerName = name + "pc"; + + variables.put("loginUser", loginUser); + OSProfile.Builder profileBuilder = OSProfile.builder() + .adminUsername(loginUser) + .computerName(computerName); + + boolean usePublicKey = options.getPublicKey() != null; + + if (usePublicKey) { + OSProfile.LinuxConfiguration configuration = OSProfile.LinuxConfiguration.create("true", + OSProfile.LinuxConfiguration.SSH.create(Arrays.asList( + OSProfile.LinuxConfiguration.SSH.SSHPublicKey.create( + "[concat('/home/',variables('loginUser'),'/.ssh/authorized_keys')]", + options.getPublicKey()) + )) + ); + profileBuilder.linuxConfiguration(configuration); + } else { + profileBuilder.adminPassword(loginPassword); + } + + OSProfile osProfile = profileBuilder.build(); + + //Build Image Reference + final String imagePublisher = template.getImage().getProviderId(); + final String imageOffer = template.getImage().getName(); + final String imageSku = template.getImage().getVersion(); + + ImageReference imageReference = ImageReference.builder() + .publisher(imagePublisher) + .offer(imageOffer) + .sku(imageSku) + .version("latest") + .build(); + + //Build OsDisk + final String storageAccountContainerName = "vhds"; + variables.put("storageAccountContainerName", storageAccountContainerName); + + final String osDiskName = name + "osdisk"; + variables.put("osDiskName", osDiskName); + + OSDisk osDisk = OSDisk.builder() + .name("[variables('osDiskName')]") + .vhd( + VHD.create("[concat('http://',variables('storageAccountName'),'.blob.core.windows.net/',variables('storageAccountContainerName'),'/',variables('osDiskName'),'.vhd')]") + ) + .caching("ReadWrite") + .createOption("FromImage") + .build(); + + + //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(DEFAULT_DATA_DISK_SIZE) + .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 storageProfile = StorageProfile.builder() + .imageReference(imageReference) + .osDisk(osDisk) + .dataDisks(dataDisks) + .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(); + + variables.put("virtualMachineName", name); + ResourceDefinition virtualMachine = ResourceDefinition.builder() + .name("[variables('virtualMachineName')]") + .type("Microsoft.Compute/virtualMachines") + .location(location) + .apiVersion(STORAGE_API_VERSION) + .dependsOn(Arrays.asList("[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]", + "[concat('Microsoft.Network/networkInterfaces/', variables('networkInterfaceCardName'))]")) + .tags(ImmutableMap.of("displayName", "VirtualMachine")) + .properties(properties) + .build(); + + resources.add(virtualMachine); + } + +} 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 new file mode 100644 index 0000000000..0e2baefcc7 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DeploymentApiLiveTest.java @@ -0,0 +1,226 @@ +/* + * 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 com.google.common.base.Predicate; +import com.google.common.net.UrlEscapers; +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.functions.ParseJobStatus; +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.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.net.URI; +import java.util.List; + +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; + +@Test(groups = "live", testName = "DeploymentApiLiveTest", singleThreaded = true) +public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest { + private int maxTestDuration = 190; + + private String resourceName; + private String deploymentName; + private String rawtemplate; + private String rawparameters; + private String rawbadParameters; + private String properties; + private String badProperties; + + @BeforeClass + @Override + public void setup() { + super.setup(); + resourceName = getResourceGroupName(); + Long now = System.currentTimeMillis(); + deploymentName = "jc" + now; + + rawtemplate = "{\"$schema\":\"https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\"contentVersion\":\"1.0.0.0\",\"parameters\":{\"newStorageAccountName\":{\"type\":\"string\",\"metadata\":{\"description\":\"Name of the Storage Account\"}},\"storageAccountType\":{\"type\":\"string\",\"defaultValue\":\"Standard_LRS\",\"allowedValues\":[\"Standard_LRS\",\"Standard_GRS\",\"Standard_ZRS\"],\"metadata\":{\"description\":\"Storage Account type\"}},\"location\":{\"type\":\"string\",\"allowedValues\":[\"East US\",\"West US\",\"West Europe\",\"East Asia\",\"Southeast Asia\"],\"metadata\":{\"description\":\"Location of storage account\"}}},\"resources\":[{\"type\":\"Microsoft.Storage/storageAccounts\",\"name\":\"[parameters('newStorageAccountName')]\",\"apiVersion\":\"2015-05-01-preview\",\"location\":\"[parameters('location')]\",\"properties\":{\"accountType\":\"[parameters('storageAccountType')]\"}}]}"; + rawparameters = "{\"newStorageAccountName\":{\"value\":\"" + resourceName + "\"},\"storageAccountType\":{\"value\":\"Standard_LRS\"},\"location\":{\"value\":\"West US\"}}"; + rawbadParameters = "{\"newStorageAccountName\":{\"value\":\"" + resourceName + "\"},\"storageAccountType\":{\"value\":\"Standard_LRS\"},\"location\":{\"value\":\"West\"}}"; + + properties = getPutBody(rawtemplate, "Incremental", rawparameters); + badProperties = getPutBody(rawtemplate, "Incremental", rawbadParameters); + } + + private String getPutBody(String template, String mode, String parameters) { + String body = "{ " + + "\"properties\" : " + + " { " + + " \"template\" : " + template + ", " + + " \"mode\" : \"" + mode + "\", " + + " \"parameters\" : " + parameters + " " + + " } " + + "}"; + 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("northeurope").description("North 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(resourceName, deploymentName, template); + return templateBuilder; + } + + @Test(groups = "live") + public void testValidate(){ + Deployment deploymentInvalid = null; + try { + deploymentInvalid = api().validate(deploymentName + "invalid", badProperties); + } catch (Exception ex) { + assertTrue(ex.getClass() == java.lang.IllegalArgumentException.class); + } + assertNull(deploymentInvalid); + + Deployment deploymentValid = null; + try { + deploymentValid = api().validate(deploymentName + "valid", properties); + } catch (Exception ex) { + assertTrue(ex.getClass() == java.lang.IllegalArgumentException.class); + } + assertNotNull(deploymentValid); + } + @Test(groups = "live") + public void testCreate() { + 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 TemplateOptions(); + 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 deploymentValid = api().validate(deploymentName, deploymentTemplate); + assertNotNull(deploymentValid); + + Deployment deployment = api().create(deploymentName, deploymentTemplate); + assertNotNull(deployment); + + //Poll until resource is ready to be used + boolean jobDone = Predicates2.retry(new Predicate() { + @Override + public boolean apply(String name) { + Deployment dp = api().get(deploymentName); + ProvisioningState state = ProvisioningState.fromValue(dp.properties().provisioningState()); + return state == ProvisioningState.SUCCEEDED; + } + }, 60 * maxTestDuration * 1000).apply(deploymentName); + assertTrue(jobDone, "create operation did not complete in the configured timeout"); + + Deployment dp = api().get(deploymentName); + ProvisioningState state = ProvisioningState.fromValue(dp.properties().provisioningState()); + assertTrue(state == ProvisioningState.SUCCEEDED); + } + + + @Test(groups = "live", dependsOnMethods = "testCreate") + public void testGetDeployment() { + Deployment deployment = api().get(deploymentName); + assertNotNull(deployment); + ProvisioningState state = ProvisioningState.fromValue(deployment.properties().provisioningState()); + assertTrue(state == ProvisioningState.SUCCEEDED); + } + + @Test(groups = "live", dependsOnMethods = "testCreate") + public void testListDeployments() { + List deployments = api().list(); + assertTrue(deployments.size() > 0); + boolean deploymentFound = false; + for (Deployment d : deployments) { + + if (d.name().equals(deploymentName)) { + deploymentFound = true; + break; + } + } + assertTrue(deploymentFound); + + } + + @Test(groups = "live", dependsOnMethods = {"testGetDeployment", "testListDeployments"}, alwaysRun = true) + public void testDelete() throws Exception { + List deployments = api().list(); + for (Deployment d : deployments) { + if (d.name().contains("jc")) { + URI uri = api().delete(d.name()); + assertNotNull(uri); + assertTrue(uri.toString().contains("api-version")); + assertTrue(uri.toString().contains("operationresults")); + + boolean jobDone = Predicates2.retry(new Predicate() { + @Override + public boolean apply(URI uri) { + return ParseJobStatus.JobStatus.NO_CONTENT == api.getJobApi().jobStatus(uri); + } + }, 60 * maxTestDuration * 1000).apply(uri); + assertTrue(jobDone, "delete operation did not complete in the configured timeout"); + } + } + } + + private DeploymentApi api() { + return api.getDeploymentApi(resourceName); + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DeploymentApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DeploymentApiMockTest.java new file mode 100644 index 0000000000..89d6acaba7 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DeploymentApiMockTest.java @@ -0,0 +1,154 @@ +/* + * 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.azurecompute.arm.domain.Deployment; +import org.jclouds.azurecompute.arm.domain.Deployment.ProvisioningState; +import com.squareup.okhttp.mockwebserver.MockResponse; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; +import org.testng.annotations.Test; + +import java.net.URI; +import java.util.List; + +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertEquals; + +@Test(groups = "unit", testName = "DeploymentApiMockTest", singleThreaded = true) +public class DeploymentApiMockTest extends BaseAzureComputeApiMockTest { + + private String subscriptionId = "SUBSCRIPTIONID"; + private String resourceGroup = "resourceGroup"; + private String deploymentName = "jcdep1458344383064"; + private String resourceName = "jcres1458344383064"; + + private String getPutBody(String template, String mode, String parameters) { + String body = "{ " + + "\"properties\" : " + + " { " + + " \"template\" : " + template + ", " + + " \"mode\" : \"" + mode + "\", " + + " \"parameters\" : " + parameters + " " + + " } " + + "}"; + return body; + } + + @Test + public void testCreateDeployment() throws Exception { + final DeploymentApi deploymentApi = api.getDeploymentApi(resourceGroup); + + // check if deployment accepted + server.enqueue(jsonResponse("/createdeploymentaccepted.json")); + String template = "{\"$schema\":\"https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\"contentVersion\":\"1.0.0.0\",\"parameters\":{\"newStorageAccountName\":{\"type\":\"string\",\"metadata\":{\"description\":\"Name of the Storage Account\"}},\"storageAccountType\":{\"type\":\"string\",\"defaultValue\":\"Standard_LRS\",\"allowedValues\":[\"Standard_LRS\",\"Standard_GRS\",\"Standard_ZRS\"],\"metadata\":{\"description\":\"Storage Account type\"}},\"location\":{\"type\":\"string\",\"allowedValues\":[\"East US\",\"West US\",\"West Europe\",\"East Asia\",\"Southeast Asia\"],\"metadata\":{\"description\":\"Location of storage account\"}}},\"resources\":[{\"type\":\"Microsoft.Storage/storageAccounts\",\"name\":\"[parameters('newStorageAccountName')]\",\"apiVersion\":\"2015-05-01-preview\",\"location\":\"[parameters('location')]\",\"properties\":{\"accountType\":\"[parameters('storageAccountType')]\"}}]}"; + String parameters = "{\"newStorageAccountName\":{\"value\":\"" + resourceName + "\"},\"storageAccountType\":{\"value\":\"Standard_LRS\"},\"location\":{\"value\":\"West US\"}}"; + String properties = getPutBody(template, "Incremental", parameters); + Deployment deployment = deploymentApi.create(deploymentName, properties); + assertTrue(deployment != null); + assertEquals(ProvisioningState.fromValue(deployment.properties().provisioningState()), ProvisioningState.ACCEPTED); + + // check if deployment succeeded + server.enqueue(jsonResponse("/createdeploymentsucceeded.json")); + deployment = deploymentApi.create(deploymentName, properties); + assertTrue(deployment != null); + assertEquals(ProvisioningState.fromValue(deployment.properties().provisioningState()), ProvisioningState.SUCCEEDED); + assertSent(server, "PUT", "/subscriptions/" + subscriptionId + "/resourcegroups/" + resourceGroup + + "/providers/microsoft.resources/deployments/" + deploymentName + "?api-version=2016-02-01", properties); + } + + @Test + public void testGetDeployment() throws Exception { + final DeploymentApi deploymentApi = api.getDeploymentApi(resourceGroup); + + // check if deployment succeeded + server.enqueue(jsonResponse("/createdeploymentsucceeded.json")); + Deployment deployment = deploymentApi.get(deploymentName); + assertTrue(deployment != null); + assertEquals(ProvisioningState.fromValue(deployment.properties().provisioningState()), ProvisioningState.SUCCEEDED); + assertSent(server, "GET", "/subscriptions/" + subscriptionId + "/resourcegroups/" + resourceGroup + + "/providers/microsoft.resources/deployments/" + deploymentName + "?api-version=2016-02-01"); + } + + @Test + public void testGetDeploymentEmpty() throws Exception { + final DeploymentApi deploymentApi = api.getDeploymentApi(resourceGroup); + + server.enqueue(new MockResponse().setResponseCode(404)); + + Deployment deployment = deploymentApi.get(deploymentName); + assertNull(deployment); + + assertSent(server, "GET", "/subscriptions/" + subscriptionId + "/resourcegroups/" + resourceGroup + + "/providers/microsoft.resources/deployments/" + deploymentName + "?api-version=2016-02-01"); + } + + @Test + public void testListDeployment() throws Exception { + final DeploymentApi deploymentApi = api.getDeploymentApi(resourceGroup); + + // check if deployment succeeded + server.enqueue(jsonResponse("/listdeployments.json")); + List deployments = deploymentApi.list(); + assertTrue(deployments.size() > 0); + + assertSent(server, "GET", "/subscriptions/" + subscriptionId + "/resourcegroups/" + resourceGroup + + "/providers/microsoft.resources/deployments?api-version=2016-02-01"); + + } + + @Test + public void testListDeploymentEmpty() throws Exception { + final DeploymentApi deploymentApi = api.getDeploymentApi(resourceGroup); + + server.enqueue(new MockResponse().setResponseCode(404)); + + List deployments = deploymentApi.list(); + assertTrue(deployments.size() == 0); + + assertSent(server, "GET", "/subscriptions/" + subscriptionId + "/resourcegroups/" + resourceGroup + + "/providers/microsoft.resources/deployments?api-version=2016-02-01"); + + } + + @Test + public void testDeleteDeployment() throws InterruptedException { + final DeploymentApi deploymentApi = api.getDeploymentApi(resourceGroup); + + server.enqueue(response202WithHeader()); + + URI uri = deploymentApi.delete(deploymentName); + assertNotNull(uri); + + assertSent(server, "DELETE", "/subscriptions/" + subscriptionId + "/resourcegroups/" + resourceGroup + + "/providers/microsoft.resources/deployments/" + deploymentName + "?api-version=2016-02-01"); + } + + @Test + public void testDeleteDeploymentReturns404() throws InterruptedException { + final DeploymentApi deploymentApi = api.getDeploymentApi(resourceGroup); + + server.enqueue(response404()); + + URI uri = deploymentApi.delete(deploymentName); + assertNull(uri); + + assertSent(server, "DELETE", "/subscriptions/" + subscriptionId + "/resourcegroups/" + resourceGroup + + "/providers/microsoft.resources/deployments/" + deploymentName + "?api-version=2016-02-01"); + } +} 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 new file mode 100644 index 0000000000..bc505e7b9b --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DeploymentTemplateBuilderTest.java @@ -0,0 +1,224 @@ +/* + * 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.azurecompute.arm.internal.BaseAzureComputeApiMockTest; +import org.jclouds.compute.options.TemplateOptions; +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.OSProfile; +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.domain.VirtualNetwork.VirtualNetworkProperties; +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.domain.Location; +import org.jclouds.domain.LocationBuilder; +import org.jclouds.domain.LocationScope; +import org.testng.annotations.Test; + +import java.util.Map; +import java.util.List; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + + +@Test(groups = "unit", testName = "DeploymentTemplateBuilderTest", singleThreaded = true) +public class DeploymentTemplateBuilderTest extends BaseAzureComputeApiMockTest { + + final String group = "jcgroup"; + + @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 testVirtualNetwork() { + DeploymentTemplateBuilder builder = getMockDeploymentTemplateBuilderWithEmptyOptions(); + DeploymentBody deploymentBody = builder.getDeploymentTemplate(); + List resources = deploymentBody.template().resources(); + Map variables = deploymentBody.template().variables(); + + ResourceDefinition resource = getResourceByType(resources, "Microsoft.Network/virtualNetworks"); + + VirtualNetworkProperties properties = (VirtualNetworkProperties) resource.properties(); + assertTrue(properties.addressSpace().addressPrefixes().size() > 0); + assertTrue(properties.subnets().size() > 0); + + 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 testVirtualMachineWithSSH() { + + 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 TemplateOptions(); + options.authorizePublicKey(rsakey); + + DeploymentTemplateBuilder builder = getMockDeploymentTemplateBuilderWithOptions(options); + 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"); + + // Check that ssh key is in place + OSProfile.LinuxConfiguration osConfig = properties.osProfile().linuxConfiguration(); + assertEquals(osConfig.disablePasswordAuthentication(), "true"); + assertTrue(osConfig.ssh().publicKeys().size() > 0); + assertEquals(osConfig.ssh().publicKeys().get(0).keyData(), rsakey); + + assertTrue(variables.containsKey(parseVariableName(resource.name()))); + } + + private Template getMockTemplate(TemplateOptions options) { + 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() { + TemplateOptions options = new TemplateOptions(); + Template template = getMockTemplate(options); + DeploymentTemplateBuilder templateBuilder = api.deploymentTemplateFactory().create(group, "mydeployment", template); + return templateBuilder; + } + + private DeploymentTemplateBuilder getMockDeploymentTemplateBuilderWithOptions(TemplateOptions options) { + Template template = getMockTemplate(options); + DeploymentTemplateBuilder templateBuilder = api.deploymentTemplateFactory().create(group, "mydeployment", template); + return templateBuilder; + } + + private ResourceDefinition getResourceByType(List resources, String type) { + for (ResourceDefinition r : resources) { + if (r.type().equals(type)) { + return r; + } + } + 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/JobApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/JobApiMockTest.java index ba87ca59fd..3e55df108c 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/JobApiMockTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/JobApiMockTest.java @@ -18,6 +18,7 @@ package org.jclouds.azurecompute.arm.features; import java.io.IOException; import java.net.URI; + import org.jclouds.azurecompute.arm.functions.ParseJobStatus.JobStatus; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; import org.testng.annotations.Test; @@ -49,11 +50,21 @@ public class JobApiMockTest extends BaseAzureComputeApiMockTest { assertSent(server, "GET", requestUrl); } - public void testGetJobStatusFailed() throws InterruptedException { + public void testGetJobStatusNoContent() throws InterruptedException { server.enqueue(jsonResponse("/resourcegroup.json").setStatus("HTTP/1.1 204 No Content")); JobStatus status = api.getJobApi().jobStatus(URI.create(requestUrl)); + assertEquals(status, JobStatus.NO_CONTENT); + + assertSent(server, "GET", requestUrl); + } + + public void testGetJobStatusFailed() throws InterruptedException { + server.enqueue(jsonResponse("/resourcegroup.json").setStatus("HTTP/1.1 208 Error")); + + JobStatus status = api.getJobApi().jobStatus(URI.create(requestUrl)); + assertEquals(status, JobStatus.FAILED); assertSent(server, "GET", requestUrl); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiLiveTest.java index c1e77a203e..34917acd38 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiLiveTest.java @@ -17,6 +17,7 @@ package org.jclouds.azurecompute.arm.features; import com.google.common.collect.ImmutableMap; +import com.google.common.base.Predicate; import org.jclouds.azurecompute.arm.domain.IdReference; import org.jclouds.azurecompute.arm.domain.IpConfiguration; import org.jclouds.azurecompute.arm.domain.IpConfigurationProperties; @@ -24,18 +25,22 @@ import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCardProperties; import org.jclouds.azurecompute.arm.domain.Subnet; import org.jclouds.azurecompute.arm.domain.VirtualNetwork; +import org.jclouds.azurecompute.arm.functions.ParseJobStatus; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; +import org.jclouds.util.Predicates2; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import java.net.URI; import java.util.Arrays; import java.util.List; import java.util.Map; + +import static org.testng.Assert.assertNull; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; @Test(groups = "live", singleThreaded = true) public class NetworkInterfaceCardApiLiveTest extends BaseAzureComputeApiLiveTest { @@ -66,8 +71,8 @@ public class NetworkInterfaceCardApiLiveTest extends BaseAzureComputeApiLiveTest public void deleteNetworkInterfaceCardResourceDoesNotExist() { final NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(resourcegroup); - boolean status = nicApi.delete(NETWORKINTERFACECARD_NAME); - assertFalse(status); + URI uri = nicApi.delete(NETWORKINTERFACECARD_NAME); + assertNull(uri); } @Test(groups = "live", dependsOnMethods = "deleteNetworkInterfaceCardResourceDoesNotExist") @@ -85,8 +90,8 @@ public class NetworkInterfaceCardApiLiveTest extends BaseAzureComputeApiLiveTest .properties(IpConfigurationProperties.builder() .privateIPAllocationMethod("Dynamic") .subnet(IdReference.create(subnetID)).build() - ).build() - )).build(); + ).build() + )).build(); final Map tags = ImmutableMap.of("jclouds", "livetest"); NetworkInterfaceCard nic = nicApi.createOrUpdate(NETWORKINTERFACECARD_NAME, LOCATION, networkInterfaceCardProperties, tags); @@ -131,9 +136,19 @@ public class NetworkInterfaceCardApiLiveTest extends BaseAzureComputeApiLiveTest public void deleteNetworkInterfaceCard() { final NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(resourcegroup); + URI uri = nicApi.delete(NETWORKINTERFACECARD_NAME); + if (uri != null) { + assertTrue(uri.toString().contains("api-version")); + assertTrue(uri.toString().contains("operationresults")); - boolean status = nicApi.delete(NETWORKINTERFACECARD_NAME); - assertTrue(status); + boolean jobDone = Predicates2.retry(new Predicate() { + @Override + public boolean apply(URI uri) { + return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri); + } + }, 60 * 2 * 1000 /* 2 minute timeout */).apply(uri); + assertTrue(jobDone, "delete operation did not complete in the configured timeout"); + } } } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiMockTest.java index 179a4ab38c..12ad0733f9 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiMockTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiMockTest.java @@ -34,7 +34,6 @@ import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; @Test(groups = "unit", testName = "NetworkInterfaceCardApiMockTest", singleThreaded = true) public class NetworkInterfaceCardApiMockTest extends BaseAzureComputeApiMockTest { @@ -123,12 +122,11 @@ public class NetworkInterfaceCardApiMockTest extends BaseAzureComputeApiMockTest public void deleteNetworkInterfaceCard() throws InterruptedException { - server.enqueue(response202()); + server.enqueue(response202WithHeader()); final NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(resourcegroup); - boolean status = nicApi.delete(nicName); - assertTrue(status); + nicApi.delete(nicName); String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkInterfaces/%s?%s", subscriptionid, resourcegroup, nicName, apiVersion); assertSent(server, "DELETE", path); @@ -137,12 +135,11 @@ public class NetworkInterfaceCardApiMockTest extends BaseAzureComputeApiMockTest public void deleteNetworkInterfaceCardResourceDoesNotExist() throws InterruptedException { - server.enqueue(response204()); + server.enqueue(response404()); final NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(resourcegroup); - boolean status = nicApi.delete(nicName); - assertFalse(status); + nicApi.delete(nicName); String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkInterfaces/%s?%s", subscriptionid, resourcegroup, nicName, apiVersion); assertSent(server, "DELETE", path); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/OSImageApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/OSImageApiLiveTest.java new file mode 100644 index 0000000000..6ceb0d4f7d --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/OSImageApiLiveTest.java @@ -0,0 +1,69 @@ +/* + * 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.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.internal.AbstractAzureComputeApiLiveTest; +import org.testng.annotations.Test; +import static org.testng.Assert.assertTrue; + +import java.util.List; + +@Test(groups = "live", testName = "OSImageApiLiveTest") +public class OSImageApiLiveTest extends AbstractAzureComputeApiLiveTest { + + @Test + public void testPublisher() { + List publishers = api().listPublishers(); + assertTrue(publishers.size() > 0); + } + + @Test + public void testList() { + List offerList = api().listOffers("MicrosoftWindowsServer"); + assertTrue(offerList.size() > 0); + + List skuList = api().listSKUs("MicrosoftWindowsServer", offerList.get(0).name()); + assertTrue(skuList.size() > 0); + + List versionList = api().listVersions("MicrosoftWindowsServer", offerList.get(0).name(), skuList.get(0).name()); + + assertTrue(versionList.size() > 0); + } + + @Test + public void testListCanonicalUbuntu() { + Iterable offerList = api().listOffers("canonical"); + int total = 0; + + for (Offer offer : offerList) { + Iterable skuList = api().listSKUs("canonical", offer.name()); + for (SKU sku : skuList) { + List versionList = api().listVersions("canonical", offer.name(), sku.name()); + total += versionList.size(); + } + } + assertTrue(total > 0); + } + + private OSImageApi api() { + return api.getOSImageApi("eastus"); + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/OSImageApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/OSImageApiMockTest.java new file mode 100644 index 0000000000..d7dbc92d89 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/OSImageApiMockTest.java @@ -0,0 +1,123 @@ +/* + * 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 static com.google.common.collect.Iterables.isEmpty; +import static com.google.common.collect.Iterables.size; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.util.List; + +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.internal.BaseAzureComputeApiMockTest; +import org.testng.annotations.Test; + +@Test(groups = "unit", testName = "OSImageApiMockTest", singleThreaded = true) +public class OSImageApiMockTest extends BaseAzureComputeApiMockTest { + + private final String subscriptionid = "SUBSCRIPTIONID"; + private final String apiversion = "?api-version=2015-06-15"; + private final String location = "eastus"; + private final String publisher = "MicrosoftWindowsServer"; + private final String offer = "WindowsServer"; + private final String sku = "2008-R2-SP1"; + + final String requestUrl = "/subscriptions/" + subscriptionid + "/providers/Microsoft.Compute/locations/" + location + "/publishers"; + + public void testPublishers() throws InterruptedException { + server.enqueue(jsonResponse("/publishers.json")); + + List publishers = api.getOSImageApi(location).listPublishers(); + + assertEquals(size(publishers), 2); + + assertSent(server, "GET", requestUrl + apiversion); + } + public void testPublishersEmtpy() throws InterruptedException { + server.enqueue(response404()); + + List publishers = api.getOSImageApi(location).listPublishers(); + + assertTrue(isEmpty(publishers)); + + assertSent(server, "GET", requestUrl + apiversion); + } + + public void testOffers() throws InterruptedException { + server.enqueue(jsonResponse("/offers.json")); + + List offers = api.getOSImageApi(location).listOffers(publisher); + + assertEquals(size(offers), 1); + + assertSent(server, "GET", requestUrl + "/" + publisher + "/artifacttypes/vmimage/offers" + apiversion); + } + public void testOffersEmtpy() throws InterruptedException { + server.enqueue(response404()); + + List offers = api.getOSImageApi(location).listOffers(publisher); + + assertTrue(isEmpty(offers)); + + assertSent(server, "GET", requestUrl + "/" + publisher + "/artifacttypes/vmimage/offers" + apiversion); + } + + public void testSkus() throws InterruptedException { + server.enqueue(jsonResponse("/skus.json")); + + List skus = api.getOSImageApi(location).listSKUs(publisher, offer); + + assertEquals(size(skus), 2); + + assertSent(server, "GET", requestUrl + "/" + publisher + "/artifacttypes/vmimage/offers/" + offer + "/skus" + apiversion); + } + + public void testSkusEmtpy() throws InterruptedException { + server.enqueue(response404()); + + List skus = api.getOSImageApi(location).listSKUs(publisher, offer); + + assertTrue(isEmpty(skus)); + + assertSent(server, "GET", requestUrl + "/" + publisher + "/artifacttypes/vmimage/offers/" + offer + "/skus" + apiversion); + } + + public void testVersions() throws InterruptedException { + server.enqueue(jsonResponse("/versions.json")); + + List versions = api.getOSImageApi(location).listVersions(publisher, offer, sku); + + assertEquals(size(versions), 2); + + assertSent(server, "GET", requestUrl + "/" + publisher + "/artifacttypes/vmimage/offers/" + offer + "/skus/" + sku + "/versions" + apiversion); + } + public void testVersionsEmtpy() throws InterruptedException { + server.enqueue(response404()); + + List versions = api.getOSImageApi(location).listVersions(publisher, offer, sku); + + assertTrue(isEmpty(versions)); + + assertSent(server, "GET", requestUrl + "/" + publisher + "/artifacttypes/vmimage/offers/" + offer + "/skus/" + sku + "/versions" + apiversion); + } + + +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiLiveTest.java index 1ad8bf3986..f9ad6ccb6b 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiLiveTest.java @@ -32,6 +32,7 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertEquals; import org.jclouds.util.Predicates2; @@ -80,7 +81,7 @@ public class ResourceGroupApiLiveTest extends BaseAzureComputeApiLiveTest { final ResourceGroup resourceGroup = api().create("jcloudstest", LOCATION, null); assertEquals(resourceGroup.name(), "jcloudstest"); assertEquals(resourceGroup.location(), LOCATION); - assertEquals(resourceGroup.tags().size(), 0); + assertNull(resourceGroup.tags()); assertTrue(resourceGroup.id().contains("jcloudstest")); assertEquals(resourceGroup.properties().provisioningState(), "Succeeded"); } @@ -107,7 +108,7 @@ public class ResourceGroupApiLiveTest extends BaseAzureComputeApiLiveTest { @AfterClass(alwaysRun = true) public void testDelete() throws Exception { - URI uri = api().delete(resourcegroup); + URI uri = api().delete("jcloudstest"); if (uri != null){ assertTrue(uri.toString().contains("api-version")); @@ -117,7 +118,7 @@ public class ResourceGroupApiLiveTest extends BaseAzureComputeApiLiveTest { @Override public boolean apply(URI uri) { return JobStatus.DONE == api.getJobApi().jobStatus(uri); } - }, 60 * 1 * 1000 /* 1 minute timeout */).apply(uri); + }, 60 * 2 * 1000 /* 1 minute timeout */).apply(uri); assertTrue(jobDone, "delete operation did not complete in the configured timeout"); } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiLiveTest.java index 9a13d77a18..6eb13ddfdf 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiLiveTest.java @@ -117,13 +117,13 @@ public class StorageAccountApiLiveTest extends BaseAzureComputeApiLiveTest { assertTrue(params.tags().containsKey("another_property_name")); assertNull(params.storageServiceProperties().accountType()); } - @Test(dependsOnMethods = "testCreate") + @Test(dependsOnMethods = {"testCreate", "testGet"}) public void testUpdateAccountType() { StorageServiceUpdateParams.StorageServiceUpdateProperties props = StorageServiceUpdateParams.StorageServiceUpdateProperties.create(StorageService.AccountType.Standard_GRS); final StorageServiceUpdateParams params = api().update(NAME, null, props); - assertTrue(params.tags().isEmpty()); + assertNull(params.tags()); assertEquals(params.storageServiceProperties().accountType(), StorageService.AccountType.Standard_GRS); } 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 new file mode 100644 index 0000000000..be2eb3e3d1 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/TemplateToDeploymentTemplateLiveTest.java @@ -0,0 +1,186 @@ +/* + * 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 com.google.common.net.UrlEscapers; +import org.jclouds.compute.options.TemplateOptions; +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.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.domain.Location; +import org.jclouds.domain.LocationBuilder; +import org.jclouds.domain.LocationScope; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +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 resourceGroup; + private String deploymentName; + + @BeforeClass + @Override + public void setup() { + super.setup(); + resourceGroup = getResourceGroupName(); + } + + @Test(groups = "live") + 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(groups = "live") + 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"); + + TemplateOptions options = new TemplateOptions(); + 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(groups = "live") + 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"); + + TemplateOptions options = new TemplateOptions(); + 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); + + //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("northeurope").description("North 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 getDeploymentTemplateBuilderWithEmptyOptions() { + TemplateOptions options = new TemplateOptions(); + Template template = getTemplate(options); + DeploymentTemplateBuilder templateBuilder = api.deploymentTemplateFactory().create(resourceGroup, deploymentName, template); + return templateBuilder; + } + + private DeploymentTemplateBuilder getDeploymentTemplateBuilderWithOptions(TemplateOptions options) { + Template template = getTemplate(options); + DeploymentTemplateBuilder templateBuilder = api.deploymentTemplateFactory().create(resourceGroup, deploymentName, template); + return templateBuilder; + } + + private DeploymentApi api() { + return api.getDeploymentApi(resourceGroup); + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VMSizeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VMSizeApiLiveTest.java new file mode 100644 index 0000000000..fdd6ce9f34 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VMSizeApiLiveTest.java @@ -0,0 +1,40 @@ +/* + * 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.azurecompute.arm.domain.VMSize; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +@Test(groups = "live", testName = "VMSizeApiLiveTest") +public class VMSizeApiLiveTest extends BaseAzureComputeApiLiveTest { + + @Test + public void testList() { + for (VMSize vmSize : api().list()) { + assertNotNull(vmSize.name()); + } + assertTrue(api().list().size() > 0); + } + + private VMSizeApi api() { + return api.getVMSizeApi(getLocation()); + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VMSizeApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VMSizeApiMockTest.java new file mode 100644 index 0000000000..6717e8bbfd --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VMSizeApiMockTest.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 com.squareup.okhttp.mockwebserver.MockResponse; +import org.jclouds.azurecompute.arm.domain.VMSize; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import java.util.List; + +@Test(groups = "unit", testName = "VMSizeApiMockTest", singleThreaded = true) +public class VMSizeApiMockTest extends BaseAzureComputeApiMockTest { + + public void testList() throws Exception { + server.enqueue(jsonResponse("/vmsizes.json")); + final VMSizeApi vmSizeAPI = api.getVMSizeApi("westeurope"); + List vmSizes = vmSizeAPI.list(); + + assertNotNull(vmSizes); + assertEquals(vmSizes.size(), 3); + assertEquals( + vmSizes.get(0), + VMSize.create("Standard_A0", 1, 1047552, 20480, 768, 1)); + + + assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/providers/Microsoft.Compute/locations/westeurope/vmSizes?api-version=2015-06-15"); + } + + public void testEmptyList() throws Exception { + server.enqueue(new MockResponse().setResponseCode(404)); + + final VMSizeApi vmSizeAPI = api.getVMSizeApi("location"); + + assertTrue(vmSizeAPI.list().isEmpty()); + + assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/providers/Microsoft.Compute/locations/location/vmSizes?api-version=2015-06-15"); + } +} 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 87b84d86a9..f117f1c7bb 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 @@ -69,7 +69,7 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { } @Test - public void testCreate(){ + public void testCreate() { StorageAccountApi storageApi = api.getStorageAccountApi(getResourceGroupName()); StorageService storageAccount = storageApi.get(getStorageServiceName()); @@ -80,7 +80,8 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { //Poll until resource is ready to be used boolean jobDone = Predicates2.retry(new Predicate() { - @Override public boolean apply(String name) { + @Override + public boolean apply(String name) { return !api().get(name).properties().provisioningState().equals("Creating"); } }, 60 * 20 * 1000).apply(getName()); @@ -109,7 +110,8 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { api().stop(getName()); //Poll until resource is ready to be used boolean jobDone = Predicates2.retry(new Predicate() { - @Override public boolean apply(String name) { + @Override + public boolean apply(String name) { String status = ""; List statuses = api().getInstanceDetails(name).statuses(); for (int c = 0; c < statuses.size(); c++) { @@ -131,7 +133,8 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { //Poll until resource is ready to be used boolean jobDone = Predicates2.retry(new Predicate() { - @Override public boolean apply(String name) { + @Override + public boolean apply(String name) { String status = ""; List statuses = api().getInstanceDetails(name).statuses(); for (int c = 0; c < statuses.size(); c++) { @@ -153,7 +156,8 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { //Poll until resource is ready to be used boolean jobDone = Predicates2.retry(new Predicate() { - @Override public boolean apply(String name) { + @Override + public boolean apply(String name) { String status = ""; List statuses = api().getInstanceDetails(name).statuses(); for (int c = 0; c < statuses.size(); c++) { @@ -171,7 +175,8 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { //Poll until resource is ready to be used jobDone = Predicates2.retry(new Predicate() { - @Override public boolean apply(String name) { + @Override + public boolean apply(String name) { String status = ""; List statuses = api().getInstanceDetails(name).statuses(); for (int c = 0; c < statuses.size(); c++) { @@ -193,7 +198,7 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { assertTrue(list.contains(vm)); } - @Test(dependsOnMethods = {"testRestart", "testList", "testGet"}, alwaysRun = true) + @Test(dependsOnMethods = {"testRestart", "testList", "testGet"}, alwaysRun = true) public void testDelete() throws Exception { URI uri = api().delete(getName()); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/functions/URIParserTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/functions/URIParserTest.java index f7b234d3aa..cd0eb0257c 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/functions/URIParserTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/functions/URIParserTest.java @@ -31,14 +31,14 @@ public class URIParserTest { public void testApply() { URIParser parser = new URIParser(); - Multimap headers = LinkedHashMultimap. create(); + Multimap headers = LinkedHashMultimap.create(); URI uri = parser.apply(HttpResponse.builder().statusCode(200).build()); assertNull(uri); try { uri = parser.apply(HttpResponse.builder().statusCode(202).build()); - } catch (IllegalStateException ex){ + } catch (IllegalStateException ex) { assertNotNull(ex); } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java index 0768daba7a..900d3e0499 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java @@ -66,6 +66,24 @@ public class BaseAzureComputeApiLiveTest extends AbstractAzureComputeApiLiveTest private String storageServiceName = null; + protected String getCredential() { + String credential = null; + if (System.getProperty("test.azurecompute-arm.credential") != null) { + credential = System.getProperty("test.azurecompute-arm.credential"); + } + assertNotNull(credential); + return credential; + } + + protected String getIdentity() { + String identity = null; + if (System.getProperty("test.azurecompute-arm.identity") != null) { + identity = System.getProperty("test.azurecompute-arm.identity"); + } + assertNotNull(identity); + return identity; + } + protected String getStorageServiceName() { if (storageServiceName == null) { storageServiceName = String.format("%3.24s", @@ -74,6 +92,10 @@ public class BaseAzureComputeApiLiveTest extends AbstractAzureComputeApiLiveTest return storageServiceName; } + protected String getLocation() { + return LOCATION; + } + protected String getEndpoint() { String endpoint = null; if (System.getProperty("test.azurecompute-arm.endpoint") != null) { @@ -114,7 +136,6 @@ public class BaseAzureComputeApiLiveTest extends AbstractAzureComputeApiLiveTest api.getResourceGroupApi().delete(name); } - @BeforeClass @Override public void setup() { diff --git a/providers/azurecompute-arm/src/test/resources/createdeploymentaccepted.json b/providers/azurecompute-arm/src/test/resources/createdeploymentaccepted.json new file mode 100644 index 0000000000..8ae5a59789 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/createdeploymentaccepted.json @@ -0,0 +1,33 @@ +{ + "id": "/subscriptions/04f7ec88-8e28-41ed-8537-5e17766001f5/resourceGroups/jims216group/providers/Microsoft.Resources/deployments/jcdep1458344383064", + "name": "jcdep1458344383064", + "properties": { + "parameters": { + "newStorageAccountName": { + "type": "String", + "value": "jcres1458344383064" + }, + "storageAccountType": { + "type": "String", + "value": "Standard_LRS" + }, + "location": { + "type": "String", + "value": "West US" + } + }, + "mode": "Incremental", + "provisioningState": "Accepted", + "timestamp": "2016-03-18T23:39:47.3048037Z", + "duration": "PT2.4433028S", + "correlationId": "8dee9711-8632-4948-9fe6-368bb75e6438", + "providers": [{ + "namespace": "Microsoft.Storage", + "resourceTypes": [{ + "resourceType": "storageAccounts", + "locations": ["westus"] + }] + }], + "dependencies": [] + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/createdeploymentsucceeded.json b/providers/azurecompute-arm/src/test/resources/createdeploymentsucceeded.json new file mode 100644 index 0000000000..e9922049a6 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/createdeploymentsucceeded.json @@ -0,0 +1,36 @@ +{ + "id": "/subscriptions/04f7ec88-8e28-41ed-8537-5e17766001f5/resourceGroups/jims216group/providers/Microsoft.Resources/deployments/jcdep1458344383064", + "name": "jcdep1458344383064", + "properties": { + "parameters": { + "newStorageAccountName": { + "type": "String", + "value": "jcres1458344383064" + }, + "storageAccountType": { + "type": "String", + "value": "Standard_LRS" + }, + "location": { + "type": "String", + "value": "West US" + } + }, + "mode": "Incremental", + "provisioningState": "Succeeded", + "timestamp": "2016-03-18T23:40:25.1856907Z", + "duration": "PT40.3241898S", + "correlationId": "8dee9711-8632-4948-9fe6-368bb75e6438", + "providers": [{ + "namespace": "Microsoft.Storage", + "resourceTypes": [{ + "resourceType": "storageAccounts", + "locations": ["westus"] + }] + }], + "dependencies": [], + "outputResources": [{ + "id": "Microsoft.Storage/storageAccounts/jcres1458344383064" + }] + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/listdeployments.json b/providers/azurecompute-arm/src/test/resources/listdeployments.json new file mode 100644 index 0000000000..122500f476 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/listdeployments.json @@ -0,0 +1,99 @@ +{ + "value": [ + { + "id": "/subscriptions/123abc12-1234-1234-1234-12345345234/resourceGroups/resourceGroup/providers/Microsoft.Resources/deployments/jcdep1458344383064", + "name": "jcdep1458344383064", + "properties": { + "parameters": {}, + "mode": "Incremental", + "provisioningState": "Running", + "timestamp": "2016-04-26T11:48:11.1807222Z", + "duration": "PT0.950828S", + "correlationId": "f7876e0f-22ec-413c-a79e-0a718b4789a2", + "providers": [ + { + "namespace": "Microsoft.Storage", + "resourceTypes": [ + { + "resourceType": "storageAccounts", + "locations": [ + "northeurope" + ] + } + ] + }, + { + "namespace": "Microsoft.Network", + "resourceTypes": [ + { + "resourceType": "virtualNetworks", + "locations": [ + "northeurope" + ] + }, + { + "resourceType": "publicIPAddresses", + "locations": [ + "northeurope" + ] + }, + { + "resourceType": "networkInterfaces", + "locations": [ + "northeurope" + ] + } + ] + }, + { + "namespace": "Microsoft.Compute", + "resourceTypes": [ + { + "resourceType": "virtualMachines", + "locations": [ + "northeurope" + ] + } + ] + } + ], + "dependencies": [ + { + "dependsOn": [ + { + "id": "/subscriptions/123abc12-1234-1234-1234-12345345234/resourceGroups/resourceGroup/providers/Microsoft.Network/publicIPAddresses/jc1461584629971publicip", + "resourceType": "Microsoft.Network/publicIPAddresses", + "resourceName": "jc1461584629971publicip" + }, + { + "id": "/subscriptions/123abc12-1234-1234-1234-12345345234/resourceGroups/resourceGroup/providers/Microsoft.Network/virtualNetworks/jc1461584629971virtualnetwork", + "resourceType": "Microsoft.Network/virtualNetworks", + "resourceName": "jc1461584629971virtualnetwork" + } + ], + "id": "/subscriptions/123abc12-1234-1234-1234-12345345234/resourceGroups/resourceGroup/providers/Microsoft.Network/networkInterfaces/jc1461584629971nic", + "resourceType": "Microsoft.Network/networkInterfaces", + "resourceName": "jc1461584629971nic" + }, + { + "dependsOn": [ + { + "id": "/subscriptions/123abc12-1234-1234-1234-12345345234/resourceGroups/resourceGroup/providers/Microsoft.Storage/storageAccounts/jc1461584629971storage", + "resourceType": "Microsoft.Storage/storageAccounts", + "resourceName": "jc1461584629971storage" + }, + { + "id": "/subscriptions/123abc12-1234-1234-1234-12345345234/resourceGroups/resourceGroup/providers/Microsoft.Network/networkInterfaces/jc1461584629971nic", + "resourceType": "Microsoft.Network/networkInterfaces", + "resourceName": "jc1461584629971nic" + } + ], + "id": "/subscriptions/123abc12-1234-1234-1234-12345345234/resourceGroups/resourceGroup/providers/Microsoft.Compute/virtualMachines/jc1461584629971VirtualMachine", + "resourceType": "Microsoft.Compute/virtualMachines", + "resourceName": "jc1461584629971VirtualMachine" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/offers.json b/providers/azurecompute-arm/src/test/resources/offers.json new file mode 100644 index 0000000000..473c748e0c --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/offers.json @@ -0,0 +1,7 @@ +[ + { + "location": "eastus", + "name": "WindowsServer", + "id": "/Subscriptions/c36d97d3-3fea-4561-aa2d-e61168908c5b/Providers/Microsoft.Compute/Locations/eastus/Publishers/MicrosoftWindowsServer/ArtifactTypes/VMImage/Offers/WindowsServer" + } +] \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/publishers.json b/providers/azurecompute-arm/src/test/resources/publishers.json new file mode 100644 index 0000000000..32d3e84de7 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/publishers.json @@ -0,0 +1,12 @@ +[ + { + "location": "eastus", + "name": "MicrosoftVisualStudio", + "id": "/Subscriptions/c36d97d3-3fea-4561-aa2d-e61168908c5b/Providers/Microsoft.Compute/Locations/eastus/Publishers/MicrosoftVisualStudio" + }, + { + "location": "eastus", + "name": "MicrosoftWindowsServer", + "id": "/Subscriptions/c36d97d3-3fea-4561-aa2d-e61168908c5b/Providers/Microsoft.Compute/Locations/eastus/Publishers/MicrosoftWindowsServer" + } +] \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/skus.json b/providers/azurecompute-arm/src/test/resources/skus.json new file mode 100644 index 0000000000..68c5a81ea4 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/skus.json @@ -0,0 +1,12 @@ +[ + { + "location": "eastus", + "name": "2008-R2-SP1", + "id": "/Subscriptions/c36d97d3-3fea-4561-aa2d-e61168908c5b/Providers/Microsoft.Compute/Locations/eastus/Publishers/MicrosoftWindowsServer/ArtifactTypes/VMImage/Offers/WindowsServer/Skus/2008-R2-SP1" + }, + { + "location": "eastus", + "name": "2012-Datacenter", + "id": "/Subscriptions/c36d97d3-3fea-4561-aa2d-e61168908c5b/Providers/Microsoft.Compute/Locations/eastus/Publishers/MicrosoftWindowsServer/ArtifactTypes/VMImage/Offers/WindowsServer/Skus/2012-Datacenter" + } +] \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/versions.json b/providers/azurecompute-arm/src/test/resources/versions.json new file mode 100644 index 0000000000..48659ed453 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/versions.json @@ -0,0 +1,12 @@ +[ + { + "location": "eastus", + "name": "2.0.20151120", + "id": "/Subscriptions/c36d97d3-3fea-4561-aa2d-e61168908c5b/Providers/Microsoft.Compute/Locations/eastus/Publishers/MicrosoftWindowsServer/ArtifactTypes/VMImage/Offers/WindowsServer/Skus/2008-R2-SP1/Versions/2.0.20151120" + }, + { + "location": "eastus", + "name": "2.0.20151214", + "id": "/Subscriptions/c36d97d3-3fea-4561-aa2d-e61168908c5b/Providers/Microsoft.Compute/Locations/eastus/Publishers/MicrosoftWindowsServer/ArtifactTypes/VMImage/Offers/WindowsServer/Skus/2008-R2-SP1/Versions/2.0.20151214" + } +] \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/vmsizes.json b/providers/azurecompute-arm/src/test/resources/vmsizes.json new file mode 100644 index 0000000000..19ec780056 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/vmsizes.json @@ -0,0 +1,28 @@ +{ + "value": [ + { + "name": "Standard_A0", + "numberOfCores": 1, + "osDiskSizeInMB": 1047552, + "resourceDiskSizeInMB": 20480, + "memoryInMB": 768, + "maxDataDiskCount": 1 + }, + { + "name": "Standard_A1", + "numberOfCores": 1, + "osDiskSizeInMB": 1047552, + "resourceDiskSizeInMB": 71680, + "memoryInMB": 1792, + "maxDataDiskCount": 2 + }, + { + "name": "Standard_A2", + "numberOfCores": 2, + "osDiskSizeInMB": 1047552, + "resourceDiskSizeInMB": 138240, + "memoryInMB": 3584, + "maxDataDiskCount": 4 + } + ] +} \ No newline at end of file From 8d8cd1728d5cef802af8bc544b3e9041c686ee54 Mon Sep 17 00:00:00 2001 From: Jim Spring Date: Mon, 6 Jun 2016 08:12:58 -0700 Subject: [PATCH 10/87] Network Security Group API --- .../azurecompute/arm/AzureComputeApi.java | 20 +- .../arm/domain/NetworkSecurityGroup.java | 54 +++++ .../NetworkSecurityGroupProperties.java | 85 +++++++ .../arm/domain/NetworkSecurityRule.java | 46 ++++ .../domain/NetworkSecurityRuleProperties.java | 143 ++++++++++++ .../arm/features/NetworkSecurityGroupApi.java | 85 +++++++ .../arm/features/NetworkSecurityRuleApi.java | 94 ++++++++ .../NetworkSecurityGroupApiLiveTest.java | 152 ++++++++++++ .../NetworkSecurityGroupApiMockTest.java | 165 +++++++++++++ .../NetworkSecurityRuleApiLiveTest.java | 217 ++++++++++++++++++ .../NetworkSecurityRuleApiMockTest.java | 206 +++++++++++++++++ .../resources/networksecuritygroupcreate.json | 125 ++++++++++ .../resources/networksecuritygroupget.json | 125 ++++++++++ .../resources/networksecuritygrouplist.json | 127 ++++++++++ .../resources/networksecurityrulecreate.json | 17 ++ .../resources/networksecurityruleget.json | 17 ++ .../networksecurityrulegetdefault.json | 17 ++ .../resources/networksecurityrulelist.json | 35 +++ .../networksecurityrulelistdefault.json | 99 ++++++++ 19 files changed, 1828 insertions(+), 1 deletion(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityGroup.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityGroupProperties.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityRule.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityRuleProperties.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApi.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/NetworkSecurityRuleApi.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityRuleApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityRuleApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/resources/networksecuritygroupcreate.json create mode 100644 providers/azurecompute-arm/src/test/resources/networksecuritygroupget.json create mode 100644 providers/azurecompute-arm/src/test/resources/networksecuritygrouplist.json create mode 100644 providers/azurecompute-arm/src/test/resources/networksecurityrulecreate.json create mode 100644 providers/azurecompute-arm/src/test/resources/networksecurityruleget.json create mode 100644 providers/azurecompute-arm/src/test/resources/networksecurityrulegetdefault.json create mode 100644 providers/azurecompute-arm/src/test/resources/networksecurityrulelist.json create mode 100644 providers/azurecompute-arm/src/test/resources/networksecurityrulelistdefault.json 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 4e10089d45..c39022eb0b 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 @@ -29,6 +29,8 @@ 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; import com.google.inject.Provides; @@ -137,7 +139,23 @@ public interface AzureComputeApi extends Closeable { @Delegate DeploymentApi getDeploymentApi(@PathParam("resourcegroup") String resourceGroup); + /** + * The NetworkSecurityGroup API includes operations for managing network security groups within your subscription. + * + * @see docs + */ + @Delegate + NetworkSecurityGroupApi getNetworkSecurityGroupApi(@PathParam("resourcegroup") String resourcegroup); + + /** + * The NetworkSecurityRule API includes operations for managing network security rules within a network security group. + * + * @see docs + */ + @Delegate + NetworkSecurityRuleApi getNetworkSecurityRuleApi(@PathParam("resourcegroup") String resourcegroup, + @PathParam("networksecuritygroup") String networksecuritygroup); + @Provides DeploymentTemplateBuilder.Factory deploymentTemplateFactory(); - } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityGroup.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityGroup.java new file mode 100644 index 0000000000..ebe842e038 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityGroup.java @@ -0,0 +1,54 @@ +/* + * 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.ImmutableMap; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import java.util.Map; + +@AutoValue +public abstract class NetworkSecurityGroup { + @Nullable + public abstract String name(); + + @Nullable + public abstract String location(); + + @Nullable + public abstract Map tags(); + + @Nullable + public abstract NetworkSecurityGroupProperties properties(); + + @Nullable + public abstract String etag(); + + @SerializedNames({"name", "location", "tags", "properties", "etag"}) + public static NetworkSecurityGroup create(final String name, + final String location, + final Map tags, + final NetworkSecurityGroupProperties properties, + final String etag) { + return new AutoValue_NetworkSecurityGroup(name, location, + (tags == null) ? null : ImmutableMap.copyOf(tags), + properties, etag); + } +} + diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityGroupProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityGroupProperties.java new file mode 100644 index 0000000000..f81ab0f835 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityGroupProperties.java @@ -0,0 +1,85 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; +import com.google.common.collect.ImmutableList; + +import java.util.List; + +@AutoValue +public abstract class NetworkSecurityGroupProperties { + + @Nullable + public abstract List securityRules(); + + @Nullable + public abstract List defaultSecurityRules(); + + @Nullable + public abstract List networkInterfaces(); + + @Nullable + public abstract List subnets(); + + @Nullable + public abstract String resourceGuid(); + + @Nullable + public abstract String provisioningState(); + + @SerializedNames({"securityRules", "defaultSecurityRules", "networkInterfaces", "subnets", "resourceGuid", "provisioningState"}) + public static NetworkSecurityGroupProperties create(final List securityRules, + final List defaultSecurityRules, + final List networkInterfaces, + final List subnets, + final String resourceGuid, + final String provisioningState) { + return builder() + .securityRules((securityRules == null) ? null : ImmutableList.copyOf(securityRules)) + .defaultSecurityRules((defaultSecurityRules == null) ? null : ImmutableList.copyOf(defaultSecurityRules)) + .networkInterfaces((networkInterfaces == null) ? null : ImmutableList.copyOf(networkInterfaces)) + .subnets((subnets == null) ? null : ImmutableList.copyOf(subnets)) + .resourceGuid(resourceGuid) + .provisioningState(provisioningState) + .build(); + } + + public static Builder builder() { + return new AutoValue_NetworkSecurityGroupProperties.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder securityRules(List securityRules); + + public abstract Builder defaultSecurityRules(List securityRules); + + public abstract Builder networkInterfaces(List networkInterfaces); + + public abstract Builder subnets(List subnets); + + public abstract Builder resourceGuid(String resourceGuid); + + public abstract Builder provisioningState(String provisioningState); + + public abstract NetworkSecurityGroupProperties build(); + } +} + diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityRule.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityRule.java new file mode 100644 index 0000000000..857a56841c --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityRule.java @@ -0,0 +1,46 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class NetworkSecurityRule { + + @Nullable + public abstract String name(); + + @Nullable + public abstract String id(); + + @Nullable + public abstract String etag(); + + @Nullable + public abstract NetworkSecurityRuleProperties properties(); + + @SerializedNames({"name", "id", "etag", "properties"}) + public static NetworkSecurityRule create(final String name, + final String id, + final String etag, + final NetworkSecurityRuleProperties properties) { + return new AutoValue_NetworkSecurityRule(name, id, etag, properties); + } +} + diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityRuleProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityRuleProperties.java new file mode 100644 index 0000000000..071050382f --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityRuleProperties.java @@ -0,0 +1,143 @@ +/* + * 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 org.jclouds.azurecompute.arm.util.GetEnumValue; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class NetworkSecurityRuleProperties { + public enum Protocol { + // * is an allowed value, will handle in + Tcp("Tcp"), + Udp("Udp"), + All("*"), + UNRECOGNIZED("Unrecognized"); + + private final String label; + + private Protocol(String label) { this.label = label; } + + public static Protocol fromValue(final String text) { + if ("*".equals(text)) { + return All; + } else { + return (Protocol) GetEnumValue.fromValueOrDefault(text, Protocol.UNRECOGNIZED); + } + } + + @Override + public String toString() { + return label; + } + } + + public enum Access { + Allow, + Deny, + UNRECOGNIZED; + + public static Access fromValue(final String text) { + return (Access) GetEnumValue.fromValueOrDefault(text, Access.UNRECOGNIZED); + } + } + + public enum Direction { + Inbound, + Outbound, + UNRECOGNIZED; + + public static Direction fromValue(final String text) { + return (Direction) GetEnumValue.fromValueOrDefault(text, Direction.UNRECOGNIZED); + } + } + + @Nullable + public abstract String description(); + + public abstract Protocol protocol(); + + @Nullable + public abstract String sourcePortRange(); + + @Nullable + public abstract String destinationPortRange(); + + public abstract String sourceAddressPrefix(); + + public abstract String destinationAddressPrefix(); + + public abstract Access access(); + + @Nullable + public abstract Integer priority(); + + public abstract Direction direction(); + + @SerializedNames({"description", "protocol", "sourcePortRange", "destinationPortRange", "sourceAddressPrefix", "destinationAddressPrefix", "access", "priority", "direction"}) + public static NetworkSecurityRuleProperties create(final String description, + final Protocol protocol, + final String sourcePortRange, + final String destinationPortRange, + final String sourceAddressPrefix, + final String destinationAddressPrefix, + final Access access, + final Integer priority, + final Direction direction) { + return builder() + .description(description) + .protocol(protocol) + .sourcePortRange(sourcePortRange) + .destinationPortRange(destinationPortRange) + .sourceAddressPrefix(sourceAddressPrefix) + .destinationAddressPrefix(destinationAddressPrefix) + .access(access) + .priority(priority) + .direction(direction) + .build(); + } + + public static Builder builder() { + return new AutoValue_NetworkSecurityRuleProperties.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder description(String description); + + public abstract Builder protocol(Protocol protocol); + + public abstract Builder sourcePortRange(String sourcePortRange); + + public abstract Builder destinationPortRange(String destinationPortRange); + + public abstract Builder sourceAddressPrefix(String sourceAddressPrefix); + + public abstract Builder destinationAddressPrefix(String sourceAddressPrefix); + + public abstract Builder access(Access access); + + public abstract Builder priority(Integer priority); + + public abstract Builder direction(Direction direction); + + public abstract NetworkSecurityRuleProperties build(); + } +} + 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 new file mode 100644 index 0000000000..e6b310d973 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApi.java @@ -0,0 +1,85 @@ +/* + * 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.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") + +@QueryParams(keys = "api-version", values = "2016-03-30") +@RequestFilters(OAuthFilter.class) +@Consumes(MediaType.APPLICATION_JSON) +public interface NetworkSecurityGroupApi { + + @Named("networksecuritygroup:list") + @GET + @SelectJson("value") + @Fallback(EmptyListOnNotFoundOr404.class) + List list(); + + @Named("networksecuritygroup:delete") + @Path("/{networksecuritygroupname}") + @DELETE + @ResponseParser(URIParser.class) + @Fallback(NullOnNotFoundOr404.class) + URI delete(@PathParam("networksecuritygroupname") String nsgName); + + @Named("networksecuritygroup:createOrUpdate") + @Path("/{networksecuritygroupname}") + @PUT + @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); + + @Named("networksecuritygroup:get") + @Path("/{networksecuritygroupname}") + @GET + @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 new file mode 100644 index 0000000000..2edd3df560 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/NetworkSecurityRuleApi.java @@ -0,0 +1,94 @@ +/* + * 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.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.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.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) +@Consumes(MediaType.APPLICATION_JSON) +public interface NetworkSecurityRuleApi { + @Named("networksecurityrule:createOrUpdate") + @Path("/securityRules/{networksecurityrulename}") + @PUT + @MapBinder(BindToJsonPayload.class) + @Produces(MediaType.APPLICATION_JSON) + NetworkSecurityRule createOrUpdate(@PathParam("networksecurityrulename") String ruleName, + @PayloadParam("properties") NetworkSecurityRuleProperties properties); + + @Named("networksecurityrule:getDefaultRule") + @Path("/defaultSecurityRules/{networksecurityrulename}") + @GET + @Fallback(NullOnNotFoundOr404.class) + NetworkSecurityRule getDefaultRule(@PathParam("networksecurityrulename") String ruleName); + + @Named("networksecurityrule:get") + @Path("/securityRules/{networksecurityrulename}") + @GET + @Fallback(NullOnNotFoundOr404.class) + NetworkSecurityRule get(@PathParam("networksecurityrulename") String ruleName); + + @Named("networksecurityrule:delete") + @Path("/securityRules/{networksecurityrulename}") + @DELETE + @ResponseParser(URIParser.class) + @Fallback(NullOnNotFoundOr404.class) + URI delete(@PathParam("networksecurityrulename") String ruleName); + + @Named("networksecuritygroup:list") + @Path("/securityRules") + @GET + @SelectJson("value") + @Fallback(EmptyListOnNotFoundOr404.class) + List list(); + + @Named("networksecuritygroup:listDefaultRules") + @Path("/defaultSecurityRules") + @GET + @SelectJson("value") + @Fallback(EmptyListOnNotFoundOr404.class) + List listDefaultRules(); +} + diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApiLiveTest.java new file mode 100644 index 0000000000..095c0e26a3 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApiLiveTest.java @@ -0,0 +1,152 @@ +/* + * 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 com.google.common.base.Predicate; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; +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.NetworkSecurityRuleProperties.Access; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Direction; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Protocol; +import org.jclouds.azurecompute.arm.functions.ParseJobStatus; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; + +import org.jclouds.util.Predicates2; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + + +import java.util.ArrayList; +import java.util.List; +import java.net.URI; + +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.AssertJUnit.assertNull; + +@Test(groups = "live", singleThreaded = true) +public class NetworkSecurityGroupApiLiveTest extends BaseAzureComputeApiLiveTest { + + private String resourcegroup; + private static String DEFAULT_NSG_NAME = "testNetworkSecurityGroup"; + + private NetworkSecurityGroup createGroup() { + NetworkSecurityRule rule = NetworkSecurityRule.create("denyallout", null, null, + NetworkSecurityRuleProperties.builder() + .description("deny all out") + .protocol(Protocol.Tcp) + .sourcePortRange("*") + .destinationPortRange("*") + .sourceAddressPrefix("*") + .destinationAddressPrefix("*") + .access(Access.Deny) + .priority(4095) + .direction(Direction.Outbound) + .build()); + ArrayList ruleList = new ArrayList(); + ruleList.add(rule); + NetworkSecurityGroup nsg = NetworkSecurityGroup.create("samplensg", "westus", null, + NetworkSecurityGroupProperties.builder() + .securityRules(ruleList) + .build(), + null); + return nsg; + } + + @BeforeClass + @Override + public void setup() { + super.setup(); + resourcegroup = getResourceGroupName(); + } + + @Test(groups = "live") + public void deleteNetworkSecurityGroupDoesNotExist() { + final NetworkSecurityGroupApi nsgApi = api.getNetworkSecurityGroupApi(resourcegroup); + URI uri = nsgApi.delete(DEFAULT_NSG_NAME); + assertNull(uri); + } + + @Test(groups = "live", dependsOnMethods = "deleteNetworkSecurityGroupDoesNotExist") + public void createNetworkSecurityGroup() { + final NetworkSecurityGroup nsg = createGroup(); + assertNotNull(nsg); + + final NetworkSecurityGroupApi nsgApi = api.getNetworkSecurityGroupApi(resourcegroup); + NetworkSecurityGroup result = nsgApi.createOrUpdate(DEFAULT_NSG_NAME, + nsg.location(), + nsg.tags(), + nsg.properties()); + assertNotNull(result); + } + + @Test(groups = "live", dependsOnMethods = "createNetworkSecurityGroup") + public void listNetworkSecurityGroups() { + final NetworkSecurityGroupApi nsgApi = api.getNetworkSecurityGroupApi(resourcegroup); + List result = nsgApi.list(); + + // verify we have something + assertNotNull(result); + assertEquals(result.size(), 1); + + // check that the nework security group matches the one we originally passed in + NetworkSecurityGroup original = createGroup(); + NetworkSecurityGroup nsg = result.get(0); + assertEquals(original.name(), nsg.name()); + assertEquals(original.location(), nsg.location()); + assertEquals(original.tags(), nsg.tags()); + + // check the network security rule in the group + assertEquals(nsg.properties().securityRules().size(), 1); + NetworkSecurityRule originalRule = original.properties().securityRules().get(0); + NetworkSecurityRule nsgRule = nsg.properties().securityRules().get(0); + assertEquals(originalRule.name(), nsgRule.name()); + assertTrue(originalRule.properties().equals(nsgRule.properties())); + } + + @Test(groups = "live", dependsOnMethods = {"listNetworkSecurityGroups", "getNetworkSecurityGroup"}, alwaysRun = true) + public void deleteNetworkSecurityGroup() { + final NetworkSecurityGroupApi nsgApi = api.getNetworkSecurityGroupApi(resourcegroup); + URI uri = nsgApi.delete(DEFAULT_NSG_NAME); + if (uri != null) { + assertTrue(uri.toString().contains("api-version")); + assertTrue(uri.toString().contains("operationresults")); + + boolean jobDone = Predicates2.retry(new Predicate() { + @Override + public boolean apply(URI uri) { + return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri); + } + }, 60 * 2 * 1000 /* 2 minute timeout */).apply(uri); + assertTrue(jobDone, "delete operation did not complete in the configured timeout"); + } + } + + @Test(groups = "live", dependsOnMethods = "createNetworkSecurityGroup") + public void getNetworkSecurityGroup() { + final NetworkSecurityGroupApi nsgApi = api.getNetworkSecurityGroupApi(resourcegroup); + NetworkSecurityGroup nsg = nsgApi.get(DEFAULT_NSG_NAME); + assertNotNull(nsg); + assertNotNull(nsg.etag()); + assertEquals(nsg.name(), DEFAULT_NSG_NAME); + } +} + 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 new file mode 100644 index 0000000000..adefd95d41 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApiMockTest.java @@ -0,0 +1,165 @@ +/* + * 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 com.google.gson.Gson; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; +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.NetworkSecurityRuleProperties.Protocol; +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 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.assertTrue; + +@Test(groups = "unit", testName = "NetworkSecurityGroupApiMockTest", singleThreaded = true) +public class NetworkSecurityGroupApiMockTest extends BaseAzureComputeApiMockTest { + private final String subscriptionid = "SUBSCRIPTIONID"; + private final String resourcegroup = "myresourcegroup"; + private final String apiVersion = "api-version=2016-03-30"; + private static String DEFAULT_NSG_NAME = "testNetworkSecurityGroup"; + + private NetworkSecurityGroup createGroup() { + NetworkSecurityRule rule = NetworkSecurityRule.create("denyallout", null, null, + NetworkSecurityRuleProperties.builder() + .description("deny all out") + .protocol(Protocol.Tcp) + .sourcePortRange("*") + .destinationPortRange("*") + .sourceAddressPrefix("*") + .destinationAddressPrefix("*") + .access(NetworkSecurityRuleProperties.Access.Deny) + .priority(4095) + .direction(NetworkSecurityRuleProperties.Direction.Outbound) + .build()); + ArrayList ruleList = new ArrayList(); + ruleList.add(rule); + NetworkSecurityGroup nsg = NetworkSecurityGroup.create("samplensg", "westus", null, + NetworkSecurityGroupProperties.builder() + .securityRules(ruleList) + .build(), + null); + return nsg; + } + + public void createNetworkSecurityGroup() throws InterruptedException { + NetworkSecurityGroup nsg = createGroup(); + + server.enqueue(jsonResponse("/networksecuritygroupcreate.json").setResponseCode(200)); + final NetworkSecurityGroupApi nsgApi = api.getNetworkSecurityGroupApi(resourcegroup); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkSecurityGroups/%s?%s", subscriptionid, resourcegroup, DEFAULT_NSG_NAME, apiVersion); + String json = String.format("{\"location\":\"%s\",\"properties\":%s}", "westus", new Gson().toJson(nsg.properties())); + NetworkSecurityGroup result = nsgApi.createOrUpdate(DEFAULT_NSG_NAME, "westus", null, nsg.properties()); + assertSent(server, "PUT", path, json); + + assertEquals(result.name(), DEFAULT_NSG_NAME); + assertEquals(result.location(), "westus"); + assertEquals(result.properties().securityRules().size(), 1); + assertEquals(result.properties().securityRules().get(0).properties().protocol(), Protocol.Tcp); + } + + public void getNetworkSecurityGroup() throws InterruptedException { + NetworkSecurityGroup nsg = createGroup(); + + server.enqueue(jsonResponse("/networksecuritygroupget.json").setResponseCode(200)); + + final NetworkSecurityGroupApi nsgApi = api.getNetworkSecurityGroupApi(resourcegroup); + NetworkSecurityGroup result = nsgApi.get(DEFAULT_NSG_NAME); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkSecurityGroups/%s?%s", subscriptionid, resourcegroup, DEFAULT_NSG_NAME, apiVersion); + assertSent(server, "GET", path); + + assertEquals(result.name(), DEFAULT_NSG_NAME); + assertEquals(result.location(), "westus"); + assertEquals(result.properties().securityRules().size(), 1); + assertEquals(result.properties().securityRules().get(0).properties().protocol(), Protocol.Tcp); + } + + public void getNetworkSecurityGroupReturns404() throws InterruptedException { + server.enqueue(response404()); + + final NetworkSecurityGroupApi nsgApi = api.getNetworkSecurityGroupApi(resourcegroup); + NetworkSecurityGroup result = nsgApi.get(DEFAULT_NSG_NAME); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkSecurityGroups/%s?%s", subscriptionid, resourcegroup, DEFAULT_NSG_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNull(result); + } + + public void listNetworkSecurityGroups() throws InterruptedException { + server.enqueue(jsonResponse("/networksecuritygrouplist.json").setResponseCode(200)); + + final NetworkSecurityGroupApi nsgApi = api.getNetworkSecurityGroupApi(resourcegroup); + List result = nsgApi.list(); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkSecurityGroups?%s", subscriptionid, resourcegroup, apiVersion); + assertSent(server, "GET", path); + + assertNotNull(result); + assertTrue(result.size() > 0); + } + + public void listNetworkSecurityGroupsReturns404() throws InterruptedException { + server.enqueue(response404()); + + final NetworkSecurityGroupApi nsgApi = api.getNetworkSecurityGroupApi(resourcegroup); + List result = nsgApi.list(); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkSecurityGroups?%s", subscriptionid, resourcegroup, apiVersion); + assertSent(server, "GET", path); + + assertTrue(isEmpty(result)); + } + + public void deleteNetworkSecurityGroup() throws InterruptedException { + server.enqueue(response202WithHeader()); + + final NetworkSecurityGroupApi nsgApi = api.getNetworkSecurityGroupApi(resourcegroup); + URI uri = nsgApi.delete(DEFAULT_NSG_NAME); + + assertEquals(server.getRequestCount(), 1); + assertNotNull(uri); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkSecurityGroups/%s?%s", subscriptionid, resourcegroup, DEFAULT_NSG_NAME, apiVersion); + assertSent(server, "DELETE", path); + + assertTrue(uri.toString().contains("api-version")); + assertTrue(uri.toString().contains("operationresults")); + } + + public void deleteNetworkSecurityGroupDoesNotExist() throws InterruptedException { + server.enqueue(response404()); + + final NetworkSecurityGroupApi nsgApi = api.getNetworkSecurityGroupApi(resourcegroup); + URI uri = nsgApi.delete(DEFAULT_NSG_NAME); + assertNull(uri); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkSecurityGroups/%s?%s", subscriptionid, resourcegroup, DEFAULT_NSG_NAME, apiVersion); + assertSent(server, "DELETE", path); + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityRuleApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityRuleApiLiveTest.java new file mode 100644 index 0000000000..fbcd2b46df --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityRuleApiLiveTest.java @@ -0,0 +1,217 @@ +/* + * 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 com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; +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.NetworkSecurityRuleProperties.Access; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Direction; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Protocol; +import org.jclouds.azurecompute.arm.functions.ParseJobStatus; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; + +import org.jclouds.util.Predicates2; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; + +@Test(groups = "live", singleThreaded = true) +public class NetworkSecurityRuleApiLiveTest extends BaseAzureComputeApiLiveTest { + + private String resourcegroup; + private static String DEFAULT_NSG_NAME = "testNetworkSecurityGroup"; + private static String UNKNOWN_RULE_NAME = "ruledoesntexist"; + + private NetworkSecurityGroup createGroup() { + NetworkSecurityRule rule = NetworkSecurityRule.create("denyallout", null, null, + NetworkSecurityRuleProperties.builder() + .description("deny all out") + .protocol(Protocol.Tcp) + .sourcePortRange("*") + .destinationPortRange("*") + .sourceAddressPrefix("*") + .destinationAddressPrefix("*") + .access(Access.Deny) + .priority(4095) + .direction(Direction.Outbound) + .build()); + ArrayList ruleList = new ArrayList(); + ruleList.add(rule); + NetworkSecurityGroup nsg = NetworkSecurityGroup.create("samplensg", "westus", null, + NetworkSecurityGroupProperties.builder() + .securityRules(ruleList) + .build(), + null); + return nsg; + } + + private NetworkSecurityRule createRule() { + NetworkSecurityRule rule = NetworkSecurityRule.create("allowalludpin", null, null, + NetworkSecurityRuleProperties.builder() + .description("allow all udp in") + .protocol(Protocol.Udp) + .sourcePortRange("*") + .destinationPortRange("*") + .sourceAddressPrefix("*") + .destinationAddressPrefix("*") + .access(Access.Allow) + .priority(4094) + .direction(Direction.Inbound) + .build()); + return rule; + } + + @BeforeClass + @Override + public void setup() { + super.setup(); + resourcegroup = getResourceGroupName(); + + // a network security group is needed + final NetworkSecurityGroup nsg = createGroup(); + final NetworkSecurityGroupApi nsgApi = api.getNetworkSecurityGroupApi(resourcegroup); + NetworkSecurityGroup result = nsgApi.createOrUpdate(DEFAULT_NSG_NAME, + nsg.location(), + nsg.tags(), + nsg.properties()); + } + + @AfterClass(alwaysRun = true) + @Override + public void tearDown() { + // remove the security group we created + final NetworkSecurityGroupApi nsgApi = api.getNetworkSecurityGroupApi(resourcegroup); + URI uri = nsgApi.delete(DEFAULT_NSG_NAME); + if (uri != null) { + boolean jobDone = Predicates2.retry(new Predicate() { + @Override + public boolean apply(URI uri) { + return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri); + } + }, 60 * 2 * 1000 /* 2 minute timeout */).apply(uri); + } + + super.tearDown(); + } + + @Test(groups = "live") + public void deleteNetworkSecurityRuleDoesNotExist() { + final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); + URI uri = ruleApi.delete(UNKNOWN_RULE_NAME); + assertNull(uri); + } + + @Test(groups = "live", dependsOnMethods = "deleteNetworkSecurityRuleDoesNotExist") + public void createNetworkSecurityRule() { + final NetworkSecurityRule rule = createRule(); + assertNotNull(rule); + + final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); + NetworkSecurityRule result = ruleApi.createOrUpdate(rule.name(), rule.properties()); + assertNotNull(result); + assertEquals(result.name(), rule.name()); + } + + @Test(groups = "live", dependsOnMethods = "createNetworkSecurityRule") + public void getNetworkSecurityRule() { + final NetworkSecurityRule rule = createRule(); + assertNotNull(rule); + + final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); + NetworkSecurityRule result = ruleApi.get(rule.name()); + assertNotNull(result); + assertNotNull(result.etag()); + assertEquals(result.name(), rule.name()); + } + + @Test(groups = "live", dependsOnMethods = "createNetworkSecurityRule") + public void getNetworkSecurityDefaultRule() { + String defaultRuleName = "AllowVnetInBound"; + + final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); + NetworkSecurityRule result = ruleApi.getDefaultRule(defaultRuleName); + + assertNotNull(result); + assertNotNull(result.etag()); + assertEquals(result.name(), defaultRuleName); + } + + @Test(groups = "live", dependsOnMethods = "createNetworkSecurityRule") + public void listNetworkSecurityRules() { + final NetworkSecurityRule rule = createRule(); + assertNotNull(rule); + + final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); + List result = ruleApi.list(); + + assertNotNull(result); + assertEquals(result.size(), 2); + + boolean rulePresent = Iterables.any(result, new Predicate() { + public boolean apply(NetworkSecurityRule input) { + return input.name().equals(rule.name()); + } + }); + + assertTrue(rulePresent); + } + + @Test(groups = "live", dependsOnMethods = "createNetworkSecurityRule") + public void listDefaultSecurityRules() { + final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); + List result = ruleApi.listDefaultRules(); + + assertNotNull(result); + assertTrue(result.size() > 0); + } + + @Test(groups = "live", dependsOnMethods = {"listNetworkSecurityRules", "listDefaultSecurityRules", "getNetworkSecurityRule"}, alwaysRun = true) + public void deleteNetworkSecurityRule() { + final NetworkSecurityRule rule = createRule(); + assertNotNull(rule); + + final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); + URI uri = ruleApi.delete(rule.name()); + if (uri != null) { + assertTrue(uri.toString().contains("api-version")); + assertTrue(uri.toString().contains("operationresults")); + + boolean jobDone = Predicates2.retry(new Predicate() { + @Override + public boolean apply(URI uri) { + return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri); + } + }, 60 * 2 * 1000 /* 2 minute timeout */).apply(uri); + assertTrue(jobDone, "delete operation did not complete in the configured timeout"); + } + } + +} + diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityRuleApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityRuleApiMockTest.java new file mode 100644 index 0000000000..1ca4284bb3 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityRuleApiMockTest.java @@ -0,0 +1,206 @@ +/* + * 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 com.google.gson.Gson; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityRule; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Protocol; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; +import org.testng.annotations.Test; + +import java.net.URI; +import java.util.List; + +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.assertTrue; +import static org.testng.Assert.assertNotNull; + + +@Test(groups = "unit", testName = "NetworkSecurityRuleApiMockTest", singleThreaded = true) +public class NetworkSecurityRuleApiMockTest extends BaseAzureComputeApiMockTest { + private final String subscriptionid = "SUBSCRIPTIONID"; + private final String resourcegroup = "myresourcegroup"; + private final String apiVersion = "api-version=2016-03-30"; + private static String DEFAULT_NSG_NAME = "testNetworkSecurityGroup"; + + private NetworkSecurityRule createRule() { + NetworkSecurityRule rule = NetworkSecurityRule.create("allowalludpin", null, null, + NetworkSecurityRuleProperties.builder() + .description("allow all udp in") + .protocol(Protocol.Udp) + .sourcePortRange("*") + .destinationPortRange("*") + .sourceAddressPrefix("*") + .destinationAddressPrefix("*") + .access(NetworkSecurityRuleProperties.Access.Allow) + .priority(4094) + .direction(NetworkSecurityRuleProperties.Direction.Inbound) + .build()); + return rule; + } + + public void createNetworkSecurityRule() throws InterruptedException { + NetworkSecurityRule rule = createRule(); + + server.enqueue(jsonResponse("/networksecurityrulecreate.json").setResponseCode(200)); + final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkSecurityGroups/%s/securityRules/%s?%s", subscriptionid, resourcegroup, DEFAULT_NSG_NAME, rule.name(), apiVersion); + NetworkSecurityRule result = ruleApi.createOrUpdate(rule.name(), rule.properties()); + String json = String.format("{\"properties\":%s}", new Gson().toJson(rule.properties())); + + assertSent(server, "PUT", path, json); + + assertNotNull(result); + assertEquals(result.name(), rule.name()); + } + + public void getNetworkSecurityRule() throws InterruptedException { + NetworkSecurityRule rule = createRule(); + + server.enqueue(jsonResponse("/networksecurityruleget.json").setResponseCode(200)); + final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkSecurityGroups/%s/securityRules/%s?%s", subscriptionid, resourcegroup, DEFAULT_NSG_NAME, rule.name(), apiVersion); + NetworkSecurityRule result = ruleApi.get(rule.name()); + assertSent(server, "GET", path); + + assertEquals(result.name(), rule.name()); + } + + public void getNetworkSecurityRuleReturns404() throws InterruptedException { + server.enqueue(response404()); + + String missingRuleName = "ruleismissing"; + final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkSecurityGroups/%s/securityRules/%s?%s", subscriptionid, resourcegroup, DEFAULT_NSG_NAME, missingRuleName, apiVersion); + NetworkSecurityRule result = ruleApi.get(missingRuleName); + assertSent(server, "GET", path); + + assertNull(result); + } + + public void getNetworkSecurityDefaultRule() throws InterruptedException { + server.enqueue(jsonResponse("/networksecurityrulegetdefault.json").setResponseCode(200)); + final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); + String ruleName = "AllowVnetInBound"; + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkSecurityGroups/%s/defaultSecurityRules/%s?%s", subscriptionid, resourcegroup, DEFAULT_NSG_NAME, ruleName, apiVersion); + NetworkSecurityRule result = ruleApi.getDefaultRule(ruleName); + assertSent(server, "GET", path); + + assertNotNull(result); + assertEquals(result.name(), ruleName); + } + + public void getNetworkSecurityDefaultRuleReturns404() throws InterruptedException { + server.enqueue(response404()); + + String missingRuleName = "ruleismissing"; + final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkSecurityGroups/%s/defaultSecurityRules/%s?%s", subscriptionid, resourcegroup, DEFAULT_NSG_NAME, missingRuleName, apiVersion); + NetworkSecurityRule result = ruleApi.getDefaultRule(missingRuleName); + assertSent(server, "GET", path); + + assertNull(result); + } + + public void listNetworkSecurityRules() throws InterruptedException { + server.enqueue(jsonResponse("/networksecurityrulelist.json").setResponseCode(200)); + + final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkSecurityGroups/%s/securityRules?%s", subscriptionid, resourcegroup, DEFAULT_NSG_NAME, apiVersion); + List result = ruleApi.list(); + assertSent(server, "GET", path); + + assertNotNull(result); + assertTrue(result.size() > 0); + } + + public void listNetworkSecurityRulesReturns404() throws InterruptedException { + server.enqueue(response404()); + + final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkSecurityGroups/%s/securityRules?%s", subscriptionid, resourcegroup, DEFAULT_NSG_NAME, apiVersion); + List result = ruleApi.list(); + assertSent(server, "GET", path); + + assertTrue(isEmpty(result)); + } + + public void listNetworkSecurityDefaultRules() throws InterruptedException { + server.enqueue(jsonResponse("/networksecurityrulelistdefault.json").setResponseCode(200)); + + final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkSecurityGroups/%s/defaultSecurityRules?%s", subscriptionid, resourcegroup, DEFAULT_NSG_NAME, apiVersion); + List result = ruleApi.listDefaultRules(); + assertSent(server, "GET", path); + + assertNotNull(result); + assertTrue(result.size() > 0); + } + + public void listNetworkSecurityDefaultRulesReturns404() throws InterruptedException { + server.enqueue(response404()); + + final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkSecurityGroups/%s/defaultSecurityRules?%s", subscriptionid, resourcegroup, DEFAULT_NSG_NAME, apiVersion); + List result = ruleApi.listDefaultRules(); + assertSent(server, "GET", path); + + assertTrue(isEmpty(result)); + } + + public void deleteNetworkSecurityRule() throws InterruptedException { + server.enqueue(response202WithHeader()); + + NetworkSecurityRule rule = createRule(); + + final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); + URI uri = ruleApi.delete(rule.name()); + + assertEquals(server.getRequestCount(), 1); + assertNotNull(uri); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkSecurityGroups/%s/securityRules/%s?%s", subscriptionid, resourcegroup, DEFAULT_NSG_NAME, rule.name(), apiVersion); + assertSent(server, "DELETE", path); + + assertTrue(uri.toString().contains("api-version")); + assertTrue(uri.toString().contains("operationresults")); + } + + public void deleteNetworkSecurityRuleDoesNotExist() throws InterruptedException { + server.enqueue(response404()); + + final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); + String dummyname = "dummyrulename"; + URI uri = ruleApi.delete(dummyname); + assertNull(uri); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkSecurityGroups/%s/securityRules/%s?%s", subscriptionid, resourcegroup, DEFAULT_NSG_NAME, dummyname, apiVersion); + assertSent(server, "DELETE", path); + } +} diff --git a/providers/azurecompute-arm/src/test/resources/networksecuritygroupcreate.json b/providers/azurecompute-arm/src/test/resources/networksecuritygroupcreate.json new file mode 100644 index 0000000000..b416bcc2bb --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/networksecuritygroupcreate.json @@ -0,0 +1,125 @@ +{ + "name": "testNetworkSecurityGroup", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup", + "etag": "W/\"1883271c-c55b-4f5b-a95a-b7415833e0ae\"", + "type": "Microsoft.Network/networkSecurityGroups", + "location": "westus", + "properties": { + "provisioningState": "Updating", + "resourceGuid": "028cb30d-f97f-4dbe-9fea-705da1f383ca", + "securityRules": [{ + "name": "denyallout", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/securityRules/denyallout", + "etag": "W/\"1883271c-c55b-4f5b-a95a-b7415833e0ae\"", + "properties": { + "provisioningState": "Updating", + "description": "deny all out", + "protocol": "Tcp", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "access": "Deny", + "priority": 4095, + "direction": "Outbound" + } + }], + "defaultSecurityRules": [{ + "name": "AllowVnetInBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/AllowVnetInBound", + "etag": "W/\"1883271c-c55b-4f5b-a95a-b7415833e0ae\"", + "properties": { + "provisioningState": "Updating", + "description": "Allow inbound traffic from all VMs in VNET", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "VirtualNetwork", + "destinationAddressPrefix": "VirtualNetwork", + "access": "Allow", + "priority": 65000, + "direction": "Inbound" + } + }, { + "name": "AllowAzureLoadBalancerInBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/AllowAzureLoadBalancerInBound", + "etag": "W/\"1883271c-c55b-4f5b-a95a-b7415833e0ae\"", + "properties": { + "provisioningState": "Updating", + "description": "Allow inbound traffic from azure load balancer", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "AzureLoadBalancer", + "destinationAddressPrefix": "*", + "access": "Allow", + "priority": 65001, + "direction": "Inbound" + } + }, { + "name": "DenyAllInBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/DenyAllInBound", + "etag": "W/\"1883271c-c55b-4f5b-a95a-b7415833e0ae\"", + "properties": { + "provisioningState": "Updating", + "description": "Deny all inbound traffic", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "access": "Deny", + "priority": 65500, + "direction": "Inbound" + } + }, { + "name": "AllowVnetOutBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/AllowVnetOutBound", + "etag": "W/\"1883271c-c55b-4f5b-a95a-b7415833e0ae\"", + "properties": { + "provisioningState": "Updating", + "description": "Allow outbound traffic from all VMs to all VMs in VNET", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "VirtualNetwork", + "destinationAddressPrefix": "VirtualNetwork", + "access": "Allow", + "priority": 65000, + "direction": "Outbound" + } + }, { + "name": "AllowInternetOutBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/AllowInternetOutBound", + "etag": "W/\"1883271c-c55b-4f5b-a95a-b7415833e0ae\"", + "properties": { + "provisioningState": "Updating", + "description": "Allow outbound traffic from all VMs to Internet", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "Internet", + "access": "Allow", + "priority": 65001, + "direction": "Outbound" + } + }, { + "name": "DenyAllOutBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/DenyAllOutBound", + "etag": "W/\"1883271c-c55b-4f5b-a95a-b7415833e0ae\"", + "properties": { + "provisioningState": "Updating", + "description": "Deny all outbound traffic", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "access": "Deny", + "priority": 65500, + "direction": "Outbound" + } + }] + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/networksecuritygroupget.json b/providers/azurecompute-arm/src/test/resources/networksecuritygroupget.json new file mode 100644 index 0000000000..17a2680553 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/networksecuritygroupget.json @@ -0,0 +1,125 @@ +{ + "name": "testNetworkSecurityGroup", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup", + "etag": "W/\"14e288e4-5d9b-48cf-89c4-b532b59d71de\"", + "type": "Microsoft.Network/networkSecurityGroups", + "location": "westus", + "properties": { + "provisioningState": "Succeeded", + "resourceGuid": "028cb30d-f97f-4dbe-9fea-705da1f383ca", + "securityRules": [{ + "name": "denyallout", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/securityRules/denyallout", + "etag": "W/\"14e288e4-5d9b-48cf-89c4-b532b59d71de\"", + "properties": { + "provisioningState": "Succeeded", + "description": "deny all out", + "protocol": "Tcp", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "access": "Deny", + "priority": 4095, + "direction": "Outbound" + } + }], + "defaultSecurityRules": [{ + "name": "AllowVnetInBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/AllowVnetInBound", + "etag": "W/\"14e288e4-5d9b-48cf-89c4-b532b59d71de\"", + "properties": { + "provisioningState": "Succeeded", + "description": "Allow inbound traffic from all VMs in VNET", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "VirtualNetwork", + "destinationAddressPrefix": "VirtualNetwork", + "access": "Allow", + "priority": 65000, + "direction": "Inbound" + } + }, { + "name": "AllowAzureLoadBalancerInBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/AllowAzureLoadBalancerInBound", + "etag": "W/\"14e288e4-5d9b-48cf-89c4-b532b59d71de\"", + "properties": { + "provisioningState": "Succeeded", + "description": "Allow inbound traffic from azure load balancer", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "AzureLoadBalancer", + "destinationAddressPrefix": "*", + "access": "Allow", + "priority": 65001, + "direction": "Inbound" + } + }, { + "name": "DenyAllInBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/DenyAllInBound", + "etag": "W/\"14e288e4-5d9b-48cf-89c4-b532b59d71de\"", + "properties": { + "provisioningState": "Succeeded", + "description": "Deny all inbound traffic", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "access": "Deny", + "priority": 65500, + "direction": "Inbound" + } + }, { + "name": "AllowVnetOutBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/AllowVnetOutBound", + "etag": "W/\"14e288e4-5d9b-48cf-89c4-b532b59d71de\"", + "properties": { + "provisioningState": "Succeeded", + "description": "Allow outbound traffic from all VMs to all VMs in VNET", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "VirtualNetwork", + "destinationAddressPrefix": "VirtualNetwork", + "access": "Allow", + "priority": 65000, + "direction": "Outbound" + } + }, { + "name": "AllowInternetOutBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/AllowInternetOutBound", + "etag": "W/\"14e288e4-5d9b-48cf-89c4-b532b59d71de\"", + "properties": { + "provisioningState": "Succeeded", + "description": "Allow outbound traffic from all VMs to Internet", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "Internet", + "access": "Allow", + "priority": 65001, + "direction": "Outbound" + } + }, { + "name": "DenyAllOutBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/DenyAllOutBound", + "etag": "W/\"14e288e4-5d9b-48cf-89c4-b532b59d71de\"", + "properties": { + "provisioningState": "Succeeded", + "description": "Deny all outbound traffic", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "access": "Deny", + "priority": 65500, + "direction": "Outbound" + } + }] + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/networksecuritygrouplist.json b/providers/azurecompute-arm/src/test/resources/networksecuritygrouplist.json new file mode 100644 index 0000000000..7beebb093d --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/networksecuritygrouplist.json @@ -0,0 +1,127 @@ +{ + "value": [{ + "name": "testNetworkSecurityGroup", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup", + "etag": "W/\"14e288e4-5d9b-48cf-89c4-b532b59d71de\"", + "type": "Microsoft.Network/networkSecurityGroups", + "location": "westus", + "properties": { + "provisioningState": "Succeeded", + "resourceGuid": "028cb30d-f97f-4dbe-9fea-705da1f383ca", + "securityRules": [{ + "name": "denyallout", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/securityRules/denyallout", + "etag": "W/\"14e288e4-5d9b-48cf-89c4-b532b59d71de\"", + "properties": { + "provisioningState": "Succeeded", + "description": "deny all out", + "protocol": "Tcp", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "access": "Deny", + "priority": 4095, + "direction": "Outbound" + } + }], + "defaultSecurityRules": [{ + "name": "AllowVnetInBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/AllowVnetInBound", + "etag": "W/\"14e288e4-5d9b-48cf-89c4-b532b59d71de\"", + "properties": { + "provisioningState": "Succeeded", + "description": "Allow inbound traffic from all VMs in VNET", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "VirtualNetwork", + "destinationAddressPrefix": "VirtualNetwork", + "access": "Allow", + "priority": 65000, + "direction": "Inbound" + } + }, { + "name": "AllowAzureLoadBalancerInBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/AllowAzureLoadBalancerInBound", + "etag": "W/\"14e288e4-5d9b-48cf-89c4-b532b59d71de\"", + "properties": { + "provisioningState": "Succeeded", + "description": "Allow inbound traffic from azure load balancer", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "AzureLoadBalancer", + "destinationAddressPrefix": "*", + "access": "Allow", + "priority": 65001, + "direction": "Inbound" + } + }, { + "name": "DenyAllInBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/DenyAllInBound", + "etag": "W/\"14e288e4-5d9b-48cf-89c4-b532b59d71de\"", + "properties": { + "provisioningState": "Succeeded", + "description": "Deny all inbound traffic", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "access": "Deny", + "priority": 65500, + "direction": "Inbound" + } + }, { + "name": "AllowVnetOutBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/AllowVnetOutBound", + "etag": "W/\"14e288e4-5d9b-48cf-89c4-b532b59d71de\"", + "properties": { + "provisioningState": "Succeeded", + "description": "Allow outbound traffic from all VMs to all VMs in VNET", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "VirtualNetwork", + "destinationAddressPrefix": "VirtualNetwork", + "access": "Allow", + "priority": 65000, + "direction": "Outbound" + } + }, { + "name": "AllowInternetOutBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/AllowInternetOutBound", + "etag": "W/\"14e288e4-5d9b-48cf-89c4-b532b59d71de\"", + "properties": { + "provisioningState": "Succeeded", + "description": "Allow outbound traffic from all VMs to Internet", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "Internet", + "access": "Allow", + "priority": 65001, + "direction": "Outbound" + } + }, { + "name": "DenyAllOutBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims947groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/DenyAllOutBound", + "etag": "W/\"14e288e4-5d9b-48cf-89c4-b532b59d71de\"", + "properties": { + "provisioningState": "Succeeded", + "description": "Deny all outbound traffic", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "access": "Deny", + "priority": 65500, + "direction": "Outbound" + } + }] + } + }] +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/networksecurityrulecreate.json b/providers/azurecompute-arm/src/test/resources/networksecurityrulecreate.json new file mode 100644 index 0000000000..c09bf088e2 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/networksecurityrulecreate.json @@ -0,0 +1,17 @@ +{ + "name": "allowalludpin", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims859groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/securityRules/allowalludpin", + "etag": "W/\"d9b6cda9-3873-445d-bc70-cd9c13f87ba7\"", + "properties": { + "provisioningState": "Updating", + "description": "allow all udp in", + "protocol": "Udp", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "access": "Allow", + "priority": 4094, + "direction": "Inbound" + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/networksecurityruleget.json b/providers/azurecompute-arm/src/test/resources/networksecurityruleget.json new file mode 100644 index 0000000000..c09bf088e2 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/networksecurityruleget.json @@ -0,0 +1,17 @@ +{ + "name": "allowalludpin", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims859groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/securityRules/allowalludpin", + "etag": "W/\"d9b6cda9-3873-445d-bc70-cd9c13f87ba7\"", + "properties": { + "provisioningState": "Updating", + "description": "allow all udp in", + "protocol": "Udp", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "access": "Allow", + "priority": 4094, + "direction": "Inbound" + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/networksecurityrulegetdefault.json b/providers/azurecompute-arm/src/test/resources/networksecurityrulegetdefault.json new file mode 100644 index 0000000000..33309850d2 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/networksecurityrulegetdefault.json @@ -0,0 +1,17 @@ +{ + "name": "AllowVnetInBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims741groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/AllowVnetInBound", + "etag": "W/\"23efab91-398a-4984-a9a7-281af38f6538\"", + "properties": { + "provisioningState": "Succeeded", + "description": "Allow inbound traffic from all VMs in VNET", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "VirtualNetwork", + "destinationAddressPrefix": "VirtualNetwork", + "access": "Allow", + "priority": 65000, + "direction": "Inbound" + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/networksecurityrulelist.json b/providers/azurecompute-arm/src/test/resources/networksecurityrulelist.json new file mode 100644 index 0000000000..d48fe322b0 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/networksecurityrulelist.json @@ -0,0 +1,35 @@ +{ + "value": [{ + "name": "denyallout", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims859groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/securityRules/denyallout", + "etag": "W/\"409ae6c7-fbe1-4bc4-aadb-c1d8330844d2\"", + "properties": { + "provisioningState": "Succeeded", + "description": "deny all out", + "protocol": "Tcp", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "access": "Deny", + "priority": 4095, + "direction": "Outbound" + } + }, { + "name": "allowalludpin", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims859groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/securityRules/allowalludpin", + "etag": "W/\"409ae6c7-fbe1-4bc4-aadb-c1d8330844d2\"", + "properties": { + "provisioningState": "Succeeded", + "description": "allow all udp in", + "protocol": "Udp", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "access": "Allow", + "priority": 4094, + "direction": "Inbound" + } + }] +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/networksecurityrulelistdefault.json b/providers/azurecompute-arm/src/test/resources/networksecurityrulelistdefault.json new file mode 100644 index 0000000000..245a7db0ed --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/networksecurityrulelistdefault.json @@ -0,0 +1,99 @@ +{ + "value": [{ + "name": "AllowVnetInBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims859groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/AllowVnetInBound", + "etag": "W/\"409ae6c7-fbe1-4bc4-aadb-c1d8330844d2\"", + "properties": { + "provisioningState": "Succeeded", + "description": "Allow inbound traffic from all VMs in VNET", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "VirtualNetwork", + "destinationAddressPrefix": "VirtualNetwork", + "access": "Allow", + "priority": 65000, + "direction": "Inbound" + } + }, { + "name": "AllowAzureLoadBalancerInBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims859groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/AllowAzureLoadBalancerInBound", + "etag": "W/\"409ae6c7-fbe1-4bc4-aadb-c1d8330844d2\"", + "properties": { + "provisioningState": "Succeeded", + "description": "Allow inbound traffic from azure load balancer", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "AzureLoadBalancer", + "destinationAddressPrefix": "*", + "access": "Allow", + "priority": 65001, + "direction": "Inbound" + } + }, { + "name": "DenyAllInBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims859groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/DenyAllInBound", + "etag": "W/\"409ae6c7-fbe1-4bc4-aadb-c1d8330844d2\"", + "properties": { + "provisioningState": "Succeeded", + "description": "Deny all inbound traffic", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "access": "Deny", + "priority": 65500, + "direction": "Inbound" + } + }, { + "name": "AllowVnetOutBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims859groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/AllowVnetOutBound", + "etag": "W/\"409ae6c7-fbe1-4bc4-aadb-c1d8330844d2\"", + "properties": { + "provisioningState": "Succeeded", + "description": "Allow outbound traffic from all VMs to all VMs in VNET", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "VirtualNetwork", + "destinationAddressPrefix": "VirtualNetwork", + "access": "Allow", + "priority": 65000, + "direction": "Outbound" + } + }, { + "name": "AllowInternetOutBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims859groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/AllowInternetOutBound", + "etag": "W/\"409ae6c7-fbe1-4bc4-aadb-c1d8330844d2\"", + "properties": { + "provisioningState": "Succeeded", + "description": "Allow outbound traffic from all VMs to Internet", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "Internet", + "access": "Allow", + "priority": 65001, + "direction": "Outbound" + } + }, { + "name": "DenyAllOutBound", + "id": "/subscriptions/e43b3d9c-f839-48a8-b0fb-691aee6f1e4d/resourceGroups/jims859groupjclouds/providers/Microsoft.Network/networkSecurityGroups/testNetworkSecurityGroup/defaultSecurityRules/DenyAllOutBound", + "etag": "W/\"409ae6c7-fbe1-4bc4-aadb-c1d8330844d2\"", + "properties": { + "provisioningState": "Succeeded", + "description": "Deny all outbound traffic", + "protocol": "*", + "sourcePortRange": "*", + "destinationPortRange": "*", + "sourceAddressPrefix": "*", + "destinationAddressPrefix": "*", + "access": "Deny", + "priority": 65500, + "direction": "Outbound" + } + }] +} \ No newline at end of file From cadd60dc2203c6d07858a7defaffe2b49b2633b6 Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Mon, 16 May 2016 18:55:01 -0700 Subject: [PATCH 11/87] JCLOUDS-664 Azurecompute-arm compute service --- providers/azurecompute-arm/README.md | 20 +- .../azurecompute/arm/AzureComputeApi.java | 11 +- .../arm/AzureComputeProviderMetadata.java | 21 +- .../arm/AzureManagementApiMetadata.java | 2 + .../arm/compute/AzureComputeService.java | 104 +++++ .../compute/AzureComputeServiceAdapter.java | 393 ++++++++++++++++++ .../AzureComputeServiceContextModule.java | 191 +++++++++ .../functions/DeploymentToNodeMetadata.java | 207 +++++++++ .../compute/functions/LocationToLocation.java | 7 +- .../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 +++ .../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 - .../getresourceprovidermetadata.json | 366 ++++++++++++++++ 29 files changed, 2564 insertions(+), 52 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceAdapter.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/config/AzureComputeServiceContextModule.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/DeploymentToNodeMetadata.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMHardwareToHardware.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMImageToImage.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourceGroupThenCreateNodes.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceProviderMetaData.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMHardware.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMImage.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ResourceProviderApi.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/CleanupResources.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceContextLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureTemplateBuilderLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceProviderAPIMockTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceProviderApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/resources/getresourceprovidermetadata.json diff --git a/providers/azurecompute-arm/README.md b/providers/azurecompute-arm/README.md index fc8bb545af..c944a8a925 100644 --- a/providers/azurecompute-arm/README.md +++ b/providers/azurecompute-arm/README.md @@ -53,13 +53,25 @@ azure login -u -p --service-principal --tenant \ + -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 + +``` + +Use the following to run all the live tests: ```bash mvn clean verify -Plive \ - -Dtest.azurecompute-arm.identity= \ - -Dtest.azurecompute-arm.credential= \ - -Dtest.azurecompute-arm.endpoint=https://management.azure.com/subscriptions/ \ + -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 + ``` 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 c39022eb0b..42749cf520 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 @@ -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 docs + */ + @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 39defdca59..4bbc5080a6 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 @@ -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; } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java index 9a3292c57b..989fd841c8 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java +++ b/providers/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>builder() + .add(AzureComputeServiceContextModule.class) .add(OAuthModule.class) .add(OkHttpCommandExecutorServiceModule.class) .add(AzureComputeHttpApiModule.class).build()); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java new file mode 100644 index 0000000000..c215e37bb7 --- /dev/null +++ b/providers/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 credentialStore, + @Memoized Supplier> images, @Memoized Supplier> sizes, + @Memoized Supplier> locations, ListNodesStrategy listNodesStrategy, + GetImageStrategy getImageStrategy, GetNodeMetadataStrategy getNodeMetadataStrategy, + CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, RebootNodeStrategy rebootNodeStrategy, + DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy startNodeStrategy, + SuspendNodeStrategy stopNodeStrategy, Provider templateBuilderProvider, + @Named("DEFAULT") Provider templateOptionsProvider, + @Named(TIMEOUT_NODE_RUNNING) Predicate> nodeRunning, + @Named(TIMEOUT_NODE_TERMINATED) Predicate> nodeTerminated, + @Named(TIMEOUT_NODE_SUSPENDED) Predicate> nodeSuspended, + InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, + RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, + PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, + @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, + CleanupResources cleanupResources, + Optional imageExtension, + Optional 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 deadNodes) { + for (NodeMetadata deadNode : deadNodes) { + cleanupResources.apply(deadNode.getId()); + } + } + +} 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 new file mode 100644 index 0000000000..9a1d221a3f --- /dev/null +++ b/providers/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 { + + 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 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 deployments = Sets.newHashSet(); + + final DeploymentApi deploymentApi = api.getDeploymentApi(group); + + if (!retry(new Predicate() { + @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(deployment, name, + LoginCredentials.builder().user(loginUser).identity(loginUser).password(loginPassword).authenticateSudo(true).build()); + } + + @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()); + + Iterable 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 hwProfiles, Collection locations) { + Multimap 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 osImagesRef, String location) { + + OSImageApi osImageApi = api.getOSImageApi(location); + + Iterable offerList = osImageApi.listOffers(publisherName); + + for (Offer offer : offerList) { + Iterable 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 listImagesByLocation(String location) { + final List osImages = Lists.newArrayList(); + Iterable publishers = Splitter.on(',').trimResults().omitEmptyStrings().split(this.azureComputeConstants.azureImagePublishers()); + for (String publisher : publishers) { + getImagesFromPublisher(publisher, osImages, location); + } + return osImages; + } + + @Override + public Iterable listImages() { + + final List osImages = Lists.newArrayList(); + final List 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 images, Collection locations) { + Multimap 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 images = listImages(); + + for (VMImage image : images) { + String imageId = VMImageToImage.encodeFieldsToUniqueId(image); + if (id.equals(imageId)){ + return image; + } + } + return null; + } + + @Override + public Iterable listLocations() { + List locations = api.getLocationApi().list(); + + List resources = api.getResourceProviderApi().get("Microsoft.Compute"); + + final List vmLocations = new ArrayList(); + + for (ResourceProviderMetaData m : resources){ + if (m.resourceType().equals("virtualMachines")){ + vmLocations.addAll(m.locations()); + break; + } + } + + Iterable result = Iterables.filter(locations, new Predicate() { + @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 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 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; + } + + @Override + public Iterable listNodes() { + List deployments = api.getDeploymentApi(azureGroup).list(); + + List vmDeployments = new ArrayList(); + + for (Deployment d : deployments){ + VMDeployment vmDeployment = new VMDeployment(); + vmDeployment.deployment = d; + VirtualMachineApi vmApi = api.getVirtualMachineApi(azureGroup); + vmDeployment.vm = vmApi.getInstanceDetails(d.name()); + List list = getIPAddresses(d); + vmDeployment.ipAddressList = list; + + VirtualMachine virtualMachine = vmApi.get(d.name()); + vmDeployment.virtualMachine = virtualMachine; + + vmDeployments.add(vmDeployment); + } + return vmDeployments; + } + + @Override + public Iterable listNodesByIds(final Iterable ids) { + return Iterables.filter(listNodes(), new Predicate() { + @Override + public boolean apply(final VMDeployment input) { + return Iterables.contains(ids, input.deployment.name()); + } + }); + } + +} 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 new file mode 100644 index 0000000000..9844be42b2 --- /dev/null +++ b/providers/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 { + + @Override + protected void configure() { + super.configure(); + 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(LocationToLocation.class); + bind(ComputeService.class).to(AzureComputeService.class); + install(new LocationsFromComputeServiceAdapterModule() { + }); + + 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 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 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 { + + 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); + } + + } + +} 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 new file mode 100644 index 0000000000..bccc63cb53 --- /dev/null +++ b/providers/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 { + + 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); + + 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); + + 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 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 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 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(); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToLocation.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToLocation.java index a4d4b1ec1d..0ca1458770 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToLocation.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToLocation.java @@ -38,6 +38,7 @@ public class LocationToLocation implements Function 0 && (index + 1) < id.length()) + id = id.substring(index + 1); + builder.id(id); builder.description(location.displayName()); builder.parent(getOnlyElement(justProvider.get())); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMHardwareToHardware.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VMHardwareToHardware.java new file mode 100644 index 0000000000..51a6e5e8a8 --- /dev/null +++ b/providers/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 { + + private final Supplier> locations; + + @Inject + VMHardwareToHardware(@Memoized final Supplier> 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 metadata = ImmutableMap.builder(); + metadata.put("maxDataDiskCount", String.valueOf(from.maxDataDiskCount)); + builder.userMetadata(metadata.build()); + + return 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 new file mode 100644 index 0000000000..65a3d4b14a --- /dev/null +++ b/providers/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 { + + 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> 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> 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 osFamily() { + return new Function() { + @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); + } + }; + } +} 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 new file mode 100644 index 0000000000..6900f1799d --- /dev/null +++ b/providers/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> execute(String group, int count, Template template, + Set goodNodes, Map badNodes, + Multimap customizationResponses) { + + ResourceGroupApi resourceGroupApi = api.getResourceGroupApi(); + ResourceGroup resourceGroup = resourceGroupApi.get(group); + final String location = template.getLocation().getId(); + final String resourceGroupName; + + if (resourceGroup == null){ + + final Map tags = ImmutableMap.of("description", "jClouds managed VMs"); + resourceGroupName = resourceGroupApi.create(group, location, tags).name(); + } else { + resourceGroupName = resourceGroup.name(); + } + + Map> responses = super.execute(resourceGroupName, count, template, goodNodes, badNodes, + customizationResponses); + + return responses; + } + +} 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 48188c41d7..48d6287740 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 @@ -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"; + } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceProviderMetaData.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceProviderMetaData.java new file mode 100644 index 0000000000..84526b9456 --- /dev/null +++ b/providers/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 locations(); + + public abstract List apiVersions(); + + @SerializedNames({"resourceType", "locations", "apiVersions"}) + public static ResourceProviderMetaData create(final String resourceType, final List locations, final List apiVersions) { + ResourceProviderMetaData.Builder builder = ResourceProviderMetaData.builder() + .resourceType(resourceType) + .locations(locations == null ? ImmutableList.of() : ImmutableList.copyOf(locations)) + .apiVersions(apiVersions == null ? ImmutableList.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 locations); + + public abstract Builder apiVersions(List apiVersions); + + abstract List locations(); + + abstract List apiVersions(); + + abstract ResourceProviderMetaData autoBuild(); + + public ResourceProviderMetaData build() { + locations(locations() != null ? ImmutableList.copyOf(locations()) : ImmutableList.of()); + apiVersions(apiVersions() != null ? ImmutableList.copyOf(apiVersions()) : ImmutableList.of()); + return autoBuild(); + } + } +} 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 2504409319..6909a7b49b 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 @@ -26,4 +26,6 @@ public class VMDeployment { public List ipAddressList; public VirtualMachineInstance vm; + + public VirtualMachine virtualMachine; } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMHardware.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMHardware.java new file mode 100644 index 0000000000..d338327dca --- /dev/null +++ b/providers/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 api + */ +@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; +} 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 new file mode 100644 index 0000000000..ccfb05aef9 --- /dev/null +++ b/providers/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; +} 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 71387e6712..3013543979 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 @@ -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 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); } } 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 new file mode 100644 index 0000000000..e3d38b8ebd --- /dev/null +++ b/providers/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 docs + */ +@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 get(@PathParam("namespace") String namespace); +} 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 new file mode 100644 index 0000000000..2b6a18ee3d --- /dev/null +++ b/providers/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 { + + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + protected final AzureComputeApi api; + private Predicate nodeTerminated; + private Predicate resourceDeleted; + + @Inject + public CleanupResources(AzureComputeApi azureComputeApi, + @Named(TIMEOUT_NODE_TERMINATED) Predicate nodeTerminated, + @Named(TIMEOUT_RESOURCE_DELETED) Predicate 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; + } + } +} 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 index ffa533e182..ed5ec9eb96 100644 --- 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 @@ -19,6 +19,7 @@ package org.jclouds.azurecompute.arm.util; import com.google.common.collect.ImmutableMap; import com.google.inject.assistedinject.Assisted; +import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule; import org.jclouds.azurecompute.arm.domain.DeploymentProperties; import org.jclouds.compute.options.TemplateOptions; import org.jclouds.azurecompute.arm.domain.DataDisk; @@ -72,12 +73,11 @@ public class DeploymentTemplateBuilder { private TemplateOptions options; private List resources; private Map variables; - private String loginUser; - private String loginPassword; + private static String loginUser; + private static String loginPassword; private String location; + private AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants; - public static final String DEFAULT_LOGIN_USER = "jclouds"; - public static final String DEFAULT_LOGIN_PASSWORD = "Password1!"; private static final String DEPLOYMENT_MODE = "Incremental"; private static final String DEFAULT_DATA_DISK_SIZE = "1023"; @@ -85,24 +85,37 @@ public class DeploymentTemplateBuilder { private static final String DEFAULT_subnetAddressPrefix = "10.0.0.0/24"; @Inject - DeploymentTemplateBuilder(Json json, @Assisted("group") String group, @Assisted("name") String name, @Assisted Template template) { + 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(TemplateOptions.class); this.variables = new HashMap(); this.resources = new ArrayList(); - this.loginUser = options.getLoginUser() == null ? DEFAULT_LOGIN_USER : options.getLoginUser(); - this.loginPassword = options.getLoginPassword() == null ? DEFAULT_LOGIN_PASSWORD : options.getLoginPassword(); this.location = template.getLocation().getId(); this.json = json; + + this.azureComputeConstants = azureComputeConstants; + + 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 String getLoginUserUsername() { + public static String getLoginUserUsername() { return loginUser; } - public String getLoginPassword() { + public static String getLoginPassword() { return loginPassword; } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceContextLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceContextLiveTest.java new file mode 100644 index 0000000000..940f7855cc --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceContextLiveTest.java @@ -0,0 +1,284 @@ +/* + * 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 com.google.common.base.Preconditions; +import com.google.common.base.Predicate; +import com.google.inject.Module; +import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; +import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; +import org.jclouds.compute.RunNodesException; +import org.jclouds.compute.RunScriptOnNodesException; +import org.jclouds.compute.domain.ComputeMetadata; +import org.jclouds.compute.domain.ExecResponse; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.OsFamily; +import org.jclouds.compute.domain.Template; +import org.jclouds.compute.domain.TemplateBuilder; +import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest; +import org.jclouds.domain.Credentials; +import org.jclouds.domain.LoginCredentials; +import org.jclouds.providers.ProviderMetadata; +import org.jclouds.sshj.config.SshjSshClientModule; +import org.testng.annotations.Test; + +import java.util.Map; +import java.util.Properties; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.assertj.core.api.Assertions.assertThat; +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; + +import static org.jclouds.compute.predicates.NodePredicates.inGroup; +import static org.jclouds.compute.options.TemplateOptions.Builder.overrideLoginCredentials; +import static org.jclouds.scriptbuilder.domain.Statements.exec; +import static org.testng.Assert.assertTrue; + +@Test(groups = "live", testName = "AzureComputeServiceContextLiveTest") +public class AzureComputeServiceContextLiveTest extends BaseComputeServiceContextLiveTest { + + public String azureGroup; + protected static final int RAND = new Random().nextInt(999); + + @Override + protected Module getSshModule() { + return new SshjSshClientModule(); + } + + @Override protected Properties setupProperties() { + azureGroup = "jc" + RAND; + + Properties properties = super.setupProperties(); + long scriptTimeout = TimeUnit.MILLISECONDS.convert(60, TimeUnit.MINUTES); + properties.setProperty(TIMEOUT_SCRIPT_COMPLETE, scriptTimeout + ""); + properties.setProperty(TIMEOUT_NODE_RUNNING, scriptTimeout + ""); + + AzureLiveTestUtils.defaultProperties(properties); + checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); + + properties.put(RESOURCE_GROUP_NAME, azureGroup); + return properties; + } + + public AzureComputeServiceContextLiveTest() { + provider = "azurecompute-arm"; + } + + @Test + public void testDefault() throws RunNodesException { + + final String groupName = this.azureGroup; + final TemplateBuilder templateBuilder = view.getComputeService().templateBuilder(); + templateBuilder.osFamily(OsFamily.UBUNTU); + templateBuilder.osVersionMatches("14.04"); + templateBuilder.hardwareId("Standard_A0"); + templateBuilder.locationId("westus"); + + final Template template = templateBuilder.build(); + + try { + Set nodes = view.getComputeService().createNodesInGroup(groupName, 1, template); + assertThat(nodes).hasSize(1); + } finally { +// Do not destroy view.getComputeService().destroyNodesMatching(inGroup(groupName)); + } + } + + private LoginCredentials getLogin() { + Credentials credentials = new Credentials("jclouds", "Password1!"); + LoginCredentials login = LoginCredentials.fromCredentials(credentials); + return login; + } + + @Test(dependsOnMethods = "testDefault") + public void testExec() throws RunScriptOnNodesException { + final String groupName = this.azureGroup; + String command = "echo hello"; + + Map responses = view.getComputeService().runScriptOnNodesMatching(// + inGroup(groupName), // predicate used to select nodes + exec(command), // what you actually intend to run + overrideLoginCredentials(getLogin()) // use my local user & + // ssh key + .runAsRoot(false) // don't attempt to run as root (sudo) + .wrapInInitScript(false)); // run command directly + + assertTrue(responses.size() > 0); + } + + public static Predicate nameStartsWith(final String prefix) { + Preconditions.checkNotNull(prefix, "prefix must be defined"); + + return new Predicate() { + @Override + public boolean apply(ComputeMetadata computeMetadata) { + return computeMetadata.getName().startsWith(prefix); + } + + @Override + public String toString() { + return "nameStartsWith(" + prefix + ")"; + } + }; + } + + @Test(dependsOnMethods = "testExec") + public void testStop() throws RunScriptOnNodesException { + final String groupName = this.azureGroup; + Set nodes = view.getComputeService().suspendNodesMatching(inGroup(groupName)); + assertTrue(nodes.size() > 0); + + boolean allStopped = false; + while (!allStopped) { + nodes = view.getComputeService().listNodesDetailsMatching(nameStartsWith(groupName)); + for (NodeMetadata node : nodes) { + if (node.getStatus() != NodeMetadata.Status.SUSPENDED) + { + // Not stopped yet + allStopped = false; + try { + Thread.sleep(15 * 1000); + } catch (InterruptedException e) { + } + continue; + } + else + { + allStopped = true; + } + } + } + assertTrue(allStopped); + } + + @Test(dependsOnMethods = "testStop") + public void testStart() throws RunScriptOnNodesException { + final String groupName = this.azureGroup; + Set nodes = view.getComputeService().resumeNodesMatching(inGroup(groupName)); + assertTrue(nodes.size() > 0); + + boolean allStarted = false; + while (!allStarted) { + nodes = view.getComputeService().listNodesDetailsMatching(nameStartsWith(groupName)); + for (NodeMetadata node : nodes) { + if (node.getStatus() != NodeMetadata.Status.RUNNING) + { + // Not started yet + allStarted = false; + try { + Thread.sleep(15 * 1000); + } catch (InterruptedException e) { + } + continue; + } + else + { + allStarted = true; + } + } + } + assertTrue(allStarted); + } + + @Test(dependsOnMethods = "testStart") + public void testRestart() throws RunScriptOnNodesException { + final String groupName = this.azureGroup; + Set nodes = view.getComputeService().rebootNodesMatching(inGroup(groupName)); + assertTrue(nodes.size() > 0); + + boolean allRestarted = false; + while (!allRestarted) { + nodes = view.getComputeService().listNodesDetailsMatching(nameStartsWith(groupName)); + for (NodeMetadata node : nodes) { + if (node.getStatus() != NodeMetadata.Status.RUNNING) + { + // Not started yet + allRestarted = false; + try { + Thread.sleep(30 * 1000); + } catch (InterruptedException e) { + } + continue; + } + else + { + allRestarted = true; + } + } + } + assertTrue(allRestarted); + + view.getComputeService().destroyNodesMatching(inGroup(groupName)); + } + + @Test(dependsOnMethods = "testRestart") + public void testLinuxNode() throws RunNodesException { + final String groupName = this.azureGroup; + final TemplateBuilder templateBuilder = view.getComputeService().templateBuilder(); + templateBuilder.osFamily(OsFamily.UBUNTU); + templateBuilder.osVersionMatches("14.04"); + templateBuilder.hardwareId("Standard_A0"); + templateBuilder.locationId("westus"); + final Template template = templateBuilder.build(); + + try { + Set nodes = view.getComputeService().createNodesInGroup(groupName, 1, template); + assertThat(nodes).hasSize(1); + } finally { + view.getComputeService().destroyNodesMatching(inGroup(groupName)); + } + } + + @Test(dependsOnMethods = "testLinuxNode") + public void testWindowsNode() throws RunNodesException { + final String groupName = this.azureGroup; + final TemplateBuilder templateBuilder = view.getComputeService().templateBuilder(); + templateBuilder.imageId("global/MicrosoftWindowsServer/WindowsServer/Windows-Server-Technical-Preview"); + templateBuilder.hardwareId("Standard_A0"); + templateBuilder.locationId("westus"); + final Template template = templateBuilder.build(); + + try { + Set nodes = view.getComputeService().createNodesInGroup(groupName, 1, template); + assertThat(nodes).hasSize(1); + } finally { + view.getComputeService().destroyNodesMatching(inGroup(groupName)); + } + } + + @Override + protected ProviderMetadata createProviderMetadata() { + AzureComputeProviderMetadata pm = AzureComputeProviderMetadata.builder().build(); + return pm; + } + + protected String setIfTestSystemPropertyPresent(Properties overrides, String key) { + if (System.getProperties().containsKey("test." + key)) { + String val = System.getProperty("test." + key); + overrides.setProperty(key, val); + return val; + } else { + return null; + } + } + +} 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 new file mode 100644 index 0000000000..ae43511fe2 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceLiveTest.java @@ -0,0 +1,73 @@ +/* + * 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 org.jclouds.compute.internal.BaseComputeServiceLiveTest; +import org.jclouds.sshj.config.SshjSshClientModule; +import org.testng.annotations.Test; + +import org.jclouds.providers.ProviderMetadata; + +import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; + +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; +import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; + +import com.google.inject.Module; +import java.util.Properties; +import java.util.concurrent.TimeUnit; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Live tests for the {@link org.jclouds.compute.ComputeService} integration. + */ +@Test(groups = "live", singleThreaded = true, testName = "AzureComputeServiceLiveTest") +public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest { + public String azureGroup; + + public AzureComputeServiceLiveTest() { + provider = "azurecompute-arm"; + } + + @Override + protected Module getSshModule() { + return new SshjSshClientModule(); + } + + @Override + protected ProviderMetadata createProviderMetadata() { + AzureComputeProviderMetadata pm = AzureComputeProviderMetadata.builder().build(); + return pm; + } + + @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); + + AzureLiveTestUtils.defaultProperties(properties); + checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); + + return properties; + + } +} 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 new file mode 100644 index 0000000000..652c12ad54 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureTemplateBuilderLiveTest.java @@ -0,0 +1,77 @@ +/* + * 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 com.google.inject.Module; +import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; +import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; +import org.jclouds.compute.internal.BaseTemplateBuilderLiveTest; +import org.jclouds.providers.ProviderMetadata; +import org.jclouds.sshj.config.SshjSshClientModule; +import org.testng.annotations.Test; + +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import com.google.common.collect.ImmutableSet; + +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"); + } + + public AzureTemplateBuilderLiveTest() { + provider = "azurecompute-arm"; + } + + @Override + protected Module getSshModule() { + return new SshjSshClientModule(); + } + + @Override + protected ProviderMetadata createProviderMetadata() { + AzureComputeProviderMetadata pm = AzureComputeProviderMetadata.builder().build(); + return pm; + } + + @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); + + AzureLiveTestUtils.defaultProperties(properties); + checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); + + return properties; + + } +} 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 new file mode 100644 index 0000000000..70f2ad606f --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceProviderAPIMockTest.java @@ -0,0 +1,67 @@ +/* + * 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.azurecompute.arm.domain.ResourceProviderMetaData; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; +import org.testng.annotations.Test; + +import java.util.List; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +@Test(groups = "unit", testName = "NetworkInterfaceCardApiMockTest", singleThreaded = true) +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")); + + final ResourceProviderApi resourceProviderApi = api.getResourceProviderApi(); + + List metaDatas = resourceProviderApi.get(resource); + + String path = String.format("/subscriptions/SUBSCRIPTIONID/providers/%s?api-version=%s", resource, apiVersion); + + assertSent(server, "GET", path); + assertTrue(metaDatas.size() > 0); + ResourceProviderMetaData md = metaDatas.get(0); + + assertEquals(md.resourceType(), "availabilitySets"); + assertEquals(md.locations().get(0), "East US"); + assertEquals(md.apiVersions().get(0), "2016-03-30"); + } + + public void getPublicIPAddressInfoEmpty() throws InterruptedException { + server.enqueue(response404()); + + final ResourceProviderApi resourceProviderApi = api.getResourceProviderApi(); + + List metaDatas = resourceProviderApi.get(resource); + + String path = String.format("/subscriptions/SUBSCRIPTIONID/providers/%s?api-version=%s", resource, apiVersion); + + assertSent(server, "GET", path); + assertNull(metaDatas); + } +} + diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceProviderApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceProviderApiLiveTest.java new file mode 100644 index 0000000000..5ebf99646c --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceProviderApiLiveTest.java @@ -0,0 +1,55 @@ +/* + * 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 com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import org.jclouds.azurecompute.arm.domain.ResourceProviderMetaData; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; +import org.testng.annotations.Test; + +import java.util.List; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + + +@Test(groups = "live", testName = "ResourceProviderApiLiveTest") +public class ResourceProviderApiLiveTest extends BaseAzureComputeApiLiveTest { + + private final String PROVIDER = "Microsoft.Compute"; + private final String VM_RESOURCE_TYPE = "virtualMachines"; + + private ResourceProviderApi api() { + return api.getResourceProviderApi(); + } + + @Test + public void testGetComputeProviderMetadata() { + + List resourceProviderMetaDatas = api().get(PROVIDER); + + assertNotNull(resourceProviderMetaDatas); + + assertTrue(Iterables.any(resourceProviderMetaDatas, new Predicate() { + @Override + public boolean apply(final ResourceProviderMetaData providerMetaData) { + return providerMetaData.resourceType().equals(VM_RESOURCE_TYPE); + } + })); + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AbstractAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AbstractAzureComputeApiLiveTest.java index bd55694815..337812be91 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AbstractAzureComputeApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AbstractAzureComputeApiLiveTest.java @@ -17,20 +17,19 @@ package org.jclouds.azurecompute.arm.internal; import static com.google.common.base.Preconditions.checkNotNull; -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 java.util.Properties; import java.util.Random; +import com.google.inject.Module; +import com.google.inject.Injector; + + import org.jclouds.apis.BaseApiLiveTest; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; -import org.jclouds.compute.config.ComputeServiceProperties; import org.jclouds.providers.ProviderMetadata; + public abstract class AbstractAzureComputeApiLiveTest extends BaseApiLiveTest { protected static final int RAND = new Random().nextInt(999); @@ -39,19 +38,16 @@ public abstract class AbstractAzureComputeApiLiveTest extends BaseApiLiveTest modules) { + Injector injector = newBuilder().modules(modules).overrides(props).buildInjector(); + return injector.getInstance(AzureComputeApi.class); + } + @Override protected Properties setupProperties() { Properties properties = super.setupProperties(); - properties.put(ComputeServiceProperties.POLL_INITIAL_PERIOD, 1000); - properties.put(ComputeServiceProperties.POLL_MAX_PERIOD, 10000); - properties.setProperty(OPERATION_TIMEOUT, "60000"); - 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}"); // for oauth AzureLiveTestUtils.defaultProperties(properties); - checkNotNull(setIfTestSystemPropertyPresent(properties, "jclouds.oauth.resource"), "test.jclouds.oauth.resource"); checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); return properties; } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java index 900d3e0499..bd9adfc4bd 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java @@ -65,25 +65,6 @@ public class BaseAzureComputeApiLiveTest extends AbstractAzureComputeApiLiveTest private String storageServiceName = null; - - protected String getCredential() { - String credential = null; - if (System.getProperty("test.azurecompute-arm.credential") != null) { - credential = System.getProperty("test.azurecompute-arm.credential"); - } - assertNotNull(credential); - return credential; - } - - protected String getIdentity() { - String identity = null; - if (System.getProperty("test.azurecompute-arm.identity") != null) { - identity = System.getProperty("test.azurecompute-arm.identity"); - } - assertNotNull(identity); - return identity; - } - protected String getStorageServiceName() { if (storageServiceName == null) { storageServiceName = String.format("%3.24s", diff --git a/providers/azurecompute-arm/src/test/resources/getresourceprovidermetadata.json b/providers/azurecompute-arm/src/test/resources/getresourceprovidermetadata.json new file mode 100644 index 0000000000..b7693d7307 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/getresourceprovidermetadata.json @@ -0,0 +1,366 @@ +{ + "id": "/subscriptions/SUBSCRIPTIONID/providers/Microsoft.Compute", + "namespace": "Microsoft.Compute", + "authorization": { + "applicationId": "12312312-1212-1212-1212-121212121212", + "roleDefinitionId": "34534534-272e-4238-8723-123423452224" + }, + "resourceTypes": [ + { + "resourceType": "availabilitySets", + "locations": [ + "East US", + "East US 2", + "West US", + "Central US", + "North Central US", + "South Central US", + "North Europe", + "West Europe", + "East Asia", + "Southeast Asia", + "Japan East", + "Japan West", + "Brazil South" + ], + "apiVersions": [ + "2016-03-30", + "2015-06-15", + "2015-05-01-preview" + ], + "capabilities": "CrossResourceGroupResourceMove, CrossSubscriptionResourceMove" + }, + { + "resourceType": "virtualMachines", + "locations": [ + "East US", + "East US 2", + "West US", + "Central US", + "North Central US", + "South Central US", + "North Europe", + "West Europe", + "East Asia", + "Southeast Asia", + "Japan East", + "Japan West", + "Brazil South" + ], + "apiVersions": [ + "2016-03-30", + "2015-06-15", + "2015-05-01-preview" + ], + "capabilities": "CrossResourceGroupResourceMove, CrossSubscriptionResourceMove" + }, + { + "resourceType": "virtualMachines/extensions", + "locations": [ + "East US", + "East US 2", + "West US", + "Central US", + "North Central US", + "South Central US", + "North Europe", + "West Europe", + "East Asia", + "Southeast Asia", + "Japan East", + "Japan West", + "Brazil South" + ], + "apiVersions": [ + "2016-03-30", + "2015-06-15", + "2015-05-01-preview" + ], + "capabilities": "CrossResourceGroupResourceMove, CrossSubscriptionResourceMove" + }, + { + "resourceType": "virtualMachines/diagnosticSettings", + "locations": [ + "East US", + "East US 2", + "West US", + "Central US", + "North Central US", + "South Central US", + "North Europe", + "West Europe", + "East Asia", + "Southeast Asia", + "Japan East", + "Japan West", + "Brazil South" + ], + "apiVersions": [ + "2014-04-01" + ] + }, + { + "resourceType": "virtualMachines/metricDefinitions", + "locations": [ + "East US", + "East US 2", + "West US", + "Central US", + "North Central US", + "South Central US", + "North Europe", + "West Europe", + "East Asia", + "Southeast Asia", + "Japan East", + "Japan West", + "Brazil South" + ], + "apiVersions": [ + "2014-04-01" + ] + }, + { + "resourceType": "virtualMachineScaleSets", + "locations": [ + "East US", + "East US 2", + "West US", + "Central US", + "North Central US", + "South Central US", + "North Europe", + "West Europe", + "East Asia", + "Southeast Asia", + "Japan East", + "Japan West", + "Brazil South" + ], + "apiVersions": [ + "2016-03-30", + "2015-06-15", + "2015-05-01-preview" + ], + "capabilities": "None" + }, + { + "resourceType": "virtualMachineScaleSets/extensions", + "locations": [ + "East US", + "East US 2", + "West US", + "Central US", + "North Central US", + "South Central US", + "North Europe", + "West Europe", + "East Asia", + "Southeast Asia", + "Japan East", + "Japan West", + "Brazil South" + ], + "apiVersions": [ + "2016-03-30", + "2015-06-15", + "2015-05-01-preview" + ], + "capabilities": "CrossResourceGroupResourceMove, CrossSubscriptionResourceMove" + }, + { + "resourceType": "virtualMachineScaleSets/virtualMachines", + "locations": [ + "East US", + "East US 2", + "West US", + "Central US", + "North Central US", + "South Central US", + "North Europe", + "West Europe", + "East Asia", + "Southeast Asia", + "Japan East", + "Japan West", + "Brazil South" + ], + "apiVersions": [ + "2016-03-30", + "2015-06-15", + "2015-05-01-preview" + ] + }, + { + "resourceType": "virtualMachineScaleSets/networkInterfaces", + "locations": [ + "East US", + "East US 2", + "West US", + "Central US", + "North Central US", + "South Central US", + "North Europe", + "West Europe", + "East Asia", + "Southeast Asia", + "Japan East", + "Japan West", + "Brazil South" + ], + "apiVersions": [ + "2016-03-30", + "2015-06-15", + "2015-05-01-preview" + ] + }, + { + "resourceType": "virtualMachineScaleSets/virtualMachines/networkInterfaces", + "locations": [ + "East US", + "East US 2", + "West US", + "Central US", + "North Central US", + "South Central US", + "North Europe", + "West Europe", + "East Asia", + "Southeast Asia", + "Japan East", + "Japan West", + "Brazil South" + ], + "apiVersions": [ + "2016-03-30", + "2015-06-15", + "2015-05-01-preview" + ] + }, + { + "resourceType": "locations", + "locations": [], + "apiVersions": [ + "2016-03-30", + "2015-06-15", + "2015-05-01-preview" + ] + }, + { + "resourceType": "locations/operations", + "locations": [ + "East US", + "East US 2", + "West US", + "Central US", + "North Central US", + "South Central US", + "North Europe", + "West Europe", + "East Asia", + "Southeast Asia", + "Japan East", + "Japan West", + "Brazil South" + ], + "apiVersions": [ + "2016-03-30", + "2015-06-15", + "2015-05-01-preview" + ] + }, + { + "resourceType": "locations/vmSizes", + "locations": [ + "East US", + "East US 2", + "West US", + "Central US", + "North Central US", + "South Central US", + "North Europe", + "West Europe", + "East Asia", + "Southeast Asia", + "Japan East", + "Japan West", + "Brazil South" + ], + "apiVersions": [ + "2016-03-30", + "2015-06-15", + "2015-05-01-preview" + ] + }, + { + "resourceType": "locations/usages", + "locations": [ + "East US", + "East US 2", + "West US", + "Central US", + "North Central US", + "South Central US", + "North Europe", + "West Europe", + "East Asia", + "Southeast Asia", + "Japan East", + "Japan West", + "Brazil South" + ], + "apiVersions": [ + "2016-03-30", + "2015-06-15", + "2015-05-01-preview" + ] + }, + { + "resourceType": "locations/publishers", + "locations": [ + "East US", + "East US 2", + "West US", + "Central US", + "North Central US", + "South Central US", + "North Europe", + "West Europe", + "East Asia", + "Southeast Asia", + "Japan East", + "Japan West", + "Brazil South" + ], + "apiVersions": [ + "2016-03-30", + "2015-06-15", + "2015-05-01-preview" + ] + }, + { + "resourceType": "operations", + "locations": [ + "East US", + "East US 2", + "West US", + "Central US", + "North Central US", + "South Central US", + "North Europe", + "West Europe", + "East Asia", + "Southeast Asia", + "Japan East", + "Japan West", + "Brazil South" + ], + "apiVersions": [ + "2016-03-30", + "2015-06-15", + "2015-05-01-preview" + ] + } + ], + "registrationState": "Registered" +} \ No newline at end of file From 10d9b38976ef692dfa52872a5f27bca658bf9101 Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Mon, 16 May 2016 18:55:01 -0700 Subject: [PATCH 12/87] JCLOUDS-664 Azurecompute-arm image capture userdata keyvault --- providers/azurecompute-arm/pom.xml | 1 + .../arm/AzureComputeProviderMetadata.java | 8 +- .../compute/AzureComputeServiceAdapter.java | 103 +++--- .../AzureComputeServiceContextModule.java | 144 ++++++++- .../AzureComputeImageExtension.java | 142 +++++++++ .../functions/DeploymentToNodeMetadata.java | 56 ++-- .../functions/VMHardwareToHardware.java | 23 +- .../arm/compute/functions/VMImageToImage.java | 29 +- .../compute/options/AzureTemplateOptions.java | 223 +++++++++++++ ...faultLoginCredentialsForImageStrategy.java | 43 +++ .../CreateResourceGroupThenCreateNodes.java | 62 +++- .../arm/config/AzureComputeProperties.java | 6 + .../arm/domain/DeploymentTemplate.java | 27 +- .../arm/domain/KeyVaultReference.java | 46 +++ .../NetworkInterfaceCardProperties.java | 12 +- .../azurecompute/arm/domain/OSDisk.java | 29 +- .../arm/domain/StorageProfile.java | 1 + .../arm/domain/TemplateParameterType.java | 34 ++ .../azurecompute/arm/domain/VMDeployment.java | 5 + .../azurecompute/arm/domain/VMHardware.java | 25 +- .../azurecompute/arm/domain/VMImage.java | 21 +- .../azurecompute/arm/features/JobApi.java | 15 + .../arm/features/VirtualMachineApi.java | 25 ++ .../arm/functions/CleanupResources.java | 88 +++-- .../arm/functions/StatusCodeParser.java | 38 +++ .../handlers/AzureComputeErrorHandler.java | 7 +- .../arm/util/DeploymentTemplateBuilder.java | 300 ++++++++++++------ .../AzureComputeServiceContextLiveTest.java | 284 ----------------- .../compute/AzureComputeServiceLiveTest.java | 64 +++- .../AzureComputeImageExtensionLiveTest.java | 89 ++++++ .../arm/features/DeploymentApiLiveTest.java | 3 +- .../DeploymentTemplateBuilderTest.java | 80 +++-- .../arm/features/JobApiMockTest.java | 23 ++ .../NetworkInterfaceCardApiMockTest.java | 3 +- .../TemplateToDeploymentTemplateLiveTest.java | 89 +++++- .../features/VirtualMachineApiLiveTest.java | 103 ++++-- .../features/VirtualMachineApiMockTest.java | 32 +- .../AbstractAzureComputeApiLiveTest.java | 15 + .../internal/BaseAzureComputeApiLiveTest.java | 10 +- .../src/test/resources/logback.xml | 82 +++++ .../test/resources/resourceDefinition.json | 22 ++ 41 files changed, 1783 insertions(+), 629 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtension.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/AzureTemplateOptions.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/AzurePopulateDefaultLoginCredentialsForImageStrategy.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/KeyVaultReference.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/TemplateParameterType.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/StatusCodeParser.java delete mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceContextLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtensionLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/resources/logback.xml create mode 100644 providers/azurecompute-arm/src/test/resources/resourceDefinition.json diff --git a/providers/azurecompute-arm/pom.xml b/providers/azurecompute-arm/pom.xml index 33251fded1..5a41e44f21 100644 --- a/providers/azurecompute-arm/pom.xml +++ b/providers/azurecompute-arm/pom.xml @@ -156,6 +156,7 @@ test + 1 ${test.azurecompute-arm.endpoint} ${test.azurecompute-arm.api-version} 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 4bbc5080a6..460df67276 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 @@ -24,6 +24,9 @@ import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATI 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_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; @@ -70,7 +73,10 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { 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_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!"); properties.put(TIMEOUT_NODE_TERMINATED, 60 * 10 * 1000); 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 9a1d221a3f..3d87d6d1f8 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 @@ -18,9 +18,11 @@ package org.jclouds.azurecompute.arm.compute; import static java.lang.String.format; import static java.util.concurrent.TimeUnit.SECONDS; +import static org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageExtension.CUSTOM_IMAGE_PREFIX; import static org.jclouds.util.Predicates2.retry; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -40,15 +42,14 @@ 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.ResourceProviderMetaData; 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; @@ -60,6 +61,8 @@ import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.domain.LoginCredentials; import org.jclouds.logging.Logger; import org.jclouds.azurecompute.arm.functions.CleanupResources; +import org.jclouds.azurecompute.arm.domain.VMSize; +import org.jclouds.azurecompute.arm.domain.Version; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; @@ -118,15 +121,13 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter deployments = Sets.newHashSet(); - final DeploymentApi deploymentApi = api.getDeploymentApi(group); + 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) { @@ -149,8 +150,18 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter(deployment, name, - LoginCredentials.builder().user(loginUser).identity(loginUser).password(loginPassword).authenticateSudo(true).build()); + NodeAndInitialCredentials credential = null; + + 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; } @Override @@ -166,17 +177,17 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter 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(); + VMHardware hwProfile = VMHardware.create( + vmSize.name(), + vmSize.numberOfCores(), + vmSize.osDiskSizeInMB(), + vmSize.resourceDiskSizeInMB(), + vmSize.memoryInMB(), + vmSize.maxDataDiskCount(), + location.name(), + false); hwProfiles.add(hwProfile); } - } checkAndSetHwAvailability(hwProfiles, Sets.newHashSet(locationIds)); @@ -186,32 +197,33 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter hwProfiles, Collection locations) { Multimap hwMap = ArrayListMultimap.create(); for (VMHardware hw : hwProfiles) { - hwMap.put(hw.name, hw.location); + hwMap.put(hw.name(), hw.location()); } - for (VMHardware hw : hwProfiles) { - hw.globallyAvailable = hwMap.get(hw.name).containsAll(locations); - } + /// TODO + // for (VMHardware hw : hwProfiles) { + // hw.globallyAvailable() = hwMap.get(hw.name()).containsAll(locations); + // } } private void getImagesFromPublisher(String publisherName, List osImagesRef, String location) { - OSImageApi osImageApi = api.getOSImageApi(location); + OSImageApi osImageApi = api.getOSImageApi(location); Iterable offerList = osImageApi.listOffers(publisherName); for (Offer offer : offerList) { Iterable 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); + Iterable versionList = osImageApi.listVersions(publisherName, offer.name(), sku.name()); + for (Version version : versionList) { + VMImage vmImage = VMImage.create(publisherName, offer.name(), sku.name(), version.name(), location, false); + osImagesRef.add(vmImage); + } } } + } private List listImagesByLocation(String location) { @@ -241,17 +253,23 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter 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); + map.put( image.offer() + "/" + image.sku(), image.location()); } + ///TODO + // 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); + if (fields[2].startsWith(CUSTOM_IMAGE_PREFIX)) { + String storage = fields[2].substring(CUSTOM_IMAGE_PREFIX.length()); + String vhd = fields[3]; + VMImage ref = VMImage.create(CUSTOM_IMAGE_PREFIX + azureGroup, CUSTOM_IMAGE_PREFIX + storage, vhd, null, fields[0], false); + return ref; + } Iterable images = listImages(); @@ -266,6 +284,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listLocations() { + List locations = api.getLocationApi().list(); List resources = api.getResourceProviderApi().get("Microsoft.Compute"); @@ -286,7 +305,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter list = getIPAddresses(deployment); vmDeployment.ipAddressList = list; - VirtualMachine vm = api.getVirtualMachineApi(azureGroup).get(id); vmDeployment.virtualMachine = vm; + vmDeployment.vm = api.getVirtualMachineApi(azureGroup).getInstanceDetails(id); + if (vm != null && vm.tags() != null) { + vmDeployment.userMetaData = vm.tags(); + String tagString = vmDeployment.userMetaData.get("tags"); + List tags = Arrays.asList(tagString.split(",")); + vmDeployment.tags = tags; + } return vmDeployment; } @@ -372,9 +397,15 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter list = getIPAddresses(d); vmDeployment.ipAddressList = list; - VirtualMachine virtualMachine = vmApi.get(d.name()); - vmDeployment.virtualMachine = virtualMachine; + VirtualMachine vm = vmApi.get(d.name()); + vmDeployment.virtualMachine = vm; + if (vm != null && vm.tags() != null) { + vmDeployment.userMetaData = vm.tags(); + String tagString = vmDeployment.userMetaData.get("tags"); + List tags = Arrays.asList(tagString.split(",")); + vmDeployment.tags = tags; + } vmDeployments.add(vmDeployment); } return vmDeployments; 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 9844be42b2..7df8111afa 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,34 +16,56 @@ */ package org.jclouds.azurecompute.arm.compute.config; +import javax.annotation.Resource; 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.extensions.AzureComputeImageExtension; 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.compute.strategy.AzurePopulateDefaultLoginCredentialsForImageStrategy; +import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; +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.Location; import org.jclouds.azurecompute.arm.compute.strategy.CreateResourceGroupThenCreateNodes; import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance; import org.jclouds.azurecompute.arm.functions.ParseJobStatus; -import org.jclouds.azurecompute.arm.compute.AzureComputeService; - +import org.jclouds.compute.options.TemplateOptions; 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.reference.ComputeServiceConstants; 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.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.RESOURCE_GROUP_NAME; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_IMAGE_LOGIN; +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.TIMEOUT_RESOURCE_DELETED; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_DATADISKSIZE; + +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; import static org.jclouds.util.Predicates2.retry; import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_IMAGE_AVAILABLE; import com.google.common.base.Function; import com.google.inject.Inject; @@ -52,21 +74,22 @@ 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 java.util.List; -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; +import org.jclouds.compute.extensions.ImageExtension; +import org.jclouds.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy; +import org.jclouds.azurecompute.arm.compute.AzureComputeService; +import org.jclouds.compute.ComputeService; +import org.jclouds.logging.Logger; public class AzureComputeServiceContextModule extends ComputeServiceAdapterContextModule { + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + @Override protected void configure() { super.configure(); @@ -84,7 +107,12 @@ public class AzureComputeServiceContextModule install(new LocationsFromComputeServiceAdapterModule() { }); + bind(TemplateOptions.class).to(AzureTemplateOptions.class); + bind(PopulateDefaultLoginCredentialsForImageStrategy.class).to(AzurePopulateDefaultLoginCredentialsForImageStrategy.class); + //bind(TemplateOptionsToStatement.class).to(TemplateOptionsToStatementWithoutPublicKey.class); bind(CreateNodesInGroupThenAddToSet.class).to(CreateResourceGroupThenCreateNodes.class); + bind(new TypeLiteral() { + }).to(AzureComputeImageExtension.class); } @Singleton @@ -122,6 +150,18 @@ public class AzureComputeServiceContextModule @Inject private String azureDefaultImageLoginProperty; + @Named(DEFAULT_VNET_ADDRESS_SPACE_PREFIX) + @Inject + private String azureDefaultVnetAddressPrefixProperty; + + @Named(DEFAULT_SUBNET_ADDRESS_PREFIX) + @Inject + private String azureDefaultSubnetAddressPrefixProperty; + + @Named(DEFAULT_DATADISKSIZE) + @Inject + private String azureDefaultDataDiskSizeProperty; + public Long operationTimeout() { return Long.parseLong(operationTimeoutProperty); } @@ -138,6 +178,18 @@ public class AzureComputeServiceContextModule return azureDefaultImageLoginProperty; } + public String azureDefaultVnetAddressPrefixProperty() { + return azureDefaultVnetAddressPrefixProperty; + } + + public String azureDefaultSubnetAddressPrefixProperty() { + return azureDefaultSubnetAddressPrefixProperty; + } + + public String azureDefaultDataDiskSizeProperty() { + return azureDefaultDataDiskSizeProperty; + } + public Integer operationPollInitialPeriod() { return Integer.parseInt(operationPollInitialPeriodProperty); } @@ -158,19 +210,39 @@ public class AzureComputeServiceContextModule @Provides @Named(TIMEOUT_NODE_TERMINATED) protected Predicate provideNodeTerminatedPredicate(final AzureComputeApi api, Timeouts timeouts, - PollPeriod pollPeriod) { + PollPeriod pollPeriod) { return retry(new ActionDonePredicate(api), timeouts.nodeTerminated, pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); } + @Provides + @Named(TIMEOUT_IMAGE_AVAILABLE) + protected Predicate provideImageAvailablePredicate(final AzureComputeApi api, Timeouts timeouts, + PollPeriod pollPeriod) { + return retry(new ImageDonePredicate(api), timeouts.imageAvailable, pollPeriod.pollInitialPeriod, + pollPeriod.pollMaxPeriod); + } + @Provides @Named(TIMEOUT_RESOURCE_DELETED) protected Predicate provideResourceDeletedPredicate(final AzureComputeApi api, Timeouts timeouts, - PollPeriod pollPeriod) { + PollPeriod pollPeriod) { return retry(new ActionDonePredicate(api), timeouts.nodeTerminated, pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); } + @Provides + @Named(TIMEOUT_NODE_SUSPENDED) + 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); + } + @VisibleForTesting static class ActionDonePredicate implements Predicate { @@ -183,9 +255,51 @@ public class AzureComputeServiceContextModule @Override public boolean apply(URI uri) { checkNotNull(uri, "uri cannot be null"); - return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri); + return (ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri)) || (ParseJobStatus.JobStatus.NO_CONTENT == api.getJobApi().jobStatus(uri)); } } + @VisibleForTesting + static class ImageDonePredicate implements Predicate { + + private final AzureComputeApi api; + + public ImageDonePredicate(AzureComputeApi api) { + this.api = checkNotNull(api, "api must not be null"); + } + + @Override + public boolean apply(URI uri) { + checkNotNull(uri, "uri cannot be null"); + List definitions = api.getJobApi().captureStatus(uri); + return definitions != null; + } + } + + @VisibleForTesting + static class NodeSuspendedPredicate implements Predicate { + + private final AzureComputeApi api; + private final String azureGroup; + + public NodeSuspendedPredicate(AzureComputeApi api, String azureGroup) { + this.api = checkNotNull(api, "api must not be null"); + this.azureGroup = checkNotNull(azureGroup, "azuregroup must not be null"); + } + + @Override + public boolean apply(String name) { + checkNotNull(name, "name cannot be null"); + String status = ""; + List statuses = api.getVirtualMachineApi(this.azureGroup).getInstanceDetails(name).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"); + } + } } 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 new file mode 100644 index 0000000000..626f51152f --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtension.java @@ -0,0 +1,142 @@ +/* + * 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.extensions; + +import com.google.common.base.Predicate; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.gson.internal.LinkedTreeMap; +import com.google.inject.Inject; +import com.google.inject.name.Named; +import org.jclouds.Constants; +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.domain.ResourceDefinition; +import org.jclouds.azurecompute.arm.domain.VMImage; +import org.jclouds.azurecompute.arm.domain.VirtualMachine; +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 static java.lang.String.format; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_IMAGE_AVAILABLE; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; + +import com.google.common.util.concurrent.UncheckedTimeoutException; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; + + +public class AzureComputeImageExtension implements ImageExtension { + private final AzureComputeApi api; + private final Predicate imageAvailablePredicate; + private final Predicate nodeSuspendedPredicate; + private final AzureComputeConstants azureComputeConstants; + private final ListeningExecutorService userExecutor; + private final String group; + private final VMImageToImage imageReferenceToImage; + public static final String CONTAINER_NAME = "vhdsnew"; + public static final String CUSTOM_IMAGE_PREFIX = "#"; + + @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; + this.api = api; + this.imageAvailablePredicate = imageAvailablePredicate; + this.nodeSuspendedPredicate = nodeSuspendedPredicate; + this.azureComputeConstants = azureComputeConstants; + } + + @Override + public ImageTemplate buildImageTemplateFromNode(String name, String id) { + String imageName = name.toLowerCase(); + return new ImageTemplateBuilder.CloneImageTemplateBuilder().nodeId(id).name(imageName).build(); + } + + @Override + public ListenableFuture createImage(ImageTemplate template) { + final CloneImageTemplate cloneTemplate = (CloneImageTemplate) template; + final String id = cloneTemplate.getSourceNodeId(); + final String storageAccountName = id.replaceAll("[^A-Za-z0-9 ]", "") + "stor"; + + // VM needs to be stopped before it can be generalized + String status = ""; + api.getVirtualMachineApi(group).stop(id); + //Poll until resource is ready to be used + if (nodeSuspendedPredicate.apply(id)) { + return userExecutor.submit(new Callable() { + @Override + public Image call() throws Exception { + api.getVirtualMachineApi(group).generalize(id); + + final String[] disks = new String[2]; + URI uri = api.getVirtualMachineApi(group).capture(id, cloneTemplate.getName(), CONTAINER_NAME); + if (uri != null) { + if (imageAvailablePredicate.apply(uri)) { + List 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); + + disks[0] = osProperties.get("name"); + disks[1] = datadiskObject.get("name"); + + VirtualMachine vm = api.getVirtualMachineApi(group).get(id); + String location = vm.location(); + final VMImage ref = VMImage.create(CUSTOM_IMAGE_PREFIX + group, CUSTOM_IMAGE_PREFIX + storageAccountName, disks[0], disks[1], location, false); + 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); + } + } + + @Override + public boolean deleteImage(String id) { + return false; + } +} 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 index bccc63cb53..40e09b724b 100644 --- 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 @@ -48,6 +48,7 @@ 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(); @@ -116,6 +117,10 @@ public class DeploymentToNodeMetadata implements Function 0) builder.publicAddresses(publicIpAddresses); @@ -171,13 +191,12 @@ public class DeploymentToNodeMetadata implements Function { @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)) + .name(from.name()) + .providerId(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) { + if (from.resourceDiskSizeInMB() != null) { builder.volume(new VolumeBuilder() - .size(Float.valueOf(from.resourceDiskSizeInMB)) + .size(Float.valueOf(from.resourceDiskSizeInMB())) .type(Volume.Type.LOCAL) .build()); } - if (from.osDiskSizeInMB != null) { + if (from.osDiskSizeInMB() != null) { builder.volume(new VolumeBuilder() - .size(Float.valueOf(from.osDiskSizeInMB)) + .size(Float.valueOf(from.osDiskSizeInMB())) .type(Volume.Type.LOCAL) .build()); } ImmutableMap.Builder metadata = ImmutableMap.builder(); - metadata.put("maxDataDiskCount", String.valueOf(from.maxDataDiskCount)); + metadata.put("maxDataDiskCount", String.valueOf(from.maxDataDiskCount())); builder.userMetadata(metadata.build()); return 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 65a3d4b14a..75bcc0e033 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 @@ -17,6 +17,8 @@ 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 com.google.common.base.Supplier; import com.google.common.collect.FluentIterable; @@ -29,7 +31,9 @@ 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; @@ -59,7 +63,7 @@ public class VMImageToImage implements Function { private final Supplier> locations; public static String encodeFieldsToUniqueId(VMImage imageReference){ - return (imageReference.globallyAvailable ? "global" : imageReference.location) + "/" + imageReference.publisher + "/" + imageReference.offer + "/" + imageReference.sku; + return (imageReference.globallyAvailable() ? "global" : imageReference.location()) + "/" + imageReference.publisher() + "/" + imageReference.offer() + "/" + imageReference.sku(); } public static String[] decodeFieldsFromUniqueId(final String id) { @@ -74,18 +78,19 @@ public class VMImageToImage implements Function { @Override public Image apply(final VMImage image) { + Credentials credentials = new Credentials(AZURE_LOGIN_USERNAME, AZURE_LOGIN_PASSWORD); final ImageBuilder builder = new ImageBuilder() - .name(image.offer) - .description(image.sku) + .name(image.offer()) + .description(image.sku()) .status(Image.Status.AVAILABLE) - .version(image.sku) + .version(image.sku()) .id(encodeFieldsToUniqueId(image)) - .providerId(image.publisher) - .location(image.globallyAvailable ? null : FluentIterable.from(locations.get()) - .firstMatch(LocationPredicates.idEquals(image.location)) + .defaultCredentials(LoginCredentials.fromCredentials(credentials)) + .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(); } @@ -94,8 +99,8 @@ public class VMImageToImage implements Function { return new Function() { @Override public OperatingSystem.Builder apply(final VMImage image) { - checkNotNull(image.offer, "offer"); - final String label = image.offer; + checkNotNull(image.offer(), "offer"); + final String label = image.offer(); OsFamily family = OsFamily.UNRECOGNIZED; if (label.contains(CENTOS)) { @@ -116,8 +121,8 @@ public class VMImageToImage implements Function { return OperatingSystem.builder(). family(family). is64Bit(true). - description(image.sku). - version(image.sku); + description(image.sku()). + version(image.sku()); } }; } 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 new file mode 100644 index 0000000000..c5267b1dbe --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/AzureTemplateOptions.java @@ -0,0 +1,223 @@ +/* + * 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.options; + +import static com.google.common.base.Objects.equal; +import org.jclouds.compute.options.TemplateOptions; +import com.google.common.base.Objects; + +/** + * Azure ARM custom options + */ +public class AzureTemplateOptions extends TemplateOptions implements Cloneable { + + + private String customData; + private String virtualNetworkAddressPrefix; + private String subnetAddressPrefix; + private String DNSLabelPrefix; + private String keyVaultIdAndSecret; + + + /** + * Custom options for the Azure ARM API + */ + public AzureTemplateOptions customData(String customData) { + this.customData = customData; + return this; + } + private String virtualNetworkName; + private String subnetId; + + /** + * Sets the CIDR block for virtual network + */ + public AzureTemplateOptions virtualNetworkAddressPrefix(String virtualNetworkAddressPrefix) { + this.virtualNetworkAddressPrefix = virtualNetworkAddressPrefix; + return this; + } + + /** + * Sets the CIDR block for subnet within virtual network + */ + public AzureTemplateOptions subnetAddressPrefix(String subnetAddressPrefix) { + this.subnetAddressPrefix = subnetAddressPrefix; + return this; + } + + /** + * Sets the DNS label prefix for public IP address. label.location.cloudapp.azure.com + */ + public AzureTemplateOptions DNSLabelPrefix(String DNSLabelPrefix) { + this.DNSLabelPrefix = DNSLabelPrefix; + return this; + } + + /** + * Sets the KeyVault id and secret separated with ":" + */ + public AzureTemplateOptions keyVaultIdAndSecret(String keyVaultIdAndSecret) { + this.keyVaultIdAndSecret = keyVaultIdAndSecret; + 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 + */ + public AzureTemplateOptions virtualNetworkName(String virtualNetworkName) { + this.virtualNetworkName = virtualNetworkName; + return this; + } + + /** + * Sets the subnet name + */ + public AzureTemplateOptions subnetId(String subnetId) { + this.subnetId = subnetId; + return this; + } + + @Override + public AzureTemplateOptions clone() { + AzureTemplateOptions options = new AzureTemplateOptions(); + copyTo(options); + return options; + } + + @Override + public void copyTo(TemplateOptions to) { + super.copyTo(to); + if (to instanceof AzureTemplateOptions) { + AzureTemplateOptions eTo = AzureTemplateOptions.class.cast(to); + eTo.customData(customData); + eTo.virtualNetworkAddressPrefix(virtualNetworkAddressPrefix); + eTo.subnetAddressPrefix(subnetAddressPrefix); + eTo.DNSLabelPrefix(DNSLabelPrefix); + eTo.keyVaultIdAndSecret(keyVaultIdAndSecret); + eTo.virtualNetworkName(virtualNetworkName); + eTo.subnetId(subnetId); + } + } + + @Override + public int hashCode() { + return Objects.hashCode(super.hashCode(), virtualNetworkAddressPrefix, subnetAddressPrefix, DNSLabelPrefix, customData, keyVaultIdAndSecret, virtualNetworkName, subnetId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + AzureTemplateOptions other = (AzureTemplateOptions) obj; + return super.equals(other) + && equal(this.customData, other.customData) + && equal(this.virtualNetworkAddressPrefix, other.virtualNetworkAddressPrefix) + && equal(this.subnetAddressPrefix, other.subnetAddressPrefix) + && equal(this.DNSLabelPrefix, other.DNSLabelPrefix) + && equal(this.keyVaultIdAndSecret, other.keyVaultIdAndSecret) + && equal(this.virtualNetworkName, other.virtualNetworkName) + && equal(this.subnetId, other.subnetId); + } + + @Override + public Objects.ToStringHelper string() { + Objects.ToStringHelper toString = super.string().omitNullValues(); + toString.add("customData", customData); + toString.add("virtualNetworkAddressPrefix", virtualNetworkAddressPrefix); + toString.add("subnetAddressPrefix", subnetAddressPrefix); + toString.add("DNSLabelPrefix", DNSLabelPrefix); + toString.add("keyVaultIdAndSecret", keyVaultIdAndSecret); + toString.add("virtualNetworkName", virtualNetworkName); + toString.add("subnetId", subnetId); + return toString; + } + + public static class Builder { + + /** + * @see AzureTemplateOptions#customData + */ + public static AzureTemplateOptions customData(String customData) { + AzureTemplateOptions options = new AzureTemplateOptions(); + return options.customData(customData); + } + + /** + * @see AzureTemplateOptions#virtualNetworkAddressPrefix + */ + public static AzureTemplateOptions virtualNetworkAddressPrefix(String virtualNetworkAddressPrefix) { + AzureTemplateOptions options = new AzureTemplateOptions(); + return options.virtualNetworkAddressPrefix(virtualNetworkAddressPrefix); + } + + /** + * @see AzureTemplateOptions#subnetAddressPrefix + */ + public static AzureTemplateOptions subnetAddressPrefix(String subnetAddressPrefix) { + AzureTemplateOptions options = new AzureTemplateOptions(); + return options.subnetAddressPrefix(subnetAddressPrefix); + } + + /** + * @see AzureTemplateOptions#DNSLabelPrefix + */ + public static AzureTemplateOptions DNSLabelPrefix(String DNSLabelPrefix) { + AzureTemplateOptions options = new AzureTemplateOptions(); + return options.DNSLabelPrefix(DNSLabelPrefix); + } + + /** + * @see AzureTemplateOptions#keyVaultIdAndSecret + */ + public static AzureTemplateOptions keyVaultIdAndSecret(String keyVaultIdAndSecret) { + AzureTemplateOptions options = new AzureTemplateOptions(); + return options.keyVaultIdAndSecret(keyVaultIdAndSecret); + } + + /** + * @see AzureTemplateOptions#virtualNetworkName + */ + public static AzureTemplateOptions virtualNetworkName(String virtualNetworkName) { + AzureTemplateOptions options = new AzureTemplateOptions(); + return options.virtualNetworkName(virtualNetworkName); + } + + /** + * @see AzureTemplateOptions#subnetId + */ + public static AzureTemplateOptions subnetId(String subnetId) { + AzureTemplateOptions options = new AzureTemplateOptions(); + return options.subnetId(subnetId); + } + } +} 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 new file mode 100644 index 0000000000..55d1a3ce37 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/AzurePopulateDefaultLoginCredentialsForImageStrategy.java @@ -0,0 +1,43 @@ +/* + * 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 6900f1799d..468b87c6f2 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 @@ -18,6 +18,7 @@ package org.jclouds.azurecompute.arm.compute.strategy; import static com.google.common.base.Preconditions.checkNotNull; +import java.util.Arrays; import java.util.Map; import java.util.Set; @@ -28,8 +29,13 @@ import javax.inject.Singleton; import com.google.common.collect.ImmutableMap; import org.jclouds.Constants; +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.Subnet; import org.jclouds.azurecompute.arm.features.ResourceGroupApi; +import org.jclouds.azurecompute.arm.features.SubnetApi; +import org.jclouds.azurecompute.arm.features.VirtualNetworkApi; import org.jclouds.compute.config.CustomizationResponse; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.Template; @@ -40,7 +46,7 @@ import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIn 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.collect.Multimap; import com.google.common.util.concurrent.ListenableFuture; @@ -54,6 +60,7 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco protected Logger logger = Logger.NULL; private final AzureComputeApi api; + private final AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants; @Inject protected CreateResourceGroupThenCreateNodes( @@ -62,11 +69,12 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco GroupNamingConvention.Factory namingConvention, @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory, - AzureComputeApi api) { + AzureComputeApi api, AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants) { super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor, customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory); this.api = checkNotNull(api, "api cannot be null"); checkNotNull(userExecutor, "userExecutor cannot be null"); + this.azureComputeConstants = azureComputeConstants; } @Override @@ -74,23 +82,59 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco Set goodNodes, Map badNodes, Multimap customizationResponses) { + String azureGroupName = this.azureComputeConstants.azureResourceGroup(); + + AzureTemplateOptions options = template.getOptions().as(AzureTemplateOptions.class); + // create resource group for jclouds group if it does not already exist ResourceGroupApi resourceGroupApi = api.getResourceGroupApi(); - ResourceGroup resourceGroup = resourceGroupApi.get(group); + ResourceGroup resourceGroup = resourceGroupApi.get(azureGroupName); final String location = template.getLocation().getId(); - final String resourceGroupName; if (resourceGroup == null){ - final Map tags = ImmutableMap.of("description", "jClouds managed VMs"); - resourceGroupName = resourceGroupApi.create(group, location, tags).name(); - } else { - resourceGroupName = resourceGroup.name(); + resourceGroupApi.create(azureGroupName, location, tags).name(); } - Map> responses = super.execute(resourceGroupName, count, template, goodNodes, badNodes, + String vnetName = azureGroupName + "virtualnetwork"; + String subnetName = azureGroupName + "subnet"; + + if (options.getVirtualNetworkName() != null) { + vnetName = options.getVirtualNetworkName(); + } + + this.getOrCreateVirtualNetworkWithSubnet(vnetName, subnetName, location, options, azureGroupName); + + + Map> responses = super.execute(group, count, template, goodNodes, badNodes, customizationResponses); return responses; } + protected synchronized void getOrCreateVirtualNetworkWithSubnet( + final String virtualNetworkName, final String subnetName, final String location, + AzureTemplateOptions options, final String azureGroupName) { + + //Subnets belong to a virtual network so that needs to be created first + VirtualNetworkApi vnApi = api.getVirtualNetworkApi(azureGroupName); + VirtualNetwork vn = vnApi.get(virtualNetworkName); + + if (vn == null) { + VirtualNetwork.VirtualNetworkProperties virtualNetworkProperties = VirtualNetwork.VirtualNetworkProperties.builder() + .addressSpace(VirtualNetwork.AddressSpace.create(Arrays.asList(this.azureComputeConstants.azureDefaultVnetAddressPrefixProperty()))) + .subnets( + Arrays.asList( + Subnet.create(subnetName, null, null, + Subnet.SubnetProperties.builder().addressPrefix(this.azureComputeConstants.azureDefaultSubnetAddressPrefixProperty()).build()))) + .build(); + vn = vnApi.createOrUpdate(virtualNetworkName, location, virtualNetworkProperties); + } + + SubnetApi subnetApi = api.getSubnetApi(azureGroupName, virtualNetworkName); + Subnet subnet = subnetApi.get(subnetName); + + options.virtualNetworkName(virtualNetworkName); + options.subnetId(subnet.id()); + + } } 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 48d6287740..e5ef5cd561 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 @@ -41,4 +41,10 @@ public class AzureComputeProperties { public static final String TIMEOUT_RESOURCE_DELETED = "jclouds.azurecompute.arm.timeout.resourcedeleted"; + public static final String DEFAULT_VNET_ADDRESS_SPACE_PREFIX = "jclouds.azurecompute.arm.vnet.addressprefix"; + + public static final String DEFAULT_SUBNET_ADDRESS_PREFIX = "jclouds.azurecompute.arm.subnet.addressprefix"; + + public static final String DEFAULT_DATADISKSIZE = "jclouds.azurecompute.arm.datadisksize"; + } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DeploymentTemplate.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DeploymentTemplate.java index 848000ddae..5221e053d8 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DeploymentTemplate.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DeploymentTemplate.java @@ -31,8 +31,25 @@ public abstract class DeploymentTemplate { //Empty placeholders as we want to generate the empty JSON object @AutoValue public abstract static class Parameters { - public static Parameters create() { - return new AutoValue_DeploymentTemplate_Parameters(); + + @Nullable + public abstract KeyVaultReference publicKeyFromAzureKeyVault(); + + public static Parameters create(KeyVaultReference reference) + { + return new AutoValue_DeploymentTemplate_Parameters(reference); + } + } + + @AutoValue + public abstract static class TemplateParameters { + + @Nullable + public abstract TemplateParameterType publicKeyFromAzureKeyVault(); + + public static TemplateParameters create(TemplateParameterType publicKeyFromAzureKeyVault) + { + return new AutoValue_DeploymentTemplate_TemplateParameters(publicKeyFromAzureKeyVault); } } @@ -40,7 +57,7 @@ public abstract class DeploymentTemplate { public abstract String contentVersion(); - public abstract Parameters parameters(); + public abstract TemplateParameters parameters(); public abstract Map variables(); @@ -52,7 +69,7 @@ public abstract class DeploymentTemplate { @SerializedNames({"$schema", "contentVersion", "parameters", "variables", "resources" , "outputs"}) public static DeploymentTemplate create(final String schema, final String contentVersion, - final Parameters parameters, + final TemplateParameters parameters, final Map variables, final List resources, final List outputs) { @@ -83,7 +100,7 @@ public abstract class DeploymentTemplate { public abstract Builder contentVersion(String type); - public abstract Builder parameters(Parameters parameters); + public abstract Builder parameters(TemplateParameters parameters); public abstract Builder variables(Map variables); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/KeyVaultReference.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/KeyVaultReference.java new file mode 100644 index 0000000000..2eb2f87e97 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/KeyVaultReference.java @@ -0,0 +1,46 @@ +/* + * 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 org.jclouds.json.SerializedNames; + +// Simple helper class to serialize / deserialize keyvault reference. + +@AutoValue +public abstract class KeyVaultReference { + + @AutoValue + public abstract static class Reference { + + public abstract IdReference keyVault(); + + public abstract String secretName(); + + @SerializedNames({"keyVault", "secretName"}) + public static Reference create(final IdReference keyVault, final String secretName) { + return new AutoValue_KeyVaultReference_Reference(keyVault, secretName); + } + } + + public abstract Reference reference(); + + @SerializedNames({"reference"}) + public static KeyVaultReference create(final Reference reference) { + return new AutoValue_KeyVaultReference(reference); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCardProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCardProperties.java index e6f2de7dac..8b19493dd0 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCardProperties.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCardProperties.java @@ -38,13 +38,17 @@ public abstract class NetworkInterfaceCardProperties { @Nullable public abstract List ipConfigurations(); - @SerializedNames({"provisioningState", "resourceGuid", "enableIPForwarding", "ipConfigurations"}) - public static NetworkInterfaceCardProperties create(final String provisioningState, final String resourceGuid, final Boolean enableIPForwarding, final List ipConfigurations) { + @Nullable + public abstract IdReference networkSecurityGroup(); + + @SerializedNames({"provisioningState", "resourceGuid", "enableIPForwarding", "ipConfigurations", "networkSecurityGroup"}) + public static NetworkInterfaceCardProperties create(final String provisioningState, final String resourceGuid, final Boolean enableIPForwarding, final List ipConfigurations, final IdReference networkSecurityGroup) { NetworkInterfaceCardProperties.Builder builder = NetworkInterfaceCardProperties.builder() .provisioningState(provisioningState) .resourceGuid(resourceGuid) .enableIPForwarding(enableIPForwarding) - .ipConfigurations(ipConfigurations == null ? null : ImmutableList.copyOf(ipConfigurations)); + .ipConfigurations(ipConfigurations == null ? null : ImmutableList.copyOf(ipConfigurations)) + .networkSecurityGroup(networkSecurityGroup); return builder.build(); } @@ -66,6 +70,8 @@ public abstract class NetworkInterfaceCardProperties { abstract List ipConfigurations(); + public abstract Builder networkSecurityGroup(IdReference networkSecurityGroup); + abstract NetworkInterfaceCardProperties autoBuild(); public NetworkInterfaceCardProperties build() { diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java index a9f7349ce5..0be43bfc40 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java @@ -52,16 +52,23 @@ public abstract class OSDisk { @Nullable public abstract String createOption(); - @SerializedNames({"osType", "name", "vhd", "caching", "createOption"}) + /** + * The url of the custom image + */ + @Nullable + public abstract VHD image(); + + @SerializedNames({"osType", "name", "vhd", "caching", "createOption", "image"}) public static OSDisk create(final String osType, final String name, final VHD vhd, - final String caching, final String createOption) { + final String caching, final String createOption, final VHD image) { return builder() - .osType(osType) - .name(name) - .vhd(vhd) - .caching(caching) - .createOption(createOption) - .build(); + .osType(osType) + .name(name) + .vhd(vhd) + .caching(caching) + .createOption(createOption) + .image(image) + .build(); } public static Builder builder() { @@ -71,15 +78,11 @@ public abstract class OSDisk { @AutoValue.Builder public abstract static class Builder { public abstract Builder osType(String osType); - public abstract Builder name(String name); - public abstract Builder caching(String caching); - public abstract Builder createOption(String createOption); - public abstract Builder vhd(VHD vhd); - + public abstract Builder image(VHD image); public abstract OSDisk build(); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageProfile.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageProfile.java index 7c693ef2e0..bcb62ee217 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageProfile.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageProfile.java @@ -29,6 +29,7 @@ public abstract class StorageProfile { /** * The image reference of the storage profile */ + @Nullable public abstract ImageReference imageReference(); /** diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/TemplateParameterType.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/TemplateParameterType.java new file mode 100644 index 0000000000..d0ccc71681 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/TemplateParameterType.java @@ -0,0 +1,34 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +// Simple helper class to serialize / deserialize id reference. + +@AutoValue +public abstract class TemplateParameterType { + @Nullable + public abstract String type(); + + @SerializedNames({"type"}) + public static TemplateParameterType create(final String type) { + return new AutoValue_TemplateParameterType(type); + } +} 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 6909a7b49b..c663944020 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 @@ -18,6 +18,7 @@ package org.jclouds.azurecompute.arm.domain; import java.util.List; +import java.util.Map; public class VMDeployment { @@ -28,4 +29,8 @@ public class VMDeployment { public VirtualMachineInstance vm; public VirtualMachine virtualMachine; + + public Map userMetaData; + + public Iterable tags; } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMHardware.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMHardware.java index d338327dca..f0aa77e943 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMHardware.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMHardware.java @@ -17,6 +17,7 @@ package org.jclouds.azurecompute.arm.domain; import com.google.auto.value.AutoValue; +import org.jclouds.json.SerializedNames; /** * A VM Size that is available in a region for a given subscription. @@ -24,45 +25,51 @@ import com.google.auto.value.AutoValue; * @see api */ @AutoValue -public class VMHardware { +public abstract class VMHardware { /** * The name of the VM size. */ - public String name; + public abstract String name(); /** * The number of cores that are available in the VM size. */ - public Integer numberOfCores; + public abstract Integer numberOfCores(); /** * Specifies the size in MB of the OS Disk. */ - public Integer osDiskSizeInMB; + public abstract Integer osDiskSizeInMB(); /** * The size of the resource disk. */ - public Integer resourceDiskSizeInMB; + public abstract Integer resourceDiskSizeInMB(); /** * Specifies the available RAM in MB. */ - public Integer memoryInMB; + public abstract Integer memoryInMB(); /** * Specifies the maximum number of data disks that can be attached to the VM size. */ - public Integer maxDataDiskCount; + public abstract Integer maxDataDiskCount(); /** * Specifies the location of the HW resource */ - public String location; + public abstract String location(); /** * Specifies if this HW is globally available */ - public boolean globallyAvailable; + public abstract boolean globallyAvailable(); + + @SerializedNames({ "name", "numberOfCores", "osDiskSizeInMB", "resourceDiskSizeInMB", "memoryInMB", "maxDataDiskCount", "location", "globallyAvailable"}) + public static VMHardware create(String name, Integer numberOfCores, Integer osDiskSizeInMB, Integer resourceDiskSizeInMB, Integer memoryInMB, Integer maxDataDiskCount, String location, boolean globallyAvailable) { + + return new AutoValue_VMHardware(name, numberOfCores, osDiskSizeInMB, resourceDiskSizeInMB, memoryInMB, maxDataDiskCount, location, globallyAvailable); + } } 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 ccfb05aef9..2d4fc919d6 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 @@ -17,37 +17,44 @@ package org.jclouds.azurecompute.arm.domain; import com.google.auto.value.AutoValue; +import org.jclouds.json.SerializedNames; @AutoValue -public class VMImage { +public abstract class VMImage { /** * The publisher of the image reference. */ - public String publisher; + public abstract String publisher(); /** * The offer of the image reference. */ - public String offer; + public abstract String offer(); /** * The sku of the image reference. */ - public String sku; + public abstract String sku(); /** * The version of the image reference. */ - public String version; + public abstract String version(); /** * The location from where Image was fetched */ - public String location; + public abstract String location(); /** * Specifies if this image is globally available */ - public boolean globallyAvailable; + public abstract boolean globallyAvailable(); + + @SerializedNames({ "publisher", "offer", "sku", "version", "location", "globallyAvailable"}) + public static VMImage create(String publisher, String offer, String sku, String version, String location, boolean globallyAvailable) { + + return new AutoValue_VMImage(publisher, offer, sku, version, location, globallyAvailable); + } } 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 7dd75a9620..f2858d9ca4 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 @@ -17,15 +17,21 @@ 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 org.jclouds.Fallbacks; +import org.jclouds.azurecompute.arm.domain.ResourceDefinition; 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; /** * The Azure Resource Manager API checks for job status and progress. @@ -37,5 +43,14 @@ public interface JobApi extends Closeable{ @GET @ResponseParser(ParseJobStatus.class) JobStatus jobStatus(@EndpointParam URI jobURI); + + /** + * Get status of captured custom image after capture call + */ + @GET + @Fallback(Fallbacks.EmptyListOnNotFoundOr404.class) + @SelectJson("resources") + List captureStatus(@EndpointParam URI jobURI); + } 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 468906485e..14f3c70332 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 @@ -131,5 +131,30 @@ public interface VirtualMachineApi { @Path("/{name}/powerOff") void stop(@PathParam("name") String name); + /** + * Generalize the virtual machine + */ + @Named("generalize") + @POST + @Path("/{name}/generalize") + void generalize(@PathParam("name") String name); + + /** + * Capture the virtual machine image + * destinationContainerName: the name of the folder created under the "system" container in the storage account + * Folder structure: Microsoft.Computer > Images > destinationContainerName + * Within the folder, there will be 1 page blob for the osDisk vhd and 1 block blob for the vmTemplate json file + */ + @Named("capture") + @POST + @Payload("%7B\"vhdPrefix\":\"{vhdPrefix}\",\"destinationContainerName\":\"{destinationContainerName}\",\"overwriteVhds\":\"true\"%7D") + @MapBinder(BindToJsonPayload.class) + @Path("/{name}/capture") + @ResponseParser(URIParser.class) + @Fallback(Fallbacks.NullOnNotFoundOr404.class) + URI capture(@PathParam("name") String name, + @PayloadParam("vhdPrefix") String vhdPrefix, + @PayloadParam("destinationContainerName") String destinationContainerName); + } 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 2b6a18ee3d..1646aec02f 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 @@ -26,8 +26,15 @@ 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.NetworkInterfaceCard; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; +import org.jclouds.azurecompute.arm.domain.PublicIPAddress; +import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.logging.Logger; +import org.jclouds.azurecompute.arm.domain.StorageService; import com.google.common.base.Function; @@ -36,6 +43,7 @@ import java.net.URI; @Singleton public class CleanupResources implements Function { + private final AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants; @Resource @Named(ComputeServiceConstants.COMPUTE_LOGGER) protected Logger logger = Logger.NULL; @@ -46,9 +54,10 @@ public class CleanupResources implements Function { @Inject public CleanupResources(AzureComputeApi azureComputeApi, + AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants, @Named(TIMEOUT_NODE_TERMINATED) Predicate nodeTerminated, @Named(TIMEOUT_RESOURCE_DELETED) Predicate resourceDeleted) { - + this.azureComputeConstants = azureComputeConstants; this.api = azureComputeApi; this.nodeTerminated = nodeTerminated; this.resourceDeleted = resourceDeleted; @@ -58,36 +67,67 @@ public class CleanupResources implements Function { 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); + String storageAccountName = id.replaceAll("[^A-Za-z0-9 ]", "") + "stor"; + String group = azureComputeConstants.azureResourceGroup(); - // Delete VM - URI uri = api.getVirtualMachineApi(group).delete(id); - if (uri != null){ - boolean jobDone = nodeTerminated.apply(uri); + 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; - 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 + if (jobDone) { + StorageService ss = api.getStorageAccountApi(group).get(storageAccountName); + if (ss != null) { + storageAcctDeleteStatus = api.getStorageAccountApi(group).delete(storageAccountName); + } else { + storageAcctDeleteStatus = true; + } + Deployment deployment = api.getDeploymentApi(group).get(id); + if (deployment != null) { uri = api.getDeploymentApi(group).delete(id); jobDone = resourceDeleted.apply(uri); if (jobDone) { - // Delete public ip - boolean ipDeleteStatus = api.getPublicIPAddressApi(group).delete(id + "publicip"); + 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; + } - // Delete Virtual network - boolean vnetDeleteStatus = api.getVirtualNetworkApi(group).delete(group + "virtualnetwork"); - return ipDeleteStatus && vnetDeleteStatus; + // 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; + } + } + else { + nsgDeleteStatus = true; + } + + return deploymentDeleteStatus && storageAcctDeleteStatus && ipDeleteStatus && nsgDeleteStatus; + } else { + return false; + } } else { return false; } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/StatusCodeParser.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/StatusCodeParser.java new file mode 100644 index 0000000000..4c14ec2983 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/StatusCodeParser.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 com.google.common.base.Function; +import org.jclouds.http.HttpResponse; + +import javax.inject.Singleton; + +import static org.jclouds.http.HttpUtils.releasePayload; + +/** + * Parses an http response code from http responser + */ +@Singleton +public class StatusCodeParser implements Function { + public String apply(final HttpResponse from) { + releasePayload(from); + final String statusCode = Integer.toString(from.getStatusCode()); + if (statusCode != null) { + return statusCode; + } + throw new IllegalStateException("did not receive RequestId in: " + from); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/handlers/AzureComputeErrorHandler.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/handlers/AzureComputeErrorHandler.java index d5a2d6917a..6532173525 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/handlers/AzureComputeErrorHandler.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/handlers/AzureComputeErrorHandler.java @@ -48,7 +48,12 @@ public class AzureComputeErrorHandler implements HttpErrorHandler { : message; switch (response.getStatusCode()) { case 400: - exception = new IllegalArgumentException(message, exception); + if (message.contains("unauthorized_client")) { + exception = new AuthorizationException(message, exception); + } + else { + exception = new IllegalArgumentException(message, exception); + } break; case 401: case 403: 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 index ed5ec9eb96..f7850d4636 100644 --- 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 @@ -16,37 +16,42 @@ */ package org.jclouds.azurecompute.arm.util; -import com.google.common.collect.ImmutableMap; +import com.google.common.base.Strings; +import com.google.common.collect.Lists; import com.google.inject.assistedinject.Assisted; +import com.google.common.base.Joiner; +import com.google.common.base.Preconditions; import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule; -import org.jclouds.azurecompute.arm.domain.DeploymentProperties; -import org.jclouds.compute.options.TemplateOptions; +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.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.Subnet; -import org.jclouds.azurecompute.arm.domain.Subnet.SubnetProperties; +import org.jclouds.azurecompute.arm.domain.TemplateParameterType; import org.jclouds.azurecompute.arm.domain.VHD; import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties; -import org.jclouds.azurecompute.arm.domain.VirtualNetwork.VirtualNetworkProperties; -import org.jclouds.azurecompute.arm.domain.VirtualNetwork.AddressSpace; +import org.jclouds.azurecompute.arm.domain.StorageService.StorageServiceProperties; +import org.jclouds.azurecompute.arm.domain.IdReference; +import org.jclouds.azurecompute.arm.domain.ResourceDefinition; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroupProperties; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityRule; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties; import org.jclouds.compute.domain.Template; import org.jclouds.json.Json; @@ -56,8 +61,10 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import static com.google.common.io.BaseEncoding.base64; import com.google.inject.Inject; +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 { @@ -66,11 +73,14 @@ public class DeploymentTemplateBuilder { } private final String name; + private final String azureGroup; private final String group; private final Template template; private final Json json; - private TemplateOptions options; + private AzureTemplateOptions options; + private Iterable tags; + private Map userMetaData; private List resources; private Map variables; private static String loginUser; @@ -79,10 +89,6 @@ public class DeploymentTemplateBuilder { private AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants; private static final String DEPLOYMENT_MODE = "Incremental"; - private static final String DEFAULT_DATA_DISK_SIZE = "1023"; - - private static final String DEFAULT_vnAddresSpacePrefix = "10.0.0.0/16"; - private static final String DEFAULT_subnetAddressPrefix = "10.0.0.0/24"; @Inject DeploymentTemplateBuilder(Json json, @Assisted("group") String group, @Assisted("name") String name, @Assisted Template template, @@ -90,13 +96,16 @@ public class DeploymentTemplateBuilder { this.name = name; this.group = group; this.template = template; - this.options = template.getOptions().as(TemplateOptions.class); + 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; @@ -126,30 +135,53 @@ public class DeploymentTemplateBuilder { public DeploymentBody getDeploymentTemplate() { addStorageResource(); - addVirtualNetworkResource(); 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(DeploymentTemplate.Parameters.create()) + .parameters(templateParameters) .build(); - DeploymentBody body = DeploymentBody.create(template, DEPLOYMENT_MODE, DeploymentTemplate.Parameters.create()); + DeploymentBody body = DeploymentBody.create(template, DEPLOYMENT_MODE, parameters); return body; } - public String getDeploymentTemplateJson(DeploymentProperties properties){ + public String getDeploymentTemplateJson(DeploymentProperties properties) { return json.toJson(properties); } private void addStorageResource() { - String storageAccountName = name.replaceAll("[^A-Za-z0-9 ]", "") + "storage"; + String storageAccountName = name.replaceAll("[^A-Za-z0-9 ]", "") + "stor"; + + String storageName = template.getImage().getName(); + if (storageName.startsWith(CUSTOM_IMAGE_PREFIX)) { + storageAccountName = storageName.substring(CUSTOM_IMAGE_PREFIX.length()); // get group name + } variables.put("storageAccountName", storageAccountName); @@ -168,47 +200,13 @@ public class DeploymentTemplateBuilder { resources.add(storageAccount); } - private void addVirtualNetworkResource() { - String virtualNetworkName = group + "virtualnetwork"; - - String subnetName = group + "subnet"; - variables.put("virtualNetworkName", virtualNetworkName); - variables.put("virtualNetworkReference", "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]"); - variables.put("subnetName", subnetName); - variables.put("subnetReference", "[concat(variables('virtualNetworkReference'),'/subnets/',variables('subnetName'))]"); - - VirtualNetworkProperties properties = VirtualNetworkProperties.builder() - .addressSpace( - AddressSpace.create(Arrays.asList(DEFAULT_vnAddresSpacePrefix)) - ) - .subnets( - Arrays.asList( - Subnet.create("[variables('subnetName')]", null, null, - SubnetProperties.builder() - .addressPrefix(DEFAULT_subnetAddressPrefix).build() - )) - ) - .build(); - - - ResourceDefinition virtualNetwork = ResourceDefinition.builder() - .name("[variables('virtualNetworkName')]") - .type("Microsoft.Network/virtualNetworks") - .location(location) - .apiVersion(STORAGE_API_VERSION) - .properties(properties) - .build(); - - resources.add(virtualNetwork); - } - private void addPublicIpAddress() { String publicIPAddressName = name + "publicip"; - String dnsLabelPrefix = name; //TODO: read from Azure template properties + String dnsLabelPrefix = options.getDNSLabelPrefix(); PublicIPAddressProperties.Builder properties = PublicIPAddressProperties.builder(); - if (!dnsLabelPrefix.isEmpty()) { + if (!Strings.isNullOrEmpty(dnsLabelPrefix)) { properties.dnsSettings(DnsSettings.builder().domainNameLabel(dnsLabelPrefix).build()); variables.put("dnsLabelPrefix", dnsLabelPrefix); } @@ -233,7 +231,11 @@ public class DeploymentTemplateBuilder { 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() @@ -244,9 +246,22 @@ public class DeploymentTemplateBuilder { ipConfigurations.add(ipConfig); - NetworkInterfaceCardProperties networkInterfaceCardProperties = NetworkInterfaceCardProperties.builder() - .ipConfigurations(ipConfigurations) - .build(); + // 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); @@ -257,16 +272,58 @@ public class DeploymentTemplateBuilder { .type("Microsoft.Network/networkInterfaces") .location(location) .apiVersion(STORAGE_API_VERSION) - .dependsOn(Arrays.asList("[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]", - "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]")) + .dependsOn(depends) .properties(networkInterfaceCardProperties) .build(); resources.add(networkInterfaceCard); } - private void addVirtualMachine() { + private void addNetworkSecurityGroup() { + int ports[] = options.getInboundPorts(); + if ((ports != null) && (ports.length > 0)) { + variables.put("networkSecurityGroupName", name + "nsg"); + variables.put("networkSecurityGroupNameReference", "[resourceId('Microsoft.Network/networkSecurityGroups',variables('networkSecurityGroupName'))]"); + List rules = new ArrayList(); + for (int i = 0; i < ports.length; i++) { + NetworkSecurityRuleProperties ruleProperties = NetworkSecurityRuleProperties.builder() + .description("default-allow-port-" + ports[i]) + .protocol(NetworkSecurityRuleProperties.Protocol.All) + .access(NetworkSecurityRuleProperties.Access.Allow) + .sourcePortRange("*") + .destinationPortRange(Integer.toString(ports[i])) + .sourceAddressPrefix("*") + .destinationAddressPrefix("*") + .priority(1234 + i) + .direction(NetworkSecurityRuleProperties.Direction.Inbound) + .build(); + + NetworkSecurityRule networkSecurityRule = NetworkSecurityRule.create( + "default-allow-port-" + ports[i], + null, + null, + ruleProperties); + + rules.add(networkSecurityRule); + } + + 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); + } + + } + + private void addVirtualMachine() { //Build OS Profile final String computerName = name + "pc"; @@ -275,51 +332,52 @@ public class DeploymentTemplateBuilder { .adminUsername(loginUser) .computerName(computerName); - boolean usePublicKey = options.getPublicKey() != null; + profileBuilder.adminPassword(loginPassword); + //boolean usePublicKey = options.getPublicKey() != null; - if (usePublicKey) { - OSProfile.LinuxConfiguration configuration = OSProfile.LinuxConfiguration.create("true", + 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')]", - options.getPublicKey()) - )) - ); + "[parameters('publicKeyFromAzureKeyVault')]" + )) + )); profileBuilder.linuxConfiguration(configuration); - } else { - profileBuilder.adminPassword(loginPassword); + } + + if (!Strings.isNullOrEmpty(options.getCustomData())){ + String encodedCustomData = base64().encode(options.getCustomData().getBytes()); + profileBuilder.customData(encodedCustomData); } OSProfile osProfile = profileBuilder.build(); - //Build Image Reference - final String imagePublisher = template.getImage().getProviderId(); - final String imageOffer = template.getImage().getName(); - final String imageSku = template.getImage().getVersion(); - - ImageReference imageReference = ImageReference.builder() - .publisher(imagePublisher) - .offer(imageOffer) - .sku(imageSku) - .version("latest") - .build(); - //Build OsDisk - final String storageAccountContainerName = "vhds"; + final String storageAccountContainerName = name + "vhds"; variables.put("storageAccountContainerName", storageAccountContainerName); final String osDiskName = name + "osdisk"; variables.put("osDiskName", osDiskName); - OSDisk osDisk = OSDisk.builder() - .name("[variables('osDiskName')]") - .vhd( - VHD.create("[concat('http://',variables('storageAccountName'),'.blob.core.windows.net/',variables('storageAccountContainerName'),'/',variables('osDiskName'),'.vhd')]") - ) - .caching("ReadWrite") - .createOption("FromImage") - .build(); + boolean usingMarketplaceImage = true; + String cusotomImageUri = ""; + // TODO: make new fields for group information + String publisher = template.getImage().getProviderId(); + String storageName = template.getImage().getName(); + String sku = template.getImage().getDescription(); // this is actual VHD + if (storageName.startsWith(CUSTOM_IMAGE_PREFIX)) { + storageName = storageName.substring(CUSTOM_IMAGE_PREFIX.length()); // get group name + cusotomImageUri = sku; + 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"; @@ -328,7 +386,7 @@ public class DeploymentTemplateBuilder { List dataDisks = new ArrayList(); DataDisk dataDisk = DataDisk.builder() .name("[variables('dataDiskName')]") - .diskSizeGB(DEFAULT_DATA_DISK_SIZE) + .diskSizeGB(azureComputeConstants.azureDefaultDataDiskSizeProperty()) .lun(0) .vhd( VHD.create("[concat('http://',variables('storageAccountName'),'.blob.core.windows.net/',variables('storageAccountContainerName'),'/',variables('dataDiskName'),'.vhd')]") @@ -339,11 +397,20 @@ public class DeploymentTemplateBuilder { dataDisks.add(dataDisk); //Create Storage Profile - StorageProfile storageProfile = StorageProfile.builder() - .imageReference(imageReference) + StorageProfile.Builder storageProfileBuilder = StorageProfile.builder() .osDisk(osDisk) - .dataDisks(dataDisks) - .build(); + .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( @@ -370,19 +437,54 @@ public class DeploymentTemplateBuilder { .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(STORAGE_API_VERSION) + .apiVersion("2015-06-15") .dependsOn(Arrays.asList("[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]", "[concat('Microsoft.Network/networkInterfaces/', variables('networkInterfaceCardName'))]")) - .tags(ImmutableMap.of("displayName", "VirtualMachine")) + .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()); + } + } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceContextLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceContextLiveTest.java deleted file mode 100644 index 940f7855cc..0000000000 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceContextLiveTest.java +++ /dev/null @@ -1,284 +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; - -import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; -import com.google.inject.Module; -import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; -import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; -import org.jclouds.compute.RunNodesException; -import org.jclouds.compute.RunScriptOnNodesException; -import org.jclouds.compute.domain.ComputeMetadata; -import org.jclouds.compute.domain.ExecResponse; -import org.jclouds.compute.domain.NodeMetadata; -import org.jclouds.compute.domain.OsFamily; -import org.jclouds.compute.domain.Template; -import org.jclouds.compute.domain.TemplateBuilder; -import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest; -import org.jclouds.domain.Credentials; -import org.jclouds.domain.LoginCredentials; -import org.jclouds.providers.ProviderMetadata; -import org.jclouds.sshj.config.SshjSshClientModule; -import org.testng.annotations.Test; - -import java.util.Map; -import java.util.Properties; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import static com.google.common.base.Preconditions.checkNotNull; -import static org.assertj.core.api.Assertions.assertThat; -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; - -import static org.jclouds.compute.predicates.NodePredicates.inGroup; -import static org.jclouds.compute.options.TemplateOptions.Builder.overrideLoginCredentials; -import static org.jclouds.scriptbuilder.domain.Statements.exec; -import static org.testng.Assert.assertTrue; - -@Test(groups = "live", testName = "AzureComputeServiceContextLiveTest") -public class AzureComputeServiceContextLiveTest extends BaseComputeServiceContextLiveTest { - - public String azureGroup; - protected static final int RAND = new Random().nextInt(999); - - @Override - protected Module getSshModule() { - return new SshjSshClientModule(); - } - - @Override protected Properties setupProperties() { - azureGroup = "jc" + RAND; - - Properties properties = super.setupProperties(); - long scriptTimeout = TimeUnit.MILLISECONDS.convert(60, TimeUnit.MINUTES); - properties.setProperty(TIMEOUT_SCRIPT_COMPLETE, scriptTimeout + ""); - properties.setProperty(TIMEOUT_NODE_RUNNING, scriptTimeout + ""); - - AzureLiveTestUtils.defaultProperties(properties); - checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); - - properties.put(RESOURCE_GROUP_NAME, azureGroup); - return properties; - } - - public AzureComputeServiceContextLiveTest() { - provider = "azurecompute-arm"; - } - - @Test - public void testDefault() throws RunNodesException { - - final String groupName = this.azureGroup; - final TemplateBuilder templateBuilder = view.getComputeService().templateBuilder(); - templateBuilder.osFamily(OsFamily.UBUNTU); - templateBuilder.osVersionMatches("14.04"); - templateBuilder.hardwareId("Standard_A0"); - templateBuilder.locationId("westus"); - - final Template template = templateBuilder.build(); - - try { - Set nodes = view.getComputeService().createNodesInGroup(groupName, 1, template); - assertThat(nodes).hasSize(1); - } finally { -// Do not destroy view.getComputeService().destroyNodesMatching(inGroup(groupName)); - } - } - - private LoginCredentials getLogin() { - Credentials credentials = new Credentials("jclouds", "Password1!"); - LoginCredentials login = LoginCredentials.fromCredentials(credentials); - return login; - } - - @Test(dependsOnMethods = "testDefault") - public void testExec() throws RunScriptOnNodesException { - final String groupName = this.azureGroup; - String command = "echo hello"; - - Map responses = view.getComputeService().runScriptOnNodesMatching(// - inGroup(groupName), // predicate used to select nodes - exec(command), // what you actually intend to run - overrideLoginCredentials(getLogin()) // use my local user & - // ssh key - .runAsRoot(false) // don't attempt to run as root (sudo) - .wrapInInitScript(false)); // run command directly - - assertTrue(responses.size() > 0); - } - - public static Predicate nameStartsWith(final String prefix) { - Preconditions.checkNotNull(prefix, "prefix must be defined"); - - return new Predicate() { - @Override - public boolean apply(ComputeMetadata computeMetadata) { - return computeMetadata.getName().startsWith(prefix); - } - - @Override - public String toString() { - return "nameStartsWith(" + prefix + ")"; - } - }; - } - - @Test(dependsOnMethods = "testExec") - public void testStop() throws RunScriptOnNodesException { - final String groupName = this.azureGroup; - Set nodes = view.getComputeService().suspendNodesMatching(inGroup(groupName)); - assertTrue(nodes.size() > 0); - - boolean allStopped = false; - while (!allStopped) { - nodes = view.getComputeService().listNodesDetailsMatching(nameStartsWith(groupName)); - for (NodeMetadata node : nodes) { - if (node.getStatus() != NodeMetadata.Status.SUSPENDED) - { - // Not stopped yet - allStopped = false; - try { - Thread.sleep(15 * 1000); - } catch (InterruptedException e) { - } - continue; - } - else - { - allStopped = true; - } - } - } - assertTrue(allStopped); - } - - @Test(dependsOnMethods = "testStop") - public void testStart() throws RunScriptOnNodesException { - final String groupName = this.azureGroup; - Set nodes = view.getComputeService().resumeNodesMatching(inGroup(groupName)); - assertTrue(nodes.size() > 0); - - boolean allStarted = false; - while (!allStarted) { - nodes = view.getComputeService().listNodesDetailsMatching(nameStartsWith(groupName)); - for (NodeMetadata node : nodes) { - if (node.getStatus() != NodeMetadata.Status.RUNNING) - { - // Not started yet - allStarted = false; - try { - Thread.sleep(15 * 1000); - } catch (InterruptedException e) { - } - continue; - } - else - { - allStarted = true; - } - } - } - assertTrue(allStarted); - } - - @Test(dependsOnMethods = "testStart") - public void testRestart() throws RunScriptOnNodesException { - final String groupName = this.azureGroup; - Set nodes = view.getComputeService().rebootNodesMatching(inGroup(groupName)); - assertTrue(nodes.size() > 0); - - boolean allRestarted = false; - while (!allRestarted) { - nodes = view.getComputeService().listNodesDetailsMatching(nameStartsWith(groupName)); - for (NodeMetadata node : nodes) { - if (node.getStatus() != NodeMetadata.Status.RUNNING) - { - // Not started yet - allRestarted = false; - try { - Thread.sleep(30 * 1000); - } catch (InterruptedException e) { - } - continue; - } - else - { - allRestarted = true; - } - } - } - assertTrue(allRestarted); - - view.getComputeService().destroyNodesMatching(inGroup(groupName)); - } - - @Test(dependsOnMethods = "testRestart") - public void testLinuxNode() throws RunNodesException { - final String groupName = this.azureGroup; - final TemplateBuilder templateBuilder = view.getComputeService().templateBuilder(); - templateBuilder.osFamily(OsFamily.UBUNTU); - templateBuilder.osVersionMatches("14.04"); - templateBuilder.hardwareId("Standard_A0"); - templateBuilder.locationId("westus"); - final Template template = templateBuilder.build(); - - try { - Set nodes = view.getComputeService().createNodesInGroup(groupName, 1, template); - assertThat(nodes).hasSize(1); - } finally { - view.getComputeService().destroyNodesMatching(inGroup(groupName)); - } - } - - @Test(dependsOnMethods = "testLinuxNode") - public void testWindowsNode() throws RunNodesException { - final String groupName = this.azureGroup; - final TemplateBuilder templateBuilder = view.getComputeService().templateBuilder(); - templateBuilder.imageId("global/MicrosoftWindowsServer/WindowsServer/Windows-Server-Technical-Preview"); - templateBuilder.hardwareId("Standard_A0"); - templateBuilder.locationId("westus"); - final Template template = templateBuilder.build(); - - try { - Set nodes = view.getComputeService().createNodesInGroup(groupName, 1, template); - assertThat(nodes).hasSize(1); - } finally { - view.getComputeService().destroyNodesMatching(inGroup(groupName)); - } - } - - @Override - protected ProviderMetadata createProviderMetadata() { - AzureComputeProviderMetadata pm = AzureComputeProviderMetadata.builder().build(); - return pm; - } - - protected String setIfTestSystemPropertyPresent(Properties overrides, String key) { - if (System.getProperties().containsKey("test." + key)) { - String val = System.getProperty("test." + key); - overrides.setProperty(key, val); - return val; - } else { - return null; - } - } - -} 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 ae43511fe2..b1223e2d0f 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,33 +16,57 @@ */ package org.jclouds.azurecompute.arm.compute; +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.internal.BaseComputeServiceLiveTest; +import org.jclouds.compute.predicates.NodePredicates; +import org.jclouds.domain.LoginCredentials; +import org.jclouds.scriptbuilder.domain.Statement; +import org.jclouds.scriptbuilder.domain.Statements; +import org.jclouds.scriptbuilder.statements.java.InstallJDK; +import org.jclouds.scriptbuilder.statements.login.AdminAccess; import org.jclouds.sshj.config.SshjSshClientModule; import org.testng.annotations.Test; - import org.jclouds.providers.ProviderMetadata; - import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; 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 org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; - import com.google.inject.Module; +import java.util.Map; import java.util.Properties; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; + import static com.google.common.base.Preconditions.checkNotNull; +import org.jclouds.logging.slf4j.config.SLF4JLoggingModule; +import org.jclouds.logging.config.LoggingModule; + /** * Live tests for the {@link org.jclouds.compute.ComputeService} integration. */ @Test(groups = "live", singleThreaded = true, testName = "AzureComputeServiceLiveTest") public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest { - public String azureGroup; + protected int nonBlockDurationSeconds = 30; public AzureComputeServiceLiveTest() { provider = "azurecompute-arm"; + nonBlockDurationSeconds = 300; + group = "az-u"; + } + + @Override + protected LoggingModule getLoggingModule() { + return new SLF4JLoggingModule(); } @Override @@ -56,18 +80,42 @@ public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest { return pm; } - @Override protected Properties setupProperties() { - azureGroup = "jc" + System.getProperty("user.name").substring(0, 3); + @Override + protected Properties setupProperties() { Properties properties = super.setupProperties(); - long scriptTimeout = TimeUnit.MILLISECONDS.convert(20, TimeUnit.MINUTES); + long scriptTimeout = TimeUnit.MILLISECONDS.convert(60, TimeUnit.MINUTES); properties.setProperty(TIMEOUT_SCRIPT_COMPLETE, scriptTimeout + ""); properties.setProperty(TIMEOUT_NODE_RUNNING, scriptTimeout + ""); - properties.put(RESOURCE_GROUP_NAME, azureGroup); + properties.setProperty(TIMEOUT_PORT_OPEN, scriptTimeout + ""); + properties.setProperty(TIMEOUT_NODE_TERMINATED, scriptTimeout + ""); + properties.setProperty(TIMEOUT_NODE_SUSPENDED, scriptTimeout + ""); + properties.put(RESOURCE_GROUP_NAME, "a4"); AzureLiveTestUtils.defaultProperties(properties); checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); return properties; + } + @Override + protected Template refreshTemplate() { + return this.template = addRunScriptToTemplate(this.buildTemplate(this.client.templateBuilder())); + } + + @Override + protected Template addRunScriptToTemplate(Template template) { + 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; + } + + @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")); } } 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 new file mode 100644 index 0000000000..fecd0fdbdd --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeImageExtensionLiveTest.java @@ -0,0 +1,89 @@ +/* + * 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.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.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; + +/** + * Live tests for the {@link org.jclouds.compute.extensions.ImageExtension} integration. + */ +@Test(groups = "live", singleThreaded = true, testName = "AzureComputeImageExtensionLiveTest") +public class AzureComputeImageExtensionLiveTest extends BaseImageExtensionLiveTest { + + public AzureComputeImageExtensionLiveTest() { + provider = "azurecompute-arm"; + } + + public static String NAME_PREFIX = "%s"; + + @Override + protected Module getSshModule() { + return new SshjSshClientModule(); + } + + @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, "a5"); + + 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}"); + + AzureLiveTestUtils.defaultProperties(properties); + checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); + + return properties; + + } + + @Override + protected ProviderMetadata createProviderMetadata() { + AzureComputeProviderMetadata pm = AzureComputeProviderMetadata.builder().build(); + return pm; + } + +} 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 0e2baefcc7..7493a63f74 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 @@ -18,6 +18,7 @@ package org.jclouds.azurecompute.arm.features; import com.google.common.base.Predicate; import com.google.common.net.UrlEscapers; +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; @@ -141,7 +142,7 @@ public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest { public void testCreate() { 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 TemplateOptions(); + TemplateOptions options = new AzureTemplateOptions(); options.authorizePublicKey(rsakey); DeploymentTemplateBuilder templateBuilder = getDeploymentTemplateBuilderWithOptions(options); DeploymentBody deploymentTemplateBody = templateBuilder.getDeploymentTemplate(); 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 index bc505e7b9b..ad5b1f3a7b 100644 --- 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 @@ -18,18 +18,17 @@ package org.jclouds.azurecompute.arm.features; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; import org.jclouds.compute.options.TemplateOptions; +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.OSProfile; 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.domain.VirtualNetwork.VirtualNetworkProperties; import org.jclouds.azurecompute.arm.util.DeploymentTemplateBuilder; import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.HardwareBuilder; @@ -56,6 +55,8 @@ import static org.testng.Assert.fail; public class DeploymentTemplateBuilderTest extends BaseAzureComputeApiMockTest { final String group = "jcgroup"; + final String vnetName = group + "virtualnetwork"; + final String subnetId = ""; @Test public void testResourceGroup() { @@ -71,22 +72,6 @@ public class DeploymentTemplateBuilderTest extends BaseAzureComputeApiMockTest { assertTrue(variables.containsKey(parseVariableName(resource.name()))); } - @Test - void testVirtualNetwork() { - DeploymentTemplateBuilder builder = getMockDeploymentTemplateBuilderWithEmptyOptions(); - DeploymentBody deploymentBody = builder.getDeploymentTemplate(); - List resources = deploymentBody.template().resources(); - Map variables = deploymentBody.template().variables(); - - ResourceDefinition resource = getResourceByType(resources, "Microsoft.Network/virtualNetworks"); - - VirtualNetworkProperties properties = (VirtualNetworkProperties) resource.properties(); - assertTrue(properties.addressSpace().addressPrefixes().size() > 0); - assertTrue(properties.subnets().size() > 0); - - assertTrue(variables.containsKey(parseVariableName(resource.name()))); - } - @Test void testPublicIpAddress() { DeploymentTemplateBuilder builder = getMockDeploymentTemplateBuilderWithEmptyOptions(); @@ -147,42 +132,49 @@ public class DeploymentTemplateBuilderTest extends BaseAzureComputeApiMockTest { } @Test - void testVirtualMachineWithSSH() { + void testCustomOptions(){ + final String dnsLabelPrefix = "mydnslabel"; + final String customData = "echo customData"; + final String customData64 = "ZWNobyBjdXN0b21EYXRh"; + final String keyvaultString = "/url/to/vault/:publickeysecret"; - 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() + .customData(customData) + .DNSLabelPrefix(dnsLabelPrefix) + .keyVaultIdAndSecret(keyvaultString); - TemplateOptions options = new TemplateOptions(); - options.authorizePublicKey(rsakey); + 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); - Template template = builder.getTemplate(); DeploymentBody deploymentBody = builder.getDeploymentTemplate(); + List resources = deploymentBody.template().resources(); - Map variables = deploymentBody.template().variables(); + ResourceDefinition publicIpResource = getResourceByType(resources, "Microsoft.Network/publicIPAddresses"); + assertNotNull(publicIpResource); - ResourceDefinition resource = getResourceByType(resources, "Microsoft.Compute/virtualMachines"); - assertNotNull(resource); + PublicIPAddressProperties ipProperties = (PublicIPAddressProperties) publicIpResource.properties(); + assertEquals(ipProperties.dnsSettings().domainNameLabel(), dnsLabelPrefix); - VirtualMachineProperties properties = (VirtualMachineProperties) resource.properties(); - assertEquals(properties.hardwareProfile().vmSize(), template.getHardware().getId()); + ResourceDefinition vmResource = getResourceByType(resources, "Microsoft.Compute/virtualMachines"); + assertNotNull(vmResource); - 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"); + VirtualMachineProperties virtualMachineProperties = (VirtualMachineProperties) vmResource.properties(); + assertEquals(virtualMachineProperties.osProfile().customData(), customData64); - // Check that ssh key is in place - OSProfile.LinuxConfiguration osConfig = properties.osProfile().linuxConfiguration(); - assertEquals(osConfig.disablePasswordAuthentication(), "true"); - assertTrue(osConfig.ssh().publicKeys().size() > 0); - assertEquals(osConfig.ssh().publicKeys().get(0).keyData(), rsakey); - - assertTrue(variables.containsKey(parseVariableName(resource.name()))); + //populated when keyvault is used to get public key. + assertNotNull(virtualMachineProperties.osProfile().linuxConfiguration().ssh().publicKeys()); } 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(); @@ -193,13 +185,19 @@ public class DeploymentTemplateBuilderTest extends BaseAzureComputeApiMockTest { } private DeploymentTemplateBuilder getMockDeploymentTemplateBuilderWithEmptyOptions() { - TemplateOptions options = new TemplateOptions(); + AzureTemplateOptions options = new AzureTemplateOptions(); + options.virtualNetworkName(vnetName); + options.subnetId(subnetId); + Template template = getMockTemplate(options); DeploymentTemplateBuilder templateBuilder = api.deploymentTemplateFactory().create(group, "mydeployment", template); return templateBuilder; } private DeploymentTemplateBuilder getMockDeploymentTemplateBuilderWithOptions(TemplateOptions options) { + ((AzureTemplateOptions)options).virtualNetworkName(vnetName); + ((AzureTemplateOptions)options).subnetId(subnetId); + Template template = getMockTemplate(options); DeploymentTemplateBuilder templateBuilder = api.deploymentTemplateFactory().create(group, "mydeployment", template); return templateBuilder; diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/JobApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/JobApiMockTest.java index 3e55df108c..736414596e 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/JobApiMockTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/JobApiMockTest.java @@ -18,12 +18,15 @@ package org.jclouds.azurecompute.arm.features; import java.io.IOException; import java.net.URI; +import java.util.List; +import org.jclouds.azurecompute.arm.domain.ResourceDefinition; import org.jclouds.azurecompute.arm.functions.ParseJobStatus.JobStatus; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; @Test(groups = "unit", testName = "JobApiMockTest", singleThreaded = true) public class JobApiMockTest extends BaseAzureComputeApiMockTest { @@ -70,4 +73,24 @@ public class JobApiMockTest extends BaseAzureComputeApiMockTest { assertSent(server, "GET", requestUrl); } + public void testCaptureJobStatus() throws IOException, InterruptedException { + server.enqueue(jsonResponse("/resourceDefinition.json").setResponseCode(200)); + + List resourceDefinitionsList = api.getJobApi().captureStatus(URI.create(requestUrl)); + + assertTrue(resourceDefinitionsList.size() > 0); + + assertSent(server, "GET", requestUrl); + } + + public void testCaptureJobStatusFailed() throws InterruptedException { + server.enqueue(response404()); + + List resourceDefinitionsList = api.getJobApi().captureStatus(URI.create(requestUrl)); + + assertEquals(resourceDefinitionsList.size(), 0); + + assertSent(server, "GET", requestUrl); + } + } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiMockTest.java index 12ad0733f9..bda8cad53f 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiMockTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiMockTest.java @@ -107,7 +107,8 @@ public class NetworkInterfaceCardApiMockTest extends BaseAzureComputeApiMockTest NetworkInterfaceCardProperties.create(null, null, null, Arrays.asList(IpConfiguration.create("myipconfig", null, null, null, IpConfigurationProperties.create(null, null, "Dynamic", IdReference.create(SubnetID), null)) - ) + ), + null ); final Map tags = ImmutableMap.of("mycustomtag", "foobar"); 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 index be2eb3e3d1..12d62556cf 100644 --- 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 @@ -17,10 +17,12 @@ package org.jclouds.azurecompute.arm.features; import com.google.common.net.UrlEscapers; -import org.jclouds.compute.options.TemplateOptions; +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; @@ -31,6 +33,7 @@ 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; @@ -47,12 +50,50 @@ public class TemplateToDeploymentTemplateLiveTest extends BaseAzureComputeApiLiv private int pollingInterval = 3; // how frequently to poll for create status private String resourceGroup; private String deploymentName; + private String vnetName; + private String subnetId; @BeforeClass @Override public void setup() { super.setup(); resourceGroup = getResourceGroupName(); + + //Subnets belong to a virtual network so that needs to be created first + VirtualNetwork vn = getOrCreateVirtualNetwork(VIRTUAL_NETWORK_NAME); + assertNotNull(vn); + vnetName = vn.name(); + + //Subnet needs to be up & running before NIC can be created + Subnet subnet = getOrCreateSubnet(DEFAULT_SUBNET_NAME, VIRTUAL_NETWORK_NAME); + assertNotNull(subnet); + assertNotNull(subnet.id()); + subnetId = subnet.id(); + } + + @Test(groups = "live") + 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(groups = "live") @@ -74,6 +115,34 @@ public class TemplateToDeploymentTemplateLiveTest extends BaseAzureComputeApiLiv assertNotNull(deployment); } + @Test(groups = "live") + 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(groups = "live") public void testValidateDeploymentTemplateLinuxNodeWithSSH() { Long now = System.currentTimeMillis(); @@ -81,7 +150,10 @@ public class TemplateToDeploymentTemplateLiveTest extends BaseAzureComputeApiLiv 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 TemplateOptions(); + AzureTemplateOptions options = new AzureTemplateOptions(); + options.virtualNetworkName(vnetName); + options.subnetId(subnetId); + options.authorizePublicKey(rsakey); DeploymentTemplateBuilder templateBuilder = getDeploymentTemplateBuilderWithOptions(options); @@ -103,8 +175,12 @@ public class TemplateToDeploymentTemplateLiveTest extends BaseAzureComputeApiLiv 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 TemplateOptions(); + 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(); @@ -144,7 +220,7 @@ public class TemplateToDeploymentTemplateLiveTest extends BaseAzureComputeApiLiv 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("northeurope").description("North Europe").parent(provider).build(); + Location region = (new LocationBuilder()).scope(LocationScope.REGION).id(LOCATION).description(LOCATIONDESCRIPTION).parent(provider).build(); OperatingSystem os = OperatingSystem.builder() .family(OsFamily.UBUNTU) @@ -168,7 +244,10 @@ public class TemplateToDeploymentTemplateLiveTest extends BaseAzureComputeApiLiv } private DeploymentTemplateBuilder getDeploymentTemplateBuilderWithEmptyOptions() { - TemplateOptions options = new TemplateOptions(); + AzureTemplateOptions options = new AzureTemplateOptions(); + options.virtualNetworkName(vnetName); + options.subnetId(subnetId); + Template template = getTemplate(options); DeploymentTemplateBuilder templateBuilder = api.deploymentTemplateFactory().create(resourceGroup, deploymentName, template); return templateBuilder; 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 f117f1c7bb..5271e2a258 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 @@ -17,6 +17,8 @@ package org.jclouds.azurecompute.arm.features; import com.google.common.base.Predicate; +import com.google.gson.internal.LinkedTreeMap; +import com.google.common.collect.Iterables; import org.jclouds.azurecompute.arm.domain.DataDisk; import org.jclouds.azurecompute.arm.domain.DiagnosticsProfile; import org.jclouds.azurecompute.arm.domain.HardwareProfile; @@ -33,16 +35,28 @@ 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.functions.ParseJobStatus; +import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; import org.jclouds.util.Predicates2; +import org.jclouds.azurecompute.arm.domain.ResourceDefinition; +import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +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_SCRIPT_COMPLETE; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_PORT_OPEN; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; import static org.testng.Assert.assertNotNull; import java.net.URI; import java.util.ArrayList; import java.util.List; +import java.util.Properties; +import java.util.concurrent.TimeUnit; import static org.testng.Assert.assertTrue; @@ -60,6 +74,23 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { nicName = nic.name(); } + @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, getResourceGroupName()); + + AzureLiveTestUtils.defaultProperties(properties); + checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); + + return properties; + } + private String getName() { if (vmName == null) { vmName = String.format("%3.24s", @@ -70,7 +101,6 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { @Test public void testCreate() { - StorageAccountApi storageApi = api.getStorageAccountApi(getResourceGroupName()); StorageService storageAccount = storageApi.get(getStorageServiceName()); String blob = storageAccount.storageServiceProperties().primaryEndpoints().get("blob"); @@ -109,22 +139,7 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { public void testStop() { api().stop(getName()); //Poll until resource is ready to be used - boolean jobDone = Predicates2.retry(new Predicate() { - @Override - public boolean apply(String name) { - String status = ""; - List statuses = api().getInstanceDetails(name).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"); - } - }, 60 * 4 * 1000).apply(getName()); - assertTrue(jobDone, "stop operation did not complete in the configured timeout"); - + nodeSuspendedPredicate.apply(getName()); } @Test(dependsOnMethods = "testGet") @@ -194,11 +209,53 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { @Test(dependsOnMethods = "testCreate") public void testList() { List list = api().list(); - VirtualMachine vm = api().get(getName()); - assertTrue(list.contains(vm)); + final VirtualMachine vm = api().get(getName()); + + boolean vmPresent = Iterables.any(list, new Predicate() { + public boolean apply(VirtualMachine input) { + return input.name().equals(vm.name()); + } + }); + + assertTrue(vmPresent); } - @Test(dependsOnMethods = {"testRestart", "testList", "testGet"}, alwaysRun = true) + @Test(dependsOnMethods = "testRestart") + public void testGeneralize() throws IllegalStateException { + api().stop(getName()); + //Poll until resource is ready to be used + + if (nodeSuspendedPredicate.apply(getName())) { + api().generalize(getName()); + } + } + + @Test(dependsOnMethods = "testGeneralize") + public void testCapture() throws IllegalStateException { + URI uri = api().capture(getName(), getName(), getName()); + 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); + + Assert.assertNotNull(osProperties.get("name")); + Assert.assertNotNull(datadiskObject.get("name")); + } + } + } + } + } + + @Test(dependsOnMethods = "testCapture", alwaysRun = true) public void testDelete() throws Exception { URI uri = api().delete(getName()); @@ -227,8 +284,10 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { VHD vhd = VHD.create(blob + "vhds/" + getName() + ".vhd"); VHD vhd2 = VHD.create(blob + "vhds/" + getName() + "data.vhd"); DataDisk dataDisk = DataDisk.create(getName() + "data", "100", 0, vhd2, "Empty"); - OSDisk osDisk = OSDisk.create(null, getName(), vhd, "ReadWrite", "FromImage"); - StorageProfile storageProfile = StorageProfile.create(imgRef, osDisk, null); + List dataDisks = new ArrayList(); + dataDisks.add(dataDisk); + OSDisk osDisk = OSDisk.create(null, getName(), vhd, "ReadWrite", "FromImage", null); + StorageProfile storageProfile = StorageProfile.create(imgRef, osDisk, dataDisks); OSProfile.WindowsConfiguration windowsConfig = OSProfile.WindowsConfiguration.create(false, null, null, true, null); OSProfile osProfile = OSProfile.create(getName(), "azureuser", "RFe3&432dg", null, null, windowsConfig); 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 a2be833e76..f6583c8139 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 @@ -74,7 +74,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { assertEquals(actual.statuses().get(0).code(), expected.statuses().get(0).code()); assertEquals(actual.statuses().get(0).displayStatus(), expected.statuses().get(0).displayStatus()); assertEquals(actual.statuses().get(0).level(), expected.statuses().get(0).level()); - assertEquals(actual.statuses().get(0).time().toString(), expected.statuses().get(0).time().toString()); + //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"); } @@ -182,12 +182,40 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { "/virtualMachines/windowsmachine/powerOff?api-version=2015-06-15"); } + public void testGeneralize() throws Exception { + server.enqueue(new MockResponse().setResponseCode(200)); + final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); + vmAPI.generalize("vm"); // IllegalStateException if failed + assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines/vm/generalize?api-version=2015-06-15"); + } + + public void testCapture() throws Exception { + server.enqueue(response202WithHeader()); + + final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); + URI uri = vmAPI.capture("vm", "prefix", "container"); + assertNotNull(uri); + assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines/vm/capture?api-version=2015-06-15", "{\"vhdPrefix\":\"prefix\",\"destinationContainerName\":\"container\"}"); + } + + public void testCapture404() throws Exception { + server.enqueue(response404()); + + final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); + URI uri = vmAPI.capture("vm", "prefix", "container"); + assertNull(uri); + assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines/vm/capture?api-version=2015-06-15", "{\"vhdPrefix\":\"prefix\",\"destinationContainerName\":\"container\"}"); + } + private VirtualMachineProperties getProperties() { HardwareProfile hwProf = HardwareProfile.create("Standard_D1"); ImageReference imgRef = ImageReference.create("publisher", "offer", "sku", "ver"); VHD vhd = VHD.create("https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd"); List dataDisks = new ArrayList(); - OSDisk osDisk = OSDisk.create("Windows", "windowsmachine", vhd, "ReadWrite", "FromImage"); + OSDisk osDisk = OSDisk.create("Windows", "windowsmachine", vhd, "ReadWrite", "FromImage", null); StorageProfile storageProfile = StorageProfile.create(imgRef, osDisk, dataDisks); OSProfile.WindowsConfiguration windowsConfig = OSProfile.WindowsConfiguration.create(false, null, null, true, null); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AbstractAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AbstractAzureComputeApiLiveTest.java index 337812be91..f3134b70d6 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AbstractAzureComputeApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AbstractAzureComputeApiLiveTest.java @@ -18,8 +18,11 @@ package org.jclouds.azurecompute.arm.internal; import static com.google.common.base.Preconditions.checkNotNull; +import java.net.URI; import java.util.Properties; import java.util.Random; + +import com.google.common.base.Predicate; import com.google.inject.Module; import com.google.inject.Injector; @@ -28,11 +31,19 @@ import org.jclouds.apis.BaseApiLiveTest; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; import org.jclouds.providers.ProviderMetadata; +import com.google.inject.name.Names; +import com.google.inject.Key; +import com.google.inject.TypeLiteral; + +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_IMAGE_AVAILABLE; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; public abstract class AbstractAzureComputeApiLiveTest extends BaseApiLiveTest { protected static final int RAND = new Random().nextInt(999); + protected Predicate nodeSuspendedPredicate; + protected Predicate imageAvailablePredicate; public AbstractAzureComputeApiLiveTest() { provider = "azurecompute-arm"; @@ -40,6 +51,10 @@ public abstract class AbstractAzureComputeApiLiveTest extends BaseApiLiveTest modules) { Injector injector = newBuilder().modules(modules).overrides(props).buildInjector(); + nodeSuspendedPredicate = injector.getInstance(Key.get(new TypeLiteral>() { + }, Names.named(TIMEOUT_NODE_SUSPENDED))); + imageAvailablePredicate = injector.getInstance(Key.get(new TypeLiteral>() { + }, Names.named(TIMEOUT_IMAGE_AVAILABLE))); return injector.getInstance(AzureComputeApi.class); } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java index bd9adfc4bd..0eec5254cb 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java @@ -48,6 +48,7 @@ import java.util.logging.Logger; public class BaseAzureComputeApiLiveTest extends AbstractAzureComputeApiLiveTest { public static final String LOCATION = "westeurope"; + public static final String LOCATIONDESCRIPTION = "West Europe"; public static final String DEFAULT_SUBNET_ADDRESS_SPACE = "10.2.0.0/23"; @@ -61,6 +62,8 @@ public class BaseAzureComputeApiLiveTest extends AbstractAzureComputeApiLiveTest private String resourceGroupName = null; + private String virtualNetworkName = null; + protected StorageService storageService; private String storageServiceName = null; @@ -101,12 +104,12 @@ public class BaseAzureComputeApiLiveTest extends AbstractAzureComputeApiLiveTest if (resourceGroupName == null) { resourceGroupName = String.format("%3.24s", System.getProperty("user.name") + RAND + "groupjclouds"); - createResourceGroup(resourceGroupName); + //createResourceGroup(resourceGroupName); } return resourceGroupName; } - private void createResourceGroup(String name) { + protected void createResourceGroup(String name) { ImmutableMap tags = ImmutableMap.builder().build(); final ResourceGroup resourceGroup = api.getResourceGroupApi().create( @@ -117,10 +120,12 @@ public class BaseAzureComputeApiLiveTest extends AbstractAzureComputeApiLiveTest api.getResourceGroupApi().delete(name); } + @BeforeClass @Override public void setup() { super.setup(); + createResourceGroup(getResourceGroupName()); storageService = getOrCreateStorageService(getStorageServiceName()); } @@ -173,6 +178,7 @@ public class BaseAzureComputeApiLiveTest extends AbstractAzureComputeApiLiveTest vn = vnApi.createOrUpdate(VIRTUAL_NETWORK_NAME, LOCATION, virtualNetworkProperties); + this.virtualNetworkName = virtualNetworkName; return vn; } diff --git a/providers/azurecompute-arm/src/test/resources/logback.xml b/providers/azurecompute-arm/src/test/resources/logback.xml new file mode 100644 index 0000000000..412e0e234c --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/logback.xml @@ -0,0 +1,82 @@ + + + + + target/test-data/jclouds.log + + + %d %-5p [%c] [%thread] %m%n + + + + + target/test-data/jclouds-wire.log + + + %d %-5p [%c] [%thread] %m%n + + + + + target/test-data/jclouds-compute.log + + + %d %-5p [%c] [%thread] %m%n + + + + + target/test-data/jclouds-ssh.log + + + %d %-5p [%c] [%thread] %m%n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/providers/azurecompute-arm/src/test/resources/resourceDefinition.json b/providers/azurecompute-arm/src/test/resources/resourceDefinition.json new file mode 100644 index 0000000000..245ce1f869 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/resourceDefinition.json @@ -0,0 +1,22 @@ +{ + "resources": [ + { + "name": "[parameters('vnName')]", + "type": "Microsoft.Compute/virtualMachines", + "location": "westeurope", + "apiVersion": "2015-06-15", + "properties": { + "hardwareProfile": { + "vmSize": "[paramters('vmSize')]" + }, + "storageProfile": { + "osDisk": { + "osType":"Windows", + "name":"testmachine-osDisk.539c38a7-642c-43cc-a20b-89b0f3e56afe.vhd" + } + }, + "provisioningState": "0.0" + } + } + ] +} \ No newline at end of file From cf438b6c1a7b89011fa3b84548d45638e8ef5db5 Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Fri, 1 Jul 2016 16:08:55 -0700 Subject: [PATCH 13/87] JCLOUDS-664 Azurecompute-arm Update image name logic --- .../arm/compute/AzureComputeServiceAdapter.java | 7 ++++--- .../compute/extensions/AzureComputeImageExtension.java | 3 ++- .../arm/compute/functions/VMImageToImage.java | 9 ++++++++- .../azurecompute/arm/functions/CleanupResources.java | 7 ------- 4 files changed, 14 insertions(+), 12 deletions(-) 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 3d87d6d1f8..48c7672757 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 @@ -265,9 +265,10 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter 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"; // VM needs to be stopped before it can be generalized @@ -118,7 +119,7 @@ public class AzureComputeImageExtension implements ImageExtension { VirtualMachine vm = api.getVirtualMachineApi(group).get(id); String location = vm.location(); - final VMImage ref = VMImage.create(CUSTOM_IMAGE_PREFIX + group, CUSTOM_IMAGE_PREFIX + storageAccountName, disks[0], disks[1], location, false); + final VMImage ref = VMImage.create(CUSTOM_IMAGE_PREFIX + group, CUSTOM_IMAGE_PREFIX + name, disks[0], disks[1], location, false); return imageReferenceToImage.apply(ref); } } 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 75bcc0e033..db2ab9c360 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 @@ -17,6 +17,7 @@ package org.jclouds.azurecompute.arm.compute.functions; import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageExtension.CUSTOM_IMAGE_PREFIX; import static org.jclouds.azurecompute.arm.compute.functions.DeploymentToNodeMetadata.AZURE_LOGIN_PASSWORD; import static org.jclouds.azurecompute.arm.compute.functions.DeploymentToNodeMetadata.AZURE_LOGIN_USERNAME; @@ -79,8 +80,14 @@ public class VMImageToImage implements Function { public Image apply(final VMImage image) { Credentials credentials = new Credentials(AZURE_LOGIN_USERNAME, AZURE_LOGIN_PASSWORD); + String name = ""; + if (image.offer().startsWith(CUSTOM_IMAGE_PREFIX)) { + name = image.offer().substring(CUSTOM_IMAGE_PREFIX.length()); + } else { + name = image.offer(); + } final ImageBuilder builder = new ImageBuilder() - .name(image.offer()) + .name(name) .description(image.sku()) .status(Image.Status.AVAILABLE) .version(image.sku()) 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 1646aec02f..6970887886 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 @@ -34,7 +34,6 @@ import org.jclouds.azurecompute.arm.domain.PublicIPAddress; import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.logging.Logger; -import org.jclouds.azurecompute.arm.domain.StorageService; import com.google.common.base.Function; @@ -79,12 +78,6 @@ public class CleanupResources implements Function { boolean deploymentDeleteStatus = false; if (jobDone) { - StorageService ss = api.getStorageAccountApi(group).get(storageAccountName); - if (ss != null) { - storageAcctDeleteStatus = api.getStorageAccountApi(group).delete(storageAccountName); - } else { - storageAcctDeleteStatus = true; - } Deployment deployment = api.getDeploymentApi(group).get(id); if (deployment != null) { uri = api.getDeploymentApi(group).delete(id); From 26e3d6cfdbbf516eeffb1443ed523f6a8c73b77c Mon Sep 17 00:00:00 2001 From: Andrea Turli Date: Wed, 13 Jul 2016 10:47:52 +0200 Subject: [PATCH 14/87] [azure-arm] add supports to port ranges to addNetworkSecurityGroup - add unit tests --- .../arm/util/DeploymentTemplateBuilder.java | 101 ++++++++++++------ .../DeploymentTemplateBuilderTest.java | 32 +++++- 2 files changed, 98 insertions(+), 35 deletions(-) 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 index f7850d4636..89de398aa0 100644 --- 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 @@ -16,11 +16,11 @@ */ package org.jclouds.azurecompute.arm.util; -import com.google.common.base.Strings; -import com.google.common.collect.Lists; -import com.google.inject.assistedinject.Assisted; -import com.google.common.base.Joiner; -import com.google.common.base.Preconditions; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule; import org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageExtension; @@ -32,38 +32,37 @@ 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.OSDisk; -import org.jclouds.azurecompute.arm.domain.OSProfile; -import org.jclouds.azurecompute.arm.domain.PublicIPAddressProperties; -import org.jclouds.azurecompute.arm.domain.StorageProfile; -import org.jclouds.azurecompute.arm.domain.StorageService; -import org.jclouds.azurecompute.arm.domain.TemplateParameterType; -import org.jclouds.azurecompute.arm.domain.VHD; -import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties; -import org.jclouds.azurecompute.arm.domain.StorageService.StorageServiceProperties; -import org.jclouds.azurecompute.arm.domain.IdReference; -import org.jclouds.azurecompute.arm.domain.ResourceDefinition; 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 java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +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 com.google.inject.Inject; - import static org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageExtension.CUSTOM_IMAGE_PREFIX; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.STORAGE_API_VERSION; @@ -280,32 +279,36 @@ public class DeploymentTemplateBuilder { } private void addNetworkSecurityGroup() { - int ports[] = options.getInboundPorts(); - if ((ports != null) && (ports.length > 0)) { + 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(); - for (int i = 0; i < ports.length; i++) { + int priority = 1234; + for (String portRange : portRanges) { NetworkSecurityRuleProperties ruleProperties = NetworkSecurityRuleProperties.builder() - .description("default-allow-port-" + ports[i]) + .description("default-allow-port-" + portRange) .protocol(NetworkSecurityRuleProperties.Protocol.All) .access(NetworkSecurityRuleProperties.Access.Allow) .sourcePortRange("*") - .destinationPortRange(Integer.toString(ports[i])) + .destinationPortRange(portRange) .sourceAddressPrefix("*") .destinationAddressPrefix("*") - .priority(1234 + i) + .priority(priority) .direction(NetworkSecurityRuleProperties.Direction.Inbound) .build(); NetworkSecurityRule networkSecurityRule = NetworkSecurityRule.create( - "default-allow-port-" + ports[i], + "default-allow-port-" + portRange, null, null, ruleProperties); rules.add(networkSecurityRule); + priority++; } NetworkSecurityGroupProperties networkSecurityGroupProperties = NetworkSecurityGroupProperties.builder() @@ -323,6 +326,44 @@ public class DeploymentTemplateBuilder { } + /** + * 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"; 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 index ad5b1f3a7b..07ab6ef4bf 100644 --- 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 @@ -16,8 +16,9 @@ */ package org.jclouds.azurecompute.arm.features; -import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; -import org.jclouds.compute.options.TemplateOptions; +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; @@ -29,6 +30,7 @@ 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; @@ -37,14 +39,12 @@ 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.annotations.Test; -import java.util.Map; -import java.util.List; - import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; @@ -171,6 +171,28 @@ public class DeploymentTemplateBuilderTest extends BaseAzureComputeApiMockTest { 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); From f67cf8b9dbe777bdeecee840a6c383554c577206 Mon Sep 17 00:00:00 2001 From: Ladislav Thon Date: Mon, 11 Jul 2016 10:32:11 +0200 Subject: [PATCH 15/87] [JCLOUDS-664] make getImage(id) only do a single API request * Fill in the private IP addresses in NodeMetadata * Unify how getNode and listNodes build the VMDeployment * Change VMDeployment to use AutoValue --- .../compute/AzureComputeServiceAdapter.java | 94 ++++++++++--------- .../functions/DeploymentToNodeMetadata.java | 49 ++++++---- .../azurecompute/arm/domain/VMDeployment.java | 36 +++++-- 3 files changed, 113 insertions(+), 66 deletions(-) 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 48c7672757..53e49eec4c 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 @@ -26,6 +26,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Set; import javax.annotation.Resource; @@ -42,6 +43,7 @@ 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.NetworkInterfaceCard; import org.jclouds.azurecompute.arm.domain.ResourceProviderMetaData; import org.jclouds.azurecompute.arm.domain.VMImage; import org.jclouds.azurecompute.arm.domain.VMHardware; @@ -51,9 +53,9 @@ import org.jclouds.azurecompute.arm.domain.PublicIPAddress; import org.jclouds.azurecompute.arm.domain.SKU; import org.jclouds.azurecompute.arm.domain.VMDeployment; import org.jclouds.azurecompute.arm.domain.VirtualMachine; +import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance; 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; @@ -131,8 +133,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter images = listImages(); + String location = fields[0]; + String publisher = fields[1]; + String offer = fields[2]; + String sku = fields[3]; - for (VMImage image : images) { - String imageId = VMImageToImage.encodeFieldsToUniqueId(image); - if (id.equals(imageId)){ - return image; - } + OSImageApi osImageApi = api.getOSImageApi(location); + List versions = osImageApi.listVersions(publisher, offer, sku); + if (!versions.isEmpty()) { + return VMImage.create(publisher, offer, sku, versions.get(0).name(), location, false); } return null; } @@ -324,21 +327,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter list = getIPAddresses(deployment); - vmDeployment.ipAddressList = list; - VirtualMachine vm = api.getVirtualMachineApi(azureGroup).get(id); - vmDeployment.virtualMachine = vm; - vmDeployment.vm = api.getVirtualMachineApi(azureGroup).getInstanceDetails(id); - if (vm != null && vm.tags() != null) { - vmDeployment.userMetaData = vm.tags(); - String tagString = vmDeployment.userMetaData.get("tags"); - List tags = Arrays.asList(tagString.split(",")); - vmDeployment.tags = tags; - } - return vmDeployment; + return convertDeploymentToVMDeployment(deployment); } @Override @@ -384,30 +373,49 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter 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; + } + + private VMDeployment convertDeploymentToVMDeployment(Deployment deployment) { + String id = deployment.id(); + String resourceGroup = getResourceGroupFromId(id); + + List ipAddressList = getIPAddresses(deployment); + List networkInterfaceCards = getNetworkInterfaceCards(deployment); + VirtualMachine vm = api.getVirtualMachineApi(azureGroup).get(id); + VirtualMachineInstance vmInstanceDetails = api.getVirtualMachineApi(azureGroup).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); + } + @Override public Iterable listNodes() { List deployments = api.getDeploymentApi(azureGroup).list(); List vmDeployments = new ArrayList(); - for (Deployment d : deployments){ - VMDeployment vmDeployment = new VMDeployment(); - vmDeployment.deployment = d; - VirtualMachineApi vmApi = api.getVirtualMachineApi(azureGroup); - vmDeployment.vm = vmApi.getInstanceDetails(d.name()); - List list = getIPAddresses(d); - vmDeployment.ipAddressList = list; - - VirtualMachine vm = vmApi.get(d.name()); - vmDeployment.virtualMachine = vm; - - if (vm != null && vm.tags() != null) { - vmDeployment.userMetaData = vm.tags(); - String tagString = vmDeployment.userMetaData.get("tags"); - List tags = Arrays.asList(tagString.split(",")); - vmDeployment.tags = tags; - } - vmDeployments.add(vmDeployment); + vmDeployments.add(convertDeploymentToVMDeployment(d)); } return vmDeployments; } @@ -417,7 +425,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter() { @Override public boolean apply(final VMDeployment input) { - return Iterables.contains(ids, input.deployment.name()); + return Iterables.contains(ids, input.deployment().name()); } }); } 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 index 40e09b724b..8ea82354a0 100644 --- 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 @@ -27,6 +27,8 @@ 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; @@ -111,20 +113,20 @@ public class DeploymentToNodeMetadata implements Function statuses = from.vm.statuses(); + 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")) { @@ -139,11 +141,11 @@ public class DeploymentToNodeMetadata implements Function publicIpAddresses = Sets.newLinkedHashSet(); - if (from.ipAddressList != null) { - for (int c = 0; c < from.ipAddressList.size(); c++) { - PublicIPAddress ip = from.ipAddressList.get(c); + 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()); @@ -174,10 +176,25 @@ public class DeploymentToNodeMetadata implements Function 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(); + if (from.virtualMachine() != null) { + String locationName = from.virtualMachine().location(); List locations = api.getLocationApi().list(); for (org.jclouds.azurecompute.arm.domain.Location location : locations) { @@ -189,7 +206,7 @@ public class DeploymentToNodeMetadata implements Function vmSizes = api.getVMSizeApi(locationName).list(); for (VMSize vmSize : vmSizes) { if (vmSize.name().equals(vmSizeName)) { 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 c663944020..948e69bced 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,21 +16,43 @@ */ package org.jclouds.azurecompute.arm.domain; +import com.google.auto.value.AutoValue; +import org.jclouds.javax.annotation.Nullable; import java.util.List; import java.util.Map; -public class VMDeployment { +@AutoValue +public abstract class VMDeployment { - public Deployment deployment; + public abstract Deployment deployment(); - public List ipAddressList; + @Nullable + public abstract List ipAddressList(); - public VirtualMachineInstance vm; + @Nullable + public abstract VirtualMachineInstance vm(); - public VirtualMachine virtualMachine; + @Nullable + public abstract VirtualMachine virtualMachine(); - public Map userMetaData; + @Nullable + public abstract List networkInterfaceCards(); - public Iterable tags; + @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); + } } From 4fe2374964c7fa0322c0ac8d39ee9e7a3735d2d7 Mon Sep 17 00:00:00 2001 From: Andrea Turli Date: Thu, 14 Jul 2016 13:05:03 +0200 Subject: [PATCH 16/87] add unit test for storage account name generation --- .../DeploymentTemplateBuilderTest.java | 55 +++++++++++++++++-- 1 file changed, 49 insertions(+), 6 deletions(-) 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 index 07ab6ef4bf..165789998f 100644 --- 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 @@ -43,13 +43,14 @@ 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; -import static org.testng.Assert.fail; - @Test(groups = "unit", testName = "DeploymentTemplateBuilderTest", singleThreaded = true) public class DeploymentTemplateBuilderTest extends BaseAzureComputeApiMockTest { @@ -106,7 +107,6 @@ public class DeploymentTemplateBuilderTest extends BaseAzureComputeApiMockTest { assertTrue(variables.containsKey(parseVariableName(resource.name()))); } - @Test void testVirtualMachine() { DeploymentTemplateBuilder builder = getMockDeploymentTemplateBuilderWithEmptyOptions(); @@ -131,6 +131,41 @@ public class DeploymentTemplateBuilderTest extends BaseAzureComputeApiMockTest { 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"; @@ -207,21 +242,29 @@ public class DeploymentTemplateBuilderTest extends BaseAzureComputeApiMockTest { } 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, "mydeployment", template); + 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, "mydeployment", template); + DeploymentTemplateBuilder templateBuilder = api.deploymentTemplateFactory().create(group, name, template); return templateBuilder; } @@ -231,7 +274,7 @@ public class DeploymentTemplateBuilderTest extends BaseAzureComputeApiMockTest { return r; } } - fail("Resource with type: " + type + " not found"); + Assert.fail("Resource with type: " + type + " not found"); return null; } From 4f62f4003628bcd95ac137fab938d6ea8cf77ff2 Mon Sep 17 00:00:00 2001 From: Andrea Turli Date: Wed, 13 Jul 2016 14:42:51 +0200 Subject: [PATCH 17/87] [azure-arm] add controlled storage account name generation - add unit test for storage account name generation --- .../arm/util/DeploymentTemplateBuilder.java | 51 +++++++++++++++++-- 1 file changed, 47 insertions(+), 4 deletions(-) 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 index 89de398aa0..d0750bdca8 100644 --- 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 @@ -21,6 +21,7 @@ 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; @@ -54,6 +55,8 @@ 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; @@ -175,13 +178,20 @@ public class DeploymentTemplateBuilder { } private void addStorageResource() { - String storageAccountName = name.replaceAll("[^A-Za-z0-9 ]", "") + "stor"; + String storageAccountName = null; - String storageName = template.getImage().getName(); - if (storageName.startsWith(CUSTOM_IMAGE_PREFIX)) { - storageAccountName = storageName.substring(CUSTOM_IMAGE_PREFIX.length()); // get group name + String imageName = template.getImage().getName(); + if (imageName.startsWith(CUSTOM_IMAGE_PREFIX)) { + storageAccountName = imageName.substring(CUSTOM_IMAGE_PREFIX.length()); // get group name } + if (Strings.isNullOrEmpty(storageAccountName)) { + storageAccountName = generateStorageAccountName(name); + } + + Validator validator = new DnsNameValidator(3, 24); + validator.validate(storageAccountName); + variables.put("storageAccountName", storageAccountName); ResourceDefinition storageAccount = ResourceDefinition.builder() @@ -528,4 +538,37 @@ public class DeploymentTemplateBuilder { 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); + } } From 3c790ae3aebb3033c834169b08485731897d2696 Mon Sep 17 00:00:00 2001 From: Janne Koskinen Date: Thu, 7 Jul 2016 13:50:59 +0300 Subject: [PATCH 18/87] JCLOUDS-664 Azurecompute-arm ImageExtension --- providers/azurecompute-arm/pom.xml | 10 ++ .../compute/AzureComputeServiceAdapter.java | 54 +++++++---- .../AzureComputeImageExtension.java | 51 ++++++---- .../functions/DeploymentToNodeMetadata.java | 2 +- .../arm/compute/functions/VMImageToImage.java | 95 ++++++++++++++----- .../azurecompute/arm/domain/VMImage.java | 54 ++++++++++- .../azurecompute/arm/util/BlobHelper.java | 91 ++++++++++++++++++ .../arm/util/DeploymentTemplateBuilder.java | 15 ++- .../AzureComputeImageExtensionLiveTest.java | 3 +- 9 files changed, 300 insertions(+), 75 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/BlobHelper.java diff --git a/providers/azurecompute-arm/pom.xml b/providers/azurecompute-arm/pom.xml index 5a41e44f21..0555c31be1 100644 --- a/providers/azurecompute-arm/pom.xml +++ b/providers/azurecompute-arm/pom.xml @@ -113,6 +113,11 @@ ${project.parent.version} test + + org.apache.jclouds.provider + azureblob + ${project.parent.version} + ch.qos.logback logback-classic @@ -135,6 +140,11 @@ + + org.apache.jclouds + jclouds-blobstore + ${project.parent.version} + 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 53e49eec4c..b21dcfc45d 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 @@ -18,7 +18,6 @@ package org.jclouds.azurecompute.arm.compute; import static java.lang.String.format; import static java.util.concurrent.TimeUnit.SECONDS; -import static org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageExtension.CUSTOM_IMAGE_PREFIX; import static org.jclouds.util.Predicates2.retry; import java.util.ArrayList; @@ -45,6 +44,7 @@ import org.jclouds.azurecompute.arm.domain.DeploymentBody; import org.jclouds.azurecompute.arm.domain.DeploymentProperties; import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; import org.jclouds.azurecompute.arm.domain.ResourceProviderMetaData; +import org.jclouds.azurecompute.arm.domain.StorageService; import org.jclouds.azurecompute.arm.domain.VMImage; import org.jclouds.azurecompute.arm.domain.VMHardware; import org.jclouds.azurecompute.arm.domain.Location; @@ -56,6 +56,7 @@ import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance; import org.jclouds.azurecompute.arm.features.DeploymentApi; import org.jclouds.azurecompute.arm.features.OSImageApi; +import org.jclouds.azurecompute.arm.util.BlobHelper; import org.jclouds.azurecompute.arm.util.DeploymentTemplateBuilder; import org.jclouds.compute.ComputeServiceAdapter; import org.jclouds.compute.domain.Template; @@ -97,7 +98,6 @@ 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, false); + VMImage vmImage = VMImage.create(publisherName, offer.name(), sku.name(), version.name(), location); osImagesRef.add(vmImage); } } @@ -247,6 +247,17 @@ 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); + } + return osImages; } @@ -264,24 +275,25 @@ 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, false); + return VMImage.create(publisher, offer, sku, versions.get(0).name(), location); } return null; } @@ -415,8 +427,18 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter vmDeployments = new ArrayList(); for (Deployment d : deployments){ - vmDeployments.add(convertDeploymentToVMDeployment(d)); + // Check that this vm is not generalized and made to custom image + try { + String storageAccountName = d.name().replaceAll("[^A-Za-z0-9 ]", "") + "stor"; + String key = api.getStorageAccountApi(azureGroup).getKeys(storageAccountName).key1(); + if (!BlobHelper.customImageExists(storageAccountName, key)) + vmDeployments.add(convertDeploymentToVMDeployment(d)); + } + catch (Exception e) { + // This might happen if there is no custom images but vm is generalized. No need to list + } } + return vmDeployments; } 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 122a5dad90..786c17a62f 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 @@ -17,18 +17,24 @@ 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 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.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.util.BlobHelper; import org.jclouds.compute.domain.CloneImageTemplate; import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.ImageTemplate; @@ -36,27 +42,25 @@ import org.jclouds.compute.domain.ImageTemplateBuilder; import org.jclouds.compute.extensions.ImageExtension; import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.AzureComputeConstants; -import static java.lang.String.format; -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_IMAGE_AVAILABLE; -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; - -import com.google.common.util.concurrent.UncheckedTimeoutException; - 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; + public class AzureComputeImageExtension implements ImageExtension { private final AzureComputeApi api; + private final ListeningExecutorService userExecutor; + private final Supplier blobstore = null; + private final String group; private final Predicate imageAvailablePredicate; private final Predicate nodeSuspendedPredicate; private final AzureComputeConstants azureComputeConstants; - private final ListeningExecutorService userExecutor; - private final String group; private final VMImageToImage imageReferenceToImage; - public static final String CONTAINER_NAME = "vhdsnew"; + public static final String CONTAINER_NAME = "jclouds"; public static final String CUSTOM_IMAGE_PREFIX = "#"; @Inject @@ -69,29 +73,28 @@ public class AzureComputeImageExtension implements ImageExtension { this.userExecutor = userExecutor; this.group = azureComputeConstants.azureResourceGroup(); this.imageReferenceToImage = imageReferenceToImage; - this.api = api; this.imageAvailablePredicate = imageAvailablePredicate; this.nodeSuspendedPredicate = nodeSuspendedPredicate; this.azureComputeConstants = azureComputeConstants; + this.api = api; } @Override public ImageTemplate buildImageTemplateFromNode(String name, String id) { - String imageName = name.toLowerCase(); - return new ImageTemplateBuilder.CloneImageTemplateBuilder().nodeId(id).name(imageName).build(); + String nameLowerCase = name.toLowerCase(); + return new ImageTemplateBuilder.CloneImageTemplateBuilder().nodeId(id).name(nameLowerCase).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"; - // VM needs to be stopped before it can be generalized - String status = ""; api.getVirtualMachineApi(group).stop(id); - //Poll until resource is ready to be used if (nodeSuspendedPredicate.apply(id)) { return userExecutor.submit(new Callable() { @Override @@ -118,26 +121,36 @@ public class AzureComputeImageExtension implements ImageExtension { disks[1] = datadiskObject.get("name"); VirtualMachine vm = api.getVirtualMachineApi(group).get(id); - String location = vm.location(); - final VMImage ref = VMImage.create(CUSTOM_IMAGE_PREFIX + group, CUSTOM_IMAGE_PREFIX + name, disks[0], disks[1], location, false); + 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()); + + cloneTemplate.getName()); } }); } else { final String illegalStateExceptionMessage = format("Node %s was not suspended within %sms.", - id, azureComputeConstants.operationTimeout()); + id, azureComputeConstants.operationTimeout()); throw new IllegalStateException(illegalStateExceptionMessage); } } @Override public boolean deleteImage(String id) { + + VMImage image = VMImageToImage.decodeFieldsFromUniqueId(id); + if (image.custom()) { + StorageServiceKeys keys = api.getStorageAccountApi(image.group()).getKeys(image.storage()); + + // This removes now all the images in this storage. At least in theory, there should be just one and if there is + // more, they should be copies of each other. + BlobHelper.deleteContainerIfExists(image.storage(), keys.key1(), "system"); + return !BlobHelper.customImageExists(image.storage(), keys.key1()); + } + return false; } } 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 index 8ea82354a0..532e786c92 100644 --- 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 @@ -210,7 +210,7 @@ public class DeploymentToNodeMetadata implements Function { return (imageReference.globallyAvailable() ? "global" : imageReference.location()) + "/" + imageReference.publisher() + "/" + imageReference.offer() + "/" + imageReference.sku(); } - public static String[] decodeFieldsFromUniqueId(final String id) { - return checkNotNull(id, "id").split("/"); + public static String encodeFieldsToUniqueIdCustom(VMImage imageReference){ + return (imageReference.globallyAvailable() ? "global" : imageReference.location()) + "/" + imageReference.group() + "/" + imageReference.storage() + "/" + imageReference.vhd1() + "/" + imageReference.offer(); + } + + public static VMImage decodeFieldsFromUniqueId(final String id) { + String fields[] = checkNotNull(id, "id").split("/"); + VMImage vmImage; + boolean custom = fields.length == 5; + if (custom) { + /* id fields indexes + 0: imageReference.location) + "/" + + 1: imageReference.group + "/" + + 2: imageReference.storage + "/" + + 3: imageReference.vhd1 + "/" + + 4: imageReference.offer + */ + vmImage = VMImage.create(fields[1], fields[2], fields[3], null, null, fields[4], fields[0]); + } else { + /* id fields indexes + 0: imageReference.location) + "/" + + 1: imageReference.publisher + "/" + + 2: imageReference.offer + "/" + + 3: imageReference.sku + "/" + + */ + vmImage = VMImage.create(fields[1], fields[2], fields[3], null, fields[0]); + } + return vmImage; } @Inject @@ -80,26 +104,41 @@ public class VMImageToImage implements Function { public Image apply(final VMImage image) { Credentials credentials = new Credentials(AZURE_LOGIN_USERNAME, AZURE_LOGIN_PASSWORD); - String name = ""; - if (image.offer().startsWith(CUSTOM_IMAGE_PREFIX)) { - name = image.offer().substring(CUSTOM_IMAGE_PREFIX.length()); - } else { - name = image.offer(); - } - final ImageBuilder builder = new ImageBuilder() - .name(name) - .description(image.sku()) - .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())) - .get()); + if (image.custom()) { - final OperatingSystem.Builder osBuilder = osFamily().apply(image); - return builder.operatingSystem(osBuilder.build()).build(); + final ImageBuilder builder = new ImageBuilder() + .location(FluentIterable.from(locations.get()) + .firstMatch(LocationPredicates.idEquals(image.location())) + .get()) + .name(image.name()) + .description("#" + image.group()) + .status(Image.Status.AVAILABLE) + .version(image.storage()) + .providerId(image.vhd1()) + .id(encodeFieldsToUniqueIdCustom(image)) + .defaultCredentials(LoginCredentials.fromCredentials(credentials)); + + final OperatingSystem.Builder osBuilder = osFamily().apply(image); + Image retimage = builder.operatingSystem(osBuilder.build()).build(); + return retimage; + + } + else { + final ImageBuilder builder = new ImageBuilder() + .name(image.offer()) + .description(image.sku()) + .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())) + .get()); + + final OperatingSystem.Builder osBuilder = osFamily().apply(image); + return builder.operatingSystem(osBuilder.build()).build(); + } } public static Function osFamily() { @@ -124,12 +163,16 @@ public class VMImageToImage implements Function { family = OsFamily.OEL; } + 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(image.sku()). - version(image.sku()); + family(family). + is64Bit(true). + description(sku). + version(sku); } }; } 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 2d4fc919d6..c83eafe22e 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 @@ -17,34 +17,39 @@ package org.jclouds.azurecompute.arm.domain; import com.google.auto.value.AutoValue; +import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; @AutoValue public abstract class VMImage { - /** * The publisher of the image reference. */ + @Nullable public abstract String publisher(); /** * The offer of the image reference. */ + @Nullable public abstract String offer(); /** * The sku of the image reference. */ + @Nullable public abstract String sku(); /** * The version of the image reference. */ + @Nullable public abstract String version(); /** * The location from where Image was fetched */ + @Nullable public abstract String location(); /** @@ -52,9 +57,50 @@ public abstract class VMImage { */ public abstract boolean globallyAvailable(); - @SerializedNames({ "publisher", "offer", "sku", "version", "location", "globallyAvailable"}) - public static VMImage create(String publisher, String offer, String sku, String version, String location, boolean globallyAvailable) { + /** + * The group of the custom image + */ + @Nullable + public abstract String group(); - return new AutoValue_VMImage(publisher, offer, sku, version, location, globallyAvailable); + /** + * The storage of the custom image. + */ + @Nullable + public abstract String storage(); + + /** + * The vhd1 of the custom image + */ + @Nullable + public abstract String vhd1(); + + /** + * The vhd2 of the custom image. + */ + @Nullable + public abstract String vhd2(); + + /** + * The name of the custom image template. + */ + @Nullable + public abstract String name(); + + /** + * 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); + } + + @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); } } 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 new file mode 100644 index 0000000000..ee794ec086 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/BlobHelper.java @@ -0,0 +1,91 @@ +/* + * 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 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; + +import java.util.ArrayList; +import java.util.List; + +public class BlobHelper { + + public static void deleteContainerIfExists(String storage, String key, String containerName) { + final AzureBlobClient azureBlob = ContextBuilder.newBuilder("azureblob") + .credentials(storage, key) + .buildApi(AzureBlobClient.class); + + try { + azureBlob.deleteContainer(containerName); + } + finally { + Closeables2.closeQuietly(azureBlob); + } + } + + 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); + } + } + + 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); + + + 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(); + + 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); + } + } + } + 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 index d0750bdca8..e5b0a43f82 100644 --- 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 @@ -182,7 +182,7 @@ public class DeploymentTemplateBuilder { String imageName = template.getImage().getName(); if (imageName.startsWith(CUSTOM_IMAGE_PREFIX)) { - storageAccountName = imageName.substring(CUSTOM_IMAGE_PREFIX.length()); // get group name + storageAccountName = template.getImage().getVersion(); } if (Strings.isNullOrEmpty(storageAccountName)) { @@ -414,13 +414,12 @@ public class DeploymentTemplateBuilder { boolean usingMarketplaceImage = true; String cusotomImageUri = ""; - // TODO: make new fields for group information - String publisher = template.getImage().getProviderId(); - String storageName = template.getImage().getName(); - String sku = template.getImage().getDescription(); // this is actual VHD - if (storageName.startsWith(CUSTOM_IMAGE_PREFIX)) { - storageName = storageName.substring(CUSTOM_IMAGE_PREFIX.length()); // get group name - cusotomImageUri = sku; + // 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; } 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 fecd0fdbdd..06f9ab7ce1 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 @@ -63,7 +63,7 @@ public class AzureComputeImageExtensionLiveTest extends BaseImageExtensionLiveTe properties.setProperty(TIMEOUT_PORT_OPEN, scriptTimeout + ""); properties.setProperty(TIMEOUT_NODE_TERMINATED, scriptTimeout + ""); properties.setProperty(TIMEOUT_NODE_SUSPENDED, scriptTimeout + ""); - properties.put(RESOURCE_GROUP_NAME, "a5"); + properties.put(RESOURCE_GROUP_NAME, "jcloudsgroup"); properties.put(ComputeServiceProperties.POLL_INITIAL_PERIOD, 1000); properties.put(ComputeServiceProperties.POLL_MAX_PERIOD, 10000); @@ -86,4 +86,5 @@ public class AzureComputeImageExtensionLiveTest extends BaseImageExtensionLiveTe return pm; } + } From 1e484fc2ce7b4b9cc546d7531316f8fb7b6d7d2b Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Sat, 17 Sep 2016 00:56:17 +0200 Subject: [PATCH 19/87] Fix package export --- providers/azurecompute-arm/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/azurecompute-arm/pom.xml b/providers/azurecompute-arm/pom.xml index 0555c31be1..df5b835ecb 100644 --- a/providers/azurecompute-arm/pom.xml +++ b/providers/azurecompute-arm/pom.xml @@ -38,7 +38,7 @@ app id app password - org.jclouds.azurecompute-arm*;version="${project.version}" + org.jclouds.azurecompute.arm*;version="${project.version}" org.jclouds*;version="${project.version}",* From 204d54d57cebfa959cee534edca79ef257e0ab71 Mon Sep 17 00:00:00 2001 From: Andrea Turli Date: Thu, 11 Aug 2016 10:52:27 +0200 Subject: [PATCH 20/87] add support for whitelisting locations - change location scope to ZONE vs REGION - edit the README - fix Region.byName - add more Regions in Region class - address initial comments from @nacx - revert ZONES to REGIONS - add parser module - remove parser from HttpApiModule - use one region in AzureLiveTestUtils --- providers/azurecompute-arm/README.md | 23 +++- .../arm/AzureManagementApiMetadata.java | 16 +-- .../compute/AzureComputeServiceAdapter.java | 109 +++++++++--------- .../compute/functions/LocationToLocation.java | 14 +-- .../arm/config/AzureComputeHttpApiModule.java | 15 +-- .../azurecompute/arm/domain/Region.java | 16 ++- .../compute/AzureComputeServiceLiveTest.java | 32 ++--- .../arm/internal/AzureLiveTestUtils.java | 5 +- .../src/test/resources/logback-test.xml | 34 ++++++ .../src/test/resources/logback.xml | 82 ------------- 10 files changed, 162 insertions(+), 184 deletions(-) create mode 100644 providers/azurecompute-arm/src/test/resources/logback-test.xml delete mode 100644 providers/azurecompute-arm/src/test/resources/logback.xml diff --git a/providers/azurecompute-arm/README.md b/providers/azurecompute-arm/README.md index c944a8a925..b1c091627c 100644 --- a/providers/azurecompute-arm/README.md +++ b/providers/azurecompute-arm/README.md @@ -4,8 +4,6 @@ jclouds Labs - Azure Compute ARM Provider Build status for azurecomputearm module: [![Build Status](https://jclouds.ci.cloudbees.com/buildStatus/icon?job=jclouds-labs/org.apache.jclouds.labs$azurecompute-arm)](https://jclouds.ci.cloudbees.com/job/jclouds-labs/org.apache.jclouds.labs$azurecompute-arm/) - - ## Setting Up Test Credentials ### Create a Service Principal @@ -75,3 +73,24 @@ mvn clean verify -Plive \ -Dtest.oauth.endpoint=https://login.microsoftonline.com//oauth2/token ``` + +## How to use it + +Azure Compute ARM provider works exactly as any other jclouds provider. +Notice that as Azure supports dozens of locations, operations like listImages can be really time-consuming. +To limit the scope of such operations there are some additional properties you may want to use: + +```bash +jclouds.azurecompute.arm.publishers +``` +which is by default `Canonical,RedHat` + +and +```bash +jclouds.regions +``` +which is by default `null`. If you want to target only the `north europe` region, you can use + +```bash +jclouds.regions="northeurope" +``` diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java index 989fd841c8..48dbe69428 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java @@ -16,21 +16,22 @@ */ package org.jclouds.azurecompute.arm; -import static org.jclouds.reflect.Reflection2.typeToken; - import java.net.URI; import java.util.Properties; import org.jclouds.apis.ApiMetadata; -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 org.jclouds.azurecompute.arm.config.AzureComputeHttpApiModule; +import org.jclouds.azurecompute.arm.config.AzureComputeParserModule; +import org.jclouds.compute.ComputeServiceContext; +import org.jclouds.http.okhttp.config.OkHttpCommandExecutorServiceModule; +import org.jclouds.oauth.v2.config.OAuthModule; +import org.jclouds.rest.internal.BaseHttpApiMetadata; import com.google.common.collect.ImmutableSet; import com.google.inject.Module; -import org.jclouds.http.okhttp.config.OkHttpCommandExecutorServiceModule; + +import static org.jclouds.reflect.Reflection2.typeToken; /** * Implementation of {@link ApiMetadata} for Microsoft Azure Resource Manager REST API @@ -72,6 +73,7 @@ public class AzureManagementApiMetadata extends BaseHttpApiMetadata osImagesRef, String location) { - - + private List getImagesFromPublisher(String publisherName, String location) { + List osImagesRef = Lists.newArrayList(); OSImageApi osImageApi = api.getOSImageApi(location); Iterable offerList = osImageApi.listOffers(publisherName); @@ -224,14 +229,14 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listImagesByLocation(String location) { final List osImages = Lists.newArrayList(); Iterable publishers = Splitter.on(',').trimResults().omitEmptyStrings().split(this.azureComputeConstants.azureImagePublishers()); for (String publisher : publishers) { - getImagesFromPublisher(publisher, osImages, location); + osImages.addAll(getImagesFromPublisher(publisher, location)); } return osImages; } @@ -240,14 +245,10 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listImages() { final List osImages = Lists.newArrayList(); - final List locationIds = Lists.newArrayList(); for (Location location : listLocations()){ - locationIds.add(location.name()); osImages.addAll(listImagesByLocation(location.name())); } - checkAndSetImageAvailability(osImages, Sets.newHashSet(locationIds)); - // list custom images List storages = api.getStorageAccountApi(azureGroup).list(); for (StorageService storage : storages) { @@ -257,22 +258,9 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter images, Collection locations) { - Multimap map = ArrayListMultimap.create(); - - for (VMImage image : images) { - map.put( image.offer() + "/" + image.sku(), image.location()); - } - ///TODO - // for (VMImage image : images) { - // image.globallyAvailable() = map.get(image.offer() + "/" + image.sku()).containsAll(locations); - // } - } - @Override public VMImage getImage(final String id) { VMImage image = VMImageToImage.decodeFieldsFromUniqueId(id); @@ -300,28 +288,43 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listLocations() { + final Iterable whiteListZoneName = findWhiteListOfRegions(); - List locations = api.getLocationApi().list(); + final Iterable vmLocations = FluentIterable.from(api.getResourceProviderApi().get("Microsoft.Compute")) + .filter(new Predicate() { + @Override + public boolean apply(ResourceProviderMetaData input) { + return input.resourceType().equals("virtualMachines"); + } + }) + .transformAndConcat(new Function>() { + @Override + public Iterable apply(ResourceProviderMetaData resourceProviderMetaData) { + return resourceProviderMetaData.locations(); + } + }); - List resources = api.getResourceProviderApi().get("Microsoft.Compute"); + List locations = FluentIterable.from(api.getLocationApi().list()) + .filter(new Predicate() { + @Override + public boolean apply(Location location) { + return Iterables.contains(vmLocations, location.displayName()); + } + }) + .filter(new Predicate() { + @Override + public boolean apply(Location location) { + return whiteListZoneName == null ? true : Iterables.contains(whiteListZoneName, location.name()); + } + }) + .toList(); - final List vmLocations = new ArrayList(); + return locations; + } - for (ResourceProviderMetaData m : resources){ - if (m.resourceType().equals("virtualMachines")){ - vmLocations.addAll(m.locations()); - break; - } - } - - Iterable result = Iterables.filter(locations, new Predicate() { - @Override - public boolean apply(Location input) { - return vmLocations.contains(input.displayName()); - } - }); - - return result; + private Iterable findWhiteListOfRegions() { + if (providerMetadata.getDefaultProperties().get(LocationConstants.PROPERTY_REGIONS) == null) return null; + return Splitter.on(",").trimResults().split((CharSequence) providerMetadata.getDefaultProperties().get(LocationConstants.PROPERTY_REGIONS)); } private String getResourceGroupFromId(String id) { diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToLocation.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToLocation.java index 0ca1458770..7c60175ab2 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToLocation.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToLocation.java @@ -16,8 +16,6 @@ */ package org.jclouds.azurecompute.arm.compute.functions; -import static com.google.common.collect.Iterables.getOnlyElement; - import javax.inject.Inject; import javax.inject.Singleton; @@ -30,6 +28,8 @@ import org.jclouds.location.suppliers.all.JustProvider; import com.google.common.base.Function; import com.google.common.collect.ImmutableSet; +import static com.google.common.collect.Iterables.getOnlyElement; + /** * Converts an Location into a Location. */ @@ -47,20 +47,14 @@ public class LocationToLocation implements Function 0 && (index + 1) < id.length()) - id = id.substring(index + 1); - builder.id(id); + builder.id(location.name()); builder.description(location.displayName()); builder.parent(getOnlyElement(justProvider.get())); - builder.scope(LocationScope.REGION); - final Region region = Region.byName(location.name()); + final Region region = Region.byName(location.displayName()); if (region != null) { builder.iso3166Codes(ImmutableSet.of(region.iso3166Code())); } - return builder.build(); } 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 30cbc1e127..bd1750f6ed 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 @@ -15,23 +15,22 @@ * limitations under the License. */ 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; import org.jclouds.http.annotation.ServerError; import org.jclouds.location.suppliers.ImplicitLocationSupplier; -import org.jclouds.location.suppliers.implicit.OnlyLocationOrFirstRegionOptionallyMatchingRegionId; - +import org.jclouds.location.suppliers.implicit.FirstRegion; +import org.jclouds.oauth.v2.config.OAuthScopes; import org.jclouds.rest.ConfiguresHttpApi; import org.jclouds.rest.config.HttpApiModule; -import org.jclouds.oauth.v2.config.OAuthScopes; -import com.google.inject.assistedinject.FactoryModuleBuilder; import com.google.inject.Scopes; +import com.google.inject.assistedinject.FactoryModuleBuilder; @ConfiguresHttpApi public class AzureComputeHttpApiModule extends HttpApiModule { @@ -46,14 +45,12 @@ public class AzureComputeHttpApiModule extends HttpApiModule { @Override protected void installLocations() { super.installLocations(); - bind(ImplicitLocationSupplier.class). - to(OnlyLocationOrFirstRegionOptionallyMatchingRegionId.class). - in(Scopes.SINGLETON); + bind(ImplicitLocationSupplier.class).to(FirstRegion.class).in(Scopes.SINGLETON); } + @Override protected void configure() { - install(new AzureComputeParserModule()); 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/domain/Region.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.java index feffa7bbac..a4453f5c1e 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.java @@ -16,12 +16,13 @@ */ package org.jclouds.azurecompute.arm.domain; +import java.util.Arrays; +import java.util.Set; + import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; -import java.util.Arrays; -import java.util.Set; /** * Regions used in Azure. @@ -46,7 +47,14 @@ public enum Region { JAPAN_WEST("Japan West", "JP-27"), BRAZIL_SOUTH("Brazil South", "BR"), AUSTRALIA_EAST("Australia East", "AU-NSW"), - AUSTRALIA_SOUTH_EAST("Australia Southeast", "AU-VIC"); + AUSTRALIA_SOUTH_EAST("Australia Southeast", "AU-VIC"), + INDIA_CENTRAL("Central India", "IN-GA"), + INDIA_SOUTH("South India", "IN-TN"), + INDIA_WEST("West India", "IN-MH"), + CHINA_EAST("China East", "CN-SH"), + CHINA_NORTH("China North", "CN-BJ"), + CANADA_CENTRAL("Canada Central", "CA-ON"), + CANADA_EAST("Canada East", "CA-QC"); private final String name; @@ -73,7 +81,6 @@ public enum Region { return region; } } - return null; } @@ -86,4 +93,5 @@ public enum Region { } })); } + } 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 b1223e2d0f..b579f6ab47 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,6 +16,13 @@ */ package org.jclouds.azurecompute.arm.compute; +import java.util.Map; +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; @@ -24,32 +31,25 @@ import org.jclouds.compute.domain.Template; 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; import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statements; import org.jclouds.scriptbuilder.statements.java.InstallJDK; import org.jclouds.scriptbuilder.statements.login.AdminAccess; import org.jclouds.sshj.config.SshjSshClientModule; import org.testng.annotations.Test; -import org.jclouds.providers.ProviderMetadata; -import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; -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 org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; import com.google.inject.Module; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; import static com.google.common.base.Preconditions.checkNotNull; -import org.jclouds.logging.slf4j.config.SLF4JLoggingModule; -import org.jclouds.logging.config.LoggingModule; - +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.RESOURCE_GROUP_NAME; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_SCRIPT_COMPLETE; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_PORT_OPEN; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; /** * Live tests for the {@link org.jclouds.compute.ComputeService} integration. diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java index c578e84a44..3f69e59f42 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java @@ -17,8 +17,10 @@ package org.jclouds.azurecompute.arm.internal; import java.util.Properties; -import static org.jclouds.oauth.v2.config.OAuthProperties.CREDENTIAL_TYPE; + +import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGIONS; import static org.jclouds.oauth.v2.config.CredentialType.CLIENT_CREDENTIALS_SECRET; +import static org.jclouds.oauth.v2.config.OAuthProperties.CREDENTIAL_TYPE; public class AzureLiveTestUtils { @@ -28,6 +30,7 @@ public class AzureLiveTestUtils { properties.put("oauth.credential", "password"); properties.put("oauth.endpoint", "https://login.microsoftonline.com/oauth2/token"); properties.put(CREDENTIAL_TYPE, CLIENT_CREDENTIALS_SECRET.toString()); + properties.put(PROPERTY_REGIONS, "northeurope"); return properties; } } diff --git a/providers/azurecompute-arm/src/test/resources/logback-test.xml b/providers/azurecompute-arm/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..c823913f6f --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/logback-test.xml @@ -0,0 +1,34 @@ + + + + + + - %msg%n + + + + + + + + + + + diff --git a/providers/azurecompute-arm/src/test/resources/logback.xml b/providers/azurecompute-arm/src/test/resources/logback.xml deleted file mode 100644 index 412e0e234c..0000000000 --- a/providers/azurecompute-arm/src/test/resources/logback.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - - - target/test-data/jclouds.log - - - %d %-5p [%c] [%thread] %m%n - - - - - target/test-data/jclouds-wire.log - - - %d %-5p [%c] [%thread] %m%n - - - - - target/test-data/jclouds-compute.log - - - %d %-5p [%c] [%thread] %m%n - - - - - target/test-data/jclouds-ssh.log - - - %d %-5p [%c] [%thread] %m%n - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From b3294bb177ae97a616b89aefdd633ac195511c68 Mon Sep 17 00:00:00 2001 From: Andrea Turli Date: Thu, 11 Aug 2016 10:52:27 +0200 Subject: [PATCH 21/87] separate the DeploymentToVMDeployment to a function - refactor logback-test.xml - change jsonBall to Value --- .../compute/AzureComputeServiceAdapter.java | 172 ++++++------------ .../functions/DeploymentToVMDeployment.java | 121 ++++++++++++ .../azurecompute/arm/domain/Deployment.java | 14 +- .../azurecompute/arm/domain/Value.java | 42 +++++ .../azurecompute/arm/util/BlobHelper.java | 6 +- .../src/test/resources/logback-test.xml | 64 ++++--- 6 files changed, 262 insertions(+), 157 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/DeploymentToVMDeployment.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Value.java 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 82b792c7b2..3941ebcfc8 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 @@ -16,11 +16,8 @@ */ package org.jclouds.azurecompute.arm.compute; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.List; -import java.util.Map; import java.util.Set; import javax.annotation.Resource; @@ -30,33 +27,32 @@ 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.domain.Deployment; import org.jclouds.azurecompute.arm.domain.DeploymentBody; import org.jclouds.azurecompute.arm.domain.DeploymentProperties; -import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; -import org.jclouds.azurecompute.arm.domain.ResourceProviderMetaData; -import org.jclouds.azurecompute.arm.domain.StorageService; -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.StorageService; import org.jclouds.azurecompute.arm.domain.VMDeployment; import org.jclouds.azurecompute.arm.domain.VMSize; import org.jclouds.azurecompute.arm.domain.Version; -import org.jclouds.azurecompute.arm.domain.VirtualMachine; -import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance; +import org.jclouds.azurecompute.arm.domain.VMHardware; +import org.jclouds.azurecompute.arm.domain.VMImage; +import org.jclouds.azurecompute.arm.domain.Value; import org.jclouds.azurecompute.arm.features.DeploymentApi; import org.jclouds.azurecompute.arm.features.OSImageApi; -import org.jclouds.azurecompute.arm.util.BlobHelper; 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.Template; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.domain.LoginCredentials; +import org.jclouds.json.Json; import org.jclouds.location.reference.LocationConstants; import org.jclouds.logging.Logger; import org.jclouds.providers.ProviderMetadata; @@ -90,17 +86,16 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter credential = null; - + NodeAndInitialCredentials credential; if (template.getOptions().getPublicKey() != null){ String privateKey = template.getOptions().getPrivateKey(); credential = new NodeAndInitialCredentials(deployment, name, @@ -167,7 +159,6 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter(deployment, name, LoginCredentials.builder().user(loginUser).password(loginPassword).authenticateSudo(true).build()); } - return credential; } @@ -288,7 +279,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listLocations() { - final Iterable whiteListZoneName = findWhiteListOfRegions(); + final Iterable whiteListedRegionNames = findWhiteListOfRegions(); final Iterable vmLocations = FluentIterable.from(api.getResourceProviderApi().get("Microsoft.Compute")) .filter(new Predicate() { @@ -314,7 +305,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter() { @Override public boolean apply(Location location) { - return whiteListZoneName == null ? true : Iterables.contains(whiteListZoneName, location.name()); + return whiteListedRegionNames == null ? true : Iterables.contains(whiteListedRegionNames, location.name()); } }) .toList(); @@ -322,27 +313,14 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter findWhiteListOfRegions() { - if (providerMetadata.getDefaultProperties().get(LocationConstants.PROPERTY_REGIONS) == null) return null; - return Splitter.on(",").trimResults().split((CharSequence) providerMetadata.getDefaultProperties().get(LocationConstants.PROPERTY_REGIONS)); - } - - 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; - return convertDeploymentToVMDeployment(deployment); + if (deployment == null) return null; + if (new IsDeploymentInRegions(findWhiteListOfRegions()).apply(deployment)) { + return deploymentToVMDeployment.apply(deployment); + } + return null; } @Override @@ -365,84 +343,21 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter 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 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; - } - - private VMDeployment convertDeploymentToVMDeployment(Deployment deployment) { - String id = deployment.id(); - String resourceGroup = getResourceGroupFromId(id); - - List ipAddressList = getIPAddresses(deployment); - List networkInterfaceCards = getNetworkInterfaceCards(deployment); - VirtualMachine vm = api.getVirtualMachineApi(azureGroup).get(id); - VirtualMachineInstance vmInstanceDetails = api.getVirtualMachineApi(azureGroup).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); - } - @Override public Iterable listNodes() { - List deployments = api.getDeploymentApi(azureGroup).list(); - - List vmDeployments = new ArrayList(); - for (Deployment d : deployments){ - // Check that this vm is not generalized and made to custom image - try { - String storageAccountName = d.name().replaceAll("[^A-Za-z0-9 ]", "") + "stor"; - String key = api.getStorageAccountApi(azureGroup).getKeys(storageAccountName).key1(); - if (!BlobHelper.customImageExists(storageAccountName, key)) - vmDeployments.add(convertDeploymentToVMDeployment(d)); - } - catch (Exception e) { - // This might happen if there is no custom images but vm is generalized. No need to list - } - } - - return vmDeployments; + return FluentIterable.from(api.getDeploymentApi(azureGroup).list()) + .filter(new IsDeploymentInRegions(findWhiteListOfRegions())) + .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(); } @Override @@ -455,4 +370,23 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter findWhiteListOfRegions() { + if (providerMetadata.getDefaultProperties().get(LocationConstants.PROPERTY_REGIONS) == null) return null; + return Splitter.on(",").trimResults().split((CharSequence) providerMetadata.getDefaultProperties().get(LocationConstants.PROPERTY_REGIONS)); + } + + private class IsDeploymentInRegions implements Predicate { + + private final Iterable whiteListOfRegions; + + public IsDeploymentInRegions(Iterable whiteListOfRegions) { + this.whiteListOfRegions = whiteListOfRegions; + } + + @Override + public boolean apply(Deployment deployment) { + Value locationValue = deployment.properties().parameters().get("location"); + return Iterables.contains(whiteListOfRegions, locationValue.value()); + } + } } 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 new file mode 100644 index 0000000000..31f1a58586 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/DeploymentToVMDeployment.java @@ -0,0 +1,121 @@ +/* + * 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/domain/Deployment.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Deployment.java index 2fc85bc36f..be363ecd0a 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Deployment.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Deployment.java @@ -16,18 +16,18 @@ */ package org.jclouds.azurecompute.arm.domain; -import static com.google.common.collect.ImmutableList.copyOf; - import java.util.List; import java.util.Map; -import com.google.common.collect.ImmutableMap; import org.jclouds.azurecompute.arm.util.GetEnumValue; import org.jclouds.domain.JsonBall; import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; import com.google.auto.value.AutoValue; -import org.jclouds.json.SerializedNames; +import com.google.common.collect.ImmutableMap; + +import static com.google.common.collect.ImmutableList.copyOf; @AutoValue public abstract class Deployment { @@ -186,7 +186,7 @@ public abstract class Deployment { public abstract ContentLink templateLink(); @Nullable - public abstract Map parameters(); + public abstract Map parameters(); @Nullable public abstract ContentLink parametersLink(); @@ -209,7 +209,7 @@ public abstract class Deployment { final List dependencies, final Map template, final ContentLink templateLink, - final Map parameters, + final Map parameters, final ContentLink parametersLink, final String mode, final String duration, @@ -222,7 +222,7 @@ public abstract class Deployment { dependencies == null ? null : copyOf(dependencies), template == null ? ImmutableMap.builder().build() : ImmutableMap.copyOf(template), templateLink, - parameters == null ? ImmutableMap.builder().build() : ImmutableMap.copyOf(parameters), + parameters == null ? ImmutableMap.builder().build() : ImmutableMap.copyOf(parameters), parametersLink, mode, duration, diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Value.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Value.java new file mode 100644 index 0000000000..4b0ce0c96d --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Value.java @@ -0,0 +1,42 @@ +/* + * 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 org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class Value { + + /** + * The type of the Value + */ + public abstract String type(); + + /** + * The name of the Value + */ + public abstract String value(); + + @SerializedNames({"type", "value"}) + public static Value create(final String type, final String value) { + + return new AutoValue_Value(type, value); + } + +} 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 ee794ec086..f5bfc758af 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,6 +16,9 @@ */ package org.jclouds.azurecompute.arm.util; +import java.util.ArrayList; +import java.util.List; + import org.jclouds.ContextBuilder; import org.jclouds.azure.storage.domain.BoundedSet; import org.jclouds.azureblob.AzureBlobClient; @@ -25,9 +28,6 @@ import org.jclouds.azureblob.domain.ListBlobsResponse; import org.jclouds.azurecompute.arm.domain.VMImage; import org.jclouds.util.Closeables2; -import java.util.ArrayList; -import java.util.List; - public class BlobHelper { public static void deleteContainerIfExists(String storage, String key, String containerName) { diff --git a/providers/azurecompute-arm/src/test/resources/logback-test.xml b/providers/azurecompute-arm/src/test/resources/logback-test.xml index c823913f6f..cb55d49823 100644 --- a/providers/azurecompute-arm/src/test/resources/logback-test.xml +++ b/providers/azurecompute-arm/src/test/resources/logback-test.xml @@ -1,34 +1,42 @@ - - - + + + target/test-data/jclouds.log - - %msg%n + %d %-5p [%c] [%thread] %m%n - - + + target/test-data/jclouds-wire.log + + %d %-5p [%c] [%thread] %m%n + + + + target/jclouds-compute.log + + %d %-5p [%c] [%thread] %m%n + + + + + + + + + + + + + + + + + + + + + + - - - - - From 8cbf312c329acd042469d5984c11436286712969 Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Wed, 21 Sep 2016 17:00:26 +0200 Subject: [PATCH 22/87] Use the existing region suppliers to filter --- .../compute/AzureComputeServiceAdapter.java | 59 ++++++------------- .../predicates/IsDeploymentInRegions.java | 46 +++++++++++++++ 2 files changed, 65 insertions(+), 40 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/predicates/IsDeploymentInRegions.java 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 3941ebcfc8..61807a9589 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 @@ -16,6 +16,11 @@ */ 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 java.util.Collection; import java.util.List; import java.util.Set; @@ -29,6 +34,7 @@ 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; @@ -38,11 +44,11 @@ import org.jclouds.azurecompute.arm.domain.ResourceProviderMetaData; import org.jclouds.azurecompute.arm.domain.SKU; import org.jclouds.azurecompute.arm.domain.StorageService; import org.jclouds.azurecompute.arm.domain.VMDeployment; -import org.jclouds.azurecompute.arm.domain.VMSize; -import org.jclouds.azurecompute.arm.domain.Version; 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.features.OSImageApi; import org.jclouds.azurecompute.arm.functions.CleanupResources; @@ -52,14 +58,13 @@ 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.json.Json; -import org.jclouds.location.reference.LocationConstants; +import org.jclouds.location.Region; import org.jclouds.logging.Logger; -import org.jclouds.providers.ProviderMetadata; import com.google.common.base.Function; 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.Iterables; @@ -68,11 +73,6 @@ import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import com.google.common.net.UrlEscapers; -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; - /** * Defines the connection between the {@link AzureComputeApi} implementation and the jclouds * {@link org.jclouds.compute.ComputeService}. @@ -86,16 +86,16 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter> regionIds; + private final IsDeploymentInRegions isDeploymentInRegions; private final DeploymentToVMDeployment deploymentToVMDeployment; @Inject AzureComputeServiceAdapter(final AzureComputeApi api, final AzureComputeConstants azureComputeConstants, - CleanupResources cleanupResources, Json json, ProviderMetadata providerMetadata, DeploymentToVMDeployment deploymentToVMDeployment) { - this.json = json; + CleanupResources cleanupResources, @Region Supplier> regionIds, + IsDeploymentInRegions isDeploymentInRegions, DeploymentToVMDeployment deploymentToVMDeployment) { this.api = api; this.azureComputeConstants = azureComputeConstants; this.azureGroup = azureComputeConstants.azureResourceGroup(); @@ -103,7 +103,8 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listLocations() { - final Iterable whiteListedRegionNames = findWhiteListOfRegions(); - final Iterable vmLocations = FluentIterable.from(api.getResourceProviderApi().get("Microsoft.Compute")) .filter(new Predicate() { @Override @@ -305,7 +304,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter() { @Override public boolean apply(Location location) { - return whiteListedRegionNames == null ? true : Iterables.contains(whiteListedRegionNames, location.name()); + return regionIds.get().isEmpty() ? true : regionIds.get().contains(location.name()); } }) .toList(); @@ -317,7 +316,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listNodes() { return FluentIterable.from(api.getDeploymentApi(azureGroup).list()) - .filter(new IsDeploymentInRegions(findWhiteListOfRegions())) + .filter(isDeploymentInRegions) .filter(new Predicate() { @Override public boolean apply(Deployment deployment) { @@ -369,24 +368,4 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter findWhiteListOfRegions() { - if (providerMetadata.getDefaultProperties().get(LocationConstants.PROPERTY_REGIONS) == null) return null; - return Splitter.on(",").trimResults().split((CharSequence) providerMetadata.getDefaultProperties().get(LocationConstants.PROPERTY_REGIONS)); - } - - private class IsDeploymentInRegions implements Predicate { - - private final Iterable whiteListOfRegions; - - public IsDeploymentInRegions(Iterable whiteListOfRegions) { - this.whiteListOfRegions = whiteListOfRegions; - } - - @Override - public boolean apply(Deployment deployment) { - Value locationValue = deployment.properties().parameters().get("location"); - return Iterables.contains(whiteListOfRegions, locationValue.value()); - } - } } 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 new file mode 100644 index 0000000000..57a0678b82 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/predicates/IsDeploymentInRegions.java @@ -0,0 +1,46 @@ +/* + * 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.predicates; + +import java.util.Set; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.azurecompute.arm.domain.Deployment; +import org.jclouds.azurecompute.arm.domain.Value; +import org.jclouds.location.Region; + +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; + +@Singleton +public class IsDeploymentInRegions implements Predicate { + + private final Supplier> regionIds; + + @Inject + IsDeploymentInRegions(@Region Supplier> regionIds) { + this.regionIds = regionIds; + } + + @Override + public boolean apply(Deployment deployment) { + Value locationValue = deployment.properties().parameters().get("location"); + return regionIds.get().contains(locationValue.value()); + } +} From 8df58654b8c6117500b15ed090c8fe7f1e5e0f26 Mon Sep 17 00:00:00 2001 From: Andrea Turli Date: Fri, 9 Sep 2016 18:30:26 +0200 Subject: [PATCH 23/87] fix azure-arm features live tests - add image publishers filter to AzureComputeServiceLiveTest - add parser module to provider - fix create network card interface - fix checkstyle --- .../arm/AzureManagementApiMetadata.java | 5 +- .../AzureComputeServiceContextModule.java | 97 +++--- .../arm/features/DeploymentApi.java | 21 +- .../azurecompute/arm/functions/URIParser.java | 9 +- .../compute/AzureComputeServiceLiveTest.java | 10 +- .../compute/AzureTemplateBuilderLiveTest.java | 12 +- .../arm/features/DeploymentApiLiveTest.java | 95 +++--- .../arm/features/LocationApiLiveTest.java | 9 +- .../NetworkInterfaceCardApiLiveTest.java | 110 +++---- .../NetworkSecurityGroupApiLiveTest.java | 111 +++---- .../NetworkSecurityRuleApiLiveTest.java | 154 +++------ .../arm/features/OSImageApiLiveTest.java | 9 +- .../features/PublicIPAddressApiLiveTest.java | 46 ++- .../features/ResourceGroupApiLiveTest.java | 71 +--- .../features/ResourceProviderApiLiveTest.java | 8 +- .../features/StorageAccountApiLiveTest.java | 46 ++- .../arm/features/SubnetApiLiveTest.java | 76 +++-- .../TemplateToDeploymentTemplateLiveTest.java | 42 ++- .../arm/features/VMSizeApiLiveTest.java | 2 +- .../features/VirtualMachineApiLiveTest.java | 307 +++++++++--------- .../features/VirtualNetworkApiLiveTest.java | 73 ++--- .../AbstractAzureComputeApiLiveTest.java | 80 ----- .../internal/BaseAzureComputeApiLiveTest.java | 295 +++++++---------- 23 files changed, 728 insertions(+), 960 deletions(-) delete mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AbstractAzureComputeApiLiveTest.java diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java index 48dbe69428..a3210608b7 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java @@ -70,11 +70,12 @@ public class AzureManagementApiMetadata extends BaseHttpApiMetadata>builder() - .add(AzureComputeServiceContextModule.class) .add(OAuthModule.class) .add(OkHttpCommandExecutorServiceModule.class) .add(AzureComputeParserModule.class) - .add(AzureComputeHttpApiModule.class).build()); + .add(AzureComputeHttpApiModule.class) + .add(AzureComputeServiceContextModule.class) + .build()); } @Override 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 7df8111afa..6033f42150 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,72 +16,69 @@ */ 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 com.google.inject.Provides; - +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.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.compute.strategy.AzurePopulateDefaultLoginCredentialsForImageStrategy; +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.Location; -import org.jclouds.azurecompute.arm.compute.strategy.CreateResourceGroupThenCreateNodes; -import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance; import org.jclouds.azurecompute.arm.functions.ParseJobStatus; -import org.jclouds.compute.options.TemplateOptions; +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.strategy.CreateNodesInGroupThenAddToSet; -import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; 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 static org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATION_TIMEOUT; +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; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATION_POLL_INITIAL_PERIOD; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATION_POLL_MAX_PERIOD; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATION_TIMEOUT; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.RESOURCE_GROUP_NAME; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TCP_RULE_FORMAT; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TCP_RULE_REGEXP; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.RESOURCE_GROUP_NAME; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_IMAGE_LOGIN; -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.TIMEOUT_RESOURCE_DELETED; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_DATADISKSIZE; - -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; -import static org.jclouds.util.Predicates2.retry; -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED; import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_IMAGE_AVAILABLE; - -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 java.util.List; - - -import org.jclouds.compute.extensions.ImageExtension; -import org.jclouds.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy; -import org.jclouds.azurecompute.arm.compute.AzureComputeService; -import org.jclouds.compute.ComputeService; -import org.jclouds.logging.Logger; +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 { @@ -209,38 +206,31 @@ public class AzureComputeServiceContextModule @Provides @Named(TIMEOUT_NODE_TERMINATED) - protected Predicate provideNodeTerminatedPredicate(final AzureComputeApi api, Timeouts timeouts, - PollPeriod pollPeriod) { + protected Predicate provideNodeTerminatedPredicate(final AzureComputeApi api, Timeouts timeouts, PollPeriod pollPeriod) { return retry(new ActionDonePredicate(api), timeouts.nodeTerminated, pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); } @Provides @Named(TIMEOUT_IMAGE_AVAILABLE) - protected Predicate provideImageAvailablePredicate(final AzureComputeApi api, Timeouts timeouts, - PollPeriod pollPeriod) { + protected Predicate provideImageAvailablePredicate(final AzureComputeApi api, Timeouts timeouts, PollPeriod pollPeriod) { return retry(new ImageDonePredicate(api), timeouts.imageAvailable, pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); } @Provides @Named(TIMEOUT_RESOURCE_DELETED) - protected Predicate provideResourceDeletedPredicate(final AzureComputeApi api, Timeouts timeouts, - PollPeriod pollPeriod) { + protected Predicate provideResourceDeletedPredicate(final AzureComputeApi api, Timeouts timeouts, PollPeriod pollPeriod) { return retry(new ActionDonePredicate(api), timeouts.nodeTerminated, pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); } @Provides @Named(TIMEOUT_NODE_SUSPENDED) - protected Predicate provideNodeSuspendedPredicate(final AzureComputeApi api, - final AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants, - Timeouts timeouts, - PollPeriod pollPeriod) { - + 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 NodeSuspendedPredicate(api, azureGroup), timeouts.nodeSuspended, pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); } @VisibleForTesting @@ -272,6 +262,7 @@ public class AzureComputeServiceContextModule @Override public boolean apply(URI uri) { checkNotNull(uri, "uri cannot be null"); + if (api.getJobApi().jobStatus(uri) != ParseJobStatus.JobStatus.DONE) return false; List definitions = api.getJobApi().captureStatus(uri); return definitions != null; } @@ -292,7 +283,9 @@ public class AzureComputeServiceContextModule public boolean apply(String name) { checkNotNull(name, "name cannot be null"); String status = ""; - List statuses = api.getVirtualMachineApi(this.azureGroup).getInstanceDetails(name).statuses(); + 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(); 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 550f8ea860..33c929a67c 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 @@ -16,35 +16,34 @@ */ package org.jclouds.azurecompute.arm.features; +import java.net.URI; +import java.util.List; + import javax.inject.Named; -import javax.ws.rs.DELETE; -import javax.ws.rs.POST; -import javax.ws.rs.Path; import javax.ws.rs.Consumes; -import javax.ws.rs.PUT; +import javax.ws.rs.DELETE; import javax.ws.rs.GET; -import javax.ws.rs.Produces; +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.Fallbacks.EmptyListOnNotFoundOr404; import org.jclouds.Fallbacks.NullOnNotFoundOr404; - import org.jclouds.azurecompute.arm.domain.Deployment; import org.jclouds.azurecompute.arm.functions.URIParser; import org.jclouds.oauth.v2.filters.OAuthFilter; -import org.jclouds.rest.annotations.QueryParams; -import org.jclouds.rest.annotations.RequestFilters; 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; -import java.net.URI; -import java.util.List; - /** * - create deployment * - delete deployment diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/URIParser.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/URIParser.java index 78fd10dadb..f67e7e295c 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/URIParser.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/URIParser.java @@ -15,12 +15,13 @@ * limitations under the License. */ package org.jclouds.azurecompute.arm.functions; -import com.google.common.base.Function; -import org.jclouds.http.HttpResponse; +import java.net.URI; import javax.inject.Singleton; -import java.net.URI; +import org.jclouds.http.HttpResponse; + +import com.google.common.base.Function; /** * Parses job status from http response */ @@ -31,7 +32,7 @@ public class URIParser implements Function { String uri = from.getFirstHeaderOrNull("Location"); return URI.create(uri); - } else if (from.getStatusCode() == 200){ + } else if (from.getStatusCode() == 200 || from.getStatusCode() == 204){ return null; } throw new IllegalStateException("did not receive expected response code and header in: " + from); 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 b579f6ab47..d6fdd3cf09 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 @@ -44,12 +44,14 @@ import org.testng.annotations.Test; 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.TIMEOUT_SCRIPT_COMPLETE; +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_PORT_OPEN; -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED; 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. @@ -90,6 +92,8 @@ public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest { properties.setProperty(TIMEOUT_NODE_TERMINATED, scriptTimeout + ""); properties.setProperty(TIMEOUT_NODE_SUSPENDED, scriptTimeout + ""); properties.put(RESOURCE_GROUP_NAME, "a4"); + properties.put(TEMPLATE, "locationId=westeurope"); + properties.put(IMAGE_PUBLISHERS, "Canonical"); AzureLiveTestUtils.defaultProperties(properties); checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); 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 652c12ad54..875624030e 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,7 +16,10 @@ */ package org.jclouds.azurecompute.arm.compute; -import com.google.inject.Module; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.TimeUnit; + import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; import org.jclouds.compute.internal.BaseTemplateBuilderLiveTest; @@ -24,11 +27,8 @@ import org.jclouds.providers.ProviderMetadata; import org.jclouds.sshj.config.SshjSshClientModule; import org.testng.annotations.Test; -import java.util.Properties; -import java.util.Set; -import java.util.concurrent.TimeUnit; - 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; @@ -41,7 +41,7 @@ public class AzureTemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest { @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"); + 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() { 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 7493a63f74..7476828384 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,14 +16,16 @@ */ package org.jclouds.azurecompute.arm.features; -import com.google.common.base.Predicate; -import com.google.common.net.UrlEscapers; +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.functions.ParseJobStatus; +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; @@ -39,25 +41,25 @@ 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; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; -import java.net.URI; -import java.util.List; +import com.google.common.base.Predicate; +import com.google.common.net.UrlEscapers; -import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; -@Test(groups = "live", testName = "DeploymentApiLiveTest", singleThreaded = true) +@Test(testName = "DeploymentApiLiveTest", singleThreaded = true) public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest { - private int maxTestDuration = 190; - private String resourceName; + private String resourceGroupName; private String deploymentName; - private String rawtemplate; - private String rawparameters; - private String rawbadParameters; + private String subnetId; + private String properties; private String badProperties; @@ -65,16 +67,37 @@ public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest { @Override public void setup() { super.setup(); - resourceName = getResourceGroupName(); - Long now = System.currentTimeMillis(); - deploymentName = "jc" + now; + resourceGroupName = String.format("rg-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); + assertNotNull(createResourceGroup(resourceGroupName)); + deploymentName = "jc" + System.currentTimeMillis(); + String virtualNetworkName = String.format("vn-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); + String storageAccountName = String.format("st%s%s", System.getProperty("user.name"), RAND); - rawtemplate = "{\"$schema\":\"https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\"contentVersion\":\"1.0.0.0\",\"parameters\":{\"newStorageAccountName\":{\"type\":\"string\",\"metadata\":{\"description\":\"Name of the Storage Account\"}},\"storageAccountType\":{\"type\":\"string\",\"defaultValue\":\"Standard_LRS\",\"allowedValues\":[\"Standard_LRS\",\"Standard_GRS\",\"Standard_ZRS\"],\"metadata\":{\"description\":\"Storage Account type\"}},\"location\":{\"type\":\"string\",\"allowedValues\":[\"East US\",\"West US\",\"West Europe\",\"East Asia\",\"Southeast Asia\"],\"metadata\":{\"description\":\"Location of storage account\"}}},\"resources\":[{\"type\":\"Microsoft.Storage/storageAccounts\",\"name\":\"[parameters('newStorageAccountName')]\",\"apiVersion\":\"2015-05-01-preview\",\"location\":\"[parameters('location')]\",\"properties\":{\"accountType\":\"[parameters('storageAccountType')]\"}}]}"; - rawparameters = "{\"newStorageAccountName\":{\"value\":\"" + resourceName + "\"},\"storageAccountType\":{\"value\":\"Standard_LRS\"},\"location\":{\"value\":\"West US\"}}"; - rawbadParameters = "{\"newStorageAccountName\":{\"value\":\"" + resourceName + "\"},\"storageAccountType\":{\"value\":\"Standard_LRS\"},\"location\":{\"value\":\"West\"}}"; + String rawtemplate = "{\"$schema\":\"https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\"contentVersion\":\"1.0.0.0\",\"parameters\":{\"newStorageAccountName\":{\"type\":\"string\",\"metadata\":{\"description\":\"Name of the Storage Account\"}},\"storageAccountType\":{\"type\":\"string\",\"defaultValue\":\"Standard_LRS\",\"allowedValues\":[\"Standard_LRS\",\"Standard_GRS\",\"Standard_ZRS\"],\"metadata\":{\"description\":\"Storage Account type\"}},\"location\":{\"type\":\"string\",\"allowedValues\":[\"East US\",\"West US\",\"West Europe\",\"East Asia\",\"Southeast Asia\"],\"metadata\":{\"description\":\"Location of storage account\"}}},\"resources\":[{\"type\":\"Microsoft.Storage/storageAccounts\",\"name\":\"[parameters('newStorageAccountName')]\",\"apiVersion\":\"2015-05-01-preview\",\"location\":\"[parameters('location')]\",\"properties\":{\"accountType\":\"[parameters('storageAccountType')]\"}}]}"; + String rawparameters = "{\"newStorageAccountName\":{\"value\":\"" + storageAccountName + "\"},\"storageAccountType\":{\"value\":\"Standard_LRS\"},\"location\":{\"value\":\"West US\"}}"; + String rawbadParameters = "{\"newStorageAccountName\":{\"value\":\"" + storageAccountName + "\"},\"storageAccountType\":{\"value\":\"Standard_LRS\"},\"location\":{\"value\":\"West\"}}"; properties = getPutBody(rawtemplate, "Incremental", rawparameters); badProperties = getPutBody(rawtemplate, "Incremental", rawbadParameters); + + //Subnets belong to a virtual network so that needs to be created first + VirtualNetwork vn = createDefaultVirtualNetwork(resourceGroupName, virtualNetworkName, "10.3.0.0/16", LOCATION); + assertNotNull(vn); + + //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.3.0.0/23"); + assertNotNull(subnet); + assertNotNull(subnet.id()); + subnetId = subnet.id(); + } + + @AfterClass + @Override + protected void tearDown() { + super.tearDown(); + URI uri = api.getResourceGroupApi().delete(resourceGroupName); + assertResourceDeleted(uri); } private String getPutBody(String template, String mode, String parameters) { @@ -91,7 +114,7 @@ public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest { 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("northeurope").description("North Europe").parent(provider).build(); + Location region = (new LocationBuilder()).scope(LocationScope.REGION).id(LOCATION).description("West Europe").parent(provider).build(); OperatingSystem os = OperatingSystem.builder() .family(OsFamily.UBUNTU) @@ -116,11 +139,11 @@ public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest { private DeploymentTemplateBuilder getDeploymentTemplateBuilderWithOptions(TemplateOptions options) { Template template = getTemplate(options); - DeploymentTemplateBuilder templateBuilder = api.deploymentTemplateFactory().create(resourceName, deploymentName, template); + DeploymentTemplateBuilder templateBuilder = api.deploymentTemplateFactory().create(resourceGroupName, deploymentName, template); return templateBuilder; } - @Test(groups = "live") + @Test public void testValidate(){ Deployment deploymentInvalid = null; try { @@ -138,12 +161,13 @@ public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest { } assertNotNull(deploymentValid); } - @Test(groups = "live") + @Test public void testCreate() { 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(); + AzureTemplateOptions options = new AzureTemplateOptions(); options.authorizePublicKey(rsakey); + options.subnetId(subnetId); DeploymentTemplateBuilder templateBuilder = getDeploymentTemplateBuilderWithOptions(options); DeploymentBody deploymentTemplateBody = templateBuilder.getDeploymentTemplate(); @@ -152,7 +176,6 @@ public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest { String deploymentTemplate = templateBuilder.getDeploymentTemplateJson(properties); deploymentTemplate = UrlEscapers.urlFormParameterEscaper().escape(deploymentTemplate); - Deployment deploymentValid = api().validate(deploymentName, deploymentTemplate); assertNotNull(deploymentValid); @@ -165,9 +188,10 @@ public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest { public boolean apply(String name) { Deployment dp = api().get(deploymentName); ProvisioningState state = ProvisioningState.fromValue(dp.properties().provisioningState()); + if (state == ProvisioningState.FAILED) Assert.fail(); return state == ProvisioningState.SUCCEEDED; } - }, 60 * maxTestDuration * 1000).apply(deploymentName); + }, 60 * 20 * 1000).apply(deploymentName); assertTrue(jobDone, "create operation did not complete in the configured timeout"); Deployment dp = api().get(deploymentName); @@ -176,7 +200,7 @@ public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest { } - @Test(groups = "live", dependsOnMethods = "testCreate") + @Test(dependsOnMethods = "testCreate") public void testGetDeployment() { Deployment deployment = api().get(deploymentName); assertNotNull(deployment); @@ -184,7 +208,7 @@ public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest { assertTrue(state == ProvisioningState.SUCCEEDED); } - @Test(groups = "live", dependsOnMethods = "testCreate") + @Test(dependsOnMethods = "testCreate") public void testListDeployments() { List deployments = api().list(); assertTrue(deployments.size() > 0); @@ -197,31 +221,20 @@ public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest { } } assertTrue(deploymentFound); - } - @Test(groups = "live", dependsOnMethods = {"testGetDeployment", "testListDeployments"}, alwaysRun = true) + @Test(dependsOnMethods = {"testGetDeployment", "testListDeployments"}) public void testDelete() throws Exception { List deployments = api().list(); for (Deployment d : deployments) { if (d.name().contains("jc")) { URI uri = api().delete(d.name()); - assertNotNull(uri); - assertTrue(uri.toString().contains("api-version")); - assertTrue(uri.toString().contains("operationresults")); - - boolean jobDone = Predicates2.retry(new Predicate() { - @Override - public boolean apply(URI uri) { - return ParseJobStatus.JobStatus.NO_CONTENT == api.getJobApi().jobStatus(uri); - } - }, 60 * maxTestDuration * 1000).apply(uri); - assertTrue(jobDone, "delete operation did not complete in the configured timeout"); + assertResourceDeleted(uri); } } } private DeploymentApi api() { - return api.getDeploymentApi(resourceName); + return api.getDeploymentApi(resourceGroupName); } } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LocationApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LocationApiLiveTest.java index fbfa88e26f..4e372949fd 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LocationApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LocationApiLiveTest.java @@ -16,6 +16,8 @@ */ package org.jclouds.azurecompute.arm.features; +import java.util.List; + import org.jclouds.azurecompute.arm.domain.Location; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; import org.testng.annotations.Test; @@ -28,10 +30,9 @@ public class LocationApiLiveTest extends BaseAzureComputeApiLiveTest { @Test public void testList() { - assertTrue(!api().list().isEmpty()); - - for (Location location : api().list()) { - assertTrue(!location.id().isEmpty()); + List locations = api().list(); + assertTrue(!locations.isEmpty()); + for (Location location : locations) { checkLocation(location); } } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiLiveTest.java index 34917acd38..0614d99620 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiLiveTest.java @@ -16,72 +16,64 @@ */ package org.jclouds.azurecompute.arm.features; -import com.google.common.collect.ImmutableMap; -import com.google.common.base.Predicate; +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + import org.jclouds.azurecompute.arm.domain.IdReference; import org.jclouds.azurecompute.arm.domain.IpConfiguration; import org.jclouds.azurecompute.arm.domain.IpConfigurationProperties; import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCardProperties; import org.jclouds.azurecompute.arm.domain.Subnet; -import org.jclouds.azurecompute.arm.domain.VirtualNetwork; -import org.jclouds.azurecompute.arm.functions.ParseJobStatus; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; -import org.jclouds.util.Predicates2; +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; -import java.net.URI; -import java.util.Arrays; -import java.util.List; -import java.util.Map; +import com.google.common.collect.ImmutableMap; - -import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; -import static org.testng.Assert.assertEquals; @Test(groups = "live", singleThreaded = true) public class NetworkInterfaceCardApiLiveTest extends BaseAzureComputeApiLiveTest { - private String resourcegroup; - private String subnetID; + private String resourceGroupName; + private String subnetId; + private String nicName; @BeforeClass @Override public void setup() { super.setup(); - - resourcegroup = getResourceGroupName(); + resourceGroupName = String.format("rg-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); + assertNotNull(api.getResourceGroupApi().create(resourceGroupName, LOCATION, ImmutableMap.of())); + String virtualNetworkName = String.format("vn-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); + nicName = String.format("nic-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); + String subnetName = String.format("s-%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 = getOrCreateVirtualNetwork(VIRTUAL_NETWORK_NAME); - assertNotNull(vn); + assertNotNull(createDefaultVirtualNetwork(resourceGroupName, virtualNetworkName, "10.2.0.0/16", LOCATION)); //Subnet needs to be up & running before NIC can be created - Subnet subnet = getOrCreateSubnet(DEFAULT_SUBNET_NAME, VIRTUAL_NETWORK_NAME); + Subnet subnet = createDefaultSubnet(resourceGroupName, subnetName, virtualNetworkName, "10.2.0.0/23"); assertNotNull(subnet); assertNotNull(subnet.id()); - subnetID = subnet.id(); + subnetId = subnet.id(); } - - @Test(groups = "live") - public void deleteNetworkInterfaceCardResourceDoesNotExist() { - - final NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(resourcegroup); - URI uri = nicApi.delete(NETWORKINTERFACECARD_NAME); - assertNull(uri); + @AfterClass + @Override + protected void tearDown() { + super.tearDown(); + deleteResourceGroup(resourceGroupName); } - @Test(groups = "live", dependsOnMethods = "deleteNetworkInterfaceCardResourceDoesNotExist") + @Test public void createNetworkInterfaceCard() { - - final NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(resourcegroup); - - - //Create properties object //Create properties object final NetworkInterfaceCardProperties networkInterfaceCardProperties = NetworkInterfaceCardProperties.builder().ipConfigurations( @@ -89,66 +81,48 @@ public class NetworkInterfaceCardApiLiveTest extends BaseAzureComputeApiLiveTest .name("myipconfig") .properties(IpConfigurationProperties.builder() .privateIPAllocationMethod("Dynamic") - .subnet(IdReference.create(subnetID)).build() + .subnet(IdReference.create(subnetId)).build() ).build() )).build(); final Map tags = ImmutableMap.of("jclouds", "livetest"); - NetworkInterfaceCard nic = nicApi.createOrUpdate(NETWORKINTERFACECARD_NAME, LOCATION, networkInterfaceCardProperties, tags); + NetworkInterfaceCard nic = api().createOrUpdate(nicName, LOCATION, networkInterfaceCardProperties, tags); - assertEquals(nic.name(), NETWORKINTERFACECARD_NAME); + assertEquals(nic.name(), nicName); assertEquals(nic.location(), LOCATION); assertTrue(nic.properties().ipConfigurations().size() > 0); assertEquals(nic.properties().ipConfigurations().get(0).name(), "myipconfig"); assertEquals(nic.properties().ipConfigurations().get(0).properties().privateIPAllocationMethod(), "Dynamic"); - assertEquals(nic.properties().ipConfigurations().get(0).properties().subnet().id(), subnetID); + assertEquals(nic.properties().ipConfigurations().get(0).properties().subnet().id(), subnetId); assertEquals(nic.tags().get("jclouds"), "livetest"); - } - @Test(groups = "live", dependsOnMethods = "createNetworkInterfaceCard") + @Test(dependsOnMethods = "createNetworkInterfaceCard") public void getNetworkInterfaceCard() { + NetworkInterfaceCard nic = api().get(nicName); - final NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(resourcegroup); - - NetworkInterfaceCard nic = nicApi.get(NETWORKINTERFACECARD_NAME); - - assertEquals(nic.name(), NETWORKINTERFACECARD_NAME); + assertEquals(nic.name(), nicName); assertEquals(nic.location(), LOCATION); assertTrue(nic.properties().ipConfigurations().size() > 0); assertEquals(nic.properties().ipConfigurations().get(0).name(), "myipconfig"); assertEquals(nic.properties().ipConfigurations().get(0).properties().privateIPAllocationMethod(), "Dynamic"); - assertEquals(nic.properties().ipConfigurations().get(0).properties().subnet().id(), subnetID); + assertEquals(nic.properties().ipConfigurations().get(0).properties().subnet().id(), subnetId); } - @Test(groups = "live", dependsOnMethods = "createNetworkInterfaceCard") + @Test(dependsOnMethods = "createNetworkInterfaceCard") public void listNetworkInterfaceCards() { - - final NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(resourcegroup); - - List nicList = nicApi.list(); - - assertTrue(nicList.contains(nicApi.get(NETWORKINTERFACECARD_NAME))); + List nicList = api().list(); + assertTrue(nicList.contains(api().get(nicName))); } - - @Test(groups = "live", dependsOnMethods = {"listNetworkInterfaceCards", "getNetworkInterfaceCard"}, alwaysRun = true) + @Test(dependsOnMethods = {"listNetworkInterfaceCards", "getNetworkInterfaceCard"}) public void deleteNetworkInterfaceCard() { + URI uri = api().delete(nicName); + assertResourceDeleted(uri); + } - final NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(resourcegroup); - URI uri = nicApi.delete(NETWORKINTERFACECARD_NAME); - if (uri != null) { - assertTrue(uri.toString().contains("api-version")); - assertTrue(uri.toString().contains("operationresults")); - - boolean jobDone = Predicates2.retry(new Predicate() { - @Override - public boolean apply(URI uri) { - return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri); - } - }, 60 * 2 * 1000 /* 2 minute timeout */).apply(uri); - assertTrue(jobDone, "delete operation did not complete in the configured timeout"); - } + private NetworkInterfaceCardApi api() { + return api.getNetworkInterfaceCardApi(resourceGroupName); } } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApiLiveTest.java index 095c0e26a3..b66b1505cb 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApiLiveTest.java @@ -16,99 +16,72 @@ */ package org.jclouds.azurecompute.arm.features; -import com.google.common.base.Predicate; +import java.net.URI; +import java.util.List; + import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; -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.NetworkSecurityRuleProperties.Access; -import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Direction; -import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Protocol; -import org.jclouds.azurecompute.arm.functions.ParseJobStatus; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; - -import org.jclouds.util.Predicates2; +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; - -import java.util.ArrayList; -import java.util.List; -import java.net.URI; - -import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; -import static org.testng.AssertJUnit.assertNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; @Test(groups = "live", singleThreaded = true) public class NetworkSecurityGroupApiLiveTest extends BaseAzureComputeApiLiveTest { - private String resourcegroup; - private static String DEFAULT_NSG_NAME = "testNetworkSecurityGroup"; - - private NetworkSecurityGroup createGroup() { - NetworkSecurityRule rule = NetworkSecurityRule.create("denyallout", null, null, - NetworkSecurityRuleProperties.builder() - .description("deny all out") - .protocol(Protocol.Tcp) - .sourcePortRange("*") - .destinationPortRange("*") - .sourceAddressPrefix("*") - .destinationAddressPrefix("*") - .access(Access.Deny) - .priority(4095) - .direction(Direction.Outbound) - .build()); - ArrayList ruleList = new ArrayList(); - ruleList.add(rule); - NetworkSecurityGroup nsg = NetworkSecurityGroup.create("samplensg", "westus", null, - NetworkSecurityGroupProperties.builder() - .securityRules(ruleList) - .build(), - null); - return nsg; - } + private String resourceGroupName; + private static String nsgName = "testNetworkSecurityGroup"; @BeforeClass @Override public void setup() { super.setup(); - resourcegroup = getResourceGroupName(); + resourceGroupName = String.format("rg-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); + assertNotNull(createResourceGroup(resourceGroupName)); + nsgName = String.format("nsg-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); } - @Test(groups = "live") + @AfterClass + @Override + protected void tearDown() { + super.tearDown(); + URI uri = deleteResourceGroup(resourceGroupName); + assertResourceDeleted(uri); + } + + @Test public void deleteNetworkSecurityGroupDoesNotExist() { - final NetworkSecurityGroupApi nsgApi = api.getNetworkSecurityGroupApi(resourcegroup); - URI uri = nsgApi.delete(DEFAULT_NSG_NAME); + URI uri = api().delete(nsgName); assertNull(uri); } - @Test(groups = "live", dependsOnMethods = "deleteNetworkSecurityGroupDoesNotExist") + @Test(dependsOnMethods = "deleteNetworkSecurityGroupDoesNotExist") public void createNetworkSecurityGroup() { - final NetworkSecurityGroup nsg = createGroup(); + final NetworkSecurityGroup nsg = newNetworkSecurityGroup(nsgName, LOCATION); assertNotNull(nsg); - final NetworkSecurityGroupApi nsgApi = api.getNetworkSecurityGroupApi(resourcegroup); - NetworkSecurityGroup result = nsgApi.createOrUpdate(DEFAULT_NSG_NAME, + NetworkSecurityGroup result = api().createOrUpdate(nsgName, nsg.location(), nsg.tags(), nsg.properties()); assertNotNull(result); } - @Test(groups = "live", dependsOnMethods = "createNetworkSecurityGroup") + @Test(dependsOnMethods = "createNetworkSecurityGroup") public void listNetworkSecurityGroups() { - final NetworkSecurityGroupApi nsgApi = api.getNetworkSecurityGroupApi(resourcegroup); - List result = nsgApi.list(); + List result = api().list(); // verify we have something assertNotNull(result); assertEquals(result.size(), 1); // check that the nework security group matches the one we originally passed in - NetworkSecurityGroup original = createGroup(); + NetworkSecurityGroup original = newNetworkSecurityGroup(nsgName, LOCATION); NetworkSecurityGroup nsg = result.get(0); assertEquals(original.name(), nsg.name()); assertEquals(original.location(), nsg.location()); @@ -122,31 +95,23 @@ public class NetworkSecurityGroupApiLiveTest extends BaseAzureComputeApiLiveTest assertTrue(originalRule.properties().equals(nsgRule.properties())); } - @Test(groups = "live", dependsOnMethods = {"listNetworkSecurityGroups", "getNetworkSecurityGroup"}, alwaysRun = true) + @Test(dependsOnMethods = {"listNetworkSecurityGroups", "getNetworkSecurityGroup"}, alwaysRun = true) public void deleteNetworkSecurityGroup() { - final NetworkSecurityGroupApi nsgApi = api.getNetworkSecurityGroupApi(resourcegroup); - URI uri = nsgApi.delete(DEFAULT_NSG_NAME); - if (uri != null) { - assertTrue(uri.toString().contains("api-version")); - assertTrue(uri.toString().contains("operationresults")); - - boolean jobDone = Predicates2.retry(new Predicate() { - @Override - public boolean apply(URI uri) { - return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri); - } - }, 60 * 2 * 1000 /* 2 minute timeout */).apply(uri); - assertTrue(jobDone, "delete operation did not complete in the configured timeout"); - } + URI uri = api().delete(nsgName); + assertResourceDeleted(uri); } - @Test(groups = "live", dependsOnMethods = "createNetworkSecurityGroup") + @Test(dependsOnMethods = "createNetworkSecurityGroup") public void getNetworkSecurityGroup() { - final NetworkSecurityGroupApi nsgApi = api.getNetworkSecurityGroupApi(resourcegroup); - NetworkSecurityGroup nsg = nsgApi.get(DEFAULT_NSG_NAME); + NetworkSecurityGroup nsg = api().get(nsgName); assertNotNull(nsg); assertNotNull(nsg.etag()); - assertEquals(nsg.name(), DEFAULT_NSG_NAME); + assertEquals(nsg.name(), nsgName); } + + private NetworkSecurityGroupApi api() { + return api.getNetworkSecurityGroupApi(resourceGroupName); + } + } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityRuleApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityRuleApiLiveTest.java index fbcd2b46df..dba70630f4 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityRuleApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityRuleApiLiveTest.java @@ -16,160 +16,104 @@ */ package org.jclouds.azurecompute.arm.features; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; +import java.net.URI; +import java.util.List; + import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; -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.NetworkSecurityRuleProperties.Access; import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Direction; import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Protocol; -import org.jclouds.azurecompute.arm.functions.ParseJobStatus; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; - -import org.jclouds.util.Predicates2; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; @Test(groups = "live", singleThreaded = true) public class NetworkSecurityRuleApiLiveTest extends BaseAzureComputeApiLiveTest { - private String resourcegroup; - private static String DEFAULT_NSG_NAME = "testNetworkSecurityGroup"; + private String resourceGroupName; private static String UNKNOWN_RULE_NAME = "ruledoesntexist"; - - private NetworkSecurityGroup createGroup() { - NetworkSecurityRule rule = NetworkSecurityRule.create("denyallout", null, null, - NetworkSecurityRuleProperties.builder() - .description("deny all out") - .protocol(Protocol.Tcp) - .sourcePortRange("*") - .destinationPortRange("*") - .sourceAddressPrefix("*") - .destinationAddressPrefix("*") - .access(Access.Deny) - .priority(4095) - .direction(Direction.Outbound) - .build()); - ArrayList ruleList = new ArrayList(); - ruleList.add(rule); - NetworkSecurityGroup nsg = NetworkSecurityGroup.create("samplensg", "westus", null, - NetworkSecurityGroupProperties.builder() - .securityRules(ruleList) - .build(), - null); - return nsg; - } - - private NetworkSecurityRule createRule() { - NetworkSecurityRule rule = NetworkSecurityRule.create("allowalludpin", null, null, - NetworkSecurityRuleProperties.builder() - .description("allow all udp in") - .protocol(Protocol.Udp) - .sourcePortRange("*") - .destinationPortRange("*") - .sourceAddressPrefix("*") - .destinationAddressPrefix("*") - .access(Access.Allow) - .priority(4094) - .direction(Direction.Inbound) - .build()); - return rule; - } + private String nsgName; @BeforeClass @Override public void setup() { super.setup(); - resourcegroup = getResourceGroupName(); + resourceGroupName = String.format("rg-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); + assertNotNull(createResourceGroup(resourceGroupName)); + nsgName = String.format("nsg-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); // a network security group is needed - final NetworkSecurityGroup nsg = createGroup(); - final NetworkSecurityGroupApi nsgApi = api.getNetworkSecurityGroupApi(resourcegroup); - NetworkSecurityGroup result = nsgApi.createOrUpdate(DEFAULT_NSG_NAME, + final NetworkSecurityGroup nsg = newNetworkSecurityGroup(nsgName, LOCATION); + assertNotNull(api.getNetworkSecurityGroupApi(resourceGroupName).createOrUpdate(nsgName, nsg.location(), nsg.tags(), - nsg.properties()); + nsg.properties())); } - @AfterClass(alwaysRun = true) + @AfterClass @Override - public void tearDown() { - // remove the security group we created - final NetworkSecurityGroupApi nsgApi = api.getNetworkSecurityGroupApi(resourcegroup); - URI uri = nsgApi.delete(DEFAULT_NSG_NAME); - if (uri != null) { - boolean jobDone = Predicates2.retry(new Predicate() { - @Override - public boolean apply(URI uri) { - return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri); - } - }, 60 * 2 * 1000 /* 2 minute timeout */).apply(uri); - } - + protected void tearDown() { super.tearDown(); + URI uri = deleteResourceGroup(resourceGroupName); + assertResourceDeleted(uri); } - @Test(groups = "live") + @Test public void deleteNetworkSecurityRuleDoesNotExist() { - final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); - URI uri = ruleApi.delete(UNKNOWN_RULE_NAME); + URI uri = api().delete(UNKNOWN_RULE_NAME); assertNull(uri); } - @Test(groups = "live", dependsOnMethods = "deleteNetworkSecurityRuleDoesNotExist") + @Test(dependsOnMethods = "deleteNetworkSecurityRuleDoesNotExist") public void createNetworkSecurityRule() { final NetworkSecurityRule rule = createRule(); assertNotNull(rule); - final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); + final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourceGroupName, nsgName); NetworkSecurityRule result = ruleApi.createOrUpdate(rule.name(), rule.properties()); assertNotNull(result); assertEquals(result.name(), rule.name()); } - @Test(groups = "live", dependsOnMethods = "createNetworkSecurityRule") + @Test(dependsOnMethods = "createNetworkSecurityRule") public void getNetworkSecurityRule() { final NetworkSecurityRule rule = createRule(); assertNotNull(rule); - final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); - NetworkSecurityRule result = ruleApi.get(rule.name()); + NetworkSecurityRule result = api().get(rule.name()); assertNotNull(result); assertNotNull(result.etag()); assertEquals(result.name(), rule.name()); } - @Test(groups = "live", dependsOnMethods = "createNetworkSecurityRule") + @Test(dependsOnMethods = "createNetworkSecurityRule") public void getNetworkSecurityDefaultRule() { String defaultRuleName = "AllowVnetInBound"; - final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); - NetworkSecurityRule result = ruleApi.getDefaultRule(defaultRuleName); + NetworkSecurityRule result = api().getDefaultRule(defaultRuleName); assertNotNull(result); assertNotNull(result.etag()); assertEquals(result.name(), defaultRuleName); } - @Test(groups = "live", dependsOnMethods = "createNetworkSecurityRule") + @Test(dependsOnMethods = "createNetworkSecurityRule") public void listNetworkSecurityRules() { final NetworkSecurityRule rule = createRule(); assertNotNull(rule); - final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); - List result = ruleApi.list(); + List result = api().list(); assertNotNull(result); assertEquals(result.size(), 2); @@ -183,34 +127,40 @@ public class NetworkSecurityRuleApiLiveTest extends BaseAzureComputeApiLiveTest assertTrue(rulePresent); } - @Test(groups = "live", dependsOnMethods = "createNetworkSecurityRule") + @Test(dependsOnMethods = "createNetworkSecurityRule") public void listDefaultSecurityRules() { - final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); - List result = ruleApi.listDefaultRules(); - + List result = api().listDefaultRules(); assertNotNull(result); assertTrue(result.size() > 0); } - @Test(groups = "live", dependsOnMethods = {"listNetworkSecurityRules", "listDefaultSecurityRules", "getNetworkSecurityRule"}, alwaysRun = true) + @Test(dependsOnMethods = {"listNetworkSecurityRules", "listDefaultSecurityRules", "getNetworkSecurityRule"}) public void deleteNetworkSecurityRule() { final NetworkSecurityRule rule = createRule(); assertNotNull(rule); - final NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourcegroup, DEFAULT_NSG_NAME); - URI uri = ruleApi.delete(rule.name()); - if (uri != null) { - assertTrue(uri.toString().contains("api-version")); - assertTrue(uri.toString().contains("operationresults")); + URI uri = api().delete(rule.name()); + assertResourceDeleted(uri); + } - boolean jobDone = Predicates2.retry(new Predicate() { - @Override - public boolean apply(URI uri) { - return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri); - } - }, 60 * 2 * 1000 /* 2 minute timeout */).apply(uri); - assertTrue(jobDone, "delete operation did not complete in the configured timeout"); - } + private NetworkSecurityRule createRule() { + NetworkSecurityRule rule = NetworkSecurityRule.create("allowalludpin", null, null, + NetworkSecurityRuleProperties.builder() + .description("allow all udp in") + .protocol(Protocol.Udp) + .sourcePortRange("*") + .destinationPortRange("*") + .sourceAddressPrefix("*") + .destinationAddressPrefix("*") + .access(Access.Allow) + .priority(4094) + .direction(Direction.Inbound) + .build()); + return rule; + } + + private NetworkSecurityRuleApi api() { + return api.getNetworkSecurityRuleApi(resourceGroupName, nsgName); } } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/OSImageApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/OSImageApiLiveTest.java index 6ceb0d4f7d..07566434ae 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/OSImageApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/OSImageApiLiveTest.java @@ -16,18 +16,19 @@ */ package org.jclouds.azurecompute.arm.features; +import java.util.List; + 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.internal.AbstractAzureComputeApiLiveTest; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; import org.testng.annotations.Test; + import static org.testng.Assert.assertTrue; -import java.util.List; - @Test(groups = "live", testName = "OSImageApiLiveTest") -public class OSImageApiLiveTest extends AbstractAzureComputeApiLiveTest { +public class OSImageApiLiveTest extends BaseAzureComputeApiLiveTest { @Test public void testPublisher() { diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApiLiveTest.java index 544323532d..98819c1374 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApiLiveTest.java @@ -16,42 +16,54 @@ */ package org.jclouds.azurecompute.arm.features; -import com.google.common.collect.ImmutableMap; +import java.net.URI; +import java.util.List; +import java.util.Map; + import org.jclouds.azurecompute.arm.domain.PublicIPAddress; import org.jclouds.azurecompute.arm.domain.PublicIPAddressProperties; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; import org.jclouds.util.Predicates2; -import com.google.common.base.Predicate; +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; -import java.util.List; -import java.util.Map; +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableMap; -import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; - +import static org.testng.Assert.assertTrue; @Test(groups = "live", singleThreaded = true) public class PublicIPAddressApiLiveTest extends BaseAzureComputeApiLiveTest { + private String resourceGroupName; private final String publicIpAddressName = "myipaddress"; - private final String subscriptionid = getSubscriptionId(); - private String resourcegroup; + private String subscriptionid; @BeforeClass @Override public void setup() { super.setup(); - resourcegroup = getResourceGroupName(); + resourceGroupName = String.format("rg-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); + assertNotNull(createResourceGroup(resourceGroupName)); + subscriptionid = getSubscriptionId(); + } + + @AfterClass + @Override + protected void tearDown() { + super.tearDown(); + URI uri = deleteResourceGroup(resourceGroupName); + assertResourceDeleted(uri); } @Test(groups = "live") public void deletePublicIPAddressResourceDoesNotExist() { - final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourcegroup); + final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourceGroupName); boolean status = ipApi.delete(publicIpAddressName); assertFalse(status); } @@ -59,7 +71,7 @@ public class PublicIPAddressApiLiveTest extends BaseAzureComputeApiLiveTest { @Test(groups = "live", dependsOnMethods = "deletePublicIPAddressResourceDoesNotExist") public void createPublicIPAddress() { - final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourcegroup); + final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourceGroupName); final Map tags = ImmutableMap.of("testkey", "testvalue"); @@ -74,7 +86,7 @@ public class PublicIPAddressApiLiveTest extends BaseAzureComputeApiLiveTest { assertNotNull(ip); assertEquals(ip.name(), publicIpAddressName); assertEquals(ip.location(), LOCATION); - assertEquals(ip.id(), String.format("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/publicIPAddresses/%s", subscriptionid, resourcegroup, publicIpAddressName)); + assertEquals(ip.id(), String.format("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/publicIPAddresses/%s", subscriptionid, resourceGroupName, publicIpAddressName)); assertEquals(ip.tags().get("testkey"), "testvalue"); assertNotNull(ip.properties()); assertEquals(ip.properties().provisioningState(), "Updating"); @@ -86,7 +98,7 @@ public class PublicIPAddressApiLiveTest extends BaseAzureComputeApiLiveTest { @Test(groups = "live", dependsOnMethods = "createPublicIPAddress") public void getPublicIPAddress() { - final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourcegroup); + final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourceGroupName); //Poll until resource is ready to be used boolean jobDone = Predicates2.retry(new Predicate() { @@ -100,7 +112,7 @@ public class PublicIPAddressApiLiveTest extends BaseAzureComputeApiLiveTest { assertNotNull(ip); assertEquals(ip.name(), publicIpAddressName); assertEquals(ip.location(), LOCATION); - assertEquals(ip.id(), String.format("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/publicIPAddresses/%s", subscriptionid, resourcegroup, publicIpAddressName)); + assertEquals(ip.id(), String.format("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/publicIPAddresses/%s", subscriptionid, resourceGroupName, publicIpAddressName)); assertEquals(ip.tags().get("testkey"), "testvalue"); assertNotNull(ip.properties()); assertEquals(ip.properties().provisioningState(), "Succeeded"); @@ -112,7 +124,7 @@ public class PublicIPAddressApiLiveTest extends BaseAzureComputeApiLiveTest { @Test(groups = "live", dependsOnMethods = "createPublicIPAddress") public void listPublicIPAddresses() { - final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourcegroup); + final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourceGroupName); List ipList = ipApi.list(); @@ -121,7 +133,7 @@ public class PublicIPAddressApiLiveTest extends BaseAzureComputeApiLiveTest { @Test(groups = "live", dependsOnMethods = {"listPublicIPAddresses", "getPublicIPAddress"}, alwaysRun = true) public void deletePublicIPAddress() { - final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourcegroup); + final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourceGroupName); boolean status = ipApi.delete(publicIpAddressName); assertTrue(status); } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiLiveTest.java index f9ad6ccb6b..3a0c134343 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiLiveTest.java @@ -16,38 +16,27 @@ */ package org.jclouds.azurecompute.arm.features; -import com.google.common.base.Predicate; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Iterables; - import java.net.URI; import java.util.List; import org.jclouds.azurecompute.arm.domain.ResourceGroup; -import org.jclouds.azurecompute.arm.functions.ParseJobStatus.JobStatus; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; - import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; + +import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; -import static org.testng.Assert.assertEquals; -import org.jclouds.util.Predicates2; - @Test(groups = "live", testName = "ResourceGroupApiLiveTest") public class ResourceGroupApiLiveTest extends BaseAzureComputeApiLiveTest { - private String resourcegroup; - @BeforeClass - @Override - public void setup(){ - super.setup(); - resourcegroup = getResourceGroupName(); - } + private static final String RESOURCE_GROUP_NAME = "jcloudstest"; private ResourceGroupApi api() { return api.getResourceGroupApi(); @@ -63,26 +52,26 @@ public class ResourceGroupApiLiveTest extends BaseAzureComputeApiLiveTest { @Override public boolean apply(final ResourceGroup group) { - return resourcegroup.equals(group.name()); + return RESOURCE_GROUP_NAME.equals(group.name()); } })); } @Test(dependsOnMethods = "testCreate") public void testRead() { - final ResourceGroup group = api().get(resourcegroup); - assertNotNull(group); - assertEquals(group.name(), resourcegroup); - assertEquals(group.location(), LOCATION); + final ResourceGroup resourceGroup = api().get(RESOURCE_GROUP_NAME); + assertNotNull(resourceGroup); + assertEquals(resourceGroup.name(), RESOURCE_GROUP_NAME); + assertEquals(resourceGroup.location(), LOCATION); } public void testCreate() { - final ResourceGroup resourceGroup = api().create("jcloudstest", LOCATION, null); - assertEquals(resourceGroup.name(), "jcloudstest"); + final ResourceGroup resourceGroup = api().create(RESOURCE_GROUP_NAME, LOCATION, null); + assertEquals(resourceGroup.name(), RESOURCE_GROUP_NAME); assertEquals(resourceGroup.location(), LOCATION); assertNull(resourceGroup.tags()); - assertTrue(resourceGroup.id().contains("jcloudstest")); + assertTrue(resourceGroup.id().contains(RESOURCE_GROUP_NAME)); assertEquals(resourceGroup.properties().provisioningState(), "Succeeded"); } @@ -90,7 +79,7 @@ public class ResourceGroupApiLiveTest extends BaseAzureComputeApiLiveTest { public void testUpdateWithEmptyTag() { ImmutableMap tags = ImmutableMap.builder().build(); - final ResourceGroup resourceGroup = api().update("jcloudstest", tags); + final ResourceGroup resourceGroup = api().update(RESOURCE_GROUP_NAME, tags); assertEquals(resourceGroup.tags().size(), 0); assertEquals(resourceGroup.properties().provisioningState(), "Succeeded"); @@ -100,7 +89,7 @@ public class ResourceGroupApiLiveTest extends BaseAzureComputeApiLiveTest { public void testUpdateWithTag() { ImmutableMap tags = ImmutableMap.builder().put("test1", "value1").build(); - final ResourceGroup resourceGroup = api().update("jcloudstest", tags); + final ResourceGroup resourceGroup = api().update(RESOURCE_GROUP_NAME, tags); assertEquals(resourceGroup.tags().size(), 1); assertEquals(resourceGroup.properties().provisioningState(), "Succeeded"); @@ -108,31 +97,7 @@ public class ResourceGroupApiLiveTest extends BaseAzureComputeApiLiveTest { @AfterClass(alwaysRun = true) public void testDelete() throws Exception { - URI uri = api().delete("jcloudstest"); - - if (uri != null){ - assertTrue(uri.toString().contains("api-version")); - assertTrue(uri.toString().contains("operationresults")); - - boolean jobDone = Predicates2.retry(new Predicate() { - @Override public boolean apply(URI uri) { - return JobStatus.DONE == api.getJobApi().jobStatus(uri); - } - }, 60 * 2 * 1000 /* 1 minute timeout */).apply(uri); - assertTrue(jobDone, "delete operation did not complete in the configured timeout"); - } - - uri = api().delete("jcloudstest"); - if (uri != null){ - assertTrue(uri.toString().contains("api-version")); - assertTrue(uri.toString().contains("operationresults")); - - boolean jobDone = Predicates2.retry(new Predicate() { - @Override public boolean apply(URI uri) { - return JobStatus.DONE == api.getJobApi().jobStatus(uri); - } - }, 60 * 1 * 1000 /* 1 minute timeout */).apply(uri); - assertTrue(jobDone, "delete operation did not complete in the configured timeout"); - } + URI uri = api().delete(RESOURCE_GROUP_NAME); + assertResourceDeleted(uri); } } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceProviderApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceProviderApiLiveTest.java index 5ebf99646c..59ca114182 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceProviderApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceProviderApiLiveTest.java @@ -16,18 +16,18 @@ */ package org.jclouds.azurecompute.arm.features; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; +import java.util.List; + import org.jclouds.azurecompute.arm.domain.ResourceProviderMetaData; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; import org.testng.annotations.Test; -import java.util.List; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; - @Test(groups = "live", testName = "ResourceProviderApiLiveTest") public class ResourceProviderApiLiveTest extends BaseAzureComputeApiLiveTest { diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiLiveTest.java index 6eb13ddfdf..c88ebdc740 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiLiveTest.java @@ -16,18 +16,21 @@ */ package org.jclouds.azurecompute.arm.features; -import com.google.common.base.Predicate; -import com.google.common.collect.ImmutableMap; +import java.net.URI; +import java.util.List; + 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.functions.ParseJobStatus; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; import org.jclouds.util.Predicates2; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; -import java.net.URI; -import java.util.List; +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableMap; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; @@ -41,13 +44,22 @@ public class StorageAccountApiLiveTest extends BaseAzureComputeApiLiveTest { private static final String NAME = String.format("%3.24s", RAND + StorageAccountApiLiveTest.class.getSimpleName().toLowerCase()); - private void check(final StorageService storage) { - assertNotNull(storage.id()); - assertNotNull(storage.name()); - assertNotNull(storage.storageServiceProperties()); - assertNotNull(storage.storageServiceProperties().accountType()); - assertFalse(storage.storageServiceProperties().primaryEndpoints().isEmpty()); - assertNotNull(storage.storageServiceProperties().creationTime()); + private String resourceGroupName; + + @BeforeClass + @Override + public void setup() { + super.setup(); + resourceGroupName = String.format("rg-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); + assertNotNull(createResourceGroup(resourceGroupName)); + } + + @AfterClass + @Override + protected void tearDown() { + super.tearDown(); + URI uri = deleteResourceGroup(resourceGroupName); + assertResourceDeleted(uri); } @Test(dependsOnMethods = "testCreate") @@ -117,6 +129,7 @@ public class StorageAccountApiLiveTest extends BaseAzureComputeApiLiveTest { assertTrue(params.tags().containsKey("another_property_name")); assertNull(params.storageServiceProperties().accountType()); } + @Test(dependsOnMethods = {"testCreate", "testGet"}) public void testUpdateAccountType() { StorageServiceUpdateParams.StorageServiceUpdateProperties props = @@ -127,7 +140,16 @@ public class StorageAccountApiLiveTest extends BaseAzureComputeApiLiveTest { assertEquals(params.storageServiceProperties().accountType(), StorageService.AccountType.Standard_GRS); } + private void check(final StorageService storage) { + assertNotNull(storage.id()); + assertNotNull(storage.name()); + assertNotNull(storage.storageServiceProperties()); + assertNotNull(storage.storageServiceProperties().accountType()); + assertFalse(storage.storageServiceProperties().primaryEndpoints().isEmpty()); + assertNotNull(storage.storageServiceProperties().creationTime()); + } + private StorageAccountApi api() { - return api.getStorageAccountApi(getResourceGroupName()); + return api.getStorageAccountApi(resourceGroupName); } } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/SubnetApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/SubnetApiLiveTest.java index 9eaf990544..8d1d505289 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/SubnetApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/SubnetApiLiveTest.java @@ -16,89 +16,87 @@ */ package org.jclouds.azurecompute.arm.features; -import org.jclouds.azurecompute.arm.domain.Subnet; +import java.util.List; +import org.jclouds.azurecompute.arm.domain.Subnet; import org.jclouds.azurecompute.arm.domain.VirtualNetwork; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; - +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; -import java.util.List; - import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; @Test(groups = "live", singleThreaded = true) public class SubnetApiLiveTest extends BaseAzureComputeApiLiveTest { - private final String subscriptionid = "subscriptionid"; - private String resourcegroup; + private String resourceGroupName; + private String virtualNetworkName; + private String subnetName; @BeforeClass @Override public void setup() { super.setup(); - resourcegroup = getResourceGroupName(); + 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")); + subnetName = "jclouds-" + RAND; // Subnets belong to a virtual network so that needs to be created first // VN will be deleted when resource group is deleted - VirtualNetwork vn = getOrCreateVirtualNetwork(VIRTUAL_NETWORK_NAME); + VirtualNetwork vn = createDefaultVirtualNetwork(resourceGroupName, virtualNetworkName, "10.2.0.0/16", LOCATION); assertNotNull(vn); } - @Test(groups = "live") - public void deleteSubnetResourceDoesNotExist() { - - final SubnetApi subnetApi = api.getSubnetApi(resourcegroup, VIRTUAL_NETWORK_NAME); - - boolean status = subnetApi.delete(DEFAULT_SUBNET_NAME); - assertFalse(status); - + @AfterClass + @Override + protected void tearDown() { + super.tearDown(); + deleteResourceGroup(resourceGroupName); } - @Test(groups = "live", dependsOnMethods = "deleteSubnetResourceDoesNotExist") + @Test + public void deleteSubnetResourceDoesNotExist() { + assertFalse(api().delete(subnetName)); + } + + @Test(dependsOnMethods = "deleteSubnetResourceDoesNotExist") public void createSubnet() { - - final SubnetApi subnetApi = api.getSubnetApi(resourcegroup, VIRTUAL_NETWORK_NAME); - //Create properties object //addressPrefix must match Virtual network address space! - Subnet.SubnetProperties properties = Subnet.SubnetProperties.builder().addressPrefix(DEFAULT_SUBNET_ADDRESS_SPACE).build(); + Subnet.SubnetProperties properties = Subnet.SubnetProperties.builder().addressPrefix("10.2.0.0/23").build(); - Subnet subnet = subnetApi.createOrUpdate(DEFAULT_SUBNET_NAME, properties); + Subnet subnet = api().createOrUpdate(subnetName, properties); - assertEquals(subnet.name(), DEFAULT_SUBNET_NAME); - assertEquals(subnet.properties().addressPrefix(), DEFAULT_SUBNET_ADDRESS_SPACE); + assertEquals(subnet.name(), subnetName); + assertEquals(subnet.properties().addressPrefix(), "10.2.0.0/23"); } - @Test(groups = "live", dependsOnMethods = "createSubnet") + @Test(dependsOnMethods = "createSubnet") public void getSubnet() { - - final SubnetApi subnetApi = api.getSubnetApi(resourcegroup, VIRTUAL_NETWORK_NAME); - Subnet subnet = subnetApi.get(DEFAULT_SUBNET_NAME); - + Subnet subnet = api().get(subnetName); assertNotNull(subnet.name()); assertNotNull(subnet.properties().addressPrefix()); } - @Test(groups = "live", dependsOnMethods = "createSubnet") + @Test(dependsOnMethods = "createSubnet") public void listSubnets() { - - final SubnetApi subnetApi = api.getSubnetApi(resourcegroup, VIRTUAL_NETWORK_NAME); - List subnets = subnetApi.list(); - + List subnets = api().list(); assertTrue(subnets.size() > 0); } - @Test(groups = "live", dependsOnMethods = {"listSubnets", "getSubnet"}, alwaysRun = true) + @Test(dependsOnMethods = {"listSubnets", "getSubnet"}, alwaysRun = true) public void deleteSubnet() { - - final SubnetApi subnetApi = api.getSubnetApi(resourcegroup, VIRTUAL_NETWORK_NAME); - boolean status = subnetApi.delete(DEFAULT_SUBNET_NAME); + boolean status = api().delete(subnetName); assertTrue(status); } + private SubnetApi api() { + return api.getSubnetApi(resourceGroupName, virtualNetworkName); + } + } 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 index 12d62556cf..3b876636e1 100644 --- 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 @@ -16,7 +16,8 @@ */ package org.jclouds.azurecompute.arm.features; -import com.google.common.net.UrlEscapers; +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; @@ -37,9 +38,12 @@ 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; @@ -48,30 +52,42 @@ public class TemplateToDeploymentTemplateLiveTest extends BaseAzureComputeApiLiv private int maxTestDuration = 400; private int pollingInterval = 3; // how frequently to poll for create status - private String resourceGroup; + private String resourceGroupName; private String deploymentName; private String vnetName; private String subnetId; + private String virtualNetworkName; @BeforeClass @Override public void setup() { super.setup(); - resourceGroup = getResourceGroupName(); + 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 = getOrCreateVirtualNetwork(VIRTUAL_NETWORK_NAME); + 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 - Subnet subnet = getOrCreateSubnet(DEFAULT_SUBNET_NAME, VIRTUAL_NETWORK_NAME); + 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(); } - @Test(groups = "live") + @AfterClass + @Override + protected void tearDown() { + super.tearDown(); + URI uri = deleteResourceGroup(resourceGroupName); + assertResourceDeleted(uri); + } + + @Test public void testValidateDeploymentTemplateLinuxNodeWithOptions() { Long now = System.currentTimeMillis(); deploymentName = "jc" + now; @@ -96,7 +112,7 @@ public class TemplateToDeploymentTemplateLiveTest extends BaseAzureComputeApiLiv assertNotNull(deployment); } - @Test(groups = "live") + @Test public void testValidateDeploymentTemplateLinuxNode() { Long now = System.currentTimeMillis(); deploymentName = "jc" + now; @@ -115,7 +131,7 @@ public class TemplateToDeploymentTemplateLiveTest extends BaseAzureComputeApiLiv assertNotNull(deployment); } - @Test(groups = "live") + @Test public void testValidateDeploymentTemplateWithCustomOptions() { Long now = System.currentTimeMillis(); deploymentName = "jc" + now; @@ -143,7 +159,7 @@ public class TemplateToDeploymentTemplateLiveTest extends BaseAzureComputeApiLiv assertNotNull(deployment); } - @Test(groups = "live") + @Test public void testValidateDeploymentTemplateLinuxNodeWithSSH() { Long now = System.currentTimeMillis(); deploymentName = "jc" + now; @@ -168,7 +184,7 @@ public class TemplateToDeploymentTemplateLiveTest extends BaseAzureComputeApiLiv assertNotNull(deployment); } - @Test(groups = "live") + @Test public void testCreateDeploymentTemplateLinuxNode() { Long now = System.currentTimeMillis(); deploymentName = "jc" + now; @@ -249,17 +265,17 @@ public class TemplateToDeploymentTemplateLiveTest extends BaseAzureComputeApiLiv options.subnetId(subnetId); Template template = getTemplate(options); - DeploymentTemplateBuilder templateBuilder = api.deploymentTemplateFactory().create(resourceGroup, deploymentName, template); + DeploymentTemplateBuilder templateBuilder = api.deploymentTemplateFactory().create(resourceGroupName, deploymentName, template); return templateBuilder; } private DeploymentTemplateBuilder getDeploymentTemplateBuilderWithOptions(TemplateOptions options) { Template template = getTemplate(options); - DeploymentTemplateBuilder templateBuilder = api.deploymentTemplateFactory().create(resourceGroup, deploymentName, template); + DeploymentTemplateBuilder templateBuilder = api.deploymentTemplateFactory().create(resourceGroupName, deploymentName, template); return templateBuilder; } private DeploymentApi api() { - return api.getDeploymentApi(resourceGroup); + return api.getDeploymentApi(resourceGroupName); } } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VMSizeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VMSizeApiLiveTest.java index fdd6ce9f34..90e258bc5e 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VMSizeApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VMSizeApiLiveTest.java @@ -35,6 +35,6 @@ public class VMSizeApiLiveTest extends BaseAzureComputeApiLiveTest { } private VMSizeApi api() { - return api.getVMSizeApi(getLocation()); + return api.getVMSizeApi(LOCATION); } } 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 5271e2a258..27023701b0 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,105 +16,113 @@ */ package org.jclouds.azurecompute.arm.features; -import com.google.common.base.Predicate; -import com.google.gson.internal.LinkedTreeMap; -import com.google.common.collect.Iterables; +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + 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.IpConfiguration; +import org.jclouds.azurecompute.arm.domain.IpConfigurationProperties; 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.ResourceDefinition; import org.jclouds.azurecompute.arm.domain.StorageProfile; import org.jclouds.azurecompute.arm.domain.StorageService; +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.VirtualMachineProperties; -import org.jclouds.azurecompute.arm.functions.ParseJobStatus; -import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; -import org.jclouds.util.Predicates2; -import org.jclouds.azurecompute.arm.domain.ResourceDefinition; import org.testng.Assert; +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; -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_SCRIPT_COMPLETE; -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING; -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_PORT_OPEN; -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED; -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; +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 java.net.URI; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; -import java.util.concurrent.TimeUnit; - import static org.testng.Assert.assertTrue; @Test(groups = "live", testName = "VirtualMachineApiLiveTest") public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { - private String subscriptionid = getSubscriptionId(); - private String vmName = null; - private String nicName = null; + private String subscriptionid; + private String resourceGroupName; + private String storageServiceName; + private String vmName; + private String nicName; + private StorageService storageService; + private String virtualNetworkName; + private String subnetId; @BeforeClass - public void Setup() { - NetworkInterfaceCard nic = getOrCreateNetworkInterfaceCard(NETWORKINTERFACECARD_NAME); + @Override + public void setup() { + super.setup(); + subscriptionid = getSubscriptionId(); + + 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")); + + storageServiceName = String.format("st%s%s", System.getProperty("user.name"), RAND); + storageService = createStorageService(resourceGroupName, storageServiceName, LOCATION); + + // Subnets belong to a virtual network so that needs to be created first + assertNotNull(createDefaultVirtualNetwork(resourceGroupName, virtualNetworkName, "10.2.0.0/16", LOCATION)); + + //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(); + + NetworkInterfaceCard nic = createNetworkInterfaceCard(resourceGroupName, "jc-nic-" + RAND, LOCATION, "ipConfig-" + RAND); assertNotNull(nic); nicName = nic.name(); + + vmName = String.format("%3.24s", System.getProperty("user.name") + RAND + this.getClass().getSimpleName()).toLowerCase().substring(0, 15); } + @AfterClass @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, getResourceGroupName()); - - AzureLiveTestUtils.defaultProperties(properties); - checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); - - return properties; - } - - private String getName() { - if (vmName == null) { - vmName = String.format("%3.24s", - System.getProperty("user.name") + RAND + this.getClass().getSimpleName()).toLowerCase().substring(0, 15); - } - return vmName; + protected void tearDown() { + super.tearDown(); + URI deleteResourceGroupURI = deleteResourceGroup(resourceGroupName); + assertResourceDeleted(deleteResourceGroupURI); } @Test public void testCreate() { - StorageAccountApi storageApi = api.getStorageAccountApi(getResourceGroupName()); - StorageService storageAccount = storageApi.get(getStorageServiceName()); - String blob = storageAccount.storageServiceProperties().primaryEndpoints().get("blob"); + String blob = storageService.storageServiceProperties().primaryEndpoints().get("blob"); - VirtualMachine vm = api().create(getName(), LOCATION, getProperties(blob, nicName)); + VirtualMachine vm = api().create(vmName, LOCATION, getProperties(blob, nicName)); assertTrue(!vm.name().isEmpty()); //Poll until resource is ready to be used - boolean jobDone = Predicates2.retry(new Predicate() { + boolean jobDone = retry(new Predicate() { @Override public boolean apply(String name) { return !api().get(name).properties().provisioningState().equals("Creating"); } - }, 60 * 20 * 1000).apply(getName()); + }, 60 * 20 * 1000).apply(vmName); assertTrue(jobDone, "create operation did not complete in the configured timeout"); String status = api().get(vmName).properties().provisioningState(); @@ -125,91 +133,40 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { @Test(dependsOnMethods = "testCreate") public void testGet() { - VirtualMachine vm = api().get(getName()); + VirtualMachine vm = api().get(vmName); assertTrue(!vm.name().isEmpty()); } @Test(dependsOnMethods = "testCreate") public void testGetInstanceView() { - VirtualMachineInstance vmi = api().getInstanceDetails(getName()); + VirtualMachineInstance vmi = api().getInstanceDetails(vmName); assertTrue(!vmi.statuses().isEmpty()); } @Test(dependsOnMethods = "testStart") public void testStop() { - api().stop(getName()); - //Poll until resource is ready to be used - nodeSuspendedPredicate.apply(getName()); + api().stop(vmName); + assertTrue(stateReached("PowerState", "VM stopped"), "stop operation did not complete in the configured timeout"); } @Test(dependsOnMethods = "testGet") public void testStart() { - api().start(getName()); - - //Poll until resource is ready to be used - boolean jobDone = Predicates2.retry(new Predicate() { - @Override - public boolean apply(String name) { - String status = ""; - List statuses = api().getInstanceDetails(name).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 running"); - } - }, 60 * 4 * 1000).apply(getName()); - assertTrue(jobDone, "start operation did not complete in the configured timeout"); - + api().start(vmName); + assertTrue(stateReached("PowerState", "VM running"), "start operation did not complete in the configured timeout"); } @Test(dependsOnMethods = "testStop") public void testRestart() { - api().start(getName()); - - //Poll until resource is ready to be used - boolean jobDone = Predicates2.retry(new Predicate() { - @Override - public boolean apply(String name) { - String status = ""; - List statuses = api().getInstanceDetails(name).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 running"); - } - }, 60 * 4 * 1000).apply(getName()); - assertTrue(jobDone, "start operation did not complete in the configured timeout"); - - api().restart(getName()); - - //Poll until resource is ready to be used - jobDone = Predicates2.retry(new Predicate() { - @Override - public boolean apply(String name) { - String status = ""; - List statuses = api().getInstanceDetails(name).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 running"); - } - }, 60 * 4 * 1000).apply(getName()); - assertTrue(jobDone, "restart operation did not complete in the configured timeout"); + api().start(vmName); + assertTrue(stateReached("PowerState", "VM 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"); } @Test(dependsOnMethods = "testCreate") public void testList() { List list = api().list(); - final VirtualMachine vm = api().get(getName()); + final VirtualMachine vm = api().get(vmName); boolean vmPresent = Iterables.any(list, new Predicate() { public boolean apply(VirtualMachine input) { @@ -222,34 +179,30 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { @Test(dependsOnMethods = "testRestart") public void testGeneralize() throws IllegalStateException { - api().stop(getName()); - //Poll until resource is ready to be used - - if (nodeSuspendedPredicate.apply(getName())) { - api().generalize(getName()); - } + api().stop(vmName); + assertTrue(stateReached("PowerState", "VM stopped"), "restart operation did not complete in the configured timeout"); + api().generalize(vmName); } @Test(dependsOnMethods = "testGeneralize") public void testCapture() throws IllegalStateException { - URI uri = api().capture(getName(), getName(), getName()); - 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); + URI uri = api().capture(vmName, vmName, vmName); + if (uri == null) Assert.fail(); + 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); - Assert.assertNotNull(osProperties.get("name")); - Assert.assertNotNull(datadiskObject.get("name")); - } + Assert.assertNotNull(osProperties.get("name")); + Assert.assertNotNull(datadiskObject.get("name")); } } } @@ -257,23 +210,12 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { @Test(dependsOnMethods = "testCapture", alwaysRun = true) public void testDelete() throws Exception { - URI uri = api().delete(getName()); - - if (uri != null) { - assertTrue(uri.toString().contains("api-version")); - - boolean jobDone = Predicates2.retry(new Predicate() { - @Override - public boolean apply(URI uri) { - return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri); - } - }, 60 * 8 * 1000 /* 2 minutes timeout */).apply(uri); - assertTrue(jobDone, "delete operation did not complete in the configured timeout"); - } + URI uri = api().delete(vmName); + assertResourceDeleted(uri); } private VirtualMachineApi api() { - return api.getVirtualMachineApi(getResourceGroupName()); + return api.getVirtualMachineApi(resourceGroupName); } private VirtualMachineProperties getProperties(String blob, String nic) { @@ -281,19 +223,19 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { HardwareProfile hwProf = HardwareProfile.create("Standard_D1"); ImageReference imgRef = ImageReference.create("MicrosoftWindowsServerEssentials", "WindowsServerEssentials", "WindowsServerEssentials", "latest"); - VHD vhd = VHD.create(blob + "vhds/" + getName() + ".vhd"); - VHD vhd2 = VHD.create(blob + "vhds/" + getName() + "data.vhd"); - DataDisk dataDisk = DataDisk.create(getName() + "data", "100", 0, vhd2, "Empty"); + VHD vhd = VHD.create(blob + "vhds/" + vmName + ".vhd"); + VHD vhd2 = VHD.create(blob + "vhds/" + vmName + "data.vhd"); + DataDisk dataDisk = DataDisk.create(vmName + "data", "100", 0, vhd2, "Empty"); List dataDisks = new ArrayList(); dataDisks.add(dataDisk); - OSDisk osDisk = OSDisk.create(null, getName(), vhd, "ReadWrite", "FromImage", null); + OSDisk osDisk = OSDisk.create(null, vmName, vhd, "ReadWrite", "FromImage", null); StorageProfile storageProfile = StorageProfile.create(imgRef, osDisk, dataDisks); OSProfile.WindowsConfiguration windowsConfig = OSProfile.WindowsConfiguration.create(false, null, null, true, null); - OSProfile osProfile = OSProfile.create(getName(), "azureuser", "RFe3&432dg", null, null, windowsConfig); + OSProfile osProfile = OSProfile.create(vmName, "azureuser", "RFe3&432dg", null, null, windowsConfig); IdReference networkInterface = IdReference.create("/subscriptions/" + subscriptionid + - "/resourceGroups/" + getResourceGroupName() + "/providers/Microsoft.Network/networkInterfaces/" + "/resourceGroups/" + resourceGroupName + "/providers/Microsoft.Network/networkInterfaces/" + nic); List networkInterfaces = new ArrayList(); @@ -306,4 +248,51 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { null, null, hwProf, storageProfile, osProfile, networkProfile, diagnosticsProfile, "Creating"); return properties; } + + protected NetworkInterfaceCard createNetworkInterfaceCard(final String resourceGroupName, String networkInterfaceCardName, String locationName, String ipConfigurationName) { + //Create properties object + final NetworkInterfaceCardProperties networkInterfaceCardProperties = + NetworkInterfaceCardProperties.builder() + .ipConfigurations(Arrays.asList(IpConfiguration.create(ipConfigurationName, null, null, null, + IpConfigurationProperties.create(null, null, "Dynamic", IdReference.create(subnetId), null)) + )).build(); + + final Map tags = ImmutableMap.of("jclouds", "livetest"); + 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 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) { + return retry(new Predicate() { + @Override + public boolean apply(String name) { + return waitForState(name, state, displayStatus); + } + }, 60 * 4 * 1000).apply(vmName); + } } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApiLiveTest.java index 71ad0b030b..7f59678ddf 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApiLiveTest.java @@ -16,87 +16,84 @@ */ package org.jclouds.azurecompute.arm.features; -import org.jclouds.azurecompute.arm.domain.VirtualNetwork; -import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; - -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - import java.util.Arrays; import java.util.List; +import org.jclouds.azurecompute.arm.domain.VirtualNetwork; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; @Test(groups = "live", singleThreaded = true) public class VirtualNetworkApiLiveTest extends BaseAzureComputeApiLiveTest { - private final String subscriptionid = "subscriptionid"; - private String resourcegroup; + private String resourceGroupName; + private String virtualNetworkName; @BeforeClass @Override public void setup() { super.setup(); - resourcegroup = getResourceGroupName(); + 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")); } - @Test(groups = "live") + @AfterClass + @Override + protected void tearDown() { + super.tearDown(); + deleteResourceGroup(resourceGroupName); + } + + @Test public void deleteVirtualNetworkResourceDoesNotExist() { - - final VirtualNetworkApi vnApi = api.getVirtualNetworkApi(resourcegroup); - - boolean status = vnApi.delete(VIRTUAL_NETWORK_NAME); + boolean status = api().delete(virtualNetworkName); assertFalse(status); - } - @Test(groups = "live", dependsOnMethods = "deleteVirtualNetworkResourceDoesNotExist") + @Test(dependsOnMethods = "deleteVirtualNetworkResourceDoesNotExist") public void createVirtualNetwork() { - final VirtualNetworkApi vnApi = api.getVirtualNetworkApi(resourcegroup); - - //Create properties object - final VirtualNetwork.VirtualNetworkProperties virtualNetworkProperties = VirtualNetwork.VirtualNetworkProperties.builder().addressSpace( VirtualNetwork.AddressSpace.create(Arrays.asList(DEFAULT_VIRTUALNETWORK_ADDRESS_PREFIX))).build(); - VirtualNetwork vn = vnApi.createOrUpdate(VIRTUAL_NETWORK_NAME, LOCATION, virtualNetworkProperties); + VirtualNetwork vn = api().createOrUpdate(virtualNetworkName, LOCATION, virtualNetworkProperties); - assertEquals(VIRTUAL_NETWORK_NAME, vn.name()); - assertEquals(LOCATION, vn.location()); + assertEquals(vn.name(), virtualNetworkName); + assertEquals(vn.location(), LOCATION); } - @Test(groups = "live", dependsOnMethods = "createVirtualNetwork") + @Test(dependsOnMethods = "createVirtualNetwork") public void getVirtualNetwork() { - - final VirtualNetworkApi vnApi = api.getVirtualNetworkApi(resourcegroup); - VirtualNetwork vn = vnApi.get(VIRTUAL_NETWORK_NAME); + VirtualNetwork vn = api().get(virtualNetworkName); assertNotNull(vn.name()); assertNotNull(vn.location()); assertNotNull(vn.properties().addressSpace().addressPrefixes()); } - @Test(groups = "live", dependsOnMethods = "createVirtualNetwork") + @Test(dependsOnMethods = "createVirtualNetwork") public void listVirtualNetworks() { - - final VirtualNetworkApi vnApi = api.getVirtualNetworkApi(resourcegroup); - List vnList = vnApi.list(); - + List vnList = api().list(); assertTrue(vnList.size() > 0); } - @Test(groups = "live", dependsOnMethods = {"listVirtualNetworks", "getVirtualNetwork"}, alwaysRun = true) + @Test(dependsOnMethods = {"listVirtualNetworks", "getVirtualNetwork"}, alwaysRun = true) public void deleteVirtualNetwork() { - - final VirtualNetworkApi vnApi = api.getVirtualNetworkApi(resourcegroup); - - boolean status = vnApi.delete(VIRTUAL_NETWORK_NAME); + boolean status = api().delete(virtualNetworkName); assertTrue(status); } + private VirtualNetworkApi api() { + return api.getVirtualNetworkApi(resourceGroupName); + } + } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AbstractAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AbstractAzureComputeApiLiveTest.java deleted file mode 100644 index f3134b70d6..0000000000 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AbstractAzureComputeApiLiveTest.java +++ /dev/null @@ -1,80 +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.internal; - -import static com.google.common.base.Preconditions.checkNotNull; - -import java.net.URI; -import java.util.Properties; -import java.util.Random; - -import com.google.common.base.Predicate; -import com.google.inject.Module; -import com.google.inject.Injector; - - -import org.jclouds.apis.BaseApiLiveTest; -import org.jclouds.azurecompute.arm.AzureComputeApi; -import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; -import org.jclouds.providers.ProviderMetadata; -import com.google.inject.name.Names; -import com.google.inject.Key; -import com.google.inject.TypeLiteral; - -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_IMAGE_AVAILABLE; -import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; - - -public abstract class AbstractAzureComputeApiLiveTest extends BaseApiLiveTest { - - protected static final int RAND = new Random().nextInt(999); - protected Predicate nodeSuspendedPredicate; - protected Predicate imageAvailablePredicate; - - public AbstractAzureComputeApiLiveTest() { - provider = "azurecompute-arm"; - } - - @Override protected AzureComputeApi create(Properties props, Iterable modules) { - Injector injector = newBuilder().modules(modules).overrides(props).buildInjector(); - nodeSuspendedPredicate = injector.getInstance(Key.get(new TypeLiteral>() { - }, Names.named(TIMEOUT_NODE_SUSPENDED))); - imageAvailablePredicate = injector.getInstance(Key.get(new TypeLiteral>() { - }, Names.named(TIMEOUT_IMAGE_AVAILABLE))); - return injector.getInstance(AzureComputeApi.class); - } - - @Override protected Properties setupProperties() { - Properties properties = super.setupProperties(); - - // for oauth - AzureLiveTestUtils.defaultProperties(properties); - checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); - return properties; - } - - @Override - protected ProviderMetadata createProviderMetadata() { - AzureComputeProviderMetadata pm = AzureComputeProviderMetadata.builder().build(); - String endpoint = null; - if (System.getProperty("test.azurecompute-arm.endpoint") != null){ - endpoint = System.getProperty("test.azurecompute-arm.endpoint"); - pm.toBuilder().endpoint(endpoint); - } - return pm; - } -} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java index 0eec5254cb..bd7cde4f7a 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java @@ -15,210 +15,157 @@ * limitations under the License. */ package org.jclouds.azurecompute.arm.internal; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; - -import com.google.common.base.Predicate; -import com.google.common.collect.ImmutableMap; -import org.jclouds.azurecompute.arm.domain.IdReference; -import org.jclouds.azurecompute.arm.domain.IpConfiguration; -import org.jclouds.azurecompute.arm.domain.IpConfigurationProperties; -import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; -import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCardProperties; -import org.jclouds.azurecompute.arm.domain.ResourceGroup; - -import org.jclouds.azurecompute.arm.domain.StorageService; -import org.jclouds.azurecompute.arm.domain.Subnet; -import org.jclouds.azurecompute.arm.domain.VirtualNetwork; -import org.jclouds.azurecompute.arm.features.NetworkInterfaceCardApi; -import org.jclouds.azurecompute.arm.features.StorageAccountApi; -import org.jclouds.azurecompute.arm.features.SubnetApi; -import org.jclouds.azurecompute.arm.features.VirtualNetworkApi; -import org.jclouds.azurecompute.arm.functions.ParseJobStatus; -import org.jclouds.util.Predicates2; -import org.testng.Assert; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; import java.net.URI; import java.util.Arrays; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; +import java.util.List; +import java.util.Properties; +import java.util.Random; -public class BaseAzureComputeApiLiveTest extends AbstractAzureComputeApiLiveTest { +import org.jclouds.apis.BaseApiLiveTest; +import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; +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.ResourceGroup; +import org.jclouds.azurecompute.arm.domain.StorageService; +import org.jclouds.azurecompute.arm.domain.Subnet; +import org.jclouds.azurecompute.arm.domain.VirtualNetwork; +import org.jclouds.azurecompute.arm.functions.ParseJobStatus; + +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; +import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.Module; +import com.google.inject.TypeLiteral; +import com.google.inject.name.Names; + +import static com.google.common.base.Preconditions.checkNotNull; +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.util.Predicates2.retry; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +public class BaseAzureComputeApiLiveTest extends BaseApiLiveTest { + + protected static final int RAND = new Random().nextInt(999); public static final String LOCATION = "westeurope"; public static final String LOCATIONDESCRIPTION = "West Europe"; - - public static final String DEFAULT_SUBNET_ADDRESS_SPACE = "10.2.0.0/23"; - - public static final String VIRTUAL_NETWORK_NAME = "jclouds-virtual-network-live-test"; - - public static final String DEFAULT_SUBNET_NAME = "jclouds-1"; - public static final String DEFAULT_VIRTUALNETWORK_ADDRESS_PREFIX = "10.2.0.0/16"; - - public static final String NETWORKINTERFACECARD_NAME = "jcloudsNic"; - - private String resourceGroupName = null; - - private String virtualNetworkName = null; - - protected StorageService storageService; - - private String storageServiceName = null; - - protected String getStorageServiceName() { - if (storageServiceName == null) { - storageServiceName = String.format("%3.24s", - System.getProperty("user.name") + RAND + this.getClass().getSimpleName()).toLowerCase(); - } - return storageServiceName; + + protected Predicate imageAvailablePredicate; + protected Predicate resourceDeleted; + + public BaseAzureComputeApiLiveTest() { + provider = "azurecompute-arm"; } - protected String getLocation() { - return LOCATION; + @Override protected AzureComputeApi create(Properties props, Iterable modules) { + Injector injector = newBuilder().modules(modules).overrides(props).buildInjector(); + imageAvailablePredicate = injector.getInstance(Key.get(new TypeLiteral>() { + }, Names.named(TIMEOUT_IMAGE_AVAILABLE))); + resourceDeleted = injector.getInstance(Key.get(new TypeLiteral>() { + }, Names.named(TIMEOUT_RESOURCE_DELETED))); + return injector.getInstance(AzureComputeApi.class); } - protected String getEndpoint() { - String endpoint = null; - if (System.getProperty("test.azurecompute-arm.endpoint") != null) { - endpoint = System.getProperty("test.azurecompute-arm.endpoint"); - } - assertNotNull(endpoint); - return endpoint; + @Override protected Properties setupProperties() { + Properties properties = super.setupProperties(); + // for oauth + AzureLiveTestUtils.defaultProperties(properties); + checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); + return properties; + } + + protected void assertResourceDeleted(URI uri) { + assertNotNull(uri); + assertTrue(resourceDeleted.apply(uri), String.format("Resource %s was not terminated in the configured timeout", uri)); } - protected String getSubscriptionId() { - String subscriptionid = null; - String endpoint = null; - endpoint = getEndpoint(); - if (endpoint != null) { - subscriptionid = endpoint.substring(endpoint.lastIndexOf("/") + 1); - } - assertNotNull(subscriptionid); - return subscriptionid; + protected VirtualNetwork createDefaultVirtualNetwork(final String resourceGroupName, String virtualNetworkName, String virtualnetworkAddressPrefix, String location) { + final VirtualNetwork.VirtualNetworkProperties virtualNetworkProperties = + VirtualNetwork.VirtualNetworkProperties.create(null, null, + VirtualNetwork.AddressSpace.create(Arrays.asList(virtualnetworkAddressPrefix)), null); + VirtualNetwork virtualNetwork = api.getVirtualNetworkApi(resourceGroupName).createOrUpdate(virtualNetworkName, location, virtualNetworkProperties); + retry(new Predicate() { + @Override + public boolean apply(String name) { + VirtualNetwork virtualNetwork = api.getVirtualNetworkApi(resourceGroupName).get(name); + return virtualNetwork.properties().provisioningState().equals("Succeeded"); + } + }, 60 * 4 * 1000).apply(virtualNetwork.name()); + return virtualNetwork; } - protected String getResourceGroupName() { - if (resourceGroupName == null) { - resourceGroupName = String.format("%3.24s", - System.getProperty("user.name") + RAND + "groupjclouds"); - //createResourceGroup(resourceGroupName); - } - return resourceGroupName; + protected Subnet createDefaultSubnet(final String resourceGroupName, String subnetName, final String virtualNetworkName, String subnetAddressSpace) { + Subnet.SubnetProperties properties = Subnet.SubnetProperties.builder().addressPrefix(subnetAddressSpace).build(); + Subnet subnet = api.getSubnetApi(resourceGroupName, virtualNetworkName).createOrUpdate(subnetName, properties); + retry(new Predicate() { + @Override + public boolean apply(String name) { + Subnet subnet = api.getSubnetApi(resourceGroupName, virtualNetworkName).get(name); + return subnet.properties().provisioningState().equals("Succeeded"); + } + }, 60 * 4 * 1000).apply(subnet.name()); + return subnet; } - protected void createResourceGroup(String name) { - ImmutableMap tags = ImmutableMap.builder().build(); - - final ResourceGroup resourceGroup = api.getResourceGroupApi().create( - name, LOCATION, tags); - } - - private void deleteResourceGroup(String name) { - api.getResourceGroupApi().delete(name); - } - - - @BeforeClass - @Override - public void setup() { - super.setup(); - createResourceGroup(getResourceGroupName()); - storageService = getOrCreateStorageService(getStorageServiceName()); - } - - @AfterClass(alwaysRun = true) - @Override - protected void tearDown() { - super.tearDown(); - Boolean status = api.getStorageAccountApi(getResourceGroupName()).delete(getStorageServiceName()); - assertTrue(status.booleanValue()); - deleteResourceGroup(getResourceGroupName()); - } - - protected StorageService getOrCreateStorageService(String storageServiceName) { - StorageAccountApi storageApi = api.getStorageAccountApi(getResourceGroupName()); - StorageService ss = storageApi.get(storageServiceName); - if (ss != null) { - return ss; - } - URI uri = storageApi.create(storageServiceName, LOCATION, ImmutableMap.of("property_name", + protected StorageService createStorageService(String resourceGroupName, String storageServiceName, String location) { + URI uri = api.getStorageAccountApi(resourceGroupName).create(storageServiceName, location, ImmutableMap.of("property_name", "property_value"), ImmutableMap.of("accountType", StorageService.AccountType.Standard_LRS.toString())); - if (uri != null){ + if (uri != null) { assertTrue(uri.toString().contains("api-version")); - boolean jobDone = Predicates2.retry(new Predicate() { - @Override public boolean apply(URI uri) { + boolean jobDone = retry(new Predicate() { + @Override + public boolean apply(URI uri) { return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri); } }, 60 * 1 * 1000 /* 1 minute timeout */).apply(uri); assertTrue(jobDone, "create operation did not complete in the configured timeout"); } - ss = storageApi.get(storageServiceName); - Assert.assertEquals(ss.location(), LOCATION); - - Logger.getAnonymousLogger().log(Level.INFO, "created storageService: {0}", ss); - return ss; + return api.getStorageAccountApi(resourceGroupName).get(storageServiceName); } - protected VirtualNetwork getOrCreateVirtualNetwork(final String virtualNetworkName) { - - VirtualNetworkApi vnApi = api.getVirtualNetworkApi(getResourceGroupName()); - VirtualNetwork vn = vnApi.get(virtualNetworkName); - - if (vn != null) { - return vn; - } - - final VirtualNetwork.VirtualNetworkProperties virtualNetworkProperties = - VirtualNetwork.VirtualNetworkProperties.create(null, null, - VirtualNetwork.AddressSpace.create(Arrays.asList(DEFAULT_VIRTUALNETWORK_ADDRESS_PREFIX)), null); - - - vn = vnApi.createOrUpdate(VIRTUAL_NETWORK_NAME, LOCATION, virtualNetworkProperties); - this.virtualNetworkName = virtualNetworkName; - return vn; + protected ResourceGroup createResourceGroup(String resourceGroupName) { + return api.getResourceGroupApi().create(resourceGroupName, LOCATION, ImmutableMap.of()); } - protected Subnet getOrCreateSubnet(final String subnetName, final String virtualNetworkName){ - - SubnetApi subnetApi = api.getSubnetApi(getResourceGroupName(), virtualNetworkName); - Subnet subnet = subnetApi.get(subnetName); - - if (subnet != null){ - return subnet; - } - - Subnet.SubnetProperties properties = Subnet.SubnetProperties.builder().addressPrefix(DEFAULT_SUBNET_ADDRESS_SPACE).build(); - subnet = subnetApi.createOrUpdate(subnetName, properties); - - return subnet; + protected URI deleteResourceGroup(String resourceGroupName) { + return api.getResourceGroupApi().delete(resourceGroupName); } - protected NetworkInterfaceCard getOrCreateNetworkInterfaceCard(final String networkInterfaceCardName){ - - NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(getResourceGroupName()); - NetworkInterfaceCard nic = nicApi.get(networkInterfaceCardName); - - if (nic != null){ - return nic; - } - - VirtualNetwork vn = getOrCreateVirtualNetwork(VIRTUAL_NETWORK_NAME); - - Subnet subnet = getOrCreateSubnet(DEFAULT_SUBNET_NAME, VIRTUAL_NETWORK_NAME); - - //Create properties object - final NetworkInterfaceCardProperties networkInterfaceCardProperties = - NetworkInterfaceCardProperties.builder() - .ipConfigurations(Arrays.asList(IpConfiguration.create("myipconfig", null, null, null, - IpConfigurationProperties.create(null, null, "Dynamic", IdReference.create(subnet.id()), null)) - )).build(); - - final Map tags = ImmutableMap.of("jclouds", "livetest"); - nic = nicApi.createOrUpdate(NETWORKINTERFACECARD_NAME, LOCATION, networkInterfaceCardProperties, tags); - return nic; + protected NetworkSecurityGroup newNetworkSecurityGroup(String nsgName, String locationName) { + NetworkSecurityRule rule = NetworkSecurityRule.create("denyallout", null, null, + NetworkSecurityRuleProperties.builder() + .description("deny all out") + .protocol(NetworkSecurityRuleProperties.Protocol.Tcp) + .sourcePortRange("*") + .destinationPortRange("*") + .sourceAddressPrefix("*") + .destinationAddressPrefix("*") + .access(NetworkSecurityRuleProperties.Access.Deny) + .priority(4095) + .direction(NetworkSecurityRuleProperties.Direction.Outbound) + .build()); + List ruleList = Lists.newArrayList(); + ruleList.add(rule); + NetworkSecurityGroup nsg = NetworkSecurityGroup.create(nsgName, locationName, null, + NetworkSecurityGroupProperties.builder() + .securityRules(ruleList) + .build(), + null); + return nsg; } + + protected String getSubscriptionId() { + String subscriptionId = endpoint.substring(endpoint.lastIndexOf("/") + 1); + assertNotNull(subscriptionId); + return subscriptionId; + } + } From cd16826dcab5a8cf4f95d86d1277aaace473edbb Mon Sep 17 00:00:00 2001 From: Andrea Turli Date: Wed, 28 Sep 2016 18:20:26 +0200 Subject: [PATCH 24/87] Refactored Azure ARM to not use Deployments * Simplified ImageExtension * Fixed access to deployed VMS * Made api-version configurable for all apis" * Fixed all feature live tests * Fixed the AzureComputeServiceLiveTest * Fixed the AzureTemplateBuilderLiveTest * Fixed the AzureComputeImageExtensionLiveTest --- providers/azurecompute-arm/README.md | 6 +- providers/azurecompute-arm/pom.xml | 7 +- .../azurecompute/arm/AzureComputeApi.java | 17 +- .../arm/AzureComputeProviderMetadata.java | 68 ++- .../compute/AzureComputeServiceAdapter.java | 342 ++++++----- .../AzureComputeServiceContextModule.java | 187 +++--- .../AzureComputeImageExtension.java | 174 +++--- .../functions/DeploymentToNodeMetadata.java | 244 -------- .../functions/DeploymentToVMDeployment.java | 121 ---- .../ResourceDefinitionToCustomImage.java | 78 +++ .../arm/compute/functions/VMImageToImage.java | 78 +-- .../VirtualMachineToNodeMetadata.java | 279 +++++++++ .../compute/options/AzureTemplateOptions.java | 54 +- .../predicates/IsDeploymentInRegions.java | 1 + ...faultLoginCredentialsForImageStrategy.java | 43 -- .../CreateResourceGroupThenCreateNodes.java | 97 ++- .../arm/config/AzureComputeHttpApiModule.java | 3 - .../arm/config/AzureComputeProperties.java | 9 +- .../azurecompute/arm/domain/VMDeployment.java | 38 +- .../azurecompute/arm/domain/VMImage.java | 43 +- .../arm/domain/VirtualMachine.java | 7 +- .../arm/domain/VirtualMachineInstance.java | 51 +- .../arm/domain/VirtualMachineProperties.java | 27 +- .../arm/features/DeploymentApi.java | 5 +- .../azurecompute/arm/features/JobApi.java | 7 +- .../arm/features/LocationApi.java | 7 +- .../arm/features/NetworkInterfaceCardApi.java | 39 +- .../arm/features/NetworkSecurityGroupApi.java | 62 +- .../arm/features/NetworkSecurityRuleApi.java | 40 +- .../azurecompute/arm/features/OSImageApi.java | 5 +- .../arm/features/PublicIPAddressApi.java | 37 +- .../arm/features/ResourceGroupApi.java | 19 +- .../arm/features/ResourceProviderApi.java | 24 +- .../arm/features/StorageAccountApi.java | 37 +- .../azurecompute/arm/features/SubnetApi.java | 33 +- .../azurecompute/arm/features/VMSizeApi.java | 20 +- .../arm/features/VirtualMachineApi.java | 35 +- .../arm/features/VirtualNetworkApi.java | 35 +- .../arm/filters/ApiVersionFilter.java | 90 +++ .../arm/functions/CleanupResources.java | 202 +++--- .../StorageProfileToStorageAccountName.java | 38 ++ .../azurecompute/arm/util/BlobHelper.java | 84 ++- .../arm/util/DeploymentTemplateBuilder.java | 573 ------------------ .../azurecompute/arm/util/GetEnumValue.java | 1 - .../compute/AzureComputeServiceLiveTest.java | 76 ++- .../compute/AzureTemplateBuilderLiveTest.java | 49 +- .../AzureComputeImageExtensionLiveTest.java | 69 ++- .../arm/features/DeploymentApiLiveTest.java | 92 ++- .../DeploymentTemplateBuilderTest.java | 287 --------- .../NetworkSecurityGroupApiMockTest.java | 2 - .../features/PublicIPAddressApiMockTest.java | 3 +- .../features/ResourceProviderAPIMockTest.java | 1 - .../features/StorageAccountApiMockTest.java | 35 -- .../arm/features/SubnetApiMockTest.java | 17 +- .../TemplateToDeploymentTemplateLiveTest.java | 281 --------- .../features/VirtualMachineApiLiveTest.java | 71 +-- .../features/VirtualMachineApiMockTest.java | 47 +- .../features/VirtualNetworkApiMockTest.java | 2 +- .../arm/filters/ApiVersionFilterTest.java | 129 ++++ .../internal/BaseAzureComputeApiMockTest.java | 19 +- 60 files changed, 1912 insertions(+), 2635 deletions(-) delete mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/DeploymentToNodeMetadata.java delete mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/DeploymentToVMDeployment.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/ResourceDefinitionToCustomImage.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VirtualMachineToNodeMetadata.java delete mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/AzurePopulateDefaultLoginCredentialsForImageStrategy.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/filters/ApiVersionFilter.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/StorageProfileToStorageAccountName.java delete mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/DeploymentTemplateBuilder.java delete mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DeploymentTemplateBuilderTest.java delete mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/TemplateToDeploymentTemplateLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/filters/ApiVersionFilterTest.java 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) From 00d9138864e890978efb012898003b74f99be097 Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Fri, 14 Oct 2016 17:51:42 +0200 Subject: [PATCH 25/87] Create one resource group in each region --- .../arm/AzureComputeProviderMetadata.java | 6 +- .../compute/AzureComputeServiceAdapter.java | 264 +++++++++--------- .../AzureComputeServiceContextModule.java | 106 +++---- .../AzureComputeImageExtension.java | 41 +-- .../LocationToResourceGroupName.java | 46 +++ .../ResourceDefinitionToCustomImage.java | 15 +- .../VirtualMachineToNodeMetadata.java | 16 +- .../CreateResourceGroupThenCreateNodes.java | 12 +- .../arm/config/AzureComputeProperties.java | 2 - .../azurecompute/arm/domain/RegionAndId.java | 50 ++++ .../arm/functions/CleanupResources.java | 38 +-- .../compute/AzureComputeServiceLiveTest.java | 23 +- .../compute/AzureTemplateBuilderLiveTest.java | 14 +- .../AzureComputeImageExtensionLiveTest.java | 23 +- .../arm/internal/AzureLiveTestUtils.java | 25 +- 15 files changed, 382 insertions(+), 299 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToResourceGroupName.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/RegionAndId.java 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 a434079a0b..beac9259c7 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 @@ -25,12 +25,13 @@ import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_P 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.compute.config.ComputeServiceProperties.IMAGE_AUTHENTICATE_SUDO; import static org.jclouds.compute.config.ComputeServiceProperties.IMAGE_LOGIN_USER; +import static org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_DELIMITER; +import static org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_PREFIX; 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; @@ -88,9 +89,10 @@ 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, "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(RESOURCENAME_PREFIX, "jclouds"); + properties.put(RESOURCENAME_DELIMITER, "-"); properties.put(DEFAULT_DATADISKSIZE, "100"); properties.put(IMAGE_PUBLISHERS, "Canonical,RedHat"); // Default credentials for all images 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 0e2ed641f5..434c92f76c 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 @@ -30,11 +30,12 @@ import java.util.List; import java.util.Set; 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.config.AzureComputeServiceContextModule.PublicIpAvailablePredicateFactory; +import org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupName; import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; import org.jclouds.azurecompute.arm.domain.DataDisk; import org.jclouds.azurecompute.arm.domain.HardwareProfile; @@ -51,6 +52,8 @@ 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.RegionAndId; +import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.domain.ResourceProviderMetaData; import org.jclouds.azurecompute.arm.domain.SKU; import org.jclouds.azurecompute.arm.domain.StorageProfile; @@ -86,63 +89,67 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Lists; /** - * Defines the connection between the {@link AzureComputeApi} implementation and the jclouds - * {@link org.jclouds.compute.ComputeService}. + * Defines the connection between the {@link AzureComputeApi} implementation and + * the jclouds {@link org.jclouds.compute.ComputeService}. */ @Singleton public class AzureComputeServiceAdapter implements ComputeServiceAdapter { - private final String azureGroup; private final CleanupResources cleanupResources; private final AzureComputeApi api; private final AzureComputeConstants azureComputeConstants; private final Supplier> regionIds; - private final Predicate publicIpAvailable; + private final PublicIpAvailablePredicateFactory publicIpAvailable; + private final LocationToResourceGroupName locationToResourceGroupName; @Inject AzureComputeServiceAdapter(final AzureComputeApi api, final AzureComputeConstants azureComputeConstants, CleanupResources cleanupResources, @Region Supplier> regionIds, - @Named("PublicIpAvailable") Predicate publicIpAvailable) { + PublicIpAvailablePredicateFactory publicIpAvailable, LocationToResourceGroupName locationToResourceGroupName) { this.api = api; this.azureComputeConstants = azureComputeConstants; - this.azureGroup = azureComputeConstants.azureResourceGroup(); this.cleanupResources = cleanupResources; this.regionIds = regionIds; this.publicIpAvailable = publicIpAvailable; + this.locationToResourceGroupName = locationToResourceGroupName; } @Override - public NodeAndInitialCredentials createNodeWithGroupEncodedIntoName( - final String group, final String name, final Template template) { + public NodeAndInitialCredentials createNodeWithGroupEncodedIntoName(final String group, + final String name, final Template template) { AzureTemplateOptions templateOptions = template.getOptions().as(AzureTemplateOptions.class); + String azureGroup = locationToResourceGroupName.apply(template.getLocation().getId()); - // TODO Store group apart from the name to be able to identify nodes with custom names in the configured group + // 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); + NetworkInterfaceCard nic = createNetworkInterfaceCard(subnetId, name, locationName, azureGroup); 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(); + 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(); + .licenseType(null) // TODO + .availabilitySet(null) // TODO + .hardwareProfile(hardwareProfile).storageProfile(storageProfile).osProfile(osProfile) + .networkProfile(networkProfile).build(); - VirtualMachine virtualMachine = api.getVirtualMachineApi(azureGroup).create(name, template.getLocation().getId(), virtualMachineProperties); + VirtualMachine virtualMachine = api.getVirtualMachineApi(azureGroup).create(name, template.getLocation().getId(), + virtualMachineProperties); - // 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); + // 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. + RegionAndId regionAndId = RegionAndId.fromRegionAndId(template.getLocation().getId(), name); + return new NodeAndInitialCredentials(virtualMachine, regionAndId.slashEncode(), null); } @Override @@ -150,16 +157,11 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter hwProfiles = Lists.newArrayList(); for (Location location : listLocations()) { Iterable vmSizes = api.getVMSizeApi(location.name()).list(); - for (VMSize vmSize : vmSizes){ - VMHardware hwProfile = VMHardware.create( - vmSize.name(), - vmSize.numberOfCores(), - vmSize.osDiskSizeInMB(), - vmSize.resourceDiskSizeInMB(), - vmSize.memoryInMB(), - vmSize.maxDataDiskCount(), - location.name(), - false); + for (VMSize vmSize : vmSizes) { + VMHardware hwProfile = VMHardware + .create(vmSize.name(), vmSize.numberOfCores(), vmSize.osDiskSizeInMB(), + vmSize.resourceDiskSizeInMB(), vmSize.memoryInMB(), vmSize.maxDataDiskCount(), location.name(), + false); hwProfiles.add(hwProfile); } } @@ -188,7 +190,8 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listImagesByLocation(String location) { final List osImages = Lists.newArrayList(); - Iterable publishers = Splitter.on(',').trimResults().omitEmptyStrings().split(this.azureComputeConstants.azureImagePublishers()); + Iterable publishers = Splitter.on(',').trimResults().omitEmptyStrings() + .split(this.azureComputeConstants.azureImagePublishers()); for (String publisher : publishers) { osImages.addAll(getImagesFromPublisher(publisher, location)); } @@ -199,42 +202,50 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listImages() { final List osImages = Lists.newArrayList(); - for (Location location : listLocations()){ + for (Location location : listLocations()) { osImages.addAll(listImagesByLocation(location.name())); } + // list custom images - List storages = api.getStorageAccountApi(azureGroup).list(); - for (StorageService storage : storages) { - String name = storage.name(); - 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); + for (ResourceGroup resourceGroup : api.getResourceGroupApi().list()) { + String azureGroup = resourceGroup.name(); + List storages = api.getStorageAccountApi(azureGroup).list(); + + for (StorageService storage : storages) { + String name = storage.name(); + 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 = decodeFieldsFromUniqueId(id); + String azureGroup = locationToResourceGroupName.apply(image.location()); + if (image.custom()) { 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 + // 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()) { @@ -270,40 +281,38 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listLocations() { final Iterable vmLocations = FluentIterable.from(api.getResourceProviderApi().get("Microsoft.Compute")) - .filter(new Predicate() { - @Override - public boolean apply(ResourceProviderMetaData input) { - return input.resourceType().equals("virtualMachines"); - } - }) - .transformAndConcat(new Function>() { - @Override - public Iterable apply(ResourceProviderMetaData resourceProviderMetaData) { - return resourceProviderMetaData.locations(); - } - }); + .filter(new Predicate() { + @Override + public boolean apply(ResourceProviderMetaData input) { + return input.resourceType().equals("virtualMachines"); + } + }).transformAndConcat(new Function>() { + @Override + public Iterable apply(ResourceProviderMetaData resourceProviderMetaData) { + return resourceProviderMetaData.locations(); + } + }); - List locations = FluentIterable.from(api.getLocationApi().list()) - .filter(new Predicate() { - @Override - public boolean apply(Location location) { - return Iterables.contains(vmLocations, location.displayName()); - } - }) - .filter(new Predicate() { - @Override - public boolean apply(Location location) { - return regionIds.get().isEmpty() ? true : regionIds.get().contains(location.name()); - } - }) - .toList(); + List locations = FluentIterable.from(api.getLocationApi().list()).filter(new Predicate() { + @Override + public boolean apply(Location location) { + return Iterables.contains(vmLocations, location.displayName()); + } + }).filter(new Predicate() { + @Override + public boolean apply(Location location) { + return regionIds.get().isEmpty() ? true : regionIds.get().contains(location.name()); + } + }).toList(); return locations; } @Override public VirtualMachine getNode(final String id) { - return api.getVirtualMachineApi(azureGroup).get(id); + RegionAndId regionAndId = RegionAndId.fromSlashEncoded(id); + String azureGroup = locationToResourceGroupName.apply(regionAndId.region()); + return api.getVirtualMachineApi(azureGroup).get(regionAndId.id()); } @Override @@ -313,22 +322,32 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listNodes() { - return api.getVirtualMachineApi(azureGroup).list(); + ImmutableList.Builder nodes = ImmutableList.builder(); + for (ResourceGroup resourceGroup : api.getResourceGroupApi().list()) { + nodes.addAll(api.getVirtualMachineApi(resourceGroup.name()).list()); + } + return nodes.build(); } @Override @@ -341,59 +360,54 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapterof()); + + 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 24f02ead6c..34a5160d8b 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 @@ -24,7 +24,6 @@ import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_P import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATION_POLL_INITIAL_PERIOD; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATION_POLL_MAX_PERIOD; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATION_TIMEOUT; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.RESOURCE_GROUP_NAME; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TCP_RULE_FORMAT; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TCP_RULE_REGEXP; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; @@ -137,10 +136,6 @@ public class AzureComputeServiceContextModule @Inject private String tcpRuleRegexpProperty; - @Named(RESOURCE_GROUP_NAME) - @Inject - private String azureResourceGroupProperty; - @Named(IMAGE_PUBLISHERS) @Inject private String azureImagePublishersProperty; @@ -161,10 +156,6 @@ public class AzureComputeServiceContextModule return Long.parseLong(operationTimeoutProperty); } - public String azureResourceGroup() { - return azureResourceGroupProperty; - } - public String azureImagePublishers() { return azureImagePublishersProperty; } @@ -199,11 +190,11 @@ 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); + @Named(TIMEOUT_NODE_RUNNING) + protected VirtualMachineInStatePredicateFactory provideVirtualMachineRunningPredicate(final AzureComputeApi api, + Timeouts timeouts, PollPeriod pollPeriod) { + return new VirtualMachineInStatePredicateFactory(api, PowerState.RUNNING, timeouts.nodeRunning, + pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); } @Provides @@ -229,19 +220,17 @@ public class AzureComputeServiceContextModule @Provides @Named(TIMEOUT_NODE_SUSPENDED) - protected Predicate provideNodeSuspendedPredicate(final AzureComputeApi api, final AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants, - Timeouts timeouts, PollPeriod pollPeriod) { - String azureGroup = azureComputeConstants.azureResourceGroup(); - return retry(new VirtualMachineInStatePredicate(api, azureGroup, PowerState.STOPPED), timeouts.nodeTerminated, - pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); + protected VirtualMachineInStatePredicateFactory provideNodeSuspendedPredicate(final AzureComputeApi api, + Timeouts timeouts, PollPeriod pollPeriod) { + return new VirtualMachineInStatePredicateFactory(api, 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(), + protected PublicIpAvailablePredicateFactory providePublicIpAvailablePredicate(final AzureComputeApi api, + final AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants, Timeouts timeouts, + PollPeriod pollPeriod) { + return new PublicIpAvailablePredicateFactory(api, azureComputeConstants.operationTimeout(), azureComputeConstants.operationPollInitialPeriod(), azureComputeConstants.operationPollMaxPeriod()); } @@ -280,45 +269,62 @@ public class AzureComputeServiceContextModule } } - @VisibleForTesting - static class VirtualMachineInStatePredicate implements Predicate { + public static class VirtualMachineInStatePredicateFactory { private final AzureComputeApi api; - private final String azureGroup; private final PowerState powerState; + private final long timeout; + private final long period; + private final long maxPeriod; - 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"); + VirtualMachineInStatePredicateFactory(AzureComputeApi api, PowerState powerState, long timeout, + long period, long maxPeriod) { + this.api = checkNotNull(api, "api cannot be null"); + this.powerState = checkNotNull(powerState, "powerState cannot be null"); + this.timeout = timeout; + this.period = period; + this.maxPeriod = maxPeriod; } - @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(); + public Predicate create(final String azureGroup) { + return retry(new Predicate() { + @Override + public boolean apply(String name) { + checkNotNull(name, "name cannot be null"); + VirtualMachineInstance vmInstance = api.getVirtualMachineApi(azureGroup).getInstanceDetails(name); + if (vmInstance == null) + return false; + return powerState == vmInstance.powerState(); + } + }, timeout, period, maxPeriod); } } - @VisibleForTesting - static class PublicIpAvailablePredicate implements Predicate { + public static class PublicIpAvailablePredicateFactory { private final AzureComputeApi api; - private final String azureGroup; + private final long timeout; + private final long period; + private final long maxPeriod; - public PublicIpAvailablePredicate(AzureComputeApi api, String azureGroup) { - this.api = checkNotNull(api, "api must not be null"); - this.azureGroup = checkNotNull(azureGroup, "azuregroup must not be null"); + PublicIpAvailablePredicateFactory(AzureComputeApi api, long timeout, + long period, long maxPeriod) { + this.api = checkNotNull(api, "api cannot be null"); + this.timeout = timeout; + this.period = period; + this.maxPeriod = maxPeriod; } - - @Override - public boolean apply(String name) { - checkNotNull(name, "name cannot be null"); - PublicIPAddress publicIp = api.getPublicIPAddressApi(azureGroup).get(name); - if (publicIp == null) return false; - return publicIp.properties().provisioningState().equalsIgnoreCase("Succeeded"); + + public Predicate create(final String azureGroup) { + return retry(new Predicate() { + @Override + public boolean apply(String name) { + checkNotNull(name, "name cannot be null"); + PublicIPAddress publicIp = api.getPublicIPAddressApi(azureGroup).get(name); + if (publicIp == null) return false; + return publicIp.properties().provisioningState().equalsIgnoreCase("Succeeded"); + } + }, timeout, period, maxPeriod); } } 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 99c9c6cde1..1e57899d5c 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 @@ -31,8 +31,10 @@ import javax.annotation.Resource; import org.jclouds.Constants; import org.jclouds.azurecompute.arm.AzureComputeApi; -import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.AzureComputeConstants; +import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.VirtualMachineInStatePredicateFactory; +import org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupName; import org.jclouds.azurecompute.arm.compute.functions.ResourceDefinitionToCustomImage; +import org.jclouds.azurecompute.arm.domain.RegionAndId; import org.jclouds.azurecompute.arm.domain.ResourceDefinition; import org.jclouds.azurecompute.arm.domain.StorageServiceKeys; import org.jclouds.azurecompute.arm.domain.VMImage; @@ -61,27 +63,27 @@ public class AzureComputeImageExtension implements ImageExtension { protected Logger logger = Logger.NULL; private final AzureComputeApi api; - private final String group; private final ListeningExecutorService userExecutor; private final Predicate imageAvailablePredicate; - private final Predicate nodeSuspendedPredicate; + private final VirtualMachineInStatePredicateFactory nodeSuspendedPredicate; private final ResourceDefinitionToCustomImage.Factory resourceDefinitionToImage; private final CleanupResources cleanupResources; + private final LocationToResourceGroupName locationToResourceGroupName; @Inject AzureComputeImageExtension(AzureComputeApi api, @Named(TIMEOUT_IMAGE_AVAILABLE) Predicate imageAvailablePredicate, - @Named(TIMEOUT_NODE_SUSPENDED) Predicate nodeSuspendedPredicate, - AzureComputeConstants azureComputeConstants, + @Named(TIMEOUT_NODE_SUSPENDED) VirtualMachineInStatePredicateFactory nodeSuspendedPredicate, @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, - ResourceDefinitionToCustomImage.Factory resourceDefinitionToImage, CleanupResources cleanupResources) { + ResourceDefinitionToCustomImage.Factory resourceDefinitionToImage, CleanupResources cleanupResources, + LocationToResourceGroupName locationToResourceGroupName) { this.api = api; this.imageAvailablePredicate = imageAvailablePredicate; this.nodeSuspendedPredicate = nodeSuspendedPredicate; - this.group = azureComputeConstants.azureResourceGroup(); this.userExecutor = userExecutor; this.resourceDefinitionToImage = resourceDefinitionToImage; this.cleanupResources = cleanupResources; + this.locationToResourceGroupName = locationToResourceGroupName; } @Override @@ -92,21 +94,23 @@ public class AzureComputeImageExtension implements ImageExtension { @Override public ListenableFuture createImage(ImageTemplate template) { final CloneImageTemplate cloneTemplate = (CloneImageTemplate) template; - final String id = cloneTemplate.getSourceNodeId(); - final String name = cloneTemplate.getName(); + + final RegionAndId regionAndId = RegionAndId.fromSlashEncoded(cloneTemplate.getSourceNodeId()); + final String group = locationToResourceGroupName.apply(regionAndId.region()); - logger.debug(">> stopping node %s...", id); - api.getVirtualMachineApi(group).stop(id); - checkState(nodeSuspendedPredicate.apply(id), "Node %s was not suspended within the configured time limit", id); + logger.debug(">> stopping node %s...", regionAndId.slashEncode()); + api.getVirtualMachineApi(group).stop(regionAndId.id()); + checkState(nodeSuspendedPredicate.create(group).apply(regionAndId.id()), + "Node %s was not suspended within the configured time limit", regionAndId.slashEncode()); return userExecutor.submit(new Callable() { @Override public Image call() throws Exception { - logger.debug(">> generalizing virtal machine %s...", id); - api.getVirtualMachineApi(group).generalize(id); + logger.debug(">> generalizing virtal machine %s...", regionAndId.id()); + api.getVirtualMachineApi(group).generalize(regionAndId.id()); - logger.debug(">> capturing virtual machine %s to container %s...", id, CONTAINER_NAME); - URI uri = api.getVirtualMachineApi(group).capture(id, cloneTemplate.getName(), CONTAINER_NAME); + logger.debug(">> capturing virtual machine %s to container %s...", regionAndId.id(), CONTAINER_NAME); + URI uri = api.getVirtualMachineApi(group).capture(regionAndId.id(), cloneTemplate.getName(), CONTAINER_NAME); checkState(uri != null && imageAvailablePredicate.apply(uri), "Image %s was not created within the configured time limit", cloneTemplate.getName()); @@ -114,7 +118,8 @@ public class AzureComputeImageExtension implements ImageExtension { 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)); + Image image = resourceDefinitionToImage.create(cloneTemplate.getSourceNodeId(), cloneTemplate.getName()) + .apply(definitions.get(0)); logger.debug(">> created %s", image); return image; } @@ -130,7 +135,7 @@ public class AzureComputeImageExtension implements ImageExtension { 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 diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToResourceGroupName.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToResourceGroupName.java new file mode 100644 index 0000000000..c97850a2b1 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/LocationToResourceGroupName.java @@ -0,0 +1,46 @@ +/* + * 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.compute.config.ComputeServiceProperties.RESOURCENAME_DELIMITER; +import static org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_PREFIX; + +import javax.inject.Inject; +import javax.inject.Named; + +import com.google.common.base.Function; + +/** + * Returns the name of the resource group for the current location. + */ +public class LocationToResourceGroupName implements Function { + + private final String prefix; + private final char delimiter; + + @Inject + LocationToResourceGroupName(@Named(RESOURCENAME_PREFIX) String prefix, @Named(RESOURCENAME_DELIMITER) char delimiter) { + this.prefix = prefix; + this.delimiter = delimiter; + } + + @Override + public String apply(String input) { + return String.format("%s%s%s", prefix, delimiter, input); + } + +} 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 index cce6b50847..02fb0f49b6 100644 --- 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 @@ -23,7 +23,7 @@ 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.RegionAndId; import org.jclouds.azurecompute.arm.domain.ResourceDefinition; import org.jclouds.azurecompute.arm.domain.VMImage; import org.jclouds.azurecompute.arm.domain.VirtualMachine; @@ -39,21 +39,24 @@ public class ResourceDefinitionToCustomImage implements Function vmImageToImage; private final String imageName; private final String storageAccountName; private final VirtualMachine vm; + private final String resourceGroup; @Inject - ResourceDefinitionToCustomImage(AzureComputeApi api, AzureComputeConstants azureComputeConstants, + ResourceDefinitionToCustomImage(AzureComputeApi api, StorageProfileToStorageAccountName storageProfileToStorageAccountName, - Function vmImageToImage, @Assisted("nodeId") String nodeId, + Function vmImageToImage, LocationToResourceGroupName locationToResourceGroupName, + @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); + + RegionAndId regionAndId = RegionAndId.fromSlashEncoded(nodeId); + this.resourceGroup = locationToResourceGroupName.apply(regionAndId.region()); + this.vm = api.getVirtualMachineApi(this.resourceGroup).get(regionAndId.id()); this.storageAccountName = storageProfileToStorageAccountName.apply(vm.properties().storageProfile()); } 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 index e151a4a17e..1f9087028f 100644 --- 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 @@ -38,6 +38,7 @@ import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextMod 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.RegionAndId; import org.jclouds.azurecompute.arm.domain.StorageProfile; import org.jclouds.azurecompute.arm.domain.StorageServiceKeys; import org.jclouds.azurecompute.arm.domain.VMImage; @@ -110,7 +111,6 @@ public class VirtualMachineToNodeMetadata implements Function> images; @@ -119,28 +119,32 @@ public class VirtualMachineToNodeMetadata implements Function credentialStore; private final Function vmImageToImge; private final StorageProfileToStorageAccountName storageProfileToStorageAccountName; + private final LocationToResourceGroupName locationToResourceGroupName; @Inject VirtualMachineToNodeMetadata(AzureComputeApi api, GroupNamingConvention.Factory namingConvention, Supplier> images, Supplier> hardwares, @Memoized Supplier> locations, Map credentialStore, final AzureComputeConstants azureComputeConstants, Function vmImageToImge, - StorageProfileToStorageAccountName storageProfileToStorageAccountName) { + StorageProfileToStorageAccountName storageProfileToStorageAccountName, + LocationToResourceGroupName locationToResourceGroupName) { 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; + this.locationToResourceGroupName = locationToResourceGroupName; } @Override public NodeMetadata apply(VirtualMachine virtualMachine) { + String azureGroup = locationToResourceGroupName.apply(virtualMachine.location()); + NodeMetadataBuilder builder = new NodeMetadataBuilder(); - builder.id(virtualMachine.name()); + builder.id(RegionAndId.fromRegionAndId(virtualMachine.location(), virtualMachine.name()).slashEncode()); builder.providerId(virtualMachine.id()); builder.name(virtualMachine.name()); builder.hostname(virtualMachine.name()); @@ -180,7 +184,7 @@ public class VirtualMachineToNodeMetadata implements Function image = findImage(virtualMachine.properties().storageProfile(), locationName); + Optional image = findImage(virtualMachine.properties().storageProfile(), locationName, azureGroup); if (image.isPresent()) { builder.imageId(image.get().getId()); builder.operatingSystem(image.get().getOperatingSystem()); @@ -239,7 +243,7 @@ public class VirtualMachineToNodeMetadata implements Function findImage(final StorageProfile storageProfile, String locatioName) { + protected Optional findImage(final StorageProfile storageProfile, String locatioName, String azureGroup) { if (storageProfile.imageReference() != null) { return Optional.fromNullable(images.get().get( encodeFieldsToUniqueId(false, locatioName, storageProfile.imageReference()))); 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 99528fdcbe..024204bec0 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 @@ -35,6 +35,7 @@ import javax.inject.Singleton; import org.jclouds.Constants; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule; +import org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupName; import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.domain.StorageService; @@ -73,20 +74,23 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco private final AzureComputeApi api; private final AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants; + private final LocationToResourceGroupName locationToResourceGroupName; @Inject protected CreateResourceGroupThenCreateNodes( CreateNodeWithGroupEncodedIntoName addNodeWithGroupStrategy, ListNodesStrategy listNodesStrategy, GroupNamingConvention.Factory namingConvention, - @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, - CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory, - AzureComputeApi api, AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants) { + @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, + CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory, + AzureComputeApi api, AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants, + LocationToResourceGroupName locationToResourceGroupName) { super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor, customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory); this.api = checkNotNull(api, "api cannot be null"); checkNotNull(userExecutor, "userExecutor cannot be null"); this.azureComputeConstants = azureComputeConstants; + this.locationToResourceGroupName = locationToResourceGroupName; } @Override @@ -100,7 +104,7 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco 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(); + String azureGroupName = locationToResourceGroupName.apply(template.getLocation().getId()); AzureTemplateOptions options = template.getOptions().as(AzureTemplateOptions.class); // create resource group for jclouds group if it does not already exist 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 8f945d94e2..2a15e4b34a 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 @@ -34,8 +34,6 @@ public class AzureComputeProperties { public static final String TCP_RULE_REGEXP = "jclouds.azurecompute.arm.tcp.rule.regexp"; - 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"; diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/RegionAndId.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/RegionAndId.java new file mode 100644 index 0000000000..233109aa0a --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/RegionAndId.java @@ -0,0 +1,50 @@ +/* + * 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 static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.auto.value.AutoValue; +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; + +@AutoValue +public abstract class RegionAndId { + + public abstract String region(); + public abstract String id(); + + RegionAndId() { + + } + + public static RegionAndId fromSlashEncoded(String id) { + Iterable parts = Splitter.on('/').split(checkNotNull(id, "id")); + checkArgument(Iterables.size(parts) == 2, "id must be in format regionId/id"); + return new AutoValue_RegionAndId(Iterables.get(parts, 0), Iterables.get(parts, 1)); + } + + public static RegionAndId fromRegionAndId(String region, String id) { + return new AutoValue_RegionAndId(region, id); + } + + public String slashEncode() { + return region() + "/" + id(); + } + +} 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 39cc32c23d..ead676a751 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 @@ -16,7 +16,6 @@ */ 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; @@ -25,7 +24,6 @@ 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; @@ -33,10 +31,11 @@ import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupName; import org.jclouds.azurecompute.arm.domain.IdReference; import org.jclouds.azurecompute.arm.domain.IpConfiguration; import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; -import org.jclouds.azurecompute.arm.domain.ResourceGroup; +import org.jclouds.azurecompute.arm.domain.RegionAndId; import org.jclouds.azurecompute.arm.domain.StorageServiceKeys; import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.azurecompute.arm.util.BlobHelper; @@ -46,10 +45,8 @@ import org.jclouds.logging.Logger; import com.google.common.base.Function; 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 { @@ -61,28 +58,29 @@ public class CleanupResources implements Function { protected final AzureComputeApi api; private final Predicate resourceDeleted; private final StorageProfileToStorageAccountName storageProfileToStorageAccountName; + private final LocationToResourceGroupName locationToResourceGroupName; @Inject CleanupResources(AzureComputeApi azureComputeApi, @Named(TIMEOUT_RESOURCE_DELETED) Predicate resourceDeleted, - StorageProfileToStorageAccountName storageProfileToStorageAccountName) { + StorageProfileToStorageAccountName storageProfileToStorageAccountName, + LocationToResourceGroupName locationToResourceGroupName) { this.api = azureComputeApi; this.resourceDeleted = resourceDeleted; this.storageProfileToStorageAccountName = storageProfileToStorageAccountName; + this.locationToResourceGroupName = locationToResourceGroupName; } @Override public Boolean apply(final String id) { - logger.debug(">> destroying %s ...", id); - - Map resourceGroupNamesAndVirtualMachines = getResourceGroupNamesAndVirtualMachines(id); - if (resourceGroupNamesAndVirtualMachines.isEmpty()) + RegionAndId regionAndId = RegionAndId.fromSlashEncoded(id); + String group = locationToResourceGroupName.apply(regionAndId.region()); + + VirtualMachine virtualMachine = api.getVirtualMachineApi(group).get(regionAndId.id()); + if (virtualMachine == null) { return true; + } - String group = checkNotNull(resourceGroupNamesAndVirtualMachines.entrySet().iterator().next().getKey(), - "resourceGroup name must not be null"); - VirtualMachine virtualMachine = checkNotNull(resourceGroupNamesAndVirtualMachines.get(group), - "virtualMachine must not be null"); - + logger.debug(">> destroying %s ...", regionAndId.slashEncode()); boolean vmDeleted = deleteVirtualMachine(group, virtualMachine); // We don't delete the network here, as it is global to the resource @@ -163,14 +161,4 @@ public class CleanupResources implements Function { 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/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/AzureComputeServiceLiveTest.java index c3389540c4..c59509f14b 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,19 +16,9 @@ */ package org.jclouds.azurecompute.arm.compute; -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.TimeUnit; import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; @@ -78,19 +68,8 @@ public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest { @Override protected Properties setupProperties() { Properties properties = super.setupProperties(); - 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"); - + setIfTestSystemPropertyPresent(properties, "oauth.endpoint"); return properties; } 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 c20655b091..56200c485b 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,8 +16,6 @@ */ 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; @@ -58,25 +56,23 @@ public class AzureTemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest { @Override protected Properties setupProperties() { Properties properties = super.setupProperties(); - properties.put(RESOURCE_GROUP_NAME, "jc"); - AzureLiveTestUtils.defaultProperties(properties); - checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); - + setIfTestSystemPropertyPresent(properties, "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()); + "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 de44668ed4..c8a9259dc5 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,20 +16,10 @@ */ package org.jclouds.azurecompute.arm.compute.extensions; -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; @@ -63,19 +53,8 @@ public class AzureComputeImageExtensionLiveTest extends BaseImageExtensionLiveTe @Override protected Properties setupProperties() { Properties properties = super.setupProperties(); - 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"); - + setIfTestSystemPropertyPresent(properties, "oauth.endpoint"); return properties; } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java index 3f69e59f42..125e11a260 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java @@ -16,21 +16,34 @@ */ package org.jclouds.azurecompute.arm.internal; -import java.util.Properties; - +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_PORT_OPEN; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_SCRIPT_COMPLETE; import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGIONS; import static org.jclouds.oauth.v2.config.CredentialType.CLIENT_CREDENTIALS_SECRET; import static org.jclouds.oauth.v2.config.OAuthProperties.CREDENTIAL_TYPE; +import java.util.Properties; +import java.util.concurrent.TimeUnit; + public class AzureLiveTestUtils { public static Properties defaultProperties(Properties properties) { properties = properties == null ? new Properties() : properties; - properties.put("oauth.identity", "foo"); - properties.put("oauth.credential", "password"); - properties.put("oauth.endpoint", "https://login.microsoftonline.com/oauth2/token"); properties.put(CREDENTIAL_TYPE, CLIENT_CREDENTIALS_SECRET.toString()); - properties.put(PROPERTY_REGIONS, "northeurope"); + properties.put(PROPERTY_REGIONS, "eastus"); + properties.put(IMAGE_PUBLISHERS, "Canonical"); + + 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); + return properties; } } From 25656f5f6351f6106ca3059a0912d6e2e6edf9ac Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Mon, 17 Oct 2016 12:38:14 +0200 Subject: [PATCH 26/87] Added support for metadata and tags to Azure ARM --- .../compute/AzureComputeServiceAdapter.java | 7 +++++-- .../VirtualMachineToNodeMetadata.java | 10 ++++------ .../arm/features/VirtualMachineApi.java | 6 ++++-- .../compute/AzureComputeServiceLiveTest.java | 14 -------------- .../features/VirtualMachineApiLiveTest.java | 4 +++- .../features/VirtualMachineApiMockTest.java | 19 ++++++++++--------- .../createvirtualmachineresponse.json | 5 ++++- .../src/test/resources/virtualmachine.json | 5 ++++- 8 files changed, 34 insertions(+), 36 deletions(-) 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 434c92f76c..8e4531d419 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 @@ -24,9 +24,11 @@ import static org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageE 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.compute.util.ComputeServiceUtils.metadataAndTagsAsCommaDelimitedValue; import static org.jclouds.util.Closeables2.closeQuietly; import java.util.List; +import java.util.Map; import java.util.Set; import javax.inject.Inject; @@ -124,7 +126,6 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter create one nic in each network // TODO inbound ports @@ -141,9 +142,11 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter metadataAndTags = metadataAndTagsAsCommaDelimitedValue(template.getOptions()); VirtualMachine virtualMachine = api.getVirtualMachineApi(azureGroup).create(name, template.getLocation().getId(), - virtualMachineProperties); + virtualMachineProperties, metadataAndTags); // Safe to pass null credentials here, as jclouds will default populate // the node with the default credentials from the image, or the ones in 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 index 1f9087028f..48c850894f 100644 --- 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 @@ -23,6 +23,7 @@ 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.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromCommaDelimitedValue; import static org.jclouds.util.Closeables2.closeQuietly; import java.util.List; @@ -96,7 +97,6 @@ public class VirtualMachineToNodeMetadata implements Function userMetaData = virtualMachine.tags(); - builder.userMetadata(userMetaData); - builder.tags(Splitter.on(",").split(userMetaData.get("tags"))); + addMetadataAndParseTagsFromCommaDelimitedValue(builder, virtualMachine.tags()); } + String locationName = virtualMachine.location(); builder.location(getLocation(locationName)); 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 2dd6d342cc..2b44fa4f4c 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 @@ -18,6 +18,7 @@ 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.Consumes; @@ -80,14 +81,15 @@ public interface VirtualMachineApi { */ @Named("CreateVirtualMachine") @PUT - @Payload("%7B\"location\":\"{location}\",\"tags\":%7B%7D,\"properties\":{properties}%7D") + @Payload("%7B\"location\":\"{location}\",\"tags\":{tags},\"properties\":{properties}%7D") @MapBinder(BindToJsonPayload.class) @Path("/{vmname}") @QueryParams(keys = "validating", values = "false") @Produces(MediaType.APPLICATION_JSON) VirtualMachine create(@PathParam("vmname") String vmname, @PayloadParam("location") String location, - @PayloadParam("properties") VirtualMachineProperties properties); + @PayloadParam("properties") VirtualMachineProperties properties, + @PayloadParam("tags") Map tags); /** * The List Virtual Machines operation 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 c59509f14b..784f007fda 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 @@ -22,7 +22,6 @@ import java.util.Properties; import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; -import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.internal.BaseComputeServiceLiveTest; @@ -36,8 +35,6 @@ 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; /** @@ -86,15 +83,4 @@ public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest { InstallJDK.fromOpenJDK() })); return template; } - - @Override - protected void checkUserMetadataContains(NodeMetadata node, ImmutableMap userMetadata) { - // User metadata not yet supported - } - - @Override - protected void checkTagsInNodeEquals(NodeMetadata node, ImmutableSet tags) { - // Tags not yet supported - } - } 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 0973693ee2..a0e2cbe520 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 @@ -23,6 +23,7 @@ import static org.testng.Assert.assertTrue; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -111,7 +112,8 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { public void testCreate() { String blob = storageService.storageServiceProperties().primaryEndpoints().get("blob"); - VirtualMachine vm = api().create(vmName, LOCATION, getProperties(blob, nicName)); + VirtualMachine vm = api().create(vmName, LOCATION, getProperties(blob, nicName), + Collections. emptyMap()); assertTrue(!vm.name().isEmpty()); //Poll until resource is ready to be used 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 bb36dc5165..fd72344191 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,6 +16,12 @@ */ package org.jclouds.azurecompute.arm.features; +import static com.google.common.collect.Iterables.isEmpty; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + import java.net.URI; import java.text.DateFormat; import java.text.SimpleDateFormat; @@ -40,14 +46,9 @@ import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; import org.testng.annotations.Test; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; 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.assertNotNull; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; - @Test(groups = "unit", testName = "VirtualMachineApiMockTest", singleThreaded = true) public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { @@ -107,11 +108,11 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { server.enqueue(jsonResponse("/createvirtualmachineresponse.json")); final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); - VirtualMachine vm = vmAPI.create("windowsmachine", "westus", getProperties()); + VirtualMachine vm = vmAPI.create("windowsmachine", "westus", getProperties(), ImmutableMap.of("foo", "bar")); assertEquals(vm, getVM()); assertSent(server, "PUT", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + "/virtualMachines/windowsmachine?validating=false&api-version=2016-03-30", - "{\"location\":\"westus\",\"properties\":" + + "{\"location\":\"westus\",\"tags\":{\"foo\":\"bar\"},\"properties\":" + "{\"vmId\":\"27ee085b-d707-xxxx-yyyy-2370e2eb1cc1\"," + "\"hardwareProfile\":{\"vmSize\":\"Standard_D1\"}," + "\"storageProfile\":{\"imageReference\":{\"publisher\":\"publisher\",\"offer\":\"offer\",\"sku\":\"sku\",\"version\":\"ver\"}," + @@ -240,7 +241,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { VirtualMachineProperties properties = getProperties(); VirtualMachine machine = VirtualMachine.create("/subscriptions/SUBSCRIPTIONID/" + "" + "resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", "windowsmachine", - "Microsoft.Compute/virtualMachines", "westus", null, properties); + "Microsoft.Compute/virtualMachines", "westus", ImmutableMap.of("foo", "bar"), properties); return machine; } diff --git a/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json b/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json index ae16bdb1e9..27464e81c8 100644 --- a/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json +++ b/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json @@ -43,5 +43,8 @@ "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", "name": "windowsmachine", "type": "Microsoft.Compute/virtualMachines", - "location": "westus" + "location": "westus", + "tags": { + "foo": "bar" + } } \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/virtualmachine.json b/providers/azurecompute-arm/src/test/resources/virtualmachine.json index 4dda519705..96a42be7cb 100644 --- a/providers/azurecompute-arm/src/test/resources/virtualmachine.json +++ b/providers/azurecompute-arm/src/test/resources/virtualmachine.json @@ -43,5 +43,8 @@ "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", "name": "windowsmachine", "type": "Microsoft.Compute/virtualMachines", - "location": "westus" + "location": "westus", + "tags": { + "foo": "bar" + } } From 43eb65938ce1ffccfd2decabf0219fea3a28e870 Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Mon, 17 Oct 2016 13:24:41 +0200 Subject: [PATCH 27/87] Configuration to deploy VMs from the Marketplace --- .../compute/AzureComputeServiceAdapter.java | 13 +- .../arm/compute/functions/VMImageToImage.java | 101 +++++++---- .../jclouds/azurecompute/arm/domain/Plan.java | 47 +++++ .../azurecompute/arm/domain/VMImage.java | 8 + .../azurecompute/arm/domain/Version.java | 51 +++++- .../arm/domain/VirtualMachine.java | 37 +++- .../azurecompute/arm/features/OSImageApi.java | 10 ++ .../arm/features/VirtualMachineApi.java | 7 +- .../features/VirtualMachineApiLiveTest.java | 2 +- .../features/VirtualMachineApiMockTest.java | 166 +++++++++++------- .../createvirtualmachineresponse.json | 5 + .../src/test/resources/virtualmachine.json | 5 + 12 files changed, 339 insertions(+), 113 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Plan.java 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 8e4531d419..4574ca71f1 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 @@ -24,6 +24,7 @@ import static org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageE 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.azurecompute.arm.compute.functions.VMImageToImage.getMarketplacePlanFromImageMetadata; import static org.jclouds.compute.util.ComputeServiceUtils.metadataAndTagsAsCommaDelimitedValue; import static org.jclouds.util.Closeables2.closeQuietly; @@ -52,6 +53,7 @@ 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.Plan; import org.jclouds.azurecompute.arm.domain.PublicIPAddress; import org.jclouds.azurecompute.arm.domain.PublicIPAddressProperties; import org.jclouds.azurecompute.arm.domain.RegionAndId; @@ -144,9 +146,10 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter metadataAndTags = metadataAndTagsAsCommaDelimitedValue(template.getOptions()); + Plan plan = getMarketplacePlanFromImageMetadata(template.getImage()); VirtualMachine virtualMachine = api.getVirtualMachineApi(azureGroup).create(name, template.getLocation().getId(), - virtualMachineProperties, metadataAndTags); + virtualMachineProperties, metadataAndTags, plan); // Safe to pass null credentials here, as jclouds will default populate // the node with the default credentials from the image, or the ones in @@ -182,8 +185,9 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter versionList = osImageApi.listVersions(publisherName, offer.name(), sku.name()); for (Version version : versionList) { + Version versionDetails = osImageApi.getVersion(publisherName, offer.name(), sku.name(), version.name()); VMImage vmImage = VMImage.azureImage().publisher(publisherName).offer(offer.name()).sku(sku.name()) - .version(version.name()).location(location).build(); + .version(versionDetails.name()).location(location).versionProperties(version.properties()).build(); osImagesRef.add(vmImage); } } @@ -275,8 +279,9 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter versions = osImageApi.listVersions(publisher, offer, sku); if (!versions.isEmpty()) { - return VMImage.azureImage().publisher(publisher).offer(offer).sku(sku).version(versions.get(0).name()) - .location(location).build(); + Version version = osImageApi.getVersion(publisher, offer, sku, versions.get(0).name()); + return VMImage.azureImage().publisher(publisher).offer(offer).sku(sku).version(version.name()) + .location(location).versionProperties(version.properties()).build(); } return null; } 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 9d9eceb2b8..f037cfe8b1 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,9 +16,13 @@ */ package org.jclouds.azurecompute.arm.compute.functions; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Map; import java.util.Set; import org.jclouds.azurecompute.arm.domain.ImageReference; +import org.jclouds.azurecompute.arm.domain.Plan; import org.jclouds.azurecompute.arm.domain.VMImage; import org.jclouds.collect.Memoized; import org.jclouds.compute.domain.Image; @@ -26,17 +30,19 @@ import org.jclouds.compute.domain.ImageBuilder; import org.jclouds.compute.domain.OperatingSystem; import org.jclouds.compute.domain.OsFamily; import org.jclouds.domain.Location; +import org.jclouds.javax.annotation.Nullable; import org.jclouds.location.predicates.LocationPredicates; import com.google.common.base.Function; import com.google.common.base.Supplier; import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableMap; import com.google.inject.Inject; -import static com.google.common.base.Preconditions.checkNotNull; - public class VMImageToImage implements Function { + public static final String MARKETPLACE_TAG = "marketplace"; + private static final String UBUNTU = "Ubuntu"; private static final String WINDOWS = "Windows"; private static final String OPENLOGIC = "openLogic"; @@ -50,16 +56,20 @@ public class VMImageToImage implements Function { 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 encodeFieldsToUniqueId(boolean globallyAvailable, String locatioName, + ImageReference imageReference) { + return (globallyAvailable ? "global" : locatioName) + "/" + imageReference.publisher() + "/" + + imageReference.offer() + "/" + imageReference.sku(); } - public static String encodeFieldsToUniqueIdCustom(VMImage imageReference){ - return (imageReference.globallyAvailable() ? "global" : imageReference.location()) + "/" + imageReference.group() + "/" + imageReference.storage() + "/" + imageReference.offer() + "/" + imageReference.name(); + 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.offer() + "/" + imageReference.name(); } public static VMImage decodeFieldsFromUniqueId(final String id) { @@ -74,7 +84,8 @@ public class VMImageToImage implements Function { 3: imageReference.offer + "/" + 4: imageReference.name */ - vmImage = VMImage.customImage().location(fields[0]).group(fields[1]).storage(fields[2]).vhd1(fields[3]).offer(fields[4]).build(); + vmImage = VMImage.customImage().location(fields[0]).group(fields[1]).storage(fields[2]).vhd1(fields[3]) + .offer(fields[4]).build(); } else { /* id fields indexes 0: imageReference.location) + "/" + @@ -82,7 +93,8 @@ public class VMImageToImage implements Function { 2: imageReference.offer + "/" + 3: imageReference.sku + "/" + */ - vmImage = VMImage.azureImage().location(fields[0]).publisher(fields[1]).offer(fields[2]).sku(fields[3]).build(); + vmImage = VMImage.azureImage().location(fields[0]).publisher(fields[1]).offer(fields[2]).sku(fields[3]) + .build(); } return vmImage; } @@ -94,37 +106,49 @@ public class VMImageToImage implements Function { @Override public Image apply(final VMImage image) { + final ImageBuilder builder = new ImageBuilder(); + addMarketplacePlanToMetadataIfPresent(builder, image); if (image.custom()) { - final ImageBuilder builder = new ImageBuilder() - .location(FluentIterable.from(locations.get()) - .firstMatch(LocationPredicates.idEquals(image.location())) - .get()) - .name(image.name()) - .description(image.group()) - .status(Image.Status.AVAILABLE) - .version("latest") - .providerId(image.vhd1()) - .id(encodeFieldsToUniqueIdCustom(image)); + builder.location( + FluentIterable.from(locations.get()).firstMatch(LocationPredicates.idEquals(image.location())) + .get()).name(image.name()).description(image.group()).status(Image.Status.AVAILABLE) + .version("latest").providerId(image.vhd1()).id(encodeFieldsToUniqueIdCustom(image)); final OperatingSystem.Builder osBuilder = osFamily().apply(image); - Image retimage = builder.operatingSystem(osBuilder.build()).build(); - return retimage; - } - else { - final ImageBuilder builder = new ImageBuilder() + builder.operatingSystem(osBuilder.build()); + } else { + builder .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()); + .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(); + builder.operatingSystem(osBuilder.build()); } + return builder.build(); + } + + private static void addMarketplacePlanToMetadataIfPresent(ImageBuilder builder, VMImage image) { + if (image.versionProperties() != null && image.versionProperties().plan() != null) { + // Store the plan information in the metadata so the adapter can + // properly configure it when deploying images from the marketplace + Plan plan = image.versionProperties().plan(); + builder.userMetadata(ImmutableMap.of("publisher", plan.publisher(), "name", plan.name(), "product", + plan.product())); + } + } + + @Nullable + public static Plan getMarketplacePlanFromImageMetadata(Image image) { + Map imageMetadata = image.getUserMetadata(); + return imageMetadata.containsKey("product") ? Plan.create(imageMetadata.get("publisher"), + imageMetadata.get("name"), imageMetadata.get("product")) : null; } public static Function osFamily() { @@ -150,13 +174,18 @@ public class VMImageToImage implements Function { } else if (label.contains(RHEL)) { family = OsFamily.RHEL; } + + // Fallback to generic operating system type + if (OsFamily.UNRECOGNIZED == family && image.versionProperties() != null + && image.versionProperties().osDiskImage() != null + && image.versionProperties().osDiskImage().operatingSystem() != null) { + family = OsFamily.fromValue(image.versionProperties().osDiskImage().operatingSystem().toUpperCase()); + } // only 64bit OS images are supported by Azure ARM - return OperatingSystem.builder(). - family(family). - is64Bit(true). - description(image.custom() ? image.vhd1() : image.sku()). - version(image.custom() ? "latest" : image.sku()); + return OperatingSystem.builder().family(family).is64Bit(true) + .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/domain/Plan.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Plan.java new file mode 100644 index 0000000000..686314647b --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Plan.java @@ -0,0 +1,47 @@ +/* + * 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 org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +/** + * Plan + */ +@AutoValue +public abstract class Plan { + /** + * The publisher of the Plan + */ + public abstract String publisher(); + + /** + * The name of the Plan + */ + public abstract String name(); + + /** + * The product of the Plan + */ + public abstract String product(); + + @SerializedNames({"publisher", "name", "product"}) + public static Plan create(final String publisher, final String name, final String product) { + return new AutoValue_Plan(publisher, name, product); + } +} 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 e4f2301168..b08355e9c1 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,6 +16,7 @@ */ package org.jclouds.azurecompute.arm.domain; +import org.jclouds.azurecompute.arm.domain.Version.VersionProperties; import org.jclouds.javax.annotation.Nullable; import com.google.auto.value.AutoValue; @@ -92,6 +93,12 @@ public abstract class VMImage { */ public abstract boolean custom(); + /** + * Extended version properties. + */ + @Nullable + public abstract VersionProperties versionProperties(); + public static Builder builder() { return new AutoValue_VMImage.Builder(); } @@ -119,6 +126,7 @@ public abstract class VMImage { public abstract Builder vhd2(String vhd2); public abstract Builder name(String name); public abstract Builder custom(boolean custom); + public abstract Builder versionProperties(VersionProperties versionProperties); public abstract VMImage build(); } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Version.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Version.java index 63d7e11fb0..26bf4b0c4c 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Version.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Version.java @@ -16,9 +16,11 @@ */ 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; + /** * Version */ @@ -39,11 +41,50 @@ public abstract class Version { * The id of the Version */ public abstract String id(); + + /** + * The plan for the Version if this image is from the marketplace. + */ + @Nullable + public abstract VersionProperties properties(); + + Version() { + + } - @SerializedNames({"location", "name", "id"}) - public static Version create(final String location, final String name, final String id) { - - return new AutoValue_Version(location, name, id); + @SerializedNames({"location", "name", "id", "properties"}) + public static Version create(final String location, final String name, final String id, + final VersionProperties properties) { + return new AutoValue_Version(location, name, id, properties); + } + + @AutoValue + public abstract static class VersionProperties { + @Nullable public abstract Plan plan(); + public abstract OSDiskImage osDiskImage(); + + VersionProperties() { + + } + + @SerializedNames({"plan", "osDiskImage"}) + public static VersionProperties create(Plan plan, OSDiskImage osDiskImage) { + return new AutoValue_Version_VersionProperties(plan, osDiskImage); + } + + @AutoValue + public abstract static class OSDiskImage { + public abstract String operatingSystem(); + + OSDiskImage() { + + } + + @SerializedNames({"operatingSystem"}) + public static OSDiskImage create(String operatingSystem) { + return new AutoValue_Version_VersionProperties_OSDiskImage(operatingSystem); + } + } } } 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 10fa231c85..65a389ce26 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 @@ -60,11 +60,42 @@ public abstract class VirtualMachine { * Specifies the properties of the vm */ public abstract VirtualMachineProperties properties(); + + /** + * Specifies the plan, for marketplace images + */ + @Nullable + public abstract Plan plan(); - @SerializedNames({"id", "name", "type", "location", "tags", "properties"}) + @SerializedNames({"id", "name", "type", "location", "tags", "properties", "plan"}) public static VirtualMachine create(final String id, final String name, final String type, final String location, - @Nullable final Map tags, VirtualMachineProperties properties) { + @Nullable final Map tags, VirtualMachineProperties properties, @Nullable Plan plan) { + return builder().id(id).name(name).type(type).location(location).tags(tags).properties(properties).plan(plan) + .build(); + } + + public static Builder builder() { + return new AutoValue_VirtualMachine.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + + public abstract Builder id(String id); + public abstract Builder name(String name); + public abstract Builder type(String type); + public abstract Builder location(String location); + public abstract Builder tags(Map tags); + public abstract Builder properties(VirtualMachineProperties properties); + public abstract Builder plan(Plan plan); + + abstract Map tags(); - return new AutoValue_VirtualMachine(id, name, type, location, tags == null ? null : ImmutableMap.copyOf(tags), properties); + abstract VirtualMachine autoBuild(); + + public VirtualMachine build() { + tags(tags() != null ? ImmutableMap.copyOf(tags()) : null); + return autoBuild(); + } } } 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 c8fb3f3aa3..50c5c450d7 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 @@ -80,4 +80,14 @@ public interface OSImageApi { @Fallback(EmptyListOnNotFoundOr404.class) List listVersions(@PathParam("publisher") String publisher, @PathParam("offer") String offer, @PathParam("sku") String sku); + + /** + * Get the details of a Version + */ + @Named("version:get") + @GET + @Path("/publishers/{publisher}/artifacttypes/vmimage/offers/{offer}/skus/{sku}/versions/{version}") + @Fallback(EmptyListOnNotFoundOr404.class) + Version getVersion(@PathParam("publisher") String publisher, @PathParam("offer") String offer, + @PathParam("sku") String sku, @PathParam("version") String version); } 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 2b44fa4f4c..805378b2b5 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 @@ -32,11 +32,13 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.jclouds.Fallbacks; +import org.jclouds.azurecompute.arm.domain.Plan; 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.javax.annotation.Nullable; import org.jclouds.oauth.v2.filters.OAuthFilter; import org.jclouds.rest.annotations.Fallback; import org.jclouds.rest.annotations.MapBinder; @@ -81,7 +83,7 @@ public interface VirtualMachineApi { */ @Named("CreateVirtualMachine") @PUT - @Payload("%7B\"location\":\"{location}\",\"tags\":{tags},\"properties\":{properties}%7D") + @Payload("%7B\"location\":\"{location}\",\"tags\":{tags},\"properties\":{properties},\"plan\":{plan}%7D") @MapBinder(BindToJsonPayload.class) @Path("/{vmname}") @QueryParams(keys = "validating", values = "false") @@ -89,7 +91,8 @@ public interface VirtualMachineApi { VirtualMachine create(@PathParam("vmname") String vmname, @PayloadParam("location") String location, @PayloadParam("properties") VirtualMachineProperties properties, - @PayloadParam("tags") Map tags); + @PayloadParam("tags") Map tags, + @Nullable @PayloadParam("plan") Plan plan); /** * The List Virtual Machines operation 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 a0e2cbe520..35ccd89aa7 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 @@ -113,7 +113,7 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { String blob = storageService.storageServiceProperties().primaryEndpoints().get("blob"); VirtualMachine vm = api().create(vmName, LOCATION, getProperties(blob, nicName), - Collections. emptyMap()); + Collections. emptyMap(), null); assertTrue(!vm.name().isEmpty()); //Poll until resource is ready to be used 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 fd72344191..5b034a0d66 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 @@ -37,6 +37,7 @@ import org.jclouds.azurecompute.arm.domain.ImageReference; 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.Plan; import org.jclouds.azurecompute.arm.domain.StorageProfile; import org.jclouds.azurecompute.arm.domain.VHD; import org.jclouds.azurecompute.arm.domain.VirtualMachine; @@ -55,16 +56,18 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { public void testGet() throws Exception { server.enqueue(jsonResponse("/virtualmachine.json")); 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=2016-03-30"); + assertEquals(vmAPI.get("windowsmachine"), + getVM(Plan.create("thinkboxsoftware", "deadline-slave-7-2", "deadline7-2"))); + assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/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=2016-03-30"); + assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines/windowsmachine?api-version=2016-03-30"); } public void testGetInstanceDetails() throws Exception { @@ -76,52 +79,80 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { assertEquals(actual.statuses().get(0).code(), expected.statuses().get(0).code()); assertEquals(actual.statuses().get(0).displayStatus(), expected.statuses().get(0).displayStatus()); 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=2016-03-30"); + // 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=2016-03-30"); } public void testGetInstanceDetailsEmpty() throws Exception { server.enqueue(new MockResponse().setResponseCode(404)); 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=2016-03-30"); + assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines/windowsmachine/instanceView?api-version=2016-03-30"); } public void testList() throws Exception { server.enqueue(jsonResponse("/virtualmachines.json")); final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); assertEquals(vmAPI.list(), getVMList()); - assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + - "/virtualMachines?api-version=2015-06-15"); + assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines?api-version=2015-06-15"); } + public void testListEmpty() throws Exception { server.enqueue(new MockResponse().setResponseCode(404)); final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); assertTrue(isEmpty(vmAPI.list())); - assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + - "/virtualMachines?api-version=2015-06-15"); + assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines?api-version=2015-06-15"); } + public void testCreateWithPlan() throws Exception { + server.enqueue(jsonResponse("/createvirtualmachineresponse.json")); + Plan plan = Plan.create("thinkboxsoftware", "deadline-slave-7-2", "deadline7-2"); + final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); + VirtualMachine vm = vmAPI + .create("windowsmachine", "westus", getProperties(), ImmutableMap.of("foo", "bar"), plan); + assertEquals(vm, getVM(plan)); + assertSent( + server, + "PUT", + "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines/windowsmachine?validating=false&api-version=2016-03-30", + "{\"location\":\"westus\",\"tags\":{\"foo\":\"bar\"},\"properties\":" + + "{\"vmId\":\"27ee085b-d707-xxxx-yyyy-2370e2eb1cc1\"," + + "\"hardwareProfile\":{\"vmSize\":\"Standard_D1\"}," + + "\"storageProfile\":{\"imageReference\":{\"publisher\":\"publisher\",\"offer\":\"offer\",\"sku\":\"sku\",\"version\":\"ver\"}," + + "\"osDisk\":{\"osType\":\"Windows\",\"name\":\"windowsmachine\"," + + "\"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\"}," + + "\"plan\":{\"name\":\"deadline-slave-7-2\",\"publisher\":\"thinkboxsoftware\",\"product\":\"deadline7-2\"}}"); + } + public void testCreate() throws Exception { server.enqueue(jsonResponse("/createvirtualmachineresponse.json")); final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); - VirtualMachine vm = vmAPI.create("windowsmachine", "westus", getProperties(), ImmutableMap.of("foo", "bar")); + VirtualMachine vm = vmAPI.create("windowsmachine", "westus", getProperties(), ImmutableMap.of("foo", "bar"), null); assertEquals(vm, getVM()); - assertSent(server, "PUT", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + - "/virtualMachines/windowsmachine?validating=false&api-version=2016-03-30", - "{\"location\":\"westus\",\"tags\":{\"foo\":\"bar\"},\"properties\":" + - "{\"vmId\":\"27ee085b-d707-xxxx-yyyy-2370e2eb1cc1\"," + - "\"hardwareProfile\":{\"vmSize\":\"Standard_D1\"}," + - "\"storageProfile\":{\"imageReference\":{\"publisher\":\"publisher\",\"offer\":\"offer\",\"sku\":\"sku\",\"version\":\"ver\"}," + - "\"osDisk\":{\"osType\":\"Windows\",\"name\":\"windowsmachine\"," + - "\"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\"}}"); - + assertSent( + server, + "PUT", + "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines/windowsmachine?validating=false&api-version=2016-03-30", + "{\"location\":\"westus\",\"tags\":{\"foo\":\"bar\"},\"properties\":" + + "{\"vmId\":\"27ee085b-d707-xxxx-yyyy-2370e2eb1cc1\"," + + "\"hardwareProfile\":{\"vmSize\":\"Standard_D1\"}," + + "\"storageProfile\":{\"imageReference\":{\"publisher\":\"publisher\",\"offer\":\"offer\",\"sku\":\"sku\",\"version\":\"ver\"}," + + "\"osDisk\":{\"osType\":\"Windows\",\"name\":\"windowsmachine\"," + + "\"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\"}}"); } public void testDeleteReturns404() throws Exception { @@ -134,9 +165,10 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { assertEquals(server.getRequestCount(), 1); assertNull(uri); - assertSent(server, "DELETE", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + - "/virtualMachines/windowsmachine?api-version=2016-03-30"); + assertSent(server, "DELETE", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines/windowsmachine?api-version=2016-03-30"); } + public void testDelete() throws Exception { server.enqueue(response202WithHeader()); @@ -147,8 +179,8 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { assertEquals(server.getRequestCount(), 1); assertNotNull(uri); - assertSent(server, "DELETE", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + - "/virtualMachines/windowsmachine?api-version=2016-03-30"); + assertSent(server, "DELETE", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines/windowsmachine?api-version=2016-03-30"); } public void testStart() throws Exception { @@ -158,8 +190,8 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { vmAPI.start("windowsmachine"); - assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + - "/virtualMachines/windowsmachine/start?api-version=2015-06-15"); + assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines/windowsmachine/start?api-version=2015-06-15"); } public void testRestart() throws Exception { @@ -169,8 +201,8 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { vmAPI.restart("windowsmachine"); - assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + - "/virtualMachines/windowsmachine/restart?api-version=2015-06-15"); + assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines/windowsmachine/restart?api-version=2015-06-15"); } public void testStop() throws Exception { @@ -180,16 +212,16 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { vmAPI.stop("windowsmachine"); - assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + - "/virtualMachines/windowsmachine/powerOff?api-version=2015-06-15"); + assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines/windowsmachine/powerOff?api-version=2015-06-15"); } public void testGeneralize() throws Exception { server.enqueue(new MockResponse().setResponseCode(200)); final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); vmAPI.generalize("vm"); // IllegalStateException if failed - assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + - "/virtualMachines/vm/generalize?api-version=2015-06-15"); + assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines/vm/generalize?api-version=2015-06-15"); } public void testCapture() throws Exception { @@ -198,8 +230,9 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); URI uri = vmAPI.capture("vm", "prefix", "container"); assertNotNull(uri); - assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + - "/virtualMachines/vm/capture?api-version=2015-06-15", "{\"vhdPrefix\":\"prefix\",\"destinationContainerName\":\"container\"}"); + assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines/vm/capture?api-version=2015-06-15", + "{\"vhdPrefix\":\"prefix\",\"destinationContainerName\":\"container\"}"); } public void testCapture404() throws Exception { @@ -208,8 +241,9 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); URI uri = vmAPI.capture("vm", "prefix", "container"); assertNull(uri); - assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + - "/virtualMachines/vm/capture?api-version=2015-06-15", "{\"vhdPrefix\":\"prefix\",\"destinationContainerName\":\"container\"}"); + assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + + "/virtualMachines/vm/capture?api-version=2015-06-15", + "{\"vhdPrefix\":\"prefix\",\"destinationContainerName\":\"container\"}"); } private VirtualMachineProperties getProperties() { @@ -220,28 +254,36 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { OSDisk osDisk = OSDisk.create("Windows", "windowsmachine", vhd, "ReadWrite", "FromImage", null); StorageProfile storageProfile = StorageProfile.create(imgRef, osDisk, dataDisks); OSProfile.WindowsConfiguration windowsConfig = OSProfile.WindowsConfiguration.create(false, null, null, true, - null); + null); OSProfile osProfile = OSProfile.create("windowsmachine", "azureuser", null, null, null, windowsConfig); - IdReference networkInterface = - IdReference.create("/subscriptions/SUBSCRIPTIONID" + - "/resourceGroups/groupname/providers/Microsoft.Network/networkInterfaces/" + - "windowsmachine167"); + IdReference networkInterface = IdReference.create("/subscriptions/SUBSCRIPTIONID" + + "/resourceGroups/groupname/providers/Microsoft.Network/networkInterfaces/" + "windowsmachine167"); List networkInterfaces = new ArrayList(); networkInterfaces.add(networkInterface); NetworkProfile networkProfile = NetworkProfile.create(networkInterfaces); DiagnosticsProfile.BootDiagnostics bootDiagnostics = DiagnosticsProfile.BootDiagnostics.create(true, - "https://groupname2760.blob.core.windows.net/"); + "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, VirtualMachineProperties.ProvisioningState.CREATING); + null, null, hwProf, storageProfile, osProfile, networkProfile, diagnosticsProfile, + VirtualMachineProperties.ProvisioningState.CREATING); return properties; } private VirtualMachine getVM() { VirtualMachineProperties properties = getProperties(); - VirtualMachine machine = VirtualMachine.create("/subscriptions/SUBSCRIPTIONID/" + "" + - "resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", "windowsmachine", - "Microsoft.Compute/virtualMachines", "westus", ImmutableMap.of("foo", "bar"), properties); + VirtualMachine machine = VirtualMachine.create("/subscriptions/SUBSCRIPTIONID/" + "" + + "resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", "windowsmachine", + "Microsoft.Compute/virtualMachines", "westus", ImmutableMap.of("foo", "bar"), properties, + Plan.create("thinkboxsoftware", "deadline-slave-7-2", "deadline7-2")); + return machine; + } + + private VirtualMachine getVM(Plan plan) { + VirtualMachineProperties properties = getProperties(); + VirtualMachine machine = VirtualMachine.create("/subscriptions/SUBSCRIPTIONID/" + "" + + "resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", "windowsmachine", + "Microsoft.Compute/virtualMachines", "westus", ImmutableMap.of("foo", "bar"), properties, plan); return machine; } @@ -255,23 +297,23 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { } catch (Exception e) { e.printStackTrace(); } - VirtualMachineInstance.VirtualMachineStatus vmStatus = - VirtualMachineInstance.VirtualMachineStatus.create("ProvisioningState/succeeded", "Info", "Provisioning succeeded", date); + VirtualMachineInstance.VirtualMachineStatus vmStatus = VirtualMachineInstance.VirtualMachineStatus.create( + "ProvisioningState/succeeded", "Info", "Provisioning succeeded", date); statuses.add(vmStatus); - VirtualMachineInstance.VirtualMachineStatus vmStatus1 = - VirtualMachineInstance.VirtualMachineStatus.create("PowerState/running", "Info", "VM running", null); + VirtualMachineInstance.VirtualMachineStatus vmStatus1 = VirtualMachineInstance.VirtualMachineStatus.create( + "PowerState/running", "Info", "VM running", null); statuses.add(vmStatus1); - VirtualMachineInstance machineInstance = - VirtualMachineInstance.create(null, null, ImmutableList.copyOf(statuses)); + VirtualMachineInstance machineInstance = VirtualMachineInstance + .create(null, null, ImmutableList.copyOf(statuses)); return machineInstance; } private List getVMList() { VirtualMachineProperties properties = getProperties(); - VirtualMachine machine = VirtualMachine.create("/subscriptions/SUBSCRIPTIONID/" + "" + - "resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", - "windowsmachine", "Microsoft.Compute/virtualMachines", "westus", null, properties); + VirtualMachine machine = VirtualMachine.create("/subscriptions/SUBSCRIPTIONID/" + "" + + "resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", "windowsmachine", + "Microsoft.Compute/virtualMachines", "westus", null, properties, null); List list = new ArrayList(); list.add(machine); return list; diff --git a/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json b/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json index 27464e81c8..2963100b0a 100644 --- a/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json +++ b/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json @@ -46,5 +46,10 @@ "location": "westus", "tags": { "foo": "bar" + }, + "plan": { + "name": "deadline-slave-7-2", + "publisher": "thinkboxsoftware", + "product": "deadline7-2" } } \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/virtualmachine.json b/providers/azurecompute-arm/src/test/resources/virtualmachine.json index 96a42be7cb..874227d00b 100644 --- a/providers/azurecompute-arm/src/test/resources/virtualmachine.json +++ b/providers/azurecompute-arm/src/test/resources/virtualmachine.json @@ -46,5 +46,10 @@ "location": "westus", "tags": { "foo": "bar" + }, + "plan": { + "name": "deadline-slave-7-2", + "publisher": "thinkboxsoftware", + "product": "deadline7-2" } } From bf40d2ed2b57d2d2344b97f4205a30cd88142fb3 Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Tue, 18 Oct 2016 11:17:38 +0200 Subject: [PATCH 28/87] Configure jclouds group in virtualmachine tags --- .../arm/compute/AzureComputeServiceAdapter.java | 10 +++++++--- .../functions/VirtualMachineToNodeMetadata.java | 8 +++++++- 2 files changed, 14 insertions(+), 4 deletions(-) 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 4574ca71f1..96704335e6 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 @@ -99,6 +99,8 @@ import com.google.common.collect.Lists; @Singleton public class AzureComputeServiceAdapter implements ComputeServiceAdapter { + public static final String GROUP_KEY = "jclouds_group"; + private final CleanupResources cleanupResources; private final AzureComputeApi api; private final AzureComputeConstants azureComputeConstants; @@ -125,8 +127,6 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter create one nic in each network // TODO inbound ports @@ -145,6 +145,9 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter metadataAndTags = metadataAndTagsAsCommaDelimitedValue(template.getOptions()); Plan plan = getMarketplacePlanFromImageMetadata(template.getImage()); @@ -187,7 +190,8 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter Date: Tue, 18 Oct 2016 12:31:46 +0200 Subject: [PATCH 29/87] Null guards --- .../VirtualMachineToNodeMetadata.java | 45 ++++++++++++------- 1 file changed, 29 insertions(+), 16 deletions(-) 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 index 6527d25d00..5e98fbf242 100644 --- 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 @@ -156,14 +156,19 @@ public class VirtualMachineToNodeMetadata implements Function() { - @Override - public String apply(VirtualMachineStatus input) { - return input.code(); - } - }))); + if (instanceDetails != null && instanceDetails.powerState() != null) { + 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(NodeMetadata.Status.PENDING); + builder.backendStatus(provisioningState.name()); + } } else { builder.status(PROVISIONINGSTATE_TO_NODESTATUS.apply(provisioningState)); builder.backendStatus(provisioningState.name()); @@ -207,8 +212,13 @@ public class VirtualMachineToNodeMetadata implements Function privateIpAddresses = Lists.newArrayList(); for (IdReference networkInterfaceCardIdReference : idReferences) { NetworkInterfaceCard networkInterfaceCard = getNetworkInterfaceCard(networkInterfaceCardIdReference); - for (IpConfiguration ipConfiguration : networkInterfaceCard.properties().ipConfigurations()) { - privateIpAddresses.add(ipConfiguration.properties().privateIPAddress()); + if (networkInterfaceCard != null && networkInterfaceCard.properties() != null + && networkInterfaceCard.properties().ipConfigurations() != null) { + for (IpConfiguration ipConfiguration : networkInterfaceCard.properties().ipConfigurations()) { + if (ipConfiguration.properties().privateIPAddress() != null) { + privateIpAddresses.add(ipConfiguration.properties().privateIPAddress()); + } + } } } return privateIpAddresses; @@ -226,12 +236,15 @@ public class VirtualMachineToNodeMetadata implements Function 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()); + if (networkInterfaceCard != null && networkInterfaceCard.properties() != null + && networkInterfaceCard.properties().ipConfigurations() != null) { + 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()); + } } } } From d030ecac5ad3662bd109339a8886fd7e46eb0ff8 Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Wed, 19 Oct 2016 16:50:50 +0200 Subject: [PATCH 30/87] Added rate limit module --- .../arm/AzureComputeProviderMetadata.java | 22 ++++---- .../config/AzureComputeRateLimitModule.java | 30 +++++++++++ ...zureComputeRateLimitExceededException.java | 51 +++++++++++++++++++ .../handlers/AzureComputeErrorHandler.java | 6 ++- .../handlers/AzureRateLimitRetryHandler.java | 39 ++++++++++++++ 5 files changed, 137 insertions(+), 11 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeRateLimitModule.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/exceptions/AzureComputeRateLimitExceededException.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/handlers/AzureRateLimitRetryHandler.java 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 beac9259c7..dd516ef3ad 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,6 +17,7 @@ package org.jclouds.azurecompute.arm; +import static org.jclouds.Constants.PROPERTY_MAX_RATE_LIMIT_WAIT; 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; @@ -30,6 +31,8 @@ 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.compute.config.ComputeServiceProperties.IMAGE_AUTHENTICATE_SUDO; import static org.jclouds.compute.config.ComputeServiceProperties.IMAGE_LOGIN_USER; +import static org.jclouds.compute.config.ComputeServiceProperties.POLL_INITIAL_PERIOD; +import static org.jclouds.compute.config.ComputeServiceProperties.POLL_MAX_PERIOD; import static org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_DELIMITER; import static org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_PREFIX; import static org.jclouds.compute.config.ComputeServiceProperties.TEMPLATE; @@ -56,7 +59,6 @@ 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; @@ -80,20 +82,22 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { public static Properties defaultProperties() { final Properties properties = AzureManagementApiMetadata.defaultProperties(); - 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(POLL_INITIAL_PERIOD, 1000); + properties.put(POLL_MAX_PERIOD, 10000); + properties.put(OPERATION_TIMEOUT, 46000000); + properties.put(OPERATION_POLL_INITIAL_PERIOD, 5); + properties.put(OPERATION_POLL_MAX_PERIOD, 15); + // Default max wait in rate limit: 5m30s + properties.put(PROPERTY_MAX_RATE_LIMIT_WAIT, 330000); + properties.put(TCP_RULE_FORMAT, "tcp_%s-%s"); + properties.put(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(DEFAULT_VNET_ADDRESS_SPACE_PREFIX, "10.0.0.0/16"); properties.put(DEFAULT_SUBNET_ADDRESS_PREFIX, "10.0.0.0/24"); properties.put(RESOURCENAME_PREFIX, "jclouds"); properties.put(RESOURCENAME_DELIMITER, "-"); - properties.put(DEFAULT_DATADISKSIZE, "100"); + properties.put(DEFAULT_DATADISKSIZE, 100); properties.put(IMAGE_PUBLISHERS, "Canonical,RedHat"); // Default credentials for all images properties.put(IMAGE_LOGIN_USER, "jclouds:Password12345!"); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeRateLimitModule.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeRateLimitModule.java new file mode 100644 index 0000000000..3038b864b7 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeRateLimitModule.java @@ -0,0 +1,30 @@ +/* + * 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.config; + +import org.jclouds.azurecompute.arm.handlers.AzureRateLimitRetryHandler; +import org.jclouds.http.HttpRetryHandler; +import org.jclouds.http.annotation.ClientError; + +import com.google.inject.AbstractModule; + +public class AzureComputeRateLimitModule extends AbstractModule { + @Override + protected void configure() { + bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(AzureRateLimitRetryHandler.class); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/exceptions/AzureComputeRateLimitExceededException.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/exceptions/AzureComputeRateLimitExceededException.java new file mode 100644 index 0000000000..d8d478eac6 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/exceptions/AzureComputeRateLimitExceededException.java @@ -0,0 +1,51 @@ +/* + * 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.exceptions; + +import org.jclouds.http.HttpResponse; +import org.jclouds.rest.RateLimitExceededException; + +import com.google.common.annotations.Beta; +import com.google.common.base.Predicate; +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; + +/** + * Provides detailed information for rate limit exceptions. + */ +@Beta +public class AzureComputeRateLimitExceededException extends RateLimitExceededException { + private static final long serialVersionUID = 1L; + private static final String RATE_LIMIT_HEADER_PREFIX = "x-ms-ratelimit-remaining-"; + + public AzureComputeRateLimitExceededException(HttpResponse response) { + super(response.getStatusLine() + "\n" + rateLimitHeaders(response)); + } + + public AzureComputeRateLimitExceededException(HttpResponse response, Throwable cause) { + super(response.getStatusLine() + "\n" + rateLimitHeaders(response), cause); + } + + private static Multimap rateLimitHeaders(HttpResponse response) { + return Multimaps.filterKeys(response.getHeaders(), new Predicate() { + @Override + public boolean apply(String input) { + return input.startsWith(RATE_LIMIT_HEADER_PREFIX); + } + }); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/handlers/AzureComputeErrorHandler.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/handlers/AzureComputeErrorHandler.java index 6532173525..8492d51b50 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/handlers/AzureComputeErrorHandler.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/handlers/AzureComputeErrorHandler.java @@ -20,6 +20,7 @@ import java.io.IOException; import javax.inject.Singleton; +import org.jclouds.azurecompute.arm.exceptions.AzureComputeRateLimitExceededException; import org.jclouds.http.HttpCommand; import org.jclouds.http.HttpErrorHandler; import org.jclouds.http.HttpResponse; @@ -65,11 +66,12 @@ public class AzureComputeErrorHandler implements HttpErrorHandler { exception = new ResourceNotFoundException(message, exception); } break; - case 409: exception = new IllegalStateException(message, exception); break; - + case 429: + exception = new AzureComputeRateLimitExceededException(response, exception); + break; default: } } finally { diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/handlers/AzureRateLimitRetryHandler.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/handlers/AzureRateLimitRetryHandler.java new file mode 100644 index 0000000000..ee5f5e53ce --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/handlers/AzureRateLimitRetryHandler.java @@ -0,0 +1,39 @@ +/* + * 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.handlers; + +import javax.inject.Singleton; + +import org.jclouds.http.HttpCommand; +import org.jclouds.http.HttpResponse; +import org.jclouds.http.handlers.RateLimitRetryHandler; + +import com.google.common.annotations.Beta; +import com.google.common.base.Optional; +import com.google.common.net.HttpHeaders; + +@Beta +@Singleton +public class AzureRateLimitRetryHandler extends RateLimitRetryHandler { + + @Override + protected Optional millisToNextAvailableRequest(HttpCommand command, HttpResponse response) { + String secondsToNextAvailableRequest = response.getFirstHeaderOrNull(HttpHeaders.RETRY_AFTER); + return secondsToNextAvailableRequest != null ? Optional.of(Long.valueOf(secondsToNextAvailableRequest) * 1000) + : Optional. absent(); + } +} From d4eed402065cf2dbd1a762aeee5a8992b7403d83 Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Wed, 19 Oct 2016 16:55:10 +0200 Subject: [PATCH 31/87] Ignore storage account access failures when listing custom images --- .../compute/AzureComputeServiceAdapter.java | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) 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 96704335e6..3b207b74d6 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 @@ -32,7 +32,9 @@ 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 javax.inject.Singleton; import org.jclouds.azurecompute.arm.AzureComputeApi; @@ -79,7 +81,9 @@ import org.jclouds.compute.ComputeServiceAdapter; import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.Template; +import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.location.Region; +import org.jclouds.logging.Logger; import com.google.common.base.Function; import com.google.common.base.Objects; @@ -101,6 +105,10 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter storages = api.getStorageAccountApi(azureGroup).list(); for (StorageService storage : storages) { - String name = storage.name(); - 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); + try { + String name = storage.name(); + 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); + } } + } catch (Exception ex) { + logger.warn("<< could not get custom images from storage account %s: %s", storage, ex.getMessage()); } } } From ea82f58b351ccbe166fc8c86ba8243e16ed89f11 Mon Sep 17 00:00:00 2001 From: Andrew Gaul Date: Sun, 23 Oct 2016 06:38:46 -0700 Subject: [PATCH 32/87] Avoid improper equality comparisons Found via error-prone. --- .../arm/features/VirtualMachineApiLiveTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 35ccd89aa7..a11ff711db 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,7 @@ */ package org.jclouds.azurecompute.arm.features; +import static org.assertj.core.api.Assertions.assertThat; import static org.jclouds.util.Predicates2.retry; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; @@ -120,15 +121,15 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { boolean jobDone = retry(new Predicate() { @Override public boolean apply(String name) { - return !api().get(name).properties().provisioningState().equals("Creating"); + return !api().get(name).properties().provisioningState().equals(VirtualMachineProperties.ProvisioningState.CREATING); } }, 60 * 20 * 1000).apply(vmName); assertTrue(jobDone, "create operation did not complete in the configured timeout"); 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")); + assertThat(status).isNotEqualTo(VirtualMachineProperties.ProvisioningState.CREATING); + assertThat(status).isNotEqualTo(VirtualMachineProperties.ProvisioningState.FAILED); } @Test(dependsOnMethods = "testCreate") From 424a88fdc5cd355f8deffb76f904d988d6d77980 Mon Sep 17 00:00:00 2001 From: Andrew Gaul Date: Sun, 23 Oct 2016 13:49:11 -0700 Subject: [PATCH 33/87] Avoid C-style array declarations Found via error-prone. --- .../azurecompute/arm/compute/functions/VMImageToImage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 f037cfe8b1..394b167ea8 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 @@ -73,7 +73,7 @@ public class VMImageToImage implements Function { } public static VMImage decodeFieldsFromUniqueId(final String id) { - String fields[] = checkNotNull(id, "id").split("/"); + String[] fields = checkNotNull(id, "id").split("/"); VMImage vmImage; boolean custom = fields.length == 5; if (custom) { From 0df84d305e077946521dbaa091603a09a1e87040 Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Thu, 3 Nov 2016 13:13:04 +0100 Subject: [PATCH 34/87] Apache jclouds 2.0.0 release --- providers/azurecompute-arm/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/azurecompute-arm/pom.xml b/providers/azurecompute-arm/pom.xml index 824e552c73..b8b7fa4b32 100644 --- a/providers/azurecompute-arm/pom.xml +++ b/providers/azurecompute-arm/pom.xml @@ -23,7 +23,7 @@ org.apache.jclouds.labs jclouds-labs - 2.0.0-SNAPSHOT + 2.0.0 azurecompute-arm jclouds Azure Compute ARM API From 139a6367da39ef73158fae1e19224a047338a9dd Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Wed, 9 Nov 2016 21:49:17 +0100 Subject: [PATCH 35/87] Revert "Apache jclouds 2.0.0 release" This reverts commit 43c102065eab2d5fbf98e75811d9088cb7cf76bc. --- providers/azurecompute-arm/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/azurecompute-arm/pom.xml b/providers/azurecompute-arm/pom.xml index b8b7fa4b32..824e552c73 100644 --- a/providers/azurecompute-arm/pom.xml +++ b/providers/azurecompute-arm/pom.xml @@ -23,7 +23,7 @@ org.apache.jclouds.labs jclouds-labs - 2.0.0 + 2.0.0-SNAPSHOT azurecompute-arm jclouds Azure Compute ARM API From e38e486ff0c1f5821832048ad540c8c9891200b4 Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Wed, 9 Nov 2016 22:40:00 +0100 Subject: [PATCH 36/87] Apache jclouds 2.0.0-rc3 release --- providers/azurecompute-arm/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/azurecompute-arm/pom.xml b/providers/azurecompute-arm/pom.xml index 824e552c73..b8b7fa4b32 100644 --- a/providers/azurecompute-arm/pom.xml +++ b/providers/azurecompute-arm/pom.xml @@ -23,7 +23,7 @@ org.apache.jclouds.labs jclouds-labs - 2.0.0-SNAPSHOT + 2.0.0 azurecompute-arm jclouds Azure Compute ARM API From d36ceddbb3ef24b7939ce56c1f217e57643f74e0 Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Tue, 15 Nov 2016 01:13:00 +0100 Subject: [PATCH 37/87] Next development version 2.1.0-SNAPSHOT --- providers/azurecompute-arm/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/azurecompute-arm/pom.xml b/providers/azurecompute-arm/pom.xml index b8b7fa4b32..5860c3049b 100644 --- a/providers/azurecompute-arm/pom.xml +++ b/providers/azurecompute-arm/pom.xml @@ -23,7 +23,7 @@ org.apache.jclouds.labs jclouds-labs - 2.0.0 + 2.1.0-SNAPSHOT azurecompute-arm jclouds Azure Compute ARM API From cf256fb48b1357b4a545c4fa6d4990a0eaebe36d Mon Sep 17 00:00:00 2001 From: Duncan Godwin Date: Tue, 10 Jan 2017 17:19:04 +0000 Subject: [PATCH 38/87] Add tenant Id lookup command --- providers/azurecompute-arm/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/providers/azurecompute-arm/README.md b/providers/azurecompute-arm/README.md index a5a9956362..50ebedbe41 100644 --- a/providers/azurecompute-arm/README.md +++ b/providers/azurecompute-arm/README.md @@ -42,6 +42,14 @@ Run the following commands to assign roles to the service principal azure role assignment create --objectId -o Contributor -c /subscriptions// ``` +Look up the the tenant Id + +```bash +azure account show -s --json + +# output will be a JSON which will include the `Tenant id` +``` + Verify service principal ```bash From 15193d034990fe19c9879d19f2a1c97193d8e9e3 Mon Sep 17 00:00:00 2001 From: Duncan Godwin Date: Wed, 11 Jan 2017 16:47:40 +0000 Subject: [PATCH 39/87] Fix generateStorageAccountName The storageAccountName was used instead of the sanitizedStorageAccountName. --- .../compute/strategy/CreateResourceGroupThenCreateNodes.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 024204bec0..5ce30b0515 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 @@ -216,7 +216,7 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco } if (nameLength > 24) { - sanitizedStorageAccountName = shorten(storageAccountName, random); + sanitizedStorageAccountName = shorten(sanitizedStorageAccountName, random); } return sanitizedStorageAccountName; } From cffee28afa146c8b7e4a1e82668c6f2c4c99d9e4 Mon Sep 17 00:00:00 2001 From: Daniel Estevez Date: Tue, 17 Jan 2017 19:13:14 -0500 Subject: [PATCH 40/87] JCLOUDS-1231: Implement the SecurityGroupExtension in ARM --- .../arm/compute/AzureComputeService.java | 82 +++-- .../compute/AzureComputeServiceAdapter.java | 20 +- .../AzureComputeServiceContextModule.java | 145 ++++++-- .../domain/RegionAndIdAndIngressRules.java | 66 ++++ .../AzureComputeSecurityGroupExtension.java | 315 ++++++++++++++++++ .../NetworkSecurityGroupToSecurityGroup.java | 72 ++++ .../NetworkSecurityRuleToIpPermission.java | 76 +++++ .../VirtualMachineToNodeMetadata.java | 4 +- .../loaders/CreateSecurityGroupIfNeeded.java | 97 ++++++ .../CreateResourceGroupThenCreateNodes.java | 112 +++++-- .../arm/domain/NetworkSecurityGroup.java | 17 +- .../azurecompute/arm/domain/RegionAndId.java | 2 +- .../arm/functions/CleanupResources.java | 74 +++- .../AzureComputeImageExtensionLiveTest.java | 1 + ...ComputeSecurityGroupExtensionLiveTest.java | 154 +++++++++ .../NetworkSecurityGroupApiMockTest.java | 2 +- .../internal/BaseAzureComputeApiLiveTest.java | 2 +- .../src/test/resources/logback-test.xml | 2 +- 18 files changed, 1104 insertions(+), 139 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/domain/RegionAndIdAndIngressRules.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityGroupToSecurityGroup.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityRuleToIpPermission.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/CreateSecurityGroupIfNeeded.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java index c215e37bb7..a561375af6 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java @@ -16,11 +16,12 @@ */ 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.Map.Entry; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; @@ -30,6 +31,8 @@ import javax.inject.Provider; import javax.inject.Singleton; import org.jclouds.Constants; +import org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupName; +import org.jclouds.azurecompute.arm.functions.CleanupResources; import org.jclouds.collect.Memoized; import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.callables.RunScriptOnNode; @@ -54,51 +57,74 @@ 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.collect.ImmutableMultimap; +import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.ListeningExecutorService; @Singleton public class AzureComputeService extends BaseComputeService { - protected final CleanupResources cleanupResources; + private final CleanupResources cleanupResources; + private final LocationToResourceGroupName locationToResourceGroupName; @Inject protected AzureComputeService(ComputeServiceContext context, Map credentialStore, - @Memoized Supplier> images, @Memoized Supplier> sizes, - @Memoized Supplier> locations, ListNodesStrategy listNodesStrategy, - GetImageStrategy getImageStrategy, GetNodeMetadataStrategy getNodeMetadataStrategy, - CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, RebootNodeStrategy rebootNodeStrategy, - DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy startNodeStrategy, - SuspendNodeStrategy stopNodeStrategy, Provider templateBuilderProvider, - @Named("DEFAULT") Provider templateOptionsProvider, - @Named(TIMEOUT_NODE_RUNNING) Predicate> nodeRunning, - @Named(TIMEOUT_NODE_TERMINATED) Predicate> nodeTerminated, - @Named(TIMEOUT_NODE_SUSPENDED) Predicate> nodeSuspended, - InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, - RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, - PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, - @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, - CleanupResources cleanupResources, - Optional imageExtension, - Optional securityGroupExtension) { + @Memoized Supplier> images, @Memoized Supplier> sizes, + @Memoized Supplier> locations, ListNodesStrategy listNodesStrategy, + GetImageStrategy getImageStrategy, GetNodeMetadataStrategy getNodeMetadataStrategy, + CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, RebootNodeStrategy rebootNodeStrategy, + DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy startNodeStrategy, + SuspendNodeStrategy stopNodeStrategy, Provider templateBuilderProvider, + @Named("DEFAULT") Provider templateOptionsProvider, + @Named(TIMEOUT_NODE_RUNNING) Predicate> nodeRunning, + @Named(TIMEOUT_NODE_TERMINATED) Predicate> nodeTerminated, + @Named(TIMEOUT_NODE_SUSPENDED) Predicate> nodeSuspended, + InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, + RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess, + PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, + @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, + CleanupResources cleanupResources, Optional imageExtension, + Optional securityGroupExtension, + LocationToResourceGroupName locationToResourceGroupName) { 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"); - + getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, + startNodeStrategy, stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, + nodeTerminated, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, + persistNodeCredentials, timeouts, userExecutor, imageExtension, securityGroupExtension); + this.cleanupResources = cleanupResources; + this.locationToResourceGroupName = locationToResourceGroupName; } @Override protected void cleanUpIncidentalResourcesOfDeadNodes(Set deadNodes) { + ImmutableMultimap.Builder regionGroups = ImmutableMultimap.builder(); + ImmutableSet.Builder resourceGroups = ImmutableSet.builder(); + for (NodeMetadata deadNode : deadNodes) { - cleanupResources.apply(deadNode.getId()); + String resourceGroup = locationToResourceGroupName.apply(deadNode.getLocation().getId()); + + resourceGroups.add(resourceGroup); + if (deadNode.getGroup() != null) { + regionGroups.put(resourceGroup, deadNode.getGroup()); + } + + try { + cleanupResources.cleanupNode(deadNode.getId()); + } catch (Exception ex) { + logger.warn(ex, "Error cleaning up resources for node %s", deadNode); + } + } + + for (Entry regionGroup : regionGroups.build().entries()) { + cleanupResources.cleanupSecurityGroupIfOrphaned(regionGroup.getKey(), regionGroup.getValue()); + } + + for (String resourceGroup : resourceGroups.build()) { + cleanupResources.deleteResourceGroupIfEmpty(resourceGroup); } } - } 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 3b207b74d6..269f6b0f68 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 @@ -20,6 +20,7 @@ import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.Iterables.contains; import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Iterables.find; +import static com.google.common.collect.Iterables.getOnlyElement; 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; @@ -81,6 +82,7 @@ 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.options.TemplateOptions; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.location.Region; import org.jclouds.logging.Logger; @@ -137,11 +139,10 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter create one nic in each network - // TODO inbound ports String locationName = template.getLocation().getId(); String subnetId = templateOptions.getSubnetId(); - NetworkInterfaceCard nic = createNetworkInterfaceCard(subnetId, name, locationName, azureGroup); + NetworkInterfaceCard nic = createNetworkInterfaceCard(subnetId, name, locationName, azureGroup, template.getOptions()); StorageProfile storageProfile = createStorageProfile(name, template.getImage(), templateOptions.getBlob()); HardwareProfile hardwareProfile = HardwareProfile.builder().vmSize(template.getHardware().getId()).build(); OSProfile osProfile = createOsProfile(name, template); @@ -341,7 +342,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter { +public class AzureComputeServiceContextModule extends + ComputeServiceAdapterContextModule { @Override protected void configure() { super.configure(); - + bind(new TypeLiteral>() { }).to(AzureComputeServiceAdapter.class); - + bind(new TypeLiteral>() { }).to(VMImageToImage.class); bind(new TypeLiteral>() { @@ -98,19 +111,27 @@ public class AzureComputeServiceContextModule }).to(VirtualMachineToNodeMetadata.class); bind(new TypeLiteral>() { }).to(LocationToLocation.class); + bind(new TypeLiteral>() { + }).to(NetworkSecurityGroupToSecurityGroup.class); + bind(new TypeLiteral>() { + }).to(NetworkSecurityRuleToIpPermission.class); bind(ComputeService.class).to(AzureComputeService.class); - + install(new LocationsFromComputeServiceAdapterModule() { }); - + install(new FactoryModuleBuilder().build(ResourceDefinitionToCustomImage.Factory.class)); bind(TemplateOptions.class).to(AzureTemplateOptions.class); bind(NodeAndTemplateOptionsToStatement.class).to(NodeAndTemplateOptionsToStatementWithoutPublicKey.class); bind(CreateNodesInGroupThenAddToSet.class).to(CreateResourceGroupThenCreateNodes.class); - + bind(new TypeLiteral>() { + }).to(CreateSecurityGroupIfNeeded.class); + bind(new TypeLiteral() { }).to(AzureComputeImageExtension.class); + bind(new TypeLiteral() { + }).to(AzureComputeSecurityGroupExtension.class); } @Singleton @@ -189,64 +210,83 @@ public class AzureComputeServiceContextModule } } + @Provides + @Singleton + protected final LoadingCache securityGroupMap( + CacheLoader in) { + return CacheBuilder.newBuilder().build(in); + } + @Provides @Named(TIMEOUT_NODE_RUNNING) protected VirtualMachineInStatePredicateFactory provideVirtualMachineRunningPredicate(final AzureComputeApi api, - Timeouts timeouts, PollPeriod pollPeriod) { + final Timeouts timeouts, final PollPeriod pollPeriod) { return new VirtualMachineInStatePredicateFactory(api, PowerState.RUNNING, timeouts.nodeRunning, pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); } - + @Provides @Named(TIMEOUT_NODE_TERMINATED) - protected Predicate provideNodeTerminatedPredicate(final AzureComputeApi api, Timeouts timeouts, PollPeriod pollPeriod) { + protected Predicate provideNodeTerminatedPredicate(final AzureComputeApi api, final Timeouts timeouts, + final PollPeriod pollPeriod) { return retry(new ActionDonePredicate(api), timeouts.nodeTerminated, pollPeriod.pollInitialPeriod, - pollPeriod.pollMaxPeriod); + pollPeriod.pollMaxPeriod); } @Provides @Named(TIMEOUT_IMAGE_AVAILABLE) - protected Predicate provideImageAvailablePredicate(final AzureComputeApi api, Timeouts timeouts, PollPeriod pollPeriod) { + protected Predicate provideImageAvailablePredicate(final AzureComputeApi api, final Timeouts timeouts, + final PollPeriod pollPeriod) { return retry(new ImageDonePredicate(api), timeouts.imageAvailable, pollPeriod.pollInitialPeriod, - pollPeriod.pollMaxPeriod); + pollPeriod.pollMaxPeriod); } @Provides @Named(TIMEOUT_RESOURCE_DELETED) - protected Predicate provideResourceDeletedPredicate(final AzureComputeApi api, Timeouts timeouts, PollPeriod pollPeriod) { + protected Predicate provideResourceDeletedPredicate(final AzureComputeApi api, final Timeouts timeouts, + final PollPeriod pollPeriod) { return retry(new ActionDonePredicate(api), timeouts.nodeTerminated, pollPeriod.pollInitialPeriod, - pollPeriod.pollMaxPeriod); + pollPeriod.pollMaxPeriod); } @Provides @Named(TIMEOUT_NODE_SUSPENDED) protected VirtualMachineInStatePredicateFactory provideNodeSuspendedPredicate(final AzureComputeApi api, - Timeouts timeouts, PollPeriod pollPeriod) { + final Timeouts timeouts, final PollPeriod pollPeriod) { return new VirtualMachineInStatePredicateFactory(api, PowerState.STOPPED, timeouts.nodeTerminated, pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); } - + @Provides protected PublicIpAvailablePredicateFactory providePublicIpAvailablePredicate(final AzureComputeApi api, - final AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants, Timeouts timeouts, - PollPeriod pollPeriod) { + final AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants, final Timeouts timeouts, + final PollPeriod pollPeriod) { return new PublicIpAvailablePredicateFactory(api, azureComputeConstants.operationTimeout(), azureComputeConstants.operationPollInitialPeriod(), azureComputeConstants.operationPollMaxPeriod()); } + @Provides + protected SecurityGroupAvailablePredicateFactory provideSecurityGroupAvailablePredicate(final AzureComputeApi api, + final AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants, final Timeouts timeouts, + final PollPeriod pollPeriod) { + return new SecurityGroupAvailablePredicateFactory(api, azureComputeConstants.operationTimeout(), + azureComputeConstants.operationPollInitialPeriod(), azureComputeConstants.operationPollMaxPeriod()); + } + @VisibleForTesting static class ActionDonePredicate implements Predicate { private final AzureComputeApi api; - public ActionDonePredicate(AzureComputeApi api) { + public ActionDonePredicate(final AzureComputeApi api) { this.api = checkNotNull(api, "api must not be null"); } @Override - public boolean apply(URI uri) { + public boolean apply(final URI uri) { checkNotNull(uri, "uri cannot be null"); - return (ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri)) || (ParseJobStatus.JobStatus.NO_CONTENT == api.getJobApi().jobStatus(uri)); + return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri) + || ParseJobStatus.JobStatus.NO_CONTENT == api.getJobApi().jobStatus(uri); } } @@ -256,14 +296,16 @@ public class AzureComputeServiceContextModule private final AzureComputeApi api; - public ImageDonePredicate(AzureComputeApi api) { + public ImageDonePredicate(final AzureComputeApi api) { this.api = checkNotNull(api, "api must not be null"); } @Override - public boolean apply(URI uri) { + public boolean apply(final URI uri) { checkNotNull(uri, "uri cannot be null"); - if (api.getJobApi().jobStatus(uri) != ParseJobStatus.JobStatus.DONE) return false; + if (api.getJobApi().jobStatus(uri) != ParseJobStatus.JobStatus.DONE) { + return false; + } List definitions = api.getJobApi().captureStatus(uri); return definitions != null; } @@ -277,8 +319,8 @@ public class AzureComputeServiceContextModule private final long period; private final long maxPeriod; - VirtualMachineInStatePredicateFactory(AzureComputeApi api, PowerState powerState, long timeout, - long period, long maxPeriod) { + VirtualMachineInStatePredicateFactory(final AzureComputeApi api, final PowerState powerState, final long timeout, + final long period, final long maxPeriod) { this.api = checkNotNull(api, "api cannot be null"); this.powerState = checkNotNull(powerState, "powerState cannot be null"); this.timeout = timeout; @@ -289,17 +331,18 @@ public class AzureComputeServiceContextModule public Predicate create(final String azureGroup) { return retry(new Predicate() { @Override - public boolean apply(String name) { + public boolean apply(final String name) { checkNotNull(name, "name cannot be null"); VirtualMachineInstance vmInstance = api.getVirtualMachineApi(azureGroup).getInstanceDetails(name); - if (vmInstance == null) + if (vmInstance == null) { return false; + } return powerState == vmInstance.powerState(); } }, timeout, period, maxPeriod); } } - + public static class PublicIpAvailablePredicateFactory { private final AzureComputeApi api; @@ -307,25 +350,57 @@ public class AzureComputeServiceContextModule private final long period; private final long maxPeriod; - PublicIpAvailablePredicateFactory(AzureComputeApi api, long timeout, - long period, long maxPeriod) { + PublicIpAvailablePredicateFactory(final AzureComputeApi api, final long timeout, final long period, + final long maxPeriod) { this.api = checkNotNull(api, "api cannot be null"); this.timeout = timeout; this.period = period; this.maxPeriod = maxPeriod; } - + public Predicate create(final String azureGroup) { return retry(new Predicate() { @Override - public boolean apply(String name) { + public boolean apply(final String name) { checkNotNull(name, "name cannot be null"); PublicIPAddress publicIp = api.getPublicIPAddressApi(azureGroup).get(name); - if (publicIp == null) return false; + if (publicIp == null) { + return false; + } return publicIp.properties().provisioningState().equalsIgnoreCase("Succeeded"); } }, timeout, period, maxPeriod); } } + public static class SecurityGroupAvailablePredicateFactory { + private final AzureComputeApi api; + private final long timeout; + private final long period; + private final long maxPeriod; + + SecurityGroupAvailablePredicateFactory(final AzureComputeApi api, final long timeout, final long period, + final long maxPeriod) { + this.api = checkNotNull(api, "api cannot be null"); + this.timeout = timeout; + this.period = period; + this.maxPeriod = maxPeriod; + } + + public Predicate create(final String resourceGroup) { + checkNotNull(resourceGroup, "resourceGroup cannot be null"); + return retry(new Predicate() { + @Override + public boolean apply(final String name) { + checkNotNull(name, "name cannot be null"); + NetworkSecurityGroup sg = api.getNetworkSecurityGroupApi(resourceGroup).get(name); + if (sg == null) { + return false; + } + return sg.properties().provisioningState().equalsIgnoreCase("Succeeded"); + } + }, timeout, period, maxPeriod); + } + } + } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/domain/RegionAndIdAndIngressRules.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/domain/RegionAndIdAndIngressRules.java new file mode 100644 index 0000000000..fa9730d183 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/domain/RegionAndIdAndIngressRules.java @@ -0,0 +1,66 @@ +/* + * 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.domain; + +import org.jclouds.azurecompute.arm.domain.RegionAndId; + +import com.google.auto.value.AutoValue; +import com.google.common.base.Objects; + +@AutoValue +public abstract class RegionAndIdAndIngressRules { + + abstract RegionAndId regionAndId(); // Intentionally hidden + public abstract int[] inboundPorts(); + + RegionAndIdAndIngressRules() { + + } + + public static RegionAndIdAndIngressRules create(String region, String id, int[] inboundPorts) { + return new AutoValue_RegionAndIdAndIngressRules(RegionAndId.fromRegionAndId(region, id), inboundPorts); + } + + public String id() { + return regionAndId().id(); + } + + public String region() { + return regionAndId().region(); + } + + // Intentionally delegate equals and hashcode to the fields in the parent + // class so that we can search only by region/id in a map + + @Override + public int hashCode() { + return Objects.hashCode(region(), id()); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof RegionAndId)) { + return false; + } + RegionAndId that = (RegionAndId) obj; + return Objects.equal(region(), that.region()) && Objects.equal(id(), that.id()); + } + +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java new file mode 100644 index 0000000000..12d140bf6c --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java @@ -0,0 +1,315 @@ +/* + * 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.extensions; + +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Predicates.equalTo; +import static com.google.common.base.Predicates.notNull; +import static com.google.common.collect.Iterables.any; +import static com.google.common.collect.Iterables.concat; +import static com.google.common.collect.Iterables.filter; +import static com.google.common.collect.Iterables.transform; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +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.SecurityGroupAvailablePredicateFactory; +import org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupName; +import org.jclouds.azurecompute.arm.domain.IdReference; +import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; +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.NetworkSecurityRuleProperties.Access; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Direction; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Protocol; +import org.jclouds.azurecompute.arm.domain.RegionAndId; +import org.jclouds.azurecompute.arm.domain.VirtualMachine; +import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi; +import org.jclouds.azurecompute.arm.features.NetworkSecurityRuleApi; +import org.jclouds.collect.Memoized; +import org.jclouds.compute.domain.SecurityGroup; +import org.jclouds.compute.domain.SecurityGroupBuilder; +import org.jclouds.compute.extensions.SecurityGroupExtension; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.domain.Location; +import org.jclouds.logging.Logger; +import org.jclouds.net.domain.IpPermission; +import org.jclouds.net.domain.IpProtocol; + +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.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.collect.Multimap; +import com.google.common.collect.Ordering; + +public class AzureComputeSecurityGroupExtension implements SecurityGroupExtension { + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + private final AzureComputeApi api; + private final Function securityGroupConverter; + private final LocationToResourceGroupName locationToResourceGroupName; + private final Supplier> locations; + private final SecurityGroupAvailablePredicateFactory securityGroupAvailable; + private final Predicate resourceDeleted; + + @Inject + AzureComputeSecurityGroupExtension(AzureComputeApi api, @Memoized Supplier> locations, + LocationToResourceGroupName locationToResourceGroupName, + Function groupConverter, + SecurityGroupAvailablePredicateFactory securityRuleAvailable, + @Named(TIMEOUT_RESOURCE_DELETED) Predicate resourceDeleted) { + this.api = api; + this.locations = locations; + this.securityGroupConverter = groupConverter; + this.locationToResourceGroupName = locationToResourceGroupName; + this.securityGroupAvailable = securityRuleAvailable; + this.resourceDeleted = resourceDeleted; + } + + @Override + public Set listSecurityGroups() { + return ImmutableSet.copyOf(concat(transform(locations.get(), new Function>() { + @Override + public Set apply(Location input) { + return listSecurityGroupsInLocation(input); + } + }))); + } + + @Override + public Set listSecurityGroupsInLocation(Location location) { + logger.debug(">> getting security groups for %s...", location); + final String resourcegroup = locationToResourceGroupName.apply(location.getId()); + List networkGroups = api.getNetworkSecurityGroupApi(resourcegroup).list(); + return ImmutableSet.copyOf(transform(filter(networkGroups, notNull()), securityGroupConverter)); + } + + @Override + public Set listSecurityGroupsForNode(String nodeId) { + logger.debug(">> getting security groups for node %s...", nodeId); + + final RegionAndId regionAndId = RegionAndId.fromSlashEncoded(nodeId); + final String resourceGroup = locationToResourceGroupName.apply(regionAndId.region()); + + VirtualMachine vm = api.getVirtualMachineApi(resourceGroup).get(regionAndId.id()); + List networkInterfacesIdReferences = vm.properties().networkProfile().networkInterfaces(); + List networkGroups = new ArrayList(); + + for (IdReference networkInterfaceCardIdReference : networkInterfacesIdReferences) { + String nicName = Iterables.getLast(Splitter.on("/").split(networkInterfaceCardIdReference.id())); + NetworkInterfaceCard card = api.getNetworkInterfaceCardApi(resourceGroup).get(nicName); + if (card != null && card.properties().networkSecurityGroup() != null) { + String secGroupName = Iterables.getLast(Splitter.on("/").split( + card.properties().networkSecurityGroup().id())); + NetworkSecurityGroup group = api.getNetworkSecurityGroupApi(resourceGroup).get(secGroupName); + networkGroups.add(group); + } + } + + return ImmutableSet.copyOf(transform(filter(networkGroups, notNull()), securityGroupConverter)); + } + + @Override + public SecurityGroup getSecurityGroupById(String id) { + logger.debug(">> getting security group %s...", id); + final RegionAndId regionAndId = RegionAndId.fromSlashEncoded(id); + final String resourceGroup = locationToResourceGroupName.apply(regionAndId.region()); + + return securityGroupConverter.apply(api.getNetworkSecurityGroupApi(resourceGroup).get(regionAndId.id())); + } + + @Override + public SecurityGroup createSecurityGroup(String name, Location location) { + final String resourceGroup = locationToResourceGroupName.apply(location.getId()); + + logger.debug(">> creating security group %s in %s...", name, location); + + SecurityGroupBuilder builder = new SecurityGroupBuilder(); + builder.name(name); + builder.location(location); + + return securityGroupConverter.apply(api.getNetworkSecurityGroupApi(resourceGroup).createOrUpdate(name, + location.getId(), null, NetworkSecurityGroupProperties.builder().build())); + } + + @Override + public boolean removeSecurityGroup(String id) { + logger.debug(">> deleting security group %s...", id); + + final RegionAndId regionAndId = RegionAndId.fromSlashEncoded(id); + final String resourcegroup = locationToResourceGroupName.apply(regionAndId.region()); + URI uri = api.getNetworkSecurityGroupApi(resourcegroup).delete(regionAndId.id()); + return resourceDeleted.apply(uri); + } + + @Override + public SecurityGroup addIpPermission(IpPermission ipPermission, SecurityGroup group) { + return addIpPermission(ipPermission.getIpProtocol(), ipPermission.getFromPort(), ipPermission.getToPort(), + ipPermission.getTenantIdGroupNamePairs(), ipPermission.getCidrBlocks(), ipPermission.getGroupIds(), group); + } + + @Override + public SecurityGroup removeIpPermission(IpPermission ipPermission, SecurityGroup group) { + return removeIpPermission(ipPermission.getIpProtocol(), ipPermission.getFromPort(), ipPermission.getToPort(), + ipPermission.getTenantIdGroupNamePairs(), ipPermission.getCidrBlocks(), ipPermission.getGroupIds(), group); + } + + @Override + public SecurityGroup addIpPermission(IpProtocol protocol, int startPort, int endPort, + Multimap tenantIdGroupNamePairs, Iterable ipRanges, Iterable groupIds, + SecurityGroup group) { + String portRange = startPort + "-" + endPort; + String ruleName = protocol + "-" + portRange; + + logger.debug(">> adding ip permission [%s] to %s...", ruleName, group.getName()); + + // TODO: Support Azure network tags somehow? + + final RegionAndId regionAndId = RegionAndId.fromSlashEncoded(group.getId()); + final String resourceGroup = locationToResourceGroupName.apply(regionAndId.region()); + + NetworkSecurityGroupApi groupApi = api.getNetworkSecurityGroupApi(resourceGroup); + NetworkSecurityGroup networkSecurityGroup = groupApi.get(regionAndId.id()); + + if (networkSecurityGroup == null) { + throw new IllegalArgumentException("Security group " + group.getName() + " was not found"); + } + + NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourceGroup, networkSecurityGroup.name()); + int nextPriority = getRuleStartingPriority(ruleApi); + + for (String ipRange : ipRanges) { + NetworkSecurityRuleProperties properties = NetworkSecurityRuleProperties.builder() + .protocol(Protocol.fromValue(protocol.name())) // + .sourceAddressPrefix(ipRange) // + .sourcePortRange("*") // + .destinationAddressPrefix("*") // + .destinationPortRange(portRange) // + .direction(Direction.Inbound) // + .access(Access.Allow) // + .priority(nextPriority++) // + .build(); + + logger.debug(">> creating network security rule %s for %s...", ruleName, ipRange); + + ruleApi.createOrUpdate(ruleName, properties); + + checkState(securityGroupAvailable.create(resourceGroup).apply(networkSecurityGroup.name()), + "Security group was not updated in the configured timeout"); + } + + return getSecurityGroupById(group.getId()); + } + + @Override + public SecurityGroup removeIpPermission(final IpProtocol protocol, int startPort, int endPort, + Multimap tenantIdGroupNamePairs, final Iterable ipRanges, Iterable groupIds, + SecurityGroup group) { + final String portRange = startPort + "-" + endPort; + String ruleName = protocol + "-" + portRange; + + logger.debug(">> deleting ip permissions matching [%s] from %s...", ruleName, group.getName()); + + final RegionAndId regionAndId = RegionAndId.fromSlashEncoded(group.getId()); + final String resourceGroup = locationToResourceGroupName.apply(regionAndId.region()); + + NetworkSecurityGroupApi groupApi = api.getNetworkSecurityGroupApi(resourceGroup); + NetworkSecurityGroup networkSecurityGroup = groupApi.get(regionAndId.id()); + + if (networkSecurityGroup == null) { + throw new IllegalArgumentException("Security group " + group.getName() + " was not found"); + } + + NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourceGroup, networkSecurityGroup.name()); + Iterable rules = filter(ruleApi.list(), new Predicate() { + @Override + public boolean apply(NetworkSecurityRule input) { + NetworkSecurityRuleProperties props = input.properties(); + return Objects.equal(portRange, props.destinationPortRange()) + && Objects.equal(Protocol.fromValue(protocol.name()), props.protocol()) + && Objects.equal(Direction.Inbound, props.direction()) // + && Objects.equal(Access.Allow, props.access()) + && any(ipRanges, equalTo(props.sourceAddressPrefix().replace("*", "0.0.0.0/0"))); + } + }); + + for (NetworkSecurityRule matchingRule : rules) { + logger.debug(">> deleting network security rule %s from %s...", matchingRule.name(), group.getName()); + ruleApi.delete(matchingRule.name()); + checkState(securityGroupAvailable.create(resourceGroup).apply(networkSecurityGroup.name()), + "Security group was not updated in the configured timeout"); + } + + return getSecurityGroupById(group.getId()); + } + + @Override + public boolean supportsTenantIdGroupNamePairs() { + return false; + } + + @Override + public boolean supportsTenantIdGroupIdPairs() { + return false; + } + + @Override + public boolean supportsGroupIds() { + return false; + } + + @Override + public boolean supportsPortRangesForGroups() { + return false; + } + + @Override + public boolean supportsExclusionCidrBlocks() { + return false; + } + + private int getRuleStartingPriority(NetworkSecurityRuleApi ruleApi) { + List existingRules = ruleApi.list(); + return existingRules.isEmpty() ? 100 : rulesByPriority().max(existingRules).properties().priority() + 1; + } + + private static Ordering rulesByPriority() { + return new Ordering() { + @Override + public int compare(NetworkSecurityRule left, NetworkSecurityRule right) { + return left.properties().priority() - right.properties().priority(); + } + }; + } + +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityGroupToSecurityGroup.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityGroupToSecurityGroup.java new file mode 100644 index 0000000000..65f5b0d8aa --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityGroupToSecurityGroup.java @@ -0,0 +1,72 @@ +/* + * 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.collect.Iterables.filter; +import static com.google.common.collect.Iterables.transform; +import static org.jclouds.azurecompute.arm.compute.functions.NetworkSecurityRuleToIpPermission.InboundRule; +import static org.jclouds.azurecompute.arm.compute.functions.VirtualMachineToNodeMetadata.getLocation; + +import java.util.Set; + +import javax.inject.Singleton; + +import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityRule; +import org.jclouds.azurecompute.arm.domain.RegionAndId; +import org.jclouds.collect.Memoized; +import org.jclouds.compute.domain.SecurityGroup; +import org.jclouds.compute.domain.SecurityGroupBuilder; +import org.jclouds.domain.Location; +import org.jclouds.net.domain.IpPermission; + +import com.google.common.base.Function; +import com.google.common.base.Supplier; +import com.google.inject.Inject; + +@Singleton +public class NetworkSecurityGroupToSecurityGroup implements Function { + private final Function ruleToPermission; + private final Supplier> locations; + + @Inject + NetworkSecurityGroupToSecurityGroup(Function ruleToPermission, + @Memoized Supplier> locations) { + this.ruleToPermission = ruleToPermission; + this.locations = locations; + } + + @Override + public SecurityGroup apply(NetworkSecurityGroup input) { + SecurityGroupBuilder builder = new SecurityGroupBuilder(); + + builder.id(RegionAndId.fromRegionAndId(input.location(), input.name()).slashEncode()); + builder.providerId(input.properties().resourceGuid()); + builder.name(input.name()); + builder.location(getLocation(locations, input.location())); + + if (input.properties().securityRules() != null) { + // We just supoprt security groups that allow traffic to a set of + // targets. We don't support deny rules or origin based rules in the + // security group api. + builder.ipPermissions(transform(filter(input.properties().securityRules(), InboundRule), ruleToPermission)); + } + + return builder.build(); + } + +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityRuleToIpPermission.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityRuleToIpPermission.java new file mode 100644 index 0000000000..e601d59403 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityRuleToIpPermission.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.azurecompute.arm.compute.functions; + +import javax.annotation.Resource; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.azurecompute.arm.domain.NetworkSecurityRule; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Access; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Direction; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.logging.Logger; +import org.jclouds.net.domain.IpPermission; +import org.jclouds.net.domain.IpProtocol; +import org.jclouds.net.util.IpPermissions; +import org.jclouds.net.util.IpPermissions.PortSelection; +import org.jclouds.net.util.IpPermissions.ToSourceSelection; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; + +@Singleton +public class NetworkSecurityRuleToIpPermission implements Function { + + public static final Predicate InboundRule = new Predicate() { + @Override + public boolean apply(NetworkSecurityRule input) { + return Direction.Inbound.equals(input.properties().direction()) + && Access.Allow.equals(input.properties().access()); + } + }; + + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + @Override + public IpPermission apply(final NetworkSecurityRule rule) { + if (!InboundRule.apply(rule)) { + logger.warn(">> ignoring non-inbound networks ecurity rule %s...", rule.name()); + return null; + } + + IpPermission permissions = IpPermissions.permit(IpProtocol.fromValue(rule.properties().protocol().name())); + + String portRange = rule.properties().destinationPortRange(); + if (!"*".equals(portRange)) { + String[] range = portRange.split("-"); + permissions = PortSelection.class.cast(permissions).fromPort(Integer.parseInt(range[0])) + .to(Integer.parseInt(range[1])); + } + + if (!"*".equals(rule.properties().sourceAddressPrefix())) { + permissions = ToSourceSelection.class.cast(permissions).originatingFromCidrBlock( + rule.properties().sourceAddressPrefix()); + } + + return permissions; + } + +} 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 index 5e98fbf242..22c818c089 100644 --- 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 @@ -191,7 +191,7 @@ public class VirtualMachineToNodeMetadata implements Function image = findImage(virtualMachine.properties().storageProfile(), locationName, azureGroup); if (image.isPresent()) { @@ -251,7 +251,7 @@ public class VirtualMachineToNodeMetadata implements Function> locations, final String locationName) { return find(locations.get(), new Predicate() { @Override public boolean apply(Location location) { diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/CreateSecurityGroupIfNeeded.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/CreateSecurityGroupIfNeeded.java new file mode 100644 index 0000000000..efb8abce86 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/CreateSecurityGroupIfNeeded.java @@ -0,0 +1,97 @@ +/* + * 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.loaders; + +import static org.jclouds.compute.util.ComputeServiceUtils.getPortRangesFromList; + +import java.util.ArrayList; +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 org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.compute.domain.RegionAndIdAndIngressRules; +import org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupName; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; +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.NetworkSecurityRuleProperties.Access; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Direction; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Protocol; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.logging.Logger; + +import com.google.common.cache.CacheLoader; + +@Singleton +public class CreateSecurityGroupIfNeeded extends CacheLoader { + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + private final AzureComputeApi api; + private final LocationToResourceGroupName locationToResourceGroupName; + + @Inject + CreateSecurityGroupIfNeeded(AzureComputeApi api, LocationToResourceGroupName locationToResourceGroupName) { + this.api = api; + this.locationToResourceGroupName = locationToResourceGroupName; + } + + @Override + public String load(RegionAndIdAndIngressRules key) throws Exception { + String resourceGroup = locationToResourceGroupName.apply(key.region()); + return createSecurityGroup(key.region(), resourceGroup, key.id(), key.inboundPorts()); + } + + private String createSecurityGroup(String location, String resourceGroup, String name, int[] inboundPorts) { + logger.debug(">> creating security group %s in %s...", name, location); + + Map portRanges = getPortRangesFromList(inboundPorts); + + List rules = new ArrayList(); + + int startPriority = 100; + for (Map.Entry portRange : portRanges.entrySet()) { + String range = portRange.getKey() + "-" + portRange.getValue(); + String ruleName = "tcp-" + range; + + NetworkSecurityRuleProperties properties = NetworkSecurityRuleProperties.builder().protocol(Protocol.Tcp) // + .sourceAddressPrefix("*") // + .sourcePortRange("*") // + .destinationAddressPrefix("*") // + .destinationPortRange(range) // + .direction(Direction.Inbound) // + .access(Access.Allow) // + .priority(startPriority++) // + .build(); + + rules.add(NetworkSecurityRule.create(ruleName, null, null, properties)); + } + + NetworkSecurityGroup securityGroup = api.getNetworkSecurityGroupApi(resourceGroup).createOrUpdate(name, location, + null, NetworkSecurityGroupProperties.builder().securityRules(rules).build()); + + return securityGroup.id(); + } + +} 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 5ce30b0515..524eb69005 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 @@ -16,8 +16,10 @@ */ package org.jclouds.azurecompute.arm.compute.strategy; +import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.Iterables.getOnlyElement; import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.decodeFieldsFromUniqueId; import static org.jclouds.util.Predicates2.retry; @@ -35,8 +37,11 @@ import javax.inject.Singleton; import org.jclouds.Constants; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule; +import org.jclouds.azurecompute.arm.compute.domain.RegionAndIdAndIngressRules; import org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupName; import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; +import org.jclouds.azurecompute.arm.domain.RegionAndId; import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.domain.StorageService; import org.jclouds.azurecompute.arm.domain.Subnet; @@ -51,15 +56,18 @@ import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.Template; import org.jclouds.compute.functions.GroupNamingConvention; +import org.jclouds.compute.options.TemplateOptions; 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.domain.Location; import org.jclouds.logging.Logger; import com.google.common.base.Predicate; import com.google.common.base.Strings; +import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Multimap; import com.google.common.util.concurrent.ListenableFuture; @@ -75,34 +83,37 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco private final AzureComputeApi api; private final AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants; private final LocationToResourceGroupName locationToResourceGroupName; + private final LoadingCache securityGroupMap; @Inject protected CreateResourceGroupThenCreateNodes( - CreateNodeWithGroupEncodedIntoName addNodeWithGroupStrategy, - ListNodesStrategy listNodesStrategy, - GroupNamingConvention.Factory namingConvention, + CreateNodeWithGroupEncodedIntoName addNodeWithGroupStrategy, + ListNodesStrategy listNodesStrategy, + GroupNamingConvention.Factory namingConvention, @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory, AzureComputeApi api, AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants, - LocationToResourceGroupName locationToResourceGroupName) { + LocationToResourceGroupName locationToResourceGroupName, + LoadingCache securityGroupMap) { super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor, - customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory); + customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory); this.api = checkNotNull(api, "api cannot be null"); checkNotNull(userExecutor, "userExecutor cannot be null"); this.azureComputeConstants = azureComputeConstants; this.locationToResourceGroupName = locationToResourceGroupName; + this.securityGroupMap = securityGroupMap; } @Override public Map> execute(String group, int count, Template template, - Set goodNodes, Map badNodes, - Multimap customizationResponses) { + 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"); + logger.warn(">> a runScript was configured but no SSH key has been provided. " + + "Authentication will delegate to the ssh-agent"); } String azureGroupName = locationToResourceGroupName.apply(template.getLocation().getId()); @@ -112,7 +123,7 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco ResourceGroup resourceGroup = resourceGroupApi.get(azureGroupName); final String location = template.getLocation().getId(); - if (resourceGroup == null){ + if (resourceGroup == null) { final Map tags = ImmutableMap.of("description", "jclouds managed VMs"); resourceGroupApi.create(azureGroupName, location, tags).name(); } @@ -125,33 +136,35 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco } this.getOrCreateVirtualNetworkWithSubnet(vnetName, subnetName, location, options, azureGroupName); + configureSecurityGroupForOptions(group, azureGroupName, template.getLocation(), options); 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); + customizationResponses); return responses; } - protected synchronized void getOrCreateVirtualNetworkWithSubnet( - final String virtualNetworkName, final String subnetName, final String location, - AzureTemplateOptions options, final String azureGroupName) { + protected synchronized void getOrCreateVirtualNetworkWithSubnet(final String virtualNetworkName, + final String subnetName, final String location, AzureTemplateOptions options, final String azureGroupName) { - //Subnets belong to a virtual network so that needs to be created first + // Subnets belong to a virtual network so that needs to be created first VirtualNetworkApi vnApi = api.getVirtualNetworkApi(azureGroupName); VirtualNetwork vn = vnApi.get(virtualNetworkName); if (vn == null) { - VirtualNetwork.VirtualNetworkProperties virtualNetworkProperties = VirtualNetwork.VirtualNetworkProperties.builder() - .addressSpace(VirtualNetwork.AddressSpace.create(Arrays.asList(this.azureComputeConstants.azureDefaultVnetAddressPrefixProperty()))) - .subnets( - Arrays.asList( - Subnet.create(subnetName, null, null, - Subnet.SubnetProperties.builder().addressPrefix(this.azureComputeConstants.azureDefaultSubnetAddressPrefixProperty()).build()))) - .build(); + VirtualNetwork.VirtualNetworkProperties virtualNetworkProperties = VirtualNetwork.VirtualNetworkProperties + .builder() + .addressSpace( + VirtualNetwork.AddressSpace.create(Arrays.asList(this.azureComputeConstants + .azureDefaultVnetAddressPrefixProperty()))) + .subnets( + Arrays.asList(Subnet.create(subnetName, null, null, Subnet.SubnetProperties.builder() + .addressPrefix(this.azureComputeConstants.azureDefaultSubnetAddressPrefixProperty()).build()))) + .build(); vn = vnApi.createOrUpdate(virtualNetworkName, location, virtualNetworkProperties); } @@ -164,10 +177,11 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco private static boolean hasRunScriptWithKeyAuthAndNoPrivateKey(Template template) { return template.getOptions().getRunScript() != null && template.getOptions().getPublicKey() != null - && !template.getOptions().hasLoginPrivateKeyOption(); + && !template.getOptions().hasLoginPrivateKeyOption(); } - public StorageService getOrCreateStorageService(String name, String resourceGroupName, String locationName, Image image) { + public StorageService getOrCreateStorageService(String name, String resourceGroupName, String locationName, + Image image) { String storageAccountName = null; VMImage imageRef = decodeFieldsFromUniqueId(image.getId()); if (imageRef.custom()) { @@ -179,10 +193,12 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco } StorageService storageService = api.getStorageAccountApi(resourceGroupName).get(storageAccountName); - if (storageService != null) return storageService; + 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())); + 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) { @@ -195,16 +211,44 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco return api.getStorageAccountApi(resourceGroupName).get(storageAccountName); } + private void configureSecurityGroupForOptions(String group, String resourceGroup, Location location, + TemplateOptions options) { + + checkArgument(options.getGroups().size() <= 1, + "Only one security group can be configured for each network interface"); + + if (!options.getGroups().isEmpty()) { + String groupName = getOnlyElement(options.getGroups()); + String groupNameWithourRegion = groupName.indexOf('/') == -1 ? groupName : RegionAndId.fromSlashEncoded( + groupName).id(); + NetworkSecurityGroup securityGroup = api.getNetworkSecurityGroupApi(resourceGroup).get(groupNameWithourRegion); + checkArgument(securityGroup != null, "Security group %s was not found", groupName); + options.securityGroups(securityGroup.id()); + } else if (options.getInboundPorts().length > 0) { + String name = namingConvention.create().sharedNameForGroup(group); + RegionAndIdAndIngressRules regionAndIdAndIngressRules = RegionAndIdAndIngressRules.create(location.getId(), + name, options.getInboundPorts()); + // this will create if not yet exists. + String securityGroupId = securityGroupMap.getUnchecked(regionAndIdAndIngressRules); + options.securityGroups(securityGroupId); + } + } + /** * 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. + * 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. + * @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); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityGroup.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityGroup.java index ebe842e038..e7c75e8610 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityGroup.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityGroup.java @@ -25,7 +25,7 @@ import java.util.Map; @AutoValue public abstract class NetworkSecurityGroup { - @Nullable + public abstract String id(); public abstract String name(); @Nullable @@ -40,15 +40,10 @@ public abstract class NetworkSecurityGroup { @Nullable public abstract String etag(); - @SerializedNames({"name", "location", "tags", "properties", "etag"}) - public static NetworkSecurityGroup create(final String name, - final String location, - final Map tags, - final NetworkSecurityGroupProperties properties, - final String etag) { - return new AutoValue_NetworkSecurityGroup(name, location, - (tags == null) ? null : ImmutableMap.copyOf(tags), - properties, etag); + @SerializedNames({ "id", "name", "location", "tags", "properties", "etag" }) + public static NetworkSecurityGroup create(final String id, final String name, final String location, + final Map tags, final NetworkSecurityGroupProperties properties, final String etag) { + return new AutoValue_NetworkSecurityGroup(id, name, location, (tags == null) ? null : ImmutableMap.copyOf(tags), + properties, etag); } } - diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/RegionAndId.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/RegionAndId.java index 233109aa0a..4105ee3dc9 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/RegionAndId.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/RegionAndId.java @@ -29,7 +29,7 @@ public abstract class RegionAndId { public abstract String region(); public abstract String id(); - RegionAndId() { + protected RegionAndId() { } 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 ead676a751..9d2a1c1850 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 @@ -35,10 +35,13 @@ import org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupNam 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.RegionAndId; import org.jclouds.azurecompute.arm.domain.StorageServiceKeys; import org.jclouds.azurecompute.arm.domain.VirtualMachine; +import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi; import org.jclouds.azurecompute.arm.util.BlobHelper; +import org.jclouds.compute.functions.GroupNamingConvention; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.logging.Logger; @@ -49,7 +52,7 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Lists; @Singleton -public class CleanupResources implements Function { +public class CleanupResources { @Resource @Named(ComputeServiceConstants.COMPUTE_LOGGER) @@ -59,22 +62,23 @@ public class CleanupResources implements Function { private final Predicate resourceDeleted; private final StorageProfileToStorageAccountName storageProfileToStorageAccountName; private final LocationToResourceGroupName locationToResourceGroupName; + private final GroupNamingConvention.Factory namingConvention; @Inject CleanupResources(AzureComputeApi azureComputeApi, @Named(TIMEOUT_RESOURCE_DELETED) Predicate resourceDeleted, StorageProfileToStorageAccountName storageProfileToStorageAccountName, - LocationToResourceGroupName locationToResourceGroupName) { + LocationToResourceGroupName locationToResourceGroupName, GroupNamingConvention.Factory namingConvention) { this.api = azureComputeApi; this.resourceDeleted = resourceDeleted; this.storageProfileToStorageAccountName = storageProfileToStorageAccountName; this.locationToResourceGroupName = locationToResourceGroupName; + this.namingConvention = namingConvention; } - @Override - public Boolean apply(final String id) { + public boolean cleanupNode(final String id) { RegionAndId regionAndId = RegionAndId.fromSlashEncoded(id); String group = locationToResourceGroupName.apply(regionAndId.region()); - + VirtualMachine virtualMachine = api.getVirtualMachineApi(group).get(regionAndId.id()); if (virtualMachine == null) { return true; @@ -82,10 +86,17 @@ public class CleanupResources implements Function { logger.debug(">> destroying %s ...", regionAndId.slashEncode()); 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 + cleanupVirtualMachineNICs(group, virtualMachine); + cleanupVirtualMachineStorage(group, virtualMachine); + + return vmDeleted; + } + + public void cleanupVirtualMachineNICs(String group, VirtualMachine virtualMachine) { for (String nicName : getNetworkCardInterfaceNames(virtualMachine)) { NetworkInterfaceCard nic = api.getNetworkInterfaceCardApi(group).get(nicName); Iterable publicIps = getPublicIps(group, nic); @@ -99,8 +110,11 @@ public class CleanupResources implements Function { api.getPublicIPAddressApi(group).delete(publicIp); } } + } - String storageAccountName = storageProfileToStorageAccountName.apply(virtualMachine.properties().storageProfile()); + public void cleanupVirtualMachineStorage(String group, VirtualMachine virtualMachine) { + String storageAccountName = storageProfileToStorageAccountName + .apply(virtualMachine.properties().storageProfile()); StorageServiceKeys keys = api.getStorageAccountApi(group).getKeys(storageAccountName); // Remove the virtual machine files @@ -118,20 +132,44 @@ public class CleanupResources implements Function { } 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)); + public boolean cleanupSecurityGroupIfOrphaned(String resourceGroup, String group) { + String name = namingConvention.create().sharedNameForGroup(group); + NetworkSecurityGroupApi sgapi = api.getNetworkSecurityGroupApi(resourceGroup); + + boolean deleted = false; + + try { + NetworkSecurityGroup securityGroup = sgapi.get(name); + if (securityGroup != null) { + List nics = securityGroup.properties().networkInterfaces(); + if (nics == null || nics.isEmpty()) { + logger.debug(">> deleting orphaned security group %s from %s...", name, resourceGroup); + try { + deleted = resourceDeleted.apply(sgapi.delete(name)); + } catch (Exception ex) { + logger.warn(ex, ">> error deleting orphaned security group %s from %s...", name, resourceGroup); + } + } + } + } catch (Exception ex) { + logger.warn(ex, "Error deleting security groups for %s and group %s", resourceGroup, group); } + + return deleted; + } + + public boolean deleteResourceGroupIfEmpty(String group) { + boolean deleted = false; + if (api.getVirtualMachineApi(group).list().isEmpty() && api.getStorageAccountApi(group).list().isEmpty() + && api.getNetworkInterfaceCardApi(group).list().isEmpty() + && api.getPublicIPAddressApi(group).list().isEmpty() + && api.getNetworkSecurityGroupApi(group).list().isEmpty()) { + logger.debug(">> the resource group %s is empty. Deleting...", group); + deleted = resourceDeleted.apply(api.getResourceGroupApi().delete(group)); + } + return deleted; } private Iterable getPublicIps(String group, NetworkInterfaceCard nic) { 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 c8a9259dc5..8939eb13d6 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 @@ -71,4 +71,5 @@ public class AzureComputeImageExtensionLiveTest extends BaseImageExtensionLiveTe .overrideLoginPrivateKey(keyPair.get("private"))); } + } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java new file mode 100644 index 0000000000..02fe52e02d --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java @@ -0,0 +1,154 @@ +/* + * 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.extensions; + +import static com.google.common.collect.Iterables.get; +import static com.google.common.collect.Iterables.getOnlyElement; +import static java.util.logging.Logger.getAnonymousLogger; +import static org.jclouds.compute.options.TemplateOptions.Builder.inboundPorts; +import static org.jclouds.compute.options.TemplateOptions.Builder.securityGroups; +import static org.jclouds.compute.predicates.NodePredicates.inGroup; +import static org.jclouds.net.domain.IpProtocol.TCP; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.ExecutionException; + +import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; +import org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupName; +import org.jclouds.azurecompute.arm.domain.ResourceGroup; +import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; +import org.jclouds.compute.ComputeService; +import org.jclouds.compute.RunNodesException; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.SecurityGroup; +import org.jclouds.compute.extensions.SecurityGroupExtension; +import org.jclouds.compute.extensions.internal.BaseSecurityGroupExtensionLiveTest; +import org.jclouds.domain.Location; +import org.jclouds.net.util.IpPermissions; +import org.jclouds.providers.ProviderMetadata; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableMap; + +/** + * Live test for AzureCompute + * {@link org.jclouds.compute.extensions.SecurityGroupExtension} implementation. + */ +@Test(groups = "live", singleThreaded = true, testName = "AzureComputeSecurityGroupExtensionLiveTest") +public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGroupExtensionLiveTest { + + private AzureComputeApi api; + private LocationToResourceGroupName locationToResourceGroupName; + private String resourceGroupName; + private ResourceGroup testResourceGroup; + + public AzureComputeSecurityGroupExtensionLiveTest() { + provider = "azurecompute-arm"; + } + + @BeforeClass(groups = { "integration", "live" }) + public void setupContext() { + super.setupContext(); + api = context.utils().injector().getInstance(AzureComputeApi.class); + locationToResourceGroupName = context.utils().injector().getInstance(LocationToResourceGroupName.class); + createResourceGroupIfMissing(); + } + + @Test(groups = { "integration", "live" }, dependsOnMethods = "testCreateSecurityGroup") + public void testCreateNodeWithSecurityGroup() throws RunNodesException, InterruptedException, ExecutionException { + ComputeService computeService = view.getComputeService(); + Optional securityGroupExtension = computeService.getSecurityGroupExtension(); + assertTrue(securityGroupExtension.isPresent(), "security group extension was not present"); + + NodeMetadata node = getOnlyElement(computeService.createNodesInGroup(nodeGroup, 1, securityGroups(groupId))); + + try { + Set groups = securityGroupExtension.get().listSecurityGroupsForNode(node.getId()); + assertEquals(groups.size(), 1, "node has " + groups.size() + " groups"); + assertEquals(getOnlyElement(groups).getId(), groupId); + } finally { + computeService.destroyNodesMatching(inGroup(node.getGroup())); + } + } + + @Test(groups = { "integration", "live" }, dependsOnMethods = "testCreateSecurityGroup") + public void testCreateNodeWithInboundPorts() throws RunNodesException, InterruptedException, ExecutionException { + ComputeService computeService = view.getComputeService(); + Optional securityGroupExtension = computeService.getSecurityGroupExtension(); + assertTrue(securityGroupExtension.isPresent(), "security group extension was not present"); + + NodeMetadata node = getOnlyElement(computeService + .createNodesInGroup(nodeGroup, 1, inboundPorts(22, 23, 24, 8000))); + + try { + Set groups = securityGroupExtension.get().listSecurityGroupsForNode(node.getId()); + assertEquals(groups.size(), 1, "node has " + groups.size() + " groups"); + + SecurityGroup group = getOnlyElement(groups); + assertEquals(group.getIpPermissions().size(), 2); + assertEquals(get(group.getIpPermissions(), 0), IpPermissions.permit(TCP).fromPort(22).to(24)); + assertEquals(get(group.getIpPermissions(), 1), IpPermissions.permit(TCP).port(8000)); + } finally { + computeService.destroyNodesMatching(inGroup(node.getGroup())); + } + } + + @AfterClass(groups = { "integration", "live" }) + @Override + protected void tearDownContext() { + super.tearDownContext(); + if (testResourceGroup != null) { + // Cleanup the resource group we created for the tests + getAnonymousLogger().info( + "deleting resource group " + testResourceGroup.name() + " for the security group live tests..."); + api.getResourceGroupApi().delete(testResourceGroup.name()); + } + } + + @Override + protected Properties setupProperties() { + Properties properties = super.setupProperties(); + AzureLiveTestUtils.defaultProperties(properties); + setIfTestSystemPropertyPresent(properties, "oauth.endpoint"); + return properties; + } + + @Override + protected ProviderMetadata createProviderMetadata() { + return AzureComputeProviderMetadata.builder().build(); + } + + private void createResourceGroupIfMissing() { + Location location = getNodeTemplate().getLocation(); + resourceGroupName = locationToResourceGroupName.apply(location.getId()); + ResourceGroup resourceGroupInLocation = api.getResourceGroupApi().get(resourceGroupName); + if (resourceGroupInLocation == null) { + getAnonymousLogger().info( + "creating resource group " + resourceGroupName + " for the security group live tests..."); + final Map tags = ImmutableMap.of("description", "AzureComputeSecurityGroupExtensionLiveTest"); + testResourceGroup = api.getResourceGroupApi().create(resourceGroupName, location.getId(), tags); + } + } +} 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 2d43694684..3dc0e4aa20 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 @@ -57,7 +57,7 @@ public class NetworkSecurityGroupApiMockTest extends BaseAzureComputeApiMockTest .build()); ArrayList ruleList = new ArrayList(); ruleList.add(rule); - NetworkSecurityGroup nsg = NetworkSecurityGroup.create("samplensg", "westus", null, + NetworkSecurityGroup nsg = NetworkSecurityGroup.create("id", "samplensg", "westus", null, NetworkSecurityGroupProperties.builder() .securityRules(ruleList) .build(), diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java index bd7cde4f7a..c3c6aa7f0a 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java @@ -154,7 +154,7 @@ public class BaseAzureComputeApiLiveTest extends BaseApiLiveTest ruleList = Lists.newArrayList(); ruleList.add(rule); - NetworkSecurityGroup nsg = NetworkSecurityGroup.create(nsgName, locationName, null, + NetworkSecurityGroup nsg = NetworkSecurityGroup.create("id", nsgName, locationName, null, NetworkSecurityGroupProperties.builder() .securityRules(ruleList) .build(), diff --git a/providers/azurecompute-arm/src/test/resources/logback-test.xml b/providers/azurecompute-arm/src/test/resources/logback-test.xml index cb55d49823..b9e961687f 100644 --- a/providers/azurecompute-arm/src/test/resources/logback-test.xml +++ b/providers/azurecompute-arm/src/test/resources/logback-test.xml @@ -13,7 +13,7 @@ - target/jclouds-compute.log + target/test-data/jclouds-compute.log %d %-5p [%c] [%thread] %m%n From 176abfa7fd4274f3a6c010926efb0f3cd6b47e33 Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Thu, 26 Jan 2017 10:34:49 +0100 Subject: [PATCH 41/87] Cleanup legacy code and introduce the resource group cache --- .../arm/AzureComputeProviderMetadata.java | 17 +-- .../arm/compute/AzureComputeService.java | 18 +-- .../compute/AzureComputeServiceAdapter.java | 51 ++++---- .../AzureComputeServiceContextModule.java | 118 ++++-------------- .../AzureComputeImageExtension.java | 25 ++-- .../AzureComputeSecurityGroupExtension.java | 75 +++++------ .../NetworkSecurityRuleToIpPermission.java | 4 +- .../ResourceDefinitionToCustomImage.java | 33 +++-- .../VirtualMachineToNodeMetadata.java | 41 +++--- .../loaders/CreateSecurityGroupIfNeeded.java | 13 +- .../loaders/ResourceGroupForLocation.java | 62 +++++++++ .../compute/options/AzureTemplateOptions.java | 108 +--------------- .../predicates/IsDeploymentInRegions.java | 47 ------- .../strategy}/CleanupResources.java | 25 ++-- .../CreateResourceGroupThenCreateNodes.java | 94 ++++++-------- .../arm/config/AzureComputeProperties.java | 14 --- ...ComputeSecurityGroupExtensionLiveTest.java | 36 ++---- 17 files changed, 292 insertions(+), 489 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/ResourceGroupForLocation.java delete mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/predicates/IsDeploymentInRegions.java rename providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/{functions => compute/strategy}/CleanupResources.java (89%) 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 dd516ef3ad..1590bf234e 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 @@ -19,16 +19,10 @@ package org.jclouds.azurecompute.arm; import static org.jclouds.Constants.PROPERTY_MAX_RATE_LIMIT_WAIT; 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.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.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.compute.config.ComputeServiceProperties.IMAGE_AUTHENTICATE_SUDO; import static org.jclouds.compute.config.ComputeServiceProperties.IMAGE_LOGIN_USER; import static org.jclouds.compute.config.ComputeServiceProperties.POLL_INITIAL_PERIOD; @@ -83,27 +77,22 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { public static Properties defaultProperties() { final Properties properties = AzureManagementApiMetadata.defaultProperties(); properties.put(POLL_INITIAL_PERIOD, 1000); - properties.put(POLL_MAX_PERIOD, 10000); + properties.put(POLL_MAX_PERIOD, 15000); properties.put(OPERATION_TIMEOUT, 46000000); - properties.put(OPERATION_POLL_INITIAL_PERIOD, 5); - properties.put(OPERATION_POLL_MAX_PERIOD, 15); + properties.put(TIMEOUT_NODE_TERMINATED, 60 * 10 * 1000); // Default max wait in rate limit: 5m30s properties.put(PROPERTY_MAX_RATE_LIMIT_WAIT, 330000); - properties.put(TCP_RULE_FORMAT, "tcp_%s-%s"); - properties.put(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(DEFAULT_VNET_ADDRESS_SPACE_PREFIX, "10.0.0.0/16"); properties.put(DEFAULT_SUBNET_ADDRESS_PREFIX, "10.0.0.0/24"); properties.put(RESOURCENAME_PREFIX, "jclouds"); properties.put(RESOURCENAME_DELIMITER, "-"); - properties.put(DEFAULT_DATADISKSIZE, 100); properties.put(IMAGE_PUBLISHERS, "Canonical,RedHat"); // 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"); @@ -114,7 +103,7 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { 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 + StorageAccountApi.class.getSimpleName(), "2015-06-15"); 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"); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java index a561375af6..f566a69c53 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java @@ -31,8 +31,8 @@ import javax.inject.Provider; import javax.inject.Singleton; import org.jclouds.Constants; -import org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupName; -import org.jclouds.azurecompute.arm.functions.CleanupResources; +import org.jclouds.azurecompute.arm.compute.strategy.CleanupResources; +import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.collect.Memoized; import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.callables.RunScriptOnNode; @@ -62,6 +62,7 @@ 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.cache.LoadingCache; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.ListeningExecutorService; @@ -69,7 +70,7 @@ import com.google.common.util.concurrent.ListeningExecutorService; @Singleton public class AzureComputeService extends BaseComputeService { private final CleanupResources cleanupResources; - private final LocationToResourceGroupName locationToResourceGroupName; + private final LoadingCache resourceGroupMap; @Inject protected AzureComputeService(ComputeServiceContext context, Map credentialStore, @@ -88,15 +89,14 @@ public class AzureComputeService extends BaseComputeService { PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, CleanupResources cleanupResources, Optional imageExtension, - Optional securityGroupExtension, - LocationToResourceGroupName locationToResourceGroupName) { + Optional securityGroupExtension, LoadingCache resourceGroupMap) { 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 = cleanupResources; - this.locationToResourceGroupName = locationToResourceGroupName; + this.resourceGroupMap = resourceGroupMap; } @Override @@ -105,11 +105,11 @@ public class AzureComputeService extends BaseComputeService { ImmutableSet.Builder resourceGroups = ImmutableSet.builder(); for (NodeMetadata deadNode : deadNodes) { - String resourceGroup = locationToResourceGroupName.apply(deadNode.getLocation().getId()); + ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(deadNode.getLocation().getId()); - resourceGroups.add(resourceGroup); + resourceGroups.add(resourceGroup.name()); if (deadNode.getGroup() != null) { - regionGroups.put(resourceGroup, deadNode.getGroup()); + regionGroups.put(resourceGroup.name(), deadNode.getGroup()); } try { 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 269f6b0f68..5a8204ebda 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 @@ -26,6 +26,7 @@ import static org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageE import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.decodeFieldsFromUniqueId; import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.encodeFieldsToUniqueIdCustom; import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.getMarketplacePlanFromImageMetadata; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; import static org.jclouds.compute.util.ComputeServiceUtils.metadataAndTagsAsCommaDelimitedValue; import static org.jclouds.util.Closeables2.closeQuietly; @@ -39,10 +40,9 @@ 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.config.AzureComputeServiceContextModule.PublicIpAvailablePredicateFactory; -import org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupName; import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; +import org.jclouds.azurecompute.arm.compute.strategy.CleanupResources; import org.jclouds.azurecompute.arm.domain.DataDisk; import org.jclouds.azurecompute.arm.domain.HardwareProfile; import org.jclouds.azurecompute.arm.domain.IdReference; @@ -76,7 +76,6 @@ 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.compute.ComputeServiceAdapter; import org.jclouds.compute.domain.Image; @@ -92,6 +91,7 @@ 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.cache.LoadingCache; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -113,21 +113,21 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter imagePublishers; private final Supplier> regionIds; private final PublicIpAvailablePredicateFactory publicIpAvailable; - private final LocationToResourceGroupName locationToResourceGroupName; + private final LoadingCache resourceGroupMap; @Inject - AzureComputeServiceAdapter(final AzureComputeApi api, final AzureComputeConstants azureComputeConstants, + AzureComputeServiceAdapter(final AzureComputeApi api, @Named(IMAGE_PUBLISHERS) String imagePublishers, CleanupResources cleanupResources, @Region Supplier> regionIds, - PublicIpAvailablePredicateFactory publicIpAvailable, LocationToResourceGroupName locationToResourceGroupName) { + PublicIpAvailablePredicateFactory publicIpAvailable, LoadingCache resourceGroupMap) { this.api = api; - this.azureComputeConstants = azureComputeConstants; + this.imagePublishers = Splitter.on(',').trimResults().omitEmptyStrings().splitToList(imagePublishers); this.cleanupResources = cleanupResources; this.regionIds = regionIds; this.publicIpAvailable = publicIpAvailable; - this.locationToResourceGroupName = locationToResourceGroupName; + this.resourceGroupMap = resourceGroupMap; } @Override @@ -135,14 +135,15 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter create one nic in each network String locationName = template.getLocation().getId(); String subnetId = templateOptions.getSubnetId(); - NetworkInterfaceCard nic = createNetworkInterfaceCard(subnetId, name, locationName, azureGroup, template.getOptions()); + NetworkInterfaceCard nic = createNetworkInterfaceCard(subnetId, name, locationName, resourceGroup.name(), + template.getOptions()); StorageProfile storageProfile = createStorageProfile(name, template.getImage(), templateOptions.getBlob()); HardwareProfile hardwareProfile = HardwareProfile.builder().vmSize(template.getHardware().getId()).build(); OSProfile osProfile = createOsProfile(name, template); @@ -160,7 +161,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter metadataAndTags = metadataAndTagsAsCommaDelimitedValue(template.getOptions()); Plan plan = getMarketplacePlanFromImageMetadata(template.getImage()); - VirtualMachine virtualMachine = api.getVirtualMachineApi(azureGroup).create(name, template.getLocation().getId(), + VirtualMachine virtualMachine = api.getVirtualMachineApi(resourceGroup.name()).create(name, template.getLocation().getId(), virtualMachineProperties, metadataAndTags, plan); // Safe to pass null credentials here, as jclouds will default populate @@ -210,9 +211,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listImagesByLocation(String location) { final List osImages = Lists.newArrayList(); - Iterable publishers = Splitter.on(',').trimResults().omitEmptyStrings() - .split(this.azureComputeConstants.azureImagePublishers()); - for (String publisher : publishers) { + for (String publisher : imagePublishers) { osImages.addAll(getImagesFromPublisher(publisher, location)); } return osImages; @@ -259,11 +258,11 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter customImagesInStorage = blobHelper.getImages(CONTAINER_NAME, azureGroup, + List customImagesInStorage = blobHelper.getImages(CONTAINER_NAME, resourceGroup.name(), CUSTOM_IMAGE_OFFER, image.location()); customImage = find(customImagesInStorage, new Predicate() { @Override @@ -336,8 +335,8 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter>() { }).to(CreateSecurityGroupIfNeeded.class); + bind(new TypeLiteral>() { + }).to(ResourceGroupForLocation.class); bind(new TypeLiteral() { }).to(AzureComputeImageExtension.class); @@ -134,82 +130,6 @@ public class AzureComputeServiceContextModule extends }).to(AzureComputeSecurityGroupExtension.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(IMAGE_PUBLISHERS) - @Inject - private String azureImagePublishersProperty; - - @Named(DEFAULT_VNET_ADDRESS_SPACE_PREFIX) - @Inject - private String azureDefaultVnetAddressPrefixProperty; - - @Named(DEFAULT_SUBNET_ADDRESS_PREFIX) - @Inject - private String azureDefaultSubnetAddressPrefixProperty; - - @Named(DEFAULT_DATADISKSIZE) - @Inject - private String azureDefaultDataDiskSizeProperty; - - public Long operationTimeout() { - return Long.parseLong(operationTimeoutProperty); - } - - public String azureImagePublishers() { - return azureImagePublishersProperty; - } - - public String azureDefaultVnetAddressPrefixProperty() { - return azureDefaultVnetAddressPrefixProperty; - } - - public String azureDefaultSubnetAddressPrefixProperty() { - return azureDefaultSubnetAddressPrefixProperty; - } - - public String azureDefaultDataDiskSizeProperty() { - return azureDefaultDataDiskSizeProperty; - } - - 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 @Singleton protected final LoadingCache securityGroupMap( @@ -217,6 +137,12 @@ public class AzureComputeServiceContextModule extends return CacheBuilder.newBuilder().build(in); } + @Provides + @Singleton + protected final LoadingCache resourceGroupMap(CacheLoader in) { + return CacheBuilder.newBuilder().build(in); + } + @Provides @Named(TIMEOUT_NODE_RUNNING) protected VirtualMachineInStatePredicateFactory provideVirtualMachineRunningPredicate(final AzureComputeApi api, @@ -259,18 +185,24 @@ public class AzureComputeServiceContextModule extends @Provides protected PublicIpAvailablePredicateFactory providePublicIpAvailablePredicate(final AzureComputeApi api, - final AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants, final Timeouts timeouts, - final PollPeriod pollPeriod) { - return new PublicIpAvailablePredicateFactory(api, azureComputeConstants.operationTimeout(), - azureComputeConstants.operationPollInitialPeriod(), azureComputeConstants.operationPollMaxPeriod()); + @Named(OPERATION_TIMEOUT) Integer operationTimeout, PollPeriod pollPeriod) { + return new PublicIpAvailablePredicateFactory(api, operationTimeout, pollPeriod.pollInitialPeriod, + pollPeriod.pollMaxPeriod); } @Provides protected SecurityGroupAvailablePredicateFactory provideSecurityGroupAvailablePredicate(final AzureComputeApi api, - final AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants, final Timeouts timeouts, - final PollPeriod pollPeriod) { - return new SecurityGroupAvailablePredicateFactory(api, azureComputeConstants.operationTimeout(), - azureComputeConstants.operationPollInitialPeriod(), azureComputeConstants.operationPollMaxPeriod()); + @Named(OPERATION_TIMEOUT) Integer operationTimeout, PollPeriod pollPeriod) { + return new SecurityGroupAvailablePredicateFactory(api, operationTimeout, pollPeriod.pollInitialPeriod, + pollPeriod.pollMaxPeriod); + } + + @Provides + @Named("STORAGE") + protected Predicate provideStorageAccountAvailablePredicate(final AzureComputeApi api, + @Named(OPERATION_TIMEOUT) Integer operationTimeout, PollPeriod pollPeriod) { + return retry(new ActionDonePredicate(api), operationTimeout, pollPeriod.pollInitialPeriod, + pollPeriod.pollMaxPeriod); } @VisibleForTesting 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 1e57899d5c..7028081228 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 @@ -32,13 +32,13 @@ import javax.annotation.Resource; import org.jclouds.Constants; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.VirtualMachineInStatePredicateFactory; -import org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupName; import org.jclouds.azurecompute.arm.compute.functions.ResourceDefinitionToCustomImage; +import org.jclouds.azurecompute.arm.compute.strategy.CleanupResources; import org.jclouds.azurecompute.arm.domain.RegionAndId; import org.jclouds.azurecompute.arm.domain.ResourceDefinition; +import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.domain.StorageServiceKeys; import org.jclouds.azurecompute.arm.domain.VMImage; -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; @@ -49,6 +49,7 @@ import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.logging.Logger; import com.google.common.base.Predicate; +import com.google.common.cache.LoadingCache; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.inject.Inject; @@ -68,7 +69,7 @@ public class AzureComputeImageExtension implements ImageExtension { private final VirtualMachineInStatePredicateFactory nodeSuspendedPredicate; private final ResourceDefinitionToCustomImage.Factory resourceDefinitionToImage; private final CleanupResources cleanupResources; - private final LocationToResourceGroupName locationToResourceGroupName; + private final LoadingCache resourceGroupMap; @Inject AzureComputeImageExtension(AzureComputeApi api, @@ -76,14 +77,14 @@ public class AzureComputeImageExtension implements ImageExtension { @Named(TIMEOUT_NODE_SUSPENDED) VirtualMachineInStatePredicateFactory nodeSuspendedPredicate, @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, ResourceDefinitionToCustomImage.Factory resourceDefinitionToImage, CleanupResources cleanupResources, - LocationToResourceGroupName locationToResourceGroupName) { + LoadingCache resourceGroupMap) { this.api = api; this.imageAvailablePredicate = imageAvailablePredicate; this.nodeSuspendedPredicate = nodeSuspendedPredicate; this.userExecutor = userExecutor; this.resourceDefinitionToImage = resourceDefinitionToImage; this.cleanupResources = cleanupResources; - this.locationToResourceGroupName = locationToResourceGroupName; + this.resourceGroupMap = resourceGroupMap; } @Override @@ -94,23 +95,25 @@ public class AzureComputeImageExtension implements ImageExtension { @Override public ListenableFuture createImage(ImageTemplate template) { final CloneImageTemplate cloneTemplate = (CloneImageTemplate) template; - + final RegionAndId regionAndId = RegionAndId.fromSlashEncoded(cloneTemplate.getSourceNodeId()); - final String group = locationToResourceGroupName.apply(regionAndId.region()); + ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(regionAndId.region()); + final String resourceGroupName = resourceGroup.name(); logger.debug(">> stopping node %s...", regionAndId.slashEncode()); - api.getVirtualMachineApi(group).stop(regionAndId.id()); - checkState(nodeSuspendedPredicate.create(group).apply(regionAndId.id()), + api.getVirtualMachineApi(resourceGroupName).stop(regionAndId.id()); + checkState(nodeSuspendedPredicate.create(resourceGroupName).apply(regionAndId.id()), "Node %s was not suspended within the configured time limit", regionAndId.slashEncode()); return userExecutor.submit(new Callable() { @Override public Image call() throws Exception { logger.debug(">> generalizing virtal machine %s...", regionAndId.id()); - api.getVirtualMachineApi(group).generalize(regionAndId.id()); + api.getVirtualMachineApi(resourceGroupName).generalize(regionAndId.id()); logger.debug(">> capturing virtual machine %s to container %s...", regionAndId.id(), CONTAINER_NAME); - URI uri = api.getVirtualMachineApi(group).capture(regionAndId.id(), cloneTemplate.getName(), CONTAINER_NAME); + URI uri = api.getVirtualMachineApi(resourceGroupName) + .capture(regionAndId.id(), cloneTemplate.getName(), CONTAINER_NAME); checkState(uri != null && imageAvailablePredicate.apply(uri), "Image %s was not created within the configured time limit", cloneTemplate.getName()); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java index 12d140bf6c..340e51ce74 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java @@ -36,7 +36,6 @@ import javax.inject.Named; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.SecurityGroupAvailablePredicateFactory; -import org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupName; import org.jclouds.azurecompute.arm.domain.IdReference; import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; @@ -47,6 +46,7 @@ import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Access; import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Direction; import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Protocol; import org.jclouds.azurecompute.arm.domain.RegionAndId; +import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi; import org.jclouds.azurecompute.arm.features.NetworkSecurityRuleApi; @@ -65,6 +65,7 @@ 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.cache.LoadingCache; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Multimap; @@ -77,23 +78,23 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio private final AzureComputeApi api; private final Function securityGroupConverter; - private final LocationToResourceGroupName locationToResourceGroupName; private final Supplier> locations; private final SecurityGroupAvailablePredicateFactory securityGroupAvailable; private final Predicate resourceDeleted; + private final LoadingCache resourceGroupMap; @Inject AzureComputeSecurityGroupExtension(AzureComputeApi api, @Memoized Supplier> locations, - LocationToResourceGroupName locationToResourceGroupName, Function groupConverter, SecurityGroupAvailablePredicateFactory securityRuleAvailable, - @Named(TIMEOUT_RESOURCE_DELETED) Predicate resourceDeleted) { + @Named(TIMEOUT_RESOURCE_DELETED) Predicate resourceDeleted, + LoadingCache resourceGroupMap) { this.api = api; this.locations = locations; this.securityGroupConverter = groupConverter; - this.locationToResourceGroupName = locationToResourceGroupName; this.securityGroupAvailable = securityRuleAvailable; this.resourceDeleted = resourceDeleted; + this.resourceGroupMap = resourceGroupMap; } @Override @@ -109,8 +110,8 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio @Override public Set listSecurityGroupsInLocation(Location location) { logger.debug(">> getting security groups for %s...", location); - final String resourcegroup = locationToResourceGroupName.apply(location.getId()); - List networkGroups = api.getNetworkSecurityGroupApi(resourcegroup).list(); + ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(location.getId()); + List networkGroups = api.getNetworkSecurityGroupApi(resourceGroup.name()).list(); return ImmutableSet.copyOf(transform(filter(networkGroups, notNull()), securityGroupConverter)); } @@ -119,19 +120,19 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio logger.debug(">> getting security groups for node %s...", nodeId); final RegionAndId regionAndId = RegionAndId.fromSlashEncoded(nodeId); - final String resourceGroup = locationToResourceGroupName.apply(regionAndId.region()); + ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(regionAndId.region()); - VirtualMachine vm = api.getVirtualMachineApi(resourceGroup).get(regionAndId.id()); + VirtualMachine vm = api.getVirtualMachineApi(resourceGroup.name()).get(regionAndId.id()); List networkInterfacesIdReferences = vm.properties().networkProfile().networkInterfaces(); List networkGroups = new ArrayList(); for (IdReference networkInterfaceCardIdReference : networkInterfacesIdReferences) { String nicName = Iterables.getLast(Splitter.on("/").split(networkInterfaceCardIdReference.id())); - NetworkInterfaceCard card = api.getNetworkInterfaceCardApi(resourceGroup).get(nicName); + NetworkInterfaceCard card = api.getNetworkInterfaceCardApi(resourceGroup.name()).get(nicName); if (card != null && card.properties().networkSecurityGroup() != null) { String secGroupName = Iterables.getLast(Splitter.on("/").split( card.properties().networkSecurityGroup().id())); - NetworkSecurityGroup group = api.getNetworkSecurityGroupApi(resourceGroup).get(secGroupName); + NetworkSecurityGroup group = api.getNetworkSecurityGroupApi(resourceGroup.name()).get(secGroupName); networkGroups.add(group); } } @@ -143,14 +144,14 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio public SecurityGroup getSecurityGroupById(String id) { logger.debug(">> getting security group %s...", id); final RegionAndId regionAndId = RegionAndId.fromSlashEncoded(id); - final String resourceGroup = locationToResourceGroupName.apply(regionAndId.region()); - - return securityGroupConverter.apply(api.getNetworkSecurityGroupApi(resourceGroup).get(regionAndId.id())); + ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(regionAndId.region()); + NetworkSecurityGroup securityGroup = api.getNetworkSecurityGroupApi(resourceGroup.name()).get(regionAndId.id()); + return securityGroup == null ? null : securityGroupConverter.apply(securityGroup); } @Override public SecurityGroup createSecurityGroup(String name, Location location) { - final String resourceGroup = locationToResourceGroupName.apply(location.getId()); + ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(location.getId()); logger.debug(">> creating security group %s in %s...", name, location); @@ -158,7 +159,7 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio builder.name(name); builder.location(location); - return securityGroupConverter.apply(api.getNetworkSecurityGroupApi(resourceGroup).createOrUpdate(name, + return securityGroupConverter.apply(api.getNetworkSecurityGroupApi(resourceGroup.name()).createOrUpdate(name, location.getId(), null, NetworkSecurityGroupProperties.builder().build())); } @@ -167,8 +168,8 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio logger.debug(">> deleting security group %s...", id); final RegionAndId regionAndId = RegionAndId.fromSlashEncoded(id); - final String resourcegroup = locationToResourceGroupName.apply(regionAndId.region()); - URI uri = api.getNetworkSecurityGroupApi(resourcegroup).delete(regionAndId.id()); + ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(regionAndId.region()); + URI uri = api.getNetworkSecurityGroupApi(resourceGroup.name()).delete(regionAndId.id()); return resourceDeleted.apply(uri); } @@ -196,35 +197,35 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio // TODO: Support Azure network tags somehow? final RegionAndId regionAndId = RegionAndId.fromSlashEncoded(group.getId()); - final String resourceGroup = locationToResourceGroupName.apply(regionAndId.region()); + ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(regionAndId.region()); - NetworkSecurityGroupApi groupApi = api.getNetworkSecurityGroupApi(resourceGroup); + NetworkSecurityGroupApi groupApi = api.getNetworkSecurityGroupApi(resourceGroup.name()); NetworkSecurityGroup networkSecurityGroup = groupApi.get(regionAndId.id()); if (networkSecurityGroup == null) { throw new IllegalArgumentException("Security group " + group.getName() + " was not found"); } - NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourceGroup, networkSecurityGroup.name()); - int nextPriority = getRuleStartingPriority(ruleApi); + NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourceGroup.name(), networkSecurityGroup.name()); + int nextPriority = getRuleStartingPriority(networkSecurityGroup); for (String ipRange : ipRanges) { NetworkSecurityRuleProperties properties = NetworkSecurityRuleProperties.builder() - .protocol(Protocol.fromValue(protocol.name())) // - .sourceAddressPrefix(ipRange) // - .sourcePortRange("*") // - .destinationAddressPrefix("*") // - .destinationPortRange(portRange) // - .direction(Direction.Inbound) // - .access(Access.Allow) // - .priority(nextPriority++) // + .protocol(Protocol.fromValue(protocol.name())) + .sourceAddressPrefix(ipRange) + .sourcePortRange("*") + .destinationAddressPrefix("*") + .destinationPortRange(portRange) + .direction(Direction.Inbound) + .access(Access.Allow) + .priority(nextPriority++) .build(); logger.debug(">> creating network security rule %s for %s...", ruleName, ipRange); ruleApi.createOrUpdate(ruleName, properties); - checkState(securityGroupAvailable.create(resourceGroup).apply(networkSecurityGroup.name()), + checkState(securityGroupAvailable.create(resourceGroup.name()).apply(networkSecurityGroup.name()), "Security group was not updated in the configured timeout"); } @@ -241,16 +242,16 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio logger.debug(">> deleting ip permissions matching [%s] from %s...", ruleName, group.getName()); final RegionAndId regionAndId = RegionAndId.fromSlashEncoded(group.getId()); - final String resourceGroup = locationToResourceGroupName.apply(regionAndId.region()); + ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(regionAndId.region()); - NetworkSecurityGroupApi groupApi = api.getNetworkSecurityGroupApi(resourceGroup); + NetworkSecurityGroupApi groupApi = api.getNetworkSecurityGroupApi(resourceGroup.name()); NetworkSecurityGroup networkSecurityGroup = groupApi.get(regionAndId.id()); if (networkSecurityGroup == null) { throw new IllegalArgumentException("Security group " + group.getName() + " was not found"); } - NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourceGroup, networkSecurityGroup.name()); + NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourceGroup.name(), networkSecurityGroup.name()); Iterable rules = filter(ruleApi.list(), new Predicate() { @Override public boolean apply(NetworkSecurityRule input) { @@ -266,7 +267,7 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio for (NetworkSecurityRule matchingRule : rules) { logger.debug(">> deleting network security rule %s from %s...", matchingRule.name(), group.getName()); ruleApi.delete(matchingRule.name()); - checkState(securityGroupAvailable.create(resourceGroup).apply(networkSecurityGroup.name()), + checkState(securityGroupAvailable.create(resourceGroup.name()).apply(networkSecurityGroup.name()), "Security group was not updated in the configured timeout"); } @@ -298,8 +299,8 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio return false; } - private int getRuleStartingPriority(NetworkSecurityRuleApi ruleApi) { - List existingRules = ruleApi.list(); + private int getRuleStartingPriority(NetworkSecurityGroup securityGroup) { + List existingRules = securityGroup.properties().securityRules(); return existingRules.isEmpty() ? 100 : rulesByPriority().max(existingRules).properties().priority() + 1; } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityRuleToIpPermission.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityRuleToIpPermission.java index e601d59403..50a0954bdd 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityRuleToIpPermission.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityRuleToIpPermission.java @@ -60,9 +60,9 @@ public class NetworkSecurityRuleToIpPermission implements Function { @@ -41,30 +43,35 @@ public class ResourceDefinitionToCustomImage implements Function vmImageToImage; private final String imageName; - private final String storageAccountName; - private final VirtualMachine vm; - private final String resourceGroup; + private final String nodeId; + private final AzureComputeApi api; + private final StorageProfileToStorageAccountName storageProfileToStorageAccountName; + private final LoadingCache resourceGroupMap; @Inject ResourceDefinitionToCustomImage(AzureComputeApi api, StorageProfileToStorageAccountName storageProfileToStorageAccountName, - Function vmImageToImage, LocationToResourceGroupName locationToResourceGroupName, - @Assisted("nodeId") String nodeId, - @Assisted("imageName") String imageName) { + Function vmImageToImage, LoadingCache resourceGroupMap, + @Assisted("nodeId") String nodeId, @Assisted("imageName") String imageName) { + this.api = api; this.vmImageToImage = vmImageToImage; + this.nodeId = nodeId; this.imageName = imageName; - - RegionAndId regionAndId = RegionAndId.fromSlashEncoded(nodeId); - this.resourceGroup = locationToResourceGroupName.apply(regionAndId.region()); - this.vm = api.getVirtualMachineApi(this.resourceGroup).get(regionAndId.id()); - this.storageAccountName = storageProfileToStorageAccountName.apply(vm.properties().storageProfile()); + this.storageProfileToStorageAccountName = storageProfileToStorageAccountName; + this.resourceGroupMap = resourceGroupMap; } @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()); + RegionAndId regionAndId = RegionAndId.fromSlashEncoded(nodeId); + ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(regionAndId.region()); + + VirtualMachine vm = api.getVirtualMachineApi(resourceGroup.name()).get(regionAndId.id()); + String storageAccountName = storageProfileToStorageAccountName.apply(vm.properties().storageProfile()); + + VMImage.Builder builder = VMImage.customImage().group(resourceGroup.name()).storage(storageAccountName) + .name(imageName).offer(CUSTOM_IMAGE_OFFER).location(vm.location()); Map properties = (Map) input.properties(); 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 index 22c818c089..92689c2e4a 100644 --- 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 @@ -17,6 +17,7 @@ package org.jclouds.azurecompute.arm.compute.functions; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Strings.nullToEmpty; import static com.google.common.collect.Iterables.find; import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Iterables.tryFind; @@ -25,6 +26,7 @@ import static org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageE 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.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromCommaDelimitedValue; +import static org.jclouds.location.predicates.LocationPredicates.idEquals; import static org.jclouds.util.Closeables2.closeQuietly; import java.util.List; @@ -36,11 +38,11 @@ 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.RegionAndId; +import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.domain.StorageProfile; import org.jclouds.azurecompute.arm.domain.StorageServiceKeys; import org.jclouds.azurecompute.arm.domain.VMImage; @@ -71,6 +73,7 @@ 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.cache.LoadingCache; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; @@ -120,15 +123,14 @@ public class VirtualMachineToNodeMetadata implements Function credentialStore; private final Function vmImageToImge; private final StorageProfileToStorageAccountName storageProfileToStorageAccountName; - private final LocationToResourceGroupName locationToResourceGroupName; + private final LoadingCache resourceGroupMap; @Inject VirtualMachineToNodeMetadata(AzureComputeApi api, GroupNamingConvention.Factory namingConvention, Supplier> images, Supplier> hardwares, @Memoized Supplier> locations, Map credentialStore, - final AzureComputeConstants azureComputeConstants, Function vmImageToImge, - StorageProfileToStorageAccountName storageProfileToStorageAccountName, - LocationToResourceGroupName locationToResourceGroupName) { + Function vmImageToImge, StorageProfileToStorageAccountName storageProfileToStorageAccountName, + LoadingCache resourceGroupMap) { this.api = api; this.nodeNamingConvention = namingConvention.createWithoutPrefix(); this.images = checkNotNull(images, "images cannot be null"); @@ -137,13 +139,13 @@ public class VirtualMachineToNodeMetadata implements Function image = findImage(virtualMachine.properties().storageProfile(), locationName, azureGroup); + Optional image = findImage(virtualMachine.properties().storageProfile(), locationName, + resourceGroup.name()); + if (image.isPresent()) { builder.imageId(image.get().getId()); builder.operatingSystem(image.get().getOperatingSystem()); @@ -252,15 +257,11 @@ public class VirtualMachineToNodeMetadata implements Function> locations, final String locationName) { - return find(locations.get(), new Predicate() { - @Override - public boolean apply(Location location) { - return locationName != null && locationName.equals(location.getId()); - } - }, null); + return find(locations.get(), idEquals(nullToEmpty(locationName)), null); } - protected Optional findImage(final StorageProfile storageProfile, String locatioName, String azureGroup) { + protected Optional findImage(final StorageProfile storageProfile, String locatioName, + String azureGroup) { if (storageProfile.imageReference() != null) { return Optional.fromNullable(images.get().get( encodeFieldsToUniqueId(false, locatioName, storageProfile.imageReference()))); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/CreateSecurityGroupIfNeeded.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/CreateSecurityGroupIfNeeded.java index efb8abce86..0ff96d8fd0 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/CreateSecurityGroupIfNeeded.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/CreateSecurityGroupIfNeeded.java @@ -29,7 +29,6 @@ import javax.inject.Singleton; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.compute.domain.RegionAndIdAndIngressRules; -import org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupName; import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroupProperties; import org.jclouds.azurecompute.arm.domain.NetworkSecurityRule; @@ -37,10 +36,12 @@ import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties; import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Access; import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Direction; import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Protocol; +import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.logging.Logger; import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; @Singleton public class CreateSecurityGroupIfNeeded extends CacheLoader { @@ -49,18 +50,18 @@ public class CreateSecurityGroupIfNeeded extends CacheLoader resourceGroupMap; @Inject - CreateSecurityGroupIfNeeded(AzureComputeApi api, LocationToResourceGroupName locationToResourceGroupName) { + CreateSecurityGroupIfNeeded(AzureComputeApi api, LoadingCache resourceGroupMap) { this.api = api; - this.locationToResourceGroupName = locationToResourceGroupName; + this.resourceGroupMap = resourceGroupMap; } @Override public String load(RegionAndIdAndIngressRules key) throws Exception { - String resourceGroup = locationToResourceGroupName.apply(key.region()); - return createSecurityGroup(key.region(), resourceGroup, key.id(), key.inboundPorts()); + ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(key.region()); + return createSecurityGroup(key.region(), resourceGroup.name(), key.id(), key.inboundPorts()); } private String createSecurityGroup(String location, String resourceGroup, String name, int[] inboundPorts) { diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/ResourceGroupForLocation.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/ResourceGroupForLocation.java new file mode 100644 index 0000000000..ddbbb26ef2 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/ResourceGroupForLocation.java @@ -0,0 +1,62 @@ +/* + * 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.loaders; + +import java.util.Map; + +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.functions.LocationToResourceGroupName; +import org.jclouds.azurecompute.arm.domain.ResourceGroup; +import org.jclouds.azurecompute.arm.features.ResourceGroupApi; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.logging.Logger; + +import com.google.common.cache.CacheLoader; +import com.google.common.collect.ImmutableMap; + +@Singleton +public class ResourceGroupForLocation extends CacheLoader { + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + private final ResourceGroupApi api; + private final LocationToResourceGroupName locationToResourceGroupName; + + @Inject + ResourceGroupForLocation(AzureComputeApi api, LocationToResourceGroupName locationToResourceGroupName) { + this.api = api.getResourceGroupApi(); + this.locationToResourceGroupName = locationToResourceGroupName; + } + + @Override + public ResourceGroup load(String locationId) throws Exception { + String azureGroupName = locationToResourceGroupName.apply(locationId); + ResourceGroup resourceGroup = api.get(azureGroupName); + if (resourceGroup == null) { + logger.debug(">> creating resource group %s", azureGroupName); + final Map tags = ImmutableMap.of("description", "jclouds managed VMs"); + resourceGroup = api.create(azureGroupName, locationId, tags); + } + return resourceGroup; + } +} 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 c71a7daba0..ecbc237f8c 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 @@ -27,56 +27,10 @@ import static com.google.common.base.Objects.equal; */ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { - - private String customData; - private String virtualNetworkAddressPrefix; - 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 - */ - public AzureTemplateOptions customData(String customData) { - this.customData = customData; - return this; - } - - /** - * Sets the CIDR block for virtual network - */ - public AzureTemplateOptions virtualNetworkAddressPrefix(String virtualNetworkAddressPrefix) { - this.virtualNetworkAddressPrefix = virtualNetworkAddressPrefix; - return this; - } - - /** - * Sets the CIDR block for subnet within virtual network - */ - public AzureTemplateOptions subnetAddressPrefix(String subnetAddressPrefix) { - this.subnetAddressPrefix = subnetAddressPrefix; - return this; - } - - /** - * Sets the DNS label prefix for public IP address. label.location.cloudapp.azure.com - */ - public AzureTemplateOptions DNSLabelPrefix(String DNSLabelPrefix) { - this.DNSLabelPrefix = DNSLabelPrefix; - return this; - } - - /** - * Sets the KeyVault id and secret separated with ":" - */ - public AzureTemplateOptions keyVaultIdAndSecret(String keyVaultIdAndSecret) { - this.keyVaultIdAndSecret = keyVaultIdAndSecret; - return this; - } - /** * Sets the virtual network name */ @@ -101,11 +55,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; } public String getBlob() { return blob; } @@ -123,11 +72,6 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { super.copyTo(to); if (to instanceof AzureTemplateOptions) { AzureTemplateOptions eTo = AzureTemplateOptions.class.cast(to); - eTo.customData(customData); - eTo.virtualNetworkAddressPrefix(virtualNetworkAddressPrefix); - eTo.subnetAddressPrefix(subnetAddressPrefix); - eTo.DNSLabelPrefix(DNSLabelPrefix); - eTo.keyVaultIdAndSecret(keyVaultIdAndSecret); eTo.virtualNetworkName(virtualNetworkName); eTo.subnetId(subnetId); eTo.blob(blob); @@ -136,7 +80,7 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { @Override public int hashCode() { - return Objects.hashCode(super.hashCode(), virtualNetworkAddressPrefix, subnetAddressPrefix, DNSLabelPrefix, customData, keyVaultIdAndSecret, virtualNetworkName, subnetId, blob); + return Objects.hashCode(super.hashCode(), virtualNetworkName, subnetId, blob); } @Override @@ -152,11 +96,6 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { } AzureTemplateOptions other = (AzureTemplateOptions) obj; return super.equals(other) - && equal(this.customData, other.customData) - && equal(this.virtualNetworkAddressPrefix, other.virtualNetworkAddressPrefix) - && equal(this.subnetAddressPrefix, other.subnetAddressPrefix) - && equal(this.DNSLabelPrefix, other.DNSLabelPrefix) - && equal(this.keyVaultIdAndSecret, other.keyVaultIdAndSecret) && equal(this.virtualNetworkName, other.virtualNetworkName) && equal(this.subnetId, other.subnetId) && equal(this.blob, other.blob); @@ -165,11 +104,6 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { @Override public Objects.ToStringHelper string() { Objects.ToStringHelper toString = super.string().omitNullValues(); - toString.add("customData", customData); - toString.add("virtualNetworkAddressPrefix", virtualNetworkAddressPrefix); - toString.add("subnetAddressPrefix", subnetAddressPrefix); - toString.add("DNSLabelPrefix", DNSLabelPrefix); - toString.add("keyVaultIdAndSecret", keyVaultIdAndSecret); toString.add("virtualNetworkName", virtualNetworkName); toString.add("subnetId", subnetId); toString.add("blob", blob); @@ -178,46 +112,6 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { public static class Builder { - /** - * @see AzureTemplateOptions#customData - */ - public static AzureTemplateOptions customData(String customData) { - AzureTemplateOptions options = new AzureTemplateOptions(); - return options.customData(customData); - } - - /** - * @see AzureTemplateOptions#virtualNetworkAddressPrefix - */ - public static AzureTemplateOptions virtualNetworkAddressPrefix(String virtualNetworkAddressPrefix) { - AzureTemplateOptions options = new AzureTemplateOptions(); - return options.virtualNetworkAddressPrefix(virtualNetworkAddressPrefix); - } - - /** - * @see AzureTemplateOptions#subnetAddressPrefix - */ - public static AzureTemplateOptions subnetAddressPrefix(String subnetAddressPrefix) { - AzureTemplateOptions options = new AzureTemplateOptions(); - return options.subnetAddressPrefix(subnetAddressPrefix); - } - - /** - * @see AzureTemplateOptions#DNSLabelPrefix - */ - public static AzureTemplateOptions DNSLabelPrefix(String DNSLabelPrefix) { - AzureTemplateOptions options = new AzureTemplateOptions(); - return options.DNSLabelPrefix(DNSLabelPrefix); - } - - /** - * @see AzureTemplateOptions#keyVaultIdAndSecret - */ - public static AzureTemplateOptions keyVaultIdAndSecret(String keyVaultIdAndSecret) { - AzureTemplateOptions options = new AzureTemplateOptions(); - return options.keyVaultIdAndSecret(keyVaultIdAndSecret); - } - /** * @see AzureTemplateOptions#virtualNetworkName */ 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 deleted file mode 100644 index 66590e1ed1..0000000000 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/predicates/IsDeploymentInRegions.java +++ /dev/null @@ -1,47 +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.predicates; - -import java.util.Set; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import org.jclouds.azurecompute.arm.domain.Deployment; -import org.jclouds.azurecompute.arm.domain.Value; -import org.jclouds.location.Region; - -import com.google.common.base.Predicate; -import com.google.common.base.Supplier; - -@Singleton -public class IsDeploymentInRegions implements Predicate { - - private final Supplier> regionIds; - - @Inject - IsDeploymentInRegions(@Region Supplier> regionIds) { - this.regionIds = regionIds; - } - - @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/functions/CleanupResources.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java similarity index 89% rename from providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/CleanupResources.java rename to providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java index 9d2a1c1850..3914bc027c 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/compute/strategy/CleanupResources.java @@ -14,7 +14,7 @@ * 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.compute.strategy; import static com.google.common.base.Predicates.notNull; import static com.google.common.collect.Iterables.filter; @@ -31,15 +31,16 @@ import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.azurecompute.arm.AzureComputeApi; -import org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupName; 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.RegionAndId; +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.features.NetworkSecurityGroupApi; +import org.jclouds.azurecompute.arm.functions.StorageProfileToStorageAccountName; import org.jclouds.azurecompute.arm.util.BlobHelper; import org.jclouds.compute.functions.GroupNamingConvention; import org.jclouds.compute.reference.ComputeServiceConstants; @@ -48,6 +49,7 @@ import org.jclouds.logging.Logger; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Splitter; +import com.google.common.cache.LoadingCache; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; @@ -58,40 +60,41 @@ public class CleanupResources { @Named(ComputeServiceConstants.COMPUTE_LOGGER) protected Logger logger = Logger.NULL; - protected final AzureComputeApi api; + private final AzureComputeApi api; private final Predicate resourceDeleted; private final StorageProfileToStorageAccountName storageProfileToStorageAccountName; - private final LocationToResourceGroupName locationToResourceGroupName; + private final LoadingCache resourceGroupMap; private final GroupNamingConvention.Factory namingConvention; @Inject CleanupResources(AzureComputeApi azureComputeApi, @Named(TIMEOUT_RESOURCE_DELETED) Predicate resourceDeleted, StorageProfileToStorageAccountName storageProfileToStorageAccountName, - LocationToResourceGroupName locationToResourceGroupName, GroupNamingConvention.Factory namingConvention) { + LoadingCache resourceGroupMap, GroupNamingConvention.Factory namingConvention) { this.api = azureComputeApi; this.resourceDeleted = resourceDeleted; this.storageProfileToStorageAccountName = storageProfileToStorageAccountName; - this.locationToResourceGroupName = locationToResourceGroupName; + this.resourceGroupMap = resourceGroupMap; this.namingConvention = namingConvention; } public boolean cleanupNode(final String id) { RegionAndId regionAndId = RegionAndId.fromSlashEncoded(id); - String group = locationToResourceGroupName.apply(regionAndId.region()); + ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(regionAndId.region()); + String resourceGroupName = resourceGroup.name(); - VirtualMachine virtualMachine = api.getVirtualMachineApi(group).get(regionAndId.id()); + VirtualMachine virtualMachine = api.getVirtualMachineApi(resourceGroupName).get(regionAndId.id()); if (virtualMachine == null) { return true; } logger.debug(">> destroying %s ...", regionAndId.slashEncode()); - boolean vmDeleted = deleteVirtualMachine(group, virtualMachine); + boolean vmDeleted = deleteVirtualMachine(resourceGroupName, 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 - cleanupVirtualMachineNICs(group, virtualMachine); - cleanupVirtualMachineStorage(group, virtualMachine); + cleanupVirtualMachineNICs(resourceGroupName, virtualMachine); + cleanupVirtualMachineStorage(resourceGroupName, virtualMachine); return vmDeleted; } 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 524eb69005..378030fa00 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 @@ -21,7 +21,8 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.Iterables.getOnlyElement; import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.decodeFieldsFromUniqueId; -import static org.jclouds.util.Predicates2.retry; +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 java.net.URI; import java.util.Arrays; @@ -36,9 +37,7 @@ import javax.inject.Singleton; import org.jclouds.Constants; import org.jclouds.azurecompute.arm.AzureComputeApi; -import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule; import org.jclouds.azurecompute.arm.compute.domain.RegionAndIdAndIngressRules; -import org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupName; import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; import org.jclouds.azurecompute.arm.domain.RegionAndId; @@ -47,10 +46,8 @@ 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; @@ -65,6 +62,7 @@ import org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThen import org.jclouds.domain.Location; import org.jclouds.logging.Logger; +import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.base.Strings; import com.google.common.cache.LoadingCache; @@ -81,9 +79,11 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco protected Logger logger = Logger.NULL; private final AzureComputeApi api; - private final AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants; - private final LocationToResourceGroupName locationToResourceGroupName; private final LoadingCache securityGroupMap; + private final LoadingCache resourceGroupMap; + private final String defaultVnetAddressPrefix; + private final String defaultSubnetAddressPrefix; + private final Predicate storageAccountCreated; @Inject protected CreateResourceGroupThenCreateNodes( @@ -92,22 +92,28 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco GroupNamingConvention.Factory namingConvention, @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory, - AzureComputeApi api, AzureComputeServiceContextModule.AzureComputeConstants azureComputeConstants, - LocationToResourceGroupName locationToResourceGroupName, - LoadingCache securityGroupMap) { + AzureComputeApi api, @Named(DEFAULT_VNET_ADDRESS_SPACE_PREFIX) String defaultVnetAddressPrefix, + @Named(DEFAULT_SUBNET_ADDRESS_PREFIX) String defaultSubnetAddressPrefix, + LoadingCache securityGroupMap, + LoadingCache resourceGroupMap, @Named("STORAGE") Predicate storageAccountCreated) { super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor, customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory); this.api = checkNotNull(api, "api cannot be null"); checkNotNull(userExecutor, "userExecutor cannot be null"); - this.azureComputeConstants = azureComputeConstants; - this.locationToResourceGroupName = locationToResourceGroupName; this.securityGroupMap = securityGroupMap; + this.resourceGroupMap = resourceGroupMap; + this.defaultVnetAddressPrefix = defaultVnetAddressPrefix; + this.defaultSubnetAddressPrefix = defaultSubnetAddressPrefix; + this.storageAccountCreated = storageAccountCreated; } @Override public Map> execute(String group, int count, Template template, Set goodNodes, Map badNodes, Multimap customizationResponses) { + + AzureTemplateOptions options = template.getOptions().as(AzureTemplateOptions.class); + // 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 @@ -115,56 +121,39 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco logger.warn(">> a runScript was configured but no SSH key has been provided. " + "Authentication will delegate to the ssh-agent"); } - String azureGroupName = locationToResourceGroupName.apply(template.getLocation().getId()); - AzureTemplateOptions options = template.getOptions().as(AzureTemplateOptions.class); - // create resource group for jclouds group if it does not already exist - ResourceGroupApi resourceGroupApi = api.getResourceGroupApi(); - ResourceGroup resourceGroup = resourceGroupApi.get(azureGroupName); - final String location = template.getLocation().getId(); + // This sill create the resource group if it does not exist + String location = template.getLocation().getId(); + ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(location); + String azureGroupName = resourceGroup.name(); - if (resourceGroup == null) { - final Map tags = ImmutableMap.of("description", "jclouds managed VMs"); - resourceGroupApi.create(azureGroupName, location, tags).name(); - } - - String vnetName = azureGroupName + "virtualnetwork"; - String subnetName = azureGroupName + "subnet"; - - if (options.getVirtualNetworkName() != null) { - vnetName = options.getVirtualNetworkName(); - } - - this.getOrCreateVirtualNetworkWithSubnet(vnetName, subnetName, location, options, azureGroupName); + getOrCreateVirtualNetworkWithSubnet(location, options, azureGroupName); configureSecurityGroupForOptions(group, azureGroupName, template.getLocation(), options); StorageService storageService = getOrCreateStorageService(group, azureGroupName, location, template.getImage()); - String blob = storageService.storageServiceProperties().primaryEndpoints().get("blob"); - options.blob(blob); + options.blob(storageService.storageServiceProperties().primaryEndpoints().get("blob")); - Map> responses = super.execute(group, count, template, goodNodes, badNodes, - customizationResponses); - - return responses; + return super.execute(group, count, template, goodNodes, badNodes, customizationResponses); } - protected synchronized void getOrCreateVirtualNetworkWithSubnet(final String virtualNetworkName, - final String subnetName, final String location, AzureTemplateOptions options, final String azureGroupName) { + protected synchronized void getOrCreateVirtualNetworkWithSubnet(final String location, AzureTemplateOptions options, + final String azureGroupName) { + String virtualNetworkName = Optional.fromNullable(options.getVirtualNetworkName()).or( + azureGroupName + "virtualnetwork"); + String subnetName = azureGroupName + "subnet"; // Subnets belong to a virtual network so that needs to be created first VirtualNetworkApi vnApi = api.getVirtualNetworkApi(azureGroupName); VirtualNetwork vn = vnApi.get(virtualNetworkName); if (vn == null) { + Subnet subnet = Subnet.create(subnetName, null, null, + Subnet.SubnetProperties.builder().addressPrefix(defaultSubnetAddressPrefix).build()); + VirtualNetwork.VirtualNetworkProperties virtualNetworkProperties = VirtualNetwork.VirtualNetworkProperties - .builder() - .addressSpace( - VirtualNetwork.AddressSpace.create(Arrays.asList(this.azureComputeConstants - .azureDefaultVnetAddressPrefixProperty()))) - .subnets( - Arrays.asList(Subnet.create(subnetName, null, null, Subnet.SubnetProperties.builder() - .addressPrefix(this.azureComputeConstants.azureDefaultSubnetAddressPrefixProperty()).build()))) - .build(); + .builder().addressSpace(VirtualNetwork.AddressSpace.create(Arrays.asList(defaultVnetAddressPrefix))) + .subnets(Arrays.asList(subnet)).build(); + vn = vnApi.createOrUpdate(virtualNetworkName, location, virtualNetworkProperties); } @@ -199,15 +188,10 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco URI uri = api.getStorageAccountApi(resourceGroupName).create(storageAccountName, locationName, ImmutableMap.of("jclouds", name), ImmutableMap.of("accountType", StorageService.AccountType.Standard_LRS.toString())); - 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", + + checkState(storageAccountCreated.apply(uri), "Storage account %s was not created in the configured timeout", storageAccountName); + return api.getStorageAccountApi(resourceGroupName).get(storageAccountName); } 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 2a15e4b34a..4ac5eaa064 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 @@ -22,30 +22,16 @@ package org.jclouds.azurecompute.arm.config; */ public class AzureComputeProperties { - public static final String STORAGE_API_VERSION = "2015-06-15"; - public static final String OPERATION_TIMEOUT = "jclouds.azurecompute.arm.operation.timeout"; - public static final String OPERATION_POLL_INITIAL_PERIOD = "jclouds.azurecompute.arm.operation.poll.initial.period"; - - public static final String OPERATION_POLL_MAX_PERIOD = "jclouds.azurecompute.arm.operation.poll.max.period"; - - public static final String TCP_RULE_FORMAT = "jclouds.azurecompute.arm.tcp.rule.format"; - - public static final String TCP_RULE_REGEXP = "jclouds.azurecompute.arm.tcp.rule.regexp"; - 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"; public static final String DEFAULT_VNET_ADDRESS_SPACE_PREFIX = "jclouds.azurecompute.arm.vnet.addressprefix"; public static final String DEFAULT_SUBNET_ADDRESS_PREFIX = "jclouds.azurecompute.arm.subnet.addressprefix"; - 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/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java index 02fe52e02d..cb13c7b1de 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java @@ -18,7 +18,6 @@ package org.jclouds.azurecompute.arm.compute.extensions; import static com.google.common.collect.Iterables.get; import static com.google.common.collect.Iterables.getOnlyElement; -import static java.util.logging.Logger.getAnonymousLogger; import static org.jclouds.compute.options.TemplateOptions.Builder.inboundPorts; import static org.jclouds.compute.options.TemplateOptions.Builder.securityGroups; import static org.jclouds.compute.predicates.NodePredicates.inGroup; @@ -26,14 +25,12 @@ import static org.jclouds.net.domain.IpProtocol.TCP; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; -import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.concurrent.ExecutionException; -import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; -import org.jclouds.azurecompute.arm.compute.functions.LocationToResourceGroupName; +import org.jclouds.azurecompute.arm.compute.strategy.CleanupResources; import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; import org.jclouds.compute.ComputeService; @@ -50,7 +47,9 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import com.google.common.base.Optional; -import com.google.common.collect.ImmutableMap; +import com.google.common.cache.LoadingCache; +import com.google.inject.Key; +import com.google.inject.TypeLiteral; /** * Live test for AzureCompute @@ -59,10 +58,9 @@ import com.google.common.collect.ImmutableMap; @Test(groups = "live", singleThreaded = true, testName = "AzureComputeSecurityGroupExtensionLiveTest") public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGroupExtensionLiveTest { - private AzureComputeApi api; - private LocationToResourceGroupName locationToResourceGroupName; - private String resourceGroupName; + private LoadingCache resourceGroupMap; private ResourceGroup testResourceGroup; + private CleanupResources cleanupResources; public AzureComputeSecurityGroupExtensionLiveTest() { provider = "azurecompute-arm"; @@ -71,8 +69,10 @@ public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGrou @BeforeClass(groups = { "integration", "live" }) public void setupContext() { super.setupContext(); - api = context.utils().injector().getInstance(AzureComputeApi.class); - locationToResourceGroupName = context.utils().injector().getInstance(LocationToResourceGroupName.class); + resourceGroupMap = context.utils().injector() + .getInstance(Key.get(new TypeLiteral>() { + })); + cleanupResources = context.utils().injector().getInstance(CleanupResources.class); createResourceGroupIfMissing(); } @@ -119,12 +119,7 @@ public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGrou @Override protected void tearDownContext() { super.tearDownContext(); - if (testResourceGroup != null) { - // Cleanup the resource group we created for the tests - getAnonymousLogger().info( - "deleting resource group " + testResourceGroup.name() + " for the security group live tests..."); - api.getResourceGroupApi().delete(testResourceGroup.name()); - } + cleanupResources.deleteResourceGroupIfEmpty(testResourceGroup.name()); } @Override @@ -142,13 +137,6 @@ public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGrou private void createResourceGroupIfMissing() { Location location = getNodeTemplate().getLocation(); - resourceGroupName = locationToResourceGroupName.apply(location.getId()); - ResourceGroup resourceGroupInLocation = api.getResourceGroupApi().get(resourceGroupName); - if (resourceGroupInLocation == null) { - getAnonymousLogger().info( - "creating resource group " + resourceGroupName + " for the security group live tests..."); - final Map tags = ImmutableMap.of("description", "AzureComputeSecurityGroupExtensionLiveTest"); - testResourceGroup = api.getResourceGroupApi().create(resourceGroupName, location.getId(), tags); - } + testResourceGroup = resourceGroupMap.getUnchecked(location.getId()); } } From c9e2286f73a490152c5892cacf7d8012008fc268 Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Thu, 26 Jan 2017 09:12:37 +0100 Subject: [PATCH 42/87] JCLOUDS-1229: Enable the rate limit module by default --- .../jclouds/azurecompute/arm/AzureManagementApiMetadata.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java index a3210608b7..d0c3e21db8 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java @@ -23,6 +23,7 @@ import org.jclouds.apis.ApiMetadata; import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule; import org.jclouds.azurecompute.arm.config.AzureComputeHttpApiModule; import org.jclouds.azurecompute.arm.config.AzureComputeParserModule; +import org.jclouds.azurecompute.arm.config.AzureComputeRateLimitModule; import org.jclouds.compute.ComputeServiceContext; import org.jclouds.http.okhttp.config.OkHttpCommandExecutorServiceModule; import org.jclouds.oauth.v2.config.OAuthModule; @@ -75,6 +76,7 @@ public class AzureManagementApiMetadata extends BaseHttpApiMetadata Date: Fri, 27 Jan 2017 14:20:18 +0100 Subject: [PATCH 43/87] Inspect all known OSFamilies --- .../arm/compute/functions/VMImageToImage.java | 66 ++++++++++--------- 1 file changed, 35 insertions(+), 31 deletions(-) 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 394b167ea8..38c076968a 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 @@ -17,6 +17,8 @@ package org.jclouds.azurecompute.arm.compute.functions; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Iterables.tryFind; +import static java.util.Arrays.asList; import java.util.Map; import java.util.Set; @@ -34,6 +36,8 @@ import org.jclouds.javax.annotation.Nullable; import org.jclouds.location.predicates.LocationPredicates; import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Predicate; import com.google.common.base.Supplier; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableMap; @@ -41,18 +45,12 @@ import com.google.inject.Inject; public class VMImageToImage implements Function { - public static final String MARKETPLACE_TAG = "marketplace"; - - 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 SLES = "SLES"; - private static final String ORACLE_lINUX = "Oracle-Linux"; - private static final String RHEL = "RHEL"; + private static final Map OTHER_OS_MAP = ImmutableMap. builder() + .put("openlogic", OsFamily.CENTOS) + .put("win", OsFamily.WINDOWS) + .put("sles", OsFamily.SUSE) + .put("oracle-linux", OsFamily.OEL) + .build(); private final Supplier> locations; @@ -155,25 +153,8 @@ public class VMImageToImage implements Function { return new Function() { @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) || label.contains(OPENLOGIC)) { - family = OsFamily.CENTOS; - } 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; - } else if (label.contains(WINDOWS)) { - family = OsFamily.WINDOWS; - } else if (label.contains(ORACLE_lINUX)) { - family = OsFamily.OEL; - } else if (label.contains(RHEL)) { - family = OsFamily.RHEL; - } + final String label = checkNotNull(image.offer(), "offer").toLowerCase(); + OsFamily family = findInStandardFamilies(label).or(findInOtherOSMap(label)).or(OsFamily.UNRECOGNIZED); // Fallback to generic operating system type if (OsFamily.UNRECOGNIZED == family && image.versionProperties() != null @@ -189,4 +170,27 @@ public class VMImageToImage implements Function { } }; } + + private static Optional findInStandardFamilies(final String label) { + return tryFind(asList(OsFamily.values()), new Predicate() { + @Override + public boolean apply(OsFamily input) { + return label.contains(input.value()); + } + }); + } + + private static Optional findInOtherOSMap(final String label) { + return tryFind(OTHER_OS_MAP.keySet(), new Predicate() { + @Override + public boolean apply(String input) { + return label.contains(input); + } + }).transform(new Function() { + @Override + public OsFamily apply(String input) { + return OTHER_OS_MAP.get(input); + } + }); + } } From ae9d4b366f852b83ca17ec60afb91dfd7f33bca0 Mon Sep 17 00:00:00 2001 From: Andrea Turli Date: Thu, 26 Jan 2017 13:08:21 +0100 Subject: [PATCH 44/87] [azurecompute-arm] performance improvements misc - improve cleanup performances: by using resourceGroupApi.resources --- .../compute/strategy/CleanupResources.java | 17 ++--- .../azurecompute/arm/domain/Resource.java | 72 +++++++++++++++++++ .../arm/features/ResourceGroupApi.java | 13 +++- .../features/ResourceGroupApiLiveTest.java | 11 ++- .../features/ResourceGroupApiMockTest.java | 37 ++++++++-- .../resources/resourcegroup-resources.json | 46 ++++++++++++ 6 files changed, 176 insertions(+), 20 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Resource.java create mode 100644 providers/azurecompute-arm/src/test/resources/resourcegroup-resources.json diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java index 3914bc027c..b971931ec4 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java @@ -16,12 +16,6 @@ */ package org.jclouds.azurecompute.arm.compute.strategy; -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.util.Closeables2.closeQuietly; - import java.net.URI; import java.util.List; @@ -53,6 +47,12 @@ import com.google.common.cache.LoadingCache; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; +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.util.Closeables2.closeQuietly; + @Singleton public class CleanupResources { @@ -165,10 +165,7 @@ public class CleanupResources { public boolean deleteResourceGroupIfEmpty(String group) { boolean deleted = false; - if (api.getVirtualMachineApi(group).list().isEmpty() && api.getStorageAccountApi(group).list().isEmpty() - && api.getNetworkInterfaceCardApi(group).list().isEmpty() - && api.getPublicIPAddressApi(group).list().isEmpty() - && api.getNetworkSecurityGroupApi(group).list().isEmpty()) { + if (api.getResourceGroupApi().resources(group).isEmpty()) { logger.debug(">> the resource group %s is empty. Deleting...", group); deleted = resourceDeleted.apply(api.getResourceGroupApi().delete(group)); } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Resource.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Resource.java new file mode 100644 index 0000000000..f04823478b --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Resource.java @@ -0,0 +1,72 @@ +/* + * 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 java.util.Map; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableMap; + +@AutoValue +public abstract class Resource { + + @AutoValue + public abstract static class Identity { + + public abstract String principalId(); + public abstract String tenantId(); + public abstract String type(); + + @SerializedNames({"principalId", "tenantId", "type" }) + public static Identity create(String principalId, String tenantId, String type) { + return new AutoValue_Resource_Identity(principalId, tenantId, type); + } + } + + @AutoValue + public abstract static class ResourceProperties{ + @Nullable + public abstract String provisioningState(); + + @SerializedNames({"provisioningState"}) + public static ResourceProperties create(final String provisioningState) { + return new AutoValue_Resource_ResourceProperties(provisioningState); + } + } + + public abstract String id(); + public abstract String name(); + public abstract String type(); + public abstract String location(); + @Nullable public abstract Map tags(); + @Nullable public abstract Identity identity(); + @Nullable public abstract SKU sku(); + @Nullable public abstract String managedBy(); + @Nullable public abstract String kind(); + @Nullable public abstract Plan plan(); + @Nullable public abstract ResourceProperties properties(); + + @SerializedNames({"id", "name", "type", "location", "tags", "identity", "sku", "managedBy", "kind", "plan", "properties"}) + public static Resource create(String id, String name, String type, String location, Map tags, + Identity identity, SKU sku, String managedBy, String kind, Plan plan, ResourceProperties properties) { + return new AutoValue_Resource(id, name, type, location, tags == null ? null : ImmutableMap.copyOf(tags), + identity, sku, managedBy, kind, plan, properties); + } +} 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 6f718a59e3..2c6a8b3904 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 @@ -15,6 +15,7 @@ * limitations under the License. */ package org.jclouds.azurecompute.arm.features; + import java.io.Closeable; import java.net.URI; import java.util.List; @@ -32,6 +33,7 @@ import javax.ws.rs.core.MediaType; import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.azurecompute.arm.domain.Resource; import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.filters.ApiVersionFilter; import org.jclouds.azurecompute.arm.functions.URIParser; @@ -67,7 +69,7 @@ public interface ResourceGroupApi extends Closeable{ @Path("/{name}") @Produces(MediaType.APPLICATION_JSON) @MapBinder(BindToJsonPayload.class) - ResourceGroup create(@PathParam("name") String name, @PayloadParam("location") String location, @Nullable @PayloadParam("tags")Map tags); + ResourceGroup create(@PathParam("name") String name, @PayloadParam("location") String location, @Nullable @PayloadParam("tags") Map tags); @Named("resourcegroup:get") @GET @@ -76,12 +78,19 @@ public interface ResourceGroupApi extends Closeable{ @Nullable ResourceGroup get(@PathParam("name") String name); + @Named("resourcegroup:resources") + @GET + @Path("/{name}/resources") + @SelectJson("value") + @Fallback(EmptyListOnNotFoundOr404.class) + List resources(@PathParam("name") String name); + @Named("resourcegroup:update") @PATCH @Produces(MediaType.APPLICATION_JSON) @Path("/{name}") @MapBinder(BindToJsonPayload.class) - ResourceGroup update(@PathParam("name") String name, @Nullable @PayloadParam("tags")Map tags); + ResourceGroup update(@PathParam("name") String name, @Nullable @PayloadParam("tags") Map tags); @Named("resourcegroup:delete") @DELETE diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiLiveTest.java index 3a0c134343..2dd8097e53 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiLiveTest.java @@ -19,6 +19,7 @@ package org.jclouds.azurecompute.arm.features; import java.net.URI; import java.util.List; +import org.jclouds.azurecompute.arm.domain.Resource; import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; import org.testng.annotations.AfterClass; @@ -42,6 +43,15 @@ public class ResourceGroupApiLiveTest extends BaseAzureComputeApiLiveTest { return api.getResourceGroupApi(); } + @Test(dependsOnMethods = "testCreate") + public void testResources() { + List resources = api().resources(RESOURCE_GROUP_NAME); + assertTrue(resources.isEmpty()); + for (Resource resource : resources) { + assertNotNull(resource); + } + } + @Test(dependsOnMethods = "testCreate") public void testList() { final List resourceGroups = api().list(); @@ -66,7 +76,6 @@ public class ResourceGroupApiLiveTest extends BaseAzureComputeApiLiveTest { } public void testCreate() { - final ResourceGroup resourceGroup = api().create(RESOURCE_GROUP_NAME, LOCATION, null); assertEquals(resourceGroup.name(), RESOURCE_GROUP_NAME); assertEquals(resourceGroup.location(), LOCATION); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiMockTest.java index 0c03c756aa..acac271c71 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiMockTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ResourceGroupApiMockTest.java @@ -16,20 +16,22 @@ */ package org.jclouds.azurecompute.arm.features; -import static com.google.common.collect.Iterables.isEmpty; -import static com.google.common.collect.Iterables.size; -import static org.testng.Assert.assertNotNull; - import java.net.URI; import java.util.List; -import com.google.common.collect.ImmutableMap; +import org.jclouds.azurecompute.arm.domain.Resource; import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; import org.testng.annotations.Test; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.assertNull; + +import com.google.common.collect.ImmutableMap; + +import static com.google.common.collect.Iterables.isEmpty; +import static com.google.common.collect.Iterables.size; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; @Test(groups = "unit", testName = "ResourceGroupApiMockTest", singleThreaded = true) public class ResourceGroupApiMockTest extends BaseAzureComputeApiMockTest { @@ -147,4 +149,25 @@ public class ResourceGroupApiMockTest extends BaseAzureComputeApiMockTest { assertSent(server, "DELETE", requestUrl + "/jcloudstest" + version); } + public void testListResourceGroupResources() throws InterruptedException { + server.enqueue(jsonResponse("/resourcegroup-resources.json")); + + List resources = api.getResourceGroupApi().resources("jcloudstest"); + + assertEquals(size(resources), 6); + + assertSent(server, "GET", requestUrl + "/jcloudstest/resources" + version); + } + + public void testListResourceGroupResourcesReturns404() throws InterruptedException { + server.enqueue(response404()); + + List resources = api.getResourceGroupApi().resources("jcloudstest"); + + assertTrue(isEmpty(resources)); + + assertEquals(server.getRequestCount(), 1); + assertSent(server, "GET", requestUrl + "/jcloudstest/resources" + version); + } + } diff --git a/providers/azurecompute-arm/src/test/resources/resourcegroup-resources.json b/providers/azurecompute-arm/src/test/resources/resourcegroup-resources.json new file mode 100644 index 0000000000..cae1a189a0 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/resourcegroup-resources.json @@ -0,0 +1,46 @@ +{ + "value": [ + { + "id": "/subscriptions/610bba05-d7a7-4567-96af-48ecbd09453b/resourceGroups/test/providers/Microsoft.Compute/virtualMachines/test", + "name": "test", + "type": "Microsoft.Compute/virtualMachines", + "location": "northeurope" + }, + { + "id": "/subscriptions/610bba05-d7a7-4567-96af-48ecbd09453b/resourceGroups/test/providers/Microsoft.Network/networkInterfaces/test641", + "name": "test641", + "type": "Microsoft.Network/networkInterfaces", + "location": "northeurope" + }, + { + "id": "/subscriptions/610bba05-d7a7-4567-96af-48ecbd09453b/resourceGroups/test/providers/Microsoft.Network/networkSecurityGroups/test-nsg", + "name": "test-nsg", + "type": "Microsoft.Network/networkSecurityGroups", + "location": "northeurope" + }, + { + "id": "/subscriptions/610bba05-d7a7-4567-96af-48ecbd09453b/resourceGroups/test/providers/Microsoft.Network/publicIPAddresses/test-ip", + "name": "test-ip", + "type": "Microsoft.Network/publicIPAddresses", + "location": "northeurope" + }, + { + "id": "/subscriptions/610bba05-d7a7-4567-96af-48ecbd09453b/resourceGroups/test/providers/Microsoft.Network/virtualNetworks/test-vnet", + "name": "test-vnet", + "type": "Microsoft.Network/virtualNetworks", + "location": "northeurope" + }, + { + "id": "/subscriptions/610bba05-d7a7-4567-96af-48ecbd09453b/resourceGroups/test/providers/Microsoft.Storage/storageAccounts/testjclo", + "name": "testjclo", + "type": "Microsoft.Storage/storageAccounts", + "sku": { + "name": "Premium_LRS", + "tier": "Premium" + }, + "kind": "Storage", + "location": "northeurope", + "tags": {} + } + ] +} From a312d661f685ac903859f73a5cdecc341464b41a Mon Sep 17 00:00:00 2001 From: Daniel Estevez Date: Mon, 23 Jan 2017 14:59:06 -0500 Subject: [PATCH 45/87] Add Load Balancer APIs to Azure ARM --- .../azurecompute/arm/AzureComputeApi.java | 25 + .../arm/AzureComputeProviderMetadata.java | 4 + .../compute/AzureComputeServiceAdapter.java | 7 +- .../AzureComputeServiceContextModule.java | 89 ++-- .../functions/TemplateToAvailabilitySet.java | 87 ++++ .../VirtualMachineToNodeMetadata.java | 10 +- .../compute/options/AzureTemplateOptions.java | 54 +- .../CreateResourceGroupThenCreateNodes.java | 16 +- .../arm/domain/AvailabilitySet.java | 84 +++- .../arm/domain/BackendAddressPool.java | 43 ++ .../domain/BackendAddressPoolProperties.java | 74 +++ .../azurecompute/arm/domain/DataDisk.java | 3 + .../azurecompute/arm/domain/Deployment.java | 2 +- .../arm/domain/DeploymentTemplate.java | 3 + .../arm/domain/DiagnosticsProfile.java | 6 + .../azurecompute/arm/domain/DnsSettings.java | 3 + .../arm/domain/FrontendIPConfigurations.java | 45 ++ .../FrontendIPConfigurationsProperties.java | 66 +++ .../arm/domain/HardwareProfile.java | 3 + .../arm/domain/ImageReference.java | 3 + .../arm/domain/InboundNatRule.java | 43 ++ .../arm/domain/InboundNatRuleProperties.java | 105 ++++ .../arm/domain/IpConfiguration.java | 2 + .../arm/domain/IpConfigurationProperties.java | 41 +- .../azurecompute/arm/domain/LoadBalancer.java | 50 ++ .../arm/domain/LoadBalancerProperties.java | 109 +++++ .../arm/domain/LoadBalancingRule.java | 43 ++ .../domain/LoadBalancingRuleProperties.java | 135 +++++ .../NetworkInterfaceCardProperties.java | 4 +- .../arm/domain/NetworkProfile.java | 3 + .../NetworkSecurityGroupProperties.java | 5 +- .../domain/NetworkSecurityRuleProperties.java | 3 + .../azurecompute/arm/domain/OSDisk.java | 3 + .../azurecompute/arm/domain/OSProfile.java | 3 + ...ilitySetVirtualMachine.java => Probe.java} | 29 +- .../arm/domain/ProbeProperties.java | 91 ++++ .../arm/domain/Provisionable.java | 22 + .../arm/domain/PublicIPAddressProperties.java | 5 +- .../arm/domain/ResourceDefinition.java | 3 + .../arm/domain/ResourceGroup.java | 2 +- .../arm/domain/ResourceProviderMetaData.java | 3 + .../azurecompute/arm/domain/Status.java | 49 ++ .../arm/domain/StorageProfile.java | 3 + .../arm/domain/StorageService.java | 4 +- .../azurecompute/arm/domain/Subnet.java | 5 +- .../jclouds/azurecompute/arm/domain/VHD.java | 3 + .../azurecompute/arm/domain/VMImage.java | 2 + .../arm/domain/VirtualMachine.java | 2 + .../arm/domain/VirtualMachineInstance.java | 57 +-- .../arm/domain/VirtualMachineProperties.java | 8 +- .../arm/domain/VirtualNetwork.java | 5 +- .../arm/features/AvailabilitySetApi.java | 83 ++++ .../arm/features/LoadBalancerApi.java | 82 ++++ .../arm/features/NetworkInterfaceCardApi.java | 7 +- .../compute/AzureComputeServiceLiveTest.java | 32 ++ .../AzureComputeImageExtensionLiveTest.java | 34 +- ...ComputeSecurityGroupExtensionLiveTest.java | 15 +- .../features/AvailabilitySetApiLiveTest.java | 100 ++++ .../features/AvailabilitySetApiMockTest.java | 153 ++++++ .../arm/features/DeploymentApiLiveTest.java | 13 +- .../arm/features/LoadBalancerApiLiveTest.java | 460 ++++++++++++++++++ .../arm/features/LoadBalancerApiMockTest.java | 155 ++++++ .../NetworkInterfaceCardApiLiveTest.java | 19 +- .../NetworkInterfaceCardApiMockTest.java | 10 +- .../NetworkSecurityGroupApiLiveTest.java | 23 +- .../NetworkSecurityRuleApiLiveTest.java | 23 +- .../features/PublicIPAddressApiLiveTest.java | 26 +- .../features/StorageAccountApiLiveTest.java | 26 +- .../arm/features/SubnetApiLiveTest.java | 31 +- .../features/VirtualMachineApiLiveTest.java | 25 +- .../features/VirtualMachineApiMockTest.java | 11 +- .../features/VirtualNetworkApiLiveTest.java | 28 +- .../arm/internal/AzureLiveTestUtils.java | 2 + .../internal/BaseAzureComputeApiLiveTest.java | 68 ++- .../test/resources/availabilitysetcreate.json | 11 + .../test/resources/availabilitysetget.json | 12 + .../test/resources/availabilitysetlist.json | 16 + .../test/resources/listvirtualnetworks.json | 2 +- .../test/resources/loadbalancercreate.json | 28 ++ .../src/test/resources/loadbalancerget.json | 54 ++ .../src/test/resources/loadbalancerlist.json | 35 ++ 81 files changed, 2725 insertions(+), 328 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/TemplateToAvailabilitySet.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/BackendAddressPool.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/BackendAddressPoolProperties.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/FrontendIPConfigurations.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/FrontendIPConfigurationsProperties.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/InboundNatRule.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/InboundNatRuleProperties.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/LoadBalancer.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/LoadBalancerProperties.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/LoadBalancingRule.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/LoadBalancingRuleProperties.java rename providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/{AvailabilitySetVirtualMachine.java => Probe.java} (66%) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ProbeProperties.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Provisionable.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Status.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApi.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/LoadBalancerApi.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/resources/availabilitysetcreate.json create mode 100644 providers/azurecompute-arm/src/test/resources/availabilitysetget.json create mode 100644 providers/azurecompute-arm/src/test/resources/availabilitysetlist.json create mode 100644 providers/azurecompute-arm/src/test/resources/loadbalancercreate.json create mode 100644 providers/azurecompute-arm/src/test/resources/loadbalancerget.json create mode 100644 providers/azurecompute-arm/src/test/resources/loadbalancerlist.json 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 c0c0994729..3700069dbe 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 @@ -20,8 +20,10 @@ import java.io.Closeable; import javax.ws.rs.PathParam; +import org.jclouds.azurecompute.arm.features.AvailabilitySetApi; import org.jclouds.azurecompute.arm.features.DeploymentApi; import org.jclouds.azurecompute.arm.features.JobApi; +import org.jclouds.azurecompute.arm.features.LoadBalancerApi; import org.jclouds.azurecompute.arm.features.LocationApi; import org.jclouds.azurecompute.arm.features.NetworkInterfaceCardApi; import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi; @@ -35,6 +37,7 @@ 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.rest.annotations.Delegate; /** @@ -156,6 +159,28 @@ public interface AzureComputeApi extends Closeable { NetworkSecurityRuleApi getNetworkSecurityRuleApi(@PathParam("resourcegroup") String resourcegroup, @PathParam("networksecuritygroup") String networksecuritygroup); + /** + * The LoadBalancer API includes operations for managing load balancers + * within your subscription. + * + * @see docs + * + */ + @Delegate + LoadBalancerApi getLoadBalancerApi(@PathParam("resourcegroup") String resourcegroup); + + /** + * The AvailabilitySet API includes operations for managing availability sets + * within your subscription. + * + * @see docs + * + */ + @Delegate + AvailabilitySetApi getAvailabilitySetApi(@PathParam("resourcegroup") String resourcegroup); + /** * The Azure Resource Provider API provides information about a resource provider and its supported resource types. * 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 1590bf234e..a4c2bbebe7 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 @@ -39,7 +39,9 @@ import java.net.URI; import java.util.Properties; import org.jclouds.azurecompute.arm.domain.Region; +import org.jclouds.azurecompute.arm.features.AvailabilitySetApi; import org.jclouds.azurecompute.arm.features.DeploymentApi; +import org.jclouds.azurecompute.arm.features.LoadBalancerApi; import org.jclouds.azurecompute.arm.features.LocationApi; import org.jclouds.azurecompute.arm.features.NetworkInterfaceCardApi; import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi; @@ -108,6 +110,8 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { 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 + LoadBalancerApi.class.getSimpleName(), "2016-03-30"); + properties.put(API_VERSION_PREFIX + AvailabilitySetApi.class.getSimpleName(), "2016-03-30"); 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"); 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 5a8204ebda..a1204bf5bd 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 @@ -139,6 +139,11 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter create one nic in each network + + IdReference availabilitySet = null; + if (templateOptions.getAvailabilitySet() != null) { + availabilitySet = IdReference.create(templateOptions.getAvailabilitySet().id()); + } String locationName = template.getLocation().getId(); String subnetId = templateOptions.getSubnetId(); @@ -151,7 +156,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter> resourceAvailable) { + return new PublicIpAvailablePredicateFactory(api, resourceAvailable); } @Provides protected SecurityGroupAvailablePredicateFactory provideSecurityGroupAvailablePredicate(final AzureComputeApi api, + Predicate> resourceAvailable) { + return new SecurityGroupAvailablePredicateFactory(api, resourceAvailable); + } + + @Provides + protected Predicate> provideResourceAvailablePredicate(final AzureComputeApi api, @Named(OPERATION_TIMEOUT) Integer operationTimeout, PollPeriod pollPeriod) { - return new SecurityGroupAvailablePredicateFactory(api, operationTimeout, pollPeriod.pollInitialPeriod, + return retry(new ResourceInStatusPredicate("Succeeded"), operationTimeout, pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); } @@ -274,64 +281,74 @@ public class AzureComputeServiceContextModule extends }, timeout, period, maxPeriod); } } + + public static class ResourceInStatusPredicate implements Predicate> { + private final String expectedStatus; + + ResourceInStatusPredicate(String expectedStatus) { + this.expectedStatus = checkNotNull(expectedStatus, "expectedStatus cannot be null"); + } + + @Override + public boolean apply(Supplier provisionableSupplier) { + checkNotNull(provisionableSupplier, "provisionableSupplier supplier cannot be null"); + Provisionable provisionable = provisionableSupplier.get(); + return provisionable != null && provisionable.provisioningState().equalsIgnoreCase(expectedStatus); + } + } public static class PublicIpAvailablePredicateFactory { - private final AzureComputeApi api; - private final long timeout; - private final long period; - private final long maxPeriod; + private final Predicate> resourceAvailable; - PublicIpAvailablePredicateFactory(final AzureComputeApi api, final long timeout, final long period, - final long maxPeriod) { + PublicIpAvailablePredicateFactory(final AzureComputeApi api, Predicate> resourceAvailable) { this.api = checkNotNull(api, "api cannot be null"); - this.timeout = timeout; - this.period = period; - this.maxPeriod = maxPeriod; + this.resourceAvailable = resourceAvailable; } public Predicate create(final String azureGroup) { - return retry(new Predicate() { + checkNotNull(azureGroup, "azureGroup cannot be null"); + return new Predicate() { @Override public boolean apply(final String name) { checkNotNull(name, "name cannot be null"); - PublicIPAddress publicIp = api.getPublicIPAddressApi(azureGroup).get(name); - if (publicIp == null) { - return false; - } - return publicIp.properties().provisioningState().equalsIgnoreCase("Succeeded"); + return resourceAvailable.apply(new Supplier() { + @Override + public Provisionable get() { + PublicIPAddress publicIp = api.getPublicIPAddressApi(azureGroup).get(name); + return publicIp == null ? null : publicIp.properties(); + } + }); } - }, timeout, period, maxPeriod); + }; } } public static class SecurityGroupAvailablePredicateFactory { private final AzureComputeApi api; - private final long timeout; - private final long period; - private final long maxPeriod; + private final Predicate> resourceAvailable; - SecurityGroupAvailablePredicateFactory(final AzureComputeApi api, final long timeout, final long period, - final long maxPeriod) { + SecurityGroupAvailablePredicateFactory(final AzureComputeApi api, + Predicate> resourceAvailable) { this.api = checkNotNull(api, "api cannot be null"); - this.timeout = timeout; - this.period = period; - this.maxPeriod = maxPeriod; + this.resourceAvailable = resourceAvailable; } public Predicate create(final String resourceGroup) { checkNotNull(resourceGroup, "resourceGroup cannot be null"); - return retry(new Predicate() { + return new Predicate() { @Override public boolean apply(final String name) { checkNotNull(name, "name cannot be null"); - NetworkSecurityGroup sg = api.getNetworkSecurityGroupApi(resourceGroup).get(name); - if (sg == null) { - return false; - } - return sg.properties().provisioningState().equalsIgnoreCase("Succeeded"); + return resourceAvailable.apply(new Supplier() { + @Override + public Provisionable get() { + NetworkSecurityGroup sg = api.getNetworkSecurityGroupApi(resourceGroup).get(name); + return sg == null ? null : sg.properties(); + } + }); } - }, timeout, period, maxPeriod); + }; } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/TemplateToAvailabilitySet.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/TemplateToAvailabilitySet.java new file mode 100644 index 0000000000..4e1adebded --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/TemplateToAvailabilitySet.java @@ -0,0 +1,87 @@ +/* + * 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.checkArgument; + +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.options.AzureTemplateOptions; +import org.jclouds.azurecompute.arm.domain.AvailabilitySet; +import org.jclouds.azurecompute.arm.domain.ResourceGroup; +import org.jclouds.compute.domain.Template; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.logging.Logger; + +import com.google.common.base.Function; +import com.google.common.cache.LoadingCache; + +@Singleton +public class TemplateToAvailabilitySet implements Function { + + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + private final AzureComputeApi api; + private final LoadingCache resourceGroupMap; + + @Inject + TemplateToAvailabilitySet(AzureComputeApi api, LoadingCache resourceGroupMap) { + this.api = api; + this.resourceGroupMap = resourceGroupMap; + } + + @Nullable + @Override + public AvailabilitySet apply(final Template input) { + checkArgument(input.getOptions() instanceof AzureTemplateOptions, "An AzureTemplateOptions object is required"); + AzureTemplateOptions options = input.getOptions().as(AzureTemplateOptions.class); + + AvailabilitySet availabilitySet = null; + String location = input.getLocation().getId(); + String resourceGroup = resourceGroupMap.getUnchecked(location).name(); + + if (options.getAvailabilitySetName() != null) { + availabilitySet = api.getAvailabilitySetApi(resourceGroup).get(options.getAvailabilitySetName()); + + checkArgument(availabilitySet != null, "No availability set with name '%s' was found", options.getAvailabilitySetName()); + checkArgument(location.equals(availabilitySet.location()), "The availability set %s does not belong to location %s", + options.getAvailabilitySetName(), location); + + } else if (options.getAvailabilitySet() != null) { + availabilitySet = api.getAvailabilitySetApi(resourceGroup).get(options.getAvailabilitySet().name()); + + if (availabilitySet != null) { + checkArgument(location.equals(availabilitySet.location()), "The availability set %s does not belong to location %s", + options.getAvailabilitySetName(), location); + } else { + availabilitySet = api.getAvailabilitySetApi(resourceGroup).createOrUpdate(options.getAvailabilitySet().name(), location, + options.getAvailabilitySet().tags(), options.getAvailabilitySet().properties()); + logger.debug(">> creating availability set [%s]", availabilitySet.name()); + } + } + + return availabilitySet; + } + +} 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 index 92689c2e4a..26bf985f25 100644 --- 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 @@ -48,10 +48,10 @@ 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.VirtualMachineInstance.PowerState; import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties; import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties.ProvisioningState; +import org.jclouds.azurecompute.arm.domain.Status; import org.jclouds.azurecompute.arm.functions.StorageProfileToStorageAccountName; import org.jclouds.azurecompute.arm.util.BlobHelper; import org.jclouds.collect.Memoized; @@ -107,7 +107,7 @@ public class VirtualMachineToNodeMetadata implements Function POWERSTATE_TO_NODESTATUS = Functions + private static final Function POWERSTATE_TO_NODESTATUS = Functions .forMap( ImmutableMap. builder() .put(PowerState.RUNNING, NodeMetadata.Status.RUNNING) @@ -161,9 +161,9 @@ public class VirtualMachineToNodeMetadata implements Function() { + transform(instanceDetails.statuses(), new Function() { @Override - public String apply(VirtualMachineStatus input) { + public String apply(Status input) { return input.code(); } }))); 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 ecbc237f8c..8381076ba4 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,6 +16,7 @@ */ package org.jclouds.azurecompute.arm.compute.options; +import org.jclouds.azurecompute.arm.domain.AvailabilitySet; import org.jclouds.compute.options.TemplateOptions; import com.google.common.base.Objects; @@ -30,6 +31,8 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { private String virtualNetworkName; private String subnetId; private String blob; + private AvailabilitySet availabilitySet; + private String availabilitySetName; /** * Sets the virtual network name @@ -54,10 +57,30 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { this.blob = blob; return this; } + + /** + * Sets the availability set where the nodes will be configured. If it does + * not exist jclouds will create a new one with the given configuration. + */ + public AzureTemplateOptions availabilitySet(AvailabilitySet availabilitySet) { + this.availabilitySet = availabilitySet; + return this; + } + + /** + * Sets the availability set where the nodes will be configured. The + * availability set must exist. + */ + public AzureTemplateOptions availabilitySet(String availabilitySetName) { + this.availabilitySetName = availabilitySetName; + return this; + } public String getVirtualNetworkName() { return virtualNetworkName; } public String getSubnetId() { return subnetId; } public String getBlob() { return blob; } + public AvailabilitySet getAvailabilitySet() { return availabilitySet; } + public String getAvailabilitySetName() { return availabilitySetName; } @Override @@ -75,12 +98,15 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { eTo.virtualNetworkName(virtualNetworkName); eTo.subnetId(subnetId); eTo.blob(blob); + eTo.availabilitySet(availabilitySet); + eTo.availabilitySet(availabilitySetName); } } @Override public int hashCode() { - return Objects.hashCode(super.hashCode(), virtualNetworkName, subnetId, blob); + return Objects.hashCode(super.hashCode(), virtualNetworkName, subnetId, blob, availabilitySet, + availabilitySetName); } @Override @@ -98,7 +124,9 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { return super.equals(other) && equal(this.virtualNetworkName, other.virtualNetworkName) && equal(this.subnetId, other.subnetId) - && equal(this.blob, other.blob); + && equal(this.blob, other.blob) + && equal(this.availabilitySet, other.availabilitySet) + && equal(this.availabilitySetName, other.availabilitySetName); } @Override @@ -113,7 +141,7 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { public static class Builder { /** - * @see AzureTemplateOptions#virtualNetworkName + * @see AzureTemplateOptions#virtualNetworkName(String) */ public static AzureTemplateOptions virtualNetworkName(String virtualNetworkName) { AzureTemplateOptions options = new AzureTemplateOptions(); @@ -121,7 +149,7 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { } /** - * @see AzureTemplateOptions#subnetId + * @see AzureTemplateOptions#subnetId(String) */ public static AzureTemplateOptions subnetId(String subnetId) { AzureTemplateOptions options = new AzureTemplateOptions(); @@ -129,11 +157,27 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { } /** - * @see AzureTemplateOptions#blob + * @see AzureTemplateOptions#blob(String) */ public static AzureTemplateOptions blob(String blob) { AzureTemplateOptions options = new AzureTemplateOptions(); return options.blob(blob); } + + /** + * @see AzureTemplateOptions#availabilitySet(AvailabilitySet) + */ + public static AzureTemplateOptions availabilitySet(AvailabilitySet availabilitySet) { + AzureTemplateOptions options = new AzureTemplateOptions(); + return options.availabilitySet(availabilitySet); + } + + /** + * @see AzureTemplateOptions#availabilitySet(String) + */ + public static AzureTemplateOptions availabilitySet(String availabilitySetName) { + AzureTemplateOptions options = new AzureTemplateOptions(); + return options.availabilitySet(availabilitySetName); + } } } 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 378030fa00..92c949956e 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 @@ -38,7 +38,9 @@ import javax.inject.Singleton; import org.jclouds.Constants; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.compute.domain.RegionAndIdAndIngressRules; +import org.jclouds.azurecompute.arm.compute.functions.TemplateToAvailabilitySet; import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; +import org.jclouds.azurecompute.arm.domain.AvailabilitySet; import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; import org.jclouds.azurecompute.arm.domain.RegionAndId; import org.jclouds.azurecompute.arm.domain.ResourceGroup; @@ -84,6 +86,7 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco private final String defaultVnetAddressPrefix; private final String defaultSubnetAddressPrefix; private final Predicate storageAccountCreated; + private final TemplateToAvailabilitySet templateToAvailabilitySet; @Inject protected CreateResourceGroupThenCreateNodes( @@ -95,7 +98,8 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco AzureComputeApi api, @Named(DEFAULT_VNET_ADDRESS_SPACE_PREFIX) String defaultVnetAddressPrefix, @Named(DEFAULT_SUBNET_ADDRESS_PREFIX) String defaultSubnetAddressPrefix, LoadingCache securityGroupMap, - LoadingCache resourceGroupMap, @Named("STORAGE") Predicate storageAccountCreated) { + LoadingCache resourceGroupMap, @Named("STORAGE") Predicate storageAccountCreated, + TemplateToAvailabilitySet templateToAvailabilitySet) { super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor, customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory); this.api = checkNotNull(api, "api cannot be null"); @@ -105,6 +109,7 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco this.defaultVnetAddressPrefix = defaultVnetAddressPrefix; this.defaultSubnetAddressPrefix = defaultSubnetAddressPrefix; this.storageAccountCreated = storageAccountCreated; + this.templateToAvailabilitySet = templateToAvailabilitySet; } @Override @@ -129,6 +134,7 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco getOrCreateVirtualNetworkWithSubnet(location, options, azureGroupName); configureSecurityGroupForOptions(group, azureGroupName, template.getLocation(), options); + configureAvailabilitySetForTemplate(template); StorageService storageService = getOrCreateStorageService(group, azureGroupName, location, template.getImage()); options.blob(storageService.storageServiceProperties().primaryEndpoints().get("blob")); @@ -217,6 +223,14 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco options.securityGroups(securityGroupId); } } + + private void configureAvailabilitySetForTemplate(Template template) { + AvailabilitySet availabilitySet = templateToAvailabilitySet.apply(template); + if (availabilitySet != null) { + logger.debug(">> configuring nodes in availability set [%s]", availabilitySet.name()); + template.getOptions().as(AzureTemplateOptions.class).availabilitySet(availabilitySet); + } + } /** * Generates a valid storage account diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/AvailabilitySet.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/AvailabilitySet.java index cb903074c1..624c6640cb 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/AvailabilitySet.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/AvailabilitySet.java @@ -17,13 +17,15 @@ package org.jclouds.azurecompute.arm.domain; +import java.util.List; +import java.util.Map; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import org.jclouds.javax.annotation.Nullable; -import org.jclouds.json.SerializedNames; -import java.util.Map; -import java.util.List; /** * AvailabilitySet for subscription @@ -45,24 +47,54 @@ public abstract class AvailabilitySet { public abstract int platformFaultDomainCount(); /** - * A list of virtual machines in availability set + * A list of virtual machines in the availability set */ @Nullable - public abstract List virtualMachines(); + public abstract List virtualMachines(); + + /** + * A list of statuses in the availability set + */ + @Nullable + public abstract List statuses(); - @SerializedNames({"platformUpdateDomainCount", "platformFaultDomainCount", "virtualMachines"}) + @SerializedNames({ "platformUpdateDomainCount", "platformFaultDomainCount", "virtualMachines", "statuses" }) public static AvailabilitySetProperties create(final int platformUpdateDomainCount, - final int platformFaultDomainCount, - List virtualMachines) { - return new AutoValue_AvailabilitySet_AvailabilitySetProperties(platformUpdateDomainCount, - platformFaultDomainCount, - virtualMachines == null ? null : ImmutableList.copyOf(virtualMachines)); + final int platformFaultDomainCount, List virtualMachines, List statuses) { + return builder().platformUpdateDomainCount(platformUpdateDomainCount) + .platformFaultDomainCount(platformFaultDomainCount).virtualMachines(virtualMachines).statuses(statuses) + .build(); + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_AvailabilitySet_AvailabilitySetProperties.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder platformUpdateDomainCount(int platformUpdateDomainCount); + public abstract Builder platformFaultDomainCount(int platformFaultDomainCount); + public abstract Builder virtualMachines(List virtualMachines); + public abstract Builder statuses(List statuses); + + abstract List virtualMachines(); + abstract List statuses(); + abstract AvailabilitySetProperties autoBuild(); + + public AvailabilitySetProperties build() { + virtualMachines(virtualMachines() != null ? ImmutableList.copyOf(virtualMachines()) : null); + statuses(statuses() != null ? ImmutableList.copyOf(statuses()) : null); + return autoBuild(); + } } } /** * The id of the availability set */ + @Nullable public abstract String id(); /** @@ -72,7 +104,7 @@ public abstract class AvailabilitySet { public abstract String name(); /** - * The name of the availability set. + * The type of the availability set. */ @Nullable public abstract String type(); @@ -99,6 +131,30 @@ public abstract class AvailabilitySet { @SerializedNames({"id", "name", "type", "location", "tags", "properties"}) public static AvailabilitySet create(final String id, final String name, final String type, final String location, final Map tags, AvailabilitySetProperties properties) { - return new AutoValue_AvailabilitySet(id, name, type, location, tags == null ? null : ImmutableMap.copyOf(tags), properties); + return builder().id(id).name(name).type(type).location(location).tags(tags).properties(properties).build(); + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_AvailabilitySet.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder id(String id); + public abstract Builder name(String name); + public abstract Builder type(String type); + public abstract Builder location(String location); + public abstract Builder tags(Map tags); + public abstract Builder properties(AvailabilitySetProperties properties); + + abstract Map tags(); + abstract AvailabilitySet autoBuild(); + + public AvailabilitySet build() { + tags(tags() != null ? ImmutableMap.copyOf(tags()) : null); + return autoBuild(); + } } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/BackendAddressPool.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/BackendAddressPool.java new file mode 100644 index 0000000000..37ea4aa674 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/BackendAddressPool.java @@ -0,0 +1,43 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class BackendAddressPool { + public abstract String name(); + + @Nullable + public abstract String id(); + + @Nullable + public abstract BackendAddressPoolProperties properties(); + + @Nullable + public abstract String etag(); + + @SerializedNames({ "name", "id", "properties", "etag" }) + public static BackendAddressPool create(final String name, final String id, + final BackendAddressPoolProperties properties, final String etag) { + return new AutoValue_BackendAddressPool(name, id, properties, etag); + } +} + diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/BackendAddressPoolProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/BackendAddressPoolProperties.java new file mode 100644 index 0000000000..4daed6ff7f --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/BackendAddressPoolProperties.java @@ -0,0 +1,74 @@ +/* + * 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 java.util.List; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; + +@AutoValue +public abstract class BackendAddressPoolProperties implements Provisionable { + + @Nullable + public abstract String provisioningState(); + + @Nullable + public abstract List backendIPConfigurations(); + + @Nullable + public abstract List loadBalancingRules(); + + + @SerializedNames({ "provisioningState", "backendIPConfigurations", "loadBalancingRules"}) + public static BackendAddressPoolProperties create(final String provisioningState, + final List backendIPConfigurations, final List loadBalancingRules) { + return builder().provisioningState(provisioningState).backendIPConfigurations(backendIPConfigurations).loadBalancingRules(loadBalancingRules).build(); + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_BackendAddressPoolProperties.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + + public abstract Builder provisioningState(String provisioningState); + + public abstract Builder backendIPConfigurations(List backendIPConfigurations); + + public abstract Builder loadBalancingRules(List loadBalancingRules); + + abstract List backendIPConfigurations(); + abstract List loadBalancingRules(); + + abstract BackendAddressPoolProperties autoBuild(); + + public BackendAddressPoolProperties build() { + backendIPConfigurations(backendIPConfigurations() != null ? ImmutableList.copyOf(backendIPConfigurations()) + : null); + loadBalancingRules(loadBalancingRules() != null ? ImmutableList.copyOf(loadBalancingRules()) : null); + return autoBuild(); + } + } +} + diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DataDisk.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DataDisk.java index de1fa366fa..ebb137ba97 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DataDisk.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DataDisk.java @@ -17,6 +17,7 @@ package org.jclouds.azurecompute.arm.domain; import com.google.auto.value.AutoValue; + import org.jclouds.json.SerializedNames; @AutoValue @@ -58,6 +59,8 @@ public abstract class DataDisk { .vhd(vhd) .build(); } + + public abstract Builder toBuilder(); public static Builder builder() { return new AutoValue_DataDisk.Builder(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Deployment.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Deployment.java index be363ecd0a..fe22591b3e 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Deployment.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Deployment.java @@ -160,7 +160,7 @@ public abstract class Deployment { } @AutoValue - public abstract static class DeploymentProperties { + public abstract static class DeploymentProperties implements Provisionable { @Nullable public abstract String provisioningState(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DeploymentTemplate.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DeploymentTemplate.java index 5221e053d8..84e6061ef7 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DeploymentTemplate.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DeploymentTemplate.java @@ -19,6 +19,7 @@ package org.jclouds.azurecompute.arm.domain; import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; + import org.jclouds.javax.annotation.Nullable; import java.util.List; @@ -89,6 +90,8 @@ public abstract class DeploymentTemplate { return builder.build(); } + + public abstract Builder toBuilder(); public static Builder builder() { return new AutoValue_DeploymentTemplate.Builder(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DiagnosticsProfile.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DiagnosticsProfile.java index 6097e595f6..bd8cb0c0c2 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DiagnosticsProfile.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DiagnosticsProfile.java @@ -17,6 +17,7 @@ package org.jclouds.azurecompute.arm.domain; import com.google.auto.value.AutoValue; + import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; @@ -38,6 +39,8 @@ public abstract class DiagnosticsProfile { .storageUri(storageUri) .build(); } + + public abstract Builder toBuilder(); public static Builder builder() { return new AutoValue_DiagnosticsProfile_BootDiagnostics.Builder(); @@ -56,6 +59,9 @@ public abstract class DiagnosticsProfile { public static DiagnosticsProfile create(final BootDiagnostics bootDiagnostics) { return builder().bootDiagnostics(bootDiagnostics).build(); } + + public abstract Builder toBuilder(); + public static Builder builder() { return new AutoValue_DiagnosticsProfile.Builder(); } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DnsSettings.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DnsSettings.java index a527eb0592..c06ef2277d 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DnsSettings.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DnsSettings.java @@ -17,6 +17,7 @@ package org.jclouds.azurecompute.arm.domain; import com.google.auto.value.AutoValue; + import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; @@ -39,6 +40,8 @@ public abstract class DnsSettings { .reverseFqdn(reverseFqdn) .build(); } + + public abstract Builder toBuilder(); public static Builder builder() { return new AutoValue_DnsSettings.Builder(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/FrontendIPConfigurations.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/FrontendIPConfigurations.java new file mode 100644 index 0000000000..fae60c9d13 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/FrontendIPConfigurations.java @@ -0,0 +1,45 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class FrontendIPConfigurations { + public abstract String name(); + + @Nullable + public abstract String id(); + + @Nullable + public abstract FrontendIPConfigurationsProperties properties(); + + @Nullable + public abstract String etag(); + + @SerializedNames({ "name", "id", "properties", "etag" }) + public static FrontendIPConfigurations create(final String name, final String id, + final FrontendIPConfigurationsProperties properties, + final String etag) { + return new AutoValue_FrontendIPConfigurations(name, id, + properties, etag); + } +} + diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/FrontendIPConfigurationsProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/FrontendIPConfigurationsProperties.java new file mode 100644 index 0000000000..b4517734f4 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/FrontendIPConfigurationsProperties.java @@ -0,0 +1,66 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class FrontendIPConfigurationsProperties { + + @Nullable + public abstract IdReference subnet(); + + @Nullable + public abstract String privateIPAddress(); + + @Nullable + public abstract String privateIPAllocationMethod(); + + @Nullable + public abstract IdReference publicIPAddress(); + + + @SerializedNames({ "subnet", "privateIPAddress", "privateIPAllocationMethod", "publicIPAddress" }) + public static FrontendIPConfigurationsProperties create(final IdReference subnet, final String privateIPAddress, + final String privateIPAllocationMethod, final IdReference publicIPAddress) { + return builder().subnet(subnet).publicIPAddress(publicIPAddress).privateIPAddress(privateIPAddress) + .privateIPAllocationMethod(privateIPAllocationMethod).build(); + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_FrontendIPConfigurationsProperties.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder subnet(IdReference subnet); + + public abstract Builder privateIPAddress(String privateIPAddress); + + public abstract Builder privateIPAllocationMethod(String privateIPAllocationMethod); + + public abstract Builder publicIPAddress(IdReference publicIPAddress); + + public abstract FrontendIPConfigurationsProperties build(); + } +} + diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/HardwareProfile.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/HardwareProfile.java index ee9a5f1a87..9342202628 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/HardwareProfile.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/HardwareProfile.java @@ -17,6 +17,7 @@ package org.jclouds.azurecompute.arm.domain; import com.google.auto.value.AutoValue; + import org.jclouds.json.SerializedNames; @AutoValue @@ -31,6 +32,8 @@ public abstract class HardwareProfile { public static HardwareProfile create(final String vmSize) { return builder().vmSize(vmSize).build(); } + + public abstract Builder toBuilder(); public static Builder builder() { return new AutoValue_HardwareProfile.Builder(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java index 9cc67478af..f9e1875b4f 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java @@ -17,6 +17,7 @@ package org.jclouds.azurecompute.arm.domain; import com.google.auto.value.AutoValue; + import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; @@ -60,6 +61,8 @@ public abstract class ImageReference { .version(version) .build(); } + + public abstract Builder toBuilder(); public static Builder builder() { return new AutoValue_ImageReference.Builder(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/InboundNatRule.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/InboundNatRule.java new file mode 100644 index 0000000000..dccc2e907c --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/InboundNatRule.java @@ -0,0 +1,43 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class InboundNatRule { + @Nullable + public abstract String name(); + + @Nullable + public abstract String id(); + + @Nullable + public abstract InboundNatRuleProperties properties(); + + @Nullable + public abstract String etag(); + + @SerializedNames({ "name", "id", "properties", "etag" }) + public static InboundNatRule create(final String name, final String id, final InboundNatRuleProperties properties, + final String etag) { + return new AutoValue_InboundNatRule(name, id, properties, etag); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/InboundNatRuleProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/InboundNatRuleProperties.java new file mode 100644 index 0000000000..9ed6aed1ca --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/InboundNatRuleProperties.java @@ -0,0 +1,105 @@ +/* + * 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 org.jclouds.azurecompute.arm.util.GetEnumValue; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class InboundNatRuleProperties implements Provisionable { + public enum Protocol { + Tcp("Tcp"), Udp("Udp"), UNRECOGNIZED("Unrecognized"); + + private final String label; + + private Protocol(final String label) { + this.label = label; + } + + public static Protocol fromValue(final String text) { + return (Protocol) GetEnumValue.fromValueOrDefault(text, Protocol.UNRECOGNIZED); + } + + @Override + public String toString() { + return label; + } + } + + @Nullable + public abstract IdReference frontendIPConfiguration(); + + @Nullable + public abstract IdReference backendIPConfiguration(); + + public abstract Protocol protocol(); + + public abstract int backendPort(); + + public abstract int frontendPort(); + + @Nullable + public abstract Boolean enableFloatingIP(); + + @Nullable + public abstract Integer idleTimeoutInMinutes(); + + @Nullable + public abstract String provisioningState(); + + @SerializedNames({ "frontendIPConfiguration", "backendIPConfiguration", "protocol", "frontendPort", "backendPort", + "provisioningState", "enableFloatingIP", "idleTimeoutInMinutes" }) + public static InboundNatRuleProperties create(final IdReference frontendIPConfiguration, + final IdReference backendIPConfiguration, final Protocol protocol, final int frontendPort, + final int backendPort, final String provisioningState, Boolean enableFloatingIP, Integer idleTimeoutInMinutes) { + return builder().frontendIPConfiguration(frontendIPConfiguration).backendIPConfiguration(backendIPConfiguration) + .protocol(protocol).frontendPort(frontendPort).backendPort(backendPort) + .provisioningState(provisioningState).enableFloatingIP(enableFloatingIP) + .idleTimeoutInMinutes(idleTimeoutInMinutes).build(); + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_InboundNatRuleProperties.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + + public abstract Builder frontendIPConfiguration(IdReference frontendIPConfiguration); + + public abstract Builder backendIPConfiguration(IdReference backendIPConfiguration); + + public abstract Builder protocol(Protocol protocol); + + public abstract Builder frontendPort(int frontendPort); + + public abstract Builder backendPort(int backendPort); + + public abstract Builder provisioningState(String provisioningState); + + public abstract Builder enableFloatingIP(Boolean enableFloatingIP); + + public abstract Builder idleTimeoutInMinutes(Integer idleTimeoutInMinutes); + + public abstract InboundNatRuleProperties build(); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IpConfiguration.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IpConfiguration.java index bb49a77a1e..e5236227ff 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IpConfiguration.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IpConfiguration.java @@ -49,6 +49,8 @@ public abstract class IpConfiguration { .properties(properties) .build(); } + + public abstract Builder toBuilder(); public static Builder builder() { return new AutoValue_IpConfiguration.Builder(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IpConfigurationProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IpConfigurationProperties.java index 8e3bd5341e..21f494fadd 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IpConfigurationProperties.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IpConfigurationProperties.java @@ -16,12 +16,16 @@ */ package org.jclouds.azurecompute.arm.domain; +import java.util.List; + import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; + import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; @AutoValue -public abstract class IpConfigurationProperties { +public abstract class IpConfigurationProperties implements Provisionable { @Nullable public abstract String provisioningState(); @@ -37,9 +41,18 @@ public abstract class IpConfigurationProperties { @Nullable public abstract IdReference publicIPAddress(); + + @Nullable + public abstract List loadBalancerBackendAddressPools(); + + @Nullable + public abstract List loadBalancerInboundNatRules(); - @SerializedNames({"provisioningState", "privateIPAddress", "privateIPAllocationMethod", "subnet", "publicIPAddress"}) - public static IpConfigurationProperties create(final String provisioningState, final String privateIPAddress, final String privateIPAllocationMethod, final IdReference subnet, final IdReference publicIPAddress) { + @SerializedNames({ "provisioningState", "privateIPAddress", "privateIPAllocationMethod", "subnet", + "publicIPAddress", "loadBalancerBackendAddressPools", "loadBalancerInboundNatRules" }) + public static IpConfigurationProperties create(final String provisioningState, final String privateIPAddress, + final String privateIPAllocationMethod, final IdReference subnet, final IdReference publicIPAddress, + List loadBalancerBackendAddressPools, List loadBalancerInboundNatRules) { return builder() .provisioningState(provisioningState) @@ -47,8 +60,12 @@ public abstract class IpConfigurationProperties { .privateIPAllocationMethod(privateIPAllocationMethod) .subnet(subnet) .publicIPAddress(publicIPAddress) + .loadBalancerBackendAddressPools(loadBalancerBackendAddressPools) + .loadBalancerInboundNatRules(loadBalancerInboundNatRules) .build(); } + + public abstract Builder toBuilder(); public static Builder builder() { return new AutoValue_IpConfigurationProperties.Builder(); @@ -65,8 +82,24 @@ public abstract class IpConfigurationProperties { public abstract Builder subnet(IdReference subnet); public abstract Builder publicIPAddress(IdReference publicIPAddress); + + public abstract Builder loadBalancerBackendAddressPools(List loadBalancerBackendAddressPools); + + public abstract Builder loadBalancerInboundNatRules(List loadBalancerInboundNatRules); + + abstract List loadBalancerBackendAddressPools(); + + abstract List loadBalancerInboundNatRules(); + + abstract IpConfigurationProperties autoBuild(); - public abstract IpConfigurationProperties build(); + public IpConfigurationProperties build() { + loadBalancerBackendAddressPools(loadBalancerBackendAddressPools() != null ? ImmutableList + .copyOf(loadBalancerBackendAddressPools()) : null); + loadBalancerInboundNatRules(loadBalancerInboundNatRules() != null ? ImmutableList + .copyOf(loadBalancerInboundNatRules()) : null); + return autoBuild(); + } } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/LoadBalancer.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/LoadBalancer.java new file mode 100644 index 0000000000..d313e36a82 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/LoadBalancer.java @@ -0,0 +1,50 @@ +/* + * 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 java.util.Map; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableMap; + +@AutoValue +public abstract class LoadBalancer { + @Nullable + public abstract String name(); + + @Nullable + public abstract String location(); + + @Nullable + public abstract Map tags(); + + @Nullable + public abstract LoadBalancerProperties properties(); + + @Nullable + public abstract String etag(); + + @SerializedNames({ "name", "location", "tags", "properties", "etag" }) + public static LoadBalancer create(final String name, final String location, final Map tags, + final LoadBalancerProperties properties, final String etag) { + return new AutoValue_LoadBalancer(name, location, tags == null ? null : ImmutableMap.copyOf(tags), properties, + etag); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/LoadBalancerProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/LoadBalancerProperties.java new file mode 100644 index 0000000000..b8ab72337f --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/LoadBalancerProperties.java @@ -0,0 +1,109 @@ +/* + * 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 java.util.List; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; + +@AutoValue +public abstract class LoadBalancerProperties implements Provisionable { + + @Nullable + public abstract List frontendIPConfigurations(); + + @Nullable + public abstract List backendAddressPools(); + + @Nullable + public abstract List loadBalancingRules(); + + @Nullable + public abstract List probes(); + + @Nullable + public abstract List inboundNatRules(); + + @Nullable + public abstract String resourceGuid(); + + @Nullable + public abstract String provisioningState(); + + @SerializedNames({ "frontendIPConfigurations", "backendAddressPools", "loadBalancingRules", "probes", + "inboundNatRules", "resourceGuid", "provisioningState" }) + public static LoadBalancerProperties create(final List frontendIPConfigurations, + final List backendAddressPools, final List loadBalancingRules, + final List probes, final List inboundNatRules, final String resourceGuid, + final String provisioningState) { + return builder().frontendIPConfigurations(frontendIPConfigurations) + .backendAddressPools(backendAddressPools == null ? null : ImmutableList.copyOf(backendAddressPools)) + .loadBalancingRules(loadBalancingRules == null ? null : ImmutableList.copyOf(loadBalancingRules)) + .probes(probes == null ? null : ImmutableList.copyOf(probes)) + .inboundNatRules(inboundNatRules == null ? null : ImmutableList.copyOf(inboundNatRules)) + .resourceGuid(resourceGuid).provisioningState(provisioningState).build(); + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_LoadBalancerProperties.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder frontendIPConfigurations(List frontendIPConfigurations); + + public abstract Builder backendAddressPools(List backendAddressPools); + + public abstract Builder loadBalancingRules(List networkInterfaces); + + public abstract Builder probes(List probes); + + public abstract Builder inboundNatRules(List inboundNatRules); + + public abstract Builder resourceGuid(String resourceGuid); + + public abstract Builder provisioningState(String provisioningState); + + abstract List frontendIPConfigurations(); + + abstract List backendAddressPools(); + + abstract List loadBalancingRules(); + + abstract List probes(); + + abstract List inboundNatRules(); + + abstract LoadBalancerProperties autoBuild(); + + public LoadBalancerProperties build() { + frontendIPConfigurations(frontendIPConfigurations() != null ? ImmutableList.copyOf(frontendIPConfigurations()) + : null); + backendAddressPools(backendAddressPools() != null ? ImmutableList.copyOf(backendAddressPools()) : null); + loadBalancingRules(loadBalancingRules() != null ? ImmutableList.copyOf(loadBalancingRules()) : null); + probes(probes() != null ? ImmutableList.copyOf(probes()) : null); + inboundNatRules(inboundNatRules() != null ? ImmutableList.copyOf(inboundNatRules()) : null); + return autoBuild(); + } + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/LoadBalancingRule.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/LoadBalancingRule.java new file mode 100644 index 0000000000..ecc97ddb77 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/LoadBalancingRule.java @@ -0,0 +1,43 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class LoadBalancingRule { + @Nullable + public abstract String name(); + + @Nullable + public abstract String id(); + + @Nullable + public abstract LoadBalancingRuleProperties properties(); + + @Nullable + public abstract String etag(); + + @SerializedNames({ "name", "id", "properties", "etag" }) + public static LoadBalancingRule create(final String name, final String id, + final LoadBalancingRuleProperties properties, final String etag) { + return new AutoValue_LoadBalancingRule(name, id, properties, etag); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/LoadBalancingRuleProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/LoadBalancingRuleProperties.java new file mode 100644 index 0000000000..ca90a156bb --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/LoadBalancingRuleProperties.java @@ -0,0 +1,135 @@ +/* + * 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 org.jclouds.azurecompute.arm.util.GetEnumValue; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class LoadBalancingRuleProperties { + + public enum Protocol { + Tcp("Tcp"), Udp("Udp"), UNRECOGNIZED("Unrecognized"); + + private final String label; + + private Protocol(final String label) { + this.label = label; + } + + public static Protocol fromValue(final String text) { + return (Protocol) GetEnumValue.fromValueOrDefault(text, Protocol.UNRECOGNIZED); + } + + @Override + public String toString() { + return label; + } + } + + public enum LoadDistribution { + Default("Default"), SourceIp("SourceIP"), SourceIPProtocol("SourceIPProtocol"), UNRECOGNIZED("Unrecognized"); + + private final String label; + + private LoadDistribution(final String label) { + this.label = label; + } + + public static LoadDistribution fromValue(final String text) { + return (LoadDistribution) GetEnumValue.fromValueOrDefault(text, LoadDistribution.UNRECOGNIZED); + } + + @Override + public String toString() { + return label; + } + } + + @Nullable + public abstract IdReference frontendIPConfiguration(); + + @Nullable + public abstract IdReference backendAddressPool(); + + public abstract Protocol protocol(); + + public abstract int frontendPort(); + + public abstract int backendPort(); + + @Nullable + public abstract IdReference probe(); + + @Nullable + public abstract Boolean enableFloatingIP(); + + @Nullable + public abstract Integer idleTimeoutInMinutes(); + + @Nullable + public abstract LoadDistribution loadDistribution(); + + @Nullable + public abstract String provisioningState(); + + @SerializedNames({ "frontendIPConfiguration", "backendAddressPool", "protocol", "frontendPort", "backendPort", + "probe", "enableFloatingIP", "idleTimeoutInMinutes", "loadDistribution", "provisioningState" }) + public static LoadBalancingRuleProperties create(final IdReference frontendIPConfiguration, + final IdReference backendAddressPool, final Protocol protocol, final int frontendPort, final int backendPort, + final IdReference probe, final Boolean enableFloatingIP, final Integer idleTimeoutInMinutes, + final LoadDistribution loadDistribution, final String provisioningState) { + return builder().frontendIPConfiguration(frontendIPConfiguration).backendAddressPool(backendAddressPool) + .protocol(protocol).frontendPort(frontendPort).backendPort(backendPort).probe(probe) + .enableFloatingIP(enableFloatingIP).idleTimeoutInMinutes(idleTimeoutInMinutes) + .loadDistribution(loadDistribution).build(); + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_LoadBalancingRuleProperties.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder frontendIPConfiguration(IdReference frontendIPConfiguration); + + public abstract Builder backendAddressPool(IdReference backendAddressPool); + + public abstract Builder protocol(Protocol protocol); + + public abstract Builder frontendPort(int frontendPort); + + public abstract Builder backendPort(int backendPort); + + public abstract Builder probe(IdReference probe); + + public abstract Builder enableFloatingIP(Boolean enableFloatingIP); + + public abstract Builder idleTimeoutInMinutes(Integer idleTimeoutInMinutes); + + public abstract Builder loadDistribution(LoadDistribution loadDistribution); + + public abstract Builder provisioningState(String provisioningState); + + public abstract LoadBalancingRuleProperties build(); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCardProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCardProperties.java index 8b19493dd0..d1976f1747 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCardProperties.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCardProperties.java @@ -24,7 +24,7 @@ import org.jclouds.json.SerializedNames; import java.util.List; @AutoValue -public abstract class NetworkInterfaceCardProperties { +public abstract class NetworkInterfaceCardProperties implements Provisionable { @Nullable public abstract String provisioningState(); @@ -52,6 +52,8 @@ public abstract class NetworkInterfaceCardProperties { return builder.build(); } + + public abstract Builder toBuilder(); public static Builder builder() { diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkProfile.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkProfile.java index ffcf9ee405..b26305f5f5 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkProfile.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkProfile.java @@ -18,6 +18,7 @@ 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; @@ -34,6 +35,8 @@ public abstract class NetworkProfile { public static NetworkProfile create(final List networkInterfaces) { return builder().networkInterfaces(networkInterfaces).build(); } + + public abstract Builder toBuilder(); public static Builder builder() { return new AutoValue_NetworkProfile.Builder(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityGroupProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityGroupProperties.java index f81ab0f835..bbc27460e4 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityGroupProperties.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityGroupProperties.java @@ -17,6 +17,7 @@ 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.common.collect.ImmutableList; @@ -24,7 +25,7 @@ import com.google.common.collect.ImmutableList; import java.util.List; @AutoValue -public abstract class NetworkSecurityGroupProperties { +public abstract class NetworkSecurityGroupProperties implements Provisionable { @Nullable public abstract List securityRules(); @@ -60,6 +61,8 @@ public abstract class NetworkSecurityGroupProperties { .provisioningState(provisioningState) .build(); } + + public abstract Builder toBuilder(); public static Builder builder() { return new AutoValue_NetworkSecurityGroupProperties.Builder(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityRuleProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityRuleProperties.java index 071050382f..e93107e92e 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityRuleProperties.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityRuleProperties.java @@ -17,6 +17,7 @@ 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; @@ -112,6 +113,8 @@ public abstract class NetworkSecurityRuleProperties { .direction(direction) .build(); } + + public abstract Builder toBuilder(); public static Builder builder() { return new AutoValue_NetworkSecurityRuleProperties.Builder(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java index 0be43bfc40..9cdee448ec 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java @@ -17,6 +17,7 @@ package org.jclouds.azurecompute.arm.domain; import com.google.auto.value.AutoValue; + import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; @@ -70,6 +71,8 @@ public abstract class OSDisk { .image(image) .build(); } + + public abstract Builder toBuilder(); public static Builder builder() { return new AutoValue_OSDisk.Builder(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSProfile.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSProfile.java index 9240824cf1..5592b4c389 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSProfile.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSProfile.java @@ -18,6 +18,7 @@ package org.jclouds.azurecompute.arm.domain; import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; + import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; @@ -212,6 +213,8 @@ public abstract class OSProfile { .windowsConfiguration(windowsConfiguration) .build(); } + + public abstract Builder toBuilder(); public static Builder builder() { return new AutoValue_OSProfile.Builder(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/AvailabilitySetVirtualMachine.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Probe.java similarity index 66% rename from providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/AvailabilitySetVirtualMachine.java rename to providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Probe.java index 3837ff2ec6..e523984dcc 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/AvailabilitySetVirtualMachine.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Probe.java @@ -16,22 +16,27 @@ */ package org.jclouds.azurecompute.arm.domain; -import com.google.auto.value.AutoValue; +import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; -/** - * The virtual machine id - */ -@AutoValue -public abstract class AvailabilitySetVirtualMachine { +import com.google.auto.value.AutoValue; - /** - * The id of the virtual machine. - */ +@AutoValue +public abstract class Probe { + @Nullable + public abstract String name(); + + @Nullable public abstract String id(); - @SerializedNames({"id"}) - public static AvailabilitySetVirtualMachine create(final String id) { - return new AutoValue_AvailabilitySetVirtualMachine(id); + @Nullable + public abstract ProbeProperties properties(); + + @Nullable + public abstract String etag(); + + @SerializedNames({ "name", "id", "properties", "etag" }) + public static Probe create(final String name, final String id, final ProbeProperties properties, final String etag) { + return new AutoValue_Probe(name, id, properties, etag); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ProbeProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ProbeProperties.java new file mode 100644 index 0000000000..6fe273e5bb --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ProbeProperties.java @@ -0,0 +1,91 @@ +/* + * 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 org.jclouds.azurecompute.arm.util.GetEnumValue; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class ProbeProperties implements Provisionable { + public enum Protocol { + Tcp("Tcp"), Http("Http"), UNRECOGNIZED("Unrecognized"); + + private final String label; + + private Protocol(final String label) { + this.label = label; + } + + public static Protocol fromValue(final String text) { + return (Protocol) GetEnumValue.fromValueOrDefault(text, Protocol.UNRECOGNIZED); + } + + @Override + public String toString() { + return label; + } + } + + @Nullable + public abstract Protocol protocol(); + + public abstract int port(); + + @Nullable + public abstract String requestPath(); + + public abstract int intervalInSeconds(); + + public abstract int numberOfProbes(); + + @Nullable + public abstract String provisioningState(); + + @SerializedNames({ "protocol", "port", "requestPath", "intervalInSeconds", "numberOfProbes", "provisioningState" }) + public static ProbeProperties create(final Protocol protocol, final int port, final String requestPath, + final int intervalInSeconds, final int numberOfProbes, final String provisioningState) { + return builder().protocol(protocol).port(port).requestPath(requestPath).intervalInSeconds(intervalInSeconds) + .numberOfProbes(numberOfProbes).provisioningState(provisioningState).build(); + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_ProbeProperties.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + + public abstract Builder protocol(Protocol protocol); + + public abstract Builder port(int port); + + public abstract Builder requestPath(String requestPath); + + public abstract Builder intervalInSeconds(int intervalInSeconds); + + public abstract Builder numberOfProbes(int numberOfProbes); + + public abstract Builder provisioningState(String provisioningState); + + public abstract ProbeProperties build(); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Provisionable.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Provisionable.java new file mode 100644 index 0000000000..f400e9338f --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Provisionable.java @@ -0,0 +1,22 @@ +/* + * 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; + +public interface Provisionable { + + String provisioningState(); +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/PublicIPAddressProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/PublicIPAddressProperties.java index 2fc7fb5d47..af7da0d5ec 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/PublicIPAddressProperties.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/PublicIPAddressProperties.java @@ -17,11 +17,12 @@ package org.jclouds.azurecompute.arm.domain; import com.google.auto.value.AutoValue; + import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; @AutoValue -public abstract class PublicIPAddressProperties { +public abstract class PublicIPAddressProperties implements Provisionable { @Nullable // needs to be nullable to create the payload for create request public abstract String provisioningState(); @@ -58,6 +59,8 @@ public abstract class PublicIPAddressProperties { .dnsSettings(dnsSettings) .build(); } + + public abstract Builder toBuilder(); public static Builder builder() { return new AutoValue_PublicIPAddressProperties.Builder(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceDefinition.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceDefinition.java index 7c68e8007c..1b51375f08 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceDefinition.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceDefinition.java @@ -20,6 +20,7 @@ package org.jclouds.azurecompute.arm.domain; import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; + import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; @@ -67,6 +68,8 @@ public abstract class ResourceDefinition { return builder.build(); } + + public abstract Builder toBuilder(); public static Builder builder() { return new AutoValue_ResourceDefinition.Builder(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceGroup.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceGroup.java index 936b813a89..51bea9e2c9 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceGroup.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceGroup.java @@ -27,7 +27,7 @@ import com.google.common.collect.ImmutableMap; public abstract class ResourceGroup { @AutoValue - public abstract static class ResourceGroupProperties{ + public abstract static class ResourceGroupProperties implements Provisionable { @Nullable public abstract String provisioningState(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceProviderMetaData.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceProviderMetaData.java index 84526b9456..e919f02e6f 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceProviderMetaData.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ResourceProviderMetaData.java @@ -18,6 +18,7 @@ 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; @@ -40,6 +41,8 @@ public abstract class ResourceProviderMetaData { return builder.build(); } + + public abstract Builder toBuilder(); public static Builder builder() { return new AutoValue_ResourceProviderMetaData.Builder(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Status.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Status.java new file mode 100644 index 0000000000..780877be7c --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Status.java @@ -0,0 +1,49 @@ +/* + * 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 java.util.Date; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class Status { + + @Nullable + public abstract String code(); + + @Nullable + public abstract String level(); + + @Nullable + public abstract String displayStatus(); + + @Nullable + public abstract String message(); + + @Nullable + public abstract Date time(); + + @SerializedNames({ "code", "level", "displayStatus", "message", "time" }) + public static Status create(final String code, final String level, final String displayStatus, final String message, + final Date time) { + return new AutoValue_Status(code, level, displayStatus, message, time); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageProfile.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageProfile.java index bcb62ee217..a65ffd7538 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageProfile.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageProfile.java @@ -18,6 +18,7 @@ package org.jclouds.azurecompute.arm.domain; import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; + import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; @@ -53,6 +54,8 @@ public abstract class StorageProfile { return builder.build(); } + + public abstract Builder toBuilder(); public static Builder builder() { return new AutoValue_StorageProfile.Builder(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageService.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageService.java index a97117fd33..0f5dbe5a6f 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageService.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageService.java @@ -22,7 +22,6 @@ import java.util.Map; import com.google.common.collect.ImmutableMap; import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; - import org.jclouds.azurecompute.arm.util.GetEnumValue; @AutoValue @@ -150,6 +149,9 @@ public abstract class StorageService { return builder.build(); } + + public abstract Builder toBuilder(); + public static Builder builder() { return new AutoValue_StorageService_StorageServiceProperties.Builder(); } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Subnet.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Subnet.java index e4024df93a..6830438f94 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Subnet.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Subnet.java @@ -21,6 +21,7 @@ import static com.google.common.collect.ImmutableList.copyOf; import java.util.List; import com.google.common.collect.ImmutableList; + import org.jclouds.javax.annotation.Nullable; import com.google.auto.value.AutoValue; import org.jclouds.json.SerializedNames; @@ -40,7 +41,7 @@ public abstract class Subnet { } @AutoValue - public abstract static class SubnetProperties { + public abstract static class SubnetProperties implements Provisionable { @Nullable public abstract String provisioningState(); @@ -59,6 +60,8 @@ public abstract class Subnet { .ipConfigurations(ipConfigurations != null ? copyOf(ipConfigurations) : null) .build(); } + + public abstract Builder toBuilder(); public static Builder builder() { return new AutoValue_Subnet_SubnetProperties.Builder(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VHD.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VHD.java index 3b1421a3af..7e6b387576 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VHD.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VHD.java @@ -17,6 +17,7 @@ package org.jclouds.azurecompute.arm.domain; import com.google.auto.value.AutoValue; + import org.jclouds.json.SerializedNames; @AutoValue @@ -31,6 +32,8 @@ public abstract class VHD { public static VHD create(final String uri) { return builder().uri(uri).build(); } + + public abstract Builder toBuilder(); public static Builder builder() { return new AutoValue_VHD.Builder(); 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 b08355e9c1..04863ad9bd 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 @@ -111,6 +111,8 @@ public abstract class VMImage { return new AutoValue_VMImage.Builder().globallyAvailable(false).custom(true); } + public abstract Builder toBuilder(); + @AutoValue.Builder public abstract static class Builder { 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 65a389ce26..86810e55ad 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 @@ -74,6 +74,8 @@ public abstract class VirtualMachine { .build(); } + public abstract Builder toBuilder(); + public static Builder builder() { return new AutoValue_VirtualMachine.Builder(); } 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 1c11e4d0f3..66ef2833e1 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 @@ -21,10 +21,8 @@ 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; @@ -40,42 +38,19 @@ import com.google.common.collect.ImmutableList; @AutoValue public abstract class VirtualMachineInstance { - @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 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(); - - @Nullable - public abstract String level(); - - @Nullable - public abstract String displayStatus(); - - @Nullable - public abstract Date time(); - - @SerializedNames({"code", "level", "displayStatus", "time"}) - public static VirtualMachineStatus create(final String code, final String level, final String displayStatus, - final Date time) { - - return new AutoValue_VirtualMachineInstance_VirtualMachineStatus(code, level, displayStatus, time); + public static PowerState fromValue(final String text) { + return (PowerState) GetEnumValue.fromValueOrDefault(text, PowerState.UNRECOGNIZED); } } - + @Nullable public abstract String platformUpdateDomain(); @@ -83,19 +58,19 @@ public abstract class VirtualMachineInstance { public abstract String platformFaultDomain(); @Nullable - public abstract List statuses(); + public abstract List statuses(); public ProvisioningState provisioningState() { - return ProvisioningState.fromValue(firstStatus(VirtualMachineStatus.PROVISIONING_STATE_PREFIX)); + return ProvisioningState.fromValue(firstStatus(PROVISIONING_STATE_PREFIX)); } public PowerState powerState() { - return PowerState.fromValue(firstStatus(VirtualMachineStatus.POWER_STATE_PREFIX)); + return PowerState.fromValue(firstStatus(POWER_STATE_PREFIX)); } private String firstStatus(final String type) { - return getFirst(transform(filter(transform(statuses(), new Function() { - @Override public String apply(VirtualMachineStatus input) { + return getFirst(transform(filter(transform(statuses(), new Function() { + @Override public String apply(Status input) { return input.code(); } }), startsWith(type)), new Function() { @@ -108,7 +83,7 @@ public abstract class VirtualMachineInstance { @SerializedNames({"platformUpdateDomain", "platformFaultDomain", "statuses"}) public static VirtualMachineInstance create(final String platformUpdateDomain, final String platformFaultDomain, - final List statuses) { + final List statuses) { return new AutoValue_VirtualMachineInstance(platformUpdateDomain, platformFaultDomain, statuses == null ? null : ImmutableList.copyOf(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 eb9520aa33..732da5ce0b 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 @@ -61,7 +61,7 @@ public abstract class VirtualMachineProperties { * The availability set of the virtual machine */ @Nullable - public abstract AvailabilitySet availabilitySet(); + public abstract IdReference availabilitySet(); /** * The hardware Profile of the virtual machine . @@ -103,7 +103,7 @@ public abstract class VirtualMachineProperties { "networkProfile", "diagnosticsProfile", "provisioningState"}) public static VirtualMachineProperties create(final String vmId, final String licenseType, - final AvailabilitySet availabilitySet, + final IdReference availabilitySet, final HardwareProfile hardwareProfile, final StorageProfile storageProfile, final OSProfile osProfile, @@ -122,6 +122,8 @@ public abstract class VirtualMachineProperties { .provisioningState(provisioningState) .build(); } + + public abstract Builder toBuilder(); public static Builder builder() { return new AutoValue_VirtualMachineProperties.Builder(); @@ -133,7 +135,7 @@ public abstract class VirtualMachineProperties { public abstract Builder licenseType(String licenseType); - public abstract Builder availabilitySet(AvailabilitySet availabilitySet); + public abstract Builder availabilitySet(IdReference availabilitySet); public abstract Builder hardwareProfile(HardwareProfile hardwareProfile); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualNetwork.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualNetwork.java index d5eddf03e4..a0f5c3e118 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualNetwork.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualNetwork.java @@ -24,6 +24,7 @@ import com.google.common.collect.ImmutableList; import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableMap; + import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; @@ -42,7 +43,7 @@ public abstract class VirtualNetwork { } @AutoValue - public abstract static class VirtualNetworkProperties { + public abstract static class VirtualNetworkProperties implements Provisionable { @Nullable public abstract String provisioningState(); @@ -65,6 +66,8 @@ public abstract class VirtualNetwork { .subnets(subnets != null ? copyOf(subnets) : null) .build(); } + + public abstract Builder toBuilder(); public static Builder builder() { return new AutoValue_VirtualNetwork_VirtualNetworkProperties.Builder(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApi.java new file mode 100644 index 0000000000..30456d47c9 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApi.java @@ -0,0 +1,83 @@ +/* + * 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.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.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.AvailabilitySet; +import org.jclouds.azurecompute.arm.domain.AvailabilitySet.AvailabilitySetProperties; +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.Compute/availabilitySets") +@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) +@Consumes(MediaType.APPLICATION_JSON) +public interface AvailabilitySetApi extends Closeable { + + @Named("availabilityset:list") + @GET + @SelectJson("value") + @Fallback(EmptyListOnNotFoundOr404.class) + List list(); + + @Named("availabilityset:get") + @Path("/{name}") + @GET + @Fallback(NullOnNotFoundOr404.class) + AvailabilitySet get(@PathParam("name") String name); + + @Named("availabilityset:createOrUpdate") + @Path("/{name}") + @PUT + @MapBinder(BindToJsonPayload.class) + @Produces(MediaType.APPLICATION_JSON) + AvailabilitySet createOrUpdate(@PathParam("name") String name, + @PayloadParam("location") String location, @Nullable @PayloadParam("tags") Map tags, + @PayloadParam("properties") AvailabilitySetProperties properties); + + @Named("availabilityset:delete") + @Path("/{name}") + @DELETE + @ResponseParser(URIParser.class) + @Fallback(NullOnNotFoundOr404.class) + URI delete(@PathParam("name") String name); + +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/LoadBalancerApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/LoadBalancerApi.java new file mode 100644 index 0000000000..f0ea900f9f --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/LoadBalancerApi.java @@ -0,0 +1,82 @@ +/* + * 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 java.util.List; +import java.util.Map; + +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.LoadBalancer; +import org.jclouds.azurecompute.arm.domain.LoadBalancerProperties; +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/loadBalancers") +@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) +@Consumes(MediaType.APPLICATION_JSON) +public interface LoadBalancerApi { + + @Named("loadbalancer:list") + @GET + @SelectJson("value") + @Fallback(EmptyListOnNotFoundOr404.class) + List list(); + + @Named("loadbalancer:get") + @Path("/{loadbalancername}") + @GET + @Fallback(NullOnNotFoundOr404.class) + LoadBalancer get(@PathParam("loadbalancername") String lbName); + + @Named("loadbalancer:createOrUpdate") + @Path("/{loadbalancername}") + @PUT + @MapBinder(BindToJsonPayload.class) + @Produces(MediaType.APPLICATION_JSON) + LoadBalancer createOrUpdate(@PathParam("loadbalancername") String lbName, + @PayloadParam("location") String location, @Nullable @PayloadParam("tags") Map tags, + @PayloadParam("properties") LoadBalancerProperties properties); + + @Named("loadbalancer:delete") + @Path("/{loadbalancername}") + @DELETE + @ResponseParser(URIParser.class) + @Fallback(NullOnNotFoundOr404.class) + URI delete(@PathParam("loadbalancername") String lbName); + +} 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 c135e9ebe2..5d2773f67a 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 @@ -35,6 +35,7 @@ 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.javax.annotation.Nullable; import org.jclouds.oauth.v2.filters.OAuthFilter; import org.jclouds.rest.annotations.Fallback; import org.jclouds.rest.annotations.MapBinder; @@ -60,9 +61,9 @@ public interface NetworkInterfaceCardApi { @MapBinder(BindToJsonPayload.class) @PUT NetworkInterfaceCard createOrUpdate(@PathParam("networkinterfacecardname") String networkinterfacecardname, - @PayloadParam("location") String location, - @PayloadParam("properties") NetworkInterfaceCardProperties properties, - @PayloadParam("tags") Map tags); + @PayloadParam("location") String location, + @PayloadParam("properties") NetworkInterfaceCardProperties properties, + @Nullable @PayloadParam("tags") Map tags); @Named("networkinterfacecard:get") @Path("/{networkinterfacecardname}") 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 784f007fda..9c2427c2bf 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 @@ -20,7 +20,9 @@ import static org.jclouds.compute.options.TemplateOptions.Builder.authorizePubli import java.util.Properties; +import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; +import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.TemplateBuilder; @@ -33,9 +35,13 @@ import org.jclouds.scriptbuilder.domain.Statements; import org.jclouds.scriptbuilder.statements.java.InstallJDK; import org.jclouds.scriptbuilder.statements.login.AdminAccess; import org.jclouds.sshj.config.SshjSshClientModule; +import org.testng.annotations.AfterClass; import org.testng.annotations.Test; +import com.google.common.cache.LoadingCache; +import com.google.inject.Key; import com.google.inject.Module; +import com.google.inject.TypeLiteral; /** * Live tests for the {@link org.jclouds.compute.ComputeService} integration. @@ -43,10 +49,36 @@ import com.google.inject.Module; @Test(groups = "live", singleThreaded = true, testName = "AzureComputeServiceLiveTest") public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest { + private LoadingCache resourceGroupMap; + public AzureComputeServiceLiveTest() { provider = "azurecompute-arm"; } + @Override + public void initializeContext() { + super.initializeContext(); + resourceGroupMap = context.utils().injector() + .getInstance(Key.get(new TypeLiteral>() { + })); + } + + @Override + @AfterClass(groups = "live", alwaysRun = true) + protected void tearDownContext() { + try { + if (template != null) { + ResourceGroup rg = resourceGroupMap.getIfPresent(template.getLocation().getId()); + if (rg != null) { + AzureComputeApi api = view.unwrapApi(AzureComputeApi.class); + api.getResourceGroupApi().delete(rg.name()); + } + } + } finally { + super.tearDownContext(); + } + } + @Override protected LoggingModule getLoggingModule() { return new SLF4JLoggingModule(); 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 8939eb13d6..a6d19fabf1 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 @@ -21,16 +21,23 @@ import static org.jclouds.compute.options.TemplateOptions.Builder.authorizePubli import java.util.Map; import java.util.Properties; +import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; +import org.jclouds.azurecompute.arm.domain.ResourceGroup; 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.domain.Location; import org.jclouds.providers.ProviderMetadata; import org.jclouds.sshj.config.SshjSshClientModule; +import org.testng.annotations.AfterClass; import org.testng.annotations.Test; +import com.google.common.cache.LoadingCache; +import com.google.inject.Key; import com.google.inject.Module; +import com.google.inject.TypeLiteral; /** * Live tests for the {@link org.jclouds.compute.extensions.ImageExtension} @@ -38,12 +45,37 @@ import com.google.inject.Module; */ @Test(groups = "live", singleThreaded = true, testName = "AzureComputeImageExtensionLiveTest") public class AzureComputeImageExtensionLiveTest extends BaseImageExtensionLiveTest { + + public static final String NAME_PREFIX = "%s"; + + private LoadingCache resourceGroupMap; public AzureComputeImageExtensionLiveTest() { provider = "azurecompute-arm"; } - public static String NAME_PREFIX = "%s"; + @Override + public void initializeContext() { + super.initializeContext(); + resourceGroupMap = context.utils().injector() + .getInstance(Key.get(new TypeLiteral>() { + })); + } + + @Override + @AfterClass(groups = "live", alwaysRun = true) + protected void tearDownContext() { + try { + Location location = getNodeTemplate().build().getLocation(); + ResourceGroup rg = resourceGroupMap.getIfPresent(location.getId()); + if (rg != null) { + AzureComputeApi api = view.unwrapApi(AzureComputeApi.class); + api.getResourceGroupApi().delete(rg.name()); + } + } finally { + super.tearDownContext(); + } + } @Override protected Module getSshModule() { diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java index cb13c7b1de..2aa012ac7a 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java @@ -29,8 +29,8 @@ import java.util.Properties; import java.util.Set; import java.util.concurrent.ExecutionException; +import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; -import org.jclouds.azurecompute.arm.compute.strategy.CleanupResources; import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; import org.jclouds.compute.ComputeService; @@ -60,7 +60,6 @@ public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGrou private LoadingCache resourceGroupMap; private ResourceGroup testResourceGroup; - private CleanupResources cleanupResources; public AzureComputeSecurityGroupExtensionLiveTest() { provider = "azurecompute-arm"; @@ -72,8 +71,7 @@ public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGrou resourceGroupMap = context.utils().injector() .getInstance(Key.get(new TypeLiteral>() { })); - cleanupResources = context.utils().injector().getInstance(CleanupResources.class); - createResourceGroupIfMissing(); + createResourceGroup(); } @Test(groups = { "integration", "live" }, dependsOnMethods = "testCreateSecurityGroup") @@ -118,8 +116,11 @@ public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGrou @AfterClass(groups = { "integration", "live" }) @Override protected void tearDownContext() { - super.tearDownContext(); - cleanupResources.deleteResourceGroupIfEmpty(testResourceGroup.name()); + try { + view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().delete(testResourceGroup.name()); + } finally { + super.tearDownContext(); + } } @Override @@ -135,7 +136,7 @@ public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGrou return AzureComputeProviderMetadata.builder().build(); } - private void createResourceGroupIfMissing() { + private void createResourceGroup() { Location location = getNodeTemplate().getLocation(); testResourceGroup = resourceGroupMap.getUnchecked(location.getId()); } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApiLiveTest.java new file mode 100644 index 0000000000..6e9e1e7a70 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApiLiveTest.java @@ -0,0 +1,100 @@ +/* + * 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 static com.google.common.collect.Iterables.any; +import static org.testng.Assert.assertEquals; +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.UUID; + +import org.jclouds.azurecompute.arm.domain.AvailabilitySet; +import org.jclouds.azurecompute.arm.domain.AvailabilitySet.AvailabilitySetProperties; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableMap; + +@Test(groups = "live", testName = "AvailabilitySetApiLiveTest", singleThreaded = true) +public class AvailabilitySetApiLiveTest extends BaseAzureComputeApiLiveTest { + + private String asName; + + @BeforeClass + @Override + public void setup() { + super.setup(); + createTestResourceGroup(); + asName = "jclouds-" + RAND; + } + + @Test + public void deleteAvailabilitySetDoesNotExist() { + assertNull(api().delete(UUID.randomUUID().toString())); + } + + @Test + public void createAvailabilitySet() { + AvailabilitySetProperties props = AvailabilitySetProperties.builder().platformUpdateDomainCount(2) + .platformFaultDomainCount(3).build(); + AvailabilitySet as = api().createOrUpdate(asName, LOCATION, null, props); + + assertNotNull(as); + assertEquals(as.name(), asName); + } + + @Test(dependsOnMethods = "createAvailabilitySet") + public void getAvailabilitySet() { + assertNotNull(api().get(asName)); + } + + @Test(dependsOnMethods = "createAvailabilitySet") + public void listAvailabilitySet() { + assertTrue(any(api().list(), new Predicate() { + @Override + public boolean apply(AvailabilitySet input) { + return asName.equals(input.name()); + } + })); + } + + @Test(dependsOnMethods = "createAvailabilitySet") + public void updateAvailabilitySet() { + AvailabilitySet as = api().get(asName); + as = api().createOrUpdate(asName, LOCATION, ImmutableMap.of("foo", "bar"), as.properties()); + + assertNotNull(as); + assertTrue(as.tags().containsKey("foo")); + assertEquals(as.tags().get("foo"), "bar"); + } + + @Test(dependsOnMethods = { "getAvailabilitySet", "listAvailabilitySet", "updateAvailabilitySet" }) + public void deleteAvailabilitySet() { + URI uri = api().delete(asName); + assertResourceDeleted(uri); + } + + private AvailabilitySetApi api() { + return api.getAvailabilitySetApi(resourceGroupName); + } + +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApiMockTest.java new file mode 100644 index 0000000000..db9a7edfe9 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApiMockTest.java @@ -0,0 +1,153 @@ +/* + * 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 static com.google.common.collect.Iterables.isEmpty; +import static org.testng.Assert.assertEquals; +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.domain.AvailabilitySet; +import org.jclouds.azurecompute.arm.domain.AvailabilitySet.AvailabilitySetProperties; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; +import org.testng.annotations.Test; + +@Test(groups = "unit", testName = "AvailabilitySetApiMockTest", singleThreaded = true) +public class AvailabilitySetApiMockTest extends BaseAzureComputeApiMockTest { + + private final String subscriptionid = "SUBSCRIPTIONID"; + private final String resourcegroup = "myresourcegroup"; + private final String asName = "myas"; + private final String apiVersion = "api-version=2016-03-30"; + + public void createAvailabilitySet() throws InterruptedException { + + server.enqueue(jsonResponse("/availabilitysetcreate.json").setResponseCode(200)); + + AvailabilitySetApi asApi = api.getAvailabilitySetApi(resourcegroup); + + AvailabilitySetProperties props = AvailabilitySetProperties.builder().platformUpdateDomainCount(2) + .platformFaultDomainCount(3).build(); + AvailabilitySet as = asApi.createOrUpdate(asName, "westeurope", null, props); + + String path = String.format( + "/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Compute/availabilitySets/%s?%s", subscriptionid, + resourcegroup, asName, apiVersion); + String json = "{\"location\":\"westeurope\",\"properties\":{\"platformUpdateDomainCount\":2,\"platformFaultDomainCount\":3}}"; + assertSent(server, "PUT", path, json); + + assertEquals(as.name(), asName); + assertEquals(as.properties().platformUpdateDomainCount(), 2); + assertEquals(as.properties().platformFaultDomainCount(), 3); + } + + public void getAvailabilitySet() throws InterruptedException { + + server.enqueue(jsonResponse("/availabilitysetget.json").setResponseCode(200)); + + AvailabilitySetApi asApi = api.getAvailabilitySetApi(resourcegroup); + + AvailabilitySet as = asApi.get(asName); + + String path = String.format( + "/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Compute/availabilitySets/%s?%s", subscriptionid, + resourcegroup, asName, apiVersion); + assertSent(server, "GET", path); + + assertEquals(as.name(), asName); + } + + public void getAvailabilitySet404() throws InterruptedException { + server.enqueue(response404()); + + AvailabilitySetApi asApi = api.getAvailabilitySetApi(resourcegroup); + + AvailabilitySet as = asApi.get(asName); + + String path = String.format( + "/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Compute/availabilitySets/%s?%s", subscriptionid, + resourcegroup, asName, apiVersion); + assertSent(server, "GET", path); + + assertNull(as); + } + + public void listAvailabilitySets() throws InterruptedException { + + server.enqueue(jsonResponse("/availabilitysetlist.json").setResponseCode(200)); + + AvailabilitySetApi asApi = api.getAvailabilitySetApi(resourcegroup); + + List asList = asApi.list(); + + String path = String.format( + "/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Compute/availabilitySets?%s", subscriptionid, + resourcegroup, apiVersion); + assertSent(server, "GET", path); + + assertTrue(asList.size() > 0); + } + + public void listAvailabilitySets404() throws InterruptedException { + server.enqueue(response404()); + + AvailabilitySetApi asApi = api.getAvailabilitySetApi(resourcegroup); + + List asList = asApi.list(); + + String path = String.format( + "/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Compute/availabilitySets?%s", subscriptionid, + resourcegroup, apiVersion); + assertSent(server, "GET", path); + + assertTrue(isEmpty(asList)); + } + + public void deleteAvailabilitySet() throws InterruptedException { + + server.enqueue(response202WithHeader()); + + AvailabilitySetApi asApi = api.getAvailabilitySetApi(resourcegroup); + + URI uri = asApi.delete(asName); + assertNotNull(uri); + + String path = String.format( + "/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Compute/availabilitySets/%s?%s", subscriptionid, + resourcegroup, asName, apiVersion); + assertSent(server, "DELETE", path); + } + + public void deleteSubnetResourceDoesNotExist() throws InterruptedException { + + server.enqueue(response204()); + + AvailabilitySetApi asApi = api.getAvailabilitySetApi(resourcegroup); + + URI uri = asApi.delete(asName); + assertNull(uri); + + String path = String.format( + "/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Compute/availabilitySets/%s?%s", subscriptionid, + resourcegroup, asName, apiVersion); + assertSent(server, "DELETE", path); + } +} 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 42116c2224..b485dc2ea8 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 @@ -31,7 +31,6 @@ import org.jclouds.azurecompute.arm.domain.VirtualNetwork; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; import org.jclouds.util.Predicates2; import org.testng.Assert; -import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -41,7 +40,6 @@ import com.google.common.net.UrlEscapers; @Test(testName = "DeploymentApiLiveTest", singleThreaded = true) public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest { - private String resourceGroupName; private String deploymentName; private String subnetId; @@ -52,8 +50,7 @@ public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest { @Override public void setup() { super.setup(); - resourceGroupName = String.format("rg-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); - assertNotNull(createResourceGroup(resourceGroupName)); + createTestResourceGroup(); deploymentName = "jc" + System.currentTimeMillis(); String virtualNetworkName = String.format("vn-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); String storageAccountName = String.format("st%s%s", System.getProperty("user.name"), RAND); @@ -77,14 +74,6 @@ public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest { subnetId = subnet.id(); } - @AfterClass - @Override - protected void tearDown() { - super.tearDown(); - URI uri = api.getResourceGroupApi().delete(resourceGroupName); - assertResourceDeleted(uri); - } - private String getPutBody(String template, String mode, String parameters) { String body = "{ " + "\"properties\" : " + diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java new file mode 100644 index 0000000000..69014a5d64 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java @@ -0,0 +1,460 @@ +/* + * 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 static org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions.Builder.availabilitySet; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.Iterables.any; +import static com.google.common.collect.Iterables.getLast; +import static com.google.common.collect.Iterables.transform; +import static com.google.common.collect.Lists.newArrayList; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; +import static org.jclouds.azurecompute.arm.domain.InboundNatRuleProperties.Protocol.Tcp; +import static org.jclouds.compute.predicates.NodePredicates.inGroup; +import static org.testng.Assert.assertEquals; +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.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.PublicIpAvailablePredicateFactory; +import org.jclouds.azurecompute.arm.domain.AvailabilitySet; +import org.jclouds.azurecompute.arm.domain.BackendAddressPool; +import org.jclouds.azurecompute.arm.domain.BackendAddressPoolProperties; +import org.jclouds.azurecompute.arm.domain.FrontendIPConfigurations; +import org.jclouds.azurecompute.arm.domain.FrontendIPConfigurationsProperties; +import org.jclouds.azurecompute.arm.domain.IdReference; +import org.jclouds.azurecompute.arm.domain.InboundNatRule; +import org.jclouds.azurecompute.arm.domain.InboundNatRuleProperties; +import org.jclouds.azurecompute.arm.domain.IpConfiguration; +import org.jclouds.azurecompute.arm.domain.IpConfigurationProperties; +import org.jclouds.azurecompute.arm.domain.LoadBalancer; +import org.jclouds.azurecompute.arm.domain.LoadBalancerProperties; +import org.jclouds.azurecompute.arm.domain.LoadBalancingRule; +import org.jclouds.azurecompute.arm.domain.LoadBalancingRuleProperties; +import org.jclouds.azurecompute.arm.domain.LoadBalancingRuleProperties.Protocol; +import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; +import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCardProperties; +import org.jclouds.azurecompute.arm.domain.Probe; +import org.jclouds.azurecompute.arm.domain.ProbeProperties; +import org.jclouds.azurecompute.arm.domain.Provisionable; +import org.jclouds.azurecompute.arm.domain.PublicIPAddress; +import org.jclouds.azurecompute.arm.domain.PublicIPAddressProperties; +import org.jclouds.azurecompute.arm.domain.RegionAndId; +import org.jclouds.azurecompute.arm.domain.ResourceGroup; +import org.jclouds.azurecompute.arm.domain.VirtualMachine; +import org.jclouds.azurecompute.arm.domain.AvailabilitySet.AvailabilitySetProperties; +import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; +import org.jclouds.compute.RunNodesException; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest; +import org.jclouds.domain.Location; +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.base.Splitter; +import com.google.common.base.Supplier; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.inject.Key; +import com.google.inject.TypeLiteral; +import com.google.inject.name.Names; + +// We extend the BaseComputeServiceContextLiveTest to create nodes using the abstraction, which is much easier +@Test(groups = "live", singleThreaded = true) +public class LoadBalancerApiLiveTest extends BaseComputeServiceContextLiveTest { + + private static final String lbName = String.format("lb-%s-%s", LoadBalancerApiLiveTest.class.getSimpleName() + .toLowerCase(), System.getProperty("user.name")); + + private LoadingCache resourceGroupMap; + private Predicate resourceDeleted; + private PublicIpAvailablePredicateFactory publicIpAvailable; + private Predicate> resourceAvailable; + private AzureComputeApi api; + + private String resourceGroupName; + private String location; + private LoadBalancerApi lbApi; + private NetworkInterfaceCardApi nicApi; + + private LoadBalancer lb; + private String group; + private List nicNames; + + public LoadBalancerApiLiveTest() { + provider = "azurecompute-arm"; + group = getClass().getSimpleName().toLowerCase(); + } + + @Override + protected Properties setupProperties() { + Properties properties = super.setupProperties(); + AzureLiveTestUtils.defaultProperties(properties); + checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); + return properties; + } + + @Override + protected void initializeContext() { + super.initializeContext(); + resourceDeleted = context.utils().injector().getInstance(Key.get(new TypeLiteral>() { + }, Names.named(TIMEOUT_RESOURCE_DELETED))); + resourceGroupMap = context.utils().injector() + .getInstance(Key.get(new TypeLiteral>() { + })); + publicIpAvailable = context.utils().injector().getInstance(PublicIpAvailablePredicateFactory.class); + resourceAvailable = context.utils().injector() + .getInstance(Key.get(new TypeLiteral>>() { + })); + api = view.unwrapApi(AzureComputeApi.class); + } + + @Override + @BeforeClass + public void setupContext() { + super.setupContext(); + // Use the resource name conventions used in the abstraction so the nodes + // can see the load balancer + ResourceGroup resourceGroup = createResourceGroup(); + resourceGroupName = resourceGroup.name(); + location = resourceGroup.location(); + lbApi = api.getLoadBalancerApi(resourceGroupName); + nicApi = api.getNetworkInterfaceCardApi(resourceGroupName); + } + + @Override + @AfterClass(alwaysRun = true) + protected void tearDownContext() { + try { + view.getComputeService().destroyNodesMatching(inGroup(group)); + } finally { + try { + URI uri = api.getResourceGroupApi().delete(resourceGroupName); + assertResourceDeleted(uri); + } finally { + super.tearDownContext(); + } + } + } + + @Test + public void testDeleteLoadBalancerDoesNotExist() { + URI uri = lbApi.delete(lbName); + assertNull(uri); + } + + @Test(dependsOnMethods = "testDeleteLoadBalancerDoesNotExist") + public void testCreateLoadBalancer() { + LoadBalancer createLB = newLoadBalancer(lbName, location); + + PublicIPAddress publicIP = createPublicIPAddress("Ip4LoadBalancer"); + FrontendIPConfigurationsProperties fronendProps = FrontendIPConfigurationsProperties.builder() + .publicIPAddress(IdReference.create(publicIP.id())).build(); + FrontendIPConfigurations frontendIps = FrontendIPConfigurations.create("ipConfigs", null, fronendProps, null); + LoadBalancerProperties props = LoadBalancerProperties.builder() + .frontendIPConfigurations(ImmutableList.of(frontendIps)).build(); + + lb = lbApi.createOrUpdate(lbName, createLB.location(), createLB.tags(), props); + assertNotNull(lb); + } + + @Test(dependsOnMethods = "testCreateLoadBalancer") + public void testListLoadBalancers() { + List result = lbApi.list(); + + // Verify we have something + assertNotNull(result); + assertTrue(result.size() > 0); + + // Check that the load balancer matches the one we originally passed in + assertTrue(any(result, new Predicate() { + @Override + public boolean apply(LoadBalancer input) { + return lb.name().equals(input.name()); + } + })); + } + + @Test(dependsOnMethods = "testCreateLoadBalancer") + public void testGetLoadBalancer() { + lb = lbApi.get(lbName); + assertNotNull(lb); + } + + @Test(dependsOnMethods = "testGetLoadBalancer") + public void testAddProbe() { + ProbeProperties probeProps = ProbeProperties.builder().protocol(ProbeProperties.Protocol.Http).port(80) + .requestPath("/").intervalInSeconds(5).numberOfProbes(2).build(); + + Probe probe = Probe.create("probetest", null, probeProps, null); + LoadBalancerProperties props = lb.properties().toBuilder().probes(ImmutableList.of(probe)).build(); + + lb = updateLoadBalancer(lbName, props); + + assertEquals(lb.properties().probes().size(), 1); + assertEquals(lb.properties().probes().get(0).name(), probe.name()); + } + + @Test(dependsOnMethods = "testGetLoadBalancer") + public void testAddBackendPool() throws Exception { + List rules = newArrayList(transform(lb.properties().loadBalancingRules(), ToIdReference)); + BackendAddressPool pool = BackendAddressPool.create("backpools", null, BackendAddressPoolProperties.builder() + .loadBalancingRules(rules).build(), null); + + LoadBalancerProperties props = lb.properties().toBuilder().backendAddressPools(ImmutableList.of(pool)).build(); + + lb = updateLoadBalancer(lbName, props); + + assertEquals(lb.properties().backendAddressPools().size(), 1); + assertEquals(lb.properties().backendAddressPools().get(0).name(), pool.name()); + } + + @Test(dependsOnMethods = { "testAddProbe", "testAddBackendPool" }) + public void testAddLoadBalancingRule() { + IdReference frontendIp = IdReference.create(lb.properties().frontendIPConfigurations().get(0).id()); + IdReference probe = IdReference.create(lb.properties().probes().get(0).id()); + IdReference backendPool = IdReference.create(lb.properties().backendAddressPools().get(0).id()); + + LoadBalancingRuleProperties ruleProperties = LoadBalancingRuleProperties.builder() + .frontendIPConfiguration(frontendIp).backendAddressPool(backendPool).frontendPort(80).backendPort(80) + .protocol(Protocol.Tcp).probe(probe).build(); + + LoadBalancingRule rule = LoadBalancingRule.create("lbRule1", null, ruleProperties, null); + LoadBalancerProperties props = lb.properties().toBuilder().loadBalancingRules(ImmutableList.of(rule)).build(); + + lb = updateLoadBalancer(lbName, props); + + assertEquals(lb.properties().loadBalancingRules().size(), 1); + assertEquals(lb.properties().loadBalancingRules().get(0).name(), rule.name()); + } + + @Test(dependsOnMethods = { "testAddBackendPool", "testAddProbe", "testAddLoadBalancingRule" }) + public void testAttachNodesToBackendPool() throws Exception { + nicNames = createVirtualMachinesInGroupAndGetNicRefs(group, 2); + + // Add the first IP of each node to the pool + List attachedNics = new ArrayList(); + BackendAddressPool targetPool = lb.properties().backendAddressPools().get(0); + for (String nicName : nicNames) { + attachedNics.add(attachNicToBackendPool(nicName, targetPool)); + } + + // Refresh the LB after having attached NICs to the pool + lb = lbApi.get(lbName); + List pools = lb.properties().backendAddressPools(); + assertEquals(pools.size(), 1); + + List backendIps = pools.get(0).properties().backendIPConfigurations(); + assertEquals(backendIps.size(), attachedNics.size()); + assertTrue(backendIps.containsAll(newArrayList(transform(attachedNics, ToFirstIpReference)))); + } + + @Test(dependsOnMethods = "testAttachNodesToBackendPool") + public void testAddInboundNatRule() { + IdReference frontendIp = IdReference.create(lb.properties().frontendIPConfigurations().get(0).id()); + + InboundNatRuleProperties natProps = InboundNatRuleProperties.builder().frontendIPConfiguration(frontendIp) + .frontendPort(5679).backendPort(56710).protocol(Tcp).build(); + + InboundNatRule natRule = InboundNatRule.create("inboundnat", null, natProps, null); + LoadBalancerProperties props = lb.properties().toBuilder().inboundNatRules(ImmutableList.of(natRule)).build(); + + lb = updateLoadBalancer(lbName, props); + + assertEquals(lb.properties().inboundNatRules().size(), 1); + assertEquals(lb.properties().inboundNatRules().get(0).name(), natRule.name()); + + InboundNatRule createdRule = lb.properties().inboundNatRules().get(0); + NetworkInterfaceCard updatedNic = attachNicToNatRule(nicNames.get(0), createdRule); + List natRulesInNic = updatedNic.properties().ipConfigurations().get(0).properties() + .loadBalancerInboundNatRules(); + + assertEquals(natRulesInNic.size(), 1); + assertEquals(natRulesInNic.get(0), IdReference.create(createdRule.id())); + + // Refresh the LB after having attached NICs to the pool + lb = lbApi.get(lbName); + + IdReference backendIpRef = IdReference.create(updatedNic.properties().ipConfigurations().get(0).id()); + assertEquals(lb.properties().inboundNatRules().size(), 1); + assertEquals(lb.properties().inboundNatRules().get(0).properties().backendIPConfiguration(), backendIpRef); + + } + + @Test(dependsOnMethods = { "testCreateLoadBalancer", "testListLoadBalancers", "testGetLoadBalancer", "testAddProbe", + "testAddLoadBalancingRule", "testAddBackendPool", "testAttachNodesToBackendPool", "testAddInboundNatRule" }, alwaysRun = true) + public void deleteLoadBalancer() { + URI uri = lbApi.delete(lbName); + assertResourceDeleted(uri); + } + + private PublicIPAddress createPublicIPAddress(final String publicIpAddressName) { + final PublicIPAddressApi ipApi = view.unwrapApi(AzureComputeApi.class).getPublicIPAddressApi(resourceGroupName); + PublicIPAddress publicIPAddress = ipApi.get(publicIpAddressName); + + if (publicIPAddress == null) { + final Map tags = ImmutableMap.of("testkey", "testvalue"); + PublicIPAddressProperties properties = PublicIPAddressProperties.builder().publicIPAllocationMethod("Static") + .idleTimeoutInMinutes(4).build(); + publicIPAddress = ipApi.createOrUpdate(publicIpAddressName, location, tags, properties); + + checkState(publicIpAvailable.create(resourceGroupName).apply(publicIpAddressName), + "Public IP was not provisioned in the configured timeout"); + } + + return publicIPAddress; + } + + private LoadBalancer newLoadBalancer(final String lbName, final String locationName) { + FrontendIPConfigurationsProperties frontendIPConfigurationsProperties = FrontendIPConfigurationsProperties + .builder().build(); + FrontendIPConfigurations frontendIPConfigurations = FrontendIPConfigurations.create("ipConfigs", null, + frontendIPConfigurationsProperties, null); + return LoadBalancer.create(lbName, locationName, null, + LoadBalancerProperties.builder().frontendIPConfigurations(ImmutableList.of(frontendIPConfigurations)) + .build(), null); + } + + private void assertResourceDeleted(final URI uri) { + if (uri != null) { + assertTrue(resourceDeleted.apply(uri), + String.format("Resource %s was not terminated in the configured timeout", uri)); + } + } + + private List createVirtualMachinesInGroupAndGetNicRefs(final String group, final int count) + throws RunNodesException { + + // To add multiple nodes in a LB they must belong to the same availability + // set + AvailabilitySetProperties props = AvailabilitySetProperties.builder().platformUpdateDomainCount(count) + .platformFaultDomainCount(count).build(); + AvailabilitySet as = AvailabilitySet.builder().name(group).properties(props).build(); + + Set nodes = view.getComputeService() + .createNodesInGroup(group, count, availabilitySet(as)); + + List nicNames = new ArrayList(); + for (NodeMetadata node : nodes) { + RegionAndId regionAndId = RegionAndId.fromSlashEncoded(node.getId()); + VirtualMachine vm = api.getVirtualMachineApi(resourceGroupName).get(regionAndId.id()); + + String nicName = getLast(Splitter.on("/").split( + vm.properties().networkProfile().networkInterfaces().get(0).id())); + nicNames.add(nicName); + } + + return nicNames; + } + + private NetworkInterfaceCard attachNicToBackendPool(final String nicName, BackendAddressPool pool) { + List poolRefs = ImmutableList.of(IdReference.create(pool.id())); + + // Assume we are attaching the first IP to the Load Balancer + NetworkInterfaceCard nic = nicApi.get(nicName); + + IpConfigurationProperties ipProps = nic.properties().ipConfigurations().get(0).properties().toBuilder() + .loadBalancerBackendAddressPools(poolRefs).build(); + List ips = ImmutableList.of(nic.properties().ipConfigurations().get(0).toBuilder() + .properties(ipProps).build()); + + NetworkInterfaceCardProperties nicProps = nic.properties().toBuilder().ipConfigurations(ips).build(); + + nicApi.createOrUpdate(nicName, location, nicProps, null); + + resourceAvailable.apply(new Supplier() { + @Override + public Provisionable get() { + NetworkInterfaceCard updated = nicApi.get(nicName); + return updated == null ? null : updated.properties(); + } + }); + + return nicApi.get(nicName); + } + + private NetworkInterfaceCard attachNicToNatRule(final String nicName, InboundNatRule rule) { + List natRuleRefs = ImmutableList.of(IdReference.create(rule.id())); + + // Assume we are attaching the first IP to the NAT rule + NetworkInterfaceCard nic = nicApi.get(nicName); + + IpConfigurationProperties ipProps = nic.properties().ipConfigurations().get(0).properties().toBuilder() + .loadBalancerInboundNatRules(natRuleRefs).build(); + List ips = ImmutableList.of(nic.properties().ipConfigurations().get(0).toBuilder() + .properties(ipProps).build()); + + NetworkInterfaceCardProperties nicProps = nic.properties().toBuilder().ipConfigurations(ips).build(); + + nicApi.createOrUpdate(nicName, location, nicProps, null); + + resourceAvailable.apply(new Supplier() { + @Override + public Provisionable get() { + NetworkInterfaceCard updated = nicApi.get(nicName); + return updated == null ? null : updated.properties(); + } + }); + + return nicApi.get(nicName); + } + + private ResourceGroup createResourceGroup() { + Location location = view.getComputeService().templateBuilder().build().getLocation(); + return resourceGroupMap.getUnchecked(location.getId()); + } + + private LoadBalancer updateLoadBalancer(final String name, LoadBalancerProperties props) { + lbApi.createOrUpdate(name, location, null, props); + resourceAvailable.apply(new Supplier() { + @Override + public Provisionable get() { + LoadBalancer updated = lbApi.get(name); + return updated == null ? null : updated.properties(); + } + }); + return lbApi.get(name); + } + + private static final Function ToIdReference = new Function() { + @Override + public IdReference apply(LoadBalancingRule input) { + return IdReference.create(input.id()); + } + }; + + private static final Function ToFirstIpReference = new Function() { + @Override + public IdReference apply(NetworkInterfaceCard input) { + return IdReference.create(input.properties().ipConfigurations().get(0).id()); + } + }; + +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiMockTest.java new file mode 100644 index 0000000000..49e88db33e --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiMockTest.java @@ -0,0 +1,155 @@ +/* + * 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 static com.google.common.collect.Iterables.isEmpty; +import static org.testng.Assert.assertEquals; +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.domain.FrontendIPConfigurations; +import org.jclouds.azurecompute.arm.domain.FrontendIPConfigurationsProperties; +import org.jclouds.azurecompute.arm.domain.LoadBalancer; +import org.jclouds.azurecompute.arm.domain.LoadBalancerProperties; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; + +@Test(groups = "unit", testName = "LoadBalancerApiMockTest", singleThreaded = true) +public class LoadBalancerApiMockTest extends BaseAzureComputeApiMockTest { + private final String subscriptionid = "SUBSCRIPTIONID"; + private final String resourcegroup = "myresourcegroup"; + private final String apiVersion = "api-version=2016-03-30"; + private final String lbName = "testLoadBalancer"; + + public void createLoadBalancer() throws InterruptedException { + LoadBalancer nsg = newLoadBalancer(); + + server.enqueue(jsonResponse("/loadbalancercreate.json").setResponseCode(200)); + final LoadBalancerApi nsgApi = api.getLoadBalancerApi(resourcegroup); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/loadBalancers/%s?%s", + subscriptionid, resourcegroup, lbName, apiVersion); + + String json = "{\"location\":\"westeurope\",\"properties\":{\"frontendIPConfigurations\":[{\"name\":\"ipConfigs\",\"properties\":{}}]}}"; + + LoadBalancer result = nsgApi.createOrUpdate(lbName, "westeurope", null, nsg.properties()); + assertSent(server, "PUT", path, json); + + assertEquals(result.name(), lbName); + assertEquals(result.location(), "westeurope"); + } + + public void getLoadBalancer() throws InterruptedException { + server.enqueue(jsonResponse("/loadbalancerget.json").setResponseCode(200)); + + final LoadBalancerApi nsgApi = api.getLoadBalancerApi(resourcegroup); + LoadBalancer result = nsgApi.get(lbName); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/loadBalancers/%s?%s", + subscriptionid, resourcegroup, lbName, apiVersion); + assertSent(server, "GET", path); + + assertEquals(result.name(), lbName); + assertEquals(result.location(), "westeurope"); + assertEquals(result.properties().loadBalancingRules().size(), 1); + assertEquals(result.properties().loadBalancingRules().get(0).name(), "lbRule1"); + } + + public void getLoadBalancerReturns404() throws InterruptedException { + server.enqueue(response404()); + + final LoadBalancerApi nsgApi = api.getLoadBalancerApi(resourcegroup); + LoadBalancer result = nsgApi.get(lbName); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/loadBalancers/%s?%s", + subscriptionid, resourcegroup, lbName, apiVersion); + assertSent(server, "GET", path); + + assertNull(result); + } + + public void listLoadBalancers() throws InterruptedException { + server.enqueue(jsonResponse("/loadbalancerlist.json").setResponseCode(200)); + + final LoadBalancerApi nsgApi = api.getLoadBalancerApi(resourcegroup); + List result = nsgApi.list(); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/loadBalancers?%s", + subscriptionid, resourcegroup, apiVersion); + assertSent(server, "GET", path); + + assertNotNull(result); + assertTrue(result.size() > 0); + } + + public void listLoadBalancersReturns404() throws InterruptedException { + server.enqueue(response404()); + + final LoadBalancerApi nsgApi = api.getLoadBalancerApi(resourcegroup); + List result = nsgApi.list(); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/loadBalancers?%s", + subscriptionid, resourcegroup, apiVersion); + assertSent(server, "GET", path); + + assertTrue(isEmpty(result)); + } + + public void deleteLoadBalancer() throws InterruptedException { + server.enqueue(response202WithHeader()); + + final LoadBalancerApi nsgApi = api.getLoadBalancerApi(resourcegroup); + URI uri = nsgApi.delete(lbName); + + assertEquals(server.getRequestCount(), 1); + assertNotNull(uri); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/loadBalancers/%s?%s", + subscriptionid, resourcegroup, lbName, apiVersion); + assertSent(server, "DELETE", path); + + assertTrue(uri.toString().contains("api-version")); + assertTrue(uri.toString().contains("operationresults")); + } + + public void deleteLoadBalancerDoesNotExist() throws InterruptedException { + server.enqueue(response404()); + + final LoadBalancerApi nsgApi = api.getLoadBalancerApi(resourcegroup); + URI uri = nsgApi.delete(lbName); + assertNull(uri); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/loadBalancers/%s?%s", + subscriptionid, resourcegroup, lbName, apiVersion); + assertSent(server, "DELETE", path); + } + + private LoadBalancer newLoadBalancer() { + FrontendIPConfigurationsProperties frontendIPConfigurationsProperties = FrontendIPConfigurationsProperties + .builder().build(); + FrontendIPConfigurations frontendIPConfigurations = FrontendIPConfigurations.create("ipConfigs", null, + frontendIPConfigurationsProperties, null); + return LoadBalancer.create(lbName, "westus", null, LoadBalancerProperties.builder() + .frontendIPConfigurations(ImmutableList.of(frontendIPConfigurations)).build(), null); + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiLiveTest.java index 0614d99620..cd95a2c1e3 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiLiveTest.java @@ -16,6 +16,10 @@ */ package org.jclouds.azurecompute.arm.features; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + import java.net.URI; import java.util.Arrays; import java.util.List; @@ -28,20 +32,14 @@ import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCardProperties; import org.jclouds.azurecompute.arm.domain.Subnet; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; -import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import com.google.common.collect.ImmutableMap; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; - @Test(groups = "live", singleThreaded = true) public class NetworkInterfaceCardApiLiveTest extends BaseAzureComputeApiLiveTest { - private String resourceGroupName; private String subnetId; private String nicName; @@ -49,7 +47,7 @@ public class NetworkInterfaceCardApiLiveTest extends BaseAzureComputeApiLiveTest @Override public void setup() { super.setup(); - resourceGroupName = String.format("rg-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); + createTestResourceGroup(); assertNotNull(api.getResourceGroupApi().create(resourceGroupName, LOCATION, ImmutableMap.of())); String virtualNetworkName = String.format("vn-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); nicName = String.format("nic-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); @@ -65,13 +63,6 @@ public class NetworkInterfaceCardApiLiveTest extends BaseAzureComputeApiLiveTest subnetId = subnet.id(); } - @AfterClass - @Override - protected void tearDown() { - super.tearDown(); - deleteResourceGroup(resourceGroupName); - } - @Test public void createNetworkInterfaceCard() { //Create properties object diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiMockTest.java index bda8cad53f..e0f0ed4724 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiMockTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiMockTest.java @@ -103,13 +103,9 @@ public class NetworkInterfaceCardApiMockTest extends BaseAzureComputeApiMockTest final String SubnetID = "/subscriptions/" + subscriptionid + "/resourceGroups/azurearmtesting/providers/Microsoft.Network/virtualNetworks/myvirtualnetwork/subnets/mysubnet"; //Create properties object - final NetworkInterfaceCardProperties networkInterfaceCardProperties = - NetworkInterfaceCardProperties.create(null, null, null, - Arrays.asList(IpConfiguration.create("myipconfig", null, null, null, - IpConfigurationProperties.create(null, null, "Dynamic", IdReference.create(SubnetID), null)) - ), - null - ); + final NetworkInterfaceCardProperties networkInterfaceCardProperties = NetworkInterfaceCardProperties.create(null, + null, null, Arrays.asList(IpConfiguration.create("myipconfig", null, null, null, IpConfigurationProperties + .create(null, null, "Dynamic", IdReference.create(SubnetID), null, null, null))), null); final Map tags = ImmutableMap.of("mycustomtag", "foobar"); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApiLiveTest.java index b66b1505cb..3a2f4ebaa9 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityGroupApiLiveTest.java @@ -16,44 +16,33 @@ */ package org.jclouds.azurecompute.arm.features; +import static org.testng.Assert.assertEquals; +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.domain.NetworkSecurityGroup; import org.jclouds.azurecompute.arm.domain.NetworkSecurityRule; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; -import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; - @Test(groups = "live", singleThreaded = true) public class NetworkSecurityGroupApiLiveTest extends BaseAzureComputeApiLiveTest { - private String resourceGroupName; private static String nsgName = "testNetworkSecurityGroup"; @BeforeClass @Override public void setup() { super.setup(); - resourceGroupName = String.format("rg-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); - assertNotNull(createResourceGroup(resourceGroupName)); + createTestResourceGroup(); nsgName = String.format("nsg-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); } - @AfterClass - @Override - protected void tearDown() { - super.tearDown(); - URI uri = deleteResourceGroup(resourceGroupName); - assertResourceDeleted(uri); - } - @Test public void deleteNetworkSecurityGroupDoesNotExist() { URI uri = api().delete(nsgName); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityRuleApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityRuleApiLiveTest.java index dba70630f4..821dbe3c4c 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityRuleApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkSecurityRuleApiLiveTest.java @@ -16,6 +16,11 @@ */ package org.jclouds.azurecompute.arm.features; +import static org.testng.Assert.assertEquals; +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; @@ -26,22 +31,15 @@ import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Access; import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Direction; import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Protocol; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; -import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; - @Test(groups = "live", singleThreaded = true) public class NetworkSecurityRuleApiLiveTest extends BaseAzureComputeApiLiveTest { - private String resourceGroupName; private static String UNKNOWN_RULE_NAME = "ruledoesntexist"; private String nsgName; @@ -49,8 +47,7 @@ public class NetworkSecurityRuleApiLiveTest extends BaseAzureComputeApiLiveTest @Override public void setup() { super.setup(); - resourceGroupName = String.format("rg-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); - assertNotNull(createResourceGroup(resourceGroupName)); + createTestResourceGroup(); nsgName = String.format("nsg-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); // a network security group is needed @@ -61,14 +58,6 @@ public class NetworkSecurityRuleApiLiveTest extends BaseAzureComputeApiLiveTest nsg.properties())); } - @AfterClass - @Override - protected void tearDown() { - super.tearDown(); - URI uri = deleteResourceGroup(resourceGroupName); - assertResourceDeleted(uri); - } - @Test public void deleteNetworkSecurityRuleDoesNotExist() { URI uri = api().delete(UNKNOWN_RULE_NAME); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApiLiveTest.java index 98819c1374..9519ed6633 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/PublicIPAddressApiLiveTest.java @@ -16,7 +16,12 @@ */ package org.jclouds.azurecompute.arm.features; -import java.net.URI; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + import java.util.List; import java.util.Map; @@ -24,23 +29,15 @@ import org.jclouds.azurecompute.arm.domain.PublicIPAddress; import org.jclouds.azurecompute.arm.domain.PublicIPAddressProperties; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; import org.jclouds.util.Predicates2; -import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableMap; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; - @Test(groups = "live", singleThreaded = true) public class PublicIPAddressApiLiveTest extends BaseAzureComputeApiLiveTest { - private String resourceGroupName; private final String publicIpAddressName = "myipaddress"; private String subscriptionid; @@ -48,19 +45,10 @@ public class PublicIPAddressApiLiveTest extends BaseAzureComputeApiLiveTest { @Override public void setup() { super.setup(); - resourceGroupName = String.format("rg-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); - assertNotNull(createResourceGroup(resourceGroupName)); + createTestResourceGroup(); subscriptionid = getSubscriptionId(); } - @AfterClass - @Override - protected void tearDown() { - super.tearDown(); - URI uri = deleteResourceGroup(resourceGroupName); - assertResourceDeleted(uri); - } - @Test(groups = "live") public void deletePublicIPAddressResourceDoesNotExist() { final PublicIPAddressApi ipApi = api.getPublicIPAddressApi(resourceGroupName); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiLiveTest.java index c88ebdc740..d01a972a29 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/StorageAccountApiLiveTest.java @@ -16,6 +16,12 @@ */ package org.jclouds.azurecompute.arm.features; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +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; @@ -25,41 +31,23 @@ import org.jclouds.azurecompute.arm.domain.StorageServiceUpdateParams; import org.jclouds.azurecompute.arm.functions.ParseJobStatus; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; import org.jclouds.util.Predicates2; -import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableMap; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; - @Test(groups = "live", testName = "StorageAccountApiLiveTest") public class StorageAccountApiLiveTest extends BaseAzureComputeApiLiveTest { private static final String NAME = String.format("%3.24s", RAND + StorageAccountApiLiveTest.class.getSimpleName().toLowerCase()); - private String resourceGroupName; - @BeforeClass @Override public void setup() { super.setup(); - resourceGroupName = String.format("rg-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); - assertNotNull(createResourceGroup(resourceGroupName)); - } - - @AfterClass - @Override - protected void tearDown() { - super.tearDown(); - URI uri = deleteResourceGroup(resourceGroupName); - assertResourceDeleted(uri); + createTestResourceGroup(); } @Test(dependsOnMethods = "testCreate") diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/SubnetApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/SubnetApiLiveTest.java index 8d1d505289..8144001747 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/SubnetApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/SubnetApiLiveTest.java @@ -16,24 +16,22 @@ */ package org.jclouds.azurecompute.arm.features; -import java.util.List; - -import org.jclouds.azurecompute.arm.domain.Subnet; -import org.jclouds.azurecompute.arm.domain.VirtualNetwork; -import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; +import java.util.List; + +import org.jclouds.azurecompute.arm.domain.Subnet; +import org.jclouds.azurecompute.arm.domain.VirtualNetwork; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + @Test(groups = "live", singleThreaded = true) public class SubnetApiLiveTest extends BaseAzureComputeApiLiveTest { - private String resourceGroupName; private String virtualNetworkName; private String subnetName; @@ -41,9 +39,9 @@ public class SubnetApiLiveTest extends BaseAzureComputeApiLiveTest { @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")); + createTestResourceGroup(); + virtualNetworkName = String.format("vn-%s-%s", this.getClass().getSimpleName().toLowerCase(), + System.getProperty("user.name")); subnetName = "jclouds-" + RAND; // Subnets belong to a virtual network so that needs to be created first @@ -52,13 +50,6 @@ public class SubnetApiLiveTest extends BaseAzureComputeApiLiveTest { assertNotNull(vn); } - @AfterClass - @Override - protected void tearDown() { - super.tearDown(); - deleteResourceGroup(resourceGroupName); - } - @Test public void deleteSubnetResourceDoesNotExist() { assertFalse(api().delete(subnetName)); 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 a11ff711db..8bc25c2b1e 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 @@ -47,11 +47,10 @@ 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.VirtualMachineInstance.PowerState; import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; import org.testng.Assert; -import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -63,7 +62,6 @@ import com.google.common.collect.Iterables; public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { private String subscriptionid; - private String resourceGroupName; private String storageServiceName; private String vmName; private String nicName; @@ -77,8 +75,7 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { super.setup(); subscriptionid = getSubscriptionId(); - resourceGroupName = String.format("rg-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); - assertNotNull(createResourceGroup(resourceGroupName)); + createTestResourceGroup(); virtualNetworkName = String.format("vn-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); storageServiceName = String.format("st%s%s", System.getProperty("user.name"), RAND); @@ -101,14 +98,6 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { vmName = String.format("%3.24s", System.getProperty("user.name") + RAND + this.getClass().getSimpleName()).toLowerCase().substring(0, 15); } - @AfterClass - @Override - protected void tearDown() { - super.tearDown(); - URI deleteResourceGroupURI = deleteResourceGroup(resourceGroupName); - assertResourceDeleted(deleteResourceGroupURI); - } - @Test public void testCreate() { String blob = storageService.storageServiceProperties().primaryEndpoints().get("blob"); @@ -253,11 +242,11 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { protected NetworkInterfaceCard createNetworkInterfaceCard(final String resourceGroupName, String networkInterfaceCardName, String locationName, String ipConfigurationName) { //Create properties object - final NetworkInterfaceCardProperties networkInterfaceCardProperties = - NetworkInterfaceCardProperties.builder() - .ipConfigurations(Arrays.asList(IpConfiguration.create(ipConfigurationName, null, null, null, - IpConfigurationProperties.create(null, null, "Dynamic", IdReference.create(subnetId), null)) - )).build(); + final NetworkInterfaceCardProperties networkInterfaceCardProperties = NetworkInterfaceCardProperties + .builder() + .ipConfigurations( + Arrays.asList(IpConfiguration.create(ipConfigurationName, null, null, null, IpConfigurationProperties + .create(null, null, "Dynamic", IdReference.create(subnetId), null, null, null)))).build(); final Map tags = ImmutableMap.of("jclouds", "livetest"); return api.getNetworkInterfaceCardApi(resourceGroupName).createOrUpdate(networkInterfaceCardName, locationName, networkInterfaceCardProperties, tags); 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 5b034a0d66..65bdeb3da8 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 @@ -43,6 +43,7 @@ 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.domain.Status; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; import org.testng.annotations.Test; @@ -288,7 +289,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { } private VirtualMachineInstance getVMInstance() { - List statuses = new ArrayList(); + List statuses = new ArrayList(); String testDate = "Wed May 04 01:38:52 PDT 2016"; DateFormat formatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy"); Date date = null; @@ -297,11 +298,11 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { } catch (Exception e) { e.printStackTrace(); } - VirtualMachineInstance.VirtualMachineStatus vmStatus = VirtualMachineInstance.VirtualMachineStatus.create( - "ProvisioningState/succeeded", "Info", "Provisioning succeeded", date); + Status vmStatus = Status.create( + "ProvisioningState/succeeded", "Info", "Provisioning succeeded", null, date); statuses.add(vmStatus); - VirtualMachineInstance.VirtualMachineStatus vmStatus1 = VirtualMachineInstance.VirtualMachineStatus.create( - "PowerState/running", "Info", "VM running", null); + Status vmStatus1 = Status.create( + "PowerState/running", "Info", "VM running", null, null); statuses.add(vmStatus1); VirtualMachineInstance machineInstance = VirtualMachineInstance diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApiLiveTest.java index 7f59678ddf..4459a1e208 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApiLiveTest.java @@ -16,42 +16,32 @@ */ package org.jclouds.azurecompute.arm.features; -import java.util.Arrays; -import java.util.List; - -import org.jclouds.azurecompute.arm.domain.VirtualNetwork; -import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; +import java.util.Arrays; +import java.util.List; + +import org.jclouds.azurecompute.arm.domain.VirtualNetwork; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + @Test(groups = "live", singleThreaded = true) public class VirtualNetworkApiLiveTest extends BaseAzureComputeApiLiveTest { - private String resourceGroupName; 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)); + createTestResourceGroup(); virtualNetworkName = String.format("vn-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); } - @AfterClass - @Override - protected void tearDown() { - super.tearDown(); - deleteResourceGroup(resourceGroupName); - } - @Test public void deleteVirtualNetworkResourceDoesNotExist() { boolean status = api().delete(virtualNetworkName); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java index 125e11a260..8cd662a433 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java @@ -17,6 +17,7 @@ package org.jclouds.azurecompute.arm.internal; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; +import static org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_PREFIX; 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; @@ -36,6 +37,7 @@ public class AzureLiveTestUtils { properties.put(CREDENTIAL_TYPE, CLIENT_CREDENTIALS_SECRET.toString()); properties.put(PROPERTY_REGIONS, "eastus"); properties.put(IMAGE_PUBLISHERS, "Canonical"); + properties.put(RESOURCENAME_PREFIX, "jcloudstest"); String defaultTimeout = String.valueOf(TimeUnit.MILLISECONDS.convert(60, TimeUnit.MINUTES)); properties.setProperty(TIMEOUT_SCRIPT_COMPLETE, defaultTimeout); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java index c3c6aa7f0a..0633294b31 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java @@ -16,6 +16,13 @@ */ package org.jclouds.azurecompute.arm.internal; +import static com.google.common.base.Preconditions.checkNotNull; +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.util.Predicates2.retry; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + import java.net.URI; import java.util.Arrays; import java.util.List; @@ -24,17 +31,21 @@ import java.util.Random; import org.jclouds.apis.BaseApiLiveTest; import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.PublicIpAvailablePredicateFactory; import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; 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.Provisionable; import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.domain.StorageService; import org.jclouds.azurecompute.arm.domain.Subnet; import org.jclouds.azurecompute.arm.domain.VirtualNetwork; import org.jclouds.azurecompute.arm.functions.ParseJobStatus; +import org.testng.annotations.AfterClass; import com.google.common.base.Predicate; +import com.google.common.base.Supplier; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.inject.Injector; @@ -43,13 +54,6 @@ import com.google.inject.Module; import com.google.inject.TypeLiteral; import com.google.inject.name.Names; -import static com.google.common.base.Preconditions.checkNotNull; -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.util.Predicates2.retry; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; - public class BaseAzureComputeApiLiveTest extends BaseApiLiveTest { protected static final int RAND = new Random().nextInt(999); @@ -59,10 +63,26 @@ public class BaseAzureComputeApiLiveTest extends BaseApiLiveTest imageAvailablePredicate; protected Predicate resourceDeleted; + protected PublicIpAvailablePredicateFactory publicIpAvailable; + protected Predicate> resourceAvailable; + + protected String resourceGroupName; public BaseAzureComputeApiLiveTest() { provider = "azurecompute-arm"; } + + @Override + @AfterClass(groups = "live") + protected void tearDown() { + try { + if (resourceGroupName != null) { + deleteResourceGroup(resourceGroupName); + } + } finally { + super.tearDown(); + } + } @Override protected AzureComputeApi create(Properties props, Iterable modules) { Injector injector = newBuilder().modules(modules).overrides(props).buildInjector(); @@ -70,6 +90,9 @@ public class BaseAzureComputeApiLiveTest extends BaseApiLiveTest>() { }, Names.named(TIMEOUT_RESOURCE_DELETED))); + publicIpAvailable = injector.getInstance(PublicIpAvailablePredicateFactory.class); + resourceAvailable = injector.getInstance(Key.get(new TypeLiteral>>() { + })); return injector.getInstance(AzureComputeApi.class); } @@ -82,18 +105,20 @@ public class BaseAzureComputeApiLiveTest extends BaseApiLiveTest() { @Override - public boolean apply(String name) { + public boolean apply(final String name) { VirtualNetwork virtualNetwork = api.getVirtualNetworkApi(resourceGroupName).get(name); return virtualNetwork.properties().provisioningState().equals("Succeeded"); } @@ -101,12 +126,12 @@ public class BaseAzureComputeApiLiveTest extends BaseApiLiveTest() { @Override - public boolean apply(String name) { + public boolean apply(final String name) { Subnet subnet = api.getSubnetApi(resourceGroupName, virtualNetworkName).get(name); return subnet.properties().provisioningState().equals("Succeeded"); } @@ -114,7 +139,7 @@ public class BaseAzureComputeApiLiveTest extends BaseApiLiveTest() { @Override - public boolean apply(URI uri) { + public boolean apply(final URI uri) { return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri); } }, 60 * 1 * 1000 /* 1 minute timeout */).apply(uri); @@ -131,12 +156,17 @@ public class BaseAzureComputeApiLiveTest extends BaseApiLiveTestof()); + protected void createTestResourceGroup() { + String name = String.format("rg-%s-%s", this.getClass().getSimpleName().toLowerCase(), + System.getProperty("user.name")); + ResourceGroup rg = api.getResourceGroupApi().create(name, LOCATION, ImmutableMap. of()); + assertNotNull(rg); + resourceGroupName = rg.name(); } - protected URI deleteResourceGroup(String resourceGroupName) { - return api.getResourceGroupApi().delete(resourceGroupName); + protected void deleteResourceGroup(final String resourceGroupName) { + URI uri = api.getResourceGroupApi().delete(resourceGroupName); + assertResourceDeleted(uri); } protected NetworkSecurityGroup newNetworkSecurityGroup(String nsgName, String locationName) { diff --git a/providers/azurecompute-arm/src/test/resources/availabilitysetcreate.json b/providers/azurecompute-arm/src/test/resources/availabilitysetcreate.json new file mode 100644 index 0000000000..748f749221 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/availabilitysetcreate.json @@ -0,0 +1,11 @@ +{ + "properties": { + "platformUpdateDomainCount": 2, + "platformFaultDomainCount": 3 + }, + "type": "Microsoft.Compute/availabilitySets", + "location": "westeurope", + "tags": {}, + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup/providers/Microsoft.Compute/availabilitySets/myas", + "name": "myas" +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/availabilitysetget.json b/providers/azurecompute-arm/src/test/resources/availabilitysetget.json new file mode 100644 index 0000000000..97870cb230 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/availabilitysetget.json @@ -0,0 +1,12 @@ +{ + "properties": { + "platformUpdateDomainCount": 2, + "platformFaultDomainCount": 3, + "virtualMachines": [] + }, + "type": "Microsoft.Compute/availabilitySets", + "location": "westeurope", + "tags": {}, + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup/providers/Microsoft.Compute/availabilitySets/myas", + "name": "myas" +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/availabilitysetlist.json b/providers/azurecompute-arm/src/test/resources/availabilitysetlist.json new file mode 100644 index 0000000000..77b8fbfe2f --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/availabilitysetlist.json @@ -0,0 +1,16 @@ +{ + "value": [ + { + "properties": { + "platformUpdateDomainCount": 2, + "platformFaultDomainCount": 3, + "virtualMachines": [] + }, + "type": "Microsoft.Compute/availabilitySets", + "location": "westeurope", + "tags": {}, + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup/providers/Microsoft.Compute/availabilitySets/myas", + "name": "myas" + } + ] +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/listvirtualnetworks.json b/providers/azurecompute-arm/src/test/resources/listvirtualnetworks.json index d71cf33608..54c4e5c23c 100644 --- a/providers/azurecompute-arm/src/test/resources/listvirtualnetworks.json +++ b/providers/azurecompute-arm/src/test/resources/listvirtualnetworks.json @@ -2,7 +2,7 @@ "value": [ { "name": "mockvirtualnetwork", - "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/azurearmtesting/providers/Microsoft.Network/virtualNetworks/mockvirtualnetwork", + "id": "/subscriptions/6b6748c8-3e69-4e27-9b71-df97a81c0bbc/resourceGroups/azurearmtesting/providers/Microsoft.Network/virtualNetworks/mockvirtualnetwork", "etag": "W/\"0dcd223f-670c-49ca-abe7-5978d127c131\"", "type": "Microsoft.Network/virtualNetworks", "location": "westeurope", diff --git a/providers/azurecompute-arm/src/test/resources/loadbalancercreate.json b/providers/azurecompute-arm/src/test/resources/loadbalancercreate.json new file mode 100644 index 0000000000..b3fa3391ff --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/loadbalancercreate.json @@ -0,0 +1,28 @@ +{ + "name": "testLoadBalancer", + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/rg-loadbalancerapilivetest-nacx/providers/Microsoft.Network/loadBalancers/testLoadBalancer", + "etag": "W/\"406af4e7-b24b-4c00-b42f-b3c4399bf61d\"", + "type": "Microsoft.Network/loadBalancers", + "location": "westeurope", + "properties": { + "provisioningState": "Succeeded", + "resourceGuid": "112b7e75-f287-4789-9f6a-9a55a6fbe47c", + "frontendIPConfigurations": [ + { + "name": "ipConfigs", + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/rg-loadbalancerapilivetest-nacx/providers/Microsoft.Network/loadBalancers/testLoadBalancer/frontendIPConfigurations/ipConfigs", + "etag": "W/\"406af4e7-b24b-4c00-b42f-b3c4399bf61d\"", + "properties": { + "provisioningState": "Succeeded", + "privateIPAllocationMethod": "Dynamic" + } + } + ], + "backendAddressPools": [], + "loadBalancingRules": [], + "probes": [], + "inboundNatRules": [], + "outboundNatRules": [], + "inboundNatPools": [] + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/loadbalancerget.json b/providers/azurecompute-arm/src/test/resources/loadbalancerget.json new file mode 100644 index 0000000000..ef4e390a2e --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/loadbalancerget.json @@ -0,0 +1,54 @@ +{ + "name": "testLoadBalancer", + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/rg-loadbalancerapilivetest-nacx/providers/Microsoft.Network/loadBalancers/testLoadBalancer", + "etag": "W/\"b2cfb60e-4ada-4546-a336-dd71e574ead6\"", + "type": "Microsoft.Network/loadBalancers", + "location": "westeurope", + "properties": { + "provisioningState": "Succeeded", + "resourceGuid": "0d53b121-95cc-47b5-bbc6-0391f5991028", + "frontendIPConfigurations": [ + { + "name": "ipConfigs", + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/rg-loadbalancerapilivetest-nacx/providers/Microsoft.Network/loadBalancers/testLoadBalancer/frontendIPConfigurations/ipConfigs", + "etag": "W/\"b2cfb60e-4ada-4546-a336-dd71e574ead6\"", + "properties": { + "provisioningState": "Succeeded", + "privateIPAllocationMethod": "Dynamic", + "publicIPAddress": { + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/rg-loadbalancerapilivetest-nacx/providers/Microsoft.Network/publicIPAddresses/Ip4LoadBalancer" + }, + "loadBalancingRules": [ + { + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/rg-loadbalancerapilivetest-nacx/providers/Microsoft.Network/loadBalancers/testLoadBalancer/loadBalancingRules/lbRule1" + } + ] + } + } + ], + "backendAddressPools": [], + "loadBalancingRules": [ + { + "name": "lbRule1", + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/rg-loadbalancerapilivetest-nacx/providers/Microsoft.Network/loadBalancers/testLoadBalancer/loadBalancingRules/lbRule1", + "etag": "W/\"b2cfb60e-4ada-4546-a336-dd71e574ead6\"", + "properties": { + "provisioningState": "Succeeded", + "frontendIPConfiguration": { + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/rg-loadbalancerapilivetest-nacx/providers/Microsoft.Network/loadBalancers/testLoadBalancer/frontendIPConfigurations/ipConfigs" + }, + "frontendPort": 80, + "backendPort": 80, + "enableFloatingIP": false, + "idleTimeoutInMinutes": 4, + "protocol": "Tcp", + "loadDistribution": "Default" + } + } + ], + "probes": [], + "inboundNatRules": [], + "outboundNatRules": [], + "inboundNatPools": [] + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/loadbalancerlist.json b/providers/azurecompute-arm/src/test/resources/loadbalancerlist.json new file mode 100644 index 0000000000..8272d397c8 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/loadbalancerlist.json @@ -0,0 +1,35 @@ +{ + "value": [ + { + "name": "testLoadBalancer", + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/rg-loadbalancerapilivetest-nacx/providers/Microsoft.Network/loadBalancers/testLoadBalancer", + "etag": "W/\"1107154b-8717-486b-80c1-af99ec62897b\"", + "type": "Microsoft.Network/loadBalancers", + "location": "westeurope", + "properties": { + "provisioningState": "Succeeded", + "resourceGuid": "383708b3-8d4e-474c-8908-9c4e311ac0bf", + "frontendIPConfigurations": [ + { + "name": "ipConfigs", + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/rg-loadbalancerapilivetest-nacx/providers/Microsoft.Network/loadBalancers/testLoadBalancer/frontendIPConfigurations/ipConfigs", + "etag": "W/\"1107154b-8717-486b-80c1-af99ec62897b\"", + "properties": { + "provisioningState": "Succeeded", + "privateIPAllocationMethod": "Dynamic", + "publicIPAddress": { + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/rg-loadbalancerapilivetest-nacx/providers/Microsoft.Network/publicIPAddresses/Ip4LoadBalancer" + } + } + } + ], + "backendAddressPools": [], + "loadBalancingRules": [], + "probes": [], + "inboundNatRules": [], + "outboundNatRules": [], + "inboundNatPools": [] + } + } + ] +} \ No newline at end of file From e0918405c67ab4cb1928073b86ff5c790b27f73f Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Mon, 6 Feb 2017 21:13:57 +0100 Subject: [PATCH 46/87] Cleanup orphaned availability sets --- .../functions/TemplateToAvailabilitySet.java | 16 ++++++++-- .../compute/strategy/CleanupResources.java | 30 +++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/TemplateToAvailabilitySet.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/TemplateToAvailabilitySet.java index 4e1adebded..bf334a0f51 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/TemplateToAvailabilitySet.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/TemplateToAvailabilitySet.java @@ -18,6 +18,9 @@ package org.jclouds.azurecompute.arm.compute.functions; import static com.google.common.base.Preconditions.checkArgument; +import java.util.HashMap; +import java.util.Map; + import javax.annotation.Resource; import javax.inject.Inject; import javax.inject.Named; @@ -75,9 +78,16 @@ public class TemplateToAvailabilitySet implements Function> creating availability set [%s]", availabilitySet.name()); + Map tags = new HashMap(); + if (options.getAvailabilitySet().tags() != null) { + tags.putAll(options.getAvailabilitySet().tags()); + } + tags.put("jclouds", options.getAvailabilitySet().name()); + + logger.debug(">> creating availability set [%s]", options.getAvailabilitySet().name()); + + availabilitySet = api.getAvailabilitySetApi(resourceGroup).createOrUpdate( + options.getAvailabilitySet().name(), location, tags, options.getAvailabilitySet().properties()); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java index b971931ec4..481f695866 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java @@ -25,6 +25,7 @@ import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.domain.AvailabilitySet; import org.jclouds.azurecompute.arm.domain.IdReference; import org.jclouds.azurecompute.arm.domain.IpConfiguration; import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; @@ -95,6 +96,7 @@ public class CleanupResources { cleanupVirtualMachineNICs(resourceGroupName, virtualMachine); cleanupVirtualMachineStorage(resourceGroupName, virtualMachine); + cleanupAvailabilitySetIfOrphaned(resourceGroupName, virtualMachine); return vmDeleted; } @@ -163,6 +165,24 @@ public class CleanupResources { return deleted; } + public boolean cleanupAvailabilitySetIfOrphaned(String resourceGroup, VirtualMachine virtualMachine) { + boolean deleted = false; + IdReference availabilitySetRef = virtualMachine.properties().availabilitySet(); + + if (availabilitySetRef != null) { + String name = Iterables.getLast(Splitter.on("/").split(availabilitySetRef.id())); + AvailabilitySet availabilitySet = api.getAvailabilitySetApi(resourceGroup).get(name); + + if (isOrphanedJcloudsAvailabilitySet(availabilitySet)) { + logger.debug(">> deleting orphaned availability set %s from %s...", name, resourceGroup); + URI uri = api.getAvailabilitySetApi(resourceGroup).delete(name); + deleted = uri == null || resourceDeleted.apply(uri); + } + } + + return deleted; + } + public boolean deleteResourceGroupIfEmpty(String group) { boolean deleted = false; if (api.getResourceGroupApi().resources(group).isEmpty()) { @@ -187,6 +207,16 @@ public class CleanupResources { }); } + private static boolean isOrphanedJcloudsAvailabilitySet(AvailabilitySet availabilitySet) { + // We check for the presence of the 'jclouds' tag to make sure we only + // delete availability sets that were automatically created by jclouds + return availabilitySet != null + && availabilitySet.tags() != null + && availabilitySet.tags().containsKey("jclouds") + && (availabilitySet.properties().virtualMachines() == null || availabilitySet.properties() + .virtualMachines().isEmpty()); + } + private List getNetworkCardInterfaceNames(VirtualMachine virtualMachine) { List nics = Lists.newArrayList(); for (IdReference idReference : virtualMachine.properties().networkProfile().networkInterfaces()) { From 6641b5be5820c8422917882f8480d913f487d420 Mon Sep 17 00:00:00 2001 From: Daniel Estevez Date: Wed, 15 Feb 2017 09:36:50 -0500 Subject: [PATCH 47/87] Minor fixes: logging correctly availabilitySetName --- .../arm/compute/functions/TemplateToAvailabilitySet.java | 2 +- .../azurecompute/arm/compute/options/AzureTemplateOptions.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/TemplateToAvailabilitySet.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/TemplateToAvailabilitySet.java index bf334a0f51..141687268c 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/TemplateToAvailabilitySet.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/TemplateToAvailabilitySet.java @@ -76,7 +76,7 @@ public class TemplateToAvailabilitySet implements Function tags = new HashMap(); if (options.getAvailabilitySet().tags() != null) { 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 8381076ba4..ec6858f3db 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 @@ -135,6 +135,8 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { toString.add("virtualNetworkName", virtualNetworkName); toString.add("subnetId", subnetId); toString.add("blob", blob); + toString.add("availabilitySet", availabilitySet); + toString.add("availabilitySetName", availabilitySetName); return toString; } From dd9bbff45200dd6f030c336e0e439754305cea41 Mon Sep 17 00:00:00 2001 From: Daniel Estevez Date: Wed, 15 Feb 2017 17:43:05 -0500 Subject: [PATCH 48/87] Adds new available Azure locations according to https://azure.microsoft.com/en-ca/regions/ --- .../java/org/jclouds/azurecompute/arm/domain/Region.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.java index a4453f5c1e..c7d571833f 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.java @@ -38,11 +38,17 @@ public enum Region { US_GOV_VIRGINIA("US Gov Virginia", "US-VA"), NORTH_CENTRAL_US("North Central US", "US-IL"), SOUTH_CENTRAL_US("South Central US", "US-TX"), + WEST_CENTRAL_US("West Central US", "US-WY"), WEST_US("West US", "US-CA"), + WEST_US_2("West US 2", "US-WA"), NORTH_EUROPE("North Europe", "IE"), + UK_SOUTH("UK South", "GB-LND"), + UK_WEST("UK West", "GB-CRF"), WEST_EUROPE("West Europe", "NL"), EAST_ASIA("East Asia", "HK"), SOUTH_EAST_ASIA("Southeast Asia", "SG"), + KOREA_CENTRAL("Korea Central", "KR-11"), + KOREA_SOUTH("Korea South", "KR-26"), JAPAN_EAST("Japan East", "JP-11"), JAPAN_WEST("Japan West", "JP-27"), BRAZIL_SOUTH("Brazil South", "BR"), From efb3dd53d0487dd10c7ebfb9ba451c8fb4c6a64a Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Thu, 16 Feb 2017 16:10:24 +0100 Subject: [PATCH 49/87] Fix NPE in ARM VirtualMachineToNodeMetadata --- .../compute/functions/VirtualMachineToNodeMetadata.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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 index 26bf985f25..6b7ef3008c 100644 --- 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 @@ -41,6 +41,7 @@ import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.domain.IdReference; import org.jclouds.azurecompute.arm.domain.IpConfiguration; import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; +import org.jclouds.azurecompute.arm.domain.PublicIPAddress; import org.jclouds.azurecompute.arm.domain.RegionAndId; import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.domain.StorageProfile; @@ -247,8 +248,10 @@ public class VirtualMachineToNodeMetadata implements Function Date: Thu, 9 Feb 2017 14:07:43 -0500 Subject: [PATCH 50/87] Checks existence of node before getting SecurityGroups and Images --- .../arm/compute/extensions/AzureComputeImageExtension.java | 3 ++- .../compute/extensions/AzureComputeSecurityGroupExtension.java | 3 +++ .../arm/compute/functions/ResourceDefinitionToCustomImage.java | 3 +++ 3 files changed, 8 insertions(+), 1 deletion(-) 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 7028081228..cae2c7eca4 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 @@ -115,7 +115,7 @@ public class AzureComputeImageExtension implements ImageExtension { URI uri = api.getVirtualMachineApi(resourceGroupName) .capture(regionAndId.id(), cloneTemplate.getName(), CONTAINER_NAME); checkState(uri != null && imageAvailablePredicate.apply(uri), - "Image %s was not created within the configured time limit", cloneTemplate.getName()); + "Image for node %s was not created within the configured time limit", cloneTemplate.getName()); List definitions = api.getJobApi().captureStatus(uri); checkState(definitions.size() == 1, @@ -123,6 +123,7 @@ public class AzureComputeImageExtension implements ImageExtension { Image image = resourceDefinitionToImage.create(cloneTemplate.getSourceNodeId(), cloneTemplate.getName()) .apply(definitions.get(0)); + checkState(image != null, "Image for node %s was not created", cloneTemplate.getSourceNodeId()); logger.debug(">> created %s", image); return image; } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java index 340e51ce74..e312b6adf7 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java @@ -123,6 +123,9 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(regionAndId.region()); VirtualMachine vm = api.getVirtualMachineApi(resourceGroup.name()).get(regionAndId.id()); + if (vm == null) { + throw new IllegalArgumentException("Node " + regionAndId.id() + " was not found"); + } List networkInterfacesIdReferences = vm.properties().networkProfile().networkInterfaces(); List networkGroups = new ArrayList(); 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 index dbde188622..c27f5843a4 100644 --- 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 @@ -68,6 +68,9 @@ public class ResourceDefinitionToCustomImage implements Function Date: Tue, 21 Feb 2017 22:45:46 +0100 Subject: [PATCH 51/87] Better create rules and explicit test for the ALL protocols --- .../AzureComputeSecurityGroupExtension.java | 4 ++-- .../NetworkSecurityRuleToIpPermission.java | 2 +- ...reComputeSecurityGroupExtensionLiveTest.java | 17 +++++++++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java index e312b6adf7..f23cfd83c9 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java @@ -193,7 +193,7 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio Multimap tenantIdGroupNamePairs, Iterable ipRanges, Iterable groupIds, SecurityGroup group) { String portRange = startPort + "-" + endPort; - String ruleName = protocol + "-" + portRange; + String ruleName = "ingress-" + protocol.name().toLowerCase() + "-" + portRange; logger.debug(">> adding ip permission [%s] to %s...", ruleName, group.getName()); @@ -240,7 +240,7 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio Multimap tenantIdGroupNamePairs, final Iterable ipRanges, Iterable groupIds, SecurityGroup group) { final String portRange = startPort + "-" + endPort; - String ruleName = protocol + "-" + portRange; + String ruleName = "ingress-" + protocol.name().toLowerCase() + "-" + portRange; logger.debug(">> deleting ip permissions matching [%s] from %s...", ruleName, group.getName()); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityRuleToIpPermission.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityRuleToIpPermission.java index 50a0954bdd..10b31743cd 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityRuleToIpPermission.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityRuleToIpPermission.java @@ -52,7 +52,7 @@ public class NetworkSecurityRuleToIpPermission implements Function> ignoring non-inbound networks ecurity rule %s...", rule.name()); + logger.warn(">> ignoring non-inbound network security rule %s...", rule.name()); return null; } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java index 2aa012ac7a..9296d690f4 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java @@ -23,6 +23,7 @@ import static org.jclouds.compute.options.TemplateOptions.Builder.securityGroups import static org.jclouds.compute.predicates.NodePredicates.inGroup; import static org.jclouds.net.domain.IpProtocol.TCP; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; import java.util.Properties; @@ -40,6 +41,7 @@ import org.jclouds.compute.domain.SecurityGroup; import org.jclouds.compute.extensions.SecurityGroupExtension; import org.jclouds.compute.extensions.internal.BaseSecurityGroupExtensionLiveTest; import org.jclouds.domain.Location; +import org.jclouds.net.domain.IpPermission; import org.jclouds.net.util.IpPermissions; import org.jclouds.providers.ProviderMetadata; import org.testng.annotations.AfterClass; @@ -74,6 +76,21 @@ public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGrou createResourceGroup(); } + @Test(groups = { "integration", "live" }, singleThreaded = true, dependsOnMethods = "testAddIpPermissionsFromSpec") + public void testAddIpPermissionForAnyProtocol() { + ComputeService computeService = view.getComputeService(); + Optional securityGroupExtension = computeService.getSecurityGroupExtension(); + assertTrue(securityGroupExtension.isPresent(), "security group extension was not present"); + + SecurityGroup group = securityGroupExtension.get().getSecurityGroupById(groupId); + assertNotNull(group, "No security group was found with id: " + groupId); + + IpPermission openAll = IpPermissions.permitAnyProtocol(); + SecurityGroup allOpenSecurityGroup = securityGroupExtension.get().addIpPermission(openAll, group); + + assertTrue(allOpenSecurityGroup.getIpPermissions().contains(openAll)); + } + @Test(groups = { "integration", "live" }, dependsOnMethods = "testCreateSecurityGroup") public void testCreateNodeWithSecurityGroup() throws RunNodesException, InterruptedException, ExecutionException { ComputeService computeService = view.getComputeService(); From cec73089eb7479f749b945a9f017458673478542 Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Wed, 8 Feb 2017 10:19:43 +0100 Subject: [PATCH 52/87] Improve image lookup when getting node info --- .../VirtualMachineToNodeMetadata.java | 101 ++++----------- .../functions/VirtualMachineToStatus.java | 119 ++++++++++++++++++ 2 files changed, 140 insertions(+), 80 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VirtualMachineToStatus.java 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 index 6b7ef3008c..29a57e4fba 100644 --- 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 @@ -16,10 +16,9 @@ */ package org.jclouds.azurecompute.arm.compute.functions; -import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Strings.nullToEmpty; 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.AzureComputeServiceAdapter.GROUP_KEY; import static org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageExtension.CONTAINER_NAME; @@ -38,6 +37,7 @@ import javax.inject.Inject; import javax.inject.Named; import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.compute.functions.VirtualMachineToStatus.StatusAndBackendStatus; import org.jclouds.azurecompute.arm.domain.IdReference; import org.jclouds.azurecompute.arm.domain.IpConfiguration; import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; @@ -48,11 +48,6 @@ 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.PowerState; -import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties; -import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties.ProvisioningState; -import org.jclouds.azurecompute.arm.domain.Status; import org.jclouds.azurecompute.arm.functions.StorageProfileToStorageAccountName; import org.jclouds.azurecompute.arm.util.BlobHelper; import org.jclouds.collect.Memoized; @@ -62,20 +57,17 @@ 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.compute.suppliers.ImageCacheSupplier; 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.cache.LoadingCache; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; @@ -85,62 +77,34 @@ public class VirtualMachineToNodeMetadata implements Function 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.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 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; private final LoadingCache resourceGroupMap; + private final ImageCacheSupplier imageCache; + private final VirtualMachineToStatus virtualMachineToStatus; @Inject VirtualMachineToNodeMetadata(AzureComputeApi api, GroupNamingConvention.Factory namingConvention, - Supplier> images, Supplier> hardwares, - @Memoized Supplier> locations, Map credentialStore, - Function vmImageToImge, StorageProfileToStorageAccountName storageProfileToStorageAccountName, - LoadingCache resourceGroupMap) { + Supplier> hardwares, @Memoized Supplier> locations, + Map credentialStore, Function vmImageToImge, + StorageProfileToStorageAccountName storageProfileToStorageAccountName, + LoadingCache resourceGroupMap, @Memoized Supplier> imageCache, + VirtualMachineToStatus virtualMachineToStatus) { 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.locations = locations; + this.hardwares = hardwares; this.vmImageToImge = vmImageToImge; this.storageProfileToStorageAccountName = storageProfileToStorageAccountName; this.resourceGroupMap = resourceGroupMap; + this.virtualMachineToStatus = virtualMachineToStatus; + checkArgument(imageCache instanceof ImageCacheSupplier, + "This provider needs an instance of the ImageCacheSupplier"); + this.imageCache = (ImageCacheSupplier) imageCache; } @Override @@ -153,32 +117,9 @@ public class VirtualMachineToNodeMetadata implements Function() { - @Override - public String apply(Status input) { - return input.code(); - } - }))); - } else { - builder.status(NodeMetadata.Status.PENDING); - builder.backendStatus(provisioningState.name()); - } - } else { - builder.status(PROVISIONINGSTATE_TO_NODESTATUS.apply(provisioningState)); - builder.backendStatus(provisioningState.name()); - } - - Credentials credentials = credentialStore.get("node#" + virtualMachine.name()); - builder.credentials(LoginCredentials.fromCredentials(credentials)); + StatusAndBackendStatus status = virtualMachineToStatus.apply(virtualMachine); + builder.status(status.status()); + builder.backendStatus(status.backendStatus()); builder.publicAddresses(getPublicIpAddresses(virtualMachine.properties().networkProfile().networkInterfaces())); builder.privateAddresses(getPrivateIpAddresses(virtualMachine.properties().networkProfile().networkInterfaces())); @@ -266,8 +207,8 @@ public class VirtualMachineToNodeMetadata implements Function findImage(final StorageProfile storageProfile, String locatioName, String azureGroup) { if (storageProfile.imageReference() != null) { - return Optional.fromNullable(images.get().get( - encodeFieldsToUniqueId(false, locatioName, storageProfile.imageReference()))); + String imageId = encodeFieldsToUniqueId(false, locatioName, storageProfile.imageReference()); + return imageCache.get(imageId); } else { String storageAccountName = storageProfileToStorageAccountName.apply(storageProfile); StorageServiceKeys keys = api.getStorageAccountApi(azureGroup).getKeys(storageAccountName); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VirtualMachineToStatus.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VirtualMachineToStatus.java new file mode 100644 index 0000000000..c0e333e3b1 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VirtualMachineToStatus.java @@ -0,0 +1,119 @@ +/* + * 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.collect.Iterables.transform; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.compute.functions.VirtualMachineToStatus.StatusAndBackendStatus; +import org.jclouds.azurecompute.arm.domain.ResourceGroup; +import org.jclouds.azurecompute.arm.domain.Status; +import org.jclouds.azurecompute.arm.domain.VirtualMachine; +import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance; +import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance.PowerState; +import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties; +import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties.ProvisioningState; +import org.jclouds.compute.domain.NodeMetadata; + +import com.google.auto.value.AutoValue; +import com.google.common.base.Function; +import com.google.common.base.Functions; +import com.google.common.base.Joiner; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableMap; + +@Singleton +public class VirtualMachineToStatus implements Function { + + @AutoValue + public abstract static class StatusAndBackendStatus { + public abstract NodeMetadata.Status status(); + + public abstract String backendStatus(); + + public static StatusAndBackendStatus create(NodeMetadata.Status status, String backendStatus) { + return new AutoValue_VirtualMachineToStatus_StatusAndBackendStatus(status, backendStatus); + } + } + + // 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.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 AzureComputeApi api; + private final LoadingCache resourceGroupMap; + + @Inject + VirtualMachineToStatus(AzureComputeApi api, LoadingCache resourceGroupMap) { + this.api = api; + this.resourceGroupMap = resourceGroupMap; + } + + @Override + public StatusAndBackendStatus apply(VirtualMachine virtualMachine) { + ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(virtualMachine.location()); + ProvisioningState provisioningState = virtualMachine.properties().provisioningState(); + + NodeMetadata.Status status = PROVISIONINGSTATE_TO_NODESTATUS.apply(provisioningState); + String backendStatus = provisioningState.name(); + + if (ProvisioningState.SUCCEEDED.equals(provisioningState)) { + // If the provisioning succeeded, we need to query the *real* status of + // the VM + VirtualMachineInstance instanceDetails = api.getVirtualMachineApi(resourceGroup.name()).getInstanceDetails( + virtualMachine.name()); + if (instanceDetails != null && instanceDetails.powerState() != null) { + status = POWERSTATE_TO_NODESTATUS.apply(instanceDetails.powerState()); + backendStatus = Joiner.on(',').join(transform(instanceDetails.statuses(), new Function() { + @Override + public String apply(Status input) { + return input.code(); + } + })); + } else { + status = NodeMetadata.Status.PENDING; + } + } + + return StatusAndBackendStatus.create(status, backendStatus); + } +} From 894be791ea6a64dc0402e275e04a73736ec87c35 Mon Sep 17 00:00:00 2001 From: Andrea Turli Date: Thu, 2 Mar 2017 22:22:42 +0100 Subject: [PATCH 53/87] edit VirtualMachineApi.create to createOrUpdate - add live test for update vm - update virtual machine api docs - fix VirtualMachineApiMockTest --- .../arm/AzureComputeProviderMetadata.java | 38 +++++++------- .../compute/AzureComputeServiceAdapter.java | 32 ++++++------ .../VirtualMachineToNodeMetadata.java | 24 ++++----- .../arm/features/VirtualMachineApi.java | 40 +++------------ .../features/VirtualMachineApiLiveTest.java | 50 ++++++++++++++----- .../features/VirtualMachineApiMockTest.java | 4 +- 6 files changed, 94 insertions(+), 94 deletions(-) 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 a4c2bbebe7..08979b7bdf 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,24 +17,6 @@ package org.jclouds.azurecompute.arm; -import static org.jclouds.Constants.PROPERTY_MAX_RATE_LIMIT_WAIT; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.API_VERSION_PREFIX; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_SUBNET_ADDRESS_PREFIX; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_VNET_ADDRESS_SPACE_PREFIX; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATION_TIMEOUT; -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.POLL_INITIAL_PERIOD; -import static org.jclouds.compute.config.ComputeServiceProperties.POLL_MAX_PERIOD; -import static org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_DELIMITER; -import static org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_PREFIX; -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.CREDENTIAL_TYPE; -import static org.jclouds.oauth.v2.config.OAuthProperties.RESOURCE; - import java.net.URI; import java.util.Properties; @@ -60,6 +42,24 @@ import org.jclouds.providers.internal.BaseProviderMetadata; import com.google.auto.service.AutoService; +import static org.jclouds.Constants.PROPERTY_MAX_RATE_LIMIT_WAIT; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.API_VERSION_PREFIX; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_SUBNET_ADDRESS_PREFIX; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_VNET_ADDRESS_SPACE_PREFIX; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATION_TIMEOUT; +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.POLL_INITIAL_PERIOD; +import static org.jclouds.compute.config.ComputeServiceProperties.POLL_MAX_PERIOD; +import static org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_DELIMITER; +import static org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_PREFIX; +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.CREDENTIAL_TYPE; +import static org.jclouds.oauth.v2.config.OAuthProperties.RESOURCE; + @AutoService(ProviderMetadata.class) public class AzureComputeProviderMetadata extends BaseProviderMetadata { @@ -114,7 +114,7 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { properties.put(API_VERSION_PREFIX + AvailabilitySetApi.class.getSimpleName(), "2016-03-30"); 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 + "CreateOrUpdateVirtualMachine", "2016-03-30"); properties.put(API_VERSION_PREFIX + "ListVirtualMachines", "2015-06-15"); properties.put(API_VERSION_PREFIX + "DeleteVirtualMachine", "2016-03-30"); 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 a1204bf5bd..f51010956f 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 @@ -16,20 +16,6 @@ */ package org.jclouds.azurecompute.arm.compute; -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.collect.Iterables.contains; -import static com.google.common.collect.Iterables.filter; -import static com.google.common.collect.Iterables.find; -import static com.google.common.collect.Iterables.getOnlyElement; -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.azurecompute.arm.compute.functions.VMImageToImage.getMarketplacePlanFromImageMetadata; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; -import static org.jclouds.compute.util.ComputeServiceUtils.metadataAndTagsAsCommaDelimitedValue; -import static org.jclouds.util.Closeables2.closeQuietly; - import java.util.List; import java.util.Map; import java.util.Set; @@ -98,6 +84,20 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; +import static com.google.common.base.Preconditions.checkState; +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 com.google.common.collect.Iterables.getOnlyElement; +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.azurecompute.arm.compute.functions.VMImageToImage.getMarketplacePlanFromImageMetadata; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; +import static org.jclouds.compute.util.ComputeServiceUtils.metadataAndTagsAsCommaDelimitedValue; +import static org.jclouds.util.Closeables2.closeQuietly; + /** * Defines the connection between the {@link AzureComputeApi} implementation and * the jclouds {@link org.jclouds.compute.ComputeService}. @@ -138,7 +138,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter create one nic in each network + // TODO network ids => createOrUpdate one nic in each network IdReference availabilitySet = null; if (templateOptions.getAvailabilitySet() != null) { @@ -166,7 +166,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter metadataAndTags = metadataAndTagsAsCommaDelimitedValue(template.getOptions()); Plan plan = getMarketplacePlanFromImageMetadata(template.getImage()); - VirtualMachine virtualMachine = api.getVirtualMachineApi(resourceGroup.name()).create(name, template.getLocation().getId(), + VirtualMachine virtualMachine = api.getVirtualMachineApi(resourceGroup.name()).createOrUpdate(name, template.getLocation().getId(), virtualMachineProperties, metadataAndTags, plan); // Safe to pass null credentials here, as jclouds will default populate 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 index 29a57e4fba..cb40a149d7 100644 --- 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 @@ -16,18 +16,6 @@ */ package org.jclouds.azurecompute.arm.compute.functions; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Strings.nullToEmpty; -import static com.google.common.collect.Iterables.find; -import static com.google.common.collect.Iterables.tryFind; -import static org.jclouds.azurecompute.arm.compute.AzureComputeServiceAdapter.GROUP_KEY; -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.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromCommaDelimitedValue; -import static org.jclouds.location.predicates.LocationPredicates.idEquals; -import static org.jclouds.util.Closeables2.closeQuietly; - import java.util.List; import java.util.Map; import java.util.Set; @@ -71,6 +59,18 @@ import com.google.common.cache.LoadingCache; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Strings.nullToEmpty; +import static com.google.common.collect.Iterables.find; +import static com.google.common.collect.Iterables.tryFind; +import static org.jclouds.azurecompute.arm.compute.AzureComputeServiceAdapter.GROUP_KEY; +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.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromCommaDelimitedValue; +import static org.jclouds.location.predicates.LocationPredicates.idEquals; +import static org.jclouds.util.Closeables2.closeQuietly; + public class VirtualMachineToNodeMetadata implements Function { @Resource 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 805378b2b5..c87390e8dc 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 @@ -53,16 +53,13 @@ import org.jclouds.rest.binders.BindToJsonPayload; /** * The Virtual Machine API includes operations for managing the virtual machines in your subscription. * - * @see docs + * @see docs */ @Path("/resourceGroups/{resourceGroup}/providers/Microsoft.Compute/virtualMachines") @RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) @Consumes(MediaType.APPLICATION_JSON) public interface VirtualMachineApi { - /** - * The Get Virtual Machine details - */ @Named("GetVirtualMachine") @GET @Path("/{name}") @@ -70,7 +67,7 @@ public interface VirtualMachineApi { VirtualMachine get(@PathParam("name") String name); /** - * Get information about the model view and instance view of a virtual machine: + * Get information about the model view and instance view of a virtual machine */ @Named("GetVirtualMachineInstance") @GET @@ -78,34 +75,25 @@ public interface VirtualMachineApi { @Fallback(Fallbacks.NullOnNotFoundOr404.class) VirtualMachineInstance getInstanceDetails(@PathParam("name") String name); - /** - * The Create Virtual Machine - */ - @Named("CreateVirtualMachine") + @Named("CreateOrUpdateVirtualMachine") @PUT @Payload("%7B\"location\":\"{location}\",\"tags\":{tags},\"properties\":{properties},\"plan\":{plan}%7D") @MapBinder(BindToJsonPayload.class) @Path("/{vmname}") @QueryParams(keys = "validating", values = "false") @Produces(MediaType.APPLICATION_JSON) - VirtualMachine create(@PathParam("vmname") String vmname, - @PayloadParam("location") String location, - @PayloadParam("properties") VirtualMachineProperties properties, - @PayloadParam("tags") Map tags, - @Nullable @PayloadParam("plan") Plan plan); + VirtualMachine createOrUpdate(@PathParam("vmname") String vmname, + @PayloadParam("location") String location, + @PayloadParam("properties") VirtualMachineProperties properties, + @PayloadParam("tags") Map tags, + @Nullable @PayloadParam("plan") Plan plan); - /** - * The List Virtual Machines operation - */ @Named("ListVirtualMachines") @GET @SelectJson("value") @Fallback(Fallbacks.EmptyListOnNotFoundOr404.class) List list(); - /** - * The Delete Virtual Machine operation - */ @Named("DeleteVirtualMachine") @DELETE @Path("/{name}") @@ -113,33 +101,21 @@ public interface VirtualMachineApi { @Fallback(Fallbacks.NullOnNotFoundOr404.class) URI delete(@PathParam("name") String name); - /** - * The Restart Virtual Machine operation - */ @Named("RestartVirtualMachine") @POST @Path("/{name}/restart") void restart(@PathParam("name") String name); - /** - * The start Virtual Machine operation - */ @Named("StartVirtualMachine") @POST @Path("/{name}/start") void start(@PathParam("name") String name); - /** - * The stop Virtual Machine operation - */ @Named("StopVirtualMachine") @POST @Path("/{name}/powerOff") void stop(@PathParam("name") String name); - /** - * Generalize the virtual machine - */ @Named("generalize") @POST @Path("/{name}/generalize") 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 8bc25c2b1e..6fe65e3da9 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,11 +16,6 @@ */ package org.jclouds.azurecompute.arm.features; -import static org.assertj.core.api.Assertions.assertThat; -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; @@ -55,9 +50,16 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; +import static org.assertj.core.api.Assertions.assertThat; +import static org.jclouds.util.Predicates2.retry; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + @Test(groups = "live", testName = "VirtualMachineApiLiveTest") public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { @@ -102,7 +104,7 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { public void testCreate() { String blob = storageService.storageServiceProperties().primaryEndpoints().get("blob"); - VirtualMachine vm = api().create(vmName, LOCATION, getProperties(blob, nicName), + VirtualMachine vm = api().createOrUpdate(vmName, LOCATION, getProperties(blob, nicName), Collections. emptyMap(), null); assertTrue(!vm.name().isEmpty()); @@ -113,7 +115,7 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { return !api().get(name).properties().provisioningState().equals(VirtualMachineProperties.ProvisioningState.CREATING); } }, 60 * 20 * 1000).apply(vmName); - assertTrue(jobDone, "create operation did not complete in the configured timeout"); + assertTrue(jobDone, "createOrUpdate operation did not complete in the configured timeout"); VirtualMachineProperties.ProvisioningState status = api().get(vmName).properties().provisioningState(); // Cannot be creating anymore. Should be succeeded or running but not failed. @@ -133,18 +135,40 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { assertTrue(!vmi.statuses().isEmpty()); } - @Test(dependsOnMethods = "testStart") - public void testStop() { - api().stop(vmName); - 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.RUNNING), "start operation did not complete in the configured timeout"); } + @Test(dependsOnMethods = "testStart") + public void testUpdate() { + VirtualMachine vm = api().get(vmName); + VirtualMachineProperties oldProperties = vm.properties(); + StorageProfile oldStorageProfile = oldProperties.storageProfile(); + + String blob = storageService.storageServiceProperties().primaryEndpoints().get("blob"); + VHD vhd = VHD.create(blob + "vhds/" + vmName + "new-data-disk.vhd"); + DataDisk newDataDisk = DataDisk.create(vmName + "new-data-disk", "1", 1, vhd, "Empty"); + List oldDataDisks = oldStorageProfile.dataDisks(); + assertEquals(oldDataDisks.size(), 1); + + ImmutableList newDataDisks = ImmutableList. builder().addAll(oldDataDisks).add(newDataDisk).build(); + StorageProfile newStorageProfile = oldStorageProfile.toBuilder().dataDisks(newDataDisks).build(); + VirtualMachineProperties newProperties = oldProperties.toBuilder().storageProfile(newStorageProfile).build(); + + VirtualMachine newVm = vm.toBuilder().properties(newProperties).build(); + vm = api().createOrUpdate(vmName, newVm.location(), newVm.properties(), newVm.tags(), newVm.plan()); + + assertEquals(vm.properties().storageProfile().dataDisks().size(), oldDataDisks.size() + 1); + } + + @Test(dependsOnMethods = "testUpdate") + public void testStop() { + api().stop(vmName); + assertTrue(stateReached(PowerState.STOPPED), "stop operation did not complete in the configured timeout"); + } + @Test(dependsOnMethods = "testStop") public void testRestart() { api().start(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 65bdeb3da8..0c03fb126d 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 @@ -115,7 +115,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { Plan plan = Plan.create("thinkboxsoftware", "deadline-slave-7-2", "deadline7-2"); final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); VirtualMachine vm = vmAPI - .create("windowsmachine", "westus", getProperties(), ImmutableMap.of("foo", "bar"), plan); + .createOrUpdate("windowsmachine", "westus", getProperties(), ImmutableMap.of("foo", "bar"), plan); assertEquals(vm, getVM(plan)); assertSent( server, @@ -138,7 +138,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { server.enqueue(jsonResponse("/createvirtualmachineresponse.json")); final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); - VirtualMachine vm = vmAPI.create("windowsmachine", "westus", getProperties(), ImmutableMap.of("foo", "bar"), null); + VirtualMachine vm = vmAPI.createOrUpdate("windowsmachine", "westus", getProperties(), ImmutableMap.of("foo", "bar"), null); assertEquals(vm, getVM()); assertSent( server, From c45728e085797fe3fca8e4a7bc53f7143fef5133 Mon Sep 17 00:00:00 2001 From: Dani Estevez Date: Tue, 14 Mar 2017 10:59:57 -0400 Subject: [PATCH 54/87] JCLOUDS-1254 Filters storage account by current available locations --- .../compute/AzureComputeServiceAdapter.java | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) 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 f51010956f..572e2bef07 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 @@ -16,10 +16,23 @@ */ package org.jclouds.azurecompute.arm.compute; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.Iterables.contains; +import static com.google.common.collect.Iterables.filter; +import static com.google.common.collect.Iterables.find; +import static com.google.common.collect.Iterables.getOnlyElement; +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.azurecompute.arm.compute.functions.VMImageToImage.getMarketplacePlanFromImageMetadata; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; +import static org.jclouds.compute.util.ComputeServiceUtils.metadataAndTagsAsCommaDelimitedValue; +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; @@ -84,20 +97,6 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; -import static com.google.common.base.Preconditions.checkState; -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 com.google.common.collect.Iterables.getOnlyElement; -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.azurecompute.arm.compute.functions.VMImageToImage.getMarketplacePlanFromImageMetadata; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; -import static org.jclouds.compute.util.ComputeServiceUtils.metadataAndTagsAsCommaDelimitedValue; -import static org.jclouds.util.Closeables2.closeQuietly; - /** * Defines the connection between the {@link AzureComputeApi} implementation and * the jclouds {@link org.jclouds.compute.ComputeService}. @@ -226,8 +225,15 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listImages() { final List osImages = Lists.newArrayList(); - for (Location location : listLocations()) { - osImages.addAll(listImagesByLocation(location.name())); + final List availableLocationNames = FluentIterable.from(listLocations()) + .transform(new Function() { + @Override public String apply(Location location) { + return location.name(); + } + }).toList(); + + for (String locationName : availableLocationNames) { + osImages.addAll(listImagesByLocation(locationName)); } // list custom images @@ -239,7 +245,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter Date: Thu, 23 Feb 2017 14:52:41 +0100 Subject: [PATCH 55/87] Initial support ManagedDataDisks - add DiskApi + tests - add ImageApi + tests - add TemplateOptions.dataDisks - use dataDisks in adapter - fix CreateOptions enum usage - fix VirtualMachineApiMockTest --- .../azurecompute/arm/AzureComputeApi.java | 18 +- .../arm/AzureComputeProviderMetadata.java | 11 +- .../compute/AzureComputeServiceAdapter.java | 224 +++++++++--------- .../arm/compute/functions/VMImageToImage.java | 15 +- .../compute/options/AzureTemplateOptions.java | 104 +++++--- .../CreateResourceGroupThenCreateNodes.java | 92 +------ .../azurecompute/arm/domain/CreationData.java | 54 +++++ .../azurecompute/arm/domain/DataDisk.java | 98 ++++++-- .../jclouds/azurecompute/arm/domain/Disk.java | 105 ++++++++ .../arm/domain/DiskProperties.java | 78 ++++++ .../azurecompute/arm/domain/Image.java | 73 ++++++ .../arm/domain/ImageProperties.java | 70 ++++++ .../arm/domain/ImageReference.java | 20 +- .../arm/domain/ManagedDiskParameters.java | 65 +++++ .../azurecompute/arm/domain/OSDisk.java | 18 +- .../azurecompute/arm/features/DiskApi.java | 81 +++++++ .../azurecompute/arm/features/ImageApi.java | 81 +++++++ .../azurecompute/arm/features/OSImageApi.java | 5 +- .../azurecompute/arm/util/VMImages.java | 27 +++ .../arm/features/DiskApiLiveTest.java | 107 +++++++++ .../arm/features/DiskApiMockTest.java | 141 +++++++++++ .../arm/features/ImageApiLiveTest.java | 105 ++++++++ .../features/VirtualMachineApiLiveTest.java | 25 +- .../features/VirtualMachineApiMockTest.java | 50 ++-- .../arm/internal/AzureLiveTestUtils.java | 8 +- .../test/resources/creatediskresponse.json | 11 + .../src/test/resources/getdisk.json | 19 ++ .../src/test/resources/image.json | 43 ++++ .../src/test/resources/listdisks.json | 23 ++ 29 files changed, 1471 insertions(+), 300 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/CreationData.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Disk.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DiskProperties.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Image.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageProperties.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ManagedDiskParameters.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/DiskApi.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ImageApi.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/VMImages.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DiskApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DiskApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ImageApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/resources/creatediskresponse.json create mode 100644 providers/azurecompute-arm/src/test/resources/getdisk.json create mode 100644 providers/azurecompute-arm/src/test/resources/image.json create mode 100644 providers/azurecompute-arm/src/test/resources/listdisks.json 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 3700069dbe..51ed402c78 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 @@ -22,9 +22,11 @@ import javax.ws.rs.PathParam; import org.jclouds.azurecompute.arm.features.AvailabilitySetApi; import org.jclouds.azurecompute.arm.features.DeploymentApi; +import org.jclouds.azurecompute.arm.features.ImageApi; import org.jclouds.azurecompute.arm.features.JobApi; import org.jclouds.azurecompute.arm.features.LoadBalancerApi; import org.jclouds.azurecompute.arm.features.LocationApi; +import org.jclouds.azurecompute.arm.features.DiskApi; import org.jclouds.azurecompute.arm.features.NetworkInterfaceCardApi; import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi; import org.jclouds.azurecompute.arm.features.NetworkSecurityRuleApi; @@ -37,7 +39,6 @@ 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.rest.annotations.Delegate; /** @@ -189,4 +190,19 @@ public interface AzureComputeApi extends Closeable { @Delegate ResourceProviderApi getResourceProviderApi(); + /** + * The ManagedDataDisk API includes operations for managing data disks within your subscription. + * + * @see docs + */ + @Delegate + DiskApi getDiskApi(@PathParam("resourcegroup") String resourcegroup); + + /** + * The virtual machine image API includes operations for managing data disks within your subscription. + * + * @see docs + */ + @Delegate + ImageApi getVirtualMachineImageApi(@PathParam("resourcegroup") String resourcegroup); } 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 08979b7bdf..3bf1ab31f8 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 @@ -23,8 +23,10 @@ import java.util.Properties; import org.jclouds.azurecompute.arm.domain.Region; import org.jclouds.azurecompute.arm.features.AvailabilitySetApi; import org.jclouds.azurecompute.arm.features.DeploymentApi; +import org.jclouds.azurecompute.arm.features.ImageApi; import org.jclouds.azurecompute.arm.features.LoadBalancerApi; import org.jclouds.azurecompute.arm.features.LocationApi; +import org.jclouds.azurecompute.arm.features.DiskApi; import org.jclouds.azurecompute.arm.features.NetworkInterfaceCardApi; import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi; import org.jclouds.azurecompute.arm.features.NetworkSecurityRuleApi; @@ -109,14 +111,11 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { 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 + VirtualMachineApi.class.getSimpleName(), "2016-04-30-preview"); properties.put(API_VERSION_PREFIX + LoadBalancerApi.class.getSimpleName(), "2016-03-30"); properties.put(API_VERSION_PREFIX + AvailabilitySetApi.class.getSimpleName(), "2016-03-30"); - properties.put(API_VERSION_PREFIX + "GetVirtualMachine", "2016-03-30"); - properties.put(API_VERSION_PREFIX + "GetVirtualMachineInstance", "2016-03-30"); - properties.put(API_VERSION_PREFIX + "CreateOrUpdateVirtualMachine", "2016-03-30"); - properties.put(API_VERSION_PREFIX + "ListVirtualMachines", "2015-06-15"); - properties.put(API_VERSION_PREFIX + "DeleteVirtualMachine", "2016-03-30"); + properties.put(API_VERSION_PREFIX + DiskApi.class.getSimpleName(), "2017-03-30"); + properties.put(API_VERSION_PREFIX + ImageApi.class.getSimpleName(), "2016-04-30-preview"); 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 572e2bef07..e79c50ddd9 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 @@ -16,23 +16,10 @@ */ package org.jclouds.azurecompute.arm.compute; -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.collect.Iterables.contains; -import static com.google.common.collect.Iterables.filter; -import static com.google.common.collect.Iterables.find; -import static com.google.common.collect.Iterables.getOnlyElement; -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.azurecompute.arm.compute.functions.VMImageToImage.getMarketplacePlanFromImageMetadata; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; -import static org.jclouds.compute.util.ComputeServiceUtils.metadataAndTagsAsCommaDelimitedValue; -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; @@ -42,6 +29,8 @@ import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.PublicIpAvailablePredicateFactory; import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; import org.jclouds.azurecompute.arm.compute.strategy.CleanupResources; +import org.jclouds.azurecompute.arm.domain.AvailabilitySet; +import org.jclouds.azurecompute.arm.domain.CreationData; import org.jclouds.azurecompute.arm.domain.DataDisk; import org.jclouds.azurecompute.arm.domain.HardwareProfile; import org.jclouds.azurecompute.arm.domain.IdReference; @@ -49,6 +38,7 @@ 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.ManagedDiskParameters; import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCardProperties; import org.jclouds.azurecompute.arm.domain.NetworkProfile; @@ -66,7 +56,6 @@ import org.jclouds.azurecompute.arm.domain.StorageProfile; import org.jclouds.azurecompute.arm.domain.StorageService; import org.jclouds.azurecompute.arm.domain.StorageService.Status; import org.jclouds.azurecompute.arm.domain.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; @@ -97,6 +86,23 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.ImmutableList.builder; +import static com.google.common.collect.ImmutableList.of; +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 com.google.common.collect.Iterables.getOnlyElement; +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.azurecompute.arm.compute.functions.VMImageToImage.getMarketplacePlanFromImageMetadata; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; +import static org.jclouds.azurecompute.arm.util.VMImages.isCustom; +import static org.jclouds.compute.util.ComputeServiceUtils.metadataAndTagsAsCommaDelimitedValue; +import static org.jclouds.util.Closeables2.closeQuietly; + /** * Defines the connection between the {@link AzureComputeApi} implementation and * the jclouds {@link org.jclouds.compute.ComputeService}. @@ -105,11 +111,11 @@ import com.google.common.collect.Lists; public class AzureComputeServiceAdapter implements ComputeServiceAdapter { public static final String GROUP_KEY = "jclouds_group"; - + @Resource @Named(ComputeServiceConstants.COMPUTE_LOGGER) protected Logger logger = Logger.NULL; - + private final CleanupResources cleanupResources; private final AzureComputeApi api; private final List imagePublishers; @@ -119,8 +125,8 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter> regionIds, - PublicIpAvailablePredicateFactory publicIpAvailable, LoadingCache resourceGroupMap) { + CleanupResources cleanupResources, @Region Supplier> regionIds, + PublicIpAvailablePredicateFactory publicIpAvailable, LoadingCache resourceGroupMap) { this.api = api; this.imagePublishers = Splitter.on(',').trimResults().omitEmptyStrings().splitToList(imagePublishers); this.cleanupResources = cleanupResources; @@ -130,35 +136,32 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter createNodeWithGroupEncodedIntoName(final String group, - final String name, final Template template) { - - AzureTemplateOptions templateOptions = template.getOptions().as(AzureTemplateOptions.class); - ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(template.getLocation().getId()); - - // TODO ARM specific options - // TODO network ids => createOrUpdate one nic in each network - - IdReference availabilitySet = null; - if (templateOptions.getAvailabilitySet() != null) { - availabilitySet = IdReference.create(templateOptions.getAvailabilitySet().id()); - } + public NodeAndInitialCredentials createNodeWithGroupEncodedIntoName(final String group, final String name, final Template template) { + // TODO network ids => create one nic in each network String locationName = template.getLocation().getId(); + Image image = template.getImage(); + String hardwareId = template.getHardware().getId(); + ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(locationName); + // TODO ARM specific options + AzureTemplateOptions templateOptions = template.getOptions().as(AzureTemplateOptions.class); String subnetId = templateOptions.getSubnetId(); - NetworkInterfaceCard nic = createNetworkInterfaceCard(subnetId, name, locationName, resourceGroup.name(), - template.getOptions()); - 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(availabilitySet) - .hardwareProfile(hardwareProfile).storageProfile(storageProfile).osProfile(osProfile) - .networkProfile(networkProfile).build(); + IdReference availabilitySet = getAvailabilitySetIdReference(templateOptions.getAvailabilitySet()); + StorageProfile storageProfile = createStorageProfile(image, templateOptions.getDataDisks()); + NetworkInterfaceCard nic = createNetworkInterfaceCard(subnetId, name, locationName, resourceGroup.name(), template.getOptions()); + HardwareProfile hardwareProfile = HardwareProfile.builder().vmSize(hardwareId).build(); + OSProfile osProfile = createOsProfile(name, template); + NetworkProfile networkProfile = NetworkProfile.builder().networkInterfaces(of(IdReference.create(nic.id()))).build(); + VirtualMachineProperties virtualMachineProperties = VirtualMachineProperties.builder() + .licenseType(null) // TODO + .availabilitySet(availabilitySet) + .hardwareProfile(hardwareProfile) + .storageProfile(storageProfile) + .osProfile(osProfile) + .networkProfile(networkProfile) + .build(); + // Store group apart from the name to be able to identify nodes with // custom names in the configured group template.getOptions().getUserMetadata().put(GROUP_KEY, group); @@ -171,7 +174,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter(virtualMachine, regionAndId.slashEncode(), null); } @@ -182,9 +185,9 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter vmSizes = api.getVMSizeApi(location.name()).list(); for (VMSize vmSize : vmSizes) { VMHardware hwProfile = VMHardware - .create(vmSize.name(), vmSize.numberOfCores(), vmSize.osDiskSizeInMB(), - vmSize.resourceDiskSizeInMB(), vmSize.memoryInMB(), vmSize.maxDataDiskCount(), location.name(), - false); + .create(vmSize.name(), vmSize.numberOfCores(), vmSize.osDiskSizeInMB(), + vmSize.resourceDiskSizeInMB(), vmSize.memoryInMB(), vmSize.maxDataDiskCount(), location.name(), + false); hwProfiles.add(hwProfile); } } @@ -204,8 +207,8 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter images = blobHelper.getImages(CONTAINER_NAME, azureGroup, CUSTOM_IMAGE_OFFER, - storage.location()); + storage.location()); osImages.addAll(images); } finally { closeQuietly(blobHelper); @@ -284,7 +287,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter customImagesInStorage = blobHelper.getImages(CONTAINER_NAME, resourceGroup.name(), - CUSTOM_IMAGE_OFFER, image.location()); + CUSTOM_IMAGE_OFFER, image.location()); customImage = find(customImagesInStorage, new Predicate() { @Override public boolean apply(VMImage input) { @@ -308,7 +311,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listLocations() { final Iterable vmLocations = FluentIterable.from(api.getResourceProviderApi().get("Microsoft.Compute")) - .filter(new Predicate() { - @Override - public boolean apply(ResourceProviderMetaData input) { - return input.resourceType().equals("virtualMachines"); - } - }).transformAndConcat(new Function>() { - @Override - public Iterable apply(ResourceProviderMetaData resourceProviderMetaData) { - return resourceProviderMetaData.locations(); - } - }); + .filter(new Predicate() { + @Override + public boolean apply(ResourceProviderMetaData input) { + return input.resourceType().equals("virtualMachines"); + } + }).transformAndConcat(new Function>() { + @Override + public Iterable apply(ResourceProviderMetaData resourceProviderMetaData) { + return resourceProviderMetaData.locations(); + } + }); List locations = FluentIterable.from(api.getLocationApi().list()).filter(new Predicate() { @Override @@ -378,7 +381,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listNodes() { - ImmutableList.Builder nodes = ImmutableList.builder(); + ImmutableList.Builder nodes = builder(); for (ResourceGroup resourceGroup : api.getResourceGroupApi().list()) { nodes.addAll(api.getVirtualMachineApi(resourceGroup.name()).list()); } @@ -401,14 +404,14 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter of()); + private StorageProfile createStorageProfile(Image image, List dataDisks) { + return StorageProfile.create(createImageReference(image), createOSDisk(image), dataDisks); } + + private ImageReference createImageReference(Image image) { + return isCustom(image.getId()) ? ImageReference.builder().id(image.getId()).build() : + ImageReference.builder() + .publisher(image.getProviderId()) + .offer(image.getName()) + .sku(image.getVersion()) + .version("latest") + .build(); + } + + private OSDisk createOSDisk(Image image) { + OsFamily osFamily = image.getOperatingSystem().getFamily(); + String osType = osFamily == OsFamily.WINDOWS ? "Windows" : "Linux"; + return OSDisk.builder() + .osType(osType) + .caching(DataDisk.CachingTypes.READ_WRITE.toString()) + .createOption(CreationData.CreateOptions.FROM_IMAGE.toString()) + .managedDiskParameters(ManagedDiskParameters.create(null, ManagedDiskParameters.StorageAccountTypes.STANDARD_LRS.toString())) + .build(); + } + + private IdReference getAvailabilitySetIdReference(AvailabilitySet availabilitySet) { + return availabilitySet != null ? IdReference.create(availabilitySet.id()) : null; + } + } 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 38c076968a..25bcc3b880 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,10 +16,6 @@ */ package org.jclouds.azurecompute.arm.compute.functions; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.collect.Iterables.tryFind; -import static java.util.Arrays.asList; - import java.util.Map; import java.util.Set; @@ -43,6 +39,11 @@ import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableMap; import com.google.inject.Inject; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Iterables.tryFind; +import static java.util.Arrays.asList; +import static org.jclouds.azurecompute.arm.util.VMImages.isCustom; + public class VMImageToImage implements Function { private static final Map OTHER_OS_MAP = ImmutableMap. builder() @@ -71,10 +72,9 @@ public class VMImageToImage implements Function { } public static VMImage decodeFieldsFromUniqueId(final String id) { - String[] fields = checkNotNull(id, "id").split("/"); VMImage vmImage; - boolean custom = fields.length == 5; - if (custom) { + String[] fields = checkNotNull(id, "id").split("/"); + if (isCustom(id)) { /* id fields indexes 0: imageReference.location) + "/" + 1: imageReference.group + "/" + @@ -193,4 +193,5 @@ public class VMImageToImage implements Function { } }); } + } 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 ec6858f3db..5566ecfb33 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,12 +16,16 @@ */ package org.jclouds.azurecompute.arm.compute.options; +import java.util.List; + import org.jclouds.azurecompute.arm.domain.AvailabilitySet; +import org.jclouds.azurecompute.arm.domain.DataDisk; import org.jclouds.compute.options.TemplateOptions; import com.google.common.base.Objects; +import com.google.common.collect.ImmutableList; -import static com.google.common.base.Objects.equal; +import static com.google.common.base.Preconditions.checkNotNull; /** * Azure ARM custom options @@ -33,6 +37,7 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { private String blob; private AvailabilitySet availabilitySet; private String availabilitySetName; + private List dataDisks = ImmutableList.of(); /** * Sets the virtual network name @@ -76,12 +81,25 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { return this; } + public AzureTemplateOptions dataDisks(Iterable dataDisks) { + for (DataDisk dataDisk : checkNotNull(dataDisks, "dataDisks")) + checkNotNull(dataDisk, "all dataDisks must be non-empty"); + this.dataDisks = ImmutableList.copyOf(dataDisks); + return this; + } + + public AzureTemplateOptions dataDisks(DataDisk... dataDisks) { + return dataDisks(ImmutableList.copyOf(checkNotNull(dataDisks, "dataDisks"))); + } + public String getVirtualNetworkName() { return virtualNetworkName; } public String getSubnetId() { return subnetId; } public String getBlob() { return blob; } public AvailabilitySet getAvailabilitySet() { return availabilitySet; } public String getAvailabilitySetName() { return availabilitySetName; } - + public List getDataDisks() { + return dataDisks; + } @Override public AzureTemplateOptions clone() { @@ -100,43 +118,56 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { eTo.blob(blob); eTo.availabilitySet(availabilitySet); eTo.availabilitySet(availabilitySetName); + eTo.dataDisks(dataDisks); } } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof AzureTemplateOptions)) return false; + if (!super.equals(o)) return false; + + AzureTemplateOptions that = (AzureTemplateOptions) o; + + if (virtualNetworkName != null ? !virtualNetworkName.equals(that.virtualNetworkName) : that.virtualNetworkName != null) + return false; + if (subnetId != null ? !subnetId.equals(that.subnetId) : that.subnetId != null) return false; + if (blob != null ? !blob.equals(that.blob) : that.blob != null) return false; + if (availabilitySet != null ? !availabilitySet.equals(that.availabilitySet) : that.availabilitySet != null) + return false; + if (availabilitySetName != null ? !availabilitySetName.equals(that.availabilitySetName) : that.availabilitySetName != null) + return false; + return dataDisks != null ? dataDisks.equals(that.dataDisks) : that.dataDisks == null; + } + @Override public int hashCode() { - return Objects.hashCode(super.hashCode(), virtualNetworkName, subnetId, blob, availabilitySet, - availabilitySetName); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - AzureTemplateOptions other = (AzureTemplateOptions) obj; - return super.equals(other) - && equal(this.virtualNetworkName, other.virtualNetworkName) - && equal(this.subnetId, other.subnetId) - && equal(this.blob, other.blob) - && equal(this.availabilitySet, other.availabilitySet) - && equal(this.availabilitySetName, other.availabilitySetName); + int result = super.hashCode(); + result = 31 * result + (virtualNetworkName != null ? virtualNetworkName.hashCode() : 0); + result = 31 * result + (subnetId != null ? subnetId.hashCode() : 0); + result = 31 * result + (blob != null ? blob.hashCode() : 0); + result = 31 * result + (availabilitySet != null ? availabilitySet.hashCode() : 0); + result = 31 * result + (availabilitySetName != null ? availabilitySetName.hashCode() : 0); + result = 31 * result + (dataDisks != null ? dataDisks.hashCode() : 0); + return result; } @Override public Objects.ToStringHelper string() { - Objects.ToStringHelper toString = super.string().omitNullValues(); - toString.add("virtualNetworkName", virtualNetworkName); - toString.add("subnetId", subnetId); - toString.add("blob", blob); - toString.add("availabilitySet", availabilitySet); - toString.add("availabilitySetName", availabilitySetName); + Objects.ToStringHelper toString = super.string(); + if (virtualNetworkName != null) + toString.add("virtualNetworkName", virtualNetworkName); + if (subnetId != null) + toString.add("subnetId", subnetId); + if (blob != null) + toString.add("blob", blob); + if (availabilitySet != null) + toString.add("availabilitySet", availabilitySet); + if (availabilitySetName != null) + toString.add("availabilitySetName", availabilitySetName); + if (!dataDisks.isEmpty()) + toString.add("dataDisks", dataDisks); return toString; } @@ -181,5 +212,18 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { AzureTemplateOptions options = new AzureTemplateOptions(); return options.availabilitySet(availabilitySetName); } + + /** + * @see AzureTemplateOptions#dataDisks + */ + public static AzureTemplateOptions dataDisks(DataDisk... dataDisks) { + AzureTemplateOptions options = new AzureTemplateOptions(); + return options.dataDisks(dataDisks); + } + + public static AzureTemplateOptions dataDisks(Iterable dataDisks) { + AzureTemplateOptions options = new AzureTemplateOptions(); + return options.dataDisks(dataDisks); + } } } 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 92c949956e..5f6d88f86a 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 @@ -16,19 +16,9 @@ */ package org.jclouds.azurecompute.arm.compute.strategy; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.collect.Iterables.getOnlyElement; -import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.decodeFieldsFromUniqueId; -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 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; @@ -44,14 +34,11 @@ import org.jclouds.azurecompute.arm.domain.AvailabilitySet; import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; import org.jclouds.azurecompute.arm.domain.RegionAndId; 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.SubnetApi; import org.jclouds.azurecompute.arm.features.VirtualNetworkApi; 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; @@ -65,14 +52,17 @@ import org.jclouds.domain.Location; import org.jclouds.logging.Logger; import com.google.common.base.Optional; -import com.google.common.base.Predicate; -import com.google.common.base.Strings; import com.google.common.cache.LoadingCache; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.Multimap; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Iterables.getOnlyElement; +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; + @Singleton public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEncodedIntoNameThenAddToSet { @@ -85,7 +75,6 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco private final LoadingCache resourceGroupMap; private final String defaultVnetAddressPrefix; private final String defaultSubnetAddressPrefix; - private final Predicate storageAccountCreated; private final TemplateToAvailabilitySet templateToAvailabilitySet; @Inject @@ -98,7 +87,7 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco AzureComputeApi api, @Named(DEFAULT_VNET_ADDRESS_SPACE_PREFIX) String defaultVnetAddressPrefix, @Named(DEFAULT_SUBNET_ADDRESS_PREFIX) String defaultSubnetAddressPrefix, LoadingCache securityGroupMap, - LoadingCache resourceGroupMap, @Named("STORAGE") Predicate storageAccountCreated, + LoadingCache resourceGroupMap, TemplateToAvailabilitySet templateToAvailabilitySet) { super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor, customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory); @@ -108,7 +97,6 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco this.resourceGroupMap = resourceGroupMap; this.defaultVnetAddressPrefix = defaultVnetAddressPrefix; this.defaultSubnetAddressPrefix = defaultSubnetAddressPrefix; - this.storageAccountCreated = storageAccountCreated; this.templateToAvailabilitySet = templateToAvailabilitySet; } @@ -136,9 +124,6 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco configureSecurityGroupForOptions(group, azureGroupName, template.getLocation(), options); configureAvailabilitySetForTemplate(template); - StorageService storageService = getOrCreateStorageService(group, azureGroupName, location, template.getImage()); - options.blob(storageService.storageServiceProperties().primaryEndpoints().get("blob")); - return super.execute(group, count, template, goodNodes, badNodes, customizationResponses); } @@ -175,32 +160,6 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco && !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())); - - checkState(storageAccountCreated.apply(uri), "Storage account %s was not created in the configured timeout", - storageAccountName); - - return api.getStorageAccountApi(resourceGroupName).get(storageAccountName); - } - private void configureSecurityGroupForOptions(String group, String resourceGroup, Location location, TemplateOptions options) { @@ -231,41 +190,4 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco template.getOptions().as(AzureTemplateOptions.class).availabilitySet(availabilitySet); } } - - /** - * 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(sanitizedStorageAccountName, 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/domain/CreationData.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/CreationData.java new file mode 100644 index 0000000000..ff31ef2291 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/CreationData.java @@ -0,0 +1,54 @@ +/* + * 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 org.jclouds.azurecompute.arm.util.GetEnumValue; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; +import com.google.common.base.CaseFormat; + +@AutoValue +public abstract class CreationData { + + + public enum CreateOptions { + EMPTY, + FROM_IMAGE, + COPY, + IMPORT, + UNRECOGNIZED; + + public static CreateOptions fromValue(final String text) { + return (CreateOptions) GetEnumValue.fromValueOrDefault(text, UNRECOGNIZED); + } + + @Override + public String toString() { + return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name()); + } + } + + @Nullable + public abstract CreateOptions createOption(); + + @SerializedNames({ "createOption" }) + public static CreationData create(CreateOptions createOption) { + return new AutoValue_CreationData(createOption); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DataDisk.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DataDisk.java index ebb137ba97..40189c3e65 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DataDisk.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DataDisk.java @@ -16,47 +16,108 @@ */ 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; +import com.google.common.base.CaseFormat; + @AutoValue -public abstract class DataDisk { +public abstract class DataDisk implements Provisionable { + + public enum DiskCreateOptionTypes { + FROM_IMAGE, + EMPTY, + ATTACH, + UNRECOGNIZED; + + public static DiskCreateOptionTypes fromValue(final String text) { + return (DiskCreateOptionTypes) GetEnumValue.fromValueOrDefault(text, UNRECOGNIZED); + } + + @Override + public String toString() { + return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name()); + } + } + + public enum CachingTypes { + NONE, + READ_ONLY, + READ_WRITE, + UNRECOGNIZED; + + public static CachingTypes fromValue(final String text) { + return (CachingTypes) GetEnumValue.fromValueOrDefault(text, UNRECOGNIZED); + } + + @Override + public String toString() { + return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name()); + } + } /** * The name of the data disk */ - public abstract String name(); + @Nullable public abstract String name(); /** * The size of the data disk */ - public abstract String diskSizeGB(); + @Nullable public abstract String diskSizeGB(); /** * The lun value of the data disk */ - public abstract int lun(); + @Nullable public abstract Integer lun(); /** * The vhd of the data disk */ - public abstract VHD vhd(); + @Nullable public abstract VHD vhd(); + + /** + * The source user image virtual hard disk. This virtual hard disk will be + * copied before using it to attach to the virtual machine. If SourceImage + * is provided, the destination virtual hard disk must not exist. + */ + @Nullable public abstract VHD image(); /** * The create option of the data disk */ - public abstract String createOption(); + public abstract DiskCreateOptionTypes createOption(); + + /** + * The caching type. Possible values include: 'None', 'ReadOnly', + * 'ReadWrite'. + */ + @Nullable public abstract CachingTypes caching(); - @SerializedNames({"name", "diskSizeGB", "lun", "vhd", "createOption"}) - public static DataDisk create(final String name, final String diskSizeGB, final int lun, - final VHD vhd, final String createOption) { + /** + * The managed disk parameters. + */ + @Nullable public abstract ManagedDiskParameters managedDiskParameters(); + + @Nullable + public abstract String provisioningState(); + + @SerializedNames({"name", "diskSizeGB", "lun", "vhd", "image", "createOption", "caching", "managedDisk", "provisioningState"}) + public static DataDisk create(final String name, final String diskSizeGB, final Integer lun, + final VHD vhd, final VHD image, final String createOption, final String caching, + final ManagedDiskParameters managedDiskParamenters, final String provisioningState) { return builder() .name(name) .diskSizeGB(diskSizeGB) .lun(lun) - .createOption(createOption) .vhd(vhd) + .image(image) + .caching(CachingTypes.fromValue(caching)) + .createOption(DiskCreateOptionTypes.fromValue(createOption)) + .managedDiskParameters(managedDiskParamenters) + .provisioningState(provisioningState) .build(); } @@ -68,16 +129,25 @@ public abstract class DataDisk { @AutoValue.Builder public abstract static class Builder { + public abstract Builder name(String name); public abstract Builder diskSizeGB(String diskSizeGB); - public abstract Builder createOption(String createOption); + public abstract Builder createOption(DiskCreateOptionTypes createOption); - public abstract Builder lun(int lun); + public abstract Builder lun(Integer lun); public abstract Builder vhd(VHD vhd); + public abstract Builder image(VHD image); + + public abstract Builder caching(CachingTypes caching); + + public abstract Builder managedDiskParameters(ManagedDiskParameters managedDiskParameters); + + public abstract Builder provisioningState(String provisioningState); + public abstract DataDisk build(); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Disk.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Disk.java new file mode 100644 index 0000000000..c090aa891b --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Disk.java @@ -0,0 +1,105 @@ +/* + * 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 java.util.Map; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableMap; + +@AutoValue +public abstract class Disk { + + /** + * The id of the disk + */ + @Nullable public abstract String id(); + + /** + * The name of the disk + */ + @Nullable public abstract String name(); + + /** + * The location of the disk + */ + public abstract String location(); + + /** + * The type of the disk + */ + @Nullable public abstract String type(); + + /** + * The sku of the disk + */ + @Nullable public abstract SKU sku(); + + /** + * The managed disk parameters. + */ + public abstract DiskProperties properties(); + + /** + * the tags of the disk + */ + @Nullable public abstract Map tags(); + + @SerializedNames({"id", "name", "location", "type", "sku", "properties", "tags"}) + public static Disk create(final String id, final String name, final String location, + final String type, final SKU sku, + final DiskProperties properties, final Map tags) { + return builder() + .id(id) + .name(name) + .location(location) + .type(type) + .sku(sku) + .properties(properties) + .tags(tags) + .build(); + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_Disk.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder id(String id); + public abstract Builder name(String name); + public abstract Builder location(String location); + public abstract Builder type(String type); + public abstract Builder sku(SKU sku); + public abstract Builder properties(DiskProperties properties); + public abstract Builder tags(Map tags); + + abstract Map tags(); + abstract Disk autoBuild(); + + public Disk build() { + tags(tags() != null ? ImmutableMap.copyOf(tags()) : null); + return autoBuild(); + } + + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DiskProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DiskProperties.java new file mode 100644 index 0000000000..bcc62ca1d4 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DiskProperties.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.domain; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class DiskProperties implements Provisionable { + + @Nullable + public abstract String provisioningState(); + + @Nullable + public abstract String timeCreated(); + + @Nullable + public abstract String diskState(); + + @Nullable + public abstract Integer diskSizeGB(); + + @Nullable + public abstract Integer lun(); + + @Nullable + public abstract VHD vhd(); + + public abstract CreationData creationData(); + + @SerializedNames({"provisioningState", "timeCreated", "diskState", "diskSizeGB", "lun", "vhd", "creationData"}) + public static DiskProperties create(final String provisioningState, final String timeCreated, final String diskState, final Integer diskSizeGB, final Integer lun, final VHD vhd, final CreationData creationData) { + return builder() + .provisioningState(provisioningState) + .timeCreated(timeCreated) + .diskState(diskState) + .diskSizeGB(diskSizeGB) + .lun(lun) + .vhd(vhd) + .creationData(creationData) + .build(); + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_DiskProperties.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder provisioningState(String provisioningState); + public abstract Builder timeCreated(String timeCreated); + public abstract Builder diskState(String diskState); + public abstract Builder diskSizeGB(Integer diskSizeGB); + public abstract Builder lun(Integer lun); + public abstract Builder vhd(VHD vhd); + public abstract Builder creationData(CreationData creationData); + public abstract DiskProperties build(); + + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Image.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Image.java new file mode 100644 index 0000000000..5d9226b5dd --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Image.java @@ -0,0 +1,73 @@ +/* + * 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 java.util.Map; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableMap; + +@AutoValue +public abstract class Image { + + /** + * The location of the image + */ + public abstract String location(); + + /** + * The image properties. + */ + public abstract ImageProperties properties(); + + /** + * the tags of the image + */ + @Nullable public abstract Map tags(); + + @SerializedNames({"location", "properties", "tags"}) + public static Image create(final String location, final ImageProperties properties, final Map tags) { + return builder().location(location).properties(properties).tags(tags).build(); + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_Image.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder location(String location); + + public abstract Builder properties(ImageProperties properties); + + public abstract Builder tags(Map tags); + + abstract Map tags(); + + abstract Image autoBuild(); + + public Image build() { + tags(tags() != null ? ImmutableMap.copyOf(tags()) : null); + return autoBuild(); + } + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageProperties.java new file mode 100644 index 0000000000..ef877bea40 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageProperties.java @@ -0,0 +1,70 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class ImageProperties implements Provisionable { + + @AutoValue + public abstract static class SourceVirtualMachine { + public abstract String id(); + + @SerializedNames({"id"}) + public static SourceVirtualMachine create(final String id) { + return new AutoValue_ImageProperties_SourceVirtualMachine(id); + } + } + + public abstract SourceVirtualMachine sourceVirtualMachine(); + + @Nullable + public abstract StorageProfile storageProfile(); + + @Nullable + public abstract String provisioningState(); + + @SerializedNames({ "sourceVirtualMachine", "storageProfile", "provisioningState"}) + public static ImageProperties create(final SourceVirtualMachine sourceVirtualMachine, + final StorageProfile storageProfile, + final String provisioningState) { + return builder() + .sourceVirtualMachine(sourceVirtualMachine) + .storageProfile(storageProfile) + .provisioningState(provisioningState) + .build(); + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_ImageProperties.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder sourceVirtualMachine(SourceVirtualMachine sourceVirtualMachine); + public abstract Builder storageProfile(StorageProfile storageProfile); + public abstract Builder provisioningState(String provisioningState); + public abstract ImageProperties build(); + + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java index f9e1875b4f..443e054a9e 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java @@ -16,14 +16,20 @@ */ 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 ImageReference { + /** + * The id of the image reference. + */ + @Nullable + public abstract String id(); + /** * The publisher of the image reference. */ @@ -48,13 +54,15 @@ public abstract class ImageReference { @Nullable public abstract String version(); - @SerializedNames({"publisher", "offer", "sku", "version"}) - public static ImageReference create(final String publisher, + @SerializedNames({"id", "publisher", "offer", "sku", "version"}) + public static ImageReference create(final String id, + final String publisher, final String offer, final String sku, final String version) { return builder() + .id(id) .publisher(publisher) .offer(offer) .sku(sku) @@ -70,12 +78,10 @@ public abstract class ImageReference { @AutoValue.Builder public abstract static class Builder { + public abstract Builder id(String id); public abstract Builder publisher(String publisher); - public abstract Builder offer(String offer); - public abstract Builder sku(String sku); - public abstract Builder version(String version); public abstract ImageReference build(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ManagedDiskParameters.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ManagedDiskParameters.java new file mode 100644 index 0000000000..84cbab1477 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ManagedDiskParameters.java @@ -0,0 +1,65 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class ManagedDiskParameters { + + public enum StorageAccountTypes { + /** Enum value Standard_LRS. */ + STANDARD_LRS("Standard_LRS"), + + /** Enum value Premium_LRS. */ + PREMIUM_LRS("Premium_LRS"); + + /** The actual serialized value for a StorageAccountTypes instance. */ + private String value; + + StorageAccountTypes(String value) { + this.value = value; + } + + public static StorageAccountTypes fromString(String value) { + StorageAccountTypes[] items = StorageAccountTypes.values(); + for (StorageAccountTypes item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + @Override + public String toString() { + return this.value; + } + } + + @Nullable public abstract String id(); + + public abstract StorageAccountTypes storageAccountType(); + + @SerializedNames({"id", "storageAccountType"}) + public static ManagedDiskParameters create(final String id, final String storageAccountType) { + return new AutoValue_ManagedDiskParameters(id, StorageAccountTypes.fromString(storageAccountType)); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java index 9cdee448ec..c87fe7556b 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java @@ -16,11 +16,11 @@ */ 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 OSDisk { /** @@ -59,9 +59,15 @@ public abstract class OSDisk { @Nullable public abstract VHD image(); - @SerializedNames({"osType", "name", "vhd", "caching", "createOption", "image"}) + /** + * The managed disk parameters. + */ + @Nullable public abstract ManagedDiskParameters managedDiskParameters(); + + @SerializedNames({"osType", "name", "vhd", "caching", "createOption", "image", "managedDisk"}) public static OSDisk create(final String osType, final String name, final VHD vhd, - final String caching, final String createOption, final VHD image) { + final String caching, final String createOption, final VHD image, + final ManagedDiskParameters managedDiskParamenters) { return builder() .osType(osType) .name(name) @@ -69,7 +75,8 @@ public abstract class OSDisk { .caching(caching) .createOption(createOption) .image(image) - .build(); + .managedDiskParameters(managedDiskParamenters) + .build(); } public abstract Builder toBuilder(); @@ -86,6 +93,7 @@ public abstract class OSDisk { public abstract Builder createOption(String createOption); public abstract Builder vhd(VHD vhd); public abstract Builder image(VHD image); + public abstract Builder managedDiskParameters(ManagedDiskParameters managedDiskParameters); public abstract OSDisk build(); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/DiskApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/DiskApi.java new file mode 100644 index 0000000000..0797dbd47f --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/DiskApi.java @@ -0,0 +1,81 @@ +/* + * 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 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.Disk; +import org.jclouds.azurecompute.arm.domain.DiskProperties; +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.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; + +@Path("/resourcegroups/{resourcegroup}/providers/Microsoft.Compute/disks") +@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) +@Consumes(MediaType.APPLICATION_JSON) +public interface DiskApi { + + @Named("disk:list") + @SelectJson("value") + @GET + @Fallback(EmptyListOnNotFoundOr404.class) + List list(); + + @Named("disk:create_or_update") + @PUT + @Payload("%7B\"location\":\"{location}\",\"properties\":{properties}%7D") + @MapBinder(BindToJsonPayload.class) + @Path("/{diskName}") + @Produces(MediaType.APPLICATION_JSON) + Disk createOrUpdate(@PathParam("diskName") String diskName, + @PayloadParam("location") String location, + @PayloadParam("properties") DiskProperties properties); + + @Named("disk:get") + @Path("/{diskName}") + @GET + @Fallback(NullOnNotFoundOr404.class) + Disk get(@PathParam("diskName") String diskName); + + @Named("disk:delete") + @Path("/{diskName}") + @DELETE + @ResponseParser(URIParser.class) + @Fallback(NullOnNotFoundOr404.class) + URI delete(@PathParam("diskName") String diskName); +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ImageApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ImageApi.java new file mode 100644 index 0000000000..c97b0ac65f --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ImageApi.java @@ -0,0 +1,81 @@ +/* + * 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 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.Image; +import org.jclouds.azurecompute.arm.domain.ImageProperties; +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.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; + +@Path("/resourcegroups/{resourcegroup}/providers/Microsoft.Compute/images") +@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) +@Consumes(MediaType.APPLICATION_JSON) +public interface ImageApi { + + @Named("image:list") + @SelectJson("value") + @GET + @Fallback(EmptyListOnNotFoundOr404.class) + List list(); + + @Named("image:create_or_update") + @PUT + @Payload("%7B\"location\":\"{location}\",\"properties\":{properties}%7D") + @MapBinder(BindToJsonPayload.class) + @Path("/{imageName}") + @Produces(MediaType.APPLICATION_JSON) + Image createOrUpdate(@PathParam("imageName") String imageName, + @PayloadParam("location") String location, + @PayloadParam("properties") ImageProperties properties); + + @Named("image:get") + @Path("/{imageName}") + @GET + @Fallback(NullOnNotFoundOr404.class) + Image get(@PathParam("imageName") String imageName); + + @Named("image:delete") + @Path("/{imageName}") + @DELETE + @ResponseParser(URIParser.class) + @Fallback(NullOnNotFoundOr404.class) + URI delete(@PathParam("imageName") String imageName); +} 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 50c5c450d7..32b3ccc38e 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 @@ -16,8 +16,6 @@ */ package org.jclouds.azurecompute.arm.features; -import static javax.ws.rs.core.MediaType.APPLICATION_JSON; - import java.util.List; import javax.inject.Named; @@ -36,6 +34,8 @@ import org.jclouds.oauth.v2.filters.OAuthFilter; import org.jclouds.rest.annotations.Fallback; import org.jclouds.rest.annotations.RequestFilters; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; + /** * The Azure Resource Management API includes operations for managing the OS images in your subscription. */ @@ -90,4 +90,5 @@ public interface OSImageApi { @Fallback(EmptyListOnNotFoundOr404.class) Version getVersion(@PathParam("publisher") String publisher, @PathParam("offer") String offer, @PathParam("sku") String sku, @PathParam("version") String version); + } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/VMImages.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/VMImages.java new file mode 100644 index 0000000000..d5b63943ad --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/VMImages.java @@ -0,0 +1,27 @@ +/* + * 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 static com.google.common.base.Preconditions.checkNotNull; + +public class VMImages { + + public static boolean isCustom(String imageId) { + return checkNotNull(imageId, "id").split("/").length == 5; + } + +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DiskApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DiskApiLiveTest.java new file mode 100644 index 0000000000..becfccd211 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DiskApiLiveTest.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.features; + +import java.net.URI; +import java.util.List; +import java.util.UUID; + +import org.jclouds.azurecompute.arm.domain.CreationData; +import org.jclouds.azurecompute.arm.domain.Disk; +import org.jclouds.azurecompute.arm.domain.DiskProperties; +import org.jclouds.azurecompute.arm.domain.Provisionable; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; +import com.google.common.collect.Iterables; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +@Test(groups = "live", singleThreaded = true) +public class DiskApiLiveTest extends BaseAzureComputeApiLiveTest { + + public static final String JCLOUDS_IMAGE_PREFIX = "jclouds-"; + private String diskName; + + @BeforeClass + @Override + public void setup() { + super.setup(); + createTestResourceGroup(); + diskName = JCLOUDS_IMAGE_PREFIX + RAND; + } + + @Test + public void deleteDiskResourceDoesNotExist() { + assertNull(api().delete(JCLOUDS_IMAGE_PREFIX + UUID.randomUUID())); + } + + @Test + public void createDisk() { + DiskProperties properties = DiskProperties.builder().creationData(CreationData.create(CreationData.CreateOptions.EMPTY)).diskSizeGB(2).build(); + Disk dataDisk = api().createOrUpdate(diskName, LOCATION, properties); + assertTrue(waitUntilAvailable(diskName), "creation operation did not complete in the configured timeout"); + assertTrue(dataDisk.properties().diskSizeGB() == 2); + } + + @Test(dependsOnMethods = "createDisk") + public void getDisk() { + Disk dataDisk = api().get(diskName); + assertNotNull(dataDisk.name()); + assertTrue(dataDisk.properties().diskSizeGB() == 2); + } + + @Test(dependsOnMethods = "createDisk") + public void listDisks() { + List dataDisks = api().list(); + assertTrue(dataDisks.size() > 0); + final Disk dataDisk = api().get(diskName); + + assertTrue(Iterables.any(dataDisks, new Predicate() { + @Override + public boolean apply(Disk input) { + return dataDisk.equals(input); + } + })); + } + + @Test(dependsOnMethods = {"listDisks", "getDisk"}, alwaysRun = true) + public void deleteDisk() { + URI uri = api().delete(diskName); + assertNotNull(uri); + } + + private DiskApi api() { + return api.getDiskApi(resourceGroupName); + } + + private boolean waitUntilAvailable(final String name) { + return resourceAvailable.apply(new Supplier() { + @Override public Provisionable get() { + Disk disk = api().get(name); + return disk == null ? null : disk.properties(); + } + }); + } + +} + diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DiskApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DiskApiMockTest.java new file mode 100644 index 0000000000..4c8ba2e0f6 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DiskApiMockTest.java @@ -0,0 +1,141 @@ +/* + * 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 java.util.List; + +import org.jclouds.azurecompute.arm.domain.CreationData; +import org.jclouds.azurecompute.arm.domain.Disk; +import org.jclouds.azurecompute.arm.domain.DiskProperties; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; +import org.testng.Assert; +import org.testng.annotations.Test; + +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.assertTrue; + + +@Test(groups = "unit", testName = "DiskApiMockTest", singleThreaded = true) +public class DiskApiMockTest extends BaseAzureComputeApiMockTest { + + private final String subscriptionid = "SUBSCRIPTIONID"; + private final String resourcegroup = "myresourcegroup"; + private final String diskName = "myDisk"; + private final String apiVersion = "api-version=2017-03-30"; + + public void createDisk() throws InterruptedException { + + server.enqueue(jsonResponse("/creatediskresponse.json").setResponseCode(200)); + + final DiskApi diskApi = api.getDiskApi(resourcegroup); + + DiskProperties properties = DiskProperties.builder().diskSizeGB(2).creationData(CreationData.create(CreationData.CreateOptions.EMPTY)).build(); + + Disk dataDisk = diskApi.createOrUpdate(diskName, "westus", properties); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Compute/disks/%s?%s", subscriptionid, resourcegroup, diskName, apiVersion); + String json = "{\"location\":\"westus\",\"properties\":{\"diskSizeGB\":2,\"creationData\":{\"createOption\":\"Empty\"}}}"; + assertSent(server, "PUT", path, json); + + assertEquals(dataDisk.properties().provisioningState(), "Updating"); + assertTrue(dataDisk.properties().diskSizeGB() == 2); + } + + public void getDisk() throws InterruptedException { + + server.enqueue(jsonResponse("/getdisk.json").setResponseCode(200)); + + final DiskApi diskApi = api.getDiskApi(resourcegroup); + + Disk dataDisk = diskApi.get(diskName); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Compute/disks/%s?%s", subscriptionid, resourcegroup, diskName, apiVersion); + assertSent(server, "GET", path); + + assertEquals(dataDisk.name(), diskName); + assertTrue(dataDisk.properties().diskSizeGB() == 2); + } + + public void getDiskReturns404() throws InterruptedException { + server.enqueue(response404()); + + final DiskApi diskApi = api.getDiskApi(resourcegroup); + + Disk dataDisk = diskApi.get(diskName); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Compute/disks/%s?%s", subscriptionid, resourcegroup, diskName, apiVersion); + assertSent(server, "GET", path); + + assertNull(dataDisk); + } + + public void listDisks() throws InterruptedException { + + server.enqueue(jsonResponse("/listdisks.json").setResponseCode(200)); + + final DiskApi diskApi = api.getDiskApi(resourcegroup); + + List dataDisks = diskApi.list(); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Compute/disks?%s", subscriptionid, resourcegroup, apiVersion); + assertSent(server, "GET", path); + + assertTrue(dataDisks.size() > 0); + } + + public void listDisksReturns404() throws InterruptedException { + server.enqueue(response404()); + + final DiskApi diskApi = api.getDiskApi(resourcegroup); + + List dataDisks = diskApi.list(); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Compute/disks?%s", subscriptionid, resourcegroup, apiVersion); + assertSent(server, "GET", path); + + assertTrue(isEmpty(dataDisks)); + } + + public void deleteDisk() throws InterruptedException { + + server.enqueue(response202WithHeader()); + + final DiskApi diskApi = api.getDiskApi(resourcegroup); + + URI uri = diskApi.delete(diskName); + Assert.assertNotNull(uri); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Compute/disks/%s?%s", subscriptionid, resourcegroup, diskName, apiVersion); + assertSent(server, "DELETE", path); + } + + public void deleteDiskResourceDoesNotExist() throws InterruptedException { + + server.enqueue(response204()); + + final DiskApi diskApi = api.getDiskApi(resourcegroup); + + URI uri = diskApi.delete(diskName); + assertNull(uri); + + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Compute/disks/%s?%s", subscriptionid, resourcegroup, diskName, apiVersion); + assertSent(server, "DELETE", path); + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ImageApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ImageApiLiveTest.java new file mode 100644 index 0000000000..038fc31419 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ImageApiLiveTest.java @@ -0,0 +1,105 @@ +/* + * 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 java.util.Collections; +import java.util.List; +import java.util.UUID; + +import org.jclouds.azurecompute.arm.domain.Image; +import org.jclouds.azurecompute.arm.domain.ImageProperties; +import org.jclouds.azurecompute.arm.domain.Provisionable; +import org.jclouds.azurecompute.arm.domain.VirtualMachine; +import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.google.common.base.Supplier; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +@Test(groups = "live", singleThreaded = true) +public class ImageApiLiveTest extends BaseAzureComputeApiLiveTest { + + public static final String JCLOUDS_VM_IMAGE_PREFIX = "jclouds-vm-image-"; + private String imageName; + private VirtualMachine virtualMachine; + + @BeforeClass + @Override + public void setup() { + super.setup(); + createTestResourceGroup(); + imageName = JCLOUDS_VM_IMAGE_PREFIX + RAND; + String vmName = "jclouds-vm-" + RAND; + + virtualMachine = api.getVirtualMachineApi(resourceGroupName).createOrUpdate(vmName, LOCATION, VirtualMachineProperties.builder().build(), + Collections. emptyMap(), null); + } + + @Test + public void deleteImageResourceDoesNotExist() { + assertNull(api().delete(JCLOUDS_VM_IMAGE_PREFIX + UUID.randomUUID())); + } + + @Test + public void CreateVirtualMachineImageFromExistingVM() { + String id = String.format("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/virtualMachines/myVM", getSubscriptionId(), resourceGroupName); + ImageProperties properties = ImageProperties.builder() + .sourceVirtualMachine(ImageProperties.SourceVirtualMachine.create(id)) + .build(); + Image image = api().createOrUpdate(imageName, LOCATION, properties); + assertTrue(waitUntilAvailable(imageName), "creation operation did not complete in the configured timeout"); + assertTrue(id.equals(image.properties().sourceVirtualMachine().id())); + } + + @Test(dependsOnMethods = "CreateVirtualMachineImageFromExistingVM") + public void getImage() { + Image image = api().get(imageName); + assertNotNull(image); + } + + @Test(dependsOnMethods = "CreateVirtualMachineImageFromExistingVM") + public void listImages() { + List images = api().list(); + assertTrue(images.size() > 0); + } + + @Test(dependsOnMethods = {"listImages", "getImage"}, alwaysRun = true) + public void deleteImage() { + URI uri = api().delete(imageName); + assertNotNull(uri); + } + + private ImageApi api() { + return api.getVirtualMachineImageApi(resourceGroupName); + } + + private boolean waitUntilAvailable(final String name) { + return resourceAvailable.apply(new Supplier() { + @Override public Provisionable get() { + Image image = api().get(name); + return image == null ? null : image.properties(); + } + }); + } +} + 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 6fe65e3da9..ccf1e70ce4 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 @@ -30,6 +30,7 @@ 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.ManagedDiskParameters; import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCardProperties; import org.jclouds.azurecompute.arm.domain.NetworkProfile; @@ -149,7 +150,13 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { String blob = storageService.storageServiceProperties().primaryEndpoints().get("blob"); VHD vhd = VHD.create(blob + "vhds/" + vmName + "new-data-disk.vhd"); - DataDisk newDataDisk = DataDisk.create(vmName + "new-data-disk", "1", 1, vhd, "Empty"); + DataDisk newDataDisk = DataDisk.builder() + .name(vmName + "new-data-disk") + .diskSizeGB("1") + .lun(1) + .createOption(DataDisk.DiskCreateOptionTypes.EMPTY) + .vhd(vhd) + .build(); List oldDataDisks = oldStorageProfile.dataDisks(); assertEquals(oldDataDisks.size(), 1); @@ -236,14 +243,18 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { private VirtualMachineProperties getProperties(String blob, String nic) { HardwareProfile hwProf = HardwareProfile.create("Standard_D1"); - ImageReference imgRef = ImageReference.create("MicrosoftWindowsServerEssentials", - "WindowsServerEssentials", "WindowsServerEssentials", "latest"); - VHD vhd = VHD.create(blob + "vhds/" + vmName + ".vhd"); - VHD vhd2 = VHD.create(blob + "vhds/" + vmName + "data.vhd"); - DataDisk dataDisk = DataDisk.create(vmName + "data", "100", 0, vhd2, "Empty"); + ImageReference imgRef = ImageReference.builder().publisher("MicrosoftWindowsServerEssentials") + .offer("WindowsServerEssentials").sku("WindowsServerEssentials").version("latest").build(); + DataDisk dataDisk = DataDisk.builder().name("data").diskSizeGB("100").lun(0).createOption(DataDisk.DiskCreateOptionTypes.EMPTY).build(); List dataDisks = new ArrayList(); dataDisks.add(dataDisk); - OSDisk osDisk = OSDisk.create(null, vmName, vhd, "ReadWrite", "FromImage", null); + + OSDisk osDisk = OSDisk.builder() + .osType("Windows") + .caching(DataDisk.CachingTypes.READ_WRITE.toString()) + .createOption("FromImage") + .managedDiskParameters(ManagedDiskParameters.create(null, ManagedDiskParameters.StorageAccountTypes.STANDARD_LRS.toString())) + .build(); StorageProfile storageProfile = StorageProfile.create(imgRef, osDisk, dataDisks); OSProfile.WindowsConfiguration windowsConfig = OSProfile.WindowsConfiguration.create(false, null, null, true, null); 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 0c03fb126d..34b59c30d0 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,12 +16,6 @@ */ package org.jclouds.azurecompute.arm.features; -import static com.google.common.collect.Iterables.isEmpty; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; - import java.net.URI; import java.text.DateFormat; import java.text.SimpleDateFormat; @@ -38,12 +32,12 @@ 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.Plan; +import org.jclouds.azurecompute.arm.domain.Status; import org.jclouds.azurecompute.arm.domain.StorageProfile; 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.domain.Status; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; import org.testng.annotations.Test; @@ -51,6 +45,12 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; 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.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + @Test(groups = "unit", testName = "VirtualMachineApiMockTest", singleThreaded = true) public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { @@ -60,7 +60,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { assertEquals(vmAPI.get("windowsmachine"), getVM(Plan.create("thinkboxsoftware", "deadline-slave-7-2", "deadline7-2"))); assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" - + "/virtualMachines/windowsmachine?api-version=2016-03-30"); + + "/virtualMachines/windowsmachine?api-version=2016-04-30-preview"); } public void testGetEmpty() throws Exception { @@ -68,7 +68,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); assertNull(vmAPI.get("windowsmachine")); assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" - + "/virtualMachines/windowsmachine?api-version=2016-03-30"); + + "/virtualMachines/windowsmachine?api-version=2016-04-30-preview"); } public void testGetInstanceDetails() throws Exception { @@ -83,7 +83,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { // 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=2016-03-30"); + + "/virtualMachines/windowsmachine/instanceView?api-version=2016-04-30-preview"); } public void testGetInstanceDetailsEmpty() throws Exception { @@ -91,7 +91,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=2016-03-30"); + + "/virtualMachines/windowsmachine/instanceView?api-version=2016-04-30-preview"); } public void testList() throws Exception { @@ -99,7 +99,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); assertEquals(vmAPI.list(), getVMList()); assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" - + "/virtualMachines?api-version=2015-06-15"); + + "/virtualMachines?api-version=2016-04-30-preview"); } public void testListEmpty() throws Exception { @@ -107,7 +107,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); assertTrue(isEmpty(vmAPI.list())); assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" - + "/virtualMachines?api-version=2015-06-15"); + + "/virtualMachines?api-version=2016-04-30-preview"); } public void testCreateWithPlan() throws Exception { @@ -121,7 +121,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { server, "PUT", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" - + "/virtualMachines/windowsmachine?validating=false&api-version=2016-03-30", + + "/virtualMachines/windowsmachine?validating=false&api-version=2016-04-30-preview", "{\"location\":\"westus\",\"tags\":{\"foo\":\"bar\"},\"properties\":" + "{\"vmId\":\"27ee085b-d707-xxxx-yyyy-2370e2eb1cc1\"," + "\"hardwareProfile\":{\"vmSize\":\"Standard_D1\"}," @@ -144,7 +144,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { server, "PUT", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" - + "/virtualMachines/windowsmachine?validating=false&api-version=2016-03-30", + + "/virtualMachines/windowsmachine?validating=false&api-version=2016-04-30-preview", "{\"location\":\"westus\",\"tags\":{\"foo\":\"bar\"},\"properties\":" + "{\"vmId\":\"27ee085b-d707-xxxx-yyyy-2370e2eb1cc1\"," + "\"hardwareProfile\":{\"vmSize\":\"Standard_D1\"}," @@ -167,7 +167,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { assertNull(uri); assertSent(server, "DELETE", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" - + "/virtualMachines/windowsmachine?api-version=2016-03-30"); + + "/virtualMachines/windowsmachine?api-version=2016-04-30-preview"); } public void testDelete() throws Exception { @@ -181,7 +181,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { assertNotNull(uri); assertSent(server, "DELETE", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" - + "/virtualMachines/windowsmachine?api-version=2016-03-30"); + + "/virtualMachines/windowsmachine?api-version=2016-04-30-preview"); } public void testStart() throws Exception { @@ -192,7 +192,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { vmAPI.start("windowsmachine"); assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" - + "/virtualMachines/windowsmachine/start?api-version=2015-06-15"); + + "/virtualMachines/windowsmachine/start?api-version=2016-04-30-preview"); } public void testRestart() throws Exception { @@ -203,7 +203,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { vmAPI.restart("windowsmachine"); assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" - + "/virtualMachines/windowsmachine/restart?api-version=2015-06-15"); + + "/virtualMachines/windowsmachine/restart?api-version=2016-04-30-preview"); } public void testStop() throws Exception { @@ -214,7 +214,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { vmAPI.stop("windowsmachine"); assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" - + "/virtualMachines/windowsmachine/powerOff?api-version=2015-06-15"); + + "/virtualMachines/windowsmachine/powerOff?api-version=2016-04-30-preview"); } public void testGeneralize() throws Exception { @@ -222,7 +222,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); vmAPI.generalize("vm"); // IllegalStateException if failed assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" - + "/virtualMachines/vm/generalize?api-version=2015-06-15"); + + "/virtualMachines/vm/generalize?api-version=2016-04-30-preview"); } public void testCapture() throws Exception { @@ -232,7 +232,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { URI uri = vmAPI.capture("vm", "prefix", "container"); assertNotNull(uri); assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" - + "/virtualMachines/vm/capture?api-version=2015-06-15", + + "/virtualMachines/vm/capture?api-version=2016-04-30-preview", "{\"vhdPrefix\":\"prefix\",\"destinationContainerName\":\"container\"}"); } @@ -243,16 +243,16 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { URI uri = vmAPI.capture("vm", "prefix", "container"); assertNull(uri); assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" - + "/virtualMachines/vm/capture?api-version=2015-06-15", + + "/virtualMachines/vm/capture?api-version=2016-04-30-preview", "{\"vhdPrefix\":\"prefix\",\"destinationContainerName\":\"container\"}"); } private VirtualMachineProperties getProperties() { HardwareProfile hwProf = HardwareProfile.create("Standard_D1"); - ImageReference imgRef = ImageReference.create("publisher", "offer", "sku", "ver"); + ImageReference imgRef = ImageReference.builder().publisher("publisher").offer("offer").sku("sku").version("ver").build(); VHD vhd = VHD.create("https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd"); List dataDisks = new ArrayList(); - OSDisk osDisk = OSDisk.create("Windows", "windowsmachine", vhd, "ReadWrite", "FromImage", null); + OSDisk osDisk = OSDisk.create("Windows", "windowsmachine", vhd, "ReadWrite", "FromImage", null, null); StorageProfile storageProfile = StorageProfile.create(imgRef, osDisk, dataDisks); OSProfile.WindowsConfiguration windowsConfig = OSProfile.WindowsConfiguration.create(false, null, null, true, null); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java index 8cd662a433..6006392787 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java @@ -16,6 +16,9 @@ */ package org.jclouds.azurecompute.arm.internal; +import java.util.Properties; +import java.util.concurrent.TimeUnit; + import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; import static org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_PREFIX; import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING; @@ -27,15 +30,12 @@ import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGIONS; import static org.jclouds.oauth.v2.config.CredentialType.CLIENT_CREDENTIALS_SECRET; import static org.jclouds.oauth.v2.config.OAuthProperties.CREDENTIAL_TYPE; -import java.util.Properties; -import java.util.concurrent.TimeUnit; - public class AzureLiveTestUtils { public static Properties defaultProperties(Properties properties) { properties = properties == null ? new Properties() : properties; properties.put(CREDENTIAL_TYPE, CLIENT_CREDENTIALS_SECRET.toString()); - properties.put(PROPERTY_REGIONS, "eastus"); + properties.put(PROPERTY_REGIONS, "westeurope"); properties.put(IMAGE_PUBLISHERS, "Canonical"); properties.put(RESOURCENAME_PREFIX, "jcloudstest"); diff --git a/providers/azurecompute-arm/src/test/resources/creatediskresponse.json b/providers/azurecompute-arm/src/test/resources/creatediskresponse.json new file mode 100644 index 0000000000..1fcc2bb5c3 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/creatediskresponse.json @@ -0,0 +1,11 @@ +{ + "properties": { + "creationData": { + "createOption": "Empty" + }, + "diskSizeGB": 2, + "provisioningState": "Updating", + "isArmResource": true + }, + "location": "westeurope" +} diff --git a/providers/azurecompute-arm/src/test/resources/getdisk.json b/providers/azurecompute-arm/src/test/resources/getdisk.json new file mode 100644 index 0000000000..db09d8d921 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/getdisk.json @@ -0,0 +1,19 @@ +{ + "sku": { + "name": "Standard_LRS", + "tier": "Standard" + }, + "properties": { + "creationData": { + "createOption": "Empty" + }, + "diskSizeGB": 2, + "timeCreated": "2017-03-01T09:38:18.5808215+00:00", + "provisioningState": "Succeeded", + "diskState": "Unattached" + }, + "type": "Microsoft.Compute/disks", + "location": "westeurope", + "id": "/subscriptions/610bba05-d7a7-4567-96af-48ecbd09453b/resourceGroups/rg-diskapilivetest-andrea/providers/Microsoft.Compute/disks/myDisk", + "name": "myDisk" +} diff --git a/providers/azurecompute-arm/src/test/resources/image.json b/providers/azurecompute-arm/src/test/resources/image.json new file mode 100644 index 0000000000..3dbdf119de --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/image.json @@ -0,0 +1,43 @@ +{ + "location": "West US", + "tags": { + "key": "value" + }, + "properties": { + "sourceVirtualMachine": { + "id": "/subscriptions/{subscriptionId}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/virtualMachines/myVM" + }, + "storageProfile": { + "osDisk": { + "osType": "Windows", + "blobUri": "https://mystorageaccount.blob.core.windows.net/osimages/osimage.vhd", + "snapshot": { + "id": "subscriptions/{subscriptionId}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/snapshots/mySnapshot1" + }, + "managedDisk": { + "id": "subscriptions/{subscriptionId}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myManagedDisk1" + }, + "osState": "generalized", + "hostCaching": "readwrite", + "storageAccountType": "Standard_LRS", + "diskSizeGB": 20 + }, + "dataDisks": [ + { + "lun": "1", + "blobUri": "https://mystorageaccount.blob.core.windows.net/dataimages/dataimage.vhd", + "snapshot": { + "id": "subscriptions/{subscriptionId}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/snapshots/mySnapshot2" + }, + "managedDisk": { + "id": "subscriptions/{subscriptionId}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myManagedDisk2" + }, + "hostCaching": "readwrite", + "storageAccountType": "Standard_LRS", + "diskSizeInGB": 20 + } + ] + }, + "provisioningState": "creating" + } +} diff --git a/providers/azurecompute-arm/src/test/resources/listdisks.json b/providers/azurecompute-arm/src/test/resources/listdisks.json new file mode 100644 index 0000000000..c84c561fb8 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/listdisks.json @@ -0,0 +1,23 @@ +{ + "value": [ + { + "sku": { + "name": "Standard_LRS", + "tier": "Standard" + }, + "properties": { + "creationData": { + "createOption": "Empty" + }, + "diskSizeGB": 2, + "timeCreated": "2017-03-01T09:48:27.4526118+00:00", + "provisioningState": "Succeeded", + "diskState": "Unattached" + }, + "type": "Microsoft.Compute/disks", + "location": "westeurope", + "id": "/subscriptions/610bba05-d7a7-4567-96af-48ecbd09453b/resourceGroups/rg-diskapilivetest-andrea/providers/Microsoft.Compute/disks/jclouds-646", + "name": "jclouds-646" + } + ] +} From cc13cfeda1e949db8fd82467b30cf2ac3cb9f950 Mon Sep 17 00:00:00 2001 From: Dani Estevez Date: Fri, 17 Mar 2017 17:23:49 -0400 Subject: [PATCH 56/87] Update ImageExtension to work with Managed Disks --- providers/azurecompute-arm/pom.xml | 29 +-- .../azurecompute/arm/AzureComputeApi.java | 3 +- .../arm/AzureComputeProviderMetadata.java | 39 ++-- .../compute/AzureComputeServiceAdapter.java | 134 ++++-------- .../AzureComputeServiceContextModule.java | 48 ++++- .../AzureComputeImageExtension.java | 83 +++----- .../functions/CustomImageToVMImage.java} | 21 +- .../ResourceDefinitionToCustomImage.java | 91 -------- .../functions/TemplateToAvailabilitySet.java | 3 +- .../arm/compute/functions/VMImageToImage.java | 32 +-- .../VirtualMachineToNodeMetadata.java | 62 ++---- .../compute/strategy/CleanupResources.java | 40 +--- .../arm/domain/AvailabilitySet.java | 75 ++++++- .../azurecompute/arm/domain/Image.java | 23 +- .../arm/domain/ImageProperties.java | 17 +- .../arm/domain/ImageReference.java | 16 +- .../arm/domain/ManagedDiskParameters.java | 35 +--- .../azurecompute/arm/domain/OSDisk.java | 28 +-- .../arm/domain/StorageAccountType.java | 47 +++++ .../azurecompute/arm/domain/VMImage.java | 21 +- .../arm/features/AvailabilitySetApi.java | 9 +- .../arm/features/DeploymentApi.java | 8 +- .../azurecompute/arm/features/DiskApi.java | 4 - .../azurecompute/arm/features/ImageApi.java | 4 - .../azurecompute/arm/features/JobApi.java | 3 +- .../arm/features/LoadBalancerApi.java | 2 - .../arm/features/NetworkSecurityGroupApi.java | 2 - .../arm/features/NetworkSecurityRuleApi.java | 3 +- .../arm/features/ResourceGroupApi.java | 3 - .../arm/features/ResourceProviderApi.java | 1 - .../arm/features/StorageAccountApi.java | 5 - .../arm/features/VirtualMachineApi.java | 4 +- .../azurecompute/arm/util/BlobHelper.java | 83 -------- .../azurecompute/arm/util/VMImages.java | 2 +- .../compute/AzureComputeServiceLiveTest.java | 16 +- .../compute/AzureTemplateBuilderLiveTest.java | 6 +- .../AzureComputeImageExtensionLiveTest.java | 63 ++++-- ...ComputeSecurityGroupExtensionLiveTest.java | 15 +- .../features/AvailabilitySetApiLiveTest.java | 9 +- .../features/AvailabilitySetApiMockTest.java | 8 +- .../arm/features/DeploymentApiLiveTest.java | 63 +----- .../arm/features/DiskApiLiveTest.java | 8 +- .../arm/features/ImageApiLiveTest.java | 196 ++++++++++++------ .../arm/features/ImageApiMockTest.java | 155 ++++++++++++++ .../arm/features/LoadBalancerApiLiveTest.java | 4 +- .../features/VirtualMachineApiLiveTest.java | 153 ++++++++------ .../features/VirtualMachineApiMockTest.java | 6 +- .../arm/internal/AzureLiveTestUtils.java | 33 ++- .../internal/BaseAzureComputeApiLiveTest.java | 21 +- .../resources/virtualmachineimagecreate.json | 21 ++ .../resources/virtualmachineimageget.json | 21 ++ .../resources/virtualmachineimagelist.json | 25 +++ 52 files changed, 940 insertions(+), 863 deletions(-) rename providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/{functions/StorageProfileToStorageAccountName.java => compute/functions/CustomImageToVMImage.java} (59%) delete mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/ResourceDefinitionToCustomImage.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageAccountType.java delete mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/BlobHelper.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ImageApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/resources/virtualmachineimagecreate.json create mode 100644 providers/azurecompute-arm/src/test/resources/virtualmachineimageget.json create mode 100644 providers/azurecompute-arm/src/test/resources/virtualmachineimagelist.json diff --git a/providers/azurecompute-arm/pom.xml b/providers/azurecompute-arm/pom.xml index 5860c3049b..028e4761bb 100644 --- a/providers/azurecompute-arm/pom.xml +++ b/providers/azurecompute-arm/pom.xml @@ -67,7 +67,11 @@ org.apache.jclouds.api oauth ${project.version} - jar + + + org.apache.jclouds.driver + jclouds-okhttp + ${project.version} org.apache.jclouds.api @@ -102,27 +106,11 @@ ${project.version} test - - org.apache.jclouds.driver - jclouds-slf4j - ${project.parent.version} - test - - - org.apache.jclouds.provider - azureblob - ${project.parent.version} - ch.qos.logback logback-classic test - - org.apache.jclouds.driver - jclouds-okhttp - ${project.version} - com.squareup.okhttp mockwebserver @@ -135,20 +123,13 @@ - - org.apache.jclouds - jclouds-blobstore - ${project.parent.version} - live - clean verify - org.apache.maven.plugins 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 51ed402c78..7081486861 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 @@ -17,7 +17,6 @@ package org.jclouds.azurecompute.arm; import java.io.Closeable; - import javax.ws.rs.PathParam; import org.jclouds.azurecompute.arm.features.AvailabilitySetApi; @@ -170,7 +169,7 @@ public interface AzureComputeApi extends Closeable { */ @Delegate LoadBalancerApi getLoadBalancerApi(@PathParam("resourcegroup") String resourcegroup); - + /** * The AvailabilitySet API includes operations for managing availability sets * within your subscription. 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 3bf1ab31f8..9d3f05d850 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 @@ -16,6 +16,23 @@ */ package org.jclouds.azurecompute.arm; +import static org.jclouds.Constants.PROPERTY_MAX_RATE_LIMIT_WAIT; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.API_VERSION_PREFIX; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_SUBNET_ADDRESS_PREFIX; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_VNET_ADDRESS_SPACE_PREFIX; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATION_TIMEOUT; +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.POLL_INITIAL_PERIOD; +import static org.jclouds.compute.config.ComputeServiceProperties.POLL_MAX_PERIOD; +import static org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_DELIMITER; +import static org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_PREFIX; +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.CREDENTIAL_TYPE; +import static org.jclouds.oauth.v2.config.OAuthProperties.RESOURCE; import java.net.URI; import java.util.Properties; @@ -44,24 +61,6 @@ import org.jclouds.providers.internal.BaseProviderMetadata; import com.google.auto.service.AutoService; -import static org.jclouds.Constants.PROPERTY_MAX_RATE_LIMIT_WAIT; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.API_VERSION_PREFIX; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_SUBNET_ADDRESS_PREFIX; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.DEFAULT_VNET_ADDRESS_SPACE_PREFIX; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATION_TIMEOUT; -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.POLL_INITIAL_PERIOD; -import static org.jclouds.compute.config.ComputeServiceProperties.POLL_MAX_PERIOD; -import static org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_DELIMITER; -import static org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_PREFIX; -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.CREDENTIAL_TYPE; -import static org.jclouds.oauth.v2.config.OAuthProperties.RESOURCE; - @AutoService(ProviderMetadata.class) public class AzureComputeProviderMetadata extends BaseProviderMetadata { @@ -96,7 +95,7 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { // 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(TEMPLATE, "imageNameMatches=UbuntuServer,osVersionMatches=1[456]\\.[01][04](\\.[0-9])?-LTS"); // 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"); @@ -113,7 +112,7 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { properties.put(API_VERSION_PREFIX + VMSizeApi.class.getSimpleName(), "2015-06-15"); properties.put(API_VERSION_PREFIX + VirtualMachineApi.class.getSimpleName(), "2016-04-30-preview"); properties.put(API_VERSION_PREFIX + LoadBalancerApi.class.getSimpleName(), "2016-03-30"); - properties.put(API_VERSION_PREFIX + AvailabilitySetApi.class.getSimpleName(), "2016-03-30"); + properties.put(API_VERSION_PREFIX + AvailabilitySetApi.class.getSimpleName(), "2016-04-30-preview"); properties.put(API_VERSION_PREFIX + DiskApi.class.getSimpleName(), "2017-03-30"); properties.put(API_VERSION_PREFIX + ImageApi.class.getSimpleName(), "2016-04-30-preview"); 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 e79c50ddd9..8f9b67c883 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 @@ -16,6 +16,19 @@ */ package org.jclouds.azurecompute.arm.compute; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.ImmutableList.builder; +import static com.google.common.collect.ImmutableList.of; +import static com.google.common.collect.Iterables.contains; +import static com.google.common.collect.Iterables.filter; +import static com.google.common.collect.Iterables.getOnlyElement; +import static com.google.common.collect.Iterables.transform; +import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.decodeFieldsFromUniqueId; +import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.getMarketplacePlanFromImageMetadata; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; +import static org.jclouds.azurecompute.arm.util.VMImages.isCustom; +import static org.jclouds.compute.util.ComputeServiceUtils.metadataAndTagsAsCommaDelimitedValue; + import java.util.List; import java.util.Map; import java.util.Set; @@ -27,6 +40,7 @@ import javax.inject.Singleton; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.PublicIpAvailablePredicateFactory; +import org.jclouds.azurecompute.arm.compute.functions.CustomImageToVMImage; import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; import org.jclouds.azurecompute.arm.compute.strategy.CleanupResources; import org.jclouds.azurecompute.arm.domain.AvailabilitySet; @@ -52,10 +66,8 @@ import org.jclouds.azurecompute.arm.domain.RegionAndId; import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.domain.ResourceProviderMetaData; import org.jclouds.azurecompute.arm.domain.SKU; +import org.jclouds.azurecompute.arm.domain.StorageAccountType; import org.jclouds.azurecompute.arm.domain.StorageProfile; -import org.jclouds.azurecompute.arm.domain.StorageService; -import org.jclouds.azurecompute.arm.domain.StorageService.Status; -import org.jclouds.azurecompute.arm.domain.StorageServiceKeys; import org.jclouds.azurecompute.arm.domain.VMHardware; import org.jclouds.azurecompute.arm.domain.VMImage; import org.jclouds.azurecompute.arm.domain.VMSize; @@ -64,7 +76,6 @@ 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.util.BlobHelper; import org.jclouds.compute.ComputeServiceAdapter; import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.OsFamily; @@ -86,23 +97,6 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.collect.ImmutableList.builder; -import static com.google.common.collect.ImmutableList.of; -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 com.google.common.collect.Iterables.getOnlyElement; -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.azurecompute.arm.compute.functions.VMImageToImage.getMarketplacePlanFromImageMetadata; -import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; -import static org.jclouds.azurecompute.arm.util.VMImages.isCustom; -import static org.jclouds.compute.util.ComputeServiceUtils.metadataAndTagsAsCommaDelimitedValue; -import static org.jclouds.util.Closeables2.closeQuietly; - /** * Defines the connection between the {@link AzureComputeApi} implementation and * the jclouds {@link org.jclouds.compute.ComputeService}. @@ -122,17 +116,20 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter> regionIds; private final PublicIpAvailablePredicateFactory publicIpAvailable; private final LoadingCache resourceGroupMap; + private final CustomImageToVMImage customImagetoVmImage; @Inject AzureComputeServiceAdapter(final AzureComputeApi api, @Named(IMAGE_PUBLISHERS) String imagePublishers, - CleanupResources cleanupResources, @Region Supplier> regionIds, - PublicIpAvailablePredicateFactory publicIpAvailable, LoadingCache resourceGroupMap) { + CleanupResources cleanupResources, @Region Supplier> regionIds, + PublicIpAvailablePredicateFactory publicIpAvailable, LoadingCache resourceGroupMap, + CustomImageToVMImage customImagetoVmImage) { this.api = api; this.imagePublishers = Splitter.on(',').trimResults().omitEmptyStrings().splitToList(imagePublishers); this.cleanupResources = cleanupResources; this.regionIds = regionIds; this.publicIpAvailable = publicIpAvailable; this.resourceGroupMap = resourceGroupMap; + this.customImagetoVmImage = customImagetoVmImage; } @Override @@ -223,50 +220,30 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listCustomImagesByLocation(String location) { + ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(location); + List customImages = api.getVirtualMachineImageApi(resourceGroup.name()).list(); + return Lists.transform(customImages, customImagetoVmImage); + } @Override public Iterable listImages() { - final List osImages = Lists.newArrayList(); - - final List availableLocationNames = FluentIterable.from(listLocations()) - .transform(new Function() { - @Override public String apply(Location location) { - return location.name(); - } - }).toList(); + final ImmutableList.Builder osImages = ImmutableList.builder(); + + Iterable availableLocationNames = transform(listLocations(), new Function() { + @Override + public String apply(Location location) { + return location.name(); + } + }); for (String locationName : availableLocationNames) { osImages.addAll(listImagesByLocation(locationName)); + osImages.addAll(listCustomImagesByLocation(locationName)); } - // list custom images - for (ResourceGroup resourceGroup : api.getResourceGroupApi().list()) { - String azureGroup = resourceGroup.name(); - List storages = api.getStorageAccountApi(azureGroup).list(); - - for (StorageService storage : storages) { - try { - String name = storage.name(); - 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); - } - } - } catch (Exception ex) { - logger.warn("<< could not get custom images from storage account %s: %s", storage, ex.getMessage()); - } - } - } - - return osImages; + return osImages.build(); } @Override @@ -275,30 +252,8 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter customImagesInStorage = blobHelper.getImages(CONTAINER_NAME, resourceGroup.name(), - 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; + org.jclouds.azurecompute.arm.domain.Image vmImage = api.getVirtualMachineImageApi(resourceGroup.name()).get(image.name()); + return vmImage == null ? null : customImagetoVmImage.apply(vmImage); } String location = image.location(); @@ -313,6 +268,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter { @@ -115,8 +114,6 @@ public class AzureComputeServiceContextModule extends install(new LocationsFromComputeServiceAdapterModule() { }); - install(new FactoryModuleBuilder().build(ResourceDefinitionToCustomImage.Factory.class)); - bind(TemplateOptions.class).to(AzureTemplateOptions.class); bind(NodeAndTemplateOptionsToStatement.class).to(NodeAndTemplateOptionsToStatementWithoutPublicKey.class); bind(CreateNodesInGroupThenAddToSet.class).to(CreateResourceGroupThenCreateNodes.class); @@ -163,9 +160,9 @@ public class AzureComputeServiceContextModule extends @Provides @Named(TIMEOUT_IMAGE_AVAILABLE) - protected Predicate provideImageAvailablePredicate(final AzureComputeApi api, final Timeouts timeouts, + protected Predicate provideImageCapturedPredicate(final AzureComputeApi api, final Timeouts timeouts, final PollPeriod pollPeriod) { - return retry(new ImageDonePredicate(api), timeouts.imageAvailable, pollPeriod.pollInitialPeriod, + return retry(new ImageCapturedPredicate(api), timeouts.imageAvailable, pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); } @@ -196,6 +193,13 @@ public class AzureComputeServiceContextModule extends Predicate> resourceAvailable) { return new SecurityGroupAvailablePredicateFactory(api, resourceAvailable); } + + @Provides + protected ImageAvailablePredicateFactory provideImageAvailablePredicate(final AzureComputeApi api, + Predicate> resourceAvailable, final Timeouts timeouts, final PollPeriod pollPeriod) { + return new ImageAvailablePredicateFactory(api, retry(new ResourceInStatusPredicate("Succeeded"), + timeouts.imageAvailable, pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod)); + } @Provides protected Predicate> provideResourceAvailablePredicate(final AzureComputeApi api, @@ -231,11 +235,11 @@ public class AzureComputeServiceContextModule extends } @VisibleForTesting - static class ImageDonePredicate implements Predicate { + static class ImageCapturedPredicate implements Predicate { private final AzureComputeApi api; - public ImageDonePredicate(final AzureComputeApi api) { + public ImageCapturedPredicate(final AzureComputeApi api) { this.api = checkNotNull(api, "api must not be null"); } @@ -351,5 +355,33 @@ public class AzureComputeServiceContextModule extends }; } } + + public static class ImageAvailablePredicateFactory { + private final AzureComputeApi api; + private final Predicate> resourceAvailable; + + ImageAvailablePredicateFactory(final AzureComputeApi api, + Predicate> resourceAvailable) { + this.api = checkNotNull(api, "api cannot be null"); + this.resourceAvailable = resourceAvailable; + } + + public Predicate create(final String resourceGroup) { + checkNotNull(resourceGroup, "resourceGroup cannot be null"); + return new Predicate() { + @Override + public boolean apply(final String name) { + checkNotNull(name, "name cannot be null"); + return resourceAvailable.apply(new Supplier() { + @Override + public Provisionable get() { + Image img = api.getVirtualMachineImageApi(resourceGroup).get(name); + return img == null ? null : img.properties(); + } + }); + } + }; + } + } } 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 cae2c7eca4..4bfa449fac 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,30 +16,29 @@ */ package org.jclouds.azurecompute.arm.compute.extensions; +import static com.google.common.base.Functions.compose; 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.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; 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.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.ImageAvailablePredicateFactory; import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.VirtualMachineInStatePredicateFactory; -import org.jclouds.azurecompute.arm.compute.functions.ResourceDefinitionToCustomImage; -import org.jclouds.azurecompute.arm.compute.strategy.CleanupResources; +import org.jclouds.azurecompute.arm.compute.functions.CustomImageToVMImage; +import org.jclouds.azurecompute.arm.domain.IdReference; +import org.jclouds.azurecompute.arm.domain.ImageProperties; import org.jclouds.azurecompute.arm.domain.RegionAndId; -import org.jclouds.azurecompute.arm.domain.ResourceDefinition; import org.jclouds.azurecompute.arm.domain.ResourceGroup; -import org.jclouds.azurecompute.arm.domain.StorageServiceKeys; import org.jclouds.azurecompute.arm.domain.VMImage; -import org.jclouds.azurecompute.arm.util.BlobHelper; +import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.compute.domain.CloneImageTemplate; import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.ImageTemplate; @@ -48,6 +47,7 @@ import org.jclouds.compute.extensions.ImageExtension; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.logging.Logger; +import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.cache.LoadingCache; import com.google.common.util.concurrent.ListenableFuture; @@ -56,7 +56,6 @@ 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 @@ -65,26 +64,29 @@ public class AzureComputeImageExtension implements ImageExtension { private final AzureComputeApi api; private final ListeningExecutorService userExecutor; - private final Predicate imageAvailablePredicate; + private final ImageAvailablePredicateFactory imageAvailablePredicate; private final VirtualMachineInStatePredicateFactory nodeSuspendedPredicate; - private final ResourceDefinitionToCustomImage.Factory resourceDefinitionToImage; - private final CleanupResources cleanupResources; private final LoadingCache resourceGroupMap; + private final Function vmImageToImage; + private final Predicate resourceDeleted; + private final CustomImageToVMImage customImagetoVmImage; @Inject AzureComputeImageExtension(AzureComputeApi api, - @Named(TIMEOUT_IMAGE_AVAILABLE) Predicate imageAvailablePredicate, + ImageAvailablePredicateFactory imageAvailablePredicate, @Named(TIMEOUT_NODE_SUSPENDED) VirtualMachineInStatePredicateFactory nodeSuspendedPredicate, @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, - ResourceDefinitionToCustomImage.Factory resourceDefinitionToImage, CleanupResources cleanupResources, - LoadingCache resourceGroupMap) { + Function vmImageToImage, LoadingCache resourceGroupMap, + @Named(TIMEOUT_RESOURCE_DELETED) Predicate resourceDeleted, + CustomImageToVMImage customImagetoVmImage) { this.api = api; this.imageAvailablePredicate = imageAvailablePredicate; this.nodeSuspendedPredicate = nodeSuspendedPredicate; this.userExecutor = userExecutor; - this.resourceDefinitionToImage = resourceDefinitionToImage; - this.cleanupResources = cleanupResources; + this.vmImageToImage = vmImageToImage; this.resourceGroupMap = resourceGroupMap; + this.resourceDeleted = resourceDeleted; + this.customImagetoVmImage = customImagetoVmImage; } @Override @@ -95,11 +97,13 @@ public class AzureComputeImageExtension implements ImageExtension { @Override public ListenableFuture createImage(ImageTemplate template) { final CloneImageTemplate cloneTemplate = (CloneImageTemplate) template; - final RegionAndId regionAndId = RegionAndId.fromSlashEncoded(cloneTemplate.getSourceNodeId()); ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(regionAndId.region()); final String resourceGroupName = resourceGroup.name(); + final VirtualMachine vm = api.getVirtualMachineApi(resourceGroupName).get(regionAndId.id()); + final IdReference vmIdRef = IdReference.create(vm.id()); + logger.debug(">> stopping node %s...", regionAndId.slashEncode()); api.getVirtualMachineApi(resourceGroupName).stop(regionAndId.id()); checkState(nodeSuspendedPredicate.create(resourceGroupName).apply(regionAndId.id()), @@ -109,23 +113,17 @@ public class AzureComputeImageExtension implements ImageExtension { @Override public Image call() throws Exception { logger.debug(">> generalizing virtal machine %s...", regionAndId.id()); + api.getVirtualMachineApi(resourceGroupName).generalize(regionAndId.id()); - logger.debug(">> capturing virtual machine %s to container %s...", regionAndId.id(), CONTAINER_NAME); - URI uri = api.getVirtualMachineApi(resourceGroupName) - .capture(regionAndId.id(), cloneTemplate.getName(), CONTAINER_NAME); - checkState(uri != null && imageAvailablePredicate.apply(uri), + org.jclouds.azurecompute.arm.domain.Image imageFromVM = api.getVirtualMachineImageApi(resourceGroupName) + .createOrUpdate(cloneTemplate.getName(), regionAndId.region(), + ImageProperties.builder().sourceVirtualMachine(vmIdRef).build()); + + checkState(imageAvailablePredicate.create(resourceGroupName).apply(imageFromVM.name()), "Image for node %s was not created within the configured time limit", cloneTemplate.getName()); - 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(cloneTemplate.getSourceNodeId(), cloneTemplate.getName()) - .apply(definitions.get(0)); - checkState(image != null, "Image for node %s was not created", cloneTemplate.getSourceNodeId()); - logger.debug(">> created %s", image); - return image; + return compose(vmImageToImage, customImagetoVmImage).apply(imageFromVM); } }); } @@ -137,25 +135,8 @@ public class AzureComputeImageExtension implements ImageExtension { logger.debug(">> deleting image %s", id); - 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("system"); - boolean result = !blobHelper.customImageExists(); - - 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); - } + ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(image.location()); + URI uri = api.getVirtualMachineImageApi(resourceGroup.name()).delete(image.name()); + return resourceDeleted.apply(uri); } } 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/compute/functions/CustomImageToVMImage.java similarity index 59% rename from providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/functions/StorageProfileToStorageAccountName.java rename to providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/CustomImageToVMImage.java index f624886d66..9cb21882c7 100644 --- 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/compute/functions/CustomImageToVMImage.java @@ -14,25 +14,18 @@ * 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.compute.functions; -import java.net.URI; - -import org.jclouds.azurecompute.arm.domain.StorageProfile; +import org.jclouds.azurecompute.arm.domain.Image; +import org.jclouds.azurecompute.arm.domain.VMImage; 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 { +public class CustomImageToVMImage 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); + public VMImage apply(Image input) { + return VMImage.customImage().customImageId(input.id()).location(input.location()).name(input.name()) + .offer(input.properties().storageProfile().osDisk().osType()).build(); } - } 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 deleted file mode 100644 index c27f5843a4..0000000000 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/ResourceDefinitionToCustomImage.java +++ /dev/null @@ -1,91 +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 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.domain.RegionAndId; -import org.jclouds.azurecompute.arm.domain.ResourceDefinition; -import org.jclouds.azurecompute.arm.domain.ResourceGroup; -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.common.cache.LoadingCache; -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 Function vmImageToImage; - private final String imageName; - private final String nodeId; - private final AzureComputeApi api; - private final StorageProfileToStorageAccountName storageProfileToStorageAccountName; - private final LoadingCache resourceGroupMap; - - @Inject - ResourceDefinitionToCustomImage(AzureComputeApi api, - StorageProfileToStorageAccountName storageProfileToStorageAccountName, - Function vmImageToImage, LoadingCache resourceGroupMap, - @Assisted("nodeId") String nodeId, @Assisted("imageName") String imageName) { - this.api = api; - this.vmImageToImage = vmImageToImage; - this.nodeId = nodeId; - this.imageName = imageName; - this.storageProfileToStorageAccountName = storageProfileToStorageAccountName; - this.resourceGroupMap = resourceGroupMap; - } - - @SuppressWarnings("unchecked") - @Override - public Image apply(ResourceDefinition input) { - RegionAndId regionAndId = RegionAndId.fromSlashEncoded(nodeId); - ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(regionAndId.region()); - - VirtualMachine vm = api.getVirtualMachineApi(resourceGroup.name()).get(regionAndId.id()); - if (vm == null) { - return null; - } - String storageAccountName = storageProfileToStorageAccountName.apply(vm.properties().storageProfile()); - - VMImage.Builder builder = VMImage.customImage().group(resourceGroup.name()).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/TemplateToAvailabilitySet.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/TemplateToAvailabilitySet.java index 141687268c..2732b6e7f4 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/TemplateToAvailabilitySet.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/TemplateToAvailabilitySet.java @@ -87,7 +87,8 @@ public class TemplateToAvailabilitySet implements Function> creating availability set [%s]", options.getAvailabilitySet().name()); availabilitySet = api.getAvailabilitySetApi(resourceGroup).createOrUpdate( - options.getAvailabilitySet().name(), location, tags, options.getAvailabilitySet().properties()); + options.getAvailabilitySet().name(), options.getAvailabilitySet().sku(), location, tags, + options.getAvailabilitySet().properties()); } } 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 25bcc3b880..4f021002b3 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 @@ -19,6 +19,7 @@ package org.jclouds.azurecompute.arm.compute.functions; import java.util.Map; import java.util.Set; +import org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageExtension; import org.jclouds.azurecompute.arm.domain.ImageReference; import org.jclouds.azurecompute.arm.domain.Plan; import org.jclouds.azurecompute.arm.domain.VMImage; @@ -55,20 +56,25 @@ public class VMImageToImage implements Function { private final Supplier> locations; - public static String encodeFieldsToUniqueId(boolean globallyAvailable, String locatioName, + public static String encodeFieldsToUniqueId(boolean globallyAvailable, String locationName, ImageReference imageReference) { - return (globallyAvailable ? "global" : locatioName) + "/" + imageReference.publisher() + "/" + return (globallyAvailable ? "global" : locationName) + "/" + imageReference.publisher() + "/" + imageReference.offer() + "/" + imageReference.sku(); } + public static String encodeFieldsToUniqueIdCustom(boolean globallyAvailable, String locationName, + ImageReference imageReference) { + return (globallyAvailable ? "global" : locationName) + "/" + imageReference.customImageId() + .substring(imageReference.customImageId().lastIndexOf("/") + 1); + } + 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.offer() + "/" + imageReference.name(); + return (imageReference.globallyAvailable() ? "global" : imageReference.location()) + "/" + imageReference.name(); } public static VMImage decodeFieldsFromUniqueId(final String id) { @@ -76,17 +82,13 @@ public class VMImageToImage implements Function { String[] fields = checkNotNull(id, "id").split("/"); if (isCustom(id)) { /* id fields indexes - 0: imageReference.location) + "/" + - 1: imageReference.group + "/" + - 2: imageReference.storage + "/" + - 3: imageReference.offer + "/" + - 4: imageReference.name + 0: imageReference.location + "/" + + 1: imageReference.name */ - vmImage = VMImage.customImage().location(fields[0]).group(fields[1]).storage(fields[2]).vhd1(fields[3]) - .offer(fields[4]).build(); + vmImage = VMImage.customImage().location(fields[0]).name(fields[1]).build(); } else { /* id fields indexes - 0: imageReference.location) + "/" + + 0: imageReference.location + "/" + 1: imageReference.publisher + "/" + 2: imageReference.offer + "/" + 3: imageReference.sku + "/" + @@ -98,7 +100,7 @@ public class VMImageToImage implements Function { } @Inject - VMImageToImage(@Memoized final Supplier> locations) { + VMImageToImage(@Memoized Supplier> locations) { this.locations = locations; } @@ -110,7 +112,7 @@ public class VMImageToImage implements Function { builder.location( FluentIterable.from(locations.get()).firstMatch(LocationPredicates.idEquals(image.location())) .get()).name(image.name()).description(image.group()).status(Image.Status.AVAILABLE) - .version("latest").providerId(image.vhd1()).id(encodeFieldsToUniqueIdCustom(image)); + .version("latest").providerId(image.customImageId()).id(encodeFieldsToUniqueIdCustom(image)); final OperatingSystem.Builder osBuilder = osFamily().apply(image); builder.operatingSystem(osBuilder.build()); @@ -165,7 +167,7 @@ public class VMImageToImage implements Function { // only 64bit OS images are supported by Azure ARM return OperatingSystem.builder().family(family).is64Bit(true) - .description(image.custom() ? image.vhd1() : image.sku()) + .description(image.custom() ? AzureComputeImageExtension.CUSTOM_IMAGE_OFFER : 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 index cb40a149d7..9bad6e57e1 100644 --- 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 @@ -16,6 +16,15 @@ */ package org.jclouds.azurecompute.arm.compute.functions; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Strings.nullToEmpty; +import static com.google.common.collect.Iterables.find; +import static org.jclouds.azurecompute.arm.compute.AzureComputeServiceAdapter.GROUP_KEY; +import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.encodeFieldsToUniqueId; +import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.encodeFieldsToUniqueIdCustom; +import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromCommaDelimitedValue; +import static org.jclouds.location.predicates.LocationPredicates.idEquals; + import java.util.List; import java.util.Map; import java.util.Set; @@ -33,11 +42,7 @@ import org.jclouds.azurecompute.arm.domain.PublicIPAddress; import org.jclouds.azurecompute.arm.domain.RegionAndId; import org.jclouds.azurecompute.arm.domain.ResourceGroup; 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.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; @@ -59,18 +64,6 @@ import com.google.common.cache.LoadingCache; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Strings.nullToEmpty; -import static com.google.common.collect.Iterables.find; -import static com.google.common.collect.Iterables.tryFind; -import static org.jclouds.azurecompute.arm.compute.AzureComputeServiceAdapter.GROUP_KEY; -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.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromCommaDelimitedValue; -import static org.jclouds.location.predicates.LocationPredicates.idEquals; -import static org.jclouds.util.Closeables2.closeQuietly; - public class VirtualMachineToNodeMetadata implements Function { @Resource @@ -81,8 +74,6 @@ public class VirtualMachineToNodeMetadata implements Function> locations; private final Supplier> hardwares; - private final Function vmImageToImge; - private final StorageProfileToStorageAccountName storageProfileToStorageAccountName; private final LoadingCache resourceGroupMap; private final ImageCacheSupplier imageCache; private final VirtualMachineToStatus virtualMachineToStatus; @@ -90,16 +81,12 @@ public class VirtualMachineToNodeMetadata implements Function> hardwares, @Memoized Supplier> locations, - Map credentialStore, Function vmImageToImge, - StorageProfileToStorageAccountName storageProfileToStorageAccountName, - LoadingCache resourceGroupMap, @Memoized Supplier> imageCache, - VirtualMachineToStatus virtualMachineToStatus) { + Map credentialStore, LoadingCache resourceGroupMap, + @Memoized Supplier> imageCache, VirtualMachineToStatus virtualMachineToStatus) { this.api = api; this.nodeNamingConvention = namingConvention.createWithoutPrefix(); this.locations = locations; this.hardwares = hardwares; - this.vmImageToImge = vmImageToImge; - this.storageProfileToStorageAccountName = storageProfileToStorageAccountName; this.resourceGroupMap = resourceGroupMap; this.virtualMachineToStatus = virtualMachineToStatus; checkArgument(imageCache instanceof ImageCacheSupplier, @@ -207,29 +194,14 @@ public class VirtualMachineToNodeMetadata implements Function findImage(final StorageProfile storageProfile, String locatioName, String azureGroup) { if (storageProfile.imageReference() != null) { - String imageId = encodeFieldsToUniqueId(false, locatioName, storageProfile.imageReference()); + // FIXME check this condition + String imageId = storageProfile.imageReference().customImageId() != null ? + encodeFieldsToUniqueIdCustom(false, locatioName, storageProfile.imageReference()) : + encodeFieldsToUniqueId(false, locatioName, storageProfile.imageReference()); return imageCache.get(imageId); } 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); - } + logger.warn("could not find image for storage profile %s", storageProfile); + return Optional.absent(); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java index 481f695866..fb635aa67d 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java @@ -16,6 +16,11 @@ */ package org.jclouds.azurecompute.arm.compute.strategy; +import static com.google.common.base.Predicates.notNull; +import static com.google.common.collect.Iterables.filter; +import static com.google.common.collect.Iterables.transform; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; + import java.net.URI; import java.util.List; @@ -32,11 +37,8 @@ import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; import org.jclouds.azurecompute.arm.domain.RegionAndId; 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.features.NetworkSecurityGroupApi; -import org.jclouds.azurecompute.arm.functions.StorageProfileToStorageAccountName; -import org.jclouds.azurecompute.arm.util.BlobHelper; import org.jclouds.compute.functions.GroupNamingConvention; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.logging.Logger; @@ -48,12 +50,6 @@ import com.google.common.cache.LoadingCache; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; -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.util.Closeables2.closeQuietly; - @Singleton public class CleanupResources { @@ -63,17 +59,14 @@ public class CleanupResources { private final AzureComputeApi api; private final Predicate resourceDeleted; - private final StorageProfileToStorageAccountName storageProfileToStorageAccountName; private final LoadingCache resourceGroupMap; private final GroupNamingConvention.Factory namingConvention; @Inject CleanupResources(AzureComputeApi azureComputeApi, @Named(TIMEOUT_RESOURCE_DELETED) Predicate resourceDeleted, - StorageProfileToStorageAccountName storageProfileToStorageAccountName, LoadingCache resourceGroupMap, GroupNamingConvention.Factory namingConvention) { this.api = azureComputeApi; this.resourceDeleted = resourceDeleted; - this.storageProfileToStorageAccountName = storageProfileToStorageAccountName; this.resourceGroupMap = resourceGroupMap; this.namingConvention = namingConvention; } @@ -95,7 +88,6 @@ public class CleanupResources { // group. It will be deleted when the resource group is deleted cleanupVirtualMachineNICs(resourceGroupName, virtualMachine); - cleanupVirtualMachineStorage(resourceGroupName, virtualMachine); cleanupAvailabilitySetIfOrphaned(resourceGroupName, virtualMachine); return vmDeleted; @@ -117,28 +109,6 @@ public class CleanupResources { } } - public void cleanupVirtualMachineStorage(String group, VirtualMachine virtualMachine) { - 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); - } - } - public boolean cleanupSecurityGroupIfOrphaned(String resourceGroup, String group) { String name = namingConvention.create().sharedNameForGroup(group); NetworkSecurityGroupApi sgapi = api.getNetworkSecurityGroupApi(resourceGroup); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/AvailabilitySet.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/AvailabilitySet.java index 624c6640cb..4c4720e76c 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/AvailabilitySet.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/AvailabilitySet.java @@ -90,6 +90,47 @@ public abstract class AvailabilitySet { } } } + + public static enum AvailabilitySetType { + MANAGED("Aligned"), + CLASSIC("Classic"); + + private final String value; + + AvailabilitySetType(String value) { + this.value = value; + } + + public static AvailabilitySetType fromString(String value) { + AvailabilitySetType[] items = AvailabilitySetType.values(); + for (AvailabilitySetType item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + throw new IllegalArgumentException("Unexpected type: " + value); + } + + @Override + public String toString() { + return this.value; + } + } + + @AutoValue + public abstract static class SKU { + + public abstract AvailabilitySetType type(); + + @SerializedNames({ "name" }) + public static SKU create(final String type) { + return create(AvailabilitySetType.fromString(type)); + } + + public static SKU create(AvailabilitySetType type) { + return new AutoValue_AvailabilitySet_SKU(type); + } + } /** * The id of the availability set @@ -115,31 +156,45 @@ public abstract class AvailabilitySet { @Nullable public abstract String location(); + /** + * Specifies the type of the availability set + */ + @Nullable + public abstract SKU sku(); + /** * Specifies the tags of the availability set */ @Nullable public abstract Map tags(); - + /** * Specifies the properties of the availability set */ @Nullable public abstract AvailabilitySetProperties properties(); - - @SerializedNames({"id", "name", "type", "location", "tags", "properties"}) + @SerializedNames({ "id", "name", "type", "location", "sku", "tags", "properties" }) public static AvailabilitySet create(final String id, final String name, final String type, final String location, - final Map tags, AvailabilitySetProperties properties) { - return builder().id(id).name(name).type(type).location(location).tags(tags).properties(properties).build(); + SKU sku, final Map tags, AvailabilitySetProperties properties) { + return builder().id(id).name(name).type(type).location(location).sku(sku).tags(tags).properties(properties) + .build(); } public abstract Builder toBuilder(); - public static Builder builder() { + private static Builder builder() { return new AutoValue_AvailabilitySet.Builder(); } + public static Builder managed() { + return builder().managed(); + } + + public static Builder classic() { + return builder().classic(); + } + @AutoValue.Builder public abstract static class Builder { public abstract Builder id(String id); @@ -149,6 +204,14 @@ public abstract class AvailabilitySet { public abstract Builder tags(Map tags); public abstract Builder properties(AvailabilitySetProperties properties); + abstract Builder sku(SKU sku); + public Builder managed() { + return sku(SKU.create(AvailabilitySetType.MANAGED)); + } + public Builder classic() { + return sku(SKU.create(AvailabilitySetType.CLASSIC)); + } + abstract Map tags(); abstract AvailabilitySet autoBuild(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Image.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Image.java index 5d9226b5dd..b442617de9 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Image.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Image.java @@ -26,6 +26,18 @@ import com.google.common.collect.ImmutableMap; @AutoValue public abstract class Image { + + /** + * The id of the image + */ + @Nullable + public abstract String id(); + + /** + * The name of the image + */ + @Nullable + public abstract String name(); /** * The location of the image @@ -42,9 +54,10 @@ public abstract class Image { */ @Nullable public abstract Map tags(); - @SerializedNames({"location", "properties", "tags"}) - public static Image create(final String location, final ImageProperties properties, final Map tags) { - return builder().location(location).properties(properties).tags(tags).build(); + @SerializedNames({"id", "name", "location", "properties", "tags"}) + public static Image create(final String id, final String name, final String location, + final ImageProperties properties, final Map tags) { + return builder().id(id).name(name).location(location).properties(properties).tags(tags).build(); } public abstract Builder toBuilder(); @@ -55,10 +68,10 @@ public abstract class Image { @AutoValue.Builder public abstract static class Builder { + public abstract Builder id(String id); + public abstract Builder name(String name); public abstract Builder location(String location); - public abstract Builder properties(ImageProperties properties); - public abstract Builder tags(Map tags); abstract Map tags(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageProperties.java index ef877bea40..44cb16ef28 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageProperties.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageProperties.java @@ -24,17 +24,8 @@ import com.google.auto.value.AutoValue; @AutoValue public abstract class ImageProperties implements Provisionable { - @AutoValue - public abstract static class SourceVirtualMachine { - public abstract String id(); - - @SerializedNames({"id"}) - public static SourceVirtualMachine create(final String id) { - return new AutoValue_ImageProperties_SourceVirtualMachine(id); - } - } - - public abstract SourceVirtualMachine sourceVirtualMachine(); + @Nullable + public abstract IdReference sourceVirtualMachine(); @Nullable public abstract StorageProfile storageProfile(); @@ -43,7 +34,7 @@ public abstract class ImageProperties implements Provisionable { public abstract String provisioningState(); @SerializedNames({ "sourceVirtualMachine", "storageProfile", "provisioningState"}) - public static ImageProperties create(final SourceVirtualMachine sourceVirtualMachine, + public static ImageProperties create(final IdReference sourceVirtualMachine, final StorageProfile storageProfile, final String provisioningState) { return builder() @@ -61,7 +52,7 @@ public abstract class ImageProperties implements Provisionable { @AutoValue.Builder public abstract static class Builder { - public abstract Builder sourceVirtualMachine(SourceVirtualMachine sourceVirtualMachine); + public abstract Builder sourceVirtualMachine(IdReference sourceVirtualMachine); public abstract Builder storageProfile(StorageProfile storageProfile); public abstract Builder provisioningState(String provisioningState); public abstract ImageProperties build(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java index 443e054a9e..d9b43cd5ee 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java @@ -25,11 +25,12 @@ import com.google.auto.value.AutoValue; public abstract class ImageReference { /** - * The id of the image reference. + * Specifies the resource identifier of a virtual machine image in your subscription. This element is only used + * for virtual machine images, not platform images or marketplace images. */ @Nullable - public abstract String id(); - + public abstract String customImageId(); + /** * The publisher of the image reference. */ @@ -53,6 +54,10 @@ public abstract class ImageReference { */ @Nullable public abstract String version(); + + ImageReference() { + + } @SerializedNames({"id", "publisher", "offer", "sku", "version"}) public static ImageReference create(final String id, @@ -61,8 +66,7 @@ public abstract class ImageReference { final String sku, final String version) { - return builder() - .id(id) + return builder().customImageId(id) .publisher(publisher) .offer(offer) .sku(sku) @@ -78,7 +82,7 @@ public abstract class ImageReference { @AutoValue.Builder public abstract static class Builder { - public abstract Builder id(String id); + public abstract Builder customImageId(String ids); public abstract Builder publisher(String publisher); public abstract Builder offer(String offer); public abstract Builder sku(String sku); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ManagedDiskParameters.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ManagedDiskParameters.java index 84cbab1477..a8a0ae30be 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ManagedDiskParameters.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ManagedDiskParameters.java @@ -24,42 +24,13 @@ import com.google.auto.value.AutoValue; @AutoValue public abstract class ManagedDiskParameters { - public enum StorageAccountTypes { - /** Enum value Standard_LRS. */ - STANDARD_LRS("Standard_LRS"), - - /** Enum value Premium_LRS. */ - PREMIUM_LRS("Premium_LRS"); - - /** The actual serialized value for a StorageAccountTypes instance. */ - private String value; - - StorageAccountTypes(String value) { - this.value = value; - } - - public static StorageAccountTypes fromString(String value) { - StorageAccountTypes[] items = StorageAccountTypes.values(); - for (StorageAccountTypes item : items) { - if (item.toString().equalsIgnoreCase(value)) { - return item; - } - } - return null; - } - - @Override - public String toString() { - return this.value; - } - } - @Nullable public abstract String id(); - public abstract StorageAccountTypes storageAccountType(); + // Might be null in custom images. In that case the API returns it in the OSDisk object. + @Nullable public abstract StorageAccountType storageAccountType(); @SerializedNames({"id", "storageAccountType"}) public static ManagedDiskParameters create(final String id, final String storageAccountType) { - return new AutoValue_ManagedDiskParameters(id, StorageAccountTypes.fromString(storageAccountType)); + return new AutoValue_ManagedDiskParameters(id, StorageAccountType.fromString(storageAccountType)); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java index c87fe7556b..20392a05d9 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSDisk.java @@ -64,21 +64,20 @@ public abstract class OSDisk { */ @Nullable public abstract ManagedDiskParameters managedDiskParameters(); - @SerializedNames({"osType", "name", "vhd", "caching", "createOption", "image", "managedDisk"}) - public static OSDisk create(final String osType, final String name, final VHD vhd, - final String caching, final String createOption, final VHD image, - final ManagedDiskParameters managedDiskParamenters) { - return builder() - .osType(osType) - .name(name) - .vhd(vhd) - .caching(caching) - .createOption(createOption) - .image(image) - .managedDiskParameters(managedDiskParamenters) - .build(); + /** + * The storage account type. This field is returned in custom images. + */ + @Nullable public abstract StorageAccountType storageAccountType(); + + @SerializedNames({ "osType", "name", "vhd", "caching", "createOption", "image", "managedDisk", "storageAccountType" }) + public static OSDisk create(final String osType, final String name, final VHD vhd, final String caching, + final String createOption, final VHD image, final ManagedDiskParameters managedDiskParamenters, + final String storageAccountType) { + return builder().osType(osType).name(name).vhd(vhd).caching(caching).createOption(createOption).image(image) + .managedDiskParameters(managedDiskParamenters) + .storageAccountType(StorageAccountType.fromString(storageAccountType)).build(); } - + public abstract Builder toBuilder(); public static Builder builder() { @@ -94,6 +93,7 @@ public abstract class OSDisk { public abstract Builder vhd(VHD vhd); public abstract Builder image(VHD image); public abstract Builder managedDiskParameters(ManagedDiskParameters managedDiskParameters); + public abstract Builder storageAccountType(StorageAccountType storageAccountType); public abstract OSDisk build(); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageAccountType.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageAccountType.java new file mode 100644 index 0000000000..33e11099ef --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/StorageAccountType.java @@ -0,0 +1,47 @@ +/* + * 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; + +public enum StorageAccountType { + /** Enum value Standard_LRS. */ + STANDARD_LRS("Standard_LRS"), + + /** Enum value Premium_LRS. */ + PREMIUM_LRS("Premium_LRS"); + + /** The actual serialized value for a StorageAccountTypes instance. */ + private String value; + + StorageAccountType(String value) { + this.value = value; + } + + public static StorageAccountType fromString(String value) { + StorageAccountType[] items = StorageAccountType.values(); + for (StorageAccountType item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + @Override + public String toString() { + return this.value; + } +} 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 04863ad9bd..a01ed23467 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 @@ -87,12 +87,18 @@ public abstract class VMImage { */ @Nullable public abstract String name(); - + /** * True if custom image */ public abstract boolean custom(); - + + /** + * The id of the custom image template. + */ + @Nullable + public abstract String customImageId(); + /** * Extended version properties. */ @@ -104,18 +110,23 @@ public abstract class VMImage { } public static Builder azureImage() { - return new AutoValue_VMImage.Builder().globallyAvailable(false).custom(false); + return builder().globallyAvailable(false).custom(false); } public static Builder customImage() { - return new AutoValue_VMImage.Builder().globallyAvailable(false).custom(true); + return builder().globallyAvailable(false).custom(true); + } + + VMImage() { + } public abstract Builder toBuilder(); @AutoValue.Builder public abstract static class Builder { - + + public abstract Builder customImageId(String id); public abstract Builder publisher(String published); public abstract Builder offer(String offer); public abstract Builder sku(String sku); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApi.java index 30456d47c9..cf5116c38b 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApi.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApi.java @@ -28,13 +28,13 @@ 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.AvailabilitySet; import org.jclouds.azurecompute.arm.domain.AvailabilitySet.AvailabilitySetProperties; +import org.jclouds.azurecompute.arm.domain.AvailabilitySet.SKU; import org.jclouds.azurecompute.arm.filters.ApiVersionFilter; import org.jclouds.azurecompute.arm.functions.URIParser; import org.jclouds.javax.annotation.Nullable; @@ -65,12 +65,13 @@ public interface AvailabilitySetApi extends Closeable { AvailabilitySet get(@PathParam("name") String name); @Named("availabilityset:createOrUpdate") + @MapBinder(BindToJsonPayload.class) @Path("/{name}") @PUT - @MapBinder(BindToJsonPayload.class) - @Produces(MediaType.APPLICATION_JSON) AvailabilitySet createOrUpdate(@PathParam("name") String name, - @PayloadParam("location") String location, @Nullable @PayloadParam("tags") Map tags, + @Nullable @PayloadParam("sku") SKU sku, + @PayloadParam("location") String location, + @Nullable @PayloadParam("tags") Map tags, @PayloadParam("properties") AvailabilitySetProperties properties); @Named("availabilityset:delete") 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 8d446a5d58..1ff43deeba 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 @@ -60,11 +60,11 @@ public interface DeploymentApi { */ @Named("deployment:create") @Path("/{deploymentname}") - @Payload("{properties}") + @Payload("{template}") @PUT @Produces(MediaType.APPLICATION_JSON) Deployment create(@PathParam("deploymentname") String deploymentname, - @PayloadParam("properties") String properties); + @PayloadParam("template") String template); /** * Get Deployment Information returns information about the specified deployment. @@ -80,11 +80,11 @@ public interface DeploymentApi { */ @Named("deployment:validate") @Path("/{deploymentname}/validate") - @Payload("{properties}") + @Payload("{template}") @POST @Produces(MediaType.APPLICATION_JSON) Deployment validate(@PathParam("deploymentname") String deploymentname, - @PayloadParam("properties") String properties); + @PayloadParam("template") String template); /** * List all deployments in a resource group diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/DiskApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/DiskApi.java index 0797dbd47f..10e9ac633f 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/DiskApi.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/DiskApi.java @@ -26,7 +26,6 @@ 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; @@ -38,7 +37,6 @@ 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.Payload; import org.jclouds.rest.annotations.PayloadParam; import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.ResponseParser; @@ -58,10 +56,8 @@ public interface DiskApi { @Named("disk:create_or_update") @PUT - @Payload("%7B\"location\":\"{location}\",\"properties\":{properties}%7D") @MapBinder(BindToJsonPayload.class) @Path("/{diskName}") - @Produces(MediaType.APPLICATION_JSON) Disk createOrUpdate(@PathParam("diskName") String diskName, @PayloadParam("location") String location, @PayloadParam("properties") DiskProperties properties); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ImageApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ImageApi.java index c97b0ac65f..96caa4029c 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ImageApi.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/ImageApi.java @@ -26,7 +26,6 @@ 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; @@ -38,7 +37,6 @@ 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.Payload; import org.jclouds.rest.annotations.PayloadParam; import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.ResponseParser; @@ -58,10 +56,8 @@ public interface ImageApi { @Named("image:create_or_update") @PUT - @Payload("%7B\"location\":\"{location}\",\"properties\":{properties}%7D") @MapBinder(BindToJsonPayload.class) @Path("/{imageName}") - @Produces(MediaType.APPLICATION_JSON) Image createOrUpdate(@PathParam("imageName") String imageName, @PayloadParam("location") String location, @PayloadParam("properties") ImageProperties properties); 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 3c3bab9bf3..5a01e90f4d 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 @@ -40,7 +40,8 @@ import org.jclouds.rest.annotations.SelectJson; @RequestFilters(OAuthFilter.class) @Consumes(MediaType.APPLICATION_JSON) -public interface JobApi extends Closeable{ +public interface JobApi extends Closeable { + @GET @ResponseParser(ParseJobStatus.class) JobStatus jobStatus(@EndpointParam URI jobURI); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/LoadBalancerApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/LoadBalancerApi.java index f0ea900f9f..f9805c05c4 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/LoadBalancerApi.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/LoadBalancerApi.java @@ -27,7 +27,6 @@ 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; @@ -67,7 +66,6 @@ public interface LoadBalancerApi { @Path("/{loadbalancername}") @PUT @MapBinder(BindToJsonPayload.class) - @Produces(MediaType.APPLICATION_JSON) LoadBalancer createOrUpdate(@PathParam("loadbalancername") String lbName, @PayloadParam("location") String location, @Nullable @PayloadParam("tags") Map tags, @PayloadParam("properties") LoadBalancerProperties properties); 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 ba4c2cd35a..41c0c856df 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 @@ -27,7 +27,6 @@ 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; @@ -68,7 +67,6 @@ public interface NetworkSecurityGroupApi { @Path("/{networksecuritygroupname}") @PUT @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); 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 8def4e3cd1..7404234c43 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 @@ -26,7 +26,6 @@ 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; @@ -48,11 +47,11 @@ import org.jclouds.rest.binders.BindToJsonPayload; @RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) @Consumes(MediaType.APPLICATION_JSON) public interface NetworkSecurityRuleApi { + @Named("networksecurityrule:createOrUpdate") @Path("/securityRules/{networksecurityrulename}") @PUT @MapBinder(BindToJsonPayload.class) - @Produces(MediaType.APPLICATION_JSON) NetworkSecurityRule createOrUpdate(@PathParam("networksecurityrulename") String ruleName, @PayloadParam("properties") NetworkSecurityRuleProperties properties); 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 2c6a8b3904..7c516216ea 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 @@ -28,7 +28,6 @@ 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; @@ -67,7 +66,6 @@ public interface ResourceGroupApi extends Closeable{ @Named("resourcegroup:create") @PUT @Path("/{name}") - @Produces(MediaType.APPLICATION_JSON) @MapBinder(BindToJsonPayload.class) ResourceGroup create(@PathParam("name") String name, @PayloadParam("location") String location, @Nullable @PayloadParam("tags") Map tags); @@ -87,7 +85,6 @@ public interface ResourceGroupApi extends Closeable{ @Named("resourcegroup:update") @PATCH - @Produces(MediaType.APPLICATION_JSON) @Path("/{name}") @MapBinder(BindToJsonPayload.class) ResourceGroup update(@PathParam("name") String name, @Nullable @PayloadParam("tags") Map tags); 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 a25e2a507e..56dd0d4bf9 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 @@ -16,7 +16,6 @@ */ package org.jclouds.azurecompute.arm.features; - import java.io.Closeable; import java.util.List; 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 5d2e06c6db..0c9399cfdd 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 @@ -79,9 +79,7 @@ public interface StorageAccountApi { * PUT */ @Named("storageaccount:create") - @Payload("%7B\"location\":\"{location}\",\"tags\":{tags},\"properties\":{properties}%7D") @Path("/resourcegroups/{resourceGroup}/providers/Microsoft.Storage/storageAccounts/{storageAccountName}") - @Produces(MediaType.APPLICATION_JSON) @ResponseParser(URIParser.class) @MapBinder(BindToJsonPayload.class) @PUT @@ -120,7 +118,6 @@ public interface StorageAccountApi { @Named("storageaccountkey:get") @POST @Path("/resourcegroups/{resourceGroup}/providers/Microsoft.Storage/storageAccounts/{storageAccountName}/listKeys") - @Produces(MediaType.APPLICATION_JSON) @Fallback(Fallbacks.NullOnNotFoundOr404.class) StorageServiceKeys getKeys(@PathParam("storageAccountName") String storageAccountName); @@ -143,10 +140,8 @@ public interface StorageAccountApi { */ @Named("storageaccount:update") @PATCH - @Payload("%7B\"tags\":{tags},\"properties\":{properties}%7D") @MapBinder(BindToJsonPayload.class) @Path("/resourcegroups/{resourceGroup}/providers/Microsoft.Storage/storageAccounts/{storageAccountName}") - @Produces(MediaType.APPLICATION_JSON) StorageServiceUpdateParams update( @PathParam("storageAccountName") String storageAccountName, @Nullable @PayloadParam("tags") Map tags, 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 c87390e8dc..39ed860d45 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 @@ -77,11 +77,9 @@ public interface VirtualMachineApi { @Named("CreateOrUpdateVirtualMachine") @PUT - @Payload("%7B\"location\":\"{location}\",\"tags\":{tags},\"properties\":{properties},\"plan\":{plan}%7D") @MapBinder(BindToJsonPayload.class) @Path("/{vmname}") @QueryParams(keys = "validating", values = "false") - @Produces(MediaType.APPLICATION_JSON) VirtualMachine createOrUpdate(@PathParam("vmname") String vmname, @PayloadParam("location") String location, @PayloadParam("properties") VirtualMachineProperties properties, @@ -130,10 +128,10 @@ public interface VirtualMachineApi { @Named("capture") @POST @Payload("%7B\"vhdPrefix\":\"{vhdPrefix}\",\"destinationContainerName\":\"{destinationContainerName}\",\"overwriteVhds\":\"true\"%7D") - @MapBinder(BindToJsonPayload.class) @Path("/{name}/capture") @ResponseParser(URIParser.class) @Fallback(Fallbacks.NullOnNotFoundOr404.class) + @Produces(MediaType.APPLICATION_JSON) URI capture(@PathParam("name") String name, @PayloadParam("vhdPrefix") String vhdPrefix, @PayloadParam("destinationContainerName") String destinationContainerName); 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 deleted file mode 100644 index b42ea5e9d0..0000000000 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/BlobHelper.java +++ /dev/null @@ -1,83 +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 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.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; - -public class BlobHelper implements Closeable { - - private final String storageAccount; - private final AzureBlobClient azureBlob; - - public BlobHelper(String storageAccount, String key) { - this.storageAccount = storageAccount; - this.azureBlob = ContextBuilder.newBuilder("azureblob").credentials(storageAccount, key) - .buildApi(AzureBlobClient.class); - } - - @Override - public void close() throws IOException { - closeQuietly(azureBlob); - } - - 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(); - - ContainerProperties systemContainer = azureBlob.getContainerProperties("system"); - if (systemContainer != null) { - ListBlobsResponse blobList = azureBlob.listBlobs(systemContainer.getName()); - for (BlobProperties blob : blobList) { - String name = blob.getName(); - - if (name.contains("-osDisk")) { - String imageName = name.substring(name.lastIndexOf('/') + 1, name.indexOf("-osDisk")); - String imageUrl = blob.getUrl().toString(); - - list.add(VMImage.customImage().group(group).storage(storageAccount).vhd1(imageUrl).name(imageName) - .offer(offer).location(location).build()); - } - } - } - - return list; - } - -} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/VMImages.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/VMImages.java index d5b63943ad..a5944ecd8e 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/VMImages.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/VMImages.java @@ -21,7 +21,7 @@ import static com.google.common.base.Preconditions.checkNotNull; public class VMImages { public static boolean isCustom(String imageId) { - return checkNotNull(imageId, "id").split("/").length == 5; + return checkNotNull(imageId, "id").split("/").length == 2; } } 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 9c2427c2bf..7c5c97fa63 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,8 +16,11 @@ */ package org.jclouds.azurecompute.arm.compute; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; import static org.jclouds.compute.options.TemplateOptions.Builder.authorizePublicKey; +import static org.testng.Assert.assertTrue; +import java.net.URI; import java.util.Properties; import org.jclouds.azurecompute.arm.AzureComputeApi; @@ -38,10 +41,12 @@ import org.jclouds.sshj.config.SshjSshClientModule; import org.testng.annotations.AfterClass; import org.testng.annotations.Test; +import com.google.common.base.Predicate; import com.google.common.cache.LoadingCache; import com.google.inject.Key; import com.google.inject.Module; import com.google.inject.TypeLiteral; +import com.google.inject.name.Names; /** * Live tests for the {@link org.jclouds.compute.ComputeService} integration. @@ -50,6 +55,7 @@ import com.google.inject.TypeLiteral; public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest { private LoadingCache resourceGroupMap; + private Predicate resourceDeleted; public AzureComputeServiceLiveTest() { provider = "azurecompute-arm"; @@ -61,6 +67,8 @@ public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest { resourceGroupMap = context.utils().injector() .getInstance(Key.get(new TypeLiteral>() { })); + resourceDeleted = context.utils().injector().getInstance(Key.get(new TypeLiteral>() { + }, Names.named(TIMEOUT_RESOURCE_DELETED))); } @Override @@ -71,7 +79,11 @@ public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest { ResourceGroup rg = resourceGroupMap.getIfPresent(template.getLocation().getId()); if (rg != null) { AzureComputeApi api = view.unwrapApi(AzureComputeApi.class); - api.getResourceGroupApi().delete(rg.name()); + URI uri = api.getResourceGroupApi().delete(rg.name()); + if (uri != null) { + assertTrue(resourceDeleted.apply(uri), + String.format("Resource %s was not terminated in the configured timeout", uri)); + } } } } finally { @@ -97,7 +109,7 @@ public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest { @Override protected Properties setupProperties() { Properties properties = super.setupProperties(); - AzureLiveTestUtils.defaultProperties(properties); + AzureLiveTestUtils.defaultProperties(properties, getClass().getSimpleName().toLowerCase()); setIfTestSystemPropertyPresent(properties, "oauth.endpoint"); return properties; } 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 56200c485b..d4cbdb07e7 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 @@ -56,7 +56,7 @@ public class AzureTemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest { @Override protected Properties setupProperties() { Properties properties = super.setupProperties(); - AzureLiveTestUtils.defaultProperties(properties); + AzureLiveTestUtils.defaultProperties(properties, getClass().getSimpleName().toLowerCase()); setIfTestSystemPropertyPresent(properties, "oauth.endpoint"); return properties; } @@ -65,8 +65,8 @@ public class AzureTemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest { @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: " + assertTrue(defaultTemplate.getImage().getOperatingSystem().getVersion().matches("1[456]\\.[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); 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 a6d19fabf1..d708723afb 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 @@ -17,7 +17,12 @@ package org.jclouds.azurecompute.arm.compute.extensions; import static org.jclouds.compute.options.TemplateOptions.Builder.authorizePublicKey; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; +import static org.jclouds.compute.options.RunScriptOptions.Builder.wrapInInitScript; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import java.net.URI; import java.util.Map; import java.util.Properties; @@ -26,18 +31,23 @@ import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; import org.jclouds.compute.ComputeTestUtils; +import org.jclouds.compute.domain.ExecResponse; +import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.extensions.internal.BaseImageExtensionLiveTest; import org.jclouds.domain.Location; import org.jclouds.providers.ProviderMetadata; import org.jclouds.sshj.config.SshjSshClientModule; import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import com.google.common.base.Predicate; import com.google.common.cache.LoadingCache; import com.google.inject.Key; import com.google.inject.Module; import com.google.inject.TypeLiteral; +import com.google.inject.name.Names; /** * Live tests for the {@link org.jclouds.compute.extensions.ImageExtension} @@ -45,38 +55,51 @@ import com.google.inject.TypeLiteral; */ @Test(groups = "live", singleThreaded = true, testName = "AzureComputeImageExtensionLiveTest") public class AzureComputeImageExtensionLiveTest extends BaseImageExtensionLiveTest { - - public static final String NAME_PREFIX = "%s"; - - private LoadingCache resourceGroupMap; + private LoadingCache resourceGroupMap; + private Predicate resourceDeleted; + private ResourceGroup testResourceGroup; + public AzureComputeImageExtensionLiveTest() { provider = "azurecompute-arm"; } - - @Override - public void initializeContext() { - super.initializeContext(); + + @BeforeClass(groups = { "integration", "live" }) + public void setupContext() { + super.setupContext(); resourceGroupMap = context.utils().injector() .getInstance(Key.get(new TypeLiteral>() { })); + resourceDeleted = context.utils().injector().getInstance(Key.get(new TypeLiteral>() { + }, Names.named(TIMEOUT_RESOURCE_DELETED))); + createResourceGroup(); } - + + @AfterClass(groups = { "integration", "live" }) @Override - @AfterClass(groups = "live", alwaysRun = true) protected void tearDownContext() { try { - Location location = getNodeTemplate().build().getLocation(); - ResourceGroup rg = resourceGroupMap.getIfPresent(location.getId()); - if (rg != null) { - AzureComputeApi api = view.unwrapApi(AzureComputeApi.class); - api.getResourceGroupApi().delete(rg.name()); + URI uri = view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().delete(testResourceGroup.name()); + if (uri != null) { + assertTrue(resourceDeleted.apply(uri), + String.format("Resource %s was not terminated in the configured timeout", uri)); } } finally { super.tearDownContext(); } } + @Override + protected void prepareNodeBeforeCreatingImage(NodeMetadata node) { + // Don't wrap in the init-script, since the comand will clear the user + // config, and jclouds won't be able to execute more than one command + // (won't be able to poll for the execution status of the command when + // running with the init-script) + ExecResponse result = view.getComputeService().runScriptOnNode(node.getId(), "waagent -deprovision+user -force", + wrapInInitScript(false)); + assertEquals(result.getExitStatus(), 0); + } + @Override protected Module getSshModule() { return new SshjSshClientModule(); @@ -85,7 +108,7 @@ public class AzureComputeImageExtensionLiveTest extends BaseImageExtensionLiveTe @Override protected Properties setupProperties() { Properties properties = super.setupProperties(); - AzureLiveTestUtils.defaultProperties(properties); + AzureLiveTestUtils.defaultProperties(properties, getClass().getSimpleName().toLowerCase()); setIfTestSystemPropertyPresent(properties, "oauth.endpoint"); return properties; } @@ -99,9 +122,11 @@ public class AzureComputeImageExtensionLiveTest extends BaseImageExtensionLiveTe public TemplateBuilder getNodeTemplate() { Map keyPair = ComputeTestUtils.setupKeyPair(); return super.getNodeTemplate().options( - authorizePublicKey(keyPair.get("public")) - .overrideLoginPrivateKey(keyPair.get("private"))); + authorizePublicKey(keyPair.get("public")).overrideLoginPrivateKey(keyPair.get("private"))); } - + private void createResourceGroup() { + Location location = getNodeTemplate().build().getLocation(); + testResourceGroup = resourceGroupMap.getUnchecked(location.getId()); + } } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java index 9296d690f4..e00880be90 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java @@ -18,6 +18,7 @@ package org.jclouds.azurecompute.arm.compute.extensions; import static com.google.common.collect.Iterables.get; import static com.google.common.collect.Iterables.getOnlyElement; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; import static org.jclouds.compute.options.TemplateOptions.Builder.inboundPorts; import static org.jclouds.compute.options.TemplateOptions.Builder.securityGroups; import static org.jclouds.compute.predicates.NodePredicates.inGroup; @@ -26,6 +27,7 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; +import java.net.URI; import java.util.Properties; import java.util.Set; import java.util.concurrent.ExecutionException; @@ -49,9 +51,11 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import com.google.common.base.Optional; +import com.google.common.base.Predicate; import com.google.common.cache.LoadingCache; import com.google.inject.Key; import com.google.inject.TypeLiteral; +import com.google.inject.name.Names; /** * Live test for AzureCompute @@ -61,6 +65,7 @@ import com.google.inject.TypeLiteral; public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGroupExtensionLiveTest { private LoadingCache resourceGroupMap; + private Predicate resourceDeleted; private ResourceGroup testResourceGroup; public AzureComputeSecurityGroupExtensionLiveTest() { @@ -73,6 +78,8 @@ public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGrou resourceGroupMap = context.utils().injector() .getInstance(Key.get(new TypeLiteral>() { })); + resourceDeleted = context.utils().injector().getInstance(Key.get(new TypeLiteral>() { + }, Names.named(TIMEOUT_RESOURCE_DELETED))); createResourceGroup(); } @@ -134,7 +141,11 @@ public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGrou @Override protected void tearDownContext() { try { - view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().delete(testResourceGroup.name()); + URI uri = view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().delete(testResourceGroup.name()); + if (uri != null) { + assertTrue(resourceDeleted.apply(uri), + String.format("Resource %s was not terminated in the configured timeout", uri)); + } } finally { super.tearDownContext(); } @@ -143,7 +154,7 @@ public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGrou @Override protected Properties setupProperties() { Properties properties = super.setupProperties(); - AzureLiveTestUtils.defaultProperties(properties); + AzureLiveTestUtils.defaultProperties(properties, "sgelivetest"); setIfTestSystemPropertyPresent(properties, "oauth.endpoint"); return properties; } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApiLiveTest.java index 6e9e1e7a70..2b9e30a8bd 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApiLiveTest.java @@ -17,6 +17,7 @@ package org.jclouds.azurecompute.arm.features; import static com.google.common.collect.Iterables.any; +import static org.jclouds.azurecompute.arm.domain.AvailabilitySet.AvailabilitySetType.MANAGED; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; @@ -27,6 +28,7 @@ import java.util.UUID; import org.jclouds.azurecompute.arm.domain.AvailabilitySet; import org.jclouds.azurecompute.arm.domain.AvailabilitySet.AvailabilitySetProperties; +import org.jclouds.azurecompute.arm.domain.AvailabilitySet.SKU; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -56,10 +58,13 @@ public class AvailabilitySetApiLiveTest extends BaseAzureComputeApiLiveTest { public void createAvailabilitySet() { AvailabilitySetProperties props = AvailabilitySetProperties.builder().platformUpdateDomainCount(2) .platformFaultDomainCount(3).build(); - AvailabilitySet as = api().createOrUpdate(asName, LOCATION, null, props); + AvailabilitySet as = api().createOrUpdate(asName, SKU.create(MANAGED), LOCATION, null, props); assertNotNull(as); assertEquals(as.name(), asName); + + assertNotNull(as.sku()); + assertEquals(as.sku().type(), MANAGED); } @Test(dependsOnMethods = "createAvailabilitySet") @@ -80,7 +85,7 @@ public class AvailabilitySetApiLiveTest extends BaseAzureComputeApiLiveTest { @Test(dependsOnMethods = "createAvailabilitySet") public void updateAvailabilitySet() { AvailabilitySet as = api().get(asName); - as = api().createOrUpdate(asName, LOCATION, ImmutableMap.of("foo", "bar"), as.properties()); + as = api().createOrUpdate(asName, SKU.create(MANAGED), LOCATION, ImmutableMap.of("foo", "bar"), as.properties()); assertNotNull(as); assertTrue(as.tags().containsKey("foo")); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApiMockTest.java index db9a7edfe9..430c32f305 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApiMockTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/AvailabilitySetApiMockTest.java @@ -17,6 +17,7 @@ package org.jclouds.azurecompute.arm.features; import static com.google.common.collect.Iterables.isEmpty; +import static org.jclouds.azurecompute.arm.domain.AvailabilitySet.AvailabilitySetType.MANAGED; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; @@ -27,6 +28,7 @@ import java.util.List; import org.jclouds.azurecompute.arm.domain.AvailabilitySet; import org.jclouds.azurecompute.arm.domain.AvailabilitySet.AvailabilitySetProperties; +import org.jclouds.azurecompute.arm.domain.AvailabilitySet.SKU; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; import org.testng.annotations.Test; @@ -36,7 +38,7 @@ public class AvailabilitySetApiMockTest extends BaseAzureComputeApiMockTest { private final String subscriptionid = "SUBSCRIPTIONID"; private final String resourcegroup = "myresourcegroup"; private final String asName = "myas"; - private final String apiVersion = "api-version=2016-03-30"; + private final String apiVersion = "api-version=2016-04-30-preview"; public void createAvailabilitySet() throws InterruptedException { @@ -46,12 +48,12 @@ public class AvailabilitySetApiMockTest extends BaseAzureComputeApiMockTest { AvailabilitySetProperties props = AvailabilitySetProperties.builder().platformUpdateDomainCount(2) .platformFaultDomainCount(3).build(); - AvailabilitySet as = asApi.createOrUpdate(asName, "westeurope", null, props); + AvailabilitySet as = asApi.createOrUpdate(asName, SKU.create(MANAGED), "westeurope", null, props); String path = String.format( "/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Compute/availabilitySets/%s?%s", subscriptionid, resourcegroup, asName, apiVersion); - String json = "{\"location\":\"westeurope\",\"properties\":{\"platformUpdateDomainCount\":2,\"platformFaultDomainCount\":3}}"; + String json = "{\"location\":\"westeurope\",\"properties\":{\"platformUpdateDomainCount\":2,\"platformFaultDomainCount\":3},\"sku\":{\"name\":\"Aligned\"}}"; assertSent(server, "PUT", path, json); assertEquals(as.name(), asName); 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 b485dc2ea8..0b9ab05971 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 @@ -23,11 +23,8 @@ 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.Subnet; -import org.jclouds.azurecompute.arm.domain.VirtualNetwork; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; import org.jclouds.util.Predicates2; import org.testng.Assert; @@ -37,12 +34,10 @@ import org.testng.annotations.Test; import com.google.common.base.Predicate; import com.google.common.net.UrlEscapers; -@Test(testName = "DeploymentApiLiveTest", singleThreaded = true) +@Test(groups = "live", testName = "DeploymentApiLiveTest", singleThreaded = true) public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest { private String deploymentName; - private String subnetId; - private String properties; private String badProperties; @@ -52,7 +47,6 @@ public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest { super.setup(); createTestResourceGroup(); deploymentName = "jc" + System.currentTimeMillis(); - String virtualNetworkName = String.format("vn-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); String storageAccountName = String.format("st%s%s", System.getProperty("user.name"), RAND); String rawtemplate = "{\"$schema\":\"https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\"contentVersion\":\"1.0.0.0\",\"parameters\":{\"newStorageAccountName\":{\"type\":\"string\",\"metadata\":{\"description\":\"Name of the Storage Account\"}},\"storageAccountType\":{\"type\":\"string\",\"defaultValue\":\"Standard_LRS\",\"allowedValues\":[\"Standard_LRS\",\"Standard_GRS\",\"Standard_ZRS\"],\"metadata\":{\"description\":\"Storage Account type\"}},\"location\":{\"type\":\"string\",\"allowedValues\":[\"East US\",\"West US\",\"West Europe\",\"East Asia\",\"Southeast Asia\"],\"metadata\":{\"description\":\"Location of storage account\"}}},\"resources\":[{\"type\":\"Microsoft.Storage/storageAccounts\",\"name\":\"[parameters('newStorageAccountName')]\",\"apiVersion\":\"2015-05-01-preview\",\"location\":\"[parameters('location')]\",\"properties\":{\"accountType\":\"[parameters('storageAccountType')]\"}}]}"; @@ -61,17 +55,6 @@ public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest { properties = getPutBody(rawtemplate, "Incremental", rawparameters); badProperties = getPutBody(rawtemplate, "Incremental", rawbadParameters); - - //Subnets belong to a virtual network so that needs to be created first - VirtualNetwork vn = createDefaultVirtualNetwork(resourceGroupName, virtualNetworkName, "10.3.0.0/16", LOCATION); - assertNotNull(vn); - - //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.3.0.0/23"); - assertNotNull(subnet); - assertNotNull(subnet.id()); - subnetId = subnet.id(); } private String getPutBody(String template, String mode, String parameters) { @@ -104,48 +87,10 @@ public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest { } assertNotNull(deploymentValid); } - @Test + + @Test(dependsOnMethods = "testValidate") public void testCreate() { - 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.authorizePublicKey(rsakey); - options.subnetId(subnetId); - - 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); + String deploymentTemplate = UrlEscapers.urlFormParameterEscaper().escape(properties); Deployment deploymentValid = api().validate(deploymentName, deploymentTemplate); assertNotNull(deploymentValid); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DiskApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DiskApiLiveTest.java index becfccd211..f5af8857a4 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DiskApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/DiskApiLiveTest.java @@ -36,10 +36,10 @@ import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; -@Test(groups = "live", singleThreaded = true) +@Test(groups = "live", testName = "DiskApiLiveTest", singleThreaded = true) public class DiskApiLiveTest extends BaseAzureComputeApiLiveTest { - public static final String JCLOUDS_IMAGE_PREFIX = "jclouds-"; + public static final String JCLOUDS_DISK_PREFIX = "jclouds-"; private String diskName; @BeforeClass @@ -47,12 +47,12 @@ public class DiskApiLiveTest extends BaseAzureComputeApiLiveTest { public void setup() { super.setup(); createTestResourceGroup(); - diskName = JCLOUDS_IMAGE_PREFIX + RAND; + diskName = JCLOUDS_DISK_PREFIX + RAND; } @Test public void deleteDiskResourceDoesNotExist() { - assertNull(api().delete(JCLOUDS_IMAGE_PREFIX + UUID.randomUUID())); + assertNull(api().delete(JCLOUDS_DISK_PREFIX + UUID.randomUUID())); } @Test diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ImageApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ImageApiLiveTest.java index 038fc31419..d976258c4a 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ImageApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ImageApiLiveTest.java @@ -16,90 +16,154 @@ */ package org.jclouds.azurecompute.arm.features; -import java.net.URI; -import java.util.Collections; -import java.util.List; -import java.util.UUID; - -import org.jclouds.azurecompute.arm.domain.Image; -import org.jclouds.azurecompute.arm.domain.ImageProperties; -import org.jclouds.azurecompute.arm.domain.Provisionable; -import org.jclouds.azurecompute.arm.domain.VirtualMachine; -import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties; -import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - -import com.google.common.base.Supplier; - +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Iterables.any; +import static com.google.common.collect.Iterables.getOnlyElement; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; +import static org.jclouds.compute.predicates.NodePredicates.inGroup; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; -@Test(groups = "live", singleThreaded = true) -public class ImageApiLiveTest extends BaseAzureComputeApiLiveTest { +import java.net.URI; +import java.util.Properties; - public static final String JCLOUDS_VM_IMAGE_PREFIX = "jclouds-vm-image-"; - private String imageName; - private VirtualMachine virtualMachine; +import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.domain.IdReference; +import org.jclouds.azurecompute.arm.domain.Image; +import org.jclouds.azurecompute.arm.domain.ImageProperties; +import org.jclouds.azurecompute.arm.domain.ResourceGroup; +import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; +import org.jclouds.compute.RunNodesException; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest; +import org.jclouds.domain.Location; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.google.common.base.Predicate; +import com.google.common.cache.LoadingCache; +import com.google.inject.Key; +import com.google.inject.TypeLiteral; +import com.google.inject.name.Names; + +// We extend the BaseComputeServiceContextLiveTest to create nodes using the abstraction, which is much easier +@Test(groups = "live", singleThreaded = true, testName = "ImageApiLiveTest") +public class ImageApiLiveTest extends BaseComputeServiceContextLiveTest { + + private static final String imageName = "imageFromRest"; + + private LoadingCache resourceGroupMap; + private Predicate resourceDeleted; + private AzureComputeApi api; + + private String resourceGroupName; + private String location; + private ImageApi imageApi; + private Image image; + + private String group; + + public ImageApiLiveTest() { + provider = "azurecompute-arm"; + group = getClass().getSimpleName().toLowerCase(); + } - @BeforeClass @Override - public void setup() { - super.setup(); - createTestResourceGroup(); - imageName = JCLOUDS_VM_IMAGE_PREFIX + RAND; - String vmName = "jclouds-vm-" + RAND; + protected Properties setupProperties() { + Properties properties = super.setupProperties(); + AzureLiveTestUtils.defaultProperties(properties, getClass().getSimpleName().toLowerCase()); + checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); + return properties; + } - virtualMachine = api.getVirtualMachineApi(resourceGroupName).createOrUpdate(vmName, LOCATION, VirtualMachineProperties.builder().build(), - Collections. emptyMap(), null); + @Override + protected void initializeContext() { + super.initializeContext(); + resourceDeleted = context.utils().injector().getInstance(Key.get(new TypeLiteral>() { + }, Names.named(TIMEOUT_RESOURCE_DELETED))); + resourceGroupMap = context.utils().injector() + .getInstance(Key.get(new TypeLiteral>() { + })); + api = view.unwrapApi(AzureComputeApi.class); + } + + @Override + @BeforeClass + public void setupContext() { + super.setupContext(); + // Use the resource name conventions used in the abstraction + ResourceGroup resourceGroup = createResourceGroup(); + resourceGroupName = resourceGroup.name(); + location = resourceGroup.location(); + imageApi = api.getVirtualMachineImageApi(resourceGroupName); + } + + @Override + @AfterClass(alwaysRun = true) + protected void tearDownContext() { + try { + view.getComputeService().destroyNodesMatching(inGroup(group)); + } finally { + try { + URI uri = api.getResourceGroupApi().delete(resourceGroupName); + assertResourceDeleted(uri); + } finally { + super.tearDownContext(); + } + } } @Test - public void deleteImageResourceDoesNotExist() { - assertNull(api().delete(JCLOUDS_VM_IMAGE_PREFIX + UUID.randomUUID())); + public void testDeleteImageDoesNotExist() { + assertNull(imageApi.delete("notAnImage")); } @Test - public void CreateVirtualMachineImageFromExistingVM() { - String id = String.format("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/virtualMachines/myVM", getSubscriptionId(), resourceGroupName); - ImageProperties properties = ImageProperties.builder() - .sourceVirtualMachine(ImageProperties.SourceVirtualMachine.create(id)) - .build(); - Image image = api().createOrUpdate(imageName, LOCATION, properties); - assertTrue(waitUntilAvailable(imageName), "creation operation did not complete in the configured timeout"); - assertTrue(id.equals(image.properties().sourceVirtualMachine().id())); - } + public void testCreateImage() throws RunNodesException { + NodeMetadata node = getOnlyElement(view.getComputeService().createNodesInGroup(group, 1)); + IdReference vmIdRef = IdReference.create(node.getProviderId()); + view.getComputeService().suspendNode(node.getId()); - @Test(dependsOnMethods = "CreateVirtualMachineImageFromExistingVM") - public void getImage() { - Image image = api().get(imageName); + api.getVirtualMachineApi(resourceGroupName).generalize(node.getName()); + + image = imageApi.createOrUpdate(imageName, location, ImageProperties.builder() + .sourceVirtualMachine(vmIdRef).build()); assertNotNull(image); } - @Test(dependsOnMethods = "CreateVirtualMachineImageFromExistingVM") - public void listImages() { - List images = api().list(); - assertTrue(images.size() > 0); - } - - @Test(dependsOnMethods = {"listImages", "getImage"}, alwaysRun = true) - public void deleteImage() { - URI uri = api().delete(imageName); - assertNotNull(uri); - } - - private ImageApi api() { - return api.getVirtualMachineImageApi(resourceGroupName); - } - - private boolean waitUntilAvailable(final String name) { - return resourceAvailable.apply(new Supplier() { - @Override public Provisionable get() { - Image image = api().get(name); - return image == null ? null : image.properties(); + @Test(dependsOnMethods = "testCreateImage") + public void testListImages() { + // Check that the image we've just created exists + assertTrue(any(imageApi.list(), new Predicate() { + @Override + public boolean apply(Image input) { + return image.name().equals(input.name()); } - }); + })); } -} + @Test(dependsOnMethods = "testCreateImage") + public void testGetImage() { + assertNotNull(imageApi.get(imageName)); + } + + @Test(dependsOnMethods = { "testCreateImage", "testListImages", "testGetImage" }, alwaysRun = true) + public void deleteImage() { + assertResourceDeleted(imageApi.delete(imageName)); + } + + private void assertResourceDeleted(final URI uri) { + if (uri != null) { + assertTrue(resourceDeleted.apply(uri), + String.format("Resource %s was not deleted in the configured timeout", uri)); + } + } + + private ResourceGroup createResourceGroup() { + Location location = view.getComputeService().templateBuilder().build().getLocation(); + return resourceGroupMap.getUnchecked(location.getId()); + } + +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ImageApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ImageApiMockTest.java new file mode 100644 index 0000000000..cec048344f --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ImageApiMockTest.java @@ -0,0 +1,155 @@ +/* + * 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 static com.google.common.collect.Iterables.isEmpty; +import static org.testng.Assert.assertEquals; +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.domain.DataDisk; +import org.jclouds.azurecompute.arm.domain.IdReference; +import org.jclouds.azurecompute.arm.domain.Image; +import org.jclouds.azurecompute.arm.domain.ImageProperties; +import org.jclouds.azurecompute.arm.domain.OSDisk; +import org.jclouds.azurecompute.arm.domain.StorageProfile; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; + +@Test(groups = "unit", testName = "ImageApiMockTest", singleThreaded = true) +public class ImageApiMockTest extends BaseAzureComputeApiMockTest { + private static final String subscriptionid = "SUBSCRIPTIONID"; + private static final String resourcegroup = "myresourcegroup"; + private static final String apiVersion = "api-version=2016-04-30-preview"; + private static final String imageName = "testVirtualMachineImage"; + private static final String location = "canadaeast"; + + private static final String PATH = String + .format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Compute/images/%s?%s", subscriptionid, + resourcegroup, imageName, apiVersion); + + public void createVirtualMachineImage() throws InterruptedException { + server.enqueue(jsonResponse("/virtualmachineimagecreate.json")); + + ImageApi imageApi = api.getVirtualMachineImageApi(resourcegroup); + Image result = imageApi.createOrUpdate(imageName, location, newVirtualMachineImage().properties()); + + assertSent(server, "PUT", PATH, "{\"location\":\"" + location + "\"," + + "\"properties\":{\"sourceVirtualMachine\":{\"id\":\"vmId\"}," + + "\"storageProfile\":{\"osDisk\":{\"osType\":\"Linux\",\"name\":\"Ubuntu\"},\"dataDisks\":[]}," + + "\"provisioningState\":\"Succeeded\"}}"); + + assertEquals(result.name(), imageName); + assertEquals(result.location(), location); + } + + public void getVirtualMachineImage() throws InterruptedException { + server.enqueue(jsonResponse("/virtualmachineimageget.json")); + + ImageApi imageApi = api.getVirtualMachineImageApi(resourcegroup); + Image result = imageApi.get(imageName); + + assertSent(server, "GET", PATH); + + assertEquals(result.name(), imageName); + assertEquals(result.location(), location); + assertNotNull(result.properties().sourceVirtualMachine()); + assertNotNull(result.properties().storageProfile()); + } + + public void getVirtualMachineImageReturns404() throws InterruptedException { + server.enqueue(response404()); + + final ImageApi imageApi = api.getVirtualMachineImageApi(resourcegroup); + Image result = imageApi.get(imageName); + + assertSent(server, "GET", PATH); + + assertNull(result); + } + + public void listVirtualMachineImages() throws InterruptedException { + server.enqueue(jsonResponse("/virtualmachineimagelist.json")); + + final ImageApi imageApi = api.getVirtualMachineImageApi(resourcegroup); + List result = imageApi.list(); + + assertSent(server, "GET", String + .format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Compute/images?%s", subscriptionid, + resourcegroup, apiVersion)); + + assertNotNull(result); + assertTrue(result.size() > 0); + } + + public void listVirtualMachineImagesReturns404() throws InterruptedException { + server.enqueue(response404()); + + final ImageApi imageApi = api.getVirtualMachineImageApi(resourcegroup); + List result = imageApi.list(); + + assertSent(server, "GET", String + .format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Compute/images?%s", subscriptionid, + resourcegroup, apiVersion)); + + assertTrue(isEmpty(result)); + } + + public void deleteVirtualMachineImage() throws InterruptedException { + server.enqueue(response202WithHeader()); + + final ImageApi imageApi = api.getVirtualMachineImageApi(resourcegroup); + URI uri = imageApi.delete(imageName); + + assertSent(server, "DELETE", PATH); + + assertNotNull(uri); + assertTrue(uri.toString().contains("api-version")); + assertTrue(uri.toString().contains("operationresults")); + } + + public void deleteVirtualMachineImageDoesNotExist() throws InterruptedException { + server.enqueue(response404()); + + final ImageApi imageApi = api.getVirtualMachineImageApi(resourcegroup); + URI uri = imageApi.delete(imageName); + assertNull(uri); + + assertSent(server, "DELETE", PATH); + } + + private Image newVirtualMachineImage() { + return Image + .builder() + .name(imageName) + .location(location) + .properties( + ImageProperties + .builder() + .sourceVirtualMachine(IdReference.create("vmId")) + .storageProfile( + StorageProfile.create(null, OSDisk.builder().osType("Linux").name("Ubuntu").build(), + ImmutableList. of())).provisioningState("Succeeded").build()).build(); + + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java index 69014a5d64..5799093089 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java @@ -116,7 +116,7 @@ public class LoadBalancerApiLiveTest extends BaseComputeServiceContextLiveTest { @Override protected Properties setupProperties() { Properties properties = super.setupProperties(); - AzureLiveTestUtils.defaultProperties(properties); + AzureLiveTestUtils.defaultProperties(properties, getClass().getSimpleName().toLowerCase()); checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); return properties; } @@ -356,7 +356,7 @@ public class LoadBalancerApiLiveTest extends BaseComputeServiceContextLiveTest { // set AvailabilitySetProperties props = AvailabilitySetProperties.builder().platformUpdateDomainCount(count) .platformFaultDomainCount(count).build(); - AvailabilitySet as = AvailabilitySet.builder().name(group).properties(props).build(); + AvailabilitySet as = AvailabilitySet.managed().name(group).properties(props).build(); Set nodes = view.getComputeService() .createNodesInGroup(group, count, availabilitySet(as)); 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 ccf1e70ce4..cecdc012fa 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,12 @@ */ package org.jclouds.azurecompute.arm.features; +import static org.assertj.core.api.Assertions.assertThat; +import static org.jclouds.util.Predicates2.retry; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + import java.net.URI; import java.util.ArrayList; import java.util.Arrays; @@ -24,7 +30,6 @@ import java.util.List; import java.util.Map; 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; @@ -37,6 +42,7 @@ 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.ResourceDefinition; +import org.jclouds.azurecompute.arm.domain.StorageAccountType; import org.jclouds.azurecompute.arm.domain.StorageProfile; import org.jclouds.azurecompute.arm.domain.StorageService; import org.jclouds.azurecompute.arm.domain.Subnet; @@ -45,8 +51,8 @@ import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance; import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance.PowerState; import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties; +import org.jclouds.azurecompute.arm.functions.ParseJobStatus; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; -import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -55,20 +61,12 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; -import static org.assertj.core.api.Assertions.assertThat; -import static org.jclouds.util.Predicates2.retry; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; - @Test(groups = "live", testName = "VirtualMachineApiLiveTest") public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { private String subscriptionid; - private String storageServiceName; private String vmName; private String nicName; - private StorageService storageService; private String virtualNetworkName; private String subnetId; @@ -81,9 +79,6 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { createTestResourceGroup(); virtualNetworkName = String.format("vn-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); - storageServiceName = String.format("st%s%s", System.getProperty("user.name"), RAND); - storageService = createStorageService(resourceGroupName, storageServiceName, LOCATION); - // Subnets belong to a virtual network so that needs to be created first assertNotNull(createDefaultVirtualNetwork(resourceGroupName, virtualNetworkName, "10.2.0.0/16", LOCATION)); @@ -103,25 +98,10 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { @Test public void testCreate() { - String blob = storageService.storageServiceProperties().primaryEndpoints().get("blob"); - - VirtualMachine vm = api().createOrUpdate(vmName, LOCATION, getProperties(blob, nicName), + VirtualMachine vm = api().createOrUpdate(vmName, LOCATION, getProperties(nicName, null), Collections. emptyMap(), null); assertTrue(!vm.name().isEmpty()); - - //Poll until resource is ready to be used - boolean jobDone = retry(new Predicate() { - @Override - public boolean apply(String name) { - return !api().get(name).properties().provisioningState().equals(VirtualMachineProperties.ProvisioningState.CREATING); - } - }, 60 * 20 * 1000).apply(vmName); - assertTrue(jobDone, "createOrUpdate operation did not complete in the configured timeout"); - - VirtualMachineProperties.ProvisioningState status = api().get(vmName).properties().provisioningState(); - // Cannot be creating anymore. Should be succeeded or running but not failed. - assertThat(status).isNotEqualTo(VirtualMachineProperties.ProvisioningState.CREATING); - assertThat(status).isNotEqualTo(VirtualMachineProperties.ProvisioningState.FAILED); + waitUntilReady(vmName); } @Test(dependsOnMethods = "testCreate") @@ -139,7 +119,7 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { @Test(dependsOnMethods = "testGet") public void testStart() { api().start(vmName); - assertTrue(stateReached(PowerState.RUNNING), "start operation did not complete in the configured timeout"); + assertTrue(stateReached(vmName, PowerState.RUNNING), "start operation did not complete in the configured timeout"); } @Test(dependsOnMethods = "testStart") @@ -147,15 +127,12 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { VirtualMachine vm = api().get(vmName); VirtualMachineProperties oldProperties = vm.properties(); StorageProfile oldStorageProfile = oldProperties.storageProfile(); - - String blob = storageService.storageServiceProperties().primaryEndpoints().get("blob"); - VHD vhd = VHD.create(blob + "vhds/" + vmName + "new-data-disk.vhd"); + DataDisk newDataDisk = DataDisk.builder() .name(vmName + "new-data-disk") .diskSizeGB("1") .lun(1) .createOption(DataDisk.DiskCreateOptionTypes.EMPTY) - .vhd(vhd) .build(); List oldDataDisks = oldStorageProfile.dataDisks(); assertEquals(oldDataDisks.size(), 1); @@ -173,15 +150,15 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { @Test(dependsOnMethods = "testUpdate") public void testStop() { api().stop(vmName); - assertTrue(stateReached(PowerState.STOPPED), "stop operation did not complete in the configured timeout"); + assertTrue(stateReached(vmName, PowerState.STOPPED), "stop operation did not complete in the configured timeout"); } @Test(dependsOnMethods = "testStop") public void testRestart() { api().start(vmName); - assertTrue(stateReached(PowerState.RUNNING), "start operation did not complete in the configured timeout"); + assertTrue(stateReached(vmName, PowerState.RUNNING), "start operation did not complete in the configured timeout"); api().restart(vmName); - assertTrue(stateReached(PowerState.RUNNING), "restart operation did not complete in the configured timeout"); + assertTrue(stateReached(vmName, PowerState.RUNNING), "restart operation did not complete in the configured timeout"); } @Test(dependsOnMethods = "testCreate") @@ -201,15 +178,31 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { @Test(dependsOnMethods = "testRestart") public void testGeneralize() throws IllegalStateException { api().stop(vmName); - assertTrue(stateReached(PowerState.STOPPED), "restart operation did not complete in the configured timeout"); + assertTrue(stateReached(vmName, PowerState.STOPPED), "restart operation did not complete in the configured timeout"); api().generalize(vmName); } @SuppressWarnings("unchecked") - @Test(dependsOnMethods = "testGeneralize") + @Test public void testCapture() throws IllegalStateException { - URI uri = api().capture(vmName, vmName, vmName); - if (uri == null) Assert.fail(); + // Capture is only allowed for Blob based VMs, so let's create one VM for this test + NetworkInterfaceCard nic = createNetworkInterfaceCard(resourceGroupName, "capture-nic-" + RAND, LOCATION, "ipConfig-" + RAND); + StorageService storageService = createStorageService(resourceGroupName, "capture" + RAND, LOCATION); + String blob = storageService.storageServiceProperties().primaryEndpoints().get("blob"); + + String captureVmName = "capture-" + RAND; + api().createOrUpdate(captureVmName, LOCATION, getProperties(nic.name(), blob), + Collections. emptyMap(), null); + waitUntilReady(captureVmName); + + api().stop(captureVmName); + assertTrue(stateReached(captureVmName, PowerState.STOPPED), + "restart operation did not complete in the configured timeout"); + api().generalize(captureVmName); + + URI uri = api().capture(captureVmName, captureVmName, captureVmName); + assertNotNull(uri); + if (imageAvailablePredicate.apply(uri)) { List definitions = api.getJobApi().captureStatus(uri); if (definitions != null) { @@ -219,18 +212,13 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { Map properties2 = (Map) storageObject; Object osDiskObject = properties2.get("osDisk"); Map osProperties = (Map) osDiskObject; - Object dataDisksObject = properties2.get("dataDisks"); - List dataProperties = (List) dataDisksObject; - Map datadiskObject = (Map) dataProperties.get(0); - assertNotNull(osProperties.get("name")); - assertNotNull(datadiskObject.get("name")); } } } } - @Test(dependsOnMethods = "testCapture", alwaysRun = true) + @Test(dependsOnMethods = "testGeneralize", alwaysRun = true) public void testDelete() throws Exception { URI uri = api().delete(vmName); assertResourceDeleted(uri); @@ -240,22 +228,28 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { return api.getVirtualMachineApi(resourceGroupName); } - private VirtualMachineProperties getProperties(String blob, String nic) { + private VirtualMachineProperties getProperties(String nic, String blob) { HardwareProfile hwProf = HardwareProfile.create("Standard_D1"); ImageReference imgRef = ImageReference.builder().publisher("MicrosoftWindowsServerEssentials") .offer("WindowsServerEssentials").sku("WindowsServerEssentials").version("latest").build(); - DataDisk dataDisk = DataDisk.builder().name("data").diskSizeGB("100").lun(0).createOption(DataDisk.DiskCreateOptionTypes.EMPTY).build(); - List dataDisks = new ArrayList(); - dataDisks.add(dataDisk); - - OSDisk osDisk = OSDisk.builder() + + DataDisk.Builder dataDisk = DataDisk.builder().name("data").diskSizeGB("100").lun(0).createOption(DataDisk.DiskCreateOptionTypes.EMPTY); + + OSDisk.Builder osDisk = OSDisk.builder() + .name("os") .osType("Windows") .caching(DataDisk.CachingTypes.READ_WRITE.toString()) - .createOption("FromImage") - .managedDiskParameters(ManagedDiskParameters.create(null, ManagedDiskParameters.StorageAccountTypes.STANDARD_LRS.toString())) - .build(); - StorageProfile storageProfile = StorageProfile.create(imgRef, osDisk, dataDisks); + .createOption("FromImage"); + + if (blob == null) { + osDisk.managedDiskParameters(ManagedDiskParameters.create(null, StorageAccountType.STANDARD_LRS.toString())); + } else { + osDisk.vhd(VHD.create(blob + "vhds/" + vmName + ".vhd")); + dataDisk.vhd(VHD.create(blob + "vhds/" + vmName + "data.vhd")); + } + + StorageProfile storageProfile = StorageProfile.create(imgRef, osDisk.build(), ImmutableList.of(dataDisk.build())); OSProfile.WindowsConfiguration windowsConfig = OSProfile.WindowsConfiguration.create(false, null, null, true, null); OSProfile osProfile = OSProfile.create(vmName, "azureuser", "RFe3&432dg", null, null, windowsConfig); @@ -267,15 +261,12 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { new ArrayList(); networkInterfaces.add(networkInterface); NetworkProfile networkProfile = NetworkProfile.create(networkInterfaces); - DiagnosticsProfile.BootDiagnostics bootDiagnostics = - DiagnosticsProfile.BootDiagnostics.create(true, blob); - DiagnosticsProfile diagnosticsProfile = DiagnosticsProfile.create(bootDiagnostics); VirtualMachineProperties properties = VirtualMachineProperties.create(null, - null, null, hwProf, storageProfile, osProfile, networkProfile, diagnosticsProfile, VirtualMachineProperties.ProvisioningState.CREATING); + null, null, hwProf, storageProfile, osProfile, networkProfile, null, VirtualMachineProperties.ProvisioningState.CREATING); return properties; } - protected NetworkInterfaceCard createNetworkInterfaceCard(final String resourceGroupName, String networkInterfaceCardName, String locationName, String ipConfigurationName) { + private NetworkInterfaceCard createNetworkInterfaceCard(final String resourceGroupName, String networkInterfaceCardName, String locationName, String ipConfigurationName) { //Create properties object final NetworkInterfaceCardProperties networkInterfaceCardProperties = NetworkInterfaceCardProperties .builder() @@ -286,12 +277,46 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { final Map tags = ImmutableMap.of("jclouds", "livetest"); return api.getNetworkInterfaceCardApi(resourceGroupName).createOrUpdate(networkInterfaceCardName, locationName, networkInterfaceCardProperties, tags); } + + private StorageService createStorageService(final String resourceGroupName, final String storageServiceName, + final String location) { + URI uri = api.getStorageAccountApi(resourceGroupName).create(storageServiceName, location, + ImmutableMap.of("property_name", "property_value"), + ImmutableMap.of("accountType", StorageService.AccountType.Standard_LRS.toString())); + if (uri != null) { + assertTrue(uri.toString().contains("api-version")); + + boolean jobDone = retry(new Predicate() { + @Override + public boolean apply(final URI uri) { + return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri); + } + }, 60 * 1 * 1000 /* 1 minute timeout */).apply(uri); + assertTrue(jobDone, "create operation did not complete in the configured timeout"); + } + return api.getStorageAccountApi(resourceGroupName).get(storageServiceName); + } private boolean waitForState(String name, final PowerState state) { return api().getInstanceDetails(name).powerState().equals(state); } + + private void waitUntilReady(String vmName) { + boolean ready = retry(new Predicate() { + @Override + public boolean apply(String name) { + return !api().get(name).properties().provisioningState().equals(VirtualMachineProperties.ProvisioningState.CREATING); + } + }, 60 * 20 * 1000).apply(vmName); + assertTrue(ready, "createOrUpdate operation did not complete in the configured timeout"); - private boolean stateReached(final PowerState state) { + VirtualMachineProperties.ProvisioningState status = api().get(vmName).properties().provisioningState(); + // Cannot be creating anymore. Should be succeeded or running but not failed. + assertThat(status).isNotEqualTo(VirtualMachineProperties.ProvisioningState.CREATING); + assertThat(status).isNotEqualTo(VirtualMachineProperties.ProvisioningState.FAILED); + } + + private boolean stateReached(String vmName, final PowerState state) { return retry(new Predicate() { @Override public boolean apply(String name) { 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 34b59c30d0..27e6f6b97a 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 @@ -233,7 +233,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { assertNotNull(uri); assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + "/virtualMachines/vm/capture?api-version=2016-04-30-preview", - "{\"vhdPrefix\":\"prefix\",\"destinationContainerName\":\"container\"}"); + "{\"vhdPrefix\":\"prefix\",\"destinationContainerName\":\"container\",\"overwriteVhds\":\"true\"}"); } public void testCapture404() throws Exception { @@ -244,7 +244,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { assertNull(uri); assertSent(server, "POST", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + "/virtualMachines/vm/capture?api-version=2016-04-30-preview", - "{\"vhdPrefix\":\"prefix\",\"destinationContainerName\":\"container\"}"); + "{\"vhdPrefix\":\"prefix\",\"destinationContainerName\":\"container\",\"overwriteVhds\":\"true\"}"); } private VirtualMachineProperties getProperties() { @@ -252,7 +252,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { ImageReference imgRef = ImageReference.builder().publisher("publisher").offer("offer").sku("sku").version("ver").build(); VHD vhd = VHD.create("https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd"); List dataDisks = new ArrayList(); - OSDisk osDisk = OSDisk.create("Windows", "windowsmachine", vhd, "ReadWrite", "FromImage", null, null); + OSDisk osDisk = OSDisk.create("Windows", "windowsmachine", vhd, "ReadWrite", "FromImage", null, null, null); StorageProfile storageProfile = StorageProfile.create(imgRef, osDisk, dataDisks); OSProfile.WindowsConfiguration windowsConfig = OSProfile.WindowsConfiguration.create(false, null, null, true, null); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java index 6006392787..754f5fe86a 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java @@ -32,21 +32,20 @@ import static org.jclouds.oauth.v2.config.OAuthProperties.CREDENTIAL_TYPE; public class AzureLiveTestUtils { - public static Properties defaultProperties(Properties properties) { - properties = properties == null ? new Properties() : properties; - properties.put(CREDENTIAL_TYPE, CLIENT_CREDENTIALS_SECRET.toString()); - properties.put(PROPERTY_REGIONS, "westeurope"); - properties.put(IMAGE_PUBLISHERS, "Canonical"); - properties.put(RESOURCENAME_PREFIX, "jcloudstest"); - - 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); - - return properties; - } -} + public static Properties defaultProperties(Properties properties, String resourceNamePrefix) { + properties = properties == null ? new Properties() : properties; + properties.put(CREDENTIAL_TYPE, CLIENT_CREDENTIALS_SECRET.toString()); + properties.put(PROPERTY_REGIONS, "westeurope"); + properties.put(IMAGE_PUBLISHERS, "Canonical"); + properties.put(RESOURCENAME_PREFIX, resourceNamePrefix); + 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); + + return properties; + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java index 0633294b31..cf6546227d 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java @@ -38,10 +38,8 @@ import org.jclouds.azurecompute.arm.domain.NetworkSecurityRule; import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties; import org.jclouds.azurecompute.arm.domain.Provisionable; import org.jclouds.azurecompute.arm.domain.ResourceGroup; -import org.jclouds.azurecompute.arm.domain.StorageService; import org.jclouds.azurecompute.arm.domain.Subnet; import org.jclouds.azurecompute.arm.domain.VirtualNetwork; -import org.jclouds.azurecompute.arm.functions.ParseJobStatus; import org.testng.annotations.AfterClass; import com.google.common.base.Predicate; @@ -99,7 +97,7 @@ public class BaseAzureComputeApiLiveTest extends BaseApiLiveTest() { - @Override - public boolean apply(final URI uri) { - return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri); - } - }, 60 * 1 * 1000 /* 1 minute timeout */).apply(uri); - assertTrue(jobDone, "create operation did not complete in the configured timeout"); - } - return api.getStorageAccountApi(resourceGroupName).get(storageServiceName); - } - protected void createTestResourceGroup() { String name = String.format("rg-%s-%s", this.getClass().getSimpleName().toLowerCase(), System.getProperty("user.name")); diff --git a/providers/azurecompute-arm/src/test/resources/virtualmachineimagecreate.json b/providers/azurecompute-arm/src/test/resources/virtualmachineimagecreate.json new file mode 100644 index 0000000000..865012f20f --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/virtualmachineimagecreate.json @@ -0,0 +1,21 @@ +{ + "type": "Microsoft.Compute/images", + "location": "canadaeast", + "id": "/subscriptions/bd81406c-6028-4037-9f03-9a3af4ff725d/resourceGroups/jcloudstest-canadaeast/providers/Microsoft.Compute/images/testVirtualMachineImage", + "name": "testVirtualMachineImage", + "properties": { + "sourceVirtualMachine": { + "id": "/subscriptions/bd81406c-6028-4037-9f03-9a3af4ff725d/resourceGroups/jcloudstest-canadaeast/providers/Microsoft.Compute/virtualMachines/vm2image" + }, + "storageProfile": { + "osDisk": { + "osType": "Linux", + "osState": "Generalized", + "blobUri": "https://jcloudstestcanadaeast982.blob.core.windows.net/vhds/vm2image20170315140332.vhd", + "caching": "ReadWrite" + }, + "dataDisks": [] + }, + "provisioningState": "Succeeded" + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/virtualmachineimageget.json b/providers/azurecompute-arm/src/test/resources/virtualmachineimageget.json new file mode 100644 index 0000000000..865012f20f --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/virtualmachineimageget.json @@ -0,0 +1,21 @@ +{ + "type": "Microsoft.Compute/images", + "location": "canadaeast", + "id": "/subscriptions/bd81406c-6028-4037-9f03-9a3af4ff725d/resourceGroups/jcloudstest-canadaeast/providers/Microsoft.Compute/images/testVirtualMachineImage", + "name": "testVirtualMachineImage", + "properties": { + "sourceVirtualMachine": { + "id": "/subscriptions/bd81406c-6028-4037-9f03-9a3af4ff725d/resourceGroups/jcloudstest-canadaeast/providers/Microsoft.Compute/virtualMachines/vm2image" + }, + "storageProfile": { + "osDisk": { + "osType": "Linux", + "osState": "Generalized", + "blobUri": "https://jcloudstestcanadaeast982.blob.core.windows.net/vhds/vm2image20170315140332.vhd", + "caching": "ReadWrite" + }, + "dataDisks": [] + }, + "provisioningState": "Succeeded" + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/virtualmachineimagelist.json b/providers/azurecompute-arm/src/test/resources/virtualmachineimagelist.json new file mode 100644 index 0000000000..cf4d3ea4a8 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/virtualmachineimagelist.json @@ -0,0 +1,25 @@ +{ + "value": [ + { + "type": "Microsoft.Compute/images", + "location": "canadaeast", + "id": "/subscriptions/bd81406c-6028-4037-9f03-9a3af4ff725d/resourceGroups/jcloudstest-canadaeast/providers/Microsoft.Compute/images/imageFromRest", + "name": "testVirtualMachineImage", + "properties": { + "sourceVirtualMachine": { + "id": "/subscriptions/bd81406c-6028-4037-9f03-9a3af4ff725d/resourceGroups/jcloudstest-canadaeast/providers/Microsoft.Compute/virtualMachines/vm2image" + }, + "storageProfile": { + "osDisk": { + "osType": "Linux", + "osState": "Generalized", + "blobUri": "https://jcloudstestcanadaeast982.blob.core.windows.net/vhds/vm2image20170315140332.vhd", + "caching": "ReadWrite" + }, + "dataDisks": [] + }, + "provisioningState": "Succeeded" + } + } + ] +} \ No newline at end of file From 83c0a3c7b255ec744c6150ce76c40e8301280c79 Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Mon, 24 Apr 2017 14:49:57 +0200 Subject: [PATCH 57/87] JCLOUDS-1273/JCLOUDS-1226: Support multiple resource groups in ARM --- .../azurecompute/arm/AzureComputeApi.java | 8 +- .../arm/compute/AzureComputeService.java | 15 ++- .../compute/AzureComputeServiceAdapter.java | 88 ++++++++------- .../AzureComputeServiceContextModule.java | 18 ++-- .../domain/LocationAndName.java} | 22 ++-- .../compute/domain/ResourceGroupAndName.java | 50 +++++++++ ... ResourceGroupAndNameAndIngressRules.java} | 33 +++--- .../AzureComputeImageExtension.java | 39 +++---- .../AzureComputeSecurityGroupExtension.java | 100 +++++++++--------- .../functions/CustomImageToVMImage.java | 4 +- .../NetworkSecurityGroupToSecurityGroup.java | 7 +- .../functions/TemplateToAvailabilitySet.java | 8 +- .../functions/VMHardwareToHardware.java | 22 ++-- .../arm/compute/functions/VMImageToImage.java | 25 +++-- .../VirtualMachineToNodeMetadata.java | 50 ++++----- .../functions/VirtualMachineToStatus.java | 11 +- .../loaders/CreateSecurityGroupIfNeeded.java | 15 +-- ...ocation.java => DefaultResourceGroup.java} | 6 +- .../compute/options/AzureTemplateOptions.java | 78 ++++++-------- .../compute/strategy/CleanupResources.java | 79 ++++++-------- ...va => CreateResourcesThenCreateNodes.java} | 76 +++++++------ .../azurecompute/arm/domain/IdReference.java | 39 ++++++- .../azurecompute/arm/domain/VMHardware.java | 11 +- .../azurecompute/arm/domain/VMImage.java | 8 ++ .../azurecompute/arm/features/JobApi.java | 2 +- .../azurecompute/arm/util/VMImages.java | 2 +- .../compute/AzureComputeServiceLiveTest.java | 29 ++--- .../compute/AzureTemplateBuilderLiveTest.java | 2 +- .../AzureComputeImageExtensionLiveTest.java | 24 ++--- ...ComputeSecurityGroupExtensionLiveTest.java | 40 ++++--- .../arm/domain/IdReferenceTest.java | 62 +++++++++++ .../arm/features/ImageApiLiveTest.java | 30 ++---- .../arm/features/LoadBalancerApiLiveTest.java | 50 +++------ .../arm/internal/AzureLiveTestUtils.java | 10 +- .../internal/BaseAzureComputeApiLiveTest.java | 2 +- 35 files changed, 577 insertions(+), 488 deletions(-) rename providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/{domain/RegionAndId.java => compute/domain/LocationAndName.java} (69%) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/domain/ResourceGroupAndName.java rename providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/domain/{RegionAndIdAndIngressRules.java => ResourceGroupAndNameAndIngressRules.java} (56%) rename providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/{ResourceGroupForLocation.java => DefaultResourceGroup.java} (91%) rename providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/{CreateResourceGroupThenCreateNodes.java => CreateResourcesThenCreateNodes.java} (77%) create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/domain/IdReferenceTest.java 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 7081486861..a25690f52a 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 @@ -17,15 +17,16 @@ package org.jclouds.azurecompute.arm; import java.io.Closeable; + import javax.ws.rs.PathParam; import org.jclouds.azurecompute.arm.features.AvailabilitySetApi; import org.jclouds.azurecompute.arm.features.DeploymentApi; +import org.jclouds.azurecompute.arm.features.DiskApi; import org.jclouds.azurecompute.arm.features.ImageApi; import org.jclouds.azurecompute.arm.features.JobApi; import org.jclouds.azurecompute.arm.features.LoadBalancerApi; import org.jclouds.azurecompute.arm.features.LocationApi; -import org.jclouds.azurecompute.arm.features.DiskApi; import org.jclouds.azurecompute.arm.features.NetworkInterfaceCardApi; import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi; import org.jclouds.azurecompute.arm.features.NetworkSecurityRuleApi; @@ -47,7 +48,7 @@ import org.jclouds.rest.annotations.Delegate; * @see doc */ public interface AzureComputeApi extends Closeable { - + /** * The Azure Resource Manager API includes operations for managing resource groups in your subscription. * @@ -56,6 +57,9 @@ public interface AzureComputeApi extends Closeable { @Delegate ResourceGroupApi getResourceGroupApi(); + /** + * Provides access to the Job tracking API. + */ @Delegate JobApi getJobApi(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java index f566a69c53..dcb9c442d8 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java @@ -31,8 +31,8 @@ import javax.inject.Provider; import javax.inject.Singleton; import org.jclouds.Constants; +import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName; import org.jclouds.azurecompute.arm.compute.strategy.CleanupResources; -import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.collect.Memoized; import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.callables.RunScriptOnNode; @@ -62,7 +62,6 @@ 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.cache.LoadingCache; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.ListeningExecutorService; @@ -70,7 +69,6 @@ import com.google.common.util.concurrent.ListeningExecutorService; @Singleton public class AzureComputeService extends BaseComputeService { private final CleanupResources cleanupResources; - private final LoadingCache resourceGroupMap; @Inject protected AzureComputeService(ComputeServiceContext context, Map credentialStore, @@ -89,14 +87,13 @@ public class AzureComputeService extends BaseComputeService { PersistNodeCredentials persistNodeCredentials, Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, CleanupResources cleanupResources, Optional imageExtension, - Optional securityGroupExtension, LoadingCache resourceGroupMap) { + Optional 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 = cleanupResources; - this.resourceGroupMap = resourceGroupMap; } @Override @@ -105,11 +102,11 @@ public class AzureComputeService extends BaseComputeService { ImmutableSet.Builder resourceGroups = ImmutableSet.builder(); for (NodeMetadata deadNode : deadNodes) { - ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(deadNode.getLocation().getId()); - - resourceGroups.add(resourceGroup.name()); + String resourceGroupName = ResourceGroupAndName.fromSlashEncoded(deadNode.getId()).resourceGroup(); + resourceGroups.add(resourceGroupName); + if (deadNode.getGroup() != null) { - regionGroups.put(resourceGroup.name(), deadNode.getGroup()); + regionGroups.put(resourceGroupName, deadNode.getGroup()); } try { 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 8f9b67c883..2e9e0f6ba4 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 @@ -19,10 +19,12 @@ package org.jclouds.azurecompute.arm.compute; import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.ImmutableList.builder; import static com.google.common.collect.ImmutableList.of; -import static com.google.common.collect.Iterables.contains; import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Iterables.getOnlyElement; import static com.google.common.collect.Iterables.transform; +import static com.google.common.collect.Lists.newArrayList; +import static org.jclouds.azurecompute.arm.compute.domain.LocationAndName.fromSlashEncoded; +import static org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName.fromResourceGroupAndName; import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.decodeFieldsFromUniqueId; import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.getMarketplacePlanFromImageMetadata; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; @@ -40,6 +42,7 @@ import javax.inject.Singleton; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.PublicIpAvailablePredicateFactory; +import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName; import org.jclouds.azurecompute.arm.compute.functions.CustomImageToVMImage; import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; import org.jclouds.azurecompute.arm.compute.strategy.CleanupResources; @@ -62,7 +65,6 @@ import org.jclouds.azurecompute.arm.domain.Offer; import org.jclouds.azurecompute.arm.domain.Plan; import org.jclouds.azurecompute.arm.domain.PublicIPAddress; import org.jclouds.azurecompute.arm.domain.PublicIPAddressProperties; -import org.jclouds.azurecompute.arm.domain.RegionAndId; import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.domain.ResourceProviderMetaData; import org.jclouds.azurecompute.arm.domain.SKU; @@ -90,7 +92,6 @@ 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.cache.LoadingCache; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -115,20 +116,18 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter imagePublishers; private final Supplier> regionIds; private final PublicIpAvailablePredicateFactory publicIpAvailable; - private final LoadingCache resourceGroupMap; private final CustomImageToVMImage customImagetoVmImage; @Inject AzureComputeServiceAdapter(final AzureComputeApi api, @Named(IMAGE_PUBLISHERS) String imagePublishers, CleanupResources cleanupResources, @Region Supplier> regionIds, - PublicIpAvailablePredicateFactory publicIpAvailable, LoadingCache resourceGroupMap, + PublicIpAvailablePredicateFactory publicIpAvailable, CustomImageToVMImage customImagetoVmImage) { this.api = api; this.imagePublishers = Splitter.on(',').trimResults().omitEmptyStrings().splitToList(imagePublishers); this.cleanupResources = cleanupResources; this.regionIds = regionIds; this.publicIpAvailable = publicIpAvailable; - this.resourceGroupMap = resourceGroupMap; this.customImagetoVmImage = customImagetoVmImage; } @@ -138,15 +137,15 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter metadataAndTags = metadataAndTagsAsCommaDelimitedValue(template.getOptions()); Plan plan = getMarketplacePlanFromImageMetadata(template.getImage()); - VirtualMachine virtualMachine = api.getVirtualMachineApi(resourceGroup.name()).createOrUpdate(name, template.getLocation().getId(), + VirtualMachine virtualMachine = api.getVirtualMachineApi(resourceGroupName).createOrUpdate(name, template.getLocation().getId(), virtualMachineProperties, metadataAndTags, plan); // 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. - RegionAndId regionAndId = RegionAndId.fromRegionAndId(locationName, name); - return new NodeAndInitialCredentials(virtualMachine, regionAndId.slashEncode(), null); + ResourceGroupAndName resourceGroupAndName = fromResourceGroupAndName(resourceGroupName, name); + return new NodeAndInitialCredentials(virtualMachine, resourceGroupAndName.slashEncode(), null); } @Override @@ -183,8 +182,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listCustomImagesByLocation(String location) { - ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(location); - List customImages = api.getVirtualMachineImageApi(resourceGroup.name()).list(); + private List listCustomImagesByResourceGroup(String resourceGroup) { + List customImages = api.getVirtualMachineImageApi(resourceGroup).list(); return Lists.transform(customImages, customImagetoVmImage); } @@ -231,16 +228,29 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listImages() { final ImmutableList.Builder osImages = ImmutableList.builder(); - Iterable availableLocationNames = transform(listLocations(), new Function() { - @Override - public String apply(Location location) { - return location.name(); - } - }); + final List availableLocationNames = newArrayList(transform(listLocations(), + new Function() { + @Override + public String apply(Location location) { + return location.name(); + } + })); for (String locationName : availableLocationNames) { osImages.addAll(listImagesByLocation(locationName)); - osImages.addAll(listCustomImagesByLocation(locationName)); + } + + // We need to look for custom images in all resource groups + Iterable resourceGroupsInLocation = filter(api.getResourceGroupApi().list(), + new Predicate() { + @Override + public boolean apply(ResourceGroup input) { + return availableLocationNames.contains(input.location()); + } + }); + + for (ResourceGroup resourceGroup : resourceGroupsInLocation) { + osImages.addAll(listCustomImagesByResourceGroup(resourceGroup.name())); } return osImages.build(); @@ -249,10 +259,10 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listNodesByIds(final Iterable ids) { - return filter(listNodes(), new Predicate() { + return transform(ids, new Function() { @Override - public boolean apply(VirtualMachine virtualMachine) { - return contains(ids, virtualMachine.id()); + public VirtualMachine apply(String input) { + return getNode(input); } }); } 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 cf3c90c58b..11d3ab141f 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 @@ -34,7 +34,7 @@ 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.domain.RegionAndIdAndIngressRules; +import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndNameAndIngressRules; import org.jclouds.azurecompute.arm.compute.extensions.AzureComputeImageExtension; import org.jclouds.azurecompute.arm.compute.extensions.AzureComputeSecurityGroupExtension; import org.jclouds.azurecompute.arm.compute.functions.LocationToLocation; @@ -44,9 +44,9 @@ 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.loaders.CreateSecurityGroupIfNeeded; -import org.jclouds.azurecompute.arm.compute.loaders.ResourceGroupForLocation; +import org.jclouds.azurecompute.arm.compute.loaders.DefaultResourceGroup; import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; -import org.jclouds.azurecompute.arm.compute.strategy.CreateResourceGroupThenCreateNodes; +import org.jclouds.azurecompute.arm.compute.strategy.CreateResourcesThenCreateNodes; import org.jclouds.azurecompute.arm.domain.Image; import org.jclouds.azurecompute.arm.domain.Location; import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; @@ -116,12 +116,12 @@ public class AzureComputeServiceContextModule extends bind(TemplateOptions.class).to(AzureTemplateOptions.class); bind(NodeAndTemplateOptionsToStatement.class).to(NodeAndTemplateOptionsToStatementWithoutPublicKey.class); - bind(CreateNodesInGroupThenAddToSet.class).to(CreateResourceGroupThenCreateNodes.class); + bind(CreateNodesInGroupThenAddToSet.class).to(CreateResourcesThenCreateNodes.class); - bind(new TypeLiteral>() { + bind(new TypeLiteral>() { }).to(CreateSecurityGroupIfNeeded.class); bind(new TypeLiteral>() { - }).to(ResourceGroupForLocation.class); + }).to(DefaultResourceGroup.class); bind(new TypeLiteral() { }).to(AzureComputeImageExtension.class); @@ -131,14 +131,14 @@ public class AzureComputeServiceContextModule extends @Provides @Singleton - protected final LoadingCache securityGroupMap( - CacheLoader in) { + protected final LoadingCache securityGroupMap( + CacheLoader in) { return CacheBuilder.newBuilder().build(in); } @Provides @Singleton - protected final LoadingCache resourceGroupMap(CacheLoader in) { + protected final LoadingCache defaultResourceGroup(CacheLoader in) { return CacheBuilder.newBuilder().build(in); } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/RegionAndId.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/domain/LocationAndName.java similarity index 69% rename from providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/RegionAndId.java rename to providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/domain/LocationAndName.java index 4105ee3dc9..014244882a 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/RegionAndId.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/domain/LocationAndName.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jclouds.azurecompute.arm.domain; +package org.jclouds.azurecompute.arm.compute.domain; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; @@ -24,27 +24,27 @@ import com.google.common.base.Splitter; import com.google.common.collect.Iterables; @AutoValue -public abstract class RegionAndId { +public abstract class LocationAndName { - public abstract String region(); - public abstract String id(); + public abstract String location(); + public abstract String name(); - protected RegionAndId() { + protected LocationAndName() { } - public static RegionAndId fromSlashEncoded(String id) { + public static LocationAndName fromSlashEncoded(String id) { Iterable parts = Splitter.on('/').split(checkNotNull(id, "id")); - checkArgument(Iterables.size(parts) == 2, "id must be in format regionId/id"); - return new AutoValue_RegionAndId(Iterables.get(parts, 0), Iterables.get(parts, 1)); + checkArgument(Iterables.size(parts) == 2, "id must be in format location/name"); + return new AutoValue_LocationAndName(Iterables.get(parts, 0), Iterables.get(parts, 1)); } - public static RegionAndId fromRegionAndId(String region, String id) { - return new AutoValue_RegionAndId(region, id); + public static LocationAndName fromLocationAndName(String location, String name) { + return new AutoValue_LocationAndName(location, name); } public String slashEncode() { - return region() + "/" + id(); + return location() + "/" + name(); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/domain/ResourceGroupAndName.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/domain/ResourceGroupAndName.java new file mode 100644 index 0000000000..c06056ecc4 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/domain/ResourceGroupAndName.java @@ -0,0 +1,50 @@ +/* + * 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.domain; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.auto.value.AutoValue; +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; + +@AutoValue +public abstract class ResourceGroupAndName { + + public abstract String resourceGroup(); + public abstract String name(); + + protected ResourceGroupAndName() { + + } + + public static ResourceGroupAndName fromSlashEncoded(String id) { + Iterable parts = Splitter.on('/').split(checkNotNull(id, "id")); + checkArgument(Iterables.size(parts) == 2, "id must be in format resourcegroup/name"); + return new AutoValue_ResourceGroupAndName(Iterables.get(parts, 0), Iterables.get(parts, 1)); + } + + public static ResourceGroupAndName fromResourceGroupAndName(String resourceGroup, String name) { + return new AutoValue_ResourceGroupAndName(resourceGroup, name); + } + + public String slashEncode() { + return resourceGroup() + "/" + name(); + } + +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/domain/RegionAndIdAndIngressRules.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/domain/ResourceGroupAndNameAndIngressRules.java similarity index 56% rename from providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/domain/RegionAndIdAndIngressRules.java rename to providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/domain/ResourceGroupAndNameAndIngressRules.java index fa9730d183..2b07406e45 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/domain/RegionAndIdAndIngressRules.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/domain/ResourceGroupAndNameAndIngressRules.java @@ -16,31 +16,36 @@ */ package org.jclouds.azurecompute.arm.compute.domain; -import org.jclouds.azurecompute.arm.domain.RegionAndId; +import static org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName.fromResourceGroupAndName; import com.google.auto.value.AutoValue; import com.google.common.base.Objects; @AutoValue -public abstract class RegionAndIdAndIngressRules { +public abstract class ResourceGroupAndNameAndIngressRules { + + abstract ResourceGroupAndName resourceGroupAndName(); // Intentionally hidden + + public abstract String location(); - abstract RegionAndId regionAndId(); // Intentionally hidden public abstract int[] inboundPorts(); - RegionAndIdAndIngressRules() { + ResourceGroupAndNameAndIngressRules() { } - public static RegionAndIdAndIngressRules create(String region, String id, int[] inboundPorts) { - return new AutoValue_RegionAndIdAndIngressRules(RegionAndId.fromRegionAndId(region, id), inboundPorts); + public static ResourceGroupAndNameAndIngressRules create(String resourceGroup, String location, String name, + int[] inboundPorts) { + return new AutoValue_ResourceGroupAndNameAndIngressRules(fromResourceGroupAndName(resourceGroup, name), location, + inboundPorts); } - public String id() { - return regionAndId().id(); + public String name() { + return resourceGroupAndName().name(); } - public String region() { - return regionAndId().region(); + public String resourceGroup() { + return resourceGroupAndName().resourceGroup(); } // Intentionally delegate equals and hashcode to the fields in the parent @@ -48,7 +53,7 @@ public abstract class RegionAndIdAndIngressRules { @Override public int hashCode() { - return Objects.hashCode(region(), id()); + return Objects.hashCode(resourceGroup(), name()); } @Override @@ -56,11 +61,11 @@ public abstract class RegionAndIdAndIngressRules { if (obj == this) { return true; } - if (!(obj instanceof RegionAndId)) { + if (!(obj instanceof ResourceGroupAndName)) { return false; } - RegionAndId that = (RegionAndId) obj; - return Objects.equal(region(), that.region()) && Objects.equal(id(), that.id()); + ResourceGroupAndName that = (ResourceGroupAndName) obj; + return Objects.equal(resourceGroup(), that.resourceGroup()) && Objects.equal(name(), that.name()); } } 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 4bfa449fac..7d654d56a1 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 @@ -19,6 +19,7 @@ package org.jclouds.azurecompute.arm.compute.extensions; import static com.google.common.base.Functions.compose; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; +import static org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName.fromSlashEncoded; import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.decodeFieldsFromUniqueId; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; @@ -32,11 +33,10 @@ import org.jclouds.Constants; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.ImageAvailablePredicateFactory; import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.VirtualMachineInStatePredicateFactory; +import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName; import org.jclouds.azurecompute.arm.compute.functions.CustomImageToVMImage; import org.jclouds.azurecompute.arm.domain.IdReference; import org.jclouds.azurecompute.arm.domain.ImageProperties; -import org.jclouds.azurecompute.arm.domain.RegionAndId; -import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.domain.VMImage; import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.compute.domain.CloneImageTemplate; @@ -49,7 +49,6 @@ import org.jclouds.logging.Logger; import com.google.common.base.Function; import com.google.common.base.Predicate; -import com.google.common.cache.LoadingCache; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.inject.Inject; @@ -66,25 +65,21 @@ public class AzureComputeImageExtension implements ImageExtension { private final ListeningExecutorService userExecutor; private final ImageAvailablePredicateFactory imageAvailablePredicate; private final VirtualMachineInStatePredicateFactory nodeSuspendedPredicate; - private final LoadingCache resourceGroupMap; private final Function vmImageToImage; private final Predicate resourceDeleted; private final CustomImageToVMImage customImagetoVmImage; @Inject - AzureComputeImageExtension(AzureComputeApi api, - ImageAvailablePredicateFactory imageAvailablePredicate, + AzureComputeImageExtension(AzureComputeApi api, ImageAvailablePredicateFactory imageAvailablePredicate, @Named(TIMEOUT_NODE_SUSPENDED) VirtualMachineInStatePredicateFactory nodeSuspendedPredicate, @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, - Function vmImageToImage, LoadingCache resourceGroupMap, - @Named(TIMEOUT_RESOURCE_DELETED) Predicate resourceDeleted, + Function vmImageToImage, @Named(TIMEOUT_RESOURCE_DELETED) Predicate resourceDeleted, CustomImageToVMImage customImagetoVmImage) { this.api = api; this.imageAvailablePredicate = imageAvailablePredicate; this.nodeSuspendedPredicate = nodeSuspendedPredicate; this.userExecutor = userExecutor; this.vmImageToImage = vmImageToImage; - this.resourceGroupMap = resourceGroupMap; this.resourceDeleted = resourceDeleted; this.customImagetoVmImage = customImagetoVmImage; } @@ -97,27 +92,27 @@ public class AzureComputeImageExtension implements ImageExtension { @Override public ListenableFuture createImage(ImageTemplate template) { final CloneImageTemplate cloneTemplate = (CloneImageTemplate) template; - final RegionAndId regionAndId = RegionAndId.fromSlashEncoded(cloneTemplate.getSourceNodeId()); - ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(regionAndId.region()); - final String resourceGroupName = resourceGroup.name(); + final ResourceGroupAndName resourceGroupAndName = fromSlashEncoded(cloneTemplate.getSourceNodeId()); + final String resourceGroupName = resourceGroupAndName.resourceGroup(); + final String vmName = resourceGroupAndName.name(); - final VirtualMachine vm = api.getVirtualMachineApi(resourceGroupName).get(regionAndId.id()); + final VirtualMachine vm = api.getVirtualMachineApi(resourceGroupName).get(vmName); final IdReference vmIdRef = IdReference.create(vm.id()); - logger.debug(">> stopping node %s...", regionAndId.slashEncode()); - api.getVirtualMachineApi(resourceGroupName).stop(regionAndId.id()); - checkState(nodeSuspendedPredicate.create(resourceGroupName).apply(regionAndId.id()), - "Node %s was not suspended within the configured time limit", regionAndId.slashEncode()); + logger.debug(">> stopping node %s...", cloneTemplate.getSourceNodeId()); + api.getVirtualMachineApi(resourceGroupName).stop(vmName); + checkState(nodeSuspendedPredicate.create(resourceGroupName).apply(vmName), + "Node %s was not suspended within the configured time limit", cloneTemplate.getSourceNodeId()); return userExecutor.submit(new Callable() { @Override public Image call() throws Exception { - logger.debug(">> generalizing virtal machine %s...", regionAndId.id()); + logger.debug(">> generalizing virtal machine %s...", vmName); - api.getVirtualMachineApi(resourceGroupName).generalize(regionAndId.id()); + api.getVirtualMachineApi(resourceGroupName).generalize(vmName); org.jclouds.azurecompute.arm.domain.Image imageFromVM = api.getVirtualMachineImageApi(resourceGroupName) - .createOrUpdate(cloneTemplate.getName(), regionAndId.region(), + .createOrUpdate(cloneTemplate.getName(), vm.location(), ImageProperties.builder().sourceVirtualMachine(vmIdRef).build()); checkState(imageAvailablePredicate.create(resourceGroupName).apply(imageFromVM.name()), @@ -134,9 +129,7 @@ public class AzureComputeImageExtension implements ImageExtension { checkArgument(image.custom(), "Only custom images can be deleted"); logger.debug(">> deleting image %s", id); - - ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(image.location()); - URI uri = api.getVirtualMachineImageApi(resourceGroup.name()).delete(image.name()); + URI uri = api.getVirtualMachineImageApi(image.resourceGroup()).delete(image.name()); return resourceDeleted.apply(uri); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java index f23cfd83c9..eafb4f1409 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java @@ -20,10 +20,10 @@ import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Predicates.equalTo; import static com.google.common.base.Predicates.notNull; import static com.google.common.collect.Iterables.any; -import static com.google.common.collect.Iterables.concat; 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.predicates.NodePredicates.locationId; import java.net.URI; import java.util.ArrayList; @@ -36,6 +36,7 @@ import javax.inject.Named; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.SecurityGroupAvailablePredicateFactory; +import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName; import org.jclouds.azurecompute.arm.domain.IdReference; import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; @@ -45,12 +46,10 @@ import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties; import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Access; import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Direction; import org.jclouds.azurecompute.arm.domain.NetworkSecurityRuleProperties.Protocol; -import org.jclouds.azurecompute.arm.domain.RegionAndId; import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi; import org.jclouds.azurecompute.arm.features.NetworkSecurityRuleApi; -import org.jclouds.collect.Memoized; import org.jclouds.compute.domain.SecurityGroup; import org.jclouds.compute.domain.SecurityGroupBuilder; import org.jclouds.compute.extensions.SecurityGroupExtension; @@ -63,11 +62,8 @@ import org.jclouds.net.domain.IpProtocol; 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.cache.LoadingCache; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; import com.google.common.collect.Multimap; import com.google.common.collect.Ordering; @@ -78,64 +74,67 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio private final AzureComputeApi api; private final Function securityGroupConverter; - private final Supplier> locations; private final SecurityGroupAvailablePredicateFactory securityGroupAvailable; private final Predicate resourceDeleted; - private final LoadingCache resourceGroupMap; + private final LoadingCache defaultResourceGroup; @Inject - AzureComputeSecurityGroupExtension(AzureComputeApi api, @Memoized Supplier> locations, + AzureComputeSecurityGroupExtension(AzureComputeApi api, Function groupConverter, SecurityGroupAvailablePredicateFactory securityRuleAvailable, @Named(TIMEOUT_RESOURCE_DELETED) Predicate resourceDeleted, - LoadingCache resourceGroupMap) { + LoadingCache defaultResourceGroup) { this.api = api; - this.locations = locations; this.securityGroupConverter = groupConverter; this.securityGroupAvailable = securityRuleAvailable; this.resourceDeleted = resourceDeleted; - this.resourceGroupMap = resourceGroupMap; + this.defaultResourceGroup = defaultResourceGroup; } @Override public Set listSecurityGroups() { - return ImmutableSet.copyOf(concat(transform(locations.get(), new Function>() { - @Override - public Set apply(Location input) { - return listSecurityGroupsInLocation(input); - } - }))); + ImmutableSet.Builder securityGroups = ImmutableSet.builder(); + for (ResourceGroup rg : api.getResourceGroupApi().list()) { + securityGroups.addAll(securityGroupsInResourceGroup(rg.name())); + } + return securityGroups.build(); + } + + private Set securityGroupsInResourceGroup(String resourceGroup) { + List networkGroups = api.getNetworkSecurityGroupApi(resourceGroup).list(); + return ImmutableSet.copyOf(transform(filter(networkGroups, notNull()), securityGroupConverter)); } @Override public Set listSecurityGroupsInLocation(Location location) { - logger.debug(">> getting security groups for %s...", location); - ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(location.getId()); - List networkGroups = api.getNetworkSecurityGroupApi(resourceGroup.name()).list(); - return ImmutableSet.copyOf(transform(filter(networkGroups, notNull()), securityGroupConverter)); + // Even though the resource groups are in a location, each security group + // can be in a different resource group, so we need to inspect all teh + // existing resource groups, and filter afterwards + return ImmutableSet.copyOf(filter(listSecurityGroups(), locationId(location.getId()))); } @Override public Set listSecurityGroupsForNode(String nodeId) { logger.debug(">> getting security groups for node %s...", nodeId); - final RegionAndId regionAndId = RegionAndId.fromSlashEncoded(nodeId); - ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(regionAndId.region()); + final ResourceGroupAndName resourceGroupAndName = ResourceGroupAndName.fromSlashEncoded(nodeId); - VirtualMachine vm = api.getVirtualMachineApi(resourceGroup.name()).get(regionAndId.id()); + VirtualMachine vm = api.getVirtualMachineApi(resourceGroupAndName.resourceGroup()).get( + resourceGroupAndName.name()); if (vm == null) { - throw new IllegalArgumentException("Node " + regionAndId.id() + " was not found"); + throw new IllegalArgumentException("Node " + nodeId + " was not found"); } List networkInterfacesIdReferences = vm.properties().networkProfile().networkInterfaces(); List networkGroups = new ArrayList(); for (IdReference networkInterfaceCardIdReference : networkInterfacesIdReferences) { - String nicName = Iterables.getLast(Splitter.on("/").split(networkInterfaceCardIdReference.id())); - NetworkInterfaceCard card = api.getNetworkInterfaceCardApi(resourceGroup.name()).get(nicName); + String nicName = networkInterfaceCardIdReference.name(); + String nicResourceGroup = networkInterfaceCardIdReference.resourceGroup(); + NetworkInterfaceCard card = api.getNetworkInterfaceCardApi(nicResourceGroup).get(nicName); if (card != null && card.properties().networkSecurityGroup() != null) { - String secGroupName = Iterables.getLast(Splitter.on("/").split( - card.properties().networkSecurityGroup().id())); - NetworkSecurityGroup group = api.getNetworkSecurityGroupApi(resourceGroup.name()).get(secGroupName); + String secGroupName = card.properties().networkSecurityGroup().name(); + String sgResourceGroup = card.properties().networkSecurityGroup().resourceGroup(); + NetworkSecurityGroup group = api.getNetworkSecurityGroupApi(sgResourceGroup).get(secGroupName); networkGroups.add(group); } } @@ -146,15 +145,15 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio @Override public SecurityGroup getSecurityGroupById(String id) { logger.debug(">> getting security group %s...", id); - final RegionAndId regionAndId = RegionAndId.fromSlashEncoded(id); - ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(regionAndId.region()); - NetworkSecurityGroup securityGroup = api.getNetworkSecurityGroupApi(resourceGroup.name()).get(regionAndId.id()); + final ResourceGroupAndName resourceGroupAndName = ResourceGroupAndName.fromSlashEncoded(id); + NetworkSecurityGroup securityGroup = api.getNetworkSecurityGroupApi(resourceGroupAndName.resourceGroup()).get( + resourceGroupAndName.name()); return securityGroup == null ? null : securityGroupConverter.apply(securityGroup); } @Override public SecurityGroup createSecurityGroup(String name, Location location) { - ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(location.getId()); + ResourceGroup resourceGroup = defaultResourceGroup.getUnchecked(location.getId()); logger.debug(">> creating security group %s in %s...", name, location); @@ -170,9 +169,9 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio public boolean removeSecurityGroup(String id) { logger.debug(">> deleting security group %s...", id); - final RegionAndId regionAndId = RegionAndId.fromSlashEncoded(id); - ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(regionAndId.region()); - URI uri = api.getNetworkSecurityGroupApi(resourceGroup.name()).delete(regionAndId.id()); + final ResourceGroupAndName resourceGroupAndName = ResourceGroupAndName.fromSlashEncoded(id); + URI uri = api.getNetworkSecurityGroupApi(resourceGroupAndName.resourceGroup()) + .delete(resourceGroupAndName.name()); return resourceDeleted.apply(uri); } @@ -199,17 +198,16 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio // TODO: Support Azure network tags somehow? - final RegionAndId regionAndId = RegionAndId.fromSlashEncoded(group.getId()); - ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(regionAndId.region()); + final ResourceGroupAndName resourceGroupAndName = ResourceGroupAndName.fromSlashEncoded(group.getId()); - NetworkSecurityGroupApi groupApi = api.getNetworkSecurityGroupApi(resourceGroup.name()); - NetworkSecurityGroup networkSecurityGroup = groupApi.get(regionAndId.id()); + NetworkSecurityGroupApi groupApi = api.getNetworkSecurityGroupApi(resourceGroupAndName.resourceGroup()); + NetworkSecurityGroup networkSecurityGroup = groupApi.get(resourceGroupAndName.name()); if (networkSecurityGroup == null) { throw new IllegalArgumentException("Security group " + group.getName() + " was not found"); } - NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourceGroup.name(), networkSecurityGroup.name()); + NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourceGroupAndName.resourceGroup(), networkSecurityGroup.name()); int nextPriority = getRuleStartingPriority(networkSecurityGroup); for (String ipRange : ipRanges) { @@ -228,7 +226,8 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio ruleApi.createOrUpdate(ruleName, properties); - checkState(securityGroupAvailable.create(resourceGroup.name()).apply(networkSecurityGroup.name()), + checkState( + securityGroupAvailable.create(resourceGroupAndName.resourceGroup()).apply(networkSecurityGroup.name()), "Security group was not updated in the configured timeout"); } @@ -244,17 +243,17 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio logger.debug(">> deleting ip permissions matching [%s] from %s...", ruleName, group.getName()); - final RegionAndId regionAndId = RegionAndId.fromSlashEncoded(group.getId()); - ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(regionAndId.region()); + final ResourceGroupAndName resourceGroupAndName = ResourceGroupAndName.fromSlashEncoded(group.getId()); - NetworkSecurityGroupApi groupApi = api.getNetworkSecurityGroupApi(resourceGroup.name()); - NetworkSecurityGroup networkSecurityGroup = groupApi.get(regionAndId.id()); + NetworkSecurityGroupApi groupApi = api.getNetworkSecurityGroupApi(resourceGroupAndName.resourceGroup()); + NetworkSecurityGroup networkSecurityGroup = groupApi.get(resourceGroupAndName.name()); if (networkSecurityGroup == null) { throw new IllegalArgumentException("Security group " + group.getName() + " was not found"); } - NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourceGroup.name(), networkSecurityGroup.name()); + NetworkSecurityRuleApi ruleApi = api.getNetworkSecurityRuleApi(resourceGroupAndName.resourceGroup(), + networkSecurityGroup.name()); Iterable rules = filter(ruleApi.list(), new Predicate() { @Override public boolean apply(NetworkSecurityRule input) { @@ -270,7 +269,8 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio for (NetworkSecurityRule matchingRule : rules) { logger.debug(">> deleting network security rule %s from %s...", matchingRule.name(), group.getName()); ruleApi.delete(matchingRule.name()); - checkState(securityGroupAvailable.create(resourceGroup.name()).apply(networkSecurityGroup.name()), + checkState( + securityGroupAvailable.create(resourceGroupAndName.resourceGroup()).apply(networkSecurityGroup.name()), "Security group was not updated in the configured timeout"); } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/CustomImageToVMImage.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/CustomImageToVMImage.java index 9cb21882c7..222053555a 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/CustomImageToVMImage.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/CustomImageToVMImage.java @@ -16,6 +16,8 @@ */ package org.jclouds.azurecompute.arm.compute.functions; +import static org.jclouds.azurecompute.arm.domain.IdReference.extractResourceGroup; + import org.jclouds.azurecompute.arm.domain.Image; import org.jclouds.azurecompute.arm.domain.VMImage; @@ -25,7 +27,7 @@ public class CustomImageToVMImage implements Function { @Override public VMImage apply(Image input) { - return VMImage.customImage().customImageId(input.id()).location(input.location()).name(input.name()) + return VMImage.customImage().resourceGroup(extractResourceGroup(input.id())).customImageId(input.id()).location(input.location()).name(input.name()) .offer(input.properties().storageProfile().osDisk().osType()).build(); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityGroupToSecurityGroup.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityGroupToSecurityGroup.java index 65f5b0d8aa..71d51aae70 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityGroupToSecurityGroup.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityGroupToSecurityGroup.java @@ -18,8 +18,10 @@ package org.jclouds.azurecompute.arm.compute.functions; import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Iterables.transform; +import static org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName.fromResourceGroupAndName; import static org.jclouds.azurecompute.arm.compute.functions.NetworkSecurityRuleToIpPermission.InboundRule; import static org.jclouds.azurecompute.arm.compute.functions.VirtualMachineToNodeMetadata.getLocation; +import static org.jclouds.azurecompute.arm.domain.IdReference.extractResourceGroup; import java.util.Set; @@ -27,7 +29,6 @@ import javax.inject.Singleton; import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; import org.jclouds.azurecompute.arm.domain.NetworkSecurityRule; -import org.jclouds.azurecompute.arm.domain.RegionAndId; import org.jclouds.collect.Memoized; import org.jclouds.compute.domain.SecurityGroup; import org.jclouds.compute.domain.SecurityGroupBuilder; @@ -54,8 +55,8 @@ public class NetworkSecurityGroupToSecurityGroup implements Function { @@ -46,12 +44,10 @@ public class TemplateToAvailabilitySet implements Function resourceGroupMap; @Inject - TemplateToAvailabilitySet(AzureComputeApi api, LoadingCache resourceGroupMap) { + TemplateToAvailabilitySet(AzureComputeApi api) { this.api = api; - this.resourceGroupMap = resourceGroupMap; } @Nullable @@ -62,7 +58,7 @@ public class TemplateToAvailabilitySet implements Function { @@ -49,10 +51,10 @@ public class VMHardwareToHardware implements Function { final HardwareBuilder builder = new HardwareBuilder() .name(from.name()) .providerId(from.name()) - .id(from.name()) + .id(fromLocationAndName(from.location(), from.name()).slashEncode()) .processors(ImmutableList.of(new Processor(from.numberOfCores(), 2))) .ram(from.memoryInMB()) - .location(from.globallyAvailable() ? null : FluentIterable.from(locations.get()) + .location(FluentIterable.from(locations.get()) .firstMatch(LocationPredicates.idEquals(from.location())) .get()); 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 4f021002b3..2a5075ce98 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,6 +16,12 @@ */ package org.jclouds.azurecompute.arm.compute.functions; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Iterables.tryFind; +import static java.util.Arrays.asList; +import static org.jclouds.azurecompute.arm.domain.IdReference.extractResourceGroup; +import static org.jclouds.azurecompute.arm.util.VMImages.isCustom; + import java.util.Map; import java.util.Set; @@ -40,11 +46,6 @@ import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableMap; import com.google.inject.Inject; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.collect.Iterables.tryFind; -import static java.util.Arrays.asList; -import static org.jclouds.azurecompute.arm.util.VMImages.isCustom; - public class VMImageToImage implements Function { private static final Map OTHER_OS_MAP = ImmutableMap. builder() @@ -64,8 +65,8 @@ public class VMImageToImage implements Function { public static String encodeFieldsToUniqueIdCustom(boolean globallyAvailable, String locationName, ImageReference imageReference) { - return (globallyAvailable ? "global" : locationName) + "/" + imageReference.customImageId() - .substring(imageReference.customImageId().lastIndexOf("/") + 1); + return extractResourceGroup(imageReference.customImageId()) + "/" + (globallyAvailable ? "global" : locationName) + + "/" + imageReference.customImageId().substring(imageReference.customImageId().lastIndexOf("/") + 1); } public static String encodeFieldsToUniqueId(VMImage imageReference) { @@ -74,7 +75,8 @@ public class VMImageToImage implements Function { } public static String encodeFieldsToUniqueIdCustom(VMImage imageReference) { - return (imageReference.globallyAvailable() ? "global" : imageReference.location()) + "/" + imageReference.name(); + return imageReference.resourceGroup() + "/" + + (imageReference.globallyAvailable() ? "global" : imageReference.location()) + "/" + imageReference.name(); } public static VMImage decodeFieldsFromUniqueId(final String id) { @@ -82,10 +84,11 @@ public class VMImageToImage implements Function { String[] fields = checkNotNull(id, "id").split("/"); if (isCustom(id)) { /* id fields indexes - 0: imageReference.location + "/" + - 1: imageReference.name + 0: imageReference.resourceGroup + 1: imageReference.location + "/" + + 2: imageReference.name */ - vmImage = VMImage.customImage().location(fields[0]).name(fields[1]).build(); + vmImage = VMImage.customImage().resourceGroup(fields[0]).location(fields[1]).name(fields[2]).build(); } else { /* id fields indexes 0: imageReference.location + "/" + 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 index 9bad6e57e1..bcfd4fee03 100644 --- 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 @@ -20,8 +20,11 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Strings.nullToEmpty; import static com.google.common.collect.Iterables.find; import static org.jclouds.azurecompute.arm.compute.AzureComputeServiceAdapter.GROUP_KEY; +import static org.jclouds.azurecompute.arm.compute.domain.LocationAndName.fromLocationAndName; +import static org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName.fromResourceGroupAndName; import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.encodeFieldsToUniqueId; import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.encodeFieldsToUniqueIdCustom; +import static org.jclouds.azurecompute.arm.domain.IdReference.extractResourceGroup; import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromCommaDelimitedValue; import static org.jclouds.location.predicates.LocationPredicates.idEquals; @@ -34,13 +37,12 @@ import javax.inject.Inject; import javax.inject.Named; import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.compute.domain.LocationAndName; import org.jclouds.azurecompute.arm.compute.functions.VirtualMachineToStatus.StatusAndBackendStatus; 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.PublicIPAddress; -import org.jclouds.azurecompute.arm.domain.RegionAndId; -import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.domain.StorageProfile; import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.collect.Memoized; @@ -58,10 +60,7 @@ import org.jclouds.logging.Logger; import com.google.common.base.Function; 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.cache.LoadingCache; -import com.google.common.collect.Iterables; import com.google.common.collect.Lists; public class VirtualMachineToNodeMetadata implements Function { @@ -74,20 +73,18 @@ public class VirtualMachineToNodeMetadata implements Function> locations; private final Supplier> hardwares; - private final LoadingCache resourceGroupMap; private final ImageCacheSupplier imageCache; private final VirtualMachineToStatus virtualMachineToStatus; @Inject VirtualMachineToNodeMetadata(AzureComputeApi api, GroupNamingConvention.Factory namingConvention, Supplier> hardwares, @Memoized Supplier> locations, - Map credentialStore, LoadingCache resourceGroupMap, - @Memoized Supplier> imageCache, VirtualMachineToStatus virtualMachineToStatus) { + Map credentialStore, @Memoized Supplier> imageCache, + VirtualMachineToStatus virtualMachineToStatus) { this.api = api; this.nodeNamingConvention = namingConvention.createWithoutPrefix(); this.locations = locations; this.hardwares = hardwares; - this.resourceGroupMap = resourceGroupMap; this.virtualMachineToStatus = virtualMachineToStatus; checkArgument(imageCache instanceof ImageCacheSupplier, "This provider needs an instance of the ImageCacheSupplier"); @@ -96,10 +93,9 @@ public class VirtualMachineToNodeMetadata implements Function image = findImage(virtualMachine.properties().storageProfile(), locationName, - resourceGroup.name()); + Optional image = findImage(virtualMachine.properties().storageProfile(), locationName); if (image.isPresent()) { builder.imageId(image.get().getId()); @@ -137,7 +132,8 @@ public class VirtualMachineToNodeMetadata implements Function getPublicIpAddresses(List idReferences) { @@ -172,11 +164,11 @@ public class VirtualMachineToNodeMetadata implements Function findImage(final StorageProfile storageProfile, String locatioName, - String azureGroup) { + protected Optional findImage(final StorageProfile storageProfile, String locatioName) { if (storageProfile.imageReference() != null) { // FIXME check this condition String imageId = storageProfile.imageReference().customImageId() != null ? @@ -205,11 +196,12 @@ public class VirtualMachineToNodeMetadata implements Function() { + protected Hardware getHardware(final LocationAndName hardwareId) { + final String slashEncoded = hardwareId.slashEncode(); + return find(hardwares.get().values(), new Predicate() { @Override public boolean apply(Hardware input) { - return input.getId().equals(vmSize); + return input.getId().equals(slashEncoded); } }); } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VirtualMachineToStatus.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VirtualMachineToStatus.java index c0e333e3b1..9669f50b70 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VirtualMachineToStatus.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/VirtualMachineToStatus.java @@ -17,13 +17,13 @@ package org.jclouds.azurecompute.arm.compute.functions; import static com.google.common.collect.Iterables.transform; +import static org.jclouds.azurecompute.arm.domain.IdReference.extractResourceGroup; import javax.inject.Inject; import javax.inject.Singleton; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.compute.functions.VirtualMachineToStatus.StatusAndBackendStatus; -import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.domain.Status; import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance; @@ -36,7 +36,6 @@ import com.google.auto.value.AutoValue; import com.google.common.base.Function; import com.google.common.base.Functions; import com.google.common.base.Joiner; -import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableMap; @Singleton @@ -80,17 +79,15 @@ public class VirtualMachineToStatus implements Function resourceGroupMap; @Inject - VirtualMachineToStatus(AzureComputeApi api, LoadingCache resourceGroupMap) { + VirtualMachineToStatus(AzureComputeApi api) { this.api = api; - this.resourceGroupMap = resourceGroupMap; } @Override public StatusAndBackendStatus apply(VirtualMachine virtualMachine) { - ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(virtualMachine.location()); + String resourceGroup = extractResourceGroup(virtualMachine.id()); ProvisioningState provisioningState = virtualMachine.properties().provisioningState(); NodeMetadata.Status status = PROVISIONINGSTATE_TO_NODESTATUS.apply(provisioningState); @@ -99,7 +96,7 @@ public class VirtualMachineToStatus implements Function { +public class CreateSecurityGroupIfNeeded extends CacheLoader { @Resource @Named(ComputeServiceConstants.COMPUTE_LOGGER) protected Logger logger = Logger.NULL; private final AzureComputeApi api; - private final LoadingCache resourceGroupMap; @Inject - CreateSecurityGroupIfNeeded(AzureComputeApi api, LoadingCache resourceGroupMap) { + CreateSecurityGroupIfNeeded(AzureComputeApi api) { this.api = api; - this.resourceGroupMap = resourceGroupMap; } @Override - public String load(RegionAndIdAndIngressRules key) throws Exception { - ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(key.region()); - return createSecurityGroup(key.region(), resourceGroup.name(), key.id(), key.inboundPorts()); + public String load(ResourceGroupAndNameAndIngressRules key) throws Exception { + return createSecurityGroup(key.location(), key.resourceGroup(), key.name(), key.inboundPorts()); } private String createSecurityGroup(String location, String resourceGroup, String name, int[] inboundPorts) { diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/ResourceGroupForLocation.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/DefaultResourceGroup.java similarity index 91% rename from providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/ResourceGroupForLocation.java rename to providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/DefaultResourceGroup.java index ddbbb26ef2..7caec25e90 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/ResourceGroupForLocation.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/DefaultResourceGroup.java @@ -34,7 +34,7 @@ import com.google.common.cache.CacheLoader; import com.google.common.collect.ImmutableMap; @Singleton -public class ResourceGroupForLocation extends CacheLoader { +public class DefaultResourceGroup extends CacheLoader { @Resource @Named(ComputeServiceConstants.COMPUTE_LOGGER) protected Logger logger = Logger.NULL; @@ -43,7 +43,7 @@ public class ResourceGroupForLocation extends CacheLoader private final LocationToResourceGroupName locationToResourceGroupName; @Inject - ResourceGroupForLocation(AzureComputeApi api, LocationToResourceGroupName locationToResourceGroupName) { + DefaultResourceGroup(AzureComputeApi api, LocationToResourceGroupName locationToResourceGroupName) { this.api = api.getResourceGroupApi(); this.locationToResourceGroupName = locationToResourceGroupName; } @@ -54,7 +54,7 @@ public class ResourceGroupForLocation extends CacheLoader ResourceGroup resourceGroup = api.get(azureGroupName); if (resourceGroup == null) { logger.debug(">> creating resource group %s", azureGroupName); - final Map tags = ImmutableMap.of("description", "jclouds managed VMs"); + final Map tags = ImmutableMap.of("description", "jclouds default resource group"); resourceGroup = api.create(azureGroupName, locationId, tags); } return resourceGroup; 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 5566ecfb33..d211421bc6 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 @@ -34,10 +34,10 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { private String virtualNetworkName; private String subnetId; - private String blob; private AvailabilitySet availabilitySet; private String availabilitySetName; private List dataDisks = ImmutableList.of(); + private String resourceGroup; /** * Sets the virtual network name @@ -54,14 +54,6 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { this.subnetId = subnetId; return this; } - - /** - * Sets the blob name - */ - public AzureTemplateOptions blob(String blob) { - this.blob = blob; - return this; - } /** * Sets the availability set where the nodes will be configured. If it does @@ -80,6 +72,14 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { this.availabilitySetName = availabilitySetName; return this; } + + /** + * The resource group where the new resources will be created. + */ + public AzureTemplateOptions resourceGroup(String resourceGroup) { + this.resourceGroup = resourceGroup; + return this; + } public AzureTemplateOptions dataDisks(Iterable dataDisks) { for (DataDisk dataDisk : checkNotNull(dataDisks, "dataDisks")) @@ -94,12 +94,10 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { public String getVirtualNetworkName() { return virtualNetworkName; } public String getSubnetId() { return subnetId; } - public String getBlob() { return blob; } public AvailabilitySet getAvailabilitySet() { return availabilitySet; } public String getAvailabilitySetName() { return availabilitySetName; } - public List getDataDisks() { - return dataDisks; - } + public List getDataDisks() { return dataDisks; } + public String getResourceGroup() { return resourceGroup; } @Override public AzureTemplateOptions clone() { @@ -115,10 +113,10 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { AzureTemplateOptions eTo = AzureTemplateOptions.class.cast(to); eTo.virtualNetworkName(virtualNetworkName); eTo.subnetId(subnetId); - eTo.blob(blob); eTo.availabilitySet(availabilitySet); eTo.availabilitySet(availabilitySetName); eTo.dataDisks(dataDisks); + eTo.resourceGroup(resourceGroup); } } @@ -129,28 +127,19 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { if (!super.equals(o)) return false; AzureTemplateOptions that = (AzureTemplateOptions) o; - - if (virtualNetworkName != null ? !virtualNetworkName.equals(that.virtualNetworkName) : that.virtualNetworkName != null) - return false; - if (subnetId != null ? !subnetId.equals(that.subnetId) : that.subnetId != null) return false; - if (blob != null ? !blob.equals(that.blob) : that.blob != null) return false; - if (availabilitySet != null ? !availabilitySet.equals(that.availabilitySet) : that.availabilitySet != null) - return false; - if (availabilitySetName != null ? !availabilitySetName.equals(that.availabilitySetName) : that.availabilitySetName != null) - return false; - return dataDisks != null ? dataDisks.equals(that.dataDisks) : that.dataDisks == null; + + return Objects.equal(virtualNetworkName, that.virtualNetworkName) && + Objects.equal(subnetId, that.subnetId) && + Objects.equal(availabilitySet, that.availabilitySet) && + Objects.equal(availabilitySetName, that.availabilitySetName) && + Objects.equal(dataDisks, that.dataDisks) && + Objects.equal(resourceGroup, that.resourceGroup); } @Override public int hashCode() { - int result = super.hashCode(); - result = 31 * result + (virtualNetworkName != null ? virtualNetworkName.hashCode() : 0); - result = 31 * result + (subnetId != null ? subnetId.hashCode() : 0); - result = 31 * result + (blob != null ? blob.hashCode() : 0); - result = 31 * result + (availabilitySet != null ? availabilitySet.hashCode() : 0); - result = 31 * result + (availabilitySetName != null ? availabilitySetName.hashCode() : 0); - result = 31 * result + (dataDisks != null ? dataDisks.hashCode() : 0); - return result; + return Objects.hashCode(virtualNetworkName, subnetId, availabilitySet, availabilitySetName, dataDisks, + resourceGroup); } @Override @@ -160,14 +149,14 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { toString.add("virtualNetworkName", virtualNetworkName); if (subnetId != null) toString.add("subnetId", subnetId); - if (blob != null) - toString.add("blob", blob); if (availabilitySet != null) toString.add("availabilitySet", availabilitySet); if (availabilitySetName != null) toString.add("availabilitySetName", availabilitySetName); if (!dataDisks.isEmpty()) toString.add("dataDisks", dataDisks); + if (resourceGroup != null) + toString.add("resourceGroup", resourceGroup); return toString; } @@ -188,14 +177,6 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { AzureTemplateOptions options = new AzureTemplateOptions(); return options.subnetId(subnetId); } - - /** - * @see AzureTemplateOptions#blob(String) - */ - public static AzureTemplateOptions blob(String blob) { - AzureTemplateOptions options = new AzureTemplateOptions(); - return options.blob(blob); - } /** * @see AzureTemplateOptions#availabilitySet(AvailabilitySet) @@ -214,16 +195,27 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { } /** - * @see AzureTemplateOptions#dataDisks + * @see AzureTemplateOptions#dataDisks(DataDisk...) */ public static AzureTemplateOptions dataDisks(DataDisk... dataDisks) { AzureTemplateOptions options = new AzureTemplateOptions(); return options.dataDisks(dataDisks); } + /** + * @see AzureTemplateOptions#dataDisks(Iterable) + */ public static AzureTemplateOptions dataDisks(Iterable dataDisks) { AzureTemplateOptions options = new AzureTemplateOptions(); return options.dataDisks(dataDisks); } + + /** + * @see AzureTemplateOptions#resourceGroup(String) + */ + public static AzureTemplateOptions resourceGroup(String resourceGroup) { + AzureTemplateOptions options = new AzureTemplateOptions(); + return options.resourceGroup(resourceGroup); + } } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java index fb635aa67d..79f2cd0bb0 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java @@ -30,13 +30,12 @@ import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName; import org.jclouds.azurecompute.arm.domain.AvailabilitySet; 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.RegionAndId; -import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi; import org.jclouds.compute.functions.GroupNamingConvention; @@ -45,10 +44,6 @@ import org.jclouds.logging.Logger; import com.google.common.base.Function; import com.google.common.base.Predicate; -import com.google.common.base.Splitter; -import com.google.common.cache.LoadingCache; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; @Singleton public class CleanupResources { @@ -59,52 +54,55 @@ public class CleanupResources { private final AzureComputeApi api; private final Predicate resourceDeleted; - private final LoadingCache resourceGroupMap; private final GroupNamingConvention.Factory namingConvention; @Inject CleanupResources(AzureComputeApi azureComputeApi, @Named(TIMEOUT_RESOURCE_DELETED) Predicate resourceDeleted, - LoadingCache resourceGroupMap, GroupNamingConvention.Factory namingConvention) { + GroupNamingConvention.Factory namingConvention) { this.api = azureComputeApi; this.resourceDeleted = resourceDeleted; - this.resourceGroupMap = resourceGroupMap; this.namingConvention = namingConvention; } public boolean cleanupNode(final String id) { - RegionAndId regionAndId = RegionAndId.fromSlashEncoded(id); - ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(regionAndId.region()); - String resourceGroupName = resourceGroup.name(); + ResourceGroupAndName resourceGroupAndName = ResourceGroupAndName.fromSlashEncoded(id); + String resourceGroupName = resourceGroupAndName.resourceGroup(); - VirtualMachine virtualMachine = api.getVirtualMachineApi(resourceGroupName).get(regionAndId.id()); + VirtualMachine virtualMachine = api.getVirtualMachineApi(resourceGroupName).get(resourceGroupAndName.name()); if (virtualMachine == null) { return true; } - logger.debug(">> destroying %s ...", regionAndId.slashEncode()); + logger.debug(">> destroying %s ...", id); boolean vmDeleted = deleteVirtualMachine(resourceGroupName, 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 - cleanupVirtualMachineNICs(resourceGroupName, virtualMachine); - cleanupAvailabilitySetIfOrphaned(resourceGroupName, virtualMachine); + cleanupVirtualMachineNICs(virtualMachine); + cleanupAvailabilitySetIfOrphaned(virtualMachine); return vmDeleted; } - public void cleanupVirtualMachineNICs(String group, VirtualMachine virtualMachine) { - for (String nicName : getNetworkCardInterfaceNames(virtualMachine)) { - NetworkInterfaceCard nic = api.getNetworkInterfaceCardApi(group).get(nicName); - Iterable publicIps = getPublicIps(group, nic); + public void cleanupVirtualMachineNICs(VirtualMachine virtualMachine) { + for (IdReference nicRef : virtualMachine.properties().networkProfile().networkInterfaces()) { + String nicResourceGroup = nicRef.resourceGroup(); + String nicName = nicRef.name(); + NetworkInterfaceCard nic = api.getNetworkInterfaceCardApi(nicRef.resourceGroup()).get(nicName); + + Iterable publicIps = getPublicIps(nic); logger.debug(">> destroying nic %s...", nicName); - URI nicDeletionURI = api.getNetworkInterfaceCardApi(group).delete(nicName); + URI nicDeletionURI = api.getNetworkInterfaceCardApi(nicResourceGroup).delete(nicName); resourceDeleted.apply(nicDeletionURI); - for (String publicIp : publicIps) { - logger.debug(">> deleting public ip nic %s...", publicIp); - api.getPublicIPAddressApi(group).delete(publicIp); + for (IdReference publicIp : publicIps) { + String publicIpResourceGroup = publicIp.resourceGroup(); + String publicIpName = publicIp.name(); + + logger.debug(">> deleting public ip nic %s...", publicIpName); + api.getPublicIPAddressApi(publicIpResourceGroup).delete(publicIpName); } } } @@ -135,12 +133,13 @@ public class CleanupResources { return deleted; } - public boolean cleanupAvailabilitySetIfOrphaned(String resourceGroup, VirtualMachine virtualMachine) { + public boolean cleanupAvailabilitySetIfOrphaned(VirtualMachine virtualMachine) { boolean deleted = false; IdReference availabilitySetRef = virtualMachine.properties().availabilitySet(); if (availabilitySetRef != null) { - String name = Iterables.getLast(Splitter.on("/").split(availabilitySetRef.id())); + String name = availabilitySetRef.name(); + String resourceGroup = availabilitySetRef.resourceGroup(); AvailabilitySet availabilitySet = api.getAvailabilitySetApi(resourceGroup).get(name); if (isOrphanedJcloudsAvailabilitySet(availabilitySet)) { @@ -162,19 +161,13 @@ public class CleanupResources { return deleted; } - 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 Iterable getPublicIps(NetworkInterfaceCard nic) { + return filter(transform(nic.properties().ipConfigurations(), new Function() { + @Override + public IdReference apply(IpConfiguration input) { + return input.properties().publicIPAddress(); + } + }), notNull()); } private static boolean isOrphanedJcloudsAvailabilitySet(AvailabilitySet availabilitySet) { @@ -187,14 +180,6 @@ public class CleanupResources { .virtualMachines().isEmpty()); } - 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())); } 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/CreateResourcesThenCreateNodes.java similarity index 77% rename from providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourceGroupThenCreateNodes.java rename to providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java index 5f6d88f86a..c3bdbdd07e 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/CreateResourcesThenCreateNodes.java @@ -16,6 +16,12 @@ */ package org.jclouds.azurecompute.arm.compute.strategy; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Iterables.getOnlyElement; +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 java.util.Arrays; import java.util.Map; import java.util.Set; @@ -27,12 +33,12 @@ import javax.inject.Singleton; import org.jclouds.Constants; import org.jclouds.azurecompute.arm.AzureComputeApi; -import org.jclouds.azurecompute.arm.compute.domain.RegionAndIdAndIngressRules; +import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName; +import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndNameAndIngressRules; import org.jclouds.azurecompute.arm.compute.functions.TemplateToAvailabilitySet; import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; import org.jclouds.azurecompute.arm.domain.AvailabilitySet; import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; -import org.jclouds.azurecompute.arm.domain.RegionAndId; import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.domain.Subnet; import org.jclouds.azurecompute.arm.domain.VirtualNetwork; @@ -42,7 +48,6 @@ 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.options.TemplateOptions; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.strategy.CreateNodeWithGroupEncodedIntoName; import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap; @@ -53,32 +58,26 @@ import org.jclouds.logging.Logger; import com.google.common.base.Optional; import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Multimap; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.collect.Iterables.getOnlyElement; -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; - @Singleton -public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEncodedIntoNameThenAddToSet { +public class CreateResourcesThenCreateNodes extends CreateNodesWithGroupEncodedIntoNameThenAddToSet { @Resource @Named(ComputeServiceConstants.COMPUTE_LOGGER) protected Logger logger = Logger.NULL; private final AzureComputeApi api; - private final LoadingCache securityGroupMap; - private final LoadingCache resourceGroupMap; + private final LoadingCache securityGroupMap; private final String defaultVnetAddressPrefix; private final String defaultSubnetAddressPrefix; private final TemplateToAvailabilitySet templateToAvailabilitySet; @Inject - protected CreateResourceGroupThenCreateNodes( + protected CreateResourcesThenCreateNodes( CreateNodeWithGroupEncodedIntoName addNodeWithGroupStrategy, ListNodesStrategy listNodesStrategy, GroupNamingConvention.Factory namingConvention, @@ -86,15 +85,13 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory, AzureComputeApi api, @Named(DEFAULT_VNET_ADDRESS_SPACE_PREFIX) String defaultVnetAddressPrefix, @Named(DEFAULT_SUBNET_ADDRESS_PREFIX) String defaultSubnetAddressPrefix, - LoadingCache securityGroupMap, - LoadingCache resourceGroupMap, + LoadingCache securityGroupMap, TemplateToAvailabilitySet templateToAvailabilitySet) { super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor, customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory); this.api = checkNotNull(api, "api cannot be null"); checkNotNull(userExecutor, "userExecutor cannot be null"); this.securityGroupMap = securityGroupMap; - this.resourceGroupMap = resourceGroupMap; this.defaultVnetAddressPrefix = defaultVnetAddressPrefix; this.defaultSubnetAddressPrefix = defaultSubnetAddressPrefix; this.templateToAvailabilitySet = templateToAvailabilitySet; @@ -117,24 +114,22 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco // This sill create the resource group if it does not exist String location = template.getLocation().getId(); - ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(location); - String azureGroupName = resourceGroup.name(); - getOrCreateVirtualNetworkWithSubnet(location, options, azureGroupName); - configureSecurityGroupForOptions(group, azureGroupName, template.getLocation(), options); + createResourceGroupIfNeeded(group, location, options); + getOrCreateVirtualNetworkWithSubnet(location, options); + configureSecurityGroupForOptions(group, template.getLocation(), options); configureAvailabilitySetForTemplate(template); return super.execute(group, count, template, goodNodes, badNodes, customizationResponses); } - protected synchronized void getOrCreateVirtualNetworkWithSubnet(final String location, AzureTemplateOptions options, - final String azureGroupName) { + protected synchronized void getOrCreateVirtualNetworkWithSubnet(final String location, AzureTemplateOptions options) { String virtualNetworkName = Optional.fromNullable(options.getVirtualNetworkName()).or( - azureGroupName + "virtualnetwork"); - String subnetName = azureGroupName + "subnet"; + options.getResourceGroup() + "virtualnetwork"); + String subnetName = options.getResourceGroup() + "subnet"; // Subnets belong to a virtual network so that needs to be created first - VirtualNetworkApi vnApi = api.getVirtualNetworkApi(azureGroupName); + VirtualNetworkApi vnApi = api.getVirtualNetworkApi(options.getResourceGroup()); VirtualNetwork vn = vnApi.get(virtualNetworkName); if (vn == null) { @@ -148,7 +143,7 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco vn = vnApi.createOrUpdate(virtualNetworkName, location, virtualNetworkProperties); } - SubnetApi subnetApi = api.getSubnetApi(azureGroupName, virtualNetworkName); + SubnetApi subnetApi = api.getSubnetApi(options.getResourceGroup(), virtualNetworkName); Subnet subnet = subnetApi.get(subnetName); options.virtualNetworkName(virtualNetworkName); @@ -160,23 +155,21 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco && !template.getOptions().hasLoginPrivateKeyOption(); } - private void configureSecurityGroupForOptions(String group, String resourceGroup, Location location, - TemplateOptions options) { + private void configureSecurityGroupForOptions(String group, Location location, AzureTemplateOptions options) { checkArgument(options.getGroups().size() <= 1, "Only one security group can be configured for each network interface"); if (!options.getGroups().isEmpty()) { - String groupName = getOnlyElement(options.getGroups()); - String groupNameWithourRegion = groupName.indexOf('/') == -1 ? groupName : RegionAndId.fromSlashEncoded( - groupName).id(); - NetworkSecurityGroup securityGroup = api.getNetworkSecurityGroupApi(resourceGroup).get(groupNameWithourRegion); - checkArgument(securityGroup != null, "Security group %s was not found", groupName); + ResourceGroupAndName securityGroupId = ResourceGroupAndName.fromSlashEncoded(getOnlyElement(options.getGroups())); + NetworkSecurityGroup securityGroup = api.getNetworkSecurityGroupApi(securityGroupId.resourceGroup()).get( + securityGroupId.name()); + checkArgument(securityGroup != null, "Security group %s was not found", securityGroupId.slashEncode()); options.securityGroups(securityGroup.id()); } else if (options.getInboundPorts().length > 0) { String name = namingConvention.create().sharedNameForGroup(group); - RegionAndIdAndIngressRules regionAndIdAndIngressRules = RegionAndIdAndIngressRules.create(location.getId(), - name, options.getInboundPorts()); + ResourceGroupAndNameAndIngressRules regionAndIdAndIngressRules = ResourceGroupAndNameAndIngressRules.create( + options.getResourceGroup(), location.getId(), name, options.getInboundPorts()); // this will create if not yet exists. String securityGroupId = securityGroupMap.getUnchecked(regionAndIdAndIngressRules); options.securityGroups(securityGroupId); @@ -190,4 +183,17 @@ public class CreateResourceGroupThenCreateNodes extends CreateNodesWithGroupEnco template.getOptions().as(AzureTemplateOptions.class).availabilitySet(availabilitySet); } } + + private void createResourceGroupIfNeeded(String group, String location, AzureTemplateOptions options) { + if (options.getResourceGroup() == null) { + options.resourceGroup(group); + } + logger.debug(">> using resource group [%s]", options.getResourceGroup()); + ResourceGroup rg = api.getResourceGroupApi().get(options.getResourceGroup()); + if (rg == null) { + logger.debug(">> resource group [%s] does not exist. Creating!", options.getResourceGroup()); + api.getResourceGroupApi().create(options.getResourceGroup(), location, + ImmutableMap.of("description", "jclouds default resource group")); + } + } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IdReference.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IdReference.java index 1854897e65..f73e3e4e55 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IdReference.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/IdReference.java @@ -16,19 +16,56 @@ */ package org.jclouds.azurecompute.arm.domain; -import com.google.auto.value.AutoValue; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; +import com.google.auto.value.AutoValue; + // Simple helper class to serialize / deserialize id reference. @AutoValue public abstract class IdReference { + + private static final Pattern RESOURCE_GROUP_PATTERN = Pattern.compile("^.*/resourceGroups/([^/]+)(/.*)?$"); + @Nullable public abstract String id(); + + @Nullable + public String resourceGroup() { + return extractResourceGroup(id()); + } + + @Nullable + public String name() { + return extractName(id()); + } @SerializedNames({"id"}) public static IdReference create(final String id) { return new AutoValue_IdReference(id); } + + /** + * Extracts the name from the given URI. + */ + public static String extractName(String uri) { + if (uri == null) + return null; + String noSlashAtEnd = uri.replaceAll("/+$", ""); + return noSlashAtEnd.substring(noSlashAtEnd.lastIndexOf('/') + 1); + } + + /** + * Extracts the resource group name from the given URI. + */ + public static String extractResourceGroup(String uri) { + if (uri == null) + return null; + Matcher m = RESOURCE_GROUP_PATTERN.matcher(uri); + return m.matches() ? m.group(1) : null; + } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMHardware.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMHardware.java index f0aa77e943..e7719038cd 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMHardware.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VMHardware.java @@ -62,14 +62,9 @@ public abstract class VMHardware { */ public abstract String location(); - /** - * Specifies if this HW is globally available - */ - public abstract boolean globallyAvailable(); + @SerializedNames({ "name", "numberOfCores", "osDiskSizeInMB", "resourceDiskSizeInMB", "memoryInMB", "maxDataDiskCount", "location"}) + public static VMHardware create(String name, Integer numberOfCores, Integer osDiskSizeInMB, Integer resourceDiskSizeInMB, Integer memoryInMB, Integer maxDataDiskCount, String location) { - @SerializedNames({ "name", "numberOfCores", "osDiskSizeInMB", "resourceDiskSizeInMB", "memoryInMB", "maxDataDiskCount", "location", "globallyAvailable"}) - public static VMHardware create(String name, Integer numberOfCores, Integer osDiskSizeInMB, Integer resourceDiskSizeInMB, Integer memoryInMB, Integer maxDataDiskCount, String location, boolean globallyAvailable) { - - return new AutoValue_VMHardware(name, numberOfCores, osDiskSizeInMB, resourceDiskSizeInMB, memoryInMB, maxDataDiskCount, location, globallyAvailable); + return new AutoValue_VMHardware(name, numberOfCores, osDiskSizeInMB, resourceDiskSizeInMB, memoryInMB, maxDataDiskCount, location); } } 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 a01ed23467..91ca8189b9 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 @@ -98,6 +98,13 @@ public abstract class VMImage { */ @Nullable public abstract String customImageId(); + + /** + * The resource group for the image in case of custom images. + * @return + */ + @Nullable + public abstract String resourceGroup(); /** * Extended version properties. @@ -127,6 +134,7 @@ public abstract class VMImage { public abstract static class Builder { public abstract Builder customImageId(String id); + public abstract Builder resourceGroup(String resourceGroup); public abstract Builder publisher(String published); public abstract Builder offer(String offer); public abstract Builder sku(String sku); 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 5a01e90f4d..a854fed657 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 @@ -15,6 +15,7 @@ * limitations under the License. */ package org.jclouds.azurecompute.arm.features; + import java.io.Closeable; import java.net.URI; import java.util.List; @@ -37,7 +38,6 @@ import org.jclouds.rest.annotations.SelectJson; /** * The Azure Resource Manager API checks for job status and progress. */ - @RequestFilters(OAuthFilter.class) @Consumes(MediaType.APPLICATION_JSON) public interface JobApi extends Closeable { diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/VMImages.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/VMImages.java index a5944ecd8e..238832e384 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/VMImages.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/VMImages.java @@ -21,7 +21,7 @@ import static com.google.common.base.Preconditions.checkNotNull; public class VMImages { public static boolean isCustom(String imageId) { - return checkNotNull(imageId, "id").split("/").length == 2; + return checkNotNull(imageId, "id").split("/").length == 3; } } 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 7c5c97fa63..46f4ed4bb9 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,8 +16,8 @@ */ package org.jclouds.azurecompute.arm.compute; +import static org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions.Builder.resourceGroup; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; -import static org.jclouds.compute.options.TemplateOptions.Builder.authorizePublicKey; import static org.testng.Assert.assertTrue; import java.net.URI; @@ -25,7 +25,6 @@ import java.util.Properties; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; -import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.TemplateBuilder; @@ -42,7 +41,6 @@ import org.testng.annotations.AfterClass; import org.testng.annotations.Test; import com.google.common.base.Predicate; -import com.google.common.cache.LoadingCache; import com.google.inject.Key; import com.google.inject.Module; import com.google.inject.TypeLiteral; @@ -54,19 +52,17 @@ import com.google.inject.name.Names; @Test(groups = "live", singleThreaded = true, testName = "AzureComputeServiceLiveTest") public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest { - private LoadingCache resourceGroupMap; private Predicate resourceDeleted; + private String resourceGroupName; public AzureComputeServiceLiveTest() { provider = "azurecompute-arm"; + resourceGroupName = getClass().getSimpleName().toLowerCase(); } @Override public void initializeContext() { super.initializeContext(); - resourceGroupMap = context.utils().injector() - .getInstance(Key.get(new TypeLiteral>() { - })); resourceDeleted = context.utils().injector().getInstance(Key.get(new TypeLiteral>() { }, Names.named(TIMEOUT_RESOURCE_DELETED))); } @@ -75,16 +71,10 @@ public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest { @AfterClass(groups = "live", alwaysRun = true) protected void tearDownContext() { try { - if (template != null) { - ResourceGroup rg = resourceGroupMap.getIfPresent(template.getLocation().getId()); - if (rg != null) { - AzureComputeApi api = view.unwrapApi(AzureComputeApi.class); - URI uri = api.getResourceGroupApi().delete(rg.name()); - if (uri != null) { - assertTrue(resourceDeleted.apply(uri), - String.format("Resource %s was not terminated in the configured timeout", uri)); - } - } + URI uri = view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().delete(resourceGroupName); + if (uri != null) { + assertTrue(resourceDeleted.apply(uri), + String.format("Resource %s was not terminated in the configured timeout", uri)); } } finally { super.tearDownContext(); @@ -109,7 +99,7 @@ public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest { @Override protected Properties setupProperties() { Properties properties = super.setupProperties(); - AzureLiveTestUtils.defaultProperties(properties, getClass().getSimpleName().toLowerCase()); + AzureLiveTestUtils.defaultProperties(properties); setIfTestSystemPropertyPresent(properties, "oauth.endpoint"); return properties; } @@ -117,7 +107,8 @@ public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest { @Override protected TemplateBuilder templateBuilder() { return super.templateBuilder().options( - authorizePublicKey(keyPair.get("public")).overrideLoginPrivateKey(keyPair.get("private"))); + resourceGroup(resourceGroupName).authorizePublicKey(keyPair.get("public")).overrideLoginPrivateKey( + keyPair.get("private"))); } @Override 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 d4cbdb07e7..b00aa0533c 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 @@ -56,7 +56,7 @@ public class AzureTemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest { @Override protected Properties setupProperties() { Properties properties = super.setupProperties(); - AzureLiveTestUtils.defaultProperties(properties, getClass().getSimpleName().toLowerCase()); + AzureLiveTestUtils.defaultProperties(properties); setIfTestSystemPropertyPresent(properties, "oauth.endpoint"); return properties; } 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 d708723afb..885269d33b 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,7 +16,7 @@ */ package org.jclouds.azurecompute.arm.compute.extensions; -import static org.jclouds.compute.options.TemplateOptions.Builder.authorizePublicKey; +import static org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions.Builder.resourceGroup; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; import static org.jclouds.compute.options.RunScriptOptions.Builder.wrapInInitScript; import static org.testng.Assert.assertEquals; @@ -28,7 +28,6 @@ import java.util.Properties; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; -import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; import org.jclouds.compute.ComputeTestUtils; import org.jclouds.compute.domain.ExecResponse; @@ -43,7 +42,6 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import com.google.common.base.Predicate; -import com.google.common.cache.LoadingCache; import com.google.inject.Key; import com.google.inject.Module; import com.google.inject.TypeLiteral; @@ -56,30 +54,27 @@ import com.google.inject.name.Names; @Test(groups = "live", singleThreaded = true, testName = "AzureComputeImageExtensionLiveTest") public class AzureComputeImageExtensionLiveTest extends BaseImageExtensionLiveTest { - private LoadingCache resourceGroupMap; private Predicate resourceDeleted; - private ResourceGroup testResourceGroup; + private String resourceGroupName; public AzureComputeImageExtensionLiveTest() { provider = "azurecompute-arm"; + resourceGroupName = getClass().getSimpleName().toLowerCase(); } @BeforeClass(groups = { "integration", "live" }) public void setupContext() { super.setupContext(); - resourceGroupMap = context.utils().injector() - .getInstance(Key.get(new TypeLiteral>() { - })); resourceDeleted = context.utils().injector().getInstance(Key.get(new TypeLiteral>() { }, Names.named(TIMEOUT_RESOURCE_DELETED))); - createResourceGroup(); + createResourceGroup(resourceGroupName); } @AfterClass(groups = { "integration", "live" }) @Override protected void tearDownContext() { try { - URI uri = view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().delete(testResourceGroup.name()); + URI uri = view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().delete(resourceGroupName); if (uri != null) { assertTrue(resourceDeleted.apply(uri), String.format("Resource %s was not terminated in the configured timeout", uri)); @@ -108,7 +103,7 @@ public class AzureComputeImageExtensionLiveTest extends BaseImageExtensionLiveTe @Override protected Properties setupProperties() { Properties properties = super.setupProperties(); - AzureLiveTestUtils.defaultProperties(properties, getClass().getSimpleName().toLowerCase()); + AzureLiveTestUtils.defaultProperties(properties); setIfTestSystemPropertyPresent(properties, "oauth.endpoint"); return properties; } @@ -122,11 +117,12 @@ public class AzureComputeImageExtensionLiveTest extends BaseImageExtensionLiveTe public TemplateBuilder getNodeTemplate() { Map keyPair = ComputeTestUtils.setupKeyPair(); return super.getNodeTemplate().options( - authorizePublicKey(keyPair.get("public")).overrideLoginPrivateKey(keyPair.get("private"))); + resourceGroup(resourceGroupName).authorizePublicKey(keyPair.get("public")).overrideLoginPrivateKey( + keyPair.get("private"))); } - private void createResourceGroup() { + private void createResourceGroup(String name) { Location location = getNodeTemplate().build().getLocation(); - testResourceGroup = resourceGroupMap.getUnchecked(location.getId()); + view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().create(name, location.getId(), null); } } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java index e00880be90..153df2964a 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtensionLiveTest.java @@ -18,9 +18,8 @@ package org.jclouds.azurecompute.arm.compute.extensions; import static com.google.common.collect.Iterables.get; import static com.google.common.collect.Iterables.getOnlyElement; +import static org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions.Builder.resourceGroup; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; -import static org.jclouds.compute.options.TemplateOptions.Builder.inboundPorts; -import static org.jclouds.compute.options.TemplateOptions.Builder.securityGroups; import static org.jclouds.compute.predicates.NodePredicates.inGroup; import static org.jclouds.net.domain.IpProtocol.TCP; import static org.testng.Assert.assertEquals; @@ -34,12 +33,13 @@ import java.util.concurrent.ExecutionException; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; -import org.jclouds.azurecompute.arm.domain.ResourceGroup; +import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; import org.jclouds.compute.ComputeService; import org.jclouds.compute.RunNodesException; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.SecurityGroup; +import org.jclouds.compute.domain.Template; import org.jclouds.compute.extensions.SecurityGroupExtension; import org.jclouds.compute.extensions.internal.BaseSecurityGroupExtensionLiveTest; import org.jclouds.domain.Location; @@ -52,7 +52,6 @@ import org.testng.annotations.Test; import com.google.common.base.Optional; import com.google.common.base.Predicate; -import com.google.common.cache.LoadingCache; import com.google.inject.Key; import com.google.inject.TypeLiteral; import com.google.inject.name.Names; @@ -64,23 +63,20 @@ import com.google.inject.name.Names; @Test(groups = "live", singleThreaded = true, testName = "AzureComputeSecurityGroupExtensionLiveTest") public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGroupExtensionLiveTest { - private LoadingCache resourceGroupMap; private Predicate resourceDeleted; - private ResourceGroup testResourceGroup; + private String resourceGroupName; public AzureComputeSecurityGroupExtensionLiveTest() { provider = "azurecompute-arm"; + resourceGroupName = "sgelivetest"; } @BeforeClass(groups = { "integration", "live" }) public void setupContext() { super.setupContext(); - resourceGroupMap = context.utils().injector() - .getInstance(Key.get(new TypeLiteral>() { - })); resourceDeleted = context.utils().injector().getInstance(Key.get(new TypeLiteral>() { }, Names.named(TIMEOUT_RESOURCE_DELETED))); - createResourceGroup(); + createResourceGroup(resourceGroupName); } @Test(groups = { "integration", "live" }, singleThreaded = true, dependsOnMethods = "testAddIpPermissionsFromSpec") @@ -104,7 +100,8 @@ public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGrou Optional securityGroupExtension = computeService.getSecurityGroupExtension(); assertTrue(securityGroupExtension.isPresent(), "security group extension was not present"); - NodeMetadata node = getOnlyElement(computeService.createNodesInGroup(nodeGroup, 1, securityGroups(groupId))); + NodeMetadata node = getOnlyElement(computeService.createNodesInGroup(nodeGroup, 1, + options().securityGroups(groupId))); try { Set groups = securityGroupExtension.get().listSecurityGroupsForNode(node.getId()); @@ -121,8 +118,8 @@ public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGrou Optional securityGroupExtension = computeService.getSecurityGroupExtension(); assertTrue(securityGroupExtension.isPresent(), "security group extension was not present"); - NodeMetadata node = getOnlyElement(computeService - .createNodesInGroup(nodeGroup, 1, inboundPorts(22, 23, 24, 8000))); + NodeMetadata node = getOnlyElement(computeService.createNodesInGroup(nodeGroup, 1, + options().inboundPorts(22, 23, 24, 8000))); try { Set groups = securityGroupExtension.get().listSecurityGroupsForNode(node.getId()); @@ -141,7 +138,7 @@ public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGrou @Override protected void tearDownContext() { try { - URI uri = view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().delete(testResourceGroup.name()); + URI uri = view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().delete(resourceGroupName); if (uri != null) { assertTrue(resourceDeleted.apply(uri), String.format("Resource %s was not terminated in the configured timeout", uri)); @@ -154,7 +151,7 @@ public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGrou @Override protected Properties setupProperties() { Properties properties = super.setupProperties(); - AzureLiveTestUtils.defaultProperties(properties, "sgelivetest"); + AzureLiveTestUtils.defaultProperties(properties); setIfTestSystemPropertyPresent(properties, "oauth.endpoint"); return properties; } @@ -163,9 +160,18 @@ public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGrou protected ProviderMetadata createProviderMetadata() { return AzureComputeProviderMetadata.builder().build(); } + + private AzureTemplateOptions options() { + return resourceGroup(resourceGroupName); + } + + @Override + public Template getNodeTemplate() { + return view.getComputeService().templateBuilder().options(options()).build(); + } - private void createResourceGroup() { + private void createResourceGroup(String name) { Location location = getNodeTemplate().getLocation(); - testResourceGroup = resourceGroupMap.getUnchecked(location.getId()); + view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().create(name, location.getId(), null); } } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/domain/IdReferenceTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/domain/IdReferenceTest.java new file mode 100644 index 0000000000..e5426d7aa0 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/domain/IdReferenceTest.java @@ -0,0 +1,62 @@ +/* + * 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 static org.jclouds.azurecompute.arm.domain.IdReference.extractName; +import static org.jclouds.azurecompute.arm.domain.IdReference.extractResourceGroup; +import static org.testng.Assert.assertEquals; + +import org.testng.annotations.Test; + +public class IdReferenceTest { + + @Test + public void testExtractResourceGroup() { + assertEquals(extractResourceGroup(null), null); + assertEquals(extractResourceGroup(""), null); + assertEquals( + extractResourceGroup("/subscriptions/subscription/resourceGroups/jclouds-northeurope/providers/Microsoft.Compute/virtualMachines/resources-8c5"), + "jclouds-northeurope"); + assertEquals(extractResourceGroup("/subscriptions/subscription/resourceGroups/jclouds-west"), "jclouds-west"); + assertEquals(extractResourceGroup("/resourceGroups/jclouds-west2"), "jclouds-west2"); + assertEquals( + extractResourceGroup("/resourceGroups/jclouds-northeurope2/providers/Microsoft.Compute/virtualMachines/resources-8c5"), + "jclouds-northeurope2"); + assertEquals(extractResourceGroup("resourceGroups/jclouds-west2"), null); + assertEquals( + extractResourceGroup("resourceGroups/jclouds-northeurope2/providers/Microsoft.Compute/virtualMachines/resources-8c5"), + null); + assertEquals( + extractResourceGroup("/subscriptions/subscription/providers/Microsoft.Compute/virtualMachines/resources-8c5"), + null); + assertEquals( + extractResourceGroup("/subscriptions/subscription/resourceGroups//jclouds-northeurope/providers/Microsoft.Compute/virtualMachines/resources-8c5"), + null); + } + + @Test + public void testExtractName() { + assertEquals(extractName(null), null); + assertEquals(extractName(""), ""); + assertEquals(extractName("foo"), "foo"); + assertEquals(extractName("/foo/bar"), "bar"); + assertEquals(extractName("/foo/bar/"), "bar"); + assertEquals(extractName("/foo/bar////"), "bar"); + assertEquals(extractName("/foo///bar////"), "bar"); + assertEquals(extractName("////bar"), "bar"); + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ImageApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ImageApiLiveTest.java index d976258c4a..15231fd871 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ImageApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/ImageApiLiveTest.java @@ -24,7 +24,7 @@ import static org.jclouds.compute.predicates.NodePredicates.inGroup; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; - +import static org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions.Builder.resourceGroup; import java.net.URI; import java.util.Properties; @@ -32,18 +32,15 @@ import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.domain.IdReference; import org.jclouds.azurecompute.arm.domain.Image; import org.jclouds.azurecompute.arm.domain.ImageProperties; -import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; import org.jclouds.compute.RunNodesException; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest; -import org.jclouds.domain.Location; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import com.google.common.base.Predicate; -import com.google.common.cache.LoadingCache; import com.google.inject.Key; import com.google.inject.TypeLiteral; import com.google.inject.name.Names; @@ -54,11 +51,9 @@ public class ImageApiLiveTest extends BaseComputeServiceContextLiveTest { private static final String imageName = "imageFromRest"; - private LoadingCache resourceGroupMap; private Predicate resourceDeleted; private AzureComputeApi api; - private String resourceGroupName; private String location; private ImageApi imageApi; private Image image; @@ -73,7 +68,7 @@ public class ImageApiLiveTest extends BaseComputeServiceContextLiveTest { @Override protected Properties setupProperties() { Properties properties = super.setupProperties(); - AzureLiveTestUtils.defaultProperties(properties, getClass().getSimpleName().toLowerCase()); + AzureLiveTestUtils.defaultProperties(properties); checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); return properties; } @@ -83,9 +78,6 @@ public class ImageApiLiveTest extends BaseComputeServiceContextLiveTest { super.initializeContext(); resourceDeleted = context.utils().injector().getInstance(Key.get(new TypeLiteral>() { }, Names.named(TIMEOUT_RESOURCE_DELETED))); - resourceGroupMap = context.utils().injector() - .getInstance(Key.get(new TypeLiteral>() { - })); api = view.unwrapApi(AzureComputeApi.class); } @@ -94,10 +86,9 @@ public class ImageApiLiveTest extends BaseComputeServiceContextLiveTest { public void setupContext() { super.setupContext(); // Use the resource name conventions used in the abstraction - ResourceGroup resourceGroup = createResourceGroup(); - resourceGroupName = resourceGroup.name(); - location = resourceGroup.location(); - imageApi = api.getVirtualMachineImageApi(resourceGroupName); + location = view.getComputeService().templateBuilder().build().getLocation().getId(); + view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().create(group, location, null); + imageApi = api.getVirtualMachineImageApi(group); } @Override @@ -107,7 +98,7 @@ public class ImageApiLiveTest extends BaseComputeServiceContextLiveTest { view.getComputeService().destroyNodesMatching(inGroup(group)); } finally { try { - URI uri = api.getResourceGroupApi().delete(resourceGroupName); + URI uri = api.getResourceGroupApi().delete(group); assertResourceDeleted(uri); } finally { super.tearDownContext(); @@ -122,11 +113,11 @@ public class ImageApiLiveTest extends BaseComputeServiceContextLiveTest { @Test public void testCreateImage() throws RunNodesException { - NodeMetadata node = getOnlyElement(view.getComputeService().createNodesInGroup(group, 1)); + NodeMetadata node = getOnlyElement(view.getComputeService().createNodesInGroup(group, 1, resourceGroup(group))); IdReference vmIdRef = IdReference.create(node.getProviderId()); view.getComputeService().suspendNode(node.getId()); - api.getVirtualMachineApi(resourceGroupName).generalize(node.getName()); + api.getVirtualMachineApi(group).generalize(node.getName()); image = imageApi.createOrUpdate(imageName, location, ImageProperties.builder() .sourceVirtualMachine(vmIdRef).build()); @@ -161,9 +152,4 @@ public class ImageApiLiveTest extends BaseComputeServiceContextLiveTest { } } - private ResourceGroup createResourceGroup() { - Location location = view.getComputeService().templateBuilder().build().getLocation(); - return resourceGroupMap.getUnchecked(location.getId()); - } - } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java index 5799093089..d267912a54 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java @@ -16,13 +16,12 @@ */ package org.jclouds.azurecompute.arm.features; -import static org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions.Builder.availabilitySet; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.Iterables.any; -import static com.google.common.collect.Iterables.getLast; import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Lists.newArrayList; +import static org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions.Builder.availabilitySet; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; import static org.jclouds.azurecompute.arm.domain.InboundNatRuleProperties.Protocol.Tcp; import static org.jclouds.compute.predicates.NodePredicates.inGroup; @@ -40,7 +39,9 @@ import java.util.Set; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.PublicIpAvailablePredicateFactory; +import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName; import org.jclouds.azurecompute.arm.domain.AvailabilitySet; +import org.jclouds.azurecompute.arm.domain.AvailabilitySet.AvailabilitySetProperties; import org.jclouds.azurecompute.arm.domain.BackendAddressPool; import org.jclouds.azurecompute.arm.domain.BackendAddressPoolProperties; import org.jclouds.azurecompute.arm.domain.FrontendIPConfigurations; @@ -62,24 +63,18 @@ import org.jclouds.azurecompute.arm.domain.ProbeProperties; import org.jclouds.azurecompute.arm.domain.Provisionable; import org.jclouds.azurecompute.arm.domain.PublicIPAddress; import org.jclouds.azurecompute.arm.domain.PublicIPAddressProperties; -import org.jclouds.azurecompute.arm.domain.RegionAndId; -import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.domain.VirtualMachine; -import org.jclouds.azurecompute.arm.domain.AvailabilitySet.AvailabilitySetProperties; import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; import org.jclouds.compute.RunNodesException; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest; -import org.jclouds.domain.Location; 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.base.Splitter; import com.google.common.base.Supplier; -import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.inject.Key; @@ -93,13 +88,11 @@ public class LoadBalancerApiLiveTest extends BaseComputeServiceContextLiveTest { private static final String lbName = String.format("lb-%s-%s", LoadBalancerApiLiveTest.class.getSimpleName() .toLowerCase(), System.getProperty("user.name")); - private LoadingCache resourceGroupMap; private Predicate resourceDeleted; private PublicIpAvailablePredicateFactory publicIpAvailable; private Predicate> resourceAvailable; private AzureComputeApi api; - private String resourceGroupName; private String location; private LoadBalancerApi lbApi; private NetworkInterfaceCardApi nicApi; @@ -116,7 +109,7 @@ public class LoadBalancerApiLiveTest extends BaseComputeServiceContextLiveTest { @Override protected Properties setupProperties() { Properties properties = super.setupProperties(); - AzureLiveTestUtils.defaultProperties(properties, getClass().getSimpleName().toLowerCase()); + AzureLiveTestUtils.defaultProperties(properties); checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); return properties; } @@ -126,9 +119,6 @@ public class LoadBalancerApiLiveTest extends BaseComputeServiceContextLiveTest { super.initializeContext(); resourceDeleted = context.utils().injector().getInstance(Key.get(new TypeLiteral>() { }, Names.named(TIMEOUT_RESOURCE_DELETED))); - resourceGroupMap = context.utils().injector() - .getInstance(Key.get(new TypeLiteral>() { - })); publicIpAvailable = context.utils().injector().getInstance(PublicIpAvailablePredicateFactory.class); resourceAvailable = context.utils().injector() .getInstance(Key.get(new TypeLiteral>>() { @@ -142,11 +132,10 @@ public class LoadBalancerApiLiveTest extends BaseComputeServiceContextLiveTest { super.setupContext(); // Use the resource name conventions used in the abstraction so the nodes // can see the load balancer - ResourceGroup resourceGroup = createResourceGroup(); - resourceGroupName = resourceGroup.name(); - location = resourceGroup.location(); - lbApi = api.getLoadBalancerApi(resourceGroupName); - nicApi = api.getNetworkInterfaceCardApi(resourceGroupName); + location = view.getComputeService().templateBuilder().build().getLocation().getId(); + view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().create(group, location, null); + lbApi = api.getLoadBalancerApi(group); + nicApi = api.getNetworkInterfaceCardApi(group); } @Override @@ -156,7 +145,7 @@ public class LoadBalancerApiLiveTest extends BaseComputeServiceContextLiveTest { view.getComputeService().destroyNodesMatching(inGroup(group)); } finally { try { - URI uri = api.getResourceGroupApi().delete(resourceGroupName); + URI uri = api.getResourceGroupApi().delete(group); assertResourceDeleted(uri); } finally { super.tearDownContext(); @@ -316,7 +305,7 @@ public class LoadBalancerApiLiveTest extends BaseComputeServiceContextLiveTest { } private PublicIPAddress createPublicIPAddress(final String publicIpAddressName) { - final PublicIPAddressApi ipApi = view.unwrapApi(AzureComputeApi.class).getPublicIPAddressApi(resourceGroupName); + final PublicIPAddressApi ipApi = view.unwrapApi(AzureComputeApi.class).getPublicIPAddressApi(group); PublicIPAddress publicIPAddress = ipApi.get(publicIpAddressName); if (publicIPAddress == null) { @@ -325,7 +314,7 @@ public class LoadBalancerApiLiveTest extends BaseComputeServiceContextLiveTest { .idleTimeoutInMinutes(4).build(); publicIPAddress = ipApi.createOrUpdate(publicIpAddressName, location, tags, properties); - checkState(publicIpAvailable.create(resourceGroupName).apply(publicIpAddressName), + checkState(publicIpAvailable.create(group).apply(publicIpAddressName), "Public IP was not provisioned in the configured timeout"); } @@ -358,16 +347,16 @@ public class LoadBalancerApiLiveTest extends BaseComputeServiceContextLiveTest { .platformFaultDomainCount(count).build(); AvailabilitySet as = AvailabilitySet.managed().name(group).properties(props).build(); - Set nodes = view.getComputeService() - .createNodesInGroup(group, count, availabilitySet(as)); + Set nodes = view.getComputeService().createNodesInGroup(group, count, + availabilitySet(as).resourceGroup(this.group)); List nicNames = new ArrayList(); for (NodeMetadata node : nodes) { - RegionAndId regionAndId = RegionAndId.fromSlashEncoded(node.getId()); - VirtualMachine vm = api.getVirtualMachineApi(resourceGroupName).get(regionAndId.id()); + ResourceGroupAndName resourceGroupAndName = ResourceGroupAndName.fromSlashEncoded(node.getId()); + VirtualMachine vm = api.getVirtualMachineApi(resourceGroupAndName.resourceGroup()).get( + resourceGroupAndName.name()); - String nicName = getLast(Splitter.on("/").split( - vm.properties().networkProfile().networkInterfaces().get(0).id())); + String nicName = vm.properties().networkProfile().networkInterfaces().get(0).name(); nicNames.add(nicName); } @@ -426,11 +415,6 @@ public class LoadBalancerApiLiveTest extends BaseComputeServiceContextLiveTest { return nicApi.get(nicName); } - private ResourceGroup createResourceGroup() { - Location location = view.getComputeService().templateBuilder().build().getLocation(); - return resourceGroupMap.getUnchecked(location.getId()); - } - private LoadBalancer updateLoadBalancer(final String name, LoadBalancerProperties props) { lbApi.createOrUpdate(name, location, null, props); resourceAvailable.apply(new Supplier() { diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java index 754f5fe86a..4d101ca455 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/AzureLiveTestUtils.java @@ -16,11 +16,7 @@ */ package org.jclouds.azurecompute.arm.internal; -import java.util.Properties; -import java.util.concurrent.TimeUnit; - import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; -import static org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_PREFIX; 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; @@ -30,14 +26,16 @@ import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGIONS; import static org.jclouds.oauth.v2.config.CredentialType.CLIENT_CREDENTIALS_SECRET; import static org.jclouds.oauth.v2.config.OAuthProperties.CREDENTIAL_TYPE; +import java.util.Properties; +import java.util.concurrent.TimeUnit; + public class AzureLiveTestUtils { - public static Properties defaultProperties(Properties properties, String resourceNamePrefix) { + public static Properties defaultProperties(Properties properties) { properties = properties == null ? new Properties() : properties; properties.put(CREDENTIAL_TYPE, CLIENT_CREDENTIALS_SECRET.toString()); properties.put(PROPERTY_REGIONS, "westeurope"); properties.put(IMAGE_PUBLISHERS, "Canonical"); - properties.put(RESOURCENAME_PREFIX, resourceNamePrefix); String defaultTimeout = String.valueOf(TimeUnit.MILLISECONDS.convert(60, TimeUnit.MINUTES)); properties.setProperty(TIMEOUT_SCRIPT_COMPLETE, defaultTimeout); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java index cf6546227d..10406b8679 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java @@ -97,7 +97,7 @@ public class BaseAzureComputeApiLiveTest extends BaseApiLiveTest Date: Tue, 25 Apr 2017 10:05:46 +0200 Subject: [PATCH 58/87] Properly honor the configured regions in all list methods (list nodes, images and security groups) --- .../compute/AzureComputeServiceAdapter.java | 28 +++++----- .../AzureComputeSecurityGroupExtension.java | 51 +++++++++++-------- 2 files changed, 47 insertions(+), 32 deletions(-) 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 2e9e0f6ba4..73ecda925f 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 @@ -220,8 +220,14 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listCustomImagesByResourceGroup(String resourceGroup) { - List customImages = api.getVirtualMachineImageApi(resourceGroup).list(); - return Lists.transform(customImages, customImagetoVmImage); + List customImgs = api.getVirtualMachineImageApi(resourceGroup).list(); + return ImmutableList.copyOf(transform( + filter(customImgs, new Predicate() { + @Override + public boolean apply(org.jclouds.azurecompute.arm.domain.Image input) { + return regionIds.get().contains(input.location()); + } + }), customImagetoVmImage)); } @Override @@ -241,15 +247,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter resourceGroupsInLocation = filter(api.getResourceGroupApi().list(), - new Predicate() { - @Override - public boolean apply(ResourceGroup input) { - return availableLocationNames.contains(input.location()); - } - }); - - for (ResourceGroup resourceGroup : resourceGroupsInLocation) { + for (ResourceGroup resourceGroup : api.getResourceGroupApi().list()) { osImages.addAll(listCustomImagesByResourceGroup(resourceGroup.name())); } @@ -345,7 +343,13 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter listNodes() { ImmutableList.Builder nodes = builder(); for (ResourceGroup resourceGroup : api.getResourceGroupApi().list()) { - nodes.addAll(api.getVirtualMachineApi(resourceGroup.name()).list()); + List vms = api.getVirtualMachineApi(resourceGroup.name()).list(); + nodes.addAll(filter(vms, new Predicate() { + @Override + public boolean apply(VirtualMachine input) { + return regionIds.get().contains(input.location()); + } + })); } return nodes.build(); } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java index eafb4f1409..59608a498f 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java @@ -23,7 +23,6 @@ import static com.google.common.collect.Iterables.any; 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.predicates.NodePredicates.locationId; import java.net.URI; import java.util.ArrayList; @@ -55,6 +54,7 @@ import org.jclouds.compute.domain.SecurityGroupBuilder; import org.jclouds.compute.extensions.SecurityGroupExtension; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.domain.Location; +import org.jclouds.location.Region; import org.jclouds.logging.Logger; import org.jclouds.net.domain.IpPermission; import org.jclouds.net.domain.IpProtocol; @@ -62,6 +62,7 @@ import org.jclouds.net.domain.IpProtocol; import com.google.common.base.Function; import com.google.common.base.Objects; import com.google.common.base.Predicate; +import com.google.common.base.Supplier; import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Multimap; @@ -77,40 +78,50 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio private final SecurityGroupAvailablePredicateFactory securityGroupAvailable; private final Predicate resourceDeleted; private final LoadingCache defaultResourceGroup; + private final Supplier> regionIds; @Inject AzureComputeSecurityGroupExtension(AzureComputeApi api, Function groupConverter, SecurityGroupAvailablePredicateFactory securityRuleAvailable, @Named(TIMEOUT_RESOURCE_DELETED) Predicate resourceDeleted, - LoadingCache defaultResourceGroup) { + LoadingCache defaultResourceGroup, + @Region Supplier> regionIds) { this.api = api; this.securityGroupConverter = groupConverter; this.securityGroupAvailable = securityRuleAvailable; this.resourceDeleted = resourceDeleted; this.defaultResourceGroup = defaultResourceGroup; - } - - @Override - public Set listSecurityGroups() { - ImmutableSet.Builder securityGroups = ImmutableSet.builder(); - for (ResourceGroup rg : api.getResourceGroupApi().list()) { - securityGroups.addAll(securityGroupsInResourceGroup(rg.name())); - } - return securityGroups.build(); - } - - private Set securityGroupsInResourceGroup(String resourceGroup) { - List networkGroups = api.getNetworkSecurityGroupApi(resourceGroup).list(); - return ImmutableSet.copyOf(transform(filter(networkGroups, notNull()), securityGroupConverter)); + this.regionIds = regionIds; } @Override public Set listSecurityGroupsInLocation(Location location) { - // Even though the resource groups are in a location, each security group - // can be in a different resource group, so we need to inspect all teh - // existing resource groups, and filter afterwards - return ImmutableSet.copyOf(filter(listSecurityGroups(), locationId(location.getId()))); + return securityGroupsInLocations(ImmutableSet.of(location.getId())); + } + + @Override + public Set listSecurityGroups() { + return securityGroupsInLocations(regionIds.get()); + } + + private Set securityGroupsInLocations(final Set locations) { + List securityGroups = new ArrayList(); + for (ResourceGroup rg : api.getResourceGroupApi().list()) { + securityGroups.addAll(securityGroupsInResourceGroup(rg.name())); + } + + return ImmutableSet.copyOf(filter(securityGroups, new Predicate() { + @Override + public boolean apply(SecurityGroup input) { + return locations.contains(input.getLocation().getId()); + } + })); + } + + private Set securityGroupsInResourceGroup(String resourceGroup) { + List networkGroups = api.getNetworkSecurityGroupApi(resourceGroup).list(); + return ImmutableSet.copyOf(transform(filter(networkGroups, notNull()), securityGroupConverter)); } @Override From 3b9609f2d546b43a305d01c9517f69a5e50588ac Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Tue, 25 Apr 2017 12:44:13 +0200 Subject: [PATCH 59/87] Added ID to the LoadBalancer entity --- .../azurecompute/arm/domain/LoadBalancer.java | 51 ++++++++++++------- .../arm/features/LoadBalancerApiLiveTest.java | 10 ++-- .../arm/features/LoadBalancerApiMockTest.java | 9 +++- 3 files changed, 48 insertions(+), 22 deletions(-) diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/LoadBalancer.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/LoadBalancer.java index d313e36a82..6e3e7482bc 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/LoadBalancer.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/LoadBalancer.java @@ -26,25 +26,42 @@ import com.google.common.collect.ImmutableMap; @AutoValue public abstract class LoadBalancer { - @Nullable - public abstract String name(); + + @Nullable public abstract String id(); + @Nullable public abstract String name(); + @Nullable public abstract String location(); + @Nullable public abstract String etag(); + @Nullable public abstract Map tags(); + @Nullable public abstract LoadBalancerProperties properties(); - @Nullable - public abstract String location(); + @SerializedNames({ "id", "name", "location", "etag", "tags", "properties", }) + public static LoadBalancer create(String id, final String name, final String location, final String etag, + final Map tags, final LoadBalancerProperties properties) { + return builder().id(id).name(name).location(location).etag(etag).tags(tags).properties(properties).build(); + } + + public abstract Builder toBuilder(); - @Nullable - public abstract Map tags(); + public static Builder builder() { + return new AutoValue_LoadBalancer.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder id(String id); + public abstract Builder name(String name); + public abstract Builder location(String location); + public abstract Builder etag(String etag); + public abstract Builder tags(Map tags); + public abstract Builder properties(LoadBalancerProperties properties); + + abstract Map tags(); - @Nullable - public abstract LoadBalancerProperties properties(); - - @Nullable - public abstract String etag(); - - @SerializedNames({ "name", "location", "tags", "properties", "etag" }) - public static LoadBalancer create(final String name, final String location, final Map tags, - final LoadBalancerProperties properties, final String etag) { - return new AutoValue_LoadBalancer(name, location, tags == null ? null : ImmutableMap.copyOf(tags), properties, - etag); + abstract LoadBalancer autoBuild(); + + public LoadBalancer build() { + tags(tags() != null ? ImmutableMap.copyOf(tags()) : null); + return autoBuild(); + } } } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java index d267912a54..c5b836beb3 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java @@ -326,9 +326,13 @@ public class LoadBalancerApiLiveTest extends BaseComputeServiceContextLiveTest { .builder().build(); FrontendIPConfigurations frontendIPConfigurations = FrontendIPConfigurations.create("ipConfigs", null, frontendIPConfigurationsProperties, null); - return LoadBalancer.create(lbName, locationName, null, - LoadBalancerProperties.builder().frontendIPConfigurations(ImmutableList.of(frontendIPConfigurations)) - .build(), null); + return LoadBalancer + .builder() + .name(lbName) + .location(locationName) + .properties( + LoadBalancerProperties.builder().frontendIPConfigurations(ImmutableList.of(frontendIPConfigurations)) + .build()).build(); } private void assertResourceDeleted(final URI uri) { diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiMockTest.java index 49e88db33e..45663eafec 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiMockTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiMockTest.java @@ -149,7 +149,12 @@ public class LoadBalancerApiMockTest extends BaseAzureComputeApiMockTest { .builder().build(); FrontendIPConfigurations frontendIPConfigurations = FrontendIPConfigurations.create("ipConfigs", null, frontendIPConfigurationsProperties, null); - return LoadBalancer.create(lbName, "westus", null, LoadBalancerProperties.builder() - .frontendIPConfigurations(ImmutableList.of(frontendIPConfigurations)).build(), null); + return LoadBalancer + .builder() + .name(lbName) + .location("westus") + .properties( + LoadBalancerProperties.builder().frontendIPConfigurations(ImmutableList.of(frontendIPConfigurations)) + .build()).build(); } } From 3a9f5787bf64673a403a2fcbd6fb3237aee95cbd Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Tue, 25 Apr 2017 16:28:17 +0200 Subject: [PATCH 60/87] Better encapsulated the image id encoding logic --- .../compute/AzureComputeServiceAdapter.java | 3 +- .../AzureComputeImageExtension.java | 3 +- .../NetworkSecurityGroupToSecurityGroup.java | 2 +- .../arm/compute/functions/VMImageToImage.java | 91 +++++-------------- .../VirtualMachineToNodeMetadata.java | 7 +- .../arm/domain/ImageReference.java | 13 +++ .../azurecompute/arm/domain/VMImage.java | 46 ++++++++-- 7 files changed, 78 insertions(+), 87 deletions(-) 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 73ecda925f..d01d6eced0 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 @@ -25,7 +25,6 @@ import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Lists.newArrayList; import static org.jclouds.azurecompute.arm.compute.domain.LocationAndName.fromSlashEncoded; import static org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName.fromResourceGroupAndName; -import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.decodeFieldsFromUniqueId; import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.getMarketplacePlanFromImageMetadata; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; import static org.jclouds.azurecompute.arm.util.VMImages.isCustom; @@ -256,7 +255,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter> deleting image %s", id); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityGroupToSecurityGroup.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityGroupToSecurityGroup.java index 71d51aae70..d38f94cdf0 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityGroupToSecurityGroup.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/functions/NetworkSecurityGroupToSecurityGroup.java @@ -61,7 +61,7 @@ public class NetworkSecurityGroupToSecurityGroup implements Function { private final Supplier> locations; - public static String encodeFieldsToUniqueId(boolean globallyAvailable, String locationName, - ImageReference imageReference) { - return (globallyAvailable ? "global" : locationName) + "/" + imageReference.publisher() + "/" - + imageReference.offer() + "/" + imageReference.sku(); - } - - public static String encodeFieldsToUniqueIdCustom(boolean globallyAvailable, String locationName, - ImageReference imageReference) { - return extractResourceGroup(imageReference.customImageId()) + "/" + (globallyAvailable ? "global" : locationName) - + "/" + imageReference.customImageId().substring(imageReference.customImageId().lastIndexOf("/") + 1); - } - - 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.resourceGroup() + "/" - + (imageReference.globallyAvailable() ? "global" : imageReference.location()) + "/" + imageReference.name(); - } - - public static VMImage decodeFieldsFromUniqueId(final String id) { - VMImage vmImage; - String[] fields = checkNotNull(id, "id").split("/"); - if (isCustom(id)) { - /* id fields indexes - 0: imageReference.resourceGroup - 1: imageReference.location + "/" + - 2: imageReference.name - */ - vmImage = VMImage.customImage().resourceGroup(fields[0]).location(fields[1]).name(fields[2]).build(); - } else { - /* id fields indexes - 0: imageReference.location + "/" + - 1: imageReference.publisher + "/" + - 2: imageReference.offer + "/" + - 3: imageReference.sku + "/" + - */ - vmImage = VMImage.azureImage().location(fields[0]).publisher(fields[1]).offer(fields[2]).sku(fields[3]) - .build(); - } - return vmImage; - } - @Inject VMImageToImage(@Memoized Supplier> locations) { this.locations = locations; @@ -111,29 +63,32 @@ public class VMImageToImage implements Function { public Image apply(final VMImage image) { final ImageBuilder builder = new ImageBuilder(); addMarketplacePlanToMetadataIfPresent(builder, image); + + Location location = FluentIterable.from(locations.get()).firstMatch(idEquals(image.location())).get(); + if (image.custom()) { - builder.location( - FluentIterable.from(locations.get()).firstMatch(LocationPredicates.idEquals(image.location())) - .get()).name(image.name()).description(image.group()).status(Image.Status.AVAILABLE) - .version("latest").providerId(image.customImageId()).id(encodeFieldsToUniqueIdCustom(image)); - - final OperatingSystem.Builder osBuilder = osFamily().apply(image); - builder.operatingSystem(osBuilder.build()); + builder + .id(image.encodeFieldsToUniqueIdCustom()) + .providerId(image.customImageId()) + .name(image.name()) + .location(location) + .description(image.group()) + .status(Image.Status.AVAILABLE) + .version("latest"); } else { builder - .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); - builder.operatingSystem(osBuilder.build()); + .id(image.encodeFieldsToUniqueId()) + .providerId(image.publisher()) + .name(image.offer()) + .location(location) + .description(image.sku()) + .status(Image.Status.AVAILABLE) + .version(image.sku()); } + + final OperatingSystem.Builder osBuilder = osFamily().apply(image); + builder.operatingSystem(osBuilder.build()); + return builder.build(); } 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 index bcfd4fee03..e4b7da8976 100644 --- 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 @@ -22,8 +22,6 @@ import static com.google.common.collect.Iterables.find; import static org.jclouds.azurecompute.arm.compute.AzureComputeServiceAdapter.GROUP_KEY; import static org.jclouds.azurecompute.arm.compute.domain.LocationAndName.fromLocationAndName; import static org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName.fromResourceGroupAndName; -import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.encodeFieldsToUniqueId; -import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.encodeFieldsToUniqueIdCustom; import static org.jclouds.azurecompute.arm.domain.IdReference.extractResourceGroup; import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromCommaDelimitedValue; import static org.jclouds.location.predicates.LocationPredicates.idEquals; @@ -185,10 +183,9 @@ public class VirtualMachineToNodeMetadata implements Function findImage(final StorageProfile storageProfile, String locatioName) { if (storageProfile.imageReference() != null) { - // FIXME check this condition String imageId = storageProfile.imageReference().customImageId() != null ? - encodeFieldsToUniqueIdCustom(false, locatioName, storageProfile.imageReference()) : - encodeFieldsToUniqueId(false, locatioName, storageProfile.imageReference()); + storageProfile.imageReference().encodeFieldsToUniqueIdCustom(locatioName) : + storageProfile.imageReference().encodeFieldsToUniqueId(locatioName); return imageCache.get(imageId); } else { logger.warn("could not find image for storage profile %s", storageProfile); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java index d9b43cd5ee..d001949494 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ImageReference.java @@ -16,6 +16,9 @@ */ package org.jclouds.azurecompute.arm.domain; +import static org.jclouds.azurecompute.arm.domain.IdReference.extractName; +import static org.jclouds.azurecompute.arm.domain.IdReference.extractResourceGroup; + import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; @@ -90,4 +93,14 @@ public abstract class ImageReference { public abstract ImageReference build(); } + + public String encodeFieldsToUniqueId(String location) { + return VMImage.azureImage().location(location).publisher(publisher()).offer(offer()).sku(sku()).build() + .encodeFieldsToUniqueId(); + } + + public String encodeFieldsToUniqueIdCustom(String location) { + return VMImage.customImage().resourceGroup(extractResourceGroup(customImageId())).location(location) + .name(extractName(customImageId())).build().encodeFieldsToUniqueIdCustom(); + } } 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 91ca8189b9..202481d7ae 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,6 +16,9 @@ */ package org.jclouds.azurecompute.arm.domain; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.azurecompute.arm.util.VMImages.isCustom; + import org.jclouds.azurecompute.arm.domain.Version.VersionProperties; import org.jclouds.javax.annotation.Nullable; @@ -53,11 +56,6 @@ public abstract class VMImage { @Nullable public abstract String location(); - /** - * Specifies if this image is globally available - */ - public abstract boolean globallyAvailable(); - /** * The group of the custom image */ @@ -112,16 +110,16 @@ public abstract class VMImage { @Nullable public abstract VersionProperties versionProperties(); - public static Builder builder() { + private static Builder builder() { return new AutoValue_VMImage.Builder(); } public static Builder azureImage() { - return builder().globallyAvailable(false).custom(false); + return builder().custom(false); } public static Builder customImage() { - return builder().globallyAvailable(false).custom(true); + return builder().custom(true); } VMImage() { @@ -140,7 +138,6 @@ public abstract class VMImage { 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); @@ -151,4 +148,35 @@ public abstract class VMImage { public abstract VMImage build(); } + + public String encodeFieldsToUniqueId() { + return String.format("%s/%s/%s/%s", location(), publisher(), offer(), sku()); + } + + public String encodeFieldsToUniqueIdCustom() { + return String.format("%s/%s/%s", resourceGroup(), location(), name()); + } + + public static VMImage decodeFieldsFromUniqueId(final String id) { + VMImage vmImage; + String[] fields = checkNotNull(id, "id").split("/"); + if (isCustom(id)) { + /* id fields indexes + 0: imageReference.resourceGroup + 1: imageReference.location + "/" + + 2: imageReference.name + */ + vmImage = VMImage.customImage().resourceGroup(fields[0]).location(fields[1]).name(fields[2]).build(); + } else { + /* id fields indexes + 0: imageReference.location + "/" + + 1: imageReference.publisher + "/" + + 2: imageReference.offer + "/" + + 3: imageReference.sku + "/" + + */ + vmImage = VMImage.azureImage().location(fields[0]).publisher(fields[1]).offer(fields[2]).sku(fields[3]) + .build(); + } + return vmImage; + } } From ec67fdea32cf6ffe96939e8a722bd21cbc215852 Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Wed, 26 Apr 2017 17:54:23 +0200 Subject: [PATCH 61/87] JCLOUDS-1274: Delete managed disks when cleaning up VM resources --- .../compute/strategy/CleanupResources.java | 50 +++++++++++++++++-- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java index 79f2cd0bb0..1f1a37dc51 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java @@ -16,13 +16,18 @@ */ package org.jclouds.azurecompute.arm.compute.strategy; +import static com.google.common.base.Predicates.not; 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 com.google.common.collect.Maps.filterValues; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; import java.net.URI; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Set; import javax.annotation.Resource; import javax.inject.Inject; @@ -32,17 +37,22 @@ import javax.inject.Singleton; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName; import org.jclouds.azurecompute.arm.domain.AvailabilitySet; +import org.jclouds.azurecompute.arm.domain.DataDisk; import org.jclouds.azurecompute.arm.domain.IdReference; import org.jclouds.azurecompute.arm.domain.IpConfiguration; +import org.jclouds.azurecompute.arm.domain.ManagedDiskParameters; import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; +import org.jclouds.azurecompute.arm.domain.OSDisk; import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi; import org.jclouds.compute.functions.GroupNamingConvention; import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.javax.annotation.Nullable; import org.jclouds.logging.Logger; import com.google.common.base.Function; +import com.google.common.base.Joiner; import com.google.common.base.Predicate; @Singleton @@ -80,12 +90,14 @@ public class CleanupResources { // group. It will be deleted when the resource group is deleted cleanupVirtualMachineNICs(virtualMachine); + cleanupManagedDisks(virtualMachine); cleanupAvailabilitySetIfOrphaned(virtualMachine); return vmDeleted; } - public void cleanupVirtualMachineNICs(VirtualMachine virtualMachine) { + public boolean cleanupVirtualMachineNICs(VirtualMachine virtualMachine) { + boolean deleted = true; for (IdReference nicRef : virtualMachine.properties().networkProfile().networkInterfaces()) { String nicResourceGroup = nicRef.resourceGroup(); String nicName = nicRef.name(); @@ -95,14 +107,44 @@ public class CleanupResources { logger.debug(">> destroying nic %s...", nicName); URI nicDeletionURI = api.getNetworkInterfaceCardApi(nicResourceGroup).delete(nicName); - resourceDeleted.apply(nicDeletionURI); + deleted &= nicDeletionURI == null || resourceDeleted.apply(nicDeletionURI); for (IdReference publicIp : publicIps) { String publicIpResourceGroup = publicIp.resourceGroup(); String publicIpName = publicIp.name(); logger.debug(">> deleting public ip nic %s...", publicIpName); - api.getPublicIPAddressApi(publicIpResourceGroup).delete(publicIpName); + deleted &= api.getPublicIPAddressApi(publicIpResourceGroup).delete(publicIpName); + } + } + return deleted; + } + + public boolean cleanupManagedDisks(VirtualMachine virtualMachine) { + Map deleteJobs = new HashMap(); + + OSDisk osDisk = virtualMachine.properties().storageProfile().osDisk(); + deleteManagedDisk(osDisk.managedDiskParameters(), deleteJobs); + + for (DataDisk dataDisk : virtualMachine.properties().storageProfile().dataDisks()) { + deleteManagedDisk(dataDisk.managedDiskParameters(), deleteJobs); + } + + Set nonDeletedDisks = filterValues(deleteJobs, not(resourceDeleted)).keySet(); + if (!nonDeletedDisks.isEmpty()) { + logger.warn(">> could not delete disks: %s", Joiner.on(',').join(nonDeletedDisks)); + } + + return nonDeletedDisks.isEmpty(); + } + + private void deleteManagedDisk(@Nullable ManagedDiskParameters managedDisk, Map deleteJobs) { + if (managedDisk != null) { + IdReference diskRef = IdReference.create(managedDisk.id()); + logger.debug(">> deleting managed disk %s...", diskRef.name()); + URI uri = api.getDiskApi(diskRef.resourceGroup()).delete(diskRef.name()); + if (uri != null) { + deleteJobs.put(diskRef.name(), uri); } } } @@ -134,7 +176,7 @@ public class CleanupResources { } public boolean cleanupAvailabilitySetIfOrphaned(VirtualMachine virtualMachine) { - boolean deleted = false; + boolean deleted = true; IdReference availabilitySetRef = virtualMachine.properties().availabilitySet(); if (availabilitySetRef != null) { From df300573863c7716759c1bfef56fa382ba73d705 Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Wed, 26 Apr 2017 15:42:36 +0200 Subject: [PATCH 62/87] JCLOUDS-1278: Allow to configure virtual machine NICs --- .../arm/AzureComputeProviderMetadata.java | 4 +- .../compute/AzureComputeServiceAdapter.java | 164 +++++++++++++----- .../AzureComputeSecurityGroupExtension.java | 21 ++- .../VirtualMachineToNodeMetadata.java | 18 +- .../loaders/CreateSecurityGroupIfNeeded.java | 9 +- .../compute/options/AzureTemplateOptions.java | 98 ++++++----- .../arm/compute/options/IpOptions.java | 76 ++++++++ .../compute/strategy/CleanupResources.java | 30 ++-- .../CreateResourcesThenCreateNodes.java | 108 ++++++++---- .../NetworkInterfaceCardProperties.java | 37 ++-- .../arm/domain/NetworkProfile.java | 44 ++++- .../arm/domain/PublicIPAddress.java | 55 ++++-- .../azurecompute/arm/domain/Subnet.java | 74 +++++--- .../arm/features/PublicIPAddressApi.java | 3 +- .../CreateResourcesThenCreateNodesTest.java | 114 ++++++++++++ .../arm/domain/IdReferenceTest.java | 1 + .../azurecompute/arm/domain/SubnetTest.java | 47 +++++ .../arm/features/LoadBalancerApiLiveTest.java | 3 +- .../NetworkInterfaceCardApiMockTest.java | 5 +- .../arm/features/SubnetApiMockTest.java | 2 +- .../features/VirtualMachineApiLiveTest.java | 11 +- .../features/VirtualMachineApiMockTest.java | 20 +-- 22 files changed, 705 insertions(+), 239 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/IpOptions.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodesTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/domain/SubnetTest.java 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 9d3f05d850..c35455cd9e 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 @@ -99,7 +99,7 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { // 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 + NetworkInterfaceCardApi.class.getSimpleName(), "2017-03-01"); 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"); @@ -107,7 +107,7 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { 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(), "2015-06-15"); - properties.put(API_VERSION_PREFIX + SubnetApi.class.getSimpleName(), "2015-06-15"); + properties.put(API_VERSION_PREFIX + SubnetApi.class.getSimpleName(), "2017-03-01"); 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(), "2016-04-30-preview"); 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 d01d6eced0..02e69fa4ae 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 @@ -27,9 +27,14 @@ import static org.jclouds.azurecompute.arm.compute.domain.LocationAndName.fromSl import static org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName.fromResourceGroupAndName; import static org.jclouds.azurecompute.arm.compute.functions.VMImageToImage.getMarketplacePlanFromImageMetadata; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.IMAGE_PUBLISHERS; +import static org.jclouds.azurecompute.arm.domain.IdReference.extractName; +import static org.jclouds.azurecompute.arm.domain.IdReference.extractResourceGroup; import static org.jclouds.azurecompute.arm.util.VMImages.isCustom; import static org.jclouds.compute.util.ComputeServiceUtils.metadataAndTagsAsCommaDelimitedValue; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Set; @@ -44,6 +49,7 @@ import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextMod import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName; import org.jclouds.azurecompute.arm.compute.functions.CustomImageToVMImage; import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; +import org.jclouds.azurecompute.arm.compute.options.IpOptions; import org.jclouds.azurecompute.arm.compute.strategy.CleanupResources; import org.jclouds.azurecompute.arm.domain.AvailabilitySet; import org.jclouds.azurecompute.arm.domain.CreationData; @@ -62,6 +68,7 @@ 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.Plan; +import org.jclouds.azurecompute.arm.domain.Provisionable; import org.jclouds.azurecompute.arm.domain.PublicIPAddress; import org.jclouds.azurecompute.arm.domain.PublicIPAddressProperties; import org.jclouds.azurecompute.arm.domain.ResourceGroup; @@ -75,13 +82,15 @@ import org.jclouds.azurecompute.arm.domain.VMSize; import org.jclouds.azurecompute.arm.domain.Version; import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties; +import org.jclouds.azurecompute.arm.domain.NetworkProfile.NetworkInterface; +import org.jclouds.azurecompute.arm.domain.NetworkProfile.NetworkInterface.NetworkInterfaceProperties; +import org.jclouds.azurecompute.arm.features.NetworkInterfaceCardApi; import org.jclouds.azurecompute.arm.features.OSImageApi; -import org.jclouds.azurecompute.arm.features.PublicIPAddressApi; 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.options.TemplateOptions; +import org.jclouds.compute.functions.GroupNamingConvention; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.location.Region; import org.jclouds.logging.Logger; @@ -105,6 +114,7 @@ import com.google.common.collect.Lists; public class AzureComputeServiceAdapter implements ComputeServiceAdapter { public static final String GROUP_KEY = "jclouds_group"; + public static final String AUTOGENERATED_IP_KEY = "jclouds-autogenerated"; @Resource @Named(ComputeServiceConstants.COMPUTE_LOGGER) @@ -116,40 +126,40 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter> regionIds; private final PublicIpAvailablePredicateFactory publicIpAvailable; private final CustomImageToVMImage customImagetoVmImage; + private final GroupNamingConvention namingConvention; + private Predicate> resourceAvailable; @Inject AzureComputeServiceAdapter(final AzureComputeApi api, @Named(IMAGE_PUBLISHERS) String imagePublishers, CleanupResources cleanupResources, @Region Supplier> regionIds, - PublicIpAvailablePredicateFactory publicIpAvailable, - CustomImageToVMImage customImagetoVmImage) { + PublicIpAvailablePredicateFactory publicIpAvailable, CustomImageToVMImage customImagetoVmImage, + GroupNamingConvention.Factory namingConvention, Predicate> resourceAvailable) { this.api = api; this.imagePublishers = Splitter.on(',').trimResults().omitEmptyStrings().splitToList(imagePublishers); this.cleanupResources = cleanupResources; this.regionIds = regionIds; this.publicIpAvailable = publicIpAvailable; this.customImagetoVmImage = customImagetoVmImage; + this.namingConvention = namingConvention.create(); + this.resourceAvailable = resourceAvailable; } @Override public NodeAndInitialCredentials createNodeWithGroupEncodedIntoName(final String group, final String name, final Template template) { - // TODO network ids => create one nic in each network - String locationName = template.getLocation().getId(); Image image = template.getImage(); String hardwareId = fromSlashEncoded(template.getHardware().getId()).name(); - // TODO ARM specific options AzureTemplateOptions templateOptions = template.getOptions().as(AzureTemplateOptions.class); - String subnetId = templateOptions.getSubnetId(); String resourceGroupName = templateOptions.getResourceGroup(); IdReference availabilitySet = getAvailabilitySetIdReference(templateOptions.getAvailabilitySet()); + NetworkProfile networkProfile = createNetworkProfile(createNetworkInterfaceCards(name, locationName, + templateOptions)); StorageProfile storageProfile = createStorageProfile(image, templateOptions.getDataDisks()); - NetworkInterfaceCard nic = createNetworkInterfaceCard(subnetId, name, locationName, resourceGroupName, template.getOptions()); HardwareProfile hardwareProfile = HardwareProfile.builder().vmSize(hardwareId).build(); OSProfile osProfile = createOsProfile(name, template); - NetworkProfile networkProfile = NetworkProfile.builder().networkInterfaces(of(IdReference.create(nic.id()))).build(); + VirtualMachineProperties virtualMachineProperties = VirtualMachineProperties.builder() - .licenseType(null) // TODO .availabilitySet(availabilitySet) .hardwareProfile(hardwareProfile) .storageProfile(storageProfile) @@ -159,11 +169,11 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter metadataAndTags = metadataAndTagsAsCommaDelimitedValue(template.getOptions()); - Plan plan = getMarketplacePlanFromImageMetadata(template.getImage()); + templateOptions.getUserMetadata().put(GROUP_KEY, group); + Map metadataAndTags = metadataAndTagsAsCommaDelimitedValue(templateOptions); + Plan plan = getMarketplacePlanFromImageMetadata(image); - VirtualMachine virtualMachine = api.getVirtualMachineApi(resourceGroupName).createOrUpdate(name, template.getLocation().getId(), + VirtualMachine virtualMachine = api.getVirtualMachineApi(resourceGroupName).createOrUpdate(name, locationName, virtualMachineProperties, metadataAndTags, plan); // Safe to pass null credentials here, as jclouds will default populate @@ -383,39 +393,113 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter createNetworkInterfaceCards(final String nodeName, final String location, + AzureTemplateOptions options) { + // Prefer a sorted list of NICs with the ones with public IPs first, to + // make sure the primary NIC is the public one + final String securityGroup = getOnlyElement(options.getGroups(), null); + return Lists.transform(publicIpsFirst(options.getIpOptions()), new Function() { + @Override + public NetworkInterfaceCard apply(IpOptions input) { + return createNetworkInterfaceCard(input, nodeName, location, securityGroup); + } + }); + } + + private NetworkInterfaceCard createNetworkInterfaceCard(IpOptions ipConfig, String nodeName, String location, + String securityGroup) { + String resourceGroup = extractResourceGroup(ipConfig.subnet()); + String subnetName = extractName(ipConfig.subnet()); - PublicIPAddressProperties properties = PublicIPAddressProperties.builder().publicIPAllocationMethod("Static") - .idleTimeoutInMinutes(4).build(); + IpConfigurationProperties.Builder ipProperties = IpConfigurationProperties.builder() + .subnet(IdReference.create(ipConfig.subnet())) + .privateIPAllocationMethod(ipConfig.address().isPresent() ? "Static" : "Dynamic") + .privateIPAddress(ipConfig.address().orNull()); - String publicIpAddressName = "public-address-" + name; - PublicIPAddress ip = ipApi.createOrUpdate(publicIpAddressName, locationName, ImmutableMap.of("jclouds", name), - properties); + configurePublicIP(ipConfig, ipProperties, resourceGroup, location, nodeName); - checkState(publicIpAvailable.create(azureGroup).apply(publicIpAddressName), - "Public IP was not provisioned in the configured timeout"); + String ipName = namingConvention.uniqueNameForGroup(subnetName); + final String nicName = namingConvention.uniqueNameForGroup(subnetName); - final NetworkInterfaceCardProperties.Builder networkInterfaceCardProperties = NetworkInterfaceCardProperties - .builder() - .ipConfigurations( - of(IpConfiguration - .builder() - .name("ipConfig-" + name) - .properties( - IpConfigurationProperties.builder().privateIPAllocationMethod("Dynamic") - .publicIPAddress(IdReference.create(ip.id())).subnet(IdReference.create(subnetId)) - .build()).build())); + IpConfiguration config = IpConfiguration.builder().name(ipName).properties(ipProperties.build()).build(); + + NetworkInterfaceCardProperties.Builder nicProperties = NetworkInterfaceCardProperties.builder().ipConfigurations( + ImmutableList.of(config)); - String securityGroup = getOnlyElement(options.getGroups(), null); if (securityGroup != null) { - networkInterfaceCardProperties.networkSecurityGroup(IdReference.create(securityGroup)); + nicProperties.networkSecurityGroup(IdReference.create(securityGroup)); } - String networkInterfaceCardName = "jc-nic-" + name; - return api.getNetworkInterfaceCardApi(azureGroup).createOrUpdate(networkInterfaceCardName, locationName, - networkInterfaceCardProperties.build(), ImmutableMap.of("jclouds", name)); + logger.debug(">> creating nic %s(%s) with security groups (%s)", nicName, config, + securityGroup != null ? securityGroup : ""); + + final NetworkInterfaceCardApi nicApi = api.getNetworkInterfaceCardApi(resourceGroup); + NetworkInterfaceCard nic = nicApi.createOrUpdate(nicName, location, nicProperties.build(), + ImmutableMap.of("jclouds", nodeName)); + + resourceAvailable.apply(new Supplier() { + @Override + public Provisionable get() { + NetworkInterfaceCard updated = nicApi.get(nicName); + return updated == null ? null : updated.properties(); + } + }); + + return nic; + } + + private void configurePublicIP(IpOptions ipConfig, IpConfigurationProperties.Builder ipProperties, + String resourceGroup, String location, String nodeName) { + if (ipConfig.publicIpId() != null) { + logger.debug(">> configuring public ip: %s", extractName(ipConfig.publicIpId())); + PublicIPAddress publicIp = api.getPublicIPAddressApi(extractResourceGroup(ipConfig.publicIpId())).get( + extractName(ipConfig.publicIpId())); + ipProperties.publicIPAddress(IdReference.create(publicIp.id())); + } else if (ipConfig.allocateNewPublicIp()) { + PublicIPAddress publicIp = createPublicIp(resourceGroup, location, nodeName); + ipProperties.publicIPAddress(IdReference.create(publicIp.id())); + } + } + + /** + * Create the network profile and configure the first NIC as primary. + */ + private NetworkProfile createNetworkProfile(List nics) { + List nicAttachments = new ArrayList(nics.size()); + for (int i = 0; i < nics.size(); i++) { + nicAttachments.add(NetworkInterface.create(nics.get(i).id(), NetworkInterfaceProperties.create(i == 0))); + } + return NetworkProfile.create(nicAttachments); + } + + private static List publicIpsFirst(List ipOptions) { + List sorted = new ArrayList(ipOptions); + Collections.sort(sorted, new Comparator() { + @Override + public int compare(IpOptions o1, IpOptions o2) { + return o1.allocateNewPublicIp() == o2.allocateNewPublicIp() ? 0 : o1.allocateNewPublicIp() ? -1 : 1; + } + }); + return sorted; + } + + private PublicIPAddress createPublicIp(String resourceGroup, String location, String nodeName) { + String name = namingConvention.uniqueNameForGroup(nodeName); + + PublicIPAddressProperties properties = PublicIPAddressProperties.builder() + .publicIPAllocationMethod("Static") + .idleTimeoutInMinutes(4) + .build(); + + logger.debug(">> allocating new public ip address: %s", name); + + PublicIPAddress ip = api.getPublicIPAddressApi(resourceGroup).createOrUpdate(name, location, + ImmutableMap.of("jclouds", nodeName, AUTOGENERATED_IP_KEY, "true"), properties); + + checkState(publicIpAvailable.create(resourceGroup).apply(name), + "Public IP was not provisioned in the configured timeout"); + + return ip; } private StorageProfile createStorageProfile(Image image, List dataDisks) { diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java index 59608a498f..50cb75a246 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java @@ -23,6 +23,8 @@ import static com.google.common.collect.Iterables.any; 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.azurecompute.arm.domain.IdReference.extractName; +import static org.jclouds.azurecompute.arm.domain.IdReference.extractResourceGroup; import java.net.URI; import java.util.ArrayList; @@ -36,8 +38,8 @@ import javax.inject.Named; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.SecurityGroupAvailablePredicateFactory; import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName; -import org.jclouds.azurecompute.arm.domain.IdReference; import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; +import org.jclouds.azurecompute.arm.domain.NetworkProfile.NetworkInterface; import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroupProperties; import org.jclouds.azurecompute.arm.domain.NetworkSecurityRule; @@ -135,12 +137,12 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio if (vm == null) { throw new IllegalArgumentException("Node " + nodeId + " was not found"); } - List networkInterfacesIdReferences = vm.properties().networkProfile().networkInterfaces(); + List networkInterfaces = vm.properties().networkProfile().networkInterfaces(); List networkGroups = new ArrayList(); - for (IdReference networkInterfaceCardIdReference : networkInterfacesIdReferences) { - String nicName = networkInterfaceCardIdReference.name(); - String nicResourceGroup = networkInterfaceCardIdReference.resourceGroup(); + for (NetworkInterface networkInterfaceCardIdReference : networkInterfaces) { + String nicName = extractName(networkInterfaceCardIdReference.id()); + String nicResourceGroup = extractResourceGroup(networkInterfaceCardIdReference.id()); NetworkInterfaceCard card = api.getNetworkInterfaceCardApi(nicResourceGroup).get(nicName); if (card != null && card.properties().networkSecurityGroup() != null) { String secGroupName = card.properties().networkSecurityGroup().name(); @@ -171,9 +173,14 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio SecurityGroupBuilder builder = new SecurityGroupBuilder(); builder.name(name); builder.location(location); + + NetworkSecurityGroup sg = api.getNetworkSecurityGroupApi(resourceGroup.name()).createOrUpdate(name, + location.getId(), null, NetworkSecurityGroupProperties.builder().build()); + + checkState(securityGroupAvailable.create(resourceGroup.name()).apply(name), + "Security group was not created in the configured timeout"); - return securityGroupConverter.apply(api.getNetworkSecurityGroupApi(resourceGroup.name()).createOrUpdate(name, - location.getId(), null, NetworkSecurityGroupProperties.builder().build())); + return securityGroupConverter.apply(sg); } @Override 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 index e4b7da8976..af43cbbcac 100644 --- 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 @@ -22,6 +22,7 @@ import static com.google.common.collect.Iterables.find; import static org.jclouds.azurecompute.arm.compute.AzureComputeServiceAdapter.GROUP_KEY; import static org.jclouds.azurecompute.arm.compute.domain.LocationAndName.fromLocationAndName; import static org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName.fromResourceGroupAndName; +import static org.jclouds.azurecompute.arm.domain.IdReference.extractName; import static org.jclouds.azurecompute.arm.domain.IdReference.extractResourceGroup; import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromCommaDelimitedValue; import static org.jclouds.location.predicates.LocationPredicates.idEquals; @@ -40,6 +41,7 @@ import org.jclouds.azurecompute.arm.compute.functions.VirtualMachineToStatus.Sta 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.NetworkProfile.NetworkInterface; import org.jclouds.azurecompute.arm.domain.PublicIPAddress; import org.jclouds.azurecompute.arm.domain.StorageProfile; import org.jclouds.azurecompute.arm.domain.VirtualMachine; @@ -136,9 +138,9 @@ public class VirtualMachineToNodeMetadata implements Function getPrivateIpAddresses(List idReferences) { + private Iterable getPrivateIpAddresses(List networkInterfaces) { List privateIpAddresses = Lists.newArrayList(); - for (IdReference networkInterfaceCardIdReference : idReferences) { + for (NetworkInterface networkInterfaceCardIdReference : networkInterfaces) { NetworkInterfaceCard networkInterfaceCard = getNetworkInterfaceCard(networkInterfaceCardIdReference); if (networkInterfaceCard != null && networkInterfaceCard.properties() != null && networkInterfaceCard.properties().ipConfigurations() != null) { @@ -152,21 +154,21 @@ public class VirtualMachineToNodeMetadata implements Function getPublicIpAddresses(List idReferences) { + private Iterable getPublicIpAddresses(List networkInterfaces) { List publicIpAddresses = Lists.newArrayList(); - for (IdReference networkInterfaceCardIdReference : idReferences) { + for (NetworkInterface networkInterfaceCardIdReference : networkInterfaces) { NetworkInterfaceCard networkInterfaceCard = getNetworkInterfaceCard(networkInterfaceCardIdReference); if (networkInterfaceCard != null && networkInterfaceCard.properties() != null && networkInterfaceCard.properties().ipConfigurations() != null) { - String resourceGroup = networkInterfaceCardIdReference.resourceGroup(); for (IpConfiguration ipConfiguration : networkInterfaceCard.properties().ipConfigurations()) { if (ipConfiguration.properties().publicIPAddress() != null) { IdReference publicIpId = ipConfiguration.properties().publicIPAddress(); - PublicIPAddress publicIp = api.getPublicIPAddressApi(resourceGroup).get(publicIpId.name()); + PublicIPAddress publicIp = api.getPublicIPAddressApi(publicIpId.resourceGroup()).get( + publicIpId.name()); if (publicIp != null && publicIp.properties().ipAddress() != null) { publicIpAddresses.add(publicIp.properties().ipAddress()); } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/CreateSecurityGroupIfNeeded.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/CreateSecurityGroupIfNeeded.java index bb5dc0993d..98732d2567 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/CreateSecurityGroupIfNeeded.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/CreateSecurityGroupIfNeeded.java @@ -16,6 +16,7 @@ */ package org.jclouds.azurecompute.arm.compute.loaders; +import static com.google.common.base.Preconditions.checkState; import static org.jclouds.compute.util.ComputeServiceUtils.getPortRangesFromList; import java.util.ArrayList; @@ -28,6 +29,7 @@ import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.SecurityGroupAvailablePredicateFactory; import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndNameAndIngressRules; import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroupProperties; @@ -48,10 +50,12 @@ public class CreateSecurityGroupIfNeeded extends CacheLoader dataDisks = ImmutableList.of(); private String resourceGroup; - - /** - * Sets the virtual network name - */ - public AzureTemplateOptions virtualNetworkName(String virtualNetworkName) { - this.virtualNetworkName = virtualNetworkName; - return this; - } - - /** - * Sets the subnet name - */ - public AzureTemplateOptions subnetId(String subnetId) { - this.subnetId = subnetId; - return this; - } + private List ipOptions = ImmutableList.of(); /** * Sets the availability set where the nodes will be configured. If it does @@ -92,12 +75,35 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { return dataDisks(ImmutableList.copyOf(checkNotNull(dataDisks, "dataDisks"))); } - public String getVirtualNetworkName() { return virtualNetworkName; } - public String getSubnetId() { return subnetId; } + /** + * Configure the NICs that will be attached to the created nodes. + *

+ * Note that the number of NICs that can be attached depends on the size of + * the virtual machine, and that the guest operating system needs to be + * prepared to set up all the configured interfaces. + *

+ * Depending on the image being used, a cloud-init or bootstrap script might + * be needed to make the interface setup. + */ + public AzureTemplateOptions ipOptions(Iterable ipOptions) { + for (IpOptions ipOption : checkNotNull(ipOptions, "ipOptions")) + checkNotNull(ipOption, "all ipOptions must be non-empty"); + this.ipOptions = ImmutableList.copyOf(ipOptions); + return this; + } + + /** + * @see {@link AzureTemplateOptions#ipOptions(Iterable) + */ + public AzureTemplateOptions ipOptions(IpOptions... ipOptions) { + return ipOptions(ImmutableList.copyOf(checkNotNull(ipOptions, "ipOptions"))); + } + public AvailabilitySet getAvailabilitySet() { return availabilitySet; } public String getAvailabilitySetName() { return availabilitySetName; } public List getDataDisks() { return dataDisks; } public String getResourceGroup() { return resourceGroup; } + public List getIpOptions() { return ipOptions; } @Override public AzureTemplateOptions clone() { @@ -111,12 +117,11 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { super.copyTo(to); if (to instanceof AzureTemplateOptions) { AzureTemplateOptions eTo = AzureTemplateOptions.class.cast(to); - eTo.virtualNetworkName(virtualNetworkName); - eTo.subnetId(subnetId); eTo.availabilitySet(availabilitySet); eTo.availabilitySet(availabilitySetName); eTo.dataDisks(dataDisks); eTo.resourceGroup(resourceGroup); + eTo.ipOptions(ipOptions); } } @@ -128,27 +133,22 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { AzureTemplateOptions that = (AzureTemplateOptions) o; - return Objects.equal(virtualNetworkName, that.virtualNetworkName) && - Objects.equal(subnetId, that.subnetId) && + return Objects.equal(availabilitySetName, that.availabilitySetName) && + Objects.equal(resourceGroup, that.resourceGroup) && Objects.equal(availabilitySet, that.availabilitySet) && - Objects.equal(availabilitySetName, that.availabilitySetName) && Objects.equal(dataDisks, that.dataDisks) && - Objects.equal(resourceGroup, that.resourceGroup); + Objects.equal(ipOptions, that.ipOptions); } @Override public int hashCode() { - return Objects.hashCode(virtualNetworkName, subnetId, availabilitySet, availabilitySetName, dataDisks, - resourceGroup); + return Objects.hashCode(availabilitySet, availabilitySetName, dataDisks, + resourceGroup, ipOptions); } @Override public Objects.ToStringHelper string() { Objects.ToStringHelper toString = super.string(); - if (virtualNetworkName != null) - toString.add("virtualNetworkName", virtualNetworkName); - if (subnetId != null) - toString.add("subnetId", subnetId); if (availabilitySet != null) toString.add("availabilitySet", availabilitySet); if (availabilitySetName != null) @@ -157,26 +157,12 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { toString.add("dataDisks", dataDisks); if (resourceGroup != null) toString.add("resourceGroup", resourceGroup); + if (!ipOptions.isEmpty()) + toString.add("ipOptions", ipOptions); return toString; } public static class Builder { - - /** - * @see AzureTemplateOptions#virtualNetworkName(String) - */ - public static AzureTemplateOptions virtualNetworkName(String virtualNetworkName) { - AzureTemplateOptions options = new AzureTemplateOptions(); - return options.virtualNetworkName(virtualNetworkName); - } - - /** - * @see AzureTemplateOptions#subnetId(String) - */ - public static AzureTemplateOptions subnetId(String subnetId) { - AzureTemplateOptions options = new AzureTemplateOptions(); - return options.subnetId(subnetId); - } /** * @see AzureTemplateOptions#availabilitySet(AvailabilitySet) @@ -217,5 +203,21 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { AzureTemplateOptions options = new AzureTemplateOptions(); return options.resourceGroup(resourceGroup); } + + /** + * @see AzureTemplateOptions#ipOptions(IpOptions...) + */ + public static AzureTemplateOptions ipOptions(IpOptions... ipOptions) { + AzureTemplateOptions options = new AzureTemplateOptions(); + return options.ipOptions(ipOptions); + } + + /** + * @see AzureTemplateOptions#ipOptions(Iterable) + */ + public static AzureTemplateOptions ipOptions(Iterable ipOptions) { + AzureTemplateOptions options = new AzureTemplateOptions(); + return options.ipOptions(ipOptions); + } } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/IpOptions.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/IpOptions.java new file mode 100644 index 0000000000..73c4c6c052 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/options/IpOptions.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.azurecompute.arm.compute.options; + +import org.jclouds.javax.annotation.Nullable; + +import com.google.auto.value.AutoValue; +import com.google.common.base.Optional; + +/** + * Configures the ip addresses to be configured for the created nodes. + */ +@AutoValue +public abstract class IpOptions { + + /** + * The subnet where the NIC will be attached. + */ + public abstract String subnet(); + + /** + * The IP address to be configured, in case of static allocation, or absent + * for dynamic assignment. + */ + public abstract Optional address(); + + /** + * Flag to indicate if a public ip address should be allocated and bound to + * this NIC. + */ + public abstract boolean allocateNewPublicIp(); + + /** + * ID of the public IP to associate with the NIC. + */ + @Nullable + public abstract String publicIpId(); + + IpOptions() { + + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_IpOptions.Builder().address((String) null).allocateNewPublicIp(false); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder subnet(String subnet); + public abstract Builder allocateNewPublicIp(boolean allocatePublicIp); + public abstract Builder publicIpId(String publicIpId); + + abstract Builder address(Optional address); + public Builder address(String address) { + return address(Optional.fromNullable(address)); + } + + public abstract IpOptions build(); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java index 1f1a37dc51..3ca1a5db5f 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CleanupResources.java @@ -21,7 +21,10 @@ 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 com.google.common.collect.Maps.filterValues; +import static org.jclouds.azurecompute.arm.compute.AzureComputeServiceAdapter.AUTOGENERATED_IP_KEY; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; +import static org.jclouds.azurecompute.arm.domain.IdReference.extractName; +import static org.jclouds.azurecompute.arm.domain.IdReference.extractResourceGroup; import java.net.URI; import java.util.HashMap; @@ -42,8 +45,10 @@ import org.jclouds.azurecompute.arm.domain.IdReference; import org.jclouds.azurecompute.arm.domain.IpConfiguration; import org.jclouds.azurecompute.arm.domain.ManagedDiskParameters; import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; +import org.jclouds.azurecompute.arm.domain.NetworkProfile.NetworkInterface; import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; import org.jclouds.azurecompute.arm.domain.OSDisk; +import org.jclouds.azurecompute.arm.domain.PublicIPAddress; import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi; import org.jclouds.compute.functions.GroupNamingConvention; @@ -98,11 +103,11 @@ public class CleanupResources { public boolean cleanupVirtualMachineNICs(VirtualMachine virtualMachine) { boolean deleted = true; - for (IdReference nicRef : virtualMachine.properties().networkProfile().networkInterfaces()) { - String nicResourceGroup = nicRef.resourceGroup(); - String nicName = nicRef.name(); - NetworkInterfaceCard nic = api.getNetworkInterfaceCardApi(nicRef.resourceGroup()).get(nicName); - + for (NetworkInterface nicRef : virtualMachine.properties().networkProfile().networkInterfaces()) { + String nicResourceGroup = extractResourceGroup(nicRef.id()); + String nicName = extractName(nicRef.id()); + NetworkInterfaceCard nic = api.getNetworkInterfaceCardApi(nicResourceGroup).get(nicName); + Iterable publicIps = getPublicIps(nic); logger.debug(">> destroying nic %s...", nicName); @@ -112,9 +117,12 @@ public class CleanupResources { for (IdReference publicIp : publicIps) { String publicIpResourceGroup = publicIp.resourceGroup(); String publicIpName = publicIp.name(); - - logger.debug(">> deleting public ip nic %s...", publicIpName); - deleted &= api.getPublicIPAddressApi(publicIpResourceGroup).delete(publicIpName); + + PublicIPAddress ip = api.getPublicIPAddressApi(publicIpResourceGroup).get(publicIpName); + if (ip.tags() != null && Boolean.parseBoolean(ip.tags().get(AUTOGENERATED_IP_KEY))) { + logger.debug(">> deleting public ip %s...", publicIpName); + deleted &= api.getPublicIPAddressApi(publicIpResourceGroup).delete(publicIpName); + } } } return deleted; @@ -129,15 +137,15 @@ public class CleanupResources { for (DataDisk dataDisk : virtualMachine.properties().storageProfile().dataDisks()) { deleteManagedDisk(dataDisk.managedDiskParameters(), deleteJobs); } - + Set nonDeletedDisks = filterValues(deleteJobs, not(resourceDeleted)).keySet(); if (!nonDeletedDisks.isEmpty()) { logger.warn(">> could not delete disks: %s", Joiner.on(',').join(nonDeletedDisks)); } - + return nonDeletedDisks.isEmpty(); } - + private void deleteManagedDisk(@Nullable ManagedDiskParameters managedDisk, Map deleteJobs) { if (managedDisk != null) { IdReference diskRef = IdReference.create(managedDisk.id()); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java index c3bdbdd07e..2ddb340aa2 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java @@ -17,10 +17,13 @@ package org.jclouds.azurecompute.arm.compute.strategy; import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.Iterables.getOnlyElement; 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.domain.IdReference.extractName; +import static org.jclouds.azurecompute.arm.domain.IdReference.extractResourceGroup; +import static org.jclouds.azurecompute.arm.domain.Subnet.extractVirtualNetwork; import java.util.Arrays; import java.util.Map; @@ -37,13 +40,15 @@ import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName; import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndNameAndIngressRules; import org.jclouds.azurecompute.arm.compute.functions.TemplateToAvailabilitySet; import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; +import org.jclouds.azurecompute.arm.compute.options.IpOptions; import org.jclouds.azurecompute.arm.domain.AvailabilitySet; 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.Subnet; -import org.jclouds.azurecompute.arm.domain.VirtualNetwork; -import org.jclouds.azurecompute.arm.features.SubnetApi; -import org.jclouds.azurecompute.arm.features.VirtualNetworkApi; +import org.jclouds.azurecompute.arm.domain.Subnet.SubnetProperties; +import org.jclouds.azurecompute.arm.domain.VirtualNetwork.AddressSpace; +import org.jclouds.azurecompute.arm.domain.VirtualNetwork.VirtualNetworkProperties; import org.jclouds.compute.config.CustomizationResponse; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.Template; @@ -56,8 +61,9 @@ import org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThen import org.jclouds.domain.Location; import org.jclouds.logging.Logger; -import com.google.common.base.Optional; +import com.google.common.annotations.VisibleForTesting; import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Multimap; import com.google.common.util.concurrent.ListenableFuture; @@ -89,8 +95,7 @@ public class CreateResourcesThenCreateNodes extends CreateNodesWithGroupEncodedI TemplateToAvailabilitySet templateToAvailabilitySet) { super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor, customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory); - this.api = checkNotNull(api, "api cannot be null"); - checkNotNull(userExecutor, "userExecutor cannot be null"); + this.api = api; this.securityGroupMap = securityGroupMap; this.defaultVnetAddressPrefix = defaultVnetAddressPrefix; this.defaultSubnetAddressPrefix = defaultSubnetAddressPrefix; @@ -103,7 +108,7 @@ public class CreateResourcesThenCreateNodes extends CreateNodesWithGroupEncodedI Multimap customizationResponses) { AzureTemplateOptions options = template.getOptions().as(AzureTemplateOptions.class); - + // 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 @@ -112,42 +117,38 @@ public class CreateResourcesThenCreateNodes extends CreateNodesWithGroupEncodedI + "Authentication will delegate to the ssh-agent"); } - // This sill create the resource group if it does not exist String location = template.getLocation().getId(); createResourceGroupIfNeeded(group, location, options); - getOrCreateVirtualNetworkWithSubnet(location, options); + + normalizeNetworkOptions(options); + createDefaultNetworkIfNeeded(group, location, options); + configureSecurityGroupForOptions(group, template.getLocation(), options); configureAvailabilitySetForTemplate(template); return super.execute(group, count, template, goodNodes, badNodes, customizationResponses); } - protected synchronized void getOrCreateVirtualNetworkWithSubnet(final String location, AzureTemplateOptions options) { - String virtualNetworkName = Optional.fromNullable(options.getVirtualNetworkName()).or( - options.getResourceGroup() + "virtualnetwork"); - String subnetName = options.getResourceGroup() + "subnet"; - - // Subnets belong to a virtual network so that needs to be created first - VirtualNetworkApi vnApi = api.getVirtualNetworkApi(options.getResourceGroup()); - VirtualNetwork vn = vnApi.get(virtualNetworkName); - - if (vn == null) { - Subnet subnet = Subnet.create(subnetName, null, null, - Subnet.SubnetProperties.builder().addressPrefix(defaultSubnetAddressPrefix).build()); - - VirtualNetwork.VirtualNetworkProperties virtualNetworkProperties = VirtualNetwork.VirtualNetworkProperties - .builder().addressSpace(VirtualNetwork.AddressSpace.create(Arrays.asList(defaultVnetAddressPrefix))) + protected synchronized void createDefaultNetworkIfNeeded(String group, String location, AzureTemplateOptions options) { + if (options.getIpOptions().isEmpty()) { + String name = namingConvention.create().sharedNameForGroup(group); + + Subnet subnet = Subnet.builder().name(name) + .properties(SubnetProperties.builder().addressPrefix(defaultSubnetAddressPrefix).build()).build(); + + VirtualNetworkProperties properties = VirtualNetworkProperties.builder() + .addressSpace(AddressSpace.create(Arrays.asList(defaultVnetAddressPrefix))) .subnets(Arrays.asList(subnet)).build(); - - vn = vnApi.createOrUpdate(virtualNetworkName, location, virtualNetworkProperties); + + logger.debug(">> network options have not been configured. Creating network %s(%s) and subnet %s(%s)", name, + defaultVnetAddressPrefix, name, defaultSubnetAddressPrefix); + + api.getVirtualNetworkApi(options.getResourceGroup()).createOrUpdate(name, location, properties); + Subnet createdSubnet = api.getSubnetApi(options.getResourceGroup(), name).get(name); + + options.ipOptions(IpOptions.builder().subnet(createdSubnet.id()).allocateNewPublicIp(true).build()); } - - SubnetApi subnetApi = api.getSubnetApi(options.getResourceGroup(), virtualNetworkName); - Subnet subnet = subnetApi.get(subnetName); - - options.virtualNetworkName(virtualNetworkName); - options.subnetId(subnet.id()); } private static boolean hasRunScriptWithKeyAuthAndNoPrivateKey(Template template) { @@ -196,4 +197,45 @@ public class CreateResourcesThenCreateNodes extends CreateNodesWithGroupEncodedI ImmutableMap.of("description", "jclouds default resource group")); } } + + @VisibleForTesting + void normalizeNetworkOptions(AzureTemplateOptions options) { + if (!options.getNetworks().isEmpty() && !options.getIpOptions().isEmpty()) { + throw new IllegalArgumentException("The options.networks and options.ipOptions are exclusive"); + } + + if (!options.getNetworks().isEmpty() && options.getIpOptions().isEmpty()) { + // The portable interface allows to configure network IDs (subnet IDs), + // but we don't know the type of the IP configurations to be applied + // when attaching nodes to those networks. We'll assume private IPs + // with Dynamic allocation and no public ip address associated. + ImmutableList.Builder ipOptions = ImmutableList.builder(); + for (String subnetId : options.getNetworks()) { + ipOptions.add(IpOptions.builder().subnet(subnetId).build()); + } + options.ipOptions(ipOptions.build()); + } + + if (!options.getIpOptions().isEmpty()) { + // Eagerly validate that all configured subnets exist. + for (IpOptions ipConfig : options.getIpOptions()) { + if (ipConfig.allocateNewPublicIp() && ipConfig.publicIpId() != null) { + throw new IllegalArgumentException("The allocateNewPublicIps and publicIpId are exclusive"); + } + + String resourceGroup = extractResourceGroup(ipConfig.subnet()); + String networkName = extractVirtualNetwork(ipConfig.subnet()); + String subnetName = extractName(ipConfig.subnet()); + + Subnet subnet = api.getSubnetApi(resourceGroup, networkName).get(subnetName); + checkState(subnet != null, "Configured subnet %s does not exist", ipConfig.subnet()); + + if (ipConfig.publicIpId() != null) { + PublicIPAddress publicIp = api.getPublicIPAddressApi(extractResourceGroup(ipConfig.publicIpId())).get( + extractName(ipConfig.publicIpId())); + checkState(publicIp != null, "Configured public ip %s does not exist", ipConfig.publicIpId()); + } + } + } + } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCardProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCardProperties.java index d1976f1747..84c8ca2c38 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCardProperties.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCardProperties.java @@ -26,23 +26,16 @@ import java.util.List; @AutoValue public abstract class NetworkInterfaceCardProperties implements Provisionable { - @Nullable - public abstract String provisioningState(); - - @Nullable - public abstract String resourceGuid(); - - @Nullable - public abstract Boolean enableIPForwarding(); - - @Nullable - public abstract List ipConfigurations(); - - @Nullable - public abstract IdReference networkSecurityGroup(); + @Nullable public abstract String provisioningState(); + @Nullable public abstract String resourceGuid(); + @Nullable public abstract Boolean enableIPForwarding(); + @Nullable public abstract List ipConfigurations(); + @Nullable public abstract IdReference networkSecurityGroup(); @SerializedNames({"provisioningState", "resourceGuid", "enableIPForwarding", "ipConfigurations", "networkSecurityGroup"}) - public static NetworkInterfaceCardProperties create(final String provisioningState, final String resourceGuid, final Boolean enableIPForwarding, final List ipConfigurations, final IdReference networkSecurityGroup) { + public static NetworkInterfaceCardProperties create(final String provisioningState, final String resourceGuid, + final Boolean enableIPForwarding, final List ipConfigurations, + final IdReference networkSecurityGroup) { NetworkInterfaceCardProperties.Builder builder = NetworkInterfaceCardProperties.builder() .provisioningState(provisioningState) .resourceGuid(resourceGuid) @@ -52,28 +45,26 @@ public abstract class NetworkInterfaceCardProperties implements Provisionable { return builder.build(); } - + + NetworkInterfaceCardProperties() { + + } + public abstract Builder toBuilder(); public static Builder builder() { - return new AutoValue_NetworkInterfaceCardProperties.Builder(); } @AutoValue.Builder public abstract static class Builder { public abstract Builder provisioningState(String provisioningState); - public abstract Builder resourceGuid(String resourceGuid); - public abstract Builder enableIPForwarding(Boolean enableIPForwarding); - public abstract Builder ipConfigurations(List ipConfigurations); - - abstract List ipConfigurations(); - public abstract Builder networkSecurityGroup(IdReference networkSecurityGroup); + abstract List ipConfigurations(); abstract NetworkInterfaceCardProperties autoBuild(); public NetworkInterfaceCardProperties build() { diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkProfile.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkProfile.java index b26305f5f5..cdb6d5184b 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkProfile.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkProfile.java @@ -19,6 +19,7 @@ package org.jclouds.azurecompute.arm.domain; import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; +import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; import java.util.List; @@ -26,16 +27,49 @@ import java.util.List; @AutoValue public abstract class NetworkProfile { + @AutoValue + public abstract static class NetworkInterface { + public abstract String id(); + @Nullable public abstract NetworkInterfaceProperties properties(); + + @AutoValue + public abstract static class NetworkInterfaceProperties { + public abstract boolean primary(); + + NetworkInterfaceProperties() { + + } + + @SerializedNames({"primary"}) + public static NetworkInterfaceProperties create(boolean primary) { + return new AutoValue_NetworkProfile_NetworkInterface_NetworkInterfaceProperties(primary); + } + } + + NetworkInterface() { + + } + + @SerializedNames({"id", "properties"}) + public static NetworkInterface create(String id, NetworkInterfaceProperties properties) { + return new AutoValue_NetworkProfile_NetworkInterface(id, properties); + } + } + /** * List of network interfaces */ - public abstract List networkInterfaces(); + public abstract List networkInterfaces(); @SerializedNames({"networkInterfaces"}) - public static NetworkProfile create(final List networkInterfaces) { + public static NetworkProfile create(final List networkInterfaces) { return builder().networkInterfaces(networkInterfaces).build(); } + NetworkProfile() { + + } + public abstract Builder toBuilder(); public static Builder builder() { @@ -44,14 +78,14 @@ public abstract class NetworkProfile { @AutoValue.Builder public abstract static class Builder { - public abstract Builder networkInterfaces(List networkInterfaces); + public abstract Builder networkInterfaces(List networkInterfaces); - abstract List networkInterfaces(); + abstract List networkInterfaces(); abstract NetworkProfile autoBuild(); public NetworkProfile build() { - networkInterfaces(networkInterfaces() != null ? ImmutableList.copyOf(networkInterfaces()) : ImmutableList.of()); + networkInterfaces(networkInterfaces() != null ? ImmutableList.copyOf(networkInterfaces()) : ImmutableList.of()); return autoBuild(); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/PublicIPAddress.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/PublicIPAddress.java index a08faddf63..8d0cb2b861 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/PublicIPAddress.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/PublicIPAddress.java @@ -17,36 +17,55 @@ 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; @AutoValue public abstract class PublicIPAddress { public abstract String name(); - public abstract String id(); - public abstract String etag(); - public abstract String location(); - - @Nullable - public abstract Map tags(); - + @Nullable public abstract Map tags(); public abstract PublicIPAddressProperties properties(); - @SerializedNames({"name", "id", "etag", "location", "tags", "properties"}) - public static PublicIPAddress create(final String name, - final String id, - final String etag, - final String location, - final Map tags, - final PublicIPAddressProperties properties) { - return new AutoValue_PublicIPAddress(name, id, etag, location, tags == null ? null : ImmutableMap.copyOf(tags), properties); + @SerializedNames({ "name", "id", "etag", "location", "tags", "properties" }) + public static PublicIPAddress create(String name, String id, String etag, String location, Map tags, + PublicIPAddressProperties properties) { + return builder().name(name).id(id).etag(etag).location(location).tags(tags).properties(properties).build(); + } + + PublicIPAddress() { + + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_PublicIPAddress.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder name(String name); + public abstract Builder id(String id); + public abstract Builder etag(String etag); + public abstract Builder location(String location); + public abstract Builder tags(Map tags); + public abstract Builder properties(PublicIPAddressProperties properties); + + abstract Map tags(); + abstract PublicIPAddress autoBuild(); + + public PublicIPAddress build() { + tags(tags() != null ? ImmutableMap.copyOf(tags()) : null); + return autoBuild(); + } } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Subnet.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Subnet.java index 6830438f94..80460b8f3f 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Subnet.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Subnet.java @@ -19,6 +19,8 @@ package org.jclouds.azurecompute.arm.domain; import static com.google.common.collect.ImmutableList.copyOf; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import com.google.common.collect.ImmutableList; @@ -29,6 +31,8 @@ import org.jclouds.json.SerializedNames; @AutoValue public abstract class Subnet { + private static final Pattern NETWORK_PATTERN = Pattern.compile("^.*/virtualNetworks/([^/]+)(/.*)?$"); + @AutoValue public abstract static class IpConfiguration { @@ -38,19 +42,18 @@ public abstract class Subnet { public static IpConfiguration create(final String id) { return new AutoValue_Subnet_IpConfiguration(id); } + + IpConfiguration() { + + } } @AutoValue public abstract static class SubnetProperties implements Provisionable { - @Nullable - public abstract String provisioningState(); - - @Nullable - public abstract String addressPrefix(); - - @Nullable - public abstract List ipConfigurations(); + @Nullable public abstract String provisioningState(); + @Nullable public abstract String addressPrefix(); + @Nullable public abstract List ipConfigurations(); @SerializedNames({"provisioningState", "addressPrefix", "ipConfigurations"}) public static SubnetProperties create(final String provisioningState, final String addressPrefix, final List ipConfigurations) { @@ -61,6 +64,10 @@ public abstract class Subnet { .build(); } + SubnetProperties() { + + } + public abstract Builder toBuilder(); public static Builder builder() { @@ -70,13 +77,10 @@ public abstract class Subnet { @AutoValue.Builder public abstract static class Builder { public abstract Builder provisioningState(String provisioningState); - public abstract Builder addressPrefix(String addressPrefix); - public abstract Builder ipConfigurations(List ipConfigurations); abstract List ipConfigurations(); - abstract SubnetProperties autoBuild(); public SubnetProperties build() { @@ -86,23 +90,47 @@ public abstract class Subnet { } } - @Nullable - public abstract String name(); - - @Nullable - public abstract String id(); - - @Nullable - public abstract String etag(); - - @Nullable - public abstract SubnetProperties properties(); + @Nullable public abstract String name(); + @Nullable public abstract String id(); + @Nullable public abstract String etag(); + @Nullable public abstract SubnetProperties properties(); + + @Nullable public String virtualNetwork() { + return extractVirtualNetwork(id()); + } + + public static String extractVirtualNetwork(String id) { + if (id == null) + return null; + Matcher m = NETWORK_PATTERN.matcher(id); + m.matches(); + return m.group(1); + } @SerializedNames({"name", "id", "etag", "properties"}) public static Subnet create(final String name, final String id, final String etag, final SubnetProperties properties) { - return new AutoValue_Subnet(name, id, etag, properties); + return builder().name(name).id(id).etag(etag).properties(properties).build(); + } + + Subnet() { + + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_Subnet.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder name(String name); + public abstract Builder id(String id); + public abstract Builder etag(String etag); + public abstract Builder properties(SubnetProperties properties); + public abstract Subnet build(); } } 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 26937535ff..75af4ff988 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 @@ -34,6 +34,7 @@ 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.javax.annotation.Nullable; import org.jclouds.oauth.v2.filters.OAuthFilter; import org.jclouds.rest.annotations.Fallback; import org.jclouds.rest.annotations.MapBinder; @@ -60,7 +61,7 @@ public interface PublicIPAddressApi { @PUT PublicIPAddress createOrUpdate(@PathParam("publicipaddressname") String publicipaddressname, @PayloadParam("location") String location, - @PayloadParam("tags") Map tags, + @Nullable @PayloadParam("tags") Map tags, @PayloadParam("properties") PublicIPAddressProperties properties); @Named("publicipaddress:get") diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodesTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodesTest.java new file mode 100644 index 0000000000..f95430c299 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodesTest.java @@ -0,0 +1,114 @@ +/* + * 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 org.easymock.EasyMock.anyObject; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import static org.testng.Assert.assertEquals; + +import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; +import org.jclouds.azurecompute.arm.compute.options.IpOptions; +import org.jclouds.azurecompute.arm.domain.PublicIPAddress; +import org.jclouds.azurecompute.arm.domain.PublicIPAddressProperties; +import org.jclouds.azurecompute.arm.domain.Subnet; +import org.jclouds.azurecompute.arm.features.PublicIPAddressApi; +import org.jclouds.azurecompute.arm.features.SubnetApi; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; + +@Test(groups = "unit", testName = "CreateResourcesThenCreateNodesTest") +public class CreateResourcesThenCreateNodesTest { + + @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "The options.networks and options.ipOptions are exclusive") + public void testNormalizeNetworkOptionsWithConflictingConfig() { + AzureTemplateOptions options = new AzureTemplateOptions(); + options.ipOptions(IpOptions.builder().subnet(netResource("/virtualNetworks/vn/subnets/foo")).build()); + options.networks(netResource("/virtualNetworks/vn/subnets/bar")); + strategy(null).normalizeNetworkOptions(options); + } + + @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "The allocateNewPublicIps and publicIpId are exclusive") + public void testNormalizeNetworkOptionsExclusivePublicIps() { + AzureTemplateOptions options = new AzureTemplateOptions(); + options.ipOptions(IpOptions.builder().subnet(netResource("/virtualNetworks/vn/subnets/foo")) + .allocateNewPublicIp(true).publicIpId(netResource("/publicIPAddresses/pub")).build()); + strategy(null).normalizeNetworkOptions(options); + } + + public void testPortableNetworkOptions() { + AzureComputeApi api = createMock(AzureComputeApi.class); + SubnetApi subnetApi = createMock(SubnetApi.class); + + expect(api.getSubnetApi(anyObject(String.class), anyObject(String.class))).andReturn(subnetApi).times(2); + expect(subnetApi.get(anyObject(String.class))).andReturn(Subnet.builder().build()).times(2); + replay(api, subnetApi); + + AzureTemplateOptions options = new AzureTemplateOptions(); + options.networks(netResource("/virtualNetworks/vn/subnets/foo"), netResource("/virtualNetworks/vn/subnets/bar")); + strategy(api).normalizeNetworkOptions(options); + + assertEquals(options.getIpOptions(), ImmutableList.of( + IpOptions.builder().subnet(netResource("/virtualNetworks/vn/subnets/foo")).build(), IpOptions.builder() + .subnet(netResource("/virtualNetworks/vn/subnets/bar")).build())); + + // Verify that the code has validated that the subnets exist + verify(api, subnetApi); + } + + public void testProviderSpecificNetworkOptions() { + AzureComputeApi api = createMock(AzureComputeApi.class); + SubnetApi subnetApi = createMock(SubnetApi.class); + PublicIPAddressApi publicIpApi = createMock(PublicIPAddressApi.class); + + expect(api.getSubnetApi(anyObject(String.class), anyObject(String.class))).andReturn(subnetApi).times(2); + expect(api.getPublicIPAddressApi(anyObject(String.class))).andReturn(publicIpApi); + expect(subnetApi.get(anyObject(String.class))).andReturn(Subnet.builder().build()).times(2); + expect(publicIpApi.get(anyObject(String.class))).andReturn(mockAddress()); + replay(api, subnetApi, publicIpApi); + + IpOptions publicOpts = IpOptions.builder().subnet(netResource("/virtualNetworks/vn/subnets/foo")) + .publicIpId(netResource("/publicIPAddresses/pub")).address("10.0.0.2").build(); + IpOptions privateOpts = IpOptions.builder().subnet(netResource("/virtualNetworks/vn/subnets/bar")).build(); + + AzureTemplateOptions options = new AzureTemplateOptions(); + options.ipOptions(publicOpts, privateOpts); + strategy(api).normalizeNetworkOptions(options); + + assertEquals(options.getIpOptions(), ImmutableList.of(publicOpts, privateOpts)); + + // Verify that the code has validated that the subnets exist + verify(api, subnetApi, publicIpApi); + } + + private static CreateResourcesThenCreateNodes strategy(AzureComputeApi api) { + return new CreateResourcesThenCreateNodes(null, null, null, null, null, api, null, null, null, null); + } + + private static String netResource(String resource) { + return "/subscriptions/subs/resourceGroups/rg/providers/Microsoft.Network" + resource; + } + + private static PublicIPAddress mockAddress() { + return PublicIPAddress.builder().name("name").id("id").etag("etag").location("location") + .properties(PublicIPAddressProperties.builder().publicIPAllocationMethod("Dynamic").build()).build(); + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/domain/IdReferenceTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/domain/IdReferenceTest.java index e5426d7aa0..e2a56e1840 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/domain/IdReferenceTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/domain/IdReferenceTest.java @@ -22,6 +22,7 @@ import static org.testng.Assert.assertEquals; import org.testng.annotations.Test; +@Test(groups = "unit", testName = "IdReferenceTest") public class IdReferenceTest { @Test diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/domain/SubnetTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/domain/SubnetTest.java new file mode 100644 index 0000000000..a5ef44c4ef --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/domain/SubnetTest.java @@ -0,0 +1,47 @@ +/* + * 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 static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; + +import org.testng.annotations.Test; + +@Test(groups = "unit", testName = "SubnetTest") +public class SubnetTest { + + @Test + public void testExtractVirtualNetwork() { + + assertEquals(Subnet.builder().build().virtualNetwork(), null); + assertEquals( + Subnet.builder() + .id("/subscriptions/subscription/resourceGroups/rg/providers/Microsoft.Network/virtualNetworks/vn/subnets/subnet") + .build().virtualNetwork(), "vn"); + assertInvalidId("/subscriptions/subscription/resourceGroups/rg/providers/Microsoft.Network/virtualNetworks"); + assertInvalidId("virtualNetworks/vn"); + } + + private static void assertInvalidId(String id) { + try { + Subnet.builder().id(id).build().virtualNetwork(); + fail("The given ID " + id + "should not match a valid virtual network"); + } catch (IllegalStateException ex) { + // Expected + } + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java index c5b836beb3..5cf42397a0 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java @@ -23,6 +23,7 @@ import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Lists.newArrayList; import static org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions.Builder.availabilitySet; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; +import static org.jclouds.azurecompute.arm.domain.IdReference.extractName; import static org.jclouds.azurecompute.arm.domain.InboundNatRuleProperties.Protocol.Tcp; import static org.jclouds.compute.predicates.NodePredicates.inGroup; import static org.testng.Assert.assertEquals; @@ -360,7 +361,7 @@ public class LoadBalancerApiLiveTest extends BaseComputeServiceContextLiveTest { VirtualMachine vm = api.getVirtualMachineApi(resourceGroupAndName.resourceGroup()).get( resourceGroupAndName.name()); - String nicName = vm.properties().networkProfile().networkInterfaces().get(0).name(); + String nicName = extractName(vm.properties().networkProfile().networkInterfaces().get(0).id()); nicNames.add(nicName); } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiMockTest.java index e0f0ed4724..dd10046c50 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiMockTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/NetworkInterfaceCardApiMockTest.java @@ -40,7 +40,7 @@ public class NetworkInterfaceCardApiMockTest extends BaseAzureComputeApiMockTest private final String subscriptionid = "SUBSCRIPTIONID"; private final String resourcegroup = "myresourcegroup"; - private final String apiVersion = "api-version=2015-06-15"; + private final String apiVersion = "api-version=2017-03-01"; private final String location = "northeurope"; private final String nicName = "myNic"; @@ -65,7 +65,8 @@ public class NetworkInterfaceCardApiMockTest extends BaseAzureComputeApiMockTest assertNull(nicApi.get(nicName)); - assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourcegroups/myresourcegroup/providers/Microsoft.Network/networkInterfaces/myNic?api-version=2015-06-15"); + String path = String.format("/subscriptions/%s/resourcegroups/%s/providers/Microsoft.Network/networkInterfaces/%s?%s", subscriptionid, resourcegroup, nicName, apiVersion); + assertSent(server, "GET", path); } public void listNetworkInterfaceCards() throws InterruptedException { 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 0113201f55..3d58591568 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 @@ -36,7 +36,7 @@ public class SubnetApiMockTest extends BaseAzureComputeApiMockTest { private final String resourcegroup = "myresourcegroup"; private final String virtualNetwork = "myvirtualnetwork"; private final String subnetName = "mysubnet"; - private final String apiVersion = "api-version=2015-06-15"; + private final String apiVersion = "api-version=2017-03-01"; public void createSubnet() throws InterruptedException { 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 cecdc012fa..f3f6aacb1f 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 @@ -51,6 +51,8 @@ import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance; import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance.PowerState; import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties; +import org.jclouds.azurecompute.arm.domain.NetworkProfile.NetworkInterface; +import org.jclouds.azurecompute.arm.domain.NetworkProfile.NetworkInterface.NetworkInterfaceProperties; import org.jclouds.azurecompute.arm.functions.ParseJobStatus; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; import org.testng.annotations.BeforeClass; @@ -253,12 +255,11 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { OSProfile.WindowsConfiguration windowsConfig = OSProfile.WindowsConfiguration.create(false, null, null, true, null); OSProfile osProfile = OSProfile.create(vmName, "azureuser", "RFe3&432dg", null, null, windowsConfig); - IdReference networkInterface = - IdReference.create("/subscriptions/" + subscriptionid + + NetworkInterface networkInterface = + NetworkInterface.create("/subscriptions/" + subscriptionid + "/resourceGroups/" + resourceGroupName + "/providers/Microsoft.Network/networkInterfaces/" - + nic); - List networkInterfaces = - new ArrayList(); + + nic, NetworkInterfaceProperties.create(true)); + List networkInterfaces = new ArrayList(); networkInterfaces.add(networkInterface); NetworkProfile networkProfile = NetworkProfile.create(networkInterfaces); VirtualMachineProperties properties = VirtualMachineProperties.create(null, 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 27e6f6b97a..95d967e3ac 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,6 +16,12 @@ */ package org.jclouds.azurecompute.arm.features; +import static com.google.common.collect.Iterables.isEmpty; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + import java.net.URI; import java.text.DateFormat; import java.text.SimpleDateFormat; @@ -26,9 +32,9 @@ 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.NetworkProfile; +import org.jclouds.azurecompute.arm.domain.NetworkProfile.NetworkInterface; import org.jclouds.azurecompute.arm.domain.OSDisk; import org.jclouds.azurecompute.arm.domain.OSProfile; import org.jclouds.azurecompute.arm.domain.Plan; @@ -45,12 +51,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; 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.assertNotNull; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; - @Test(groups = "unit", testName = "VirtualMachineApiMockTest", singleThreaded = true) public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { @@ -257,9 +257,9 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { OSProfile.WindowsConfiguration windowsConfig = OSProfile.WindowsConfiguration.create(false, null, null, true, null); OSProfile osProfile = OSProfile.create("windowsmachine", "azureuser", null, null, null, windowsConfig); - IdReference networkInterface = IdReference.create("/subscriptions/SUBSCRIPTIONID" - + "/resourceGroups/groupname/providers/Microsoft.Network/networkInterfaces/" + "windowsmachine167"); - List networkInterfaces = new ArrayList(); + NetworkInterface networkInterface = NetworkInterface.create("/subscriptions/SUBSCRIPTIONID" + + "/resourceGroups/groupname/providers/Microsoft.Network/networkInterfaces/" + "windowsmachine167", null); + List networkInterfaces = new ArrayList(); networkInterfaces.add(networkInterface); NetworkProfile networkProfile = NetworkProfile.create(networkInterfaces); DiagnosticsProfile.BootDiagnostics bootDiagnostics = DiagnosticsProfile.BootDiagnostics.create(true, From 45480c49131063a4eeedc801ba53d730bafb3f01 Mon Sep 17 00:00:00 2001 From: Dani Estevez Date: Mon, 22 May 2017 13:49:59 -0400 Subject: [PATCH 63/87] Fixes India regions to their actual name --- .../java/org/jclouds/azurecompute/arm/domain/Region.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.java index c7d571833f..c65ae5914d 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.java @@ -54,9 +54,9 @@ public enum Region { BRAZIL_SOUTH("Brazil South", "BR"), AUSTRALIA_EAST("Australia East", "AU-NSW"), AUSTRALIA_SOUTH_EAST("Australia Southeast", "AU-VIC"), - INDIA_CENTRAL("Central India", "IN-GA"), - INDIA_SOUTH("South India", "IN-TN"), - INDIA_WEST("West India", "IN-MH"), + CENTRAL_INDIA("Central India", "IN-GA"), + SOUTH_INDIA("South India", "IN-TN"), + WEST_INDIA("West India", "IN-MH"), CHINA_EAST("China East", "CN-SH"), CHINA_NORTH("China North", "CN-BJ"), CANADA_CENTRAL("Canada Central", "CA-ON"), From 50ae01985af0e630cb71078e58db3cc746482cce Mon Sep 17 00:00:00 2001 From: Yavor Yanchev Date: Fri, 19 May 2017 12:41:16 +0300 Subject: [PATCH 64/87] Adding support for provisioning of Windows VMs with enabled WinRM - Provisioning using pre-existing KeyVault - Enabling WinRM with pre-existing certificate --- .../compute/AzureComputeServiceAdapter.java | 16 +++- .../compute/options/AzureTemplateOptions.java | 60 +++++++++++++- .../azurecompute/arm/domain/OSProfile.java | 82 ++++++++++++++----- .../azurecompute/arm/domain/Secrets.java | 55 +++++++++++++ .../arm/domain/VaultCertificate.java | 46 +++++++++++ .../features/VirtualMachineApiLiveTest.java | 35 ++++++-- .../features/VirtualMachineApiMockTest.java | 82 ++++++++++++++----- .../internal/BaseAzureComputeApiLiveTest.java | 19 +++++ .../createvirtualmachineresponse.json | 69 ++++++++++++++-- .../src/test/resources/virtualmachine.json | 65 +++++++++++++-- .../src/test/resources/virtualmachines.json | 57 +++++++++++-- 11 files changed, 513 insertions(+), 73 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Secrets.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VaultCertificate.java 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 02e69fa4ae..ccb748a956 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 @@ -64,6 +64,8 @@ import org.jclouds.azurecompute.arm.domain.ManagedDiskParameters; 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.NetworkProfile.NetworkInterface; +import org.jclouds.azurecompute.arm.domain.NetworkProfile.NetworkInterface.NetworkInterfaceProperties; import org.jclouds.azurecompute.arm.domain.OSDisk; import org.jclouds.azurecompute.arm.domain.OSProfile; import org.jclouds.azurecompute.arm.domain.Offer; @@ -82,8 +84,6 @@ import org.jclouds.azurecompute.arm.domain.VMSize; import org.jclouds.azurecompute.arm.domain.Version; import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties; -import org.jclouds.azurecompute.arm.domain.NetworkProfile.NetworkInterface; -import org.jclouds.azurecompute.arm.domain.NetworkProfile.NetworkInterface.NetworkInterfaceProperties; import org.jclouds.azurecompute.arm.features.NetworkInterfaceCardApi; import org.jclouds.azurecompute.arm.features.OSImageApi; import org.jclouds.compute.ComputeServiceAdapter; @@ -390,6 +390,17 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter dataDisks = ImmutableList.of(); private String resourceGroup; private List ipOptions = ImmutableList.of(); + private WindowsConfiguration windowsConfiguration; + private List secrets = ImmutableList.of(); /** * Sets the availability set where the nodes will be configured. If it does @@ -98,12 +102,36 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { public AzureTemplateOptions ipOptions(IpOptions... ipOptions) { return ipOptions(ImmutableList.copyOf(checkNotNull(ipOptions, "ipOptions"))); } - + + /** + * Windows configuration parameters + * + * @see docs + */ + public AzureTemplateOptions windowsConfiguration(WindowsConfiguration windowsConfiguration) { + this.windowsConfiguration = windowsConfiguration; + return this; + } + + /** + * Import certificates in the Windows Certificate Store + * + * @see docs + */ + public AzureTemplateOptions secrets(Iterable secrets) { + for (Secrets secret : checkNotNull(secrets, "secrets")) + checkNotNull(secret, "secrets can not be empty"); + this.secrets = ImmutableList.copyOf(secrets); + return this; + } + public AvailabilitySet getAvailabilitySet() { return availabilitySet; } public String getAvailabilitySetName() { return availabilitySetName; } public List getDataDisks() { return dataDisks; } public String getResourceGroup() { return resourceGroup; } public List getIpOptions() { return ipOptions; } + public WindowsConfiguration getWindowsConfiguration() { return windowsConfiguration; } + public List getSecrets() { return secrets; } @Override public AzureTemplateOptions clone() { @@ -122,6 +150,8 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { eTo.dataDisks(dataDisks); eTo.resourceGroup(resourceGroup); eTo.ipOptions(ipOptions); + eTo.windowsConfiguration(windowsConfiguration); + eTo.secrets(secrets); } } @@ -137,7 +167,9 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { Objects.equal(resourceGroup, that.resourceGroup) && Objects.equal(availabilitySet, that.availabilitySet) && Objects.equal(dataDisks, that.dataDisks) && - Objects.equal(ipOptions, that.ipOptions); + Objects.equal(ipOptions, that.ipOptions) && + Objects.equal(windowsConfiguration, that.windowsConfiguration) && + Objects.equal(secrets, that.secrets); } @Override @@ -159,6 +191,10 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { toString.add("resourceGroup", resourceGroup); if (!ipOptions.isEmpty()) toString.add("ipOptions", ipOptions); + if (windowsConfiguration != null) + toString.add("windowsConfiguration", windowsConfiguration); + if (!secrets.isEmpty()) + toString.add("secrets", secrets); return toString; } @@ -219,5 +255,21 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { AzureTemplateOptions options = new AzureTemplateOptions(); return options.ipOptions(ipOptions); } + + /** + * @see AzureTemplateOptions#windowsConfiguration(WindowsConfiguration) + */ + public static AzureTemplateOptions windowsConfiguration(WindowsConfiguration windowsConfiguration) { + AzureTemplateOptions options = new AzureTemplateOptions(); + return options.windowsConfiguration(windowsConfiguration); + } + + /** + * @see AzureTemplateOptions#secrets(List) + */ + public static AzureTemplateOptions secrets(Iterable secrets) { + AzureTemplateOptions options = new AzureTemplateOptions(); + return options.secrets(secrets); + } } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSProfile.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSProfile.java index 5592b4c389..b77dc9e5fc 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSProfile.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSProfile.java @@ -16,15 +16,14 @@ */ package org.jclouds.azurecompute.arm.domain; -import com.google.auto.value.AutoValue; -import com.google.common.collect.ImmutableList; +import java.util.List; +import org.jclouds.azurecompute.arm.util.GetEnumValue; import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; -import java.util.List; -import java.util.Map; -import com.google.common.collect.ImmutableMap; +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; @AutoValue public abstract class OSProfile { @@ -91,15 +90,52 @@ public abstract class OSProfile { @AutoValue public abstract static class WinRM { + public enum Protocol { + + HTTP("http"), + HTTPS("https"), + UNRECOGNIZED("Unrecognized"); + + private String value; + + Protocol(String value) { + this.value = value; + } + + public static Protocol fromValue(String value) { + return (Protocol) GetEnumValue.fromValueOrDefault(value, Protocol.UNRECOGNIZED); + } + + @Override + public String toString() { + return this.value; + } + } + + @AutoValue + public abstract static class ProtocolListener { + + public abstract Protocol protocol(); + + @Nullable + public abstract String certificateUrl(); + + @SerializedNames({"protocol", "certificateUrl"}) + public static ProtocolListener create(final Protocol protocol, final String certificateUrl) { + + return new AutoValue_OSProfile_WindowsConfiguration_WinRM_ProtocolListener( + protocol, certificateUrl); + } + } /** * Map of different settings */ - public abstract Map listeners(); + public abstract List listeners(); @SerializedNames({"listeners"}) - public static WinRM create(final Map listeners) { - return new AutoValue_OSProfile_WindowsConfiguration_WinRM(listeners == null ? ImmutableMap.of() : ImmutableMap.copyOf(listeners)); + public static WinRM create(final List listeners) { + return new AutoValue_OSProfile_WindowsConfiguration_WinRM(listeners == null ? ImmutableList.of() : ImmutableList.copyOf(listeners)); } } @@ -139,27 +175,20 @@ public abstract class OSProfile { * unattend content */ @Nullable - public abstract AdditionalUnattendContent additionalUnattendContent(); + public abstract List additionalUnattendContent(); /** * is automatic updates enabled */ public abstract boolean enableAutomaticUpdates(); - /** - * list of certificates - */ - @Nullable - public abstract List secrets(); - - @SerializedNames({"provisionVMAgent", "winRM", "additionalUnattendContent", "enableAutomaticUpdates", - "secrets"}) + @SerializedNames({"provisionVMAgent", "winRM", "additionalUnattendContent", "enableAutomaticUpdates"}) public static WindowsConfiguration create(final boolean provisionVMAgent, final WinRM winRM, - final AdditionalUnattendContent additionalUnattendContent, - final boolean enableAutomaticUpdates, final List secrets) { + final List additionalUnattendContent, + final boolean enableAutomaticUpdates) { return new AutoValue_OSProfile_WindowsConfiguration(provisionVMAgent, winRM, - additionalUnattendContent, enableAutomaticUpdates, secrets == null ? null : ImmutableList.copyOf(secrets)); + additionalUnattendContent, enableAutomaticUpdates); } } @@ -199,11 +228,17 @@ public abstract class OSProfile { @Nullable public abstract WindowsConfiguration windowsConfiguration(); + /** + * The Secrets configuration of the VM + */ + @Nullable + public abstract List secrets(); + @SerializedNames({"computerName", "adminUsername", "adminPassword", "customData", "linuxConfiguration", - "windowsConfiguration"}) + "windowsConfiguration", "secrets"}) public static OSProfile create(final String computerName, final String adminUsername, final String adminPassword, final String customData, final LinuxConfiguration linuxConfiguration, - final WindowsConfiguration windowsConfiguration) { + final WindowsConfiguration windowsConfiguration, final List secrets) { return builder() .computerName(computerName) .adminUsername(adminUsername) @@ -211,6 +246,7 @@ public abstract class OSProfile { .customData(customData) .linuxConfiguration(linuxConfiguration) .windowsConfiguration(windowsConfiguration) + .secrets(secrets) .build(); } @@ -234,6 +270,8 @@ public abstract class OSProfile { public abstract Builder windowsConfiguration(WindowsConfiguration windowsConfiguration); + public abstract Builder secrets(List secrets); + public abstract OSProfile build(); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Secrets.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Secrets.java new file mode 100644 index 0000000000..5fcf7048a5 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Secrets.java @@ -0,0 +1,55 @@ +/* + * 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 org.jclouds.json.SerializedNames; +import java.util.List; + +/** + * Group of certificates stored in one and the same KeyVault + */ +@AutoValue +public abstract class Secrets { + + @AutoValue + public abstract static class SourceVault { + + public abstract String id(); + + @SerializedNames({"id"}) + public static SourceVault create(final String id) { + return new AutoValue_Secrets_SourceVault(id); + } + } + + /** + * Name of the KeyVault which contains all the certificates + */ + public abstract SourceVault sourceVault(); + + /** + * List of the certificates + */ + public abstract List vaultCertificates(); + + @SerializedNames({"sourceVault", "vaultCertificates"}) + public static Secrets create(final SourceVault sourceVault, final List vaultCertificates) { + return new AutoValue_Secrets(sourceVault, vaultCertificates); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VaultCertificate.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VaultCertificate.java new file mode 100644 index 0000000000..dd35eb6393 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VaultCertificate.java @@ -0,0 +1,46 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +/** + * Certificate stored in a Key Vault + */ +@AutoValue +public abstract class VaultCertificate { + + /** + * The URL of the certificate + */ + public abstract String certificateUrl(); + + /** + * Certificate's store name + */ + @Nullable + public abstract String certificateStore(); + + @SerializedNames({"certificateUrl", "certificateStore"}) + public static VaultCertificate create(final String certificateUrl, final String certificateStore) { + return new AutoValue_VaultCertificate(certificateUrl, certificateStore); + } +} 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 f3f6aacb1f..34b289e6c8 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 @@ -42,22 +42,28 @@ 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.ResourceDefinition; +import org.jclouds.azurecompute.arm.domain.Secrets; import org.jclouds.azurecompute.arm.domain.StorageAccountType; import org.jclouds.azurecompute.arm.domain.StorageProfile; import org.jclouds.azurecompute.arm.domain.StorageService; import org.jclouds.azurecompute.arm.domain.Subnet; import org.jclouds.azurecompute.arm.domain.VHD; +import org.jclouds.azurecompute.arm.domain.VaultCertificate; import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance; import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance.PowerState; import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties; import org.jclouds.azurecompute.arm.domain.NetworkProfile.NetworkInterface; import org.jclouds.azurecompute.arm.domain.NetworkProfile.NetworkInterface.NetworkInterfaceProperties; +import org.jclouds.azurecompute.arm.domain.OSProfile.WindowsConfiguration.WinRM.Protocol; +import org.jclouds.azurecompute.arm.domain.OSProfile.WindowsConfiguration.WinRM.ProtocolListener; import org.jclouds.azurecompute.arm.functions.ParseJobStatus; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import static org.testng.util.Strings.isNullOrEmpty; +import com.beust.jcommander.internal.Lists; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -79,6 +85,7 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { subscriptionid = getSubscriptionId(); createTestResourceGroup(); + 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 @@ -232,9 +239,9 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { private VirtualMachineProperties getProperties(String nic, String blob) { - HardwareProfile hwProf = HardwareProfile.create("Standard_D1"); - ImageReference imgRef = ImageReference.builder().publisher("MicrosoftWindowsServerEssentials") - .offer("WindowsServerEssentials").sku("WindowsServerEssentials").version("latest").build(); + HardwareProfile hwProf = HardwareProfile.create("Standard_D1_v2"); + ImageReference imgRef = ImageReference.builder().publisher("MicrosoftWindowsServer") + .offer("WindowsServer").sku("2008-R2-SP1").version("latest").build(); DataDisk.Builder dataDisk = DataDisk.builder().name("data").diskSizeGB("100").lun(0).createOption(DataDisk.DiskCreateOptionTypes.EMPTY); @@ -250,11 +257,25 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest { osDisk.vhd(VHD.create(blob + "vhds/" + vmName + ".vhd")); dataDisk.vhd(VHD.create(blob + "vhds/" + vmName + "data.vhd")); } - + StorageProfile storageProfile = StorageProfile.create(imgRef, osDisk.build(), ImmutableList.of(dataDisk.build())); - OSProfile.WindowsConfiguration windowsConfig = OSProfile.WindowsConfiguration.create(false, null, null, true, - null); - OSProfile osProfile = OSProfile.create(vmName, "azureuser", "RFe3&432dg", null, null, windowsConfig); + + List secrets = null; + OSProfile.WindowsConfiguration.WinRM winRm = null; + if (!isNullOrEmpty(vaultResourceGroup) && !isNullOrEmpty(vaultName) && !isNullOrEmpty(vaultCertificateUrl)) { + List listeners = Lists.newArrayList(); + + listeners.add(OSProfile.WindowsConfiguration.WinRM.ProtocolListener.create(Protocol.HTTPS, vaultCertificateUrl)); + listeners.add(OSProfile.WindowsConfiguration.WinRM.ProtocolListener.create(Protocol.HTTP, null)); + + winRm = OSProfile.WindowsConfiguration.WinRM.create(listeners); + VaultCertificate vaultCertificate = VaultCertificate.create(vaultCertificateUrl, vaultName); + secrets = ImmutableList.of(Secrets.create(Secrets.SourceVault.create(String.format("%s/providers/Microsoft.KeyVault/vaults/%s", + api.getResourceGroupApi().get(vaultResourceGroup).id(), vaultName)), + ImmutableList.of(vaultCertificate))); + } + OSProfile.WindowsConfiguration windowsConfig = OSProfile.WindowsConfiguration.create(true, winRm, null, true); + OSProfile osProfile = OSProfile.create(vmName, "azureuser", "RFe3&432dg", null, null, windowsConfig, secrets); NetworkInterface networkInterface = NetworkInterface.create("/subscriptions/" + subscriptionid + "/resourceGroups/" + resourceGroupName + "/providers/Microsoft.Network/networkInterfaces/" 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 95d967e3ac..83e5ef210d 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 @@ -32,15 +32,23 @@ 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.ManagedDiskParameters; import org.jclouds.azurecompute.arm.domain.NetworkProfile; import org.jclouds.azurecompute.arm.domain.NetworkProfile.NetworkInterface; import org.jclouds.azurecompute.arm.domain.OSDisk; import org.jclouds.azurecompute.arm.domain.OSProfile; +import org.jclouds.azurecompute.arm.domain.OSProfile.LinuxConfiguration; +import org.jclouds.azurecompute.arm.domain.OSProfile.WindowsConfiguration.AdditionalUnattendContent; +import org.jclouds.azurecompute.arm.domain.OSProfile.WindowsConfiguration.WinRM.Protocol; +import org.jclouds.azurecompute.arm.domain.Secrets.SourceVault; import org.jclouds.azurecompute.arm.domain.Plan; +import org.jclouds.azurecompute.arm.domain.Secrets; import org.jclouds.azurecompute.arm.domain.Status; import org.jclouds.azurecompute.arm.domain.StorageProfile; import org.jclouds.azurecompute.arm.domain.VHD; +import org.jclouds.azurecompute.arm.domain.VaultCertificate; import org.jclouds.azurecompute.arm.domain.VirtualMachine; import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance; import org.jclouds.azurecompute.arm.domain.VirtualMachineProperties; @@ -122,18 +130,30 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { "PUT", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + "/virtualMachines/windowsmachine?validating=false&api-version=2016-04-30-preview", - "{\"location\":\"westus\",\"tags\":{\"foo\":\"bar\"},\"properties\":" - + "{\"vmId\":\"27ee085b-d707-xxxx-yyyy-2370e2eb1cc1\"," + "{\"location\":\"westus\",\"properties\":" + + "{\"vmId\":\"27ee085b-d707-xxxx-yyyy-2370e2eb1cc1\",\"licenseType\":\"Windows_Server\"," + + "\"availabilitySet\":{\"id\":\"/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/availabilitySets/myAVSet\"}," + "\"hardwareProfile\":{\"vmSize\":\"Standard_D1\"}," - + "\"storageProfile\":{\"imageReference\":{\"publisher\":\"publisher\",\"offer\":\"offer\",\"sku\":\"sku\",\"version\":\"ver\"}," + + "\"storageProfile\":{\"imageReference\":{\"id\":\"/subscriptions/SUBSCRIPTIONID/providers/Microsoft.Compute/locations/westus/publishers/MicrosoftWindowsServerEssentials/artifactype/vmimage/offers/OFFER/skus/OFFER/versions/latest\"," + + "\"publisher\":\"publisher\",\"offer\":\"OFFER\",\"sku\":\"sku\",\"version\":\"ver\"}," + "\"osDisk\":{\"osType\":\"Windows\",\"name\":\"windowsmachine\"," - + "\"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}}," + + "\"vhd\":{\"uri\":\"https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd\"},\"caching\":\"ReadWrite\",\"createOption\":\"FromImage\"," + + "\"managedDisk\":{\"id\":\"/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk\",\"storageAccountType\":\"Standard_LRS\"}}," + + "\"dataDisks\":[{\"name\":\"mydatadisk1\",\"diskSizeGB\":\"1\",\"lun\":0,\"vhd\":{\"uri\":\"http://mystorage1.blob.core.windows.net/vhds/mydatadisk1.vhd\"},\"createOption\":\"Empty\",\"caching\":\"Unrecognized\"}]}," + + "\"osProfile\":{\"computerName\":\"windowsmachine\",\"adminUsername\":\"azureuser\",\"adminPassword\":\"password\",\"customData\":\"\",\"windowsConfiguration\":{\"provisionVMAgent\":false," + + "\"winRM\":{\"listeners\":[{\"protocol\":\"https\",\"certificateUrl\":\"url-to-certificate\"}]},\"additionalUnattendContent\":[{\"pass\":\"oobesystem\",\"component\":\"Microsoft-Windows-Shell-Setup\",\"settingName\":\"FirstLogonCommands\",\"content\":\"\"}]," + + "\"enableAutomaticUpdates\":true}," + + "\"secrets\":[{\"sourceVault\":{\"id\":\"/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup1/providers/Microsoft.KeyVault/vaults/myvault1\"},\"vaultCertificates\":[{\"certificateUrl\":\"https://myvault1.vault.azure.net/secrets/SECRETNAME/SECRETVERSION\",\"certificateStore\":\"CERTIFICATESTORENAME\"}]}]}," + "\"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\"}," + + "\"tags\":{\"foo\":\"bar\"}," + "\"plan\":{\"name\":\"deadline-slave-7-2\",\"publisher\":\"thinkboxsoftware\",\"product\":\"deadline7-2\"}}"); } - + + // See https://docs.microsoft.com/en-us/rest/api/compute/virtualmachines/virtualmachines-create-or-update + // for where part of the example json response comes from. Unfortunately examples in the microsoft docs + // are not valid json (e.g. missing commas, illegal quotes). Therefore this example merges the original + // real-world example (presumably taken from the jclouds wire log), and snippets from the microsoft docs. public void testCreate() throws Exception { server.enqueue(jsonResponse("/createvirtualmachineresponse.json")); @@ -145,15 +165,23 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { "PUT", "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute" + "/virtualMachines/windowsmachine?validating=false&api-version=2016-04-30-preview", - "{\"location\":\"westus\",\"tags\":{\"foo\":\"bar\"},\"properties\":" - + "{\"vmId\":\"27ee085b-d707-xxxx-yyyy-2370e2eb1cc1\"," + "{\"location\":\"westus\",\"properties\":" + + "{\"vmId\":\"27ee085b-d707-xxxx-yyyy-2370e2eb1cc1\",\"licenseType\":\"Windows_Server\"," + + "\"availabilitySet\":{\"id\":\"/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/availabilitySets/myAVSet\"}," + "\"hardwareProfile\":{\"vmSize\":\"Standard_D1\"}," - + "\"storageProfile\":{\"imageReference\":{\"publisher\":\"publisher\",\"offer\":\"offer\",\"sku\":\"sku\",\"version\":\"ver\"}," + + "\"storageProfile\":{\"imageReference\":{\"id\":\"/subscriptions/SUBSCRIPTIONID/providers/Microsoft.Compute/locations/westus/publishers/MicrosoftWindowsServerEssentials/artifactype/vmimage/offers/OFFER/skus/OFFER/versions/latest\"," + + "\"publisher\":\"publisher\",\"offer\":\"OFFER\",\"sku\":\"sku\",\"version\":\"ver\"}," + "\"osDisk\":{\"osType\":\"Windows\",\"name\":\"windowsmachine\"," - + "\"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}}," + + "\"vhd\":{\"uri\":\"https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd\"},\"caching\":\"ReadWrite\",\"createOption\":\"FromImage\"," + + "\"managedDisk\":{\"id\":\"/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk\",\"storageAccountType\":\"Standard_LRS\"}}," + + "\"dataDisks\":[{\"name\":\"mydatadisk1\",\"diskSizeGB\":\"1\",\"lun\":0,\"vhd\":{\"uri\":\"http://mystorage1.blob.core.windows.net/vhds/mydatadisk1.vhd\"},\"createOption\":\"Empty\",\"caching\":\"Unrecognized\"}]}," + + "\"osProfile\":{\"computerName\":\"windowsmachine\",\"adminUsername\":\"azureuser\",\"adminPassword\":\"password\",\"customData\":\"\",\"windowsConfiguration\":{\"provisionVMAgent\":false," + + "\"winRM\":{\"listeners\":[{\"protocol\":\"https\",\"certificateUrl\":\"url-to-certificate\"}]},\"additionalUnattendContent\":[{\"pass\":\"oobesystem\",\"component\":\"Microsoft-Windows-Shell-Setup\",\"settingName\":\"FirstLogonCommands\",\"content\":\"\"}]," + + "\"enableAutomaticUpdates\":true}," + + "\"secrets\":[{\"sourceVault\":{\"id\":\"/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup1/providers/Microsoft.KeyVault/vaults/myvault1\"},\"vaultCertificates\":[{\"certificateUrl\":\"https://myvault1.vault.azure.net/secrets/SECRETNAME/SECRETVERSION\",\"certificateStore\":\"CERTIFICATESTORENAME\"}]}]}," + "\"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\"}," + + "\"tags\":{\"foo\":\"bar\"}}"); } public void testDeleteReturns404() throws Exception { @@ -248,15 +276,31 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { } private VirtualMachineProperties getProperties() { + String licenseType = "Windows_Server"; + IdReference availabilitySet = IdReference.create("/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/availabilitySets/myAVSet"); HardwareProfile hwProf = HardwareProfile.create("Standard_D1"); - ImageReference imgRef = ImageReference.builder().publisher("publisher").offer("offer").sku("sku").version("ver").build(); + ImageReference imgRef = ImageReference.builder().publisher("publisher").offer("OFFER").sku("sku").version("ver") + .customImageId("/subscriptions/SUBSCRIPTIONID/providers/Microsoft.Compute/locations/westus/publishers/MicrosoftWindowsServerEssentials/artifactype/vmimage/offers/OFFER/skus/OFFER/versions/latest") + .build(); VHD vhd = VHD.create("https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd"); - List dataDisks = new ArrayList(); - OSDisk osDisk = OSDisk.create("Windows", "windowsmachine", vhd, "ReadWrite", "FromImage", null, null, null); + List dataDisks = ImmutableList.of( + DataDisk.create("mydatadisk1", "1", 0, VHD.create("http://mystorage1.blob.core.windows.net/vhds/mydatadisk1.vhd"), + null, "Empty", null, null, null)); + ManagedDiskParameters managedDiskParameters = ManagedDiskParameters.create("/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk", + "Standard_LRS"); + OSDisk osDisk = OSDisk.create("Windows", "windowsmachine", vhd, "ReadWrite", "FromImage", null, managedDiskParameters, null); StorageProfile storageProfile = StorageProfile.create(imgRef, osDisk, dataDisks); - OSProfile.WindowsConfiguration windowsConfig = OSProfile.WindowsConfiguration.create(false, null, null, true, - null); - OSProfile osProfile = OSProfile.create("windowsmachine", "azureuser", null, null, null, windowsConfig); + LinuxConfiguration linuxConfig = null; + OSProfile.WindowsConfiguration.WinRM winrm = OSProfile.WindowsConfiguration.WinRM.create( + ImmutableList.of( + OSProfile.WindowsConfiguration.WinRM.ProtocolListener.create(Protocol.HTTPS, "url-to-certificate"))); + List additionalUnattendContent = ImmutableList.of( + AdditionalUnattendContent.create("oobesystem", "Microsoft-Windows-Shell-Setup", "FirstLogonCommands", "")); + OSProfile.WindowsConfiguration windowsConfig = OSProfile.WindowsConfiguration.create(false, winrm, additionalUnattendContent, true); + List secrets = ImmutableList.of( + Secrets.create(SourceVault.create("/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup1/providers/Microsoft.KeyVault/vaults/myvault1"), + ImmutableList.of(VaultCertificate.create("https://myvault1.vault.azure.net/secrets/SECRETNAME/SECRETVERSION", "CERTIFICATESTORENAME")))); + OSProfile osProfile = OSProfile.create("windowsmachine", "azureuser", "password", "", linuxConfig, windowsConfig, secrets); NetworkInterface networkInterface = NetworkInterface.create("/subscriptions/SUBSCRIPTIONID" + "/resourceGroups/groupname/providers/Microsoft.Network/networkInterfaces/" + "windowsmachine167", null); List networkInterfaces = new ArrayList(); @@ -266,7 +310,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, + licenseType, availabilitySet, hwProf, storageProfile, osProfile, networkProfile, diagnosticsProfile, VirtualMachineProperties.ProvisioningState.CREATING); return properties; } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java index 10406b8679..90502fe8e0 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java @@ -41,6 +41,7 @@ import org.jclouds.azurecompute.arm.domain.ResourceGroup; import org.jclouds.azurecompute.arm.domain.Subnet; import org.jclouds.azurecompute.arm.domain.VirtualNetwork; import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; import com.google.common.base.Predicate; import com.google.common.base.Supplier; @@ -66,6 +67,10 @@ public class BaseAzureComputeApiLiveTest extends BaseApiLiveTest modules) { Injector injector = newBuilder().modules(modules).overrides(props).buildInjector(); imageAvailablePredicate = injector.getInstance(Key.get(new TypeLiteral>() { diff --git a/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json b/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json index 2963100b0a..bc8ca2d11b 100644 --- a/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json +++ b/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json @@ -1,37 +1,92 @@ { "properties": { "vmId": "27ee085b-d707-xxxx-yyyy-2370e2eb1cc1", + "licenseType": "Windows_Server", + "availabilitySet": { + "id":"/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/availabilitySets/myAVSet" + }, "hardwareProfile": { "vmSize": "Standard_D1" }, "storageProfile": { "imageReference": { "publisher": "publisher", - "offer": "offer", + "offer": "OFFER", "sku": "sku", - "version": "ver" + "version": "ver", + "id": "/subscriptions/SUBSCRIPTIONID/providers/Microsoft.Compute/locations/westus/publishers/MicrosoftWindowsServerEssentials/artifactype/vmimage/offers/OFFER/skus/OFFER/versions/latest" }, "osDisk": { "osType": "Windows", "name": "windowsmachine", "createOption": "FromImage", + "managedDisk": { + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk", + "storageAccountType": "Standard_LRS" + }, "vhd": { "uri": "https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd" }, "caching": "ReadWrite" }, - "dataDisks": [] + "dataDisks":[ + { + "name":"mydatadisk1", + "diskSizeGB":"1", + "lun": 0, + "vhd": { + "uri" : "http://mystorage1.blob.core.windows.net/vhds/mydatadisk1.vhd" + }, + "createOption":"Empty" + } + ] }, "osProfile": { "computerName": "windowsmachine", "adminUsername": "azureuser", + "adminPassword": "password", + "customData": "", "windowsConfiguration": { "provisionVMAgent": false, - "enableAutomaticUpdates": true + "enableAutomaticUpdates": true, + "winRM": { + "listeners": [ + { + "protocol": "https", + "certificateUrl": "url-to-certificate" + } + ] + }, + "additionalUnattendContent": [ + { + "pass":"oobesystem", + "component":"Microsoft-Windows-Shell-Setup", + "settingName":"FirstLogonCommands", + "content":"" + } + ] }, - "secrets": [] + "secrets":[ + { + "sourceVault": { + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup1/providers/Microsoft.KeyVault/vaults/myvault1" + }, + "vaultCertificates": [ + { + "certificateUrl": "https://myvault1.vault.azure.net/secrets/SECRETNAME/SECRETVERSION", + "certificateStore": "CERTIFICATESTORENAME" + } + ] + } + ] + }, + "networkProfile": { + "networkInterfaces":[ + { + "id":"/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Network/networkInterfaces/windowsmachine167" + } + ] }, - "networkProfile": {"networkInterfaces":[{"id":"/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Network/networkInterfaces/windowsmachine167"}]}, "diagnosticsProfile": { "bootDiagnostics": { "enabled": true, @@ -52,4 +107,4 @@ "publisher": "thinkboxsoftware", "product": "deadline7-2" } -} \ No newline at end of file +} diff --git a/providers/azurecompute-arm/src/test/resources/virtualmachine.json b/providers/azurecompute-arm/src/test/resources/virtualmachine.json index 874227d00b..70e7f4a3bd 100644 --- a/providers/azurecompute-arm/src/test/resources/virtualmachine.json +++ b/providers/azurecompute-arm/src/test/resources/virtualmachine.json @@ -1,37 +1,90 @@ { "properties": { "vmId": "27ee085b-d707-xxxx-yyyy-2370e2eb1cc1", + "licenseType": "Windows_Server", + "availabilitySet":{ + "id":"/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/availabilitySets/myAVSet" + }, "hardwareProfile": { "vmSize": "Standard_D1" }, "storageProfile": { "imageReference": { "publisher": "publisher", - "offer": "offer", + "offer": "OFFER", "sku": "sku", - "version": "ver" + "version": "ver", + "id": "/subscriptions/SUBSCRIPTIONID/providers/Microsoft.Compute/locations/westus/publishers/MicrosoftWindowsServerEssentials/artifactype/vmimage/offers/OFFER/skus/OFFER/versions/latest" }, "osDisk": { "osType": "Windows", "name": "windowsmachine", "createOption": "FromImage", + "managedDisk": { + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk", + "storageAccountType": "Standard_LRS" + }, "vhd": { "uri": "https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd" }, "caching": "ReadWrite" }, - "dataDisks": [] + "dataDisks":[ + { + "name":"mydatadisk1", + "diskSizeGB":"1", + "lun": 0, + "vhd": { + "uri" : "http://mystorage1.blob.core.windows.net/vhds/mydatadisk1.vhd" + }, + "createOption":"Empty" + } + ] }, "osProfile": { "computerName": "windowsmachine", "adminUsername": "azureuser", + "adminPassword":"password", + "customData":"", "windowsConfiguration": { "provisionVMAgent": false, - "enableAutomaticUpdates": true + "enableAutomaticUpdates": true, + "winRM": { + "listeners":[{ + "protocol": "https", + "certificateUrl": "url-to-certificate" + }] + }, + "additionalUnattendContent":[ + { + "pass":"oobesystem", + "component":"Microsoft-Windows-Shell-Setup", + "settingName":"FirstLogonCommands", + "content":"" + } + ] }, - "secrets": [] + "secrets":[ + { + "sourceVault": { + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup1/providers/Microsoft.KeyVault/vaults/myvault1" + }, + "vaultCertificates": [ + { + "certificateUrl": "https://myvault1.vault.azure.net/secrets/SECRETNAME/SECRETVERSION", + "certificateStore": "CERTIFICATESTORENAME" + } + ] + } + ] + }, + "networkProfile": { + "networkInterfaces":[ + { + "id":"/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Network/networkInterfaces/windowsmachine167" + } + ] }, - "networkProfile": {"networkInterfaces":[{"id":"/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Network/networkInterfaces/windowsmachine167"}]}, "diagnosticsProfile": { "bootDiagnostics": { "enabled": true, diff --git a/providers/azurecompute-arm/src/test/resources/virtualmachines.json b/providers/azurecompute-arm/src/test/resources/virtualmachines.json index cd0e24b5ec..758a109ec0 100644 --- a/providers/azurecompute-arm/src/test/resources/virtualmachines.json +++ b/providers/azurecompute-arm/src/test/resources/virtualmachines.json @@ -3,35 +3,82 @@ { "properties": { "vmId": "27ee085b-d707-xxxx-yyyy-2370e2eb1cc1", + "licenseType": "Windows_Server", + "availabilitySet":{ + "id":"/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/availabilitySets/myAVSet" + }, "hardwareProfile": { "vmSize": "Standard_D1" }, "storageProfile": { "imageReference": { "publisher": "publisher", - "offer": "offer", + "offer": "OFFER", "sku": "sku", - "version": "ver" + "version": "ver", + "id": "/subscriptions/SUBSCRIPTIONID/providers/Microsoft.Compute/locations/westus/publishers/MicrosoftWindowsServerEssentials/artifactype/vmimage/offers/OFFER/skus/OFFER/versions/latest" }, "osDisk": { "osType": "Windows", "name": "windowsmachine", "createOption": "FromImage", + "managedDisk": { + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk", + "storageAccountType": "Standard_LRS" + }, "vhd": { "uri": "https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd" }, "caching": "ReadWrite" }, - "dataDisks": [] + "dataDisks":[ + { + "name":"mydatadisk1", + "diskSizeGB":"1", + "lun": 0, + "vhd": { + "uri" : "http://mystorage1.blob.core.windows.net/vhds/mydatadisk1.vhd" + }, + "createOption":"Empty" + } + ] }, "osProfile": { "computerName": "windowsmachine", "adminUsername": "azureuser", + "adminPassword":"password", + "customData":"", "windowsConfiguration": { "provisionVMAgent": false, - "enableAutomaticUpdates": true + "enableAutomaticUpdates": true, + "winRM": { + "listeners":[{ + "protocol": "https", + "certificateUrl": "url-to-certificate" + }] + }, + "additionalUnattendContent":[ + { + "pass":"oobesystem", + "component":"Microsoft-Windows-Shell-Setup", + "settingName":"FirstLogonCommands", + "content":"" + } + ] }, - "secrets": [] + "secrets":[ + { + "sourceVault": { + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup1/providers/Microsoft.KeyVault/vaults/myvault1" + }, + "vaultCertificates": [ + { + "certificateUrl": "https://myvault1.vault.azure.net/secrets/SECRETNAME/SECRETVERSION", + "certificateStore": "CERTIFICATESTORENAME" + } + ] + } + ] }, "networkProfile": { "networkInterfaces": [ From 9718bec43916b45b8f4a53042fd04be6dee60214 Mon Sep 17 00:00:00 2001 From: Valentin Aitken Date: Fri, 26 May 2017 17:56:41 +0300 Subject: [PATCH 65/87] Azurecompute ARM - proper tests for disks - Fix DataDisk.CachingTypes.fromValue to recognize values properly - Fix tests which had blob disks and managed disks at the same time - At this point managed disks are used by default and should be tested. --- .../azurecompute/arm/domain/DataDisk.java | 15 ++- .../features/VirtualMachineApiMockTest.java | 75 +++++++++--- .../createvirtualmachineresponse.json | 9 +- .../src/test/resources/image.json | 4 +- .../src/test/resources/virtualmachine.json | 12 +- .../src/test/resources/virtualmachines.json | 113 ++++++++++++++++-- 6 files changed, 188 insertions(+), 40 deletions(-) diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DataDisk.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DataDisk.java index 40189c3e65..2d615098af 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DataDisk.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/DataDisk.java @@ -49,7 +49,12 @@ public abstract class DataDisk implements Provisionable { UNRECOGNIZED; public static CachingTypes fromValue(final String text) { - return (CachingTypes) GetEnumValue.fromValueOrDefault(text, UNRECOGNIZED); + for (CachingTypes type : CachingTypes.values()) { + if (type.toString().equals(text)) { + return type; + } + } + return UNRECOGNIZED; } @Override @@ -108,13 +113,15 @@ public abstract class DataDisk implements Provisionable { public static DataDisk create(final String name, final String diskSizeGB, final Integer lun, final VHD vhd, final VHD image, final String createOption, final String caching, final ManagedDiskParameters managedDiskParamenters, final String provisioningState) { - return builder() - .name(name) + final Builder builder = builder(); + if (caching != null) { + builder.caching(CachingTypes.fromValue(caching)); + } + return builder.name(name) .diskSizeGB(diskSizeGB) .lun(lun) .vhd(vhd) .image(image) - .caching(CachingTypes.fromValue(caching)) .createOption(DiskCreateOptionTypes.fromValue(createOption)) .managedDiskParameters(managedDiskParamenters) .provisioningState(provisioningState) 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 83e5ef210d..258ae1a6f1 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 @@ -42,9 +42,9 @@ import org.jclouds.azurecompute.arm.domain.OSProfile; import org.jclouds.azurecompute.arm.domain.OSProfile.LinuxConfiguration; import org.jclouds.azurecompute.arm.domain.OSProfile.WindowsConfiguration.AdditionalUnattendContent; import org.jclouds.azurecompute.arm.domain.OSProfile.WindowsConfiguration.WinRM.Protocol; -import org.jclouds.azurecompute.arm.domain.Secrets.SourceVault; import org.jclouds.azurecompute.arm.domain.Plan; import org.jclouds.azurecompute.arm.domain.Secrets; +import org.jclouds.azurecompute.arm.domain.Secrets.SourceVault; import org.jclouds.azurecompute.arm.domain.Status; import org.jclouds.azurecompute.arm.domain.StorageProfile; import org.jclouds.azurecompute.arm.domain.VHD; @@ -123,7 +123,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { Plan plan = Plan.create("thinkboxsoftware", "deadline-slave-7-2", "deadline7-2"); final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); VirtualMachine vm = vmAPI - .createOrUpdate("windowsmachine", "westus", getProperties(), ImmutableMap.of("foo", "bar"), plan); + .createOrUpdate("windowsmachine", "westus", getVMWithManagedDisksProperties(), ImmutableMap.of("foo", "bar"), plan); assertEquals(vm, getVM(plan)); assertSent( server, @@ -137,9 +137,9 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { + "\"storageProfile\":{\"imageReference\":{\"id\":\"/subscriptions/SUBSCRIPTIONID/providers/Microsoft.Compute/locations/westus/publishers/MicrosoftWindowsServerEssentials/artifactype/vmimage/offers/OFFER/skus/OFFER/versions/latest\"," + "\"publisher\":\"publisher\",\"offer\":\"OFFER\",\"sku\":\"sku\",\"version\":\"ver\"}," + "\"osDisk\":{\"osType\":\"Windows\",\"name\":\"windowsmachine\"," - + "\"vhd\":{\"uri\":\"https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd\"},\"caching\":\"ReadWrite\",\"createOption\":\"FromImage\"," + + "\"caching\":\"ReadWrite\",\"createOption\":\"FromImage\"," + "\"managedDisk\":{\"id\":\"/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk\",\"storageAccountType\":\"Standard_LRS\"}}," - + "\"dataDisks\":[{\"name\":\"mydatadisk1\",\"diskSizeGB\":\"1\",\"lun\":0,\"vhd\":{\"uri\":\"http://mystorage1.blob.core.windows.net/vhds/mydatadisk1.vhd\"},\"createOption\":\"Empty\",\"caching\":\"Unrecognized\"}]}," + + "\"dataDisks\":[{\"name\":\"mydatadisk1\",\"diskSizeGB\":\"1\",\"lun\":0,\"createOption\":\"Empty\",\"caching\":\"ReadWrite\",\"managedDisk\":{\"id\":\"/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk\",\"storageAccountType\":\"Standard_LRS\"}}]}," + "\"osProfile\":{\"computerName\":\"windowsmachine\",\"adminUsername\":\"azureuser\",\"adminPassword\":\"password\",\"customData\":\"\",\"windowsConfiguration\":{\"provisionVMAgent\":false," + "\"winRM\":{\"listeners\":[{\"protocol\":\"https\",\"certificateUrl\":\"url-to-certificate\"}]},\"additionalUnattendContent\":[{\"pass\":\"oobesystem\",\"component\":\"Microsoft-Windows-Shell-Setup\",\"settingName\":\"FirstLogonCommands\",\"content\":\"\"}]," + "\"enableAutomaticUpdates\":true}," @@ -158,7 +158,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { server.enqueue(jsonResponse("/createvirtualmachineresponse.json")); final VirtualMachineApi vmAPI = api.getVirtualMachineApi("groupname"); - VirtualMachine vm = vmAPI.createOrUpdate("windowsmachine", "westus", getProperties(), ImmutableMap.of("foo", "bar"), null); + VirtualMachine vm = vmAPI.createOrUpdate("windowsmachine", "westus", getVMWithManagedDisksProperties(), ImmutableMap.of("foo", "bar"), null); assertEquals(vm, getVM()); assertSent( server, @@ -172,9 +172,9 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { + "\"storageProfile\":{\"imageReference\":{\"id\":\"/subscriptions/SUBSCRIPTIONID/providers/Microsoft.Compute/locations/westus/publishers/MicrosoftWindowsServerEssentials/artifactype/vmimage/offers/OFFER/skus/OFFER/versions/latest\"," + "\"publisher\":\"publisher\",\"offer\":\"OFFER\",\"sku\":\"sku\",\"version\":\"ver\"}," + "\"osDisk\":{\"osType\":\"Windows\",\"name\":\"windowsmachine\"," - + "\"vhd\":{\"uri\":\"https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd\"},\"caching\":\"ReadWrite\",\"createOption\":\"FromImage\"," + + "\"caching\":\"ReadWrite\",\"createOption\":\"FromImage\"," + "\"managedDisk\":{\"id\":\"/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk\",\"storageAccountType\":\"Standard_LRS\"}}," - + "\"dataDisks\":[{\"name\":\"mydatadisk1\",\"diskSizeGB\":\"1\",\"lun\":0,\"vhd\":{\"uri\":\"http://mystorage1.blob.core.windows.net/vhds/mydatadisk1.vhd\"},\"createOption\":\"Empty\",\"caching\":\"Unrecognized\"}]}," + + "\"dataDisks\":[{\"name\":\"mydatadisk1\",\"diskSizeGB\":\"1\",\"lun\":0,\"createOption\":\"Empty\",\"caching\":\"ReadWrite\",\"managedDisk\":{\"id\":\"/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk\",\"storageAccountType\":\"Standard_LRS\"}}]}," + "\"osProfile\":{\"computerName\":\"windowsmachine\",\"adminUsername\":\"azureuser\",\"adminPassword\":\"password\",\"customData\":\"\",\"windowsConfiguration\":{\"provisionVMAgent\":false," + "\"winRM\":{\"listeners\":[{\"protocol\":\"https\",\"certificateUrl\":\"url-to-certificate\"}]},\"additionalUnattendContent\":[{\"pass\":\"oobesystem\",\"component\":\"Microsoft-Windows-Shell-Setup\",\"settingName\":\"FirstLogonCommands\",\"content\":\"\"}]," + "\"enableAutomaticUpdates\":true}," @@ -275,7 +275,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { "{\"vhdPrefix\":\"prefix\",\"destinationContainerName\":\"container\",\"overwriteVhds\":\"true\"}"); } - private VirtualMachineProperties getProperties() { + private VirtualMachineProperties getVMWithBlobDisksProperties() { String licenseType = "Windows_Server"; IdReference availabilitySet = IdReference.create("/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/availabilitySets/myAVSet"); HardwareProfile hwProf = HardwareProfile.create("Standard_D1"); @@ -284,7 +284,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { .build(); VHD vhd = VHD.create("https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd"); List dataDisks = ImmutableList.of( - DataDisk.create("mydatadisk1", "1", 0, VHD.create("http://mystorage1.blob.core.windows.net/vhds/mydatadisk1.vhd"), + DataDisk.create("mydatadisk1", "1", 0, VHD.create("http://mystorage1.blob.core.windows.net/vhds/mydatadisk1.vhd"), null, "Empty", null, null, null)); ManagedDiskParameters managedDiskParameters = ManagedDiskParameters.create("/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk", "Standard_LRS"); @@ -297,6 +297,44 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { List additionalUnattendContent = ImmutableList.of( AdditionalUnattendContent.create("oobesystem", "Microsoft-Windows-Shell-Setup", "FirstLogonCommands", "")); OSProfile.WindowsConfiguration windowsConfig = OSProfile.WindowsConfiguration.create(false, winrm, additionalUnattendContent, true); + List secrets = ImmutableList.of( + Secrets.create(SourceVault.create("/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup1/providers/Microsoft.KeyVault/vaults/myvault1"), + ImmutableList.of(VaultCertificate.create("https://myvault1.vault.azure.net/secrets/SECRETNAME/SECRETVERSION", "CERTIFICATESTORENAME")))); + OSProfile osProfile = OSProfile.create("windowsmachine", "azureuser", "password", "", linuxConfig, windowsConfig, secrets); + NetworkInterface networkInterface = NetworkInterface.create("/subscriptions/SUBSCRIPTIONID" + + "/resourceGroups/groupname/providers/Microsoft.Network/networkInterfaces/" + "windowsmachine167", null); + List networkInterfaces = new ArrayList(); + networkInterfaces.add(networkInterface); + NetworkProfile networkProfile = NetworkProfile.create(networkInterfaces); + DiagnosticsProfile.BootDiagnostics bootDiagnostics = DiagnosticsProfile.BootDiagnostics.create(true, + "https://groupname2760.blob.core.windows.net/"); + DiagnosticsProfile diagnosticsProfile = DiagnosticsProfile.create(bootDiagnostics); + VirtualMachineProperties properties = VirtualMachineProperties.create("27ee085b-d707-xxxx-yyyy-2370e2eb1cc1", + licenseType, availabilitySet, hwProf, storageProfile, osProfile, networkProfile, diagnosticsProfile, + VirtualMachineProperties.ProvisioningState.CREATING); + return properties; + } + + private VirtualMachineProperties getVMWithManagedDisksProperties() { + String licenseType = "Windows_Server"; + IdReference availabilitySet = IdReference.create("/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/availabilitySets/myAVSet"); + HardwareProfile hwProf = HardwareProfile.create("Standard_D1"); + ImageReference imgRef = ImageReference.builder().publisher("publisher").offer("OFFER").sku("sku").version("ver") + .customImageId("/subscriptions/SUBSCRIPTIONID/providers/Microsoft.Compute/locations/westus/publishers/MicrosoftWindowsServerEssentials/artifactype/vmimage/offers/OFFER/skus/OFFER/versions/latest") + .build(); + ManagedDiskParameters managedDiskParameters = ManagedDiskParameters.create("/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk", + "Standard_LRS"); + List dataDisks = ImmutableList.of( + DataDisk.builder().name("mydatadisk1").diskSizeGB("1").lun(0).managedDiskParameters(managedDiskParameters).createOption(DataDisk.DiskCreateOptionTypes.EMPTY).caching(DataDisk.CachingTypes.READ_WRITE).build()); + OSDisk osDisk = OSDisk.builder().osType("Windows").name("windowsmachine").caching("ReadWrite").createOption("FromImage").managedDiskParameters(managedDiskParameters).build(); + StorageProfile storageProfile = StorageProfile.create(imgRef, osDisk, dataDisks); + LinuxConfiguration linuxConfig = null; + OSProfile.WindowsConfiguration.WinRM winrm = OSProfile.WindowsConfiguration.WinRM.create( + ImmutableList.of( + OSProfile.WindowsConfiguration.WinRM.ProtocolListener.create(Protocol.HTTPS, "url-to-certificate"))); + List additionalUnattendContent = ImmutableList.of( + AdditionalUnattendContent.create("oobesystem", "Microsoft-Windows-Shell-Setup", "FirstLogonCommands", "")); + OSProfile.WindowsConfiguration windowsConfig = OSProfile.WindowsConfiguration.create(false, winrm, additionalUnattendContent, true); List secrets = ImmutableList.of( Secrets.create(SourceVault.create("/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup1/providers/Microsoft.KeyVault/vaults/myvault1"), ImmutableList.of(VaultCertificate.create("https://myvault1.vault.azure.net/secrets/SECRETNAME/SECRETVERSION", "CERTIFICATESTORENAME")))); @@ -316,7 +354,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { } private VirtualMachine getVM() { - VirtualMachineProperties properties = getProperties(); + VirtualMachineProperties properties = getVMWithManagedDisksProperties(); VirtualMachine machine = VirtualMachine.create("/subscriptions/SUBSCRIPTIONID/" + "" + "resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", "windowsmachine", "Microsoft.Compute/virtualMachines", "westus", ImmutableMap.of("foo", "bar"), properties, @@ -325,7 +363,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { } private VirtualMachine getVM(Plan plan) { - VirtualMachineProperties properties = getProperties(); + VirtualMachineProperties properties = getVMWithManagedDisksProperties(); VirtualMachine machine = VirtualMachine.create("/subscriptions/SUBSCRIPTIONID/" + "" + "resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", "windowsmachine", "Microsoft.Compute/virtualMachines", "westus", ImmutableMap.of("foo", "bar"), properties, plan); @@ -355,12 +393,17 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { } private List getVMList() { - VirtualMachineProperties properties = getProperties(); - VirtualMachine machine = VirtualMachine.create("/subscriptions/SUBSCRIPTIONID/" + "" - + "resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", "windowsmachine", - "Microsoft.Compute/virtualMachines", "westus", null, properties, null); List list = new ArrayList(); - list.add(machine); + VirtualMachineProperties propertiesWithManagedDisks = getVMWithManagedDisksProperties(); + VirtualMachine machineWithManagedDisks = VirtualMachine.create("/subscriptions/SUBSCRIPTIONID/" + "" + + "resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", "windowsmachine", + "Microsoft.Compute/virtualMachines", "westus", null, propertiesWithManagedDisks, null); + list.add(machineWithManagedDisks); + VirtualMachineProperties propertiesWithBlobDisks = getVMWithBlobDisksProperties(); + VirtualMachine machineWithBlobDisks = VirtualMachine.create("/subscriptions/SUBSCRIPTIONID/" + "" + + "resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", "windowsmachine", + "Microsoft.Compute/virtualMachines", "westus", null, propertiesWithBlobDisks, null); + list.add(machineWithBlobDisks); return list; } } diff --git a/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json b/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json index bc8ca2d11b..4279f83e66 100644 --- a/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json +++ b/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json @@ -24,9 +24,6 @@ "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk", "storageAccountType": "Standard_LRS" }, - "vhd": { - "uri": "https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd" - }, "caching": "ReadWrite" }, "dataDisks":[ @@ -34,9 +31,11 @@ "name":"mydatadisk1", "diskSizeGB":"1", "lun": 0, - "vhd": { - "uri" : "http://mystorage1.blob.core.windows.net/vhds/mydatadisk1.vhd" + "managedDisk": { + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk", + "storageAccountType": "Standard_LRS" }, + "caching": "ReadWrite", "createOption":"Empty" } ] diff --git a/providers/azurecompute-arm/src/test/resources/image.json b/providers/azurecompute-arm/src/test/resources/image.json index 3dbdf119de..0c7b54ca94 100644 --- a/providers/azurecompute-arm/src/test/resources/image.json +++ b/providers/azurecompute-arm/src/test/resources/image.json @@ -18,7 +18,7 @@ "id": "subscriptions/{subscriptionId}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myManagedDisk1" }, "osState": "generalized", - "hostCaching": "readwrite", + "hostCaching": "ReadWrite", "storageAccountType": "Standard_LRS", "diskSizeGB": 20 }, @@ -32,7 +32,7 @@ "managedDisk": { "id": "subscriptions/{subscriptionId}/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myManagedDisk2" }, - "hostCaching": "readwrite", + "hostCaching": "ReadWrite", "storageAccountType": "Standard_LRS", "diskSizeInGB": 20 } diff --git a/providers/azurecompute-arm/src/test/resources/virtualmachine.json b/providers/azurecompute-arm/src/test/resources/virtualmachine.json index 70e7f4a3bd..51ad1fb080 100644 --- a/providers/azurecompute-arm/src/test/resources/virtualmachine.json +++ b/providers/azurecompute-arm/src/test/resources/virtualmachine.json @@ -24,9 +24,6 @@ "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk", "storageAccountType": "Standard_LRS" }, - "vhd": { - "uri": "https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd" - }, "caching": "ReadWrite" }, "dataDisks":[ @@ -34,10 +31,13 @@ "name":"mydatadisk1", "diskSizeGB":"1", "lun": 0, - "vhd": { - "uri" : "http://mystorage1.blob.core.windows.net/vhds/mydatadisk1.vhd" + "createOption":"Empty", + "managedDisk": { + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk", + "storageAccountType": "Standard_LRS" }, - "createOption":"Empty" + "createOption":"Empty", + "caching": "ReadWrite" } ] }, diff --git a/providers/azurecompute-arm/src/test/resources/virtualmachines.json b/providers/azurecompute-arm/src/test/resources/virtualmachines.json index 758a109ec0..27ee602180 100644 --- a/providers/azurecompute-arm/src/test/resources/virtualmachines.json +++ b/providers/azurecompute-arm/src/test/resources/virtualmachines.json @@ -26,9 +26,6 @@ "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk", "storageAccountType": "Standard_LRS" }, - "vhd": { - "uri": "https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd" - }, "caching": "ReadWrite" }, "dataDisks":[ @@ -36,10 +33,12 @@ "name":"mydatadisk1", "diskSizeGB":"1", "lun": 0, - "vhd": { - "uri" : "http://mystorage1.blob.core.windows.net/vhds/mydatadisk1.vhd" - }, - "createOption":"Empty" + "createOption":"Empty", + "caching":"ReadWrite", + "managedDisk": { + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk", + "storageAccountType": "Standard_LRS" + } } ] }, @@ -99,6 +98,106 @@ "name": "windowsmachine", "type": "Microsoft.Compute/virtualMachines", "location": "westus" + }, + { + "properties": { + "vmId": "27ee085b-d707-xxxx-yyyy-2370e2eb1cc1", + "licenseType": "Windows_Server", + "availabilitySet":{ + "id":"/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/availabilitySets/myAVSet" + }, + "hardwareProfile": { + "vmSize": "Standard_D1" + }, + "storageProfile": { + "imageReference": { + "publisher": "publisher", + "offer": "OFFER", + "sku": "sku", + "version": "ver", + "id": "/subscriptions/SUBSCRIPTIONID/providers/Microsoft.Compute/locations/westus/publishers/MicrosoftWindowsServerEssentials/artifactype/vmimage/offers/OFFER/skus/OFFER/versions/latest" + }, + "osDisk": { + "osType": "Windows", + "name": "windowsmachine", + "createOption": "FromImage", + "managedDisk": { + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk", + "storageAccountType": "Standard_LRS" + }, + "vhd": { + "uri": "https://groupname2760.blob.core.windows.net/vhds/windowsmachine201624102936.vhd" + }, + "caching": "ReadWrite" + }, + "dataDisks":[ + { + "name":"mydatadisk1", + "diskSizeGB":"1", + "lun": 0, + "vhd": { + "uri" : "http://mystorage1.blob.core.windows.net/vhds/mydatadisk1.vhd" + }, + "createOption":"Empty" + } + ] + }, + "osProfile": { + "computerName": "windowsmachine", + "adminUsername": "azureuser", + "adminPassword":"password", + "customData":"", + "windowsConfiguration": { + "provisionVMAgent": false, + "enableAutomaticUpdates": true, + "winRM": { + "listeners":[{ + "protocol": "https", + "certificateUrl": "url-to-certificate" + }] + }, + "additionalUnattendContent":[ + { + "pass":"oobesystem", + "component":"Microsoft-Windows-Shell-Setup", + "settingName":"FirstLogonCommands", + "content":"" + } + ] + }, + "secrets":[ + { + "sourceVault": { + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup1/providers/Microsoft.KeyVault/vaults/myvault1" + }, + "vaultCertificates": [ + { + "certificateUrl": "https://myvault1.vault.azure.net/secrets/SECRETNAME/SECRETVERSION", + "certificateStore": "CERTIFICATESTORENAME" + } + ] + } + ] + }, + "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" + }, + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Compute/virtualMachines/windowsmachine", + "name": "windowsmachine", + "type": "Microsoft.Compute/virtualMachines", + "location": "westus" } ] } From b2cc647ff220df6129eb8b508325a34c8ce5a44c Mon Sep 17 00:00:00 2001 From: Dani Estevez Date: Fri, 2 Jun 2017 16:23:20 -0400 Subject: [PATCH 66/87] Implements metrics and metricdefinitions API --- .../azurecompute/arm/AzureComputeApi.java | 20 +++ .../arm/AzureComputeProviderMetadata.java | 4 + .../azurecompute/arm/domain/Metric.java | 51 +++++++ .../azurecompute/arm/domain/MetricData.java | 74 +++++++++ .../arm/domain/MetricDefinition.java | 97 ++++++++++++ .../azurecompute/arm/domain/MetricName.java | 38 +++++ .../arm/features/MetricDefinitionsApi.java | 52 +++++++ .../azurecompute/arm/features/MetricsApi.java | 51 +++++++ .../MetricDefinitionsApiLiveTest.java | 131 ++++++++++++++++ .../MetricDefinitionsApiMockTest.java | 65 ++++++++ .../arm/features/MetricsApiLiveTest.java | 143 ++++++++++++++++++ .../arm/features/MetricsApiMockTest.java | 72 +++++++++ .../src/test/resources/metricdefinitions.json | 25 +++ .../src/test/resources/metrics.json | 19 +++ 14 files changed, 842 insertions(+) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Metric.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/MetricData.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/MetricDefinition.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/MetricName.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/MetricDefinitionsApi.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/MetricsApi.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/MetricDefinitionsApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/MetricDefinitionsApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/MetricsApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/MetricsApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/resources/metricdefinitions.json create mode 100644 providers/azurecompute-arm/src/test/resources/metrics.json 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 a25690f52a..123f6e326e 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 @@ -27,6 +27,8 @@ import org.jclouds.azurecompute.arm.features.ImageApi; import org.jclouds.azurecompute.arm.features.JobApi; import org.jclouds.azurecompute.arm.features.LoadBalancerApi; import org.jclouds.azurecompute.arm.features.LocationApi; +import org.jclouds.azurecompute.arm.features.MetricDefinitionsApi; +import org.jclouds.azurecompute.arm.features.MetricsApi; import org.jclouds.azurecompute.arm.features.NetworkInterfaceCardApi; import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi; import org.jclouds.azurecompute.arm.features.NetworkSecurityRuleApi; @@ -208,4 +210,22 @@ public interface AzureComputeApi extends Closeable { */ @Delegate ImageApi getVirtualMachineImageApi(@PathParam("resourcegroup") String resourcegroup); + + /** + * The metrics API includes operations to get insights into entities within your + * subscription. + * + * @see docs + */ + @Delegate + MetricsApi getMetricsApi(@PathParam("resourceid") String resourceid); + + /** + * The metric definitions API includes operations to get insights available for entities within your + * subscription. + * + * @see docs + */ + @Delegate + MetricDefinitionsApi getMetricsDefinitionsApi(@PathParam("resourceid") String resourceid); } 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 c35455cd9e..6a5c587b4d 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 @@ -44,6 +44,8 @@ import org.jclouds.azurecompute.arm.features.ImageApi; import org.jclouds.azurecompute.arm.features.LoadBalancerApi; import org.jclouds.azurecompute.arm.features.LocationApi; import org.jclouds.azurecompute.arm.features.DiskApi; +import org.jclouds.azurecompute.arm.features.MetricDefinitionsApi; +import org.jclouds.azurecompute.arm.features.MetricsApi; import org.jclouds.azurecompute.arm.features.NetworkInterfaceCardApi; import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi; import org.jclouds.azurecompute.arm.features.NetworkSecurityRuleApi; @@ -115,6 +117,8 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { properties.put(API_VERSION_PREFIX + AvailabilitySetApi.class.getSimpleName(), "2016-04-30-preview"); properties.put(API_VERSION_PREFIX + DiskApi.class.getSimpleName(), "2017-03-30"); properties.put(API_VERSION_PREFIX + ImageApi.class.getSimpleName(), "2016-04-30-preview"); + properties.put(API_VERSION_PREFIX + MetricDefinitionsApi.class.getSimpleName(), "2017-05-01-preview"); + properties.put(API_VERSION_PREFIX + MetricsApi.class.getSimpleName(), "2016-09-01"); return properties; } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Metric.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Metric.java new file mode 100644 index 0000000000..0320db24c8 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Metric.java @@ -0,0 +1,51 @@ +/* + * 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 java.util.List; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; + +/** + * A Metric with its values for a resource + */ +@AutoValue +public abstract class Metric { + + public abstract List data(); + + public abstract String id(); + + @Nullable + public abstract MetricName name(); + + public abstract String type(); + + public abstract String unit(); + + @SerializedNames({ "data", "id", "name", "type", "unit" }) + public static Metric create(final List data, final String id, final MetricName name, final String type, + final String unit) { + return new AutoValue_Metric(data == null ? ImmutableList. of() : ImmutableList.copyOf(data), id, name, + type, unit); + } + +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/MetricData.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/MetricData.java new file mode 100644 index 0000000000..29e810e4b2 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/MetricData.java @@ -0,0 +1,74 @@ +/* + * 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 java.util.Date; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +/** + * + */ +@AutoValue +public abstract class MetricData +{ + + /** + * The timestamp for the metric value in ISO 8601 format. + */ + public abstract Date timeStamp(); + + /** + * The average value in the time range + */ + @Nullable + public abstract Double total(); + + /** + * The sum of all of the values in the time range. + */ + @Nullable + public abstract Double average(); + + /** + * The least value in the time range. + */ + @Nullable + public abstract Double minimum(); + + /** + * The greatest value in the time range. + */ + @Nullable + public abstract Double maximum(); + + /** + * The number of samples in the time range. + */ + @Nullable + public abstract Long count(); + + @SerializedNames({"timeStamp", "total", "average", "minimum", "maximum", "count"}) + public static MetricData create(final Date timeStamp, final Double total, final Double average, + final Double minimum, final Double maximum, final Long count) + { + return new AutoValue_MetricData(timeStamp, total, average, minimum, maximum, count); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/MetricDefinition.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/MetricDefinition.java new file mode 100644 index 0000000000..95f8d47a17 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/MetricDefinition.java @@ -0,0 +1,97 @@ +/* + * 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 java.util.List; + +import org.jclouds.azurecompute.arm.util.GetEnumValue; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; + +/** + * A Metric definition for a resource + */ +@AutoValue +public abstract class MetricDefinition { + + public enum AggregationType { + None("None"), Average("Average"), Count("Count"), Total("Total"), Minimum("Minimum"), Maximum( + "Maximum"), UNRECOGNIZED("Unrecognized"); + + private final String label; + + AggregationType(String label) { + this.label = label; + } + + public static AggregationType fromValue(final String text) { + return (AggregationType) GetEnumValue.fromValueOrDefault(text, AggregationType.UNRECOGNIZED); + } + + @Override + public String toString() { + return label; + } + } + + @Nullable + public abstract String resourceId(); + + public abstract MetricName name(); + + @Nullable + public abstract Boolean isDimensionRequired(); + + public abstract String unit(); + + public abstract AggregationType primaryAggregationType(); + + public abstract List metricAvailabilities(); + + public abstract String id(); + + @SerializedNames({ "resourceId", "name", "isDimensionRequired", "unit", "primaryAggregationType", + "metricAvailabilities", "id" }) + public static MetricDefinition create(final String resourceId, final MetricName name, + final Boolean isDimensionRequired, final String unit, final AggregationType primaryAggregationType, + List metricAvailabilities, final String id) { + return new AutoValue_MetricDefinition(resourceId, name, isDimensionRequired, unit, primaryAggregationType, + metricAvailabilities == null ? + ImmutableList. of() : + ImmutableList.copyOf(metricAvailabilities), id); + } + + @AutoValue + public abstract static class MetricAvailability { + + public abstract String timeGrain(); + + public abstract String retention(); + + MetricAvailability() { + + } + + @SerializedNames({ "timeGrain", "retention" }) + public static MetricDefinition.MetricAvailability create(String timeGrain, String retention) { + return new AutoValue_MetricDefinition_MetricAvailability(timeGrain, retention); + } + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/MetricName.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/MetricName.java new file mode 100644 index 0000000000..7caf52ed67 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/MetricName.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.domain; + +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +/** + * A Metric with its values for a resource + */ +@AutoValue +public abstract class MetricName { + + public abstract String value(); + + public abstract String localizedValue(); + + @SerializedNames({ "value", "localizedValue" }) + public static MetricName create(String value, String localizedValue) { + return new AutoValue_MetricName(value, localizedValue); + } + +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/MetricDefinitionsApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/MetricDefinitionsApi.java new file mode 100644 index 0000000000..ba62a28ecf --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/MetricDefinitionsApi.java @@ -0,0 +1,52 @@ +/* + * 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 javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; +import org.jclouds.azurecompute.arm.domain.MetricDefinition; +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; + +/** + * This Azure Resource Manager API provides all the metric definitions available for a given resource + *

+ * + * @see docs + */ +@Path("/{resourceid}") +@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) +@Consumes(MediaType.APPLICATION_JSON) +public interface MetricDefinitionsApi { + @Named("metrics:list") + @Path("/providers/microsoft.insights/metricdefinitions") + @GET + @SelectJson("value") + @Fallback(EmptyListOnNotFoundOr404.class) + List list(@Nullable @QueryParam("$filter") String filter); +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/MetricsApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/MetricsApi.java new file mode 100644 index 0000000000..03d19a193b --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/MetricsApi.java @@ -0,0 +1,51 @@ +/* + * 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 javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; +import org.jclouds.azurecompute.arm.domain.Metric; +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; + +/** + * This Azure Resource Manager API provides all the metric data available for a given resource + *

+ * + * @see docs + */ +@Path("/{resourceid}") +@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) +@Consumes(MediaType.APPLICATION_JSON) +public interface MetricsApi { + @Named("metrics:list") + @Path("/providers/microsoft.insights/metrics") + @GET + @SelectJson("value") + @Fallback(EmptyListOnNotFoundOr404.class) + List list(@QueryParam("$filter") String filter); +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/MetricDefinitionsApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/MetricDefinitionsApiLiveTest.java new file mode 100644 index 0000000000..cb8027face --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/MetricDefinitionsApiLiveTest.java @@ -0,0 +1,131 @@ +/* + * 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 static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Iterables.getOnlyElement; +import static org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions.Builder.resourceGroup; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; +import static org.jclouds.compute.predicates.NodePredicates.inGroup; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +import java.net.URI; +import java.util.List; +import java.util.Properties; + +import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.domain.IdReference; +import org.jclouds.azurecompute.arm.domain.MetricDefinition; +import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; +import org.jclouds.compute.RunNodesException; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.google.common.base.Predicate; +import com.google.inject.Key; +import com.google.inject.TypeLiteral; +import com.google.inject.name.Names; + +@Test(groups = "live", singleThreaded = true) +public class MetricDefinitionsApiLiveTest extends BaseComputeServiceContextLiveTest { + + private Predicate resourceDeleted; + private AzureComputeApi api; + + private String location; + private MetricDefinitionsApi metricDefinitionsApi; + + private String group; + + public MetricDefinitionsApiLiveTest() { + provider = "azurecompute-arm"; + group = getClass().getSimpleName().toLowerCase(); + } + + @Override + protected Properties setupProperties() { + Properties properties = super.setupProperties(); + AzureLiveTestUtils.defaultProperties(properties); + checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); + return properties; + } + + @Override + protected void initializeContext() { + super.initializeContext(); + resourceDeleted = context.utils().injector().getInstance(Key.get(new TypeLiteral>() { + }, Names.named(TIMEOUT_RESOURCE_DELETED))); + api = view.unwrapApi(AzureComputeApi.class); + } + + @Override + @BeforeClass + public void setupContext() { + super.setupContext(); + NodeMetadata node = null; + try { + node = getOnlyElement(view.getComputeService().createNodesInGroup(group, 1, resourceGroup(group))); + } catch (RunNodesException e) { + fail(); + } + String resourceId = String.format("/resourceGroups/%s/providers/Microsoft.Compute/virtualMachines/%s", + IdReference.extractResourceGroup(node.getProviderId()), IdReference.extractName(node.getProviderId())); + + location = view.getComputeService().templateBuilder().build().getLocation().getId(); + view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().create(group, location, null); + metricDefinitionsApi = api.getMetricsDefinitionsApi(resourceId); + } + + @Override + @AfterClass(alwaysRun = true) + protected void tearDownContext() { + try { + view.getComputeService().destroyNodesMatching(inGroup(group)); + } finally { + try { + URI uri = api.getResourceGroupApi().delete(group); + assertResourceDeleted(uri); + } finally { + super.tearDownContext(); + } + } + } + + public void listVirtualMachineMetricDefinitions() { + List result = metricDefinitionsApi.list("name.value eq 'Percentage CPU'"); + + // verify we have something + assertNotNull(result); + assertTrue(result.size() > 1); + assertEquals(result.get(0).name().value(), "Percentage CPU"); + } + + private void assertResourceDeleted(final URI uri) { + if (uri != null) { + assertTrue(resourceDeleted.apply(uri), + String.format("Resource %s was not deleted in the configured timeout", uri)); + } + } + +} + diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/MetricDefinitionsApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/MetricDefinitionsApiMockTest.java new file mode 100644 index 0000000000..8fd06b8d6f --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/MetricDefinitionsApiMockTest.java @@ -0,0 +1,65 @@ +/* + * 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 static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import org.jclouds.azurecompute.arm.domain.MetricDefinition; +import org.jclouds.azurecompute.arm.domain.MetricName; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; +import com.squareup.okhttp.mockwebserver.MockResponse; + +@Test(groups = "unit", testName = "MetricDefinitionsApiMockTest", singleThreaded = true) +public class MetricDefinitionsApiMockTest extends BaseAzureComputeApiMockTest { + + private final String resourceId = "resourceGroups/myresourceGroup/providers/Microsoft.Compute/virtualMachines/myvm"; + private final String filter = "(name.value eq 'Percentage CPU')"; + + public void testList() throws Exception { + server.enqueue(jsonResponse("/metricdefinitions.json")); + final MetricDefinitionsApi metricDefinitionsApi = api.getMetricsDefinitionsApi(resourceId); + assertEquals(metricDefinitionsApi.list(filter), ImmutableList.of(MetricDefinition.create( + "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup/providers/Microsoft" + + ".Compute/virtualMachines/myvm", MetricName.create("Percentage CPU", "Percentage CPU"), + Boolean.FALSE, "Percent", MetricDefinition.AggregationType.Average, + ImmutableList. of( + MetricDefinition.MetricAvailability.create("PT1M", "P30D"), + MetricDefinition.MetricAvailability.create("PT1H", "P30D")), + "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup/providers" + + "/Microsoft.Compute/virtualMachines/myvm/providers/microsoft" + + ".insights/metricdefinitions/Percentage " + "CPU"))); + assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourceGroup/providers/Microsoft" + + ".Compute/virtualMachines/myvm/providers/microsoft.insights/metricdefinitions?$filter=%28name" + + ".value%20eq%20%27Percentage%20CPU%27%29&api-version=2017-05-01-preview"); + } + + public void testEmptyList() throws Exception { + server.enqueue(new MockResponse().setResponseCode(404)); + + final MetricDefinitionsApi metricDefinitionsApi = api.getMetricsDefinitionsApi(resourceId); + + assertTrue(metricDefinitionsApi.list(filter).isEmpty()); + + assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourceGroup/providers/Microsoft" + + ".Compute/virtualMachines/myvm/providers/microsoft.insights/metricdefinitions?$filter=%28name" + + ".value%20eq%20%27Percentage%20CPU%27%29&api-version=2017-05-01-preview"); + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/MetricsApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/MetricsApiLiveTest.java new file mode 100644 index 0000000000..5fe19db348 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/MetricsApiLiveTest.java @@ -0,0 +1,143 @@ +/* + * 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 static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Iterables.getOnlyElement; +import static org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions.Builder.resourceGroup; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; +import static org.jclouds.compute.predicates.NodePredicates.inGroup; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +import java.net.URI; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Properties; + +import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.domain.IdReference; +import org.jclouds.azurecompute.arm.domain.Metric; +import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; +import org.jclouds.compute.RunNodesException; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.google.common.base.Predicate; +import com.google.inject.Key; +import com.google.inject.TypeLiteral; +import com.google.inject.name.Names; + +@Test(groups = "live", singleThreaded = true) +public class MetricsApiLiveTest extends BaseComputeServiceContextLiveTest { + + private Predicate resourceDeleted; + private AzureComputeApi api; + + private String location; + private MetricsApi metricsApi; + + private String group; + + private String startTime; + private SimpleDateFormat dateFormat; + + public MetricsApiLiveTest() { + provider = "azurecompute-arm"; + group = getClass().getSimpleName().toLowerCase(); + } + + @Override + protected Properties setupProperties() { + Properties properties = super.setupProperties(); + AzureLiveTestUtils.defaultProperties(properties); + checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); + return properties; + } + + @Override + protected void initializeContext() { + super.initializeContext(); + resourceDeleted = context.utils().injector().getInstance(Key.get(new TypeLiteral>() { + }, Names.named(TIMEOUT_RESOURCE_DELETED))); + api = view.unwrapApi(AzureComputeApi.class); + } + + @Override + @BeforeClass + public void setupContext() { + super.setupContext(); + + dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + startTime = dateFormat.format(new Date()); + + NodeMetadata node = null; + try { + node = getOnlyElement(view.getComputeService().createNodesInGroup(group, 1, resourceGroup(group))); + } catch (RunNodesException e) { + fail(); + } + String resourceId = String.format("/resourceGroups/%s/providers/Microsoft.Compute/virtualMachines/%s", + IdReference.extractResourceGroup(node.getProviderId()), IdReference.extractName(node.getProviderId())); + + location = view.getComputeService().templateBuilder().build().getLocation().getId(); + view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().create(group, location, null); + metricsApi = api.getMetricsApi(resourceId); + } + + @Override + @AfterClass(alwaysRun = true) + protected void tearDownContext() { + try { + view.getComputeService().destroyNodesMatching(inGroup(group)); + } finally { + try { + URI uri = api.getResourceGroupApi().delete(group); + assertResourceDeleted(uri); + } finally { + super.tearDownContext(); + } + } + } + + public void listVirtualMachineMetrics() throws RunNodesException { + List result = metricsApi + .list("(name.value eq 'Percentage CPU') and startTime eq " + startTime + " and endTime eq " + dateFormat + .format(new Date()) + " and timeGrain eq duration'PT1M'"); + + // verify we have something + assertNotNull(result); + assertEquals(result.size(), 1); + assertEquals(result.get(0).name().value(), "Percentage CPU"); + assertTrue(result.get(0).data().size() > 1); + } + + private void assertResourceDeleted(final URI uri) { + if (uri != null) { + assertTrue(resourceDeleted.apply(uri), + String.format("Resource %s was not deleted in the configured timeout", uri)); + } + } + +} + diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/MetricsApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/MetricsApiMockTest.java new file mode 100644 index 0000000000..c6e30c1c4d --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/MetricsApiMockTest.java @@ -0,0 +1,72 @@ +/* + * 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 static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.text.ParsePosition; +import java.text.SimpleDateFormat; +import java.util.Locale; + +import org.jclouds.azurecompute.arm.domain.Metric; +import org.jclouds.azurecompute.arm.domain.MetricData; +import org.jclouds.azurecompute.arm.domain.MetricName; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; +import com.squareup.okhttp.mockwebserver.MockResponse; + +@Test(groups = "unit", testName = "MetricsApiMockTest", singleThreaded = true) +public class MetricsApiMockTest extends BaseAzureComputeApiMockTest { + + private final String resourceId = "resourceGroups/myresourceGroup/providers/Microsoft.Compute/virtualMachines/myvm"; + private final String filter = "(name.value eq 'Percentage CPU') and startTime eq 2017-06-01T11:14:00Z and " + + "endTime eq 2017-06-01T11:23:00Z and timeGrain eq duration'PT1M'"; + + public void testList() throws Exception { + server.enqueue(jsonResponse("/metrics.json")); + final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US); + final MetricsApi metricsApi = api.getMetricsApi(resourceId); + assertEquals(metricsApi.list(filter), ImmutableList.of(Metric.create(ImmutableList.of(MetricData + .create(dateFormat.parse("2017-06-01T07:14:00", new ParsePosition(0)), null, + Double.valueOf(0.295), null, null, null)), + "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup/providers" + + "/Microsoft.Compute/virtualMachines/myvm/providers/Microsoft.Insights/metrics/Percentage CPU", + MetricName.create("Percentage CPU", "Percentage CPU"), "Microsoft.Insights/metrics", "Percent"))); + assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourceGroup/providers/Microsoft" + + ".Compute/virtualMachines/myvm/providers/microsoft.insights/metrics?$filter=%28name" + + ".value%20eq%20%27Percentage%20CPU%27%29%20and%20startTime%20eq%202017-06-01T11%3A14%3A00Z%20and" + + "%20endTime%20eq%202017-06-01T11%3A23%3A00Z%20and%20timeGrain%20eq%20duration%27PT1M%27&api-version" + + "=2016-09-01"); + } + + public void testEmptyList() throws Exception { + server.enqueue(new MockResponse().setResponseCode(404)); + + final MetricsApi metricsAPI = api.getMetricsApi(resourceId); + + assertTrue(metricsAPI.list(filter).isEmpty()); + + assertSent(server, "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourceGroup/providers/Microsoft" + + ".Compute/virtualMachines/myvm/providers/microsoft.insights/metrics?$filter=%28name" + + ".value%20eq%20%27Percentage%20CPU%27%29%20and%20startTime%20eq%202017-06-01T11%3A14%3A00Z%20and" + + "%20endTime%20eq%202017-06-01T11%3A23%3A00Z%20and%20timeGrain%20eq%20duration%27PT1M%27&api-version" + + "=2016-09-01"); + } +} diff --git a/providers/azurecompute-arm/src/test/resources/metricdefinitions.json b/providers/azurecompute-arm/src/test/resources/metricdefinitions.json new file mode 100644 index 0000000000..3df0a84089 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/metricdefinitions.json @@ -0,0 +1,25 @@ +{ + "value": [ + { + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup/providers/Microsoft.Compute/virtualMachines/myvm/providers/microsoft.insights/metricdefinitions/Percentage CPU", + "resourceId": "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup/providers/Microsoft.Compute/virtualMachines/myvm", + "name": { + "value": "Percentage CPU", + "localizedValue": "Percentage CPU" + }, + "isDimensionRequired": false, + "unit": "Percent", + "primaryAggregationType": "Average", + "metricAvailabilities": [ + { + "timeGrain": "PT1M", + "retention": "P30D" + }, + { + "timeGrain": "PT1H", + "retention": "P30D" + } + ] + } + ] +} diff --git a/providers/azurecompute-arm/src/test/resources/metrics.json b/providers/azurecompute-arm/src/test/resources/metrics.json new file mode 100644 index 0000000000..754e5d19c1 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/metrics.json @@ -0,0 +1,19 @@ +{ + "value": [ + { + "data": [ + { + "timeStamp": "2017-06-01T11:14:00Z", + "average": 0.295 + } + ], + "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup/providers/Microsoft.Compute/virtualMachines/myvm/providers/Microsoft.Insights/metrics/Percentage CPU", + "name": { + "value": "Percentage CPU", + "localizedValue": "Percentage CPU" + }, + "type": "Microsoft.Insights/metrics", + "unit": "Percent" + } + ] +} From f086c050f9061fc0de62b3eafcf9df90fdcb9d8c Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Wed, 28 Jun 2017 09:29:52 +0200 Subject: [PATCH 67/87] Use the date service to parse dates --- .../azurecompute/arm/features/MetricsApiMockTest.java | 11 ++++------- .../arm/internal/BaseAzureComputeApiMockTest.java | 3 +++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/MetricsApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/MetricsApiMockTest.java index c6e30c1c4d..2001d193e1 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/MetricsApiMockTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/MetricsApiMockTest.java @@ -19,9 +19,7 @@ package org.jclouds.azurecompute.arm.features; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; -import java.text.ParsePosition; -import java.text.SimpleDateFormat; -import java.util.Locale; +import java.util.Date; import org.jclouds.azurecompute.arm.domain.Metric; import org.jclouds.azurecompute.arm.domain.MetricData; @@ -41,11 +39,10 @@ public class MetricsApiMockTest extends BaseAzureComputeApiMockTest { public void testList() throws Exception { server.enqueue(jsonResponse("/metrics.json")); - final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US); final MetricsApi metricsApi = api.getMetricsApi(resourceId); - assertEquals(metricsApi.list(filter), ImmutableList.of(Metric.create(ImmutableList.of(MetricData - .create(dateFormat.parse("2017-06-01T07:14:00", new ParsePosition(0)), null, - Double.valueOf(0.295), null, null, null)), + Date timestamp = dateService.iso8601DateOrSecondsDateParse("2017-06-01T11:14:00Z"); + assertEquals(metricsApi.list(filter), ImmutableList.of(Metric.create( + ImmutableList.of(MetricData.create(timestamp, null, Double.valueOf(0.295), null, null, null)), "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup/providers" + "/Microsoft.Compute/virtualMachines/myvm/providers/Microsoft.Insights/metrics/Percentage CPU", MetricName.create("Percentage CPU", "Percentage CPU"), "Microsoft.Insights/metrics", "Percent"))); 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 dc4ad28cf6..f704e5f2b7 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.date.DateService; import org.jclouds.rest.ApiContext; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; @@ -52,6 +53,7 @@ public class BaseAzureComputeApiMockTest { protected MockWebServer server; protected AzureComputeApi api; protected ApiContext context; + protected DateService dateService; // So that we can ignore formatting. private final JsonParser parser = new JsonParser(); @@ -68,6 +70,7 @@ public class BaseAzureComputeApiMockTest { .overrides(setupProperties()) .build(); api = context.getApi(); + dateService = context.utils().injector().getInstance(DateService.class); } protected Properties setupProperties() { From cb556428e36543abb40035554e5bad685e6af0d2 Mon Sep 17 00:00:00 2001 From: Svetoslav Neykov Date: Thu, 6 Jul 2017 10:51:27 +0300 Subject: [PATCH 68/87] Fix SGE.removeSecurityGroup for when the SG doesn't exist --- .../extensions/AzureComputeSecurityGroupExtension.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java index 50cb75a246..eaf820cd57 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java @@ -190,7 +190,15 @@ public class AzureComputeSecurityGroupExtension implements SecurityGroupExtensio final ResourceGroupAndName resourceGroupAndName = ResourceGroupAndName.fromSlashEncoded(id); URI uri = api.getNetworkSecurityGroupApi(resourceGroupAndName.resourceGroup()) .delete(resourceGroupAndName.name()); - return resourceDeleted.apply(uri); + + // https://docs.microsoft.com/en-us/rest/api/network/virtualnetwork/delete-a-network-security-group + if (uri != null) { + // 202-Accepted if resource exists and the request is accepted. + return resourceDeleted.apply(uri); + } else { + // 204-No Content if resource does not exist. + return false; + } } @Override From 180efdf799c3df627f5538aae0b9429fa173b935 Mon Sep 17 00:00:00 2001 From: Svetoslav Neykov Date: Wed, 12 Jul 2017 08:08:54 +0300 Subject: [PATCH 69/87] Generate Azure VM password on the fly --- .../arm/AzureComputeProviderMetadata.java | 5 +-- .../compute/AzureComputeServiceAdapter.java | 11 ++++--- .../CreateResourcesThenCreateNodes.java | 15 +++++++++ .../azurecompute/arm/util/Passwords.java | 32 +++++++++++++++++++ 4 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/Passwords.java 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 6a5c587b4d..a866ffba45 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 @@ -94,8 +94,9 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { properties.put(RESOURCENAME_PREFIX, "jclouds"); properties.put(RESOURCENAME_DELIMITER, "-"); properties.put(IMAGE_PUBLISHERS, "Canonical,RedHat"); - // Default credentials for all images - properties.put(IMAGE_LOGIN_USER, "jclouds:Password12345!"); + // Default credentials for all images, Azure doesn't accept root, admin; generate the password on the fly + properties.put(IMAGE_LOGIN_USER, "jclouds"); + // Azure allows for passwordless sudo only when using a public key to login to the machine properties.put(IMAGE_AUTHENTICATE_SUDO, "true"); properties.put(TEMPLATE, "imageNameMatches=UbuntuServer,osVersionMatches=1[456]\\.[01][04](\\.[0-9])?-LTS"); // Api versions used in each API 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 ccb748a956..0a37d5dbe8 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 @@ -375,18 +375,19 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter customizationResponses) { AzureTemplateOptions options = template.getOptions().as(AzureTemplateOptions.class); + + // TODO Generate a private key instead. Also no need to use AUTHENTICATE_SUDO in this case. + generatePasswordIfNoneProvided(template); // If there is a script to be run on the node and public key // authentication has been configured, warn users if the private key @@ -130,6 +136,15 @@ public class CreateResourcesThenCreateNodes extends CreateNodesWithGroupEncodedI return super.execute(group, count, template, goodNodes, badNodes, customizationResponses); } + // Azure requires that we pass it the VM password. Need to generate one if not overridden by the user. + private void generatePasswordIfNoneProvided(Template template) { + TemplateOptions options = template.getOptions(); + if (options.getLoginPassword() == null) { + Optional passwordOptional = template.getImage().getDefaultCredentials().getOptionalPassword(); + options.overrideLoginPassword(passwordOptional.or(Passwords.generate())); + } + } + protected synchronized void createDefaultNetworkIfNeeded(String group, String location, AzureTemplateOptions options) { if (options.getIpOptions().isEmpty()) { String name = namingConvention.create().sharedNameForGroup(group); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/Passwords.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/Passwords.java new file mode 100644 index 0000000000..9bc189e6cf --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/Passwords.java @@ -0,0 +1,32 @@ +/* + * 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 com.google.common.io.BaseEncoding; + +import java.util.Random; + +// Seems to be a common theme between providers, perhaps should be provided by core (see other 'Passwords' classes) +public class Passwords { + private static final Random random = new Random(); + + public static String generate() { + final byte[] buffer = new byte[15]; + random.nextBytes(buffer); + return BaseEncoding.base64Url().omitPadding().encode(buffer); + } +} From c7050757f5d9d7fa396a0b297202dcf3856c0a66 Mon Sep 17 00:00:00 2001 From: jims Date: Thu, 27 Jul 2017 13:04:39 -0700 Subject: [PATCH 70/87] Subscription ID wasn't being substituted, add default oauth.endpoint --- .../azurecompute/arm/AzureComputeProviderMetadata.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 a866ffba45..eb52746575 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 @@ -89,6 +89,8 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { properties.put(PROPERTY_MAX_RATE_LIMIT_WAIT, 330000); properties.put(RESOURCE, "https://management.azure.com/"); properties.put(CREDENTIAL_TYPE, CLIENT_CREDENTIALS_SECRET.toString()); + // Set a default Oauth endpoint for Azure, fill in the tenantId based on the value supplied + properties.put("oauth.endpoint", "https://login.microsoft.com/${azurecompute-arm.tenantId}/oauth2/token"); 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(RESOURCENAME_PREFIX, "jclouds"); @@ -135,7 +137,7 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { id("azurecompute-arm") .name("Azure Resource Management") .apiMetadata(new AzureManagementApiMetadata()) - .endpoint("https://management.azure.com/subscriptions/SUBSCRIPTION_ID") + .endpoint("https://management.azure.com/subscriptions/${azurecompute-arm.subscriptionId}") .homepage(URI.create("https://www.windowsazure.com/")) .console(URI.create("https://windows.azure.com/default.aspx")) .linkedServices("azureblob") From 7100e811b5a93b05274afee908847d33cbb6f33a Mon Sep 17 00:00:00 2001 From: Svetoslav Neykov Date: Fri, 21 Jul 2017 09:28:06 +0300 Subject: [PATCH 71/87] Re-use the just added Passwords from jclouds-core --- .../CreateResourcesThenCreateNodes.java | 2 +- .../azurecompute/arm/util/Passwords.java | 32 ------------------- 2 files changed, 1 insertion(+), 33 deletions(-) delete mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/Passwords.java diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java index e1d346c894..4c712d09f7 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java @@ -50,7 +50,7 @@ import org.jclouds.azurecompute.arm.domain.Subnet; import org.jclouds.azurecompute.arm.domain.Subnet.SubnetProperties; import org.jclouds.azurecompute.arm.domain.VirtualNetwork.AddressSpace; import org.jclouds.azurecompute.arm.domain.VirtualNetwork.VirtualNetworkProperties; -import org.jclouds.azurecompute.arm.util.Passwords; +import org.jclouds.util.Passwords; import org.jclouds.compute.config.CustomizationResponse; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.Template; diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/Passwords.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/Passwords.java deleted file mode 100644 index 9bc189e6cf..0000000000 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/util/Passwords.java +++ /dev/null @@ -1,32 +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 com.google.common.io.BaseEncoding; - -import java.util.Random; - -// Seems to be a common theme between providers, perhaps should be provided by core (see other 'Passwords' classes) -public class Passwords { - private static final Random random = new Random(); - - public static String generate() { - final byte[] buffer = new byte[15]; - random.nextBytes(buffer); - return BaseEncoding.base64Url().omitPadding().encode(buffer); - } -} From b38ce8d7b317f2e8d486c38a81365d30ec4145f5 Mon Sep 17 00:00:00 2001 From: Andrew Gaul Date: Thu, 24 Aug 2017 18:26:39 -0700 Subject: [PATCH 72/87] JCLOUDS-1225: Address Guava 18 Objects changes Fixed with: find -name \*.java | xargs sed -i 's/Objects.[Tt]oStringHelper/More&/g' find -name \*.java | xargs sed -i 's/Objects.firstNonNull/More&/g' find -name \*.java | xargs sed -i 's/^\(import com.google.common.base.\)\(Objects.*\)/\1More\2\n\1\2/g' find -name \*.java | xargs java -jar google-java-format-1.3-all-deps.jar -i --fix-imports-only --skip-sorting-imports --- .../azurecompute/arm/compute/AzureComputeServiceAdapter.java | 4 ++-- .../arm/compute/options/AzureTemplateOptions.java | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) 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 0a37d5dbe8..213d438c36 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 @@ -96,7 +96,7 @@ 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.MoreObjects; import com.google.common.base.Predicate; import com.google.common.base.Splitter; import com.google.common.base.Supplier; @@ -375,7 +375,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter Date: Thu, 24 Aug 2017 13:11:47 +0100 Subject: [PATCH 73/87] Cleanup extraneous resources This was not being called as doDestroyNode returns once node deleted. Change based on similar code on gce compute provider --- .../arm/compute/AzureComputeService.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java index dcb9c442d8..e82110a5fc 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java @@ -16,9 +16,12 @@ */ package org.jclouds.azurecompute.arm.compute; +import static com.google.common.collect.Iterables.filter; +import static com.google.common.collect.Sets.newHashSet; 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.predicates.NodePredicates.all; import java.util.Map; import java.util.Map.Entry; @@ -124,4 +127,28 @@ public class AzureComputeService extends BaseComputeService { cleanupResources.deleteResourceGroupIfEmpty(resourceGroup); } } + + @Override + public void destroyNode(String id) { + // Azure ARM does not return TERMINATED nodes, so in practice no node will never reach the TERMINATED + // state, and the deleted nodes will never be returned. + // In order to be able to clean up the resources associated to the deleted nodes, we have to retrieve + // the details of the nodes before deleting them. + NodeMetadata nodeMetadataBeforeDelete = getNodeMetadata(id); + super.destroyNode(id); + //Node metadata is null after deletion but we still need to clean up incidental resources + cleanUpIncidentalResourcesOfDeadNodes(ImmutableSet.of(nodeMetadataBeforeDelete)); + } + + @Override + public Set destroyNodesMatching(Predicate filter) { + // Azure ARM does not return TERMINATED nodes, so in practice no node will never reach the TERMINATED + // state, and the deleted nodes will never be returned. + // In order to be able to clean up the resources associated to the deleted nodes, we have to retrieve + // the details of the nodes before deleting them. + Set nodes = newHashSet(filter(listNodesDetailsMatching(all()), filter)); + super.destroyNodesMatching(filter); // This returns an empty list (a list of null elements) in Azure ARM, as the api does not return deleted nodes + cleanUpIncidentalResourcesOfDeadNodes(nodes); + return nodes; + } } From fd00c7db7504a8067a2a972f7606e29ff067f51d Mon Sep 17 00:00:00 2001 From: Andrew Gaul Date: Wed, 30 Aug 2017 12:24:36 -0700 Subject: [PATCH 74/87] Make auto service optional This makes dependencies consistent and eliminates warnings of the form: $M2_HOME/repository/org/apache/jclouds/driver/jclouds-slf4j/2.1.0-SNAPSHOT/jclouds-slf4j-2.1.0-SNAPSHOT.jar(org/jclouds/logging/slf4j/config/SLF4JLoggingModule.class): warning: Cannot find annotation method 'value()' in type 'AutoService': class file for com.google.auto.service.AutoService not found Reference: https://github.com/google/auto/tree/master/service#download --- providers/azurecompute-arm/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/providers/azurecompute-arm/pom.xml b/providers/azurecompute-arm/pom.xml index 028e4761bb..72ff3e2db9 100644 --- a/providers/azurecompute-arm/pom.xml +++ b/providers/azurecompute-arm/pom.xml @@ -52,6 +52,7 @@ com.google.auto.service auto-service provided + true com.google.auto.value From 79daee361aa5acca298f16e7fa38a520bbc0c0eb Mon Sep 17 00:00:00 2001 From: Andrea Turli Date: Wed, 6 Sep 2017 11:46:10 +0200 Subject: [PATCH 75/87] remove overrides from AzureComputeService for destroyNode and destroyNodesMatching - uses https://github.com/jclouds/jclouds/pull/1135 --- .../arm/compute/AzureComputeService.java | 36 +++---------------- 1 file changed, 5 insertions(+), 31 deletions(-) diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java index e82110a5fc..e676460f23 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/AzureComputeService.java @@ -16,13 +16,6 @@ */ package org.jclouds.azurecompute.arm.compute; -import static com.google.common.collect.Iterables.filter; -import static com.google.common.collect.Sets.newHashSet; -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.predicates.NodePredicates.all; - import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -69,6 +62,10 @@ import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.ListeningExecutorService; +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; + @Singleton public class AzureComputeService extends BaseComputeService { private final CleanupResources cleanupResources; @@ -127,28 +124,5 @@ public class AzureComputeService extends BaseComputeService { cleanupResources.deleteResourceGroupIfEmpty(resourceGroup); } } - - @Override - public void destroyNode(String id) { - // Azure ARM does not return TERMINATED nodes, so in practice no node will never reach the TERMINATED - // state, and the deleted nodes will never be returned. - // In order to be able to clean up the resources associated to the deleted nodes, we have to retrieve - // the details of the nodes before deleting them. - NodeMetadata nodeMetadataBeforeDelete = getNodeMetadata(id); - super.destroyNode(id); - //Node metadata is null after deletion but we still need to clean up incidental resources - cleanUpIncidentalResourcesOfDeadNodes(ImmutableSet.of(nodeMetadataBeforeDelete)); - } - - @Override - public Set destroyNodesMatching(Predicate filter) { - // Azure ARM does not return TERMINATED nodes, so in practice no node will never reach the TERMINATED - // state, and the deleted nodes will never be returned. - // In order to be able to clean up the resources associated to the deleted nodes, we have to retrieve - // the details of the nodes before deleting them. - Set nodes = newHashSet(filter(listNodesDetailsMatching(all()), filter)); - super.destroyNodesMatching(filter); // This returns an empty list (a list of null elements) in Azure ARM, as the api does not return deleted nodes - cleanUpIncidentalResourcesOfDeadNodes(nodes); - return nodes; - } + } From b0abfa4b9a2ce825ddef1ee82d1028fbed625ab0 Mon Sep 17 00:00:00 2001 From: Andrea Turli Date: Wed, 13 Sep 2017 11:59:37 +0200 Subject: [PATCH 76/87] [ARM] IpOption will allocate a public ip when a network is specified --- .../CreateResourcesThenCreateNodes.java | 29 +++++++++---------- .../CreateResourcesThenCreateNodesTest.java | 19 ++++++------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java index 4c712d09f7..fb832c144d 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java @@ -16,15 +16,6 @@ */ package org.jclouds.azurecompute.arm.compute.strategy; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.collect.Iterables.getOnlyElement; -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.domain.IdReference.extractName; -import static org.jclouds.azurecompute.arm.domain.IdReference.extractResourceGroup; -import static org.jclouds.azurecompute.arm.domain.Subnet.extractVirtualNetwork; - import java.util.Arrays; import java.util.Map; import java.util.Set; @@ -34,7 +25,6 @@ import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; -import com.google.common.base.Optional; import org.jclouds.Constants; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName; @@ -50,7 +40,6 @@ import org.jclouds.azurecompute.arm.domain.Subnet; import org.jclouds.azurecompute.arm.domain.Subnet.SubnetProperties; import org.jclouds.azurecompute.arm.domain.VirtualNetwork.AddressSpace; import org.jclouds.azurecompute.arm.domain.VirtualNetwork.VirtualNetworkProperties; -import org.jclouds.util.Passwords; import org.jclouds.compute.config.CustomizationResponse; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.Template; @@ -63,8 +52,10 @@ import org.jclouds.compute.strategy.ListNodesStrategy; import org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet; import org.jclouds.domain.Location; import org.jclouds.logging.Logger; +import org.jclouds.util.Passwords; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Optional; import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -72,6 +63,15 @@ import com.google.common.collect.Multimap; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.Iterables.getOnlyElement; +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.domain.IdReference.extractName; +import static org.jclouds.azurecompute.arm.domain.IdReference.extractResourceGroup; +import static org.jclouds.azurecompute.arm.domain.Subnet.extractVirtualNetwork; + @Singleton public class CreateResourcesThenCreateNodes extends CreateNodesWithGroupEncodedIntoNameThenAddToSet { @@ -219,14 +219,14 @@ public class CreateResourcesThenCreateNodes extends CreateNodesWithGroupEncodedI throw new IllegalArgumentException("The options.networks and options.ipOptions are exclusive"); } - if (!options.getNetworks().isEmpty() && options.getIpOptions().isEmpty()) { + if (!options.getNetworks().isEmpty()) { // The portable interface allows to configure network IDs (subnet IDs), // but we don't know the type of the IP configurations to be applied // when attaching nodes to those networks. We'll assume private IPs - // with Dynamic allocation and no public ip address associated. + // with Dynamic allocation and new public ip address allocated. ImmutableList.Builder ipOptions = ImmutableList.builder(); for (String subnetId : options.getNetworks()) { - ipOptions.add(IpOptions.builder().subnet(subnetId).build()); + ipOptions.add(IpOptions.builder().subnet(subnetId).allocateNewPublicIp(true).build()); } options.ipOptions(ipOptions.build()); } @@ -241,7 +241,6 @@ public class CreateResourcesThenCreateNodes extends CreateNodesWithGroupEncodedI String resourceGroup = extractResourceGroup(ipConfig.subnet()); String networkName = extractVirtualNetwork(ipConfig.subnet()); String subnetName = extractName(ipConfig.subnet()); - Subnet subnet = api.getSubnetApi(resourceGroup, networkName).get(subnetName); checkState(subnet != null, "Configured subnet %s does not exist", ipConfig.subnet()); diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodesTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodesTest.java index f95430c299..51a45af484 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodesTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodesTest.java @@ -16,13 +16,6 @@ */ package org.jclouds.azurecompute.arm.compute.strategy; -import static org.easymock.EasyMock.anyObject; -import static org.easymock.EasyMock.createMock; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.replay; -import static org.easymock.EasyMock.verify; -import static org.testng.Assert.assertEquals; - import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions; import org.jclouds.azurecompute.arm.compute.options.IpOptions; @@ -35,6 +28,13 @@ import org.testng.annotations.Test; import com.google.common.collect.ImmutableList; +import static org.easymock.EasyMock.anyObject; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import static org.testng.Assert.assertEquals; + @Test(groups = "unit", testName = "CreateResourcesThenCreateNodesTest") public class CreateResourcesThenCreateNodesTest { @@ -67,8 +67,9 @@ public class CreateResourcesThenCreateNodesTest { strategy(api).normalizeNetworkOptions(options); assertEquals(options.getIpOptions(), ImmutableList.of( - IpOptions.builder().subnet(netResource("/virtualNetworks/vn/subnets/foo")).build(), IpOptions.builder() - .subnet(netResource("/virtualNetworks/vn/subnets/bar")).build())); + IpOptions.builder().subnet(netResource("/virtualNetworks/vn/subnets/foo")).allocateNewPublicIp(true).build(), + IpOptions.builder().subnet(netResource("/virtualNetworks/vn/subnets/bar")).allocateNewPublicIp(true).build()) + ); // Verify that the code has validated that the subnets exist verify(api, subnetApi); From 7d3b1bebd5d40fcc1532ffbe264cdd31ee623f2f Mon Sep 17 00:00:00 2001 From: Vikas Rangarajan Date: Fri, 26 May 2017 16:16:35 -0500 Subject: [PATCH 77/87] JCLOUDS-1282: Add back support for Azure ARM custom data --- .../compute/AzureComputeServiceAdapter.java | 8 +- .../compute/options/AzureTemplateOptions.java | 126 ++++++++++++------ 2 files changed, 93 insertions(+), 41 deletions(-) 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 213d438c36..37585e2609 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 @@ -99,6 +99,7 @@ import com.google.common.base.Function; import com.google.common.base.MoreObjects; import com.google.common.base.Predicate; import com.google.common.base.Splitter; +import com.google.common.base.Strings; import com.google.common.base.Supplier; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; @@ -381,7 +382,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter ipOptions = ImmutableList.of(); private WindowsConfiguration windowsConfiguration; private List secrets = ImmutableList.of(); - + private String customData; + /** * Sets the availability set where the nodes will be configured. If it does * not exist jclouds will create a new one with the given configuration. @@ -60,7 +61,7 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { this.availabilitySetName = availabilitySetName; return this; } - + /** * The resource group where the new resources will be created. */ @@ -79,7 +80,7 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { public AzureTemplateOptions dataDisks(DataDisk... dataDisks) { return dataDisks(ImmutableList.copyOf(checkNotNull(dataDisks, "dataDisks"))); } - + /** * Configure the NICs that will be attached to the created nodes. *

@@ -99,6 +100,7 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { /** * @see {@link AzureTemplateOptions#ipOptions(Iterable) + */ public AzureTemplateOptions ipOptions(IpOptions... ipOptions) { return ipOptions(ImmutableList.copyOf(checkNotNull(ipOptions, "ipOptions"))); @@ -107,32 +109,66 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { /** * Windows configuration parameters * - * @see docs + * @see docs */ public AzureTemplateOptions windowsConfiguration(WindowsConfiguration windowsConfiguration) { - this.windowsConfiguration = windowsConfiguration; - return this; - } + this.windowsConfiguration = windowsConfiguration; + return this; + } /** * Import certificates in the Windows Certificate Store * - * @see docs + * @see docs */ public AzureTemplateOptions secrets(Iterable secrets) { - for (Secrets secret : checkNotNull(secrets, "secrets")) - checkNotNull(secret, "secrets can not be empty"); - this.secrets = ImmutableList.copyOf(secrets); - return this; - } + for (Secrets secret : checkNotNull(secrets, "secrets")) + checkNotNull(secret, "secrets can not be empty"); + this.secrets = ImmutableList.copyOf(secrets); + return this; + } - public AvailabilitySet getAvailabilitySet() { return availabilitySet; } - public String getAvailabilitySetName() { return availabilitySetName; } - public List getDataDisks() { return dataDisks; } - public String getResourceGroup() { return resourceGroup; } - public List getIpOptions() { return ipOptions; } - public WindowsConfiguration getWindowsConfiguration() { return windowsConfiguration; } - public List getSecrets() { return secrets; } + /** + * Custom data (for cloud-init) for the Azure ARM API + */ + public AzureTemplateOptions customData(String customData) { + this.customData = customData; + return this; + } + + public AvailabilitySet getAvailabilitySet() { + return availabilitySet; + } + + public String getAvailabilitySetName() { + return availabilitySetName; + } + + public List getDataDisks() { + return dataDisks; + } + + public String getResourceGroup() { + return resourceGroup; + } + + public List getIpOptions() { + return ipOptions; + } + + public WindowsConfiguration getWindowsConfiguration() { + return windowsConfiguration; + } + + public List getSecrets() { + return secrets; + } + + public String getCustomData() { + return customData; + } @Override public AzureTemplateOptions clone() { @@ -153,30 +189,32 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { eTo.ipOptions(ipOptions); eTo.windowsConfiguration(windowsConfiguration); eTo.secrets(secrets); + eTo.customData(customData); } } @Override public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof AzureTemplateOptions)) return false; - if (!super.equals(o)) return false; + if (this == o) + return true; + if (!(o instanceof AzureTemplateOptions)) + return false; + if (!super.equals(o)) + return false; AzureTemplateOptions that = (AzureTemplateOptions) o; - - return Objects.equal(availabilitySetName, that.availabilitySetName) && - Objects.equal(resourceGroup, that.resourceGroup) && - Objects.equal(availabilitySet, that.availabilitySet) && - Objects.equal(dataDisks, that.dataDisks) && - Objects.equal(ipOptions, that.ipOptions) && - Objects.equal(windowsConfiguration, that.windowsConfiguration) && - Objects.equal(secrets, that.secrets); + + return Objects.equal(availabilitySetName, that.availabilitySetName) + && Objects.equal(resourceGroup, that.resourceGroup) && Objects.equal(availabilitySet, that.availabilitySet) + && Objects.equal(dataDisks, that.dataDisks) && Objects.equal(ipOptions, that.ipOptions) + && Objects.equal(windowsConfiguration, that.windowsConfiguration) && Objects.equal(secrets, that.secrets) + && Objects.equal(this.customData, that.customData); } @Override public int hashCode() { - return Objects.hashCode(availabilitySet, availabilitySetName, dataDisks, - resourceGroup, ipOptions); + return Objects.hashCode(super.hashCode(), availabilitySet, availabilitySetName, dataDisks, resourceGroup, + ipOptions, customData); } @Override @@ -193,14 +231,16 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { if (!ipOptions.isEmpty()) toString.add("ipOptions", ipOptions); if (windowsConfiguration != null) - toString.add("windowsConfiguration", windowsConfiguration); + toString.add("windowsConfiguration", windowsConfiguration); if (!secrets.isEmpty()) - toString.add("secrets", secrets); + toString.add("secrets", secrets); + if (customData != null) + toString.add("customData", customData); return toString; } public static class Builder { - + /** * @see AzureTemplateOptions#availabilitySet(AvailabilitySet) */ @@ -208,7 +248,7 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { AzureTemplateOptions options = new AzureTemplateOptions(); return options.availabilitySet(availabilitySet); } - + /** * @see AzureTemplateOptions#availabilitySet(String) */ @@ -232,7 +272,7 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { AzureTemplateOptions options = new AzureTemplateOptions(); return options.dataDisks(dataDisks); } - + /** * @see AzureTemplateOptions#resourceGroup(String) */ @@ -240,7 +280,7 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { AzureTemplateOptions options = new AzureTemplateOptions(); return options.resourceGroup(resourceGroup); } - + /** * @see AzureTemplateOptions#ipOptions(IpOptions...) */ @@ -272,5 +312,13 @@ public class AzureTemplateOptions extends TemplateOptions implements Cloneable { AzureTemplateOptions options = new AzureTemplateOptions(); return options.secrets(secrets); } + + /** + * @see AzureTemplateOptions#customData + */ + public static AzureTemplateOptions customData(String customData) { + AzureTemplateOptions options = new AzureTemplateOptions(); + return options.customData(customData); + } } } From e1e89b5ffb1053b3ee750309c6b1e16976184c69 Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Wed, 25 Oct 2017 15:17:39 +0200 Subject: [PATCH 78/87] Update Azure ARM credentials instructions --- providers/azurecompute-arm/README.md | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/providers/azurecompute-arm/README.md b/providers/azurecompute-arm/README.md index 50ebedbe41..ed8abd49e1 100644 --- a/providers/azurecompute-arm/README.md +++ b/providers/azurecompute-arm/README.md @@ -13,24 +13,21 @@ Install and configure Azure CLI following these [steps](http://azure.microsoft.c Using the Azure CLI, run the following commands to create a service principal ```bash -# Set mode to ARM -azure config mode arm - # Enter your Microsoft account credentials when prompted -azure login +az login # Set current subscription to create a service principal -azure account set +az account set --subscription -# Create an AAD application with your information. -azure ad app create --name --password --home-page --identifier-uris +# Create an AD application with your information. +az ad app create --display-name --password --homepage --identifier-uris -# For example: azure ad app create --name "jcloudsarm" --password abcd --home-page "https://jcloudsarm" --identifier-uris "https://jcloudsarm" +# For example: az ad app create --display-name "jcloudsarm" --password abcd --homepage "https://jcloudsarm" --identifier-uris "https://jcloudsarm" # Output will include a value for `Application Id`, which will be used for the live tests # Create a Service Principal -azure ad sp create +az ad sp create --id # Output will include a value for `Object Id`, to be used in the next step ``` @@ -39,13 +36,13 @@ Run the following commands to assign roles to the service principal ```bash # Assign roles for this service principal -azure role assignment create --objectId -o Contributor -c /subscriptions// +az role assignment create --role Contributor --assignee ``` Look up the the tenant Id ```bash -azure account show -s --json +az account show # output will be a JSON which will include the `Tenant id` ``` @@ -53,7 +50,7 @@ azure account show -s --json Verify service principal ```bash -azure login -u -p --service-principal --tenant +az login -u -p --service-principal --tenant ``` ## Run Live Tests From bc520cfdf2ab1977356502fa2d97c30d1bc177e8 Mon Sep 17 00:00:00 2001 From: Andrea Turli Date: Wed, 11 Oct 2017 17:26:14 +0100 Subject: [PATCH 79/87] fix domain object - fix VirtuaMachineMockTest --- .../azurecompute/arm/domain/OSProfile.java | 6 +++--- .../arm/features/VirtualMachineApiMockTest.java | 16 ++++++++-------- .../resources/createvirtualmachineresponse.json | 4 ++-- .../src/test/resources/virtualmachine.json | 4 ++-- .../src/test/resources/virtualmachines.json | 8 ++++---- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSProfile.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSProfile.java index b77dc9e5fc..3f5a0bccaf 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSProfile.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSProfile.java @@ -150,13 +150,13 @@ public abstract class OSProfile { public abstract String content(); - @SerializedNames({"pass", "component", "settingName", "content"}) - public static AdditionalUnattendContent create(final String pass, final String component, + @SerializedNames({"passName", "componentName", "settingName", "content"}) + public static AdditionalUnattendContent create(final String passName, final String componentName, final String settingName, final String content) { return new AutoValue_OSProfile_WindowsConfiguration_AdditionalUnattendContent( - pass, component, settingName, content); + passName, componentName, settingName, content); } } 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 258ae1a6f1..372b303300 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,12 +16,6 @@ */ package org.jclouds.azurecompute.arm.features; -import static com.google.common.collect.Iterables.isEmpty; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; - import java.net.URI; import java.text.DateFormat; import java.text.SimpleDateFormat; @@ -59,6 +53,12 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; 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.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + @Test(groups = "unit", testName = "VirtualMachineApiMockTest", singleThreaded = true) public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { @@ -141,7 +141,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { + "\"managedDisk\":{\"id\":\"/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk\",\"storageAccountType\":\"Standard_LRS\"}}," + "\"dataDisks\":[{\"name\":\"mydatadisk1\",\"diskSizeGB\":\"1\",\"lun\":0,\"createOption\":\"Empty\",\"caching\":\"ReadWrite\",\"managedDisk\":{\"id\":\"/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk\",\"storageAccountType\":\"Standard_LRS\"}}]}," + "\"osProfile\":{\"computerName\":\"windowsmachine\",\"adminUsername\":\"azureuser\",\"adminPassword\":\"password\",\"customData\":\"\",\"windowsConfiguration\":{\"provisionVMAgent\":false," - + "\"winRM\":{\"listeners\":[{\"protocol\":\"https\",\"certificateUrl\":\"url-to-certificate\"}]},\"additionalUnattendContent\":[{\"pass\":\"oobesystem\",\"component\":\"Microsoft-Windows-Shell-Setup\",\"settingName\":\"FirstLogonCommands\",\"content\":\"\"}]," + + "\"winRM\":{\"listeners\":[{\"protocol\":\"https\",\"certificateUrl\":\"url-to-certificate\"}]},\"additionalUnattendContent\":[{\"passName\":\"oobesystem\",\"componentName\":\"Microsoft-Windows-Shell-Setup\",\"settingName\":\"FirstLogonCommands\",\"content\":\"\"}]," + "\"enableAutomaticUpdates\":true}," + "\"secrets\":[{\"sourceVault\":{\"id\":\"/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup1/providers/Microsoft.KeyVault/vaults/myvault1\"},\"vaultCertificates\":[{\"certificateUrl\":\"https://myvault1.vault.azure.net/secrets/SECRETNAME/SECRETVERSION\",\"certificateStore\":\"CERTIFICATESTORENAME\"}]}]}," + "\"networkProfile\":{\"networkInterfaces\":[{\"id\":\"/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Network/networkInterfaces/windowsmachine167\"}]}," @@ -176,7 +176,7 @@ public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest { + "\"managedDisk\":{\"id\":\"/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk\",\"storageAccountType\":\"Standard_LRS\"}}," + "\"dataDisks\":[{\"name\":\"mydatadisk1\",\"diskSizeGB\":\"1\",\"lun\":0,\"createOption\":\"Empty\",\"caching\":\"ReadWrite\",\"managedDisk\":{\"id\":\"/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk\",\"storageAccountType\":\"Standard_LRS\"}}]}," + "\"osProfile\":{\"computerName\":\"windowsmachine\",\"adminUsername\":\"azureuser\",\"adminPassword\":\"password\",\"customData\":\"\",\"windowsConfiguration\":{\"provisionVMAgent\":false," - + "\"winRM\":{\"listeners\":[{\"protocol\":\"https\",\"certificateUrl\":\"url-to-certificate\"}]},\"additionalUnattendContent\":[{\"pass\":\"oobesystem\",\"component\":\"Microsoft-Windows-Shell-Setup\",\"settingName\":\"FirstLogonCommands\",\"content\":\"\"}]," + + "\"winRM\":{\"listeners\":[{\"protocol\":\"https\",\"certificateUrl\":\"url-to-certificate\"}]},\"additionalUnattendContent\":[{\"passName\":\"oobesystem\",\"componentName\":\"Microsoft-Windows-Shell-Setup\",\"settingName\":\"FirstLogonCommands\",\"content\":\"\"}]," + "\"enableAutomaticUpdates\":true}," + "\"secrets\":[{\"sourceVault\":{\"id\":\"/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup1/providers/Microsoft.KeyVault/vaults/myvault1\"},\"vaultCertificates\":[{\"certificateUrl\":\"https://myvault1.vault.azure.net/secrets/SECRETNAME/SECRETVERSION\",\"certificateStore\":\"CERTIFICATESTORENAME\"}]}]}," + "\"networkProfile\":{\"networkInterfaces\":[{\"id\":\"/subscriptions/SUBSCRIPTIONID/resourceGroups/groupname/providers/Microsoft.Network/networkInterfaces/windowsmachine167\"}]}," diff --git a/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json b/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json index 4279f83e66..7402e1437a 100644 --- a/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json +++ b/providers/azurecompute-arm/src/test/resources/createvirtualmachineresponse.json @@ -58,8 +58,8 @@ }, "additionalUnattendContent": [ { - "pass":"oobesystem", - "component":"Microsoft-Windows-Shell-Setup", + "passName":"oobesystem", + "componentName":"Microsoft-Windows-Shell-Setup", "settingName":"FirstLogonCommands", "content":"" } diff --git a/providers/azurecompute-arm/src/test/resources/virtualmachine.json b/providers/azurecompute-arm/src/test/resources/virtualmachine.json index 51ad1fb080..17d89b559d 100644 --- a/providers/azurecompute-arm/src/test/resources/virtualmachine.json +++ b/providers/azurecompute-arm/src/test/resources/virtualmachine.json @@ -57,8 +57,8 @@ }, "additionalUnattendContent":[ { - "pass":"oobesystem", - "component":"Microsoft-Windows-Shell-Setup", + "passName":"oobesystem", + "componentName":"Microsoft-Windows-Shell-Setup", "settingName":"FirstLogonCommands", "content":"" } diff --git a/providers/azurecompute-arm/src/test/resources/virtualmachines.json b/providers/azurecompute-arm/src/test/resources/virtualmachines.json index 27ee602180..e77e58be08 100644 --- a/providers/azurecompute-arm/src/test/resources/virtualmachines.json +++ b/providers/azurecompute-arm/src/test/resources/virtualmachines.json @@ -58,8 +58,8 @@ }, "additionalUnattendContent":[ { - "pass":"oobesystem", - "component":"Microsoft-Windows-Shell-Setup", + "passName":"oobesystem", + "componentName":"Microsoft-Windows-Shell-Setup", "settingName":"FirstLogonCommands", "content":"" } @@ -158,8 +158,8 @@ }, "additionalUnattendContent":[ { - "pass":"oobesystem", - "component":"Microsoft-Windows-Shell-Setup", + "passName":"oobesystem", + "componentName":"Microsoft-Windows-Shell-Setup", "settingName":"FirstLogonCommands", "content":"" } From af79f8f812962fd658753586783b690e89dabb88 Mon Sep 17 00:00:00 2001 From: Andrea Turli Date: Thu, 26 Oct 2017 11:49:13 +0200 Subject: [PATCH 80/87] Azure ARM fix OSProfile domain object --- .../java/org/jclouds/azurecompute/arm/domain/OSProfile.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSProfile.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSProfile.java index 3f5a0bccaf..67c1ad355b 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSProfile.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/OSProfile.java @@ -148,7 +148,7 @@ public abstract class OSProfile { public abstract String settingName(); - public abstract String content(); + @Nullable public abstract String content(); @SerializedNames({"passName", "componentName", "settingName", "content"}) public static AdditionalUnattendContent create(final String passName, final String componentName, From 8b33c4407889fdd11c06f0275a6275dcdc11f327 Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Mon, 6 Nov 2017 09:09:30 +0100 Subject: [PATCH 81/87] Add tags to virtual network creation --- .../arm/compute/strategy/CreateResourcesThenCreateNodes.java | 2 +- .../jclouds/azurecompute/arm/features/VirtualNetworkApi.java | 3 +++ .../azurecompute/arm/features/VirtualNetworkApiLiveTest.java | 2 +- .../azurecompute/arm/features/VirtualNetworkApiMockTest.java | 2 +- .../azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java | 2 +- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java index fb832c144d..e5d38fbe5f 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java @@ -159,7 +159,7 @@ public class CreateResourcesThenCreateNodes extends CreateNodesWithGroupEncodedI logger.debug(">> network options have not been configured. Creating network %s(%s) and subnet %s(%s)", name, defaultVnetAddressPrefix, name, defaultSubnetAddressPrefix); - api.getVirtualNetworkApi(options.getResourceGroup()).createOrUpdate(name, location, properties); + api.getVirtualNetworkApi(options.getResourceGroup()).createOrUpdate(name, location, null, properties); Subnet createdSubnet = api.getSubnetApi(options.getResourceGroup(), name).get(name); options.ipOptions(IpOptions.builder().subnet(createdSubnet.id()).allocateNewPublicIp(true).build()); 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 1e657f39cb..a4237ff7ad 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 @@ -16,6 +16,7 @@ */ package org.jclouds.azurecompute.arm.features; import java.util.List; +import java.util.Map; import javax.inject.Named; import javax.ws.rs.Consumes; @@ -31,6 +32,7 @@ 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.javax.annotation.Nullable; import org.jclouds.oauth.v2.filters.OAuthFilter; import org.jclouds.rest.annotations.Fallback; import org.jclouds.rest.annotations.MapBinder; @@ -57,6 +59,7 @@ public interface VirtualNetworkApi { @PUT VirtualNetwork createOrUpdate(@PathParam("virtualnetworkname") String virtualnetworkname, @PayloadParam("location") String location, + @Nullable @PayloadParam("tags") Map tags, @PayloadParam("properties")VirtualNetwork.VirtualNetworkProperties properties); @Named("virtualnetwork:get") diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApiLiveTest.java index 4459a1e208..c0271d3961 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualNetworkApiLiveTest.java @@ -55,7 +55,7 @@ public class VirtualNetworkApiLiveTest extends BaseAzureComputeApiLiveTest { VirtualNetwork.VirtualNetworkProperties.builder().addressSpace( VirtualNetwork.AddressSpace.create(Arrays.asList(DEFAULT_VIRTUALNETWORK_ADDRESS_PREFIX))).build(); - VirtualNetwork vn = api().createOrUpdate(virtualNetworkName, LOCATION, virtualNetworkProperties); + VirtualNetwork vn = api().createOrUpdate(virtualNetworkName, LOCATION, null, virtualNetworkProperties); assertEquals(vn.name(), virtualNetworkName); assertEquals(vn.location(), LOCATION); 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 79b48ef3db..8ba0406088 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); - vnApi.createOrUpdate(virtualNetwork, location, virtualNetworkProperties); + vnApi.createOrUpdate(virtualNetwork, location, null, 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/internal/BaseAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java index 90502fe8e0..f439315174 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java @@ -132,7 +132,7 @@ public class BaseAzureComputeApiLiveTest extends BaseApiLiveTest() { @Override public boolean apply(final String name) { From 7368d58ad9534aaea2800860c07d311ff15d98d2 Mon Sep 17 00:00:00 2001 From: jucolon Date: Thu, 10 Aug 2017 16:17:39 -0400 Subject: [PATCH 82/87] JCLOUDS-1342 : Azure-ARM Virtual Machine Scale Set Support --- .../azurecompute/arm/AzureComputeApi.java | 39 +- .../arm/AzureComputeProviderMetadata.java | 20 +- .../azurecompute/arm/domain/Extension.java | 40 ++ .../arm/domain/ExtensionProfile.java | 39 ++ .../arm/domain/ExtensionProfileSettings.java | 42 ++ .../arm/domain/ExtensionProperties.java | 70 +++ .../arm/domain/NetworkInterfaceCard.java | 3 +- .../NetworkInterfaceCardProperties.java | 3 +- .../domain/NetworkInterfaceConfiguration.java | 44 ++ ...tworkInterfaceConfigurationProperties.java | 68 +++ .../NetworkSecurityGroupProperties.java | 3 +- .../arm/domain/VirtualMachine.java | 16 +- .../arm/domain/VirtualMachineScaleSet.java | 110 +++++ .../VirtualMachineScaleSetDNSSettings.java | 41 ++ ...VirtualMachineScaleSetIpConfiguration.java | 61 +++ ...hineScaleSetIpConfigurationProperties.java | 118 +++++ .../VirtualMachineScaleSetNetworkProfile.java | 58 +++ ...alMachineScaleSetNetworkSecurityGroup.java | 39 ++ .../VirtualMachineScaleSetOSProfile.java | 277 +++++++++++ .../domain/VirtualMachineScaleSetPlan.java | 51 ++ .../VirtualMachineScaleSetProperties.java | 106 ++++ ...eScaleSetPublicIPAddressConfiguration.java | 59 +++ ...hineScaleSetPublicIPAddressProperties.java | 54 +++ .../arm/domain/VirtualMachineScaleSetSKU.java | 45 ++ .../VirtualMachineScaleSetUpgradeMode.java | 35 ++ .../VirtualMachineScaleSetUpgradePolicy.java | 35 ++ ...lMachineScaleSetVirtualMachineProfile.java | 83 ++++ .../features/VirtualMachineScaleSetApi.java | 88 ++++ .../VirtualMachineScaleSetApiLiveTest.java | 297 ++++++++++++ .../VirtualMachineScaleSetApiMockTest.java | 453 ++++++++++++++++++ .../internal/BaseAzureComputeApiMockTest.java | 1 + .../src/test/resources/virtualmachine.json | 1 - .../resources/virtualmachinescalesetget.json | 64 +++ .../virtualmachinescalesetgetwhen404.json | 6 + .../resources/virtualmachinescalesetlist.json | 93 ++++ .../virtualmachinescalesetlistwhen404.json | 6 + ...machinescalesetresponsecreateorupdate.json | 103 ++++ 37 files changed, 2635 insertions(+), 36 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Extension.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ExtensionProfile.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ExtensionProfileSettings.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ExtensionProperties.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceConfiguration.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceConfigurationProperties.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSet.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetDNSSettings.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetIpConfiguration.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetIpConfigurationProperties.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetNetworkProfile.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetNetworkSecurityGroup.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetOSProfile.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetPlan.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetProperties.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetPublicIPAddressConfiguration.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetPublicIPAddressProperties.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetSKU.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetUpgradeMode.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetUpgradePolicy.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetVirtualMachineProfile.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualMachineScaleSetApi.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineScaleSetApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineScaleSetApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/resources/virtualmachinescalesetget.json create mode 100644 providers/azurecompute-arm/src/test/resources/virtualmachinescalesetgetwhen404.json create mode 100644 providers/azurecompute-arm/src/test/resources/virtualmachinescalesetlist.json create mode 100644 providers/azurecompute-arm/src/test/resources/virtualmachinescalesetlistwhen404.json create mode 100644 providers/azurecompute-arm/src/test/resources/virtualmachinescalesetresponsecreateorupdate.json 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 123f6e326e..86235804f1 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 @@ -20,27 +20,28 @@ import java.io.Closeable; import javax.ws.rs.PathParam; -import org.jclouds.azurecompute.arm.features.AvailabilitySetApi; -import org.jclouds.azurecompute.arm.features.DeploymentApi; -import org.jclouds.azurecompute.arm.features.DiskApi; -import org.jclouds.azurecompute.arm.features.ImageApi; import org.jclouds.azurecompute.arm.features.JobApi; -import org.jclouds.azurecompute.arm.features.LoadBalancerApi; import org.jclouds.azurecompute.arm.features.LocationApi; -import org.jclouds.azurecompute.arm.features.MetricDefinitionsApi; -import org.jclouds.azurecompute.arm.features.MetricsApi; -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.NetworkInterfaceCardApi; +import org.jclouds.azurecompute.arm.features.PublicIPAddressApi; +import org.jclouds.azurecompute.arm.features.VirtualMachineApi; +import org.jclouds.azurecompute.arm.features.VirtualMachineScaleSetApi; +import org.jclouds.azurecompute.arm.features.VMSizeApi; +import org.jclouds.azurecompute.arm.features.OSImageApi; +import org.jclouds.azurecompute.arm.features.DeploymentApi; +import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi; +import org.jclouds.azurecompute.arm.features.NetworkSecurityRuleApi; +import org.jclouds.azurecompute.arm.features.LoadBalancerApi; +import org.jclouds.azurecompute.arm.features.AvailabilitySetApi; +import org.jclouds.azurecompute.arm.features.ResourceProviderApi; +import org.jclouds.azurecompute.arm.features.DiskApi; +import org.jclouds.azurecompute.arm.features.ImageApi; +import org.jclouds.azurecompute.arm.features.MetricsApi; +import org.jclouds.azurecompute.arm.features.MetricDefinitionsApi; import org.jclouds.rest.annotations.Delegate; /** @@ -124,6 +125,14 @@ public interface AzureComputeApi extends Closeable { @Delegate VirtualMachineApi getVirtualMachineApi(@PathParam("resourceGroup") String resourceGroup); + /** + * The Virtual Machine Scale Set API includes operations for managing the virtual machines in your subscription. + * + * @see docs + */ + @Delegate + VirtualMachineScaleSetApi getVirtualMachineScaleSetApi(@PathParam("resourceGroup") String resourceGroup); + /** * This Azure Resource Manager API lists all available virtual machine sizes for a subscription in a given region * 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 eb52746575..8849a1fb89 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 @@ -38,26 +38,27 @@ import java.net.URI; import java.util.Properties; import org.jclouds.azurecompute.arm.domain.Region; -import org.jclouds.azurecompute.arm.features.AvailabilitySetApi; import org.jclouds.azurecompute.arm.features.DeploymentApi; -import org.jclouds.azurecompute.arm.features.ImageApi; -import org.jclouds.azurecompute.arm.features.LoadBalancerApi; import org.jclouds.azurecompute.arm.features.LocationApi; -import org.jclouds.azurecompute.arm.features.DiskApi; -import org.jclouds.azurecompute.arm.features.MetricDefinitionsApi; -import org.jclouds.azurecompute.arm.features.MetricsApi; 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.PublicIPAddressApi; 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.VirtualNetworkApi; 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.LoadBalancerApi; +import org.jclouds.azurecompute.arm.features.AvailabilitySetApi; +import org.jclouds.azurecompute.arm.features.DiskApi; +import org.jclouds.azurecompute.arm.features.ImageApi; +import org.jclouds.azurecompute.arm.features.MetricDefinitionsApi; +import org.jclouds.azurecompute.arm.features.MetricsApi; +import org.jclouds.azurecompute.arm.features.VirtualMachineScaleSetApi; import org.jclouds.providers.ProviderMetadata; import org.jclouds.providers.internal.BaseProviderMetadata; @@ -122,7 +123,8 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { properties.put(API_VERSION_PREFIX + ImageApi.class.getSimpleName(), "2016-04-30-preview"); properties.put(API_VERSION_PREFIX + MetricDefinitionsApi.class.getSimpleName(), "2017-05-01-preview"); properties.put(API_VERSION_PREFIX + MetricsApi.class.getSimpleName(), "2016-09-01"); - + properties.put(API_VERSION_PREFIX + VirtualMachineScaleSetApi.class.getSimpleName(), "2017-03-30"); + return properties; } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Extension.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Extension.java new file mode 100644 index 0000000000..5eafb04e74 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Extension.java @@ -0,0 +1,40 @@ +/* + * 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 org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class Extension { + + /** + * The name reference of the extension profile + */ + public abstract String name(); + + /** + * The properties reference of the extension profile + */ + public abstract ExtensionProperties properties(); + + + @SerializedNames({"name", "properties"}) + public static Extension create(final String name, final ExtensionProperties properties) { + return new AutoValue_Extension(name, properties); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ExtensionProfile.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ExtensionProfile.java new file mode 100644 index 0000000000..92ab4fb559 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ExtensionProfile.java @@ -0,0 +1,39 @@ +/* + * 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 ExtensionProfile { + + /** + * The list of extensions of the extension profile + */ + public abstract List extensions(); + + + @SerializedNames({"extensions"}) + public static ExtensionProfile create(final List extensions) { + return new AutoValue_ExtensionProfile(extensions == null ? + ImmutableList.of() : ImmutableList.copyOf(extensions)); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ExtensionProfileSettings.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ExtensionProfileSettings.java new file mode 100644 index 0000000000..265bf7689e --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ExtensionProfileSettings.java @@ -0,0 +1,42 @@ +/* + * 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 ExtensionProfileSettings { + + /** + * The fileUris reference of the extension profile settings + */ + public abstract List fileUris(); + + /** + * The commandToExecute of the extension profile settings + */ + public abstract String commandToExecute(); + + @SerializedNames({"fileUris", "commandToExecute"}) + public static ExtensionProfileSettings create(final List fileUris, final String commandToExecute) { + return new AutoValue_ExtensionProfileSettings(fileUris == null ? ImmutableList.of() : ImmutableList.copyOf(fileUris), commandToExecute); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ExtensionProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ExtensionProperties.java new file mode 100644 index 0000000000..d4e8b7fe38 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ExtensionProperties.java @@ -0,0 +1,70 @@ +/* + * 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.ImmutableMap; +import org.jclouds.json.SerializedNames; + +import java.util.Map; + +@AutoValue +public abstract class ExtensionProperties { + + /** + * The publisher reference of the extension properties + */ + public abstract String publisher(); + + /** + * The type reference of the extension properties + */ + public abstract String type(); + + /** + * The typeHandlerVersion reference of the extension properties + */ + public abstract String typeHandlerVersion(); + + /** + * The autoUpgradeMinorVersion reference of the extension properties + */ + public abstract Boolean autoUpgradeMinorVersion(); + + /** + * The ExtensionProfileSettings of the extension properties + */ + public abstract ExtensionProfileSettings settings(); + + /** + * The list of the protectedSettings of the extension properties + */ + public abstract Map protectedSettings(); + + @SerializedNames({ "publisher", "type", "typeHandlerVersion", + "autoUpgradeMinorVersion", "settings", "protectedSettings"}) + public static ExtensionProperties create(final String publisher, String type, + final String typeHandlerVersion, + final Boolean autoUpgradeMinorVersion, + final ExtensionProfileSettings settings, + final Map protectedSettings) { + return new AutoValue_ExtensionProperties(publisher, type, typeHandlerVersion, autoUpgradeMinorVersion, + settings, protectedSettings == null ? + ImmutableMap.of() : ImmutableMap.copyOf(protectedSettings)); + } +} + diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCard.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCard.java index 567addc553..66bc1a3780 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCard.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCard.java @@ -51,6 +51,7 @@ public abstract class NetworkInterfaceCard { final String location, final NetworkInterfaceCardProperties properties, final Map tags) { - return new AutoValue_NetworkInterfaceCard(name, id, etag, location, properties, tags == null ? null : ImmutableMap.copyOf(tags)); + return new AutoValue_NetworkInterfaceCard(name, id, etag, location, properties, + tags != null ? ImmutableMap.copyOf(tags) : null); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCardProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCardProperties.java index 84c8ca2c38..680d0a2350 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCardProperties.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceCardProperties.java @@ -32,7 +32,8 @@ public abstract class NetworkInterfaceCardProperties implements Provisionable { @Nullable public abstract List ipConfigurations(); @Nullable public abstract IdReference networkSecurityGroup(); - @SerializedNames({"provisioningState", "resourceGuid", "enableIPForwarding", "ipConfigurations", "networkSecurityGroup"}) + @SerializedNames({"provisioningState", "resourceGuid", "enableIPForwarding", "ipConfigurations", + "networkSecurityGroup"}) public static NetworkInterfaceCardProperties create(final String provisioningState, final String resourceGuid, final Boolean enableIPForwarding, final List ipConfigurations, final IdReference networkSecurityGroup) { diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceConfiguration.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceConfiguration.java new file mode 100644 index 0000000000..b2e81b2040 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceConfiguration.java @@ -0,0 +1,44 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class NetworkInterfaceConfiguration { + /** + * The name of the NetworkInterfaceConfiguration + */ + @Nullable + public abstract String name(); + + /** + * The networkConfigurationProperties of the NetworkInterfaceConfiguration + */ + @Nullable + public abstract NetworkInterfaceConfigurationProperties networkInterfaceConfigurationProperties(); + + @SerializedNames({"name", "properties"}) + public static NetworkInterfaceConfiguration create( + final String name, NetworkInterfaceConfigurationProperties networkInterfaceConfigurationProperties) { + + return new AutoValue_NetworkInterfaceConfiguration(name, networkInterfaceConfigurationProperties); + } + +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceConfigurationProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceConfigurationProperties.java new file mode 100644 index 0000000000..85518b84be --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkInterfaceConfigurationProperties.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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import java.util.List; + + +@AutoValue +public abstract class NetworkInterfaceConfigurationProperties { + /** + * The primary of the NetworkInterfaceConfigurationProperties + */ + @Nullable + public abstract Boolean primary(); + + /** + * The enableAcceleratedNetworking of the NetworkInterfaceConfigurationProperties + */ + @Nullable + public abstract Boolean enableAcceleratedNetworking(); + + /** + * The networkSecurityGroup of the NetworkInterfaceConfigurationProperties + */ + @Nullable + public abstract VirtualMachineScaleSetNetworkSecurityGroup networkSecurityGroup(); + + /** + * The dnsSettings of the NetworkInterfaceConfigurationProperties + */ + @Nullable + public abstract VirtualMachineScaleSetDNSSettings dnsSettings(); + + /** + * The ipConfigurations of the NetworkInterfaceConfigurationProperties + */ + public abstract List ipConfigurations(); + + + @SerializedNames({"primary", "enableAcceleratedNetworking", "networkSecurityGroup", "dnsSettings", "ipConfigurations"}) + public static NetworkInterfaceConfigurationProperties create(final Boolean primary, + final Boolean enableAcceleratedNetworking, + final VirtualMachineScaleSetNetworkSecurityGroup networkSecurityGroup, + final VirtualMachineScaleSetDNSSettings dnsSettings, + final List ipConfigurations) { + + return new AutoValue_NetworkInterfaceConfigurationProperties(primary, enableAcceleratedNetworking, + networkSecurityGroup, dnsSettings, ipConfigurations); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityGroupProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityGroupProperties.java index bbc27460e4..60fb2e62d8 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityGroupProperties.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/NetworkSecurityGroupProperties.java @@ -45,7 +45,8 @@ public abstract class NetworkSecurityGroupProperties implements Provisionable { @Nullable public abstract String provisioningState(); - @SerializedNames({"securityRules", "defaultSecurityRules", "networkInterfaces", "subnets", "resourceGuid", "provisioningState"}) + @SerializedNames({"securityRules", "defaultSecurityRules", "networkInterfaces", "subnets", "resourceGuid", + "provisioningState"}) public static NetworkSecurityGroupProperties create(final List securityRules, final List defaultSecurityRules, final List networkInterfaces, 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 86810e55ad..c0224f34a4 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 @@ -60,7 +60,7 @@ public abstract class VirtualMachine { * Specifies the properties of the vm */ public abstract VirtualMachineProperties properties(); - + /** * Specifies the plan, for marketplace images */ @@ -69,20 +69,20 @@ public abstract class VirtualMachine { @SerializedNames({"id", "name", "type", "location", "tags", "properties", "plan"}) public static VirtualMachine create(final String id, final String name, final String type, final String location, - @Nullable final Map tags, VirtualMachineProperties properties, @Nullable Plan plan) { + @Nullable final Map tags, VirtualMachineProperties properties, @Nullable Plan plan) { return builder().id(id).name(name).type(type).location(location).tags(tags).properties(properties).plan(plan) - .build(); + .build(); } - + public abstract Builder toBuilder(); - + public static Builder builder() { return new AutoValue_VirtualMachine.Builder(); } - + @AutoValue.Builder public abstract static class Builder { - + public abstract Builder id(String id); public abstract Builder name(String name); public abstract Builder type(String type); @@ -90,7 +90,7 @@ public abstract class VirtualMachine { public abstract Builder tags(Map tags); public abstract Builder properties(VirtualMachineProperties properties); public abstract Builder plan(Plan plan); - + abstract Map tags(); abstract VirtualMachine autoBuild(); diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSet.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSet.java new file mode 100644 index 0000000000..2fc3f597f8 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSet.java @@ -0,0 +1,110 @@ +/* + * 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.ImmutableMap; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import java.util.Map; + +/** + * VirtualMachineScaleSet for subscription + */ +@AutoValue +public abstract class VirtualMachineScaleSet { + + /** + * The id of the virtual machine scale set + */ + @Nullable + public abstract String id(); + + /** + * The name of the virtual machine scale set + */ + @Nullable + public abstract String name(); + + /** + * The location of the virtual machine scale set + */ + @Nullable + public abstract String location(); + + /** + * Specifies the sku of the virtual machine scale set + */ + public abstract VirtualMachineScaleSetSKU sku(); + + /** + * Specifies the tags of the virtual machine scale set + */ + @Nullable + public abstract Map tags(); + + + /** + * Specifies the optional plan of the virtual machine scale set (only for market image) + */ + @Nullable + public abstract VirtualMachineScaleSetPlan plan(); + + /** + * Specifies the properties of the availability set + */ + @Nullable + public abstract VirtualMachineScaleSetProperties properties(); + + @SerializedNames({ "id", "name", "location", "sku", "tags", "plan", "properties"}) + public static VirtualMachineScaleSet create(final String id, final String name, final String location, + VirtualMachineScaleSetSKU sku, final Map tags, + VirtualMachineScaleSetPlan plan, + VirtualMachineScaleSetProperties properties) { + return builder().id(id).name(name).location(location).sku(sku).tags(tags) + .plan(plan).properties(properties) + .build(); + } + + public abstract Builder toBuilder(); + + private static Builder builder() { + return new AutoValue_VirtualMachineScaleSet.Builder(); + } + + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder id(String id); + public abstract Builder name(String name); + public abstract Builder location(String location); + public abstract Builder sku(VirtualMachineScaleSetSKU sku); + public abstract Builder tags(Map tags); + public abstract Builder plan(VirtualMachineScaleSetPlan plan); + public abstract Builder properties(VirtualMachineScaleSetProperties properties); + + abstract Map tags(); + abstract VirtualMachineScaleSet autoBuild(); + + public VirtualMachineScaleSet build() { + tags(tags() != null ? ImmutableMap.copyOf(tags()) : null); + return autoBuild(); + } + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetDNSSettings.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetDNSSettings.java new file mode 100644 index 0000000000..d91c68bd58 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetDNSSettings.java @@ -0,0 +1,41 @@ +/* + * 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; + +/** + * VirtualMachineScaleSetDNSSettings + */ +@AutoValue +public abstract class VirtualMachineScaleSetDNSSettings { + /** + * The list of DNS servers of the Virtual Machine Scale Set DNS Settings + */ + public abstract List dnsServers(); + + @SerializedNames({"dnsServers"}) + public static VirtualMachineScaleSetDNSSettings create(final List dnsServers) { + + return new AutoValue_VirtualMachineScaleSetDNSSettings( + dnsServers == null ? ImmutableList.of() : ImmutableList.copyOf(dnsServers)); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetIpConfiguration.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetIpConfiguration.java new file mode 100644 index 0000000000..257072e162 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetIpConfiguration.java @@ -0,0 +1,61 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class VirtualMachineScaleSetIpConfiguration { + + /** + * The name of the Virtual Machine Scale Set Ip Configuration + */ + @Nullable + public abstract String name(); + + /** + * The properties of the Virtual Machine Scale Set Ip Configuration + */ + @Nullable + public abstract VirtualMachineScaleSetIpConfigurationProperties properties(); + + @SerializedNames({"name", "properties"}) + public static VirtualMachineScaleSetIpConfiguration create( + final String name, + final VirtualMachineScaleSetIpConfigurationProperties properties) { + return builder() + .name(name) + .properties(properties) + .build(); + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_VirtualMachineScaleSetIpConfiguration.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder name(String name); + public abstract Builder properties(VirtualMachineScaleSetIpConfigurationProperties properties); + public abstract VirtualMachineScaleSetIpConfiguration build(); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetIpConfigurationProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetIpConfigurationProperties.java new file mode 100644 index 0000000000..ee23152e94 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetIpConfigurationProperties.java @@ -0,0 +1,118 @@ +/* + * 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.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import java.util.List; + +@AutoValue +public abstract class VirtualMachineScaleSetIpConfigurationProperties { + + /** + * The public IP address configuration of the Virtual Machine Scale Set Ip Configuration Properties + */ + @Nullable + public abstract VirtualMachineScaleSetPublicIPAddressConfiguration publicIPAddressConfiguration(); + + /** + * The subnet of the Virtual Machine Scale Set Ip Configuration Properties + */ + public abstract Subnet subnet(); + + /** + * The private IP address version of the Virtual Machine Scale Set Ip Configuration Properties + */ + @Nullable + public abstract String privateIPAddressVersion(); + + /** + * The load balancer backend address pools of the Virtual Machine Scale Set Ip Configuration Properties + */ + public abstract List loadBalancerBackendAddressPools(); + + /** + * The load balancer inbound nat pools of the Virtual Machine Scale Set Ip Configuration Properties + */ + public abstract List loadBalancerInboundNatPools(); + + /** + * The application gateway backend address Pools of the Virtual Machine Scale Set Ip Configuration Properties + */ + @Nullable + public abstract String applicationGatewayBackendAddressPools(); + + @SerializedNames({"publicIPAddressConfiguration", "subnet", "privateIPAddressVersion", + "loadBalancerBackendAddressPools", "loadBalancerInboundNatPools", "applicationGatewayBackendAddressPools"}) + public static VirtualMachineScaleSetIpConfigurationProperties create( + final VirtualMachineScaleSetPublicIPAddressConfiguration publicIPAddressConfiguration, + final Subnet subnet, + final String privateIPAddressVersion, + final List loadBalancerBackendAddressPools, + final List loadBalancerInboundNatPools, + final String applicationGatewayBackendAddressPools) + + { + + return builder() + .publicIPAddressConfiguration(publicIPAddressConfiguration) + .subnet(subnet) + .privateIPAddressVersion(privateIPAddressVersion) + .lbBackendAddressPools(loadBalancerBackendAddressPools) + .lbInboundNatPools(loadBalancerInboundNatPools) + .applicationGatewayBackendAddressPools(applicationGatewayBackendAddressPools) + .build(); + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_VirtualMachineScaleSetIpConfigurationProperties.Builder() + .lbBackendAddressPools(null) + .lbInboundNatPools(null); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder publicIPAddressConfiguration(VirtualMachineScaleSetPublicIPAddressConfiguration publicIPAddressConfiguration); + + public abstract Builder subnet(Subnet subnet); + + public abstract Builder loadBalancerBackendAddressPools(List loadBalancerBackendAddressPools); + + public abstract Builder loadBalancerInboundNatPools(List loadBalancerInboundNatPools); + + public abstract Builder privateIPAddressVersion(String privateIPAddressVersion); + + public Builder lbBackendAddressPools(List loadBalancerBackendAddressPools) { + return loadBalancerBackendAddressPools(loadBalancerBackendAddressPools != null ? ImmutableList + .copyOf(loadBalancerBackendAddressPools) : ImmutableList.of()); + } + public Builder lbInboundNatPools(List loadBalancerInboundNatPools) { + return loadBalancerInboundNatPools(loadBalancerInboundNatPools != null ? ImmutableList + .copyOf(loadBalancerInboundNatPools) : ImmutableList.of()); + } + + public abstract Builder applicationGatewayBackendAddressPools(String applicationGatewayBackendAddressPools); + public abstract VirtualMachineScaleSetIpConfigurationProperties build(); + + } +} + diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetNetworkProfile.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetNetworkProfile.java new file mode 100644 index 0000000000..9d4c462da5 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetNetworkProfile.java @@ -0,0 +1,58 @@ +/* + * 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 VirtualMachineScaleSetNetworkProfile { + + /** + * The network interface configurations of the Virtual Machine Scale Set Network Profile + */ + public abstract List networkInterfaceConfigurations(); + + + @SerializedNames({"networkInterfaceConfigurations"}) + public static VirtualMachineScaleSetNetworkProfile create( + final List networkInterfaceConfigurations) { + return builder() + .networkInterfaceConfigurations(networkInterfaceConfigurations == null ? + ImmutableList.of() : ImmutableList.copyOf(networkInterfaceConfigurations) ) + .build(); + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_VirtualMachineScaleSetNetworkProfile.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + + public abstract Builder networkInterfaceConfigurations( + List networkInterfaceConfigurations); + + public abstract VirtualMachineScaleSetNetworkProfile build(); + + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetNetworkSecurityGroup.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetNetworkSecurityGroup.java new file mode 100644 index 0000000000..8874d5051d --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetNetworkSecurityGroup.java @@ -0,0 +1,39 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +/** + * Virtual Machine Scale Set Network Security Group + */ +@AutoValue +public abstract class VirtualMachineScaleSetNetworkSecurityGroup { + /** + * The id of the Virtual Machine Scale Set Network Security Group + */ + @Nullable + public abstract String id(); + + @SerializedNames({"id"}) + public static VirtualMachineScaleSetNetworkSecurityGroup create(final String id) { + + return new AutoValue_VirtualMachineScaleSetNetworkSecurityGroup(id); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetOSProfile.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetOSProfile.java new file mode 100644 index 0000000000..5593457163 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetOSProfile.java @@ -0,0 +1,277 @@ +/* + * 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.azurecompute.arm.util.GetEnumValue; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import java.util.List; + +@AutoValue +public abstract class VirtualMachineScaleSetOSProfile { + + @AutoValue + public abstract static class LinuxConfiguration { + + + @AutoValue + public abstract static class SSH { + + @AutoValue + public abstract static class SSHPublicKey { + + /** + * The path for the SSH public key + */ + @Nullable + public abstract String path(); + + /** + * The key data for the SSH public key + */ + @Nullable + public abstract String keyData(); + + @SerializedNames({"path", "keyData"}) + public static SSHPublicKey create(final String path, final String keyData) { + + return new AutoValue_VirtualMachineScaleSetOSProfile_LinuxConfiguration_SSH_SSHPublicKey( + path, keyData); + } + } + + /** + * The list of public keys and paths + */ + @Nullable + public abstract List publicKeys(); + + @SerializedNames({"publicKeys"}) + public static SSH create(final List publicKeys) { + + return new AutoValue_VirtualMachineScaleSetOSProfile_LinuxConfiguration_SSH( + publicKeys); + } + } + + /** + * The authentication method password or ssh + */ + public abstract Boolean disablePasswordAuthentication(); + + /** + * ssh keys + */ + @Nullable + public abstract SSH ssh(); + + @SerializedNames({"disablePasswordAuthentication", "ssh"}) + public static LinuxConfiguration create(final Boolean disablePasswordAuthentication, + final SSH ssh) { + + return new AutoValue_VirtualMachineScaleSetOSProfile_LinuxConfiguration(disablePasswordAuthentication, + ssh); + } + } + + @AutoValue + public abstract static class WindowsConfiguration { + + @AutoValue + public abstract static class WinRM { + public enum Protocol { + + HTTP("http"), + HTTPS("https"), + UNRECOGNIZED("Unrecognized"); + + private String value; + + Protocol(String value) { + this.value = value; + } + + public static Protocol fromValue(String value) { + return (Protocol) GetEnumValue.fromValueOrDefault(value, Protocol.UNRECOGNIZED); + } + + @Override + public String toString() { + return this.value; + } + } + + @AutoValue + public abstract static class ProtocolListener { + + /** + * The protocol for the protcol listener + */ + public abstract Protocol protocol(); + + /** + * The certificate url or the protcol listener + */ + @Nullable + public abstract String certificateUrl(); + + @SerializedNames({"protocol", "certificateUrl"}) + public static ProtocolListener create(final Protocol protocol, final String certificateUrl) { + + return new AutoValue_VirtualMachineScaleSetOSProfile_WindowsConfiguration_WinRM_ProtocolListener( + protocol, certificateUrl); + } + } + + /** + * Map of different settings + */ + public abstract List listeners(); + + @SerializedNames({"listeners"}) + public static WinRM create(final List listeners) { + return new AutoValue_VirtualMachineScaleSetOSProfile_WindowsConfiguration_WinRM(listeners == null ? ImmutableList.of() : ImmutableList.copyOf(listeners)); + } + } + + @AutoValue + public abstract static class AdditionalUnattendContent { + + public abstract String pass(); + + public abstract String component(); + + public abstract String settingName(); + + public abstract String content(); + + @SerializedNames({"pass", "component", "settingName", "content"}) + public static AdditionalUnattendContent create(final String pass, final String component, + final String settingName, + final String content) { + + return new AutoValue_VirtualMachineScaleSetOSProfile_WindowsConfiguration_AdditionalUnattendContent( + pass, component, settingName, content); + } + } + + /** + * The provision VM Agent true of false. + */ + public abstract boolean provisionVMAgent(); + + /** + * winRM + */ + @Nullable + public abstract WinRM winRM(); + + /** + * unattend content + */ + public abstract List additionalUnattendContent(); + + /** + * is automatic updates enabled + */ + public abstract boolean enableAutomaticUpdates(); + + @SerializedNames({"provisionVMAgent", "winRM", "additionalUnattendContent", "enableAutomaticUpdates"}) + public static WindowsConfiguration create(final boolean provisionVMAgent, final WinRM winRM, + final List additionalUnattendContent, + final boolean enableAutomaticUpdates) { + + return new AutoValue_VirtualMachineScaleSetOSProfile_WindowsConfiguration(provisionVMAgent, winRM, + additionalUnattendContent == null ? ImmutableList.of() : ImmutableList.copyOf(additionalUnattendContent), enableAutomaticUpdates); + } + } + + /** + * The computer name of the VM + */ + @Nullable + public abstract String computerNamePrefix(); + + /** + * The admin username of the VM + */ + @Nullable + public abstract String adminUsername(); + + /** + * The admin password of the VM + */ + @Nullable + public abstract String adminPassword(); + + /** + * The linux configuration of the VM + */ + @Nullable + public abstract LinuxConfiguration linuxConfiguration(); + + /** + * The windows configuration of the VM + */ + @Nullable + public abstract WindowsConfiguration windowsConfiguration(); + + /** + * The Secrets configuration of the VM + */ + public abstract List secrets(); + + @SerializedNames({"computerNamePrefix", "adminUsername", "adminPassword", "linuxConfiguration", + "windowsConfiguration", "secrets"}) + public static VirtualMachineScaleSetOSProfile create(final String computerNamePrefix, final String adminUsername, + final String adminPassword, final LinuxConfiguration linuxConfiguration, + final WindowsConfiguration windowsConfiguration, final List secrets) { + return builder() + .computerNamePrefix(computerNamePrefix) + .adminUsername(adminUsername) + .adminPassword(adminPassword) + .linuxConfiguration(linuxConfiguration) + .windowsConfiguration(windowsConfiguration) + ._secrets(secrets) + .build(); + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_VirtualMachineScaleSetOSProfile.Builder()._secrets(null); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder computerNamePrefix(String computerNamePrefix); + public abstract Builder adminUsername(String adminUsername); + public abstract Builder adminPassword(String adminPassword); + public abstract Builder linuxConfiguration(LinuxConfiguration linuxConfiguration); + public abstract Builder windowsConfiguration(WindowsConfiguration windowsConfiguration); + public abstract Builder secrets(List secrets); + + public Builder _secrets(List secrets) { + return secrets(secrets != null ? ImmutableList.copyOf(secrets) : ImmutableList.of()); + } + + public abstract VirtualMachineScaleSetOSProfile build(); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetPlan.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetPlan.java new file mode 100644 index 0000000000..1864ca7955 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetPlan.java @@ -0,0 +1,51 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +/** + * SKU + */ +@AutoValue +public abstract class VirtualMachineScaleSetPlan { + /** + * The name of the Virtual Machine Scale Set Plan + */ + @Nullable + public abstract String name(); + + /** + * The publisher of the Virtual Machine Scale Set Plan + */ + @Nullable + public abstract String publisher(); + + /** + * The product of the Virtual Machine Scale Set Plan + */ + @Nullable + public abstract String product(); + + @SerializedNames({"name", "publisher", "product"}) + public static VirtualMachineScaleSetPlan create(final String name, final String publisher, final String product) { + + return new AutoValue_VirtualMachineScaleSetPlan(name, publisher, product); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetProperties.java new file mode 100644 index 0000000000..d7370860ac --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetProperties.java @@ -0,0 +1,106 @@ +/* + * 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 org.jclouds.azurecompute.arm.util.GetEnumValue; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + + +@AutoValue +public abstract class VirtualMachineScaleSetProperties { + + 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 singlePlacementGroup of the VirtualMachineScaleSetProperties + */ + @Nullable + public abstract Boolean singlePlacementGroup(); + + /** + * Specifies the over provision of the virtual machine scale set + */ + @Nullable + public abstract Boolean overProvision(); + + /** + * Specifies the upgrade policy of the virtual machine scale set + */ + public abstract VirtualMachineScaleSetUpgradePolicy upgradePolicy(); + + /** + * Specifies the state of the provision of the virtual machine scale set + */ + @Nullable + public abstract ProvisioningState provisioningState(); + + /** + * Specifies the virtual machine profile of the virtual machine scale set + */ + public abstract VirtualMachineScaleSetVirtualMachineProfile virtualMachineProfile(); + + @SerializedNames({"singlePlacementGroup", "overProvision", "upgradePolicy", "provisioningState", "virtualMachineProfile"}) + public static VirtualMachineScaleSetProperties create( + final Boolean singlePlacementGroup, + final Boolean overProvision, + final VirtualMachineScaleSetUpgradePolicy upgradePolicy, + final ProvisioningState provisioningState, + final VirtualMachineScaleSetVirtualMachineProfile virtualMachineProfile) { + return builder().singlePlacementGroup(singlePlacementGroup).overProvision(overProvision). + upgradePolicy(upgradePolicy).provisioningState(provisioningState).virtualMachineProfile(virtualMachineProfile).build(); + } + + public abstract Builder toBuilder(); + + private static Builder builder() { + return new AutoValue_VirtualMachineScaleSetProperties.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder singlePlacementGroup(Boolean singlePlacementGroup); + + public abstract Builder overProvision(Boolean overProvision); + + public abstract Builder upgradePolicy(VirtualMachineScaleSetUpgradePolicy upgradePolicy); + + public abstract Builder provisioningState(ProvisioningState provisioningState); + + public abstract Builder virtualMachineProfile(VirtualMachineScaleSetVirtualMachineProfile virtualMachineProfile); + + public abstract VirtualMachineScaleSetProperties build(); + } +} + + diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetPublicIPAddressConfiguration.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetPublicIPAddressConfiguration.java new file mode 100644 index 0000000000..3347713461 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetPublicIPAddressConfiguration.java @@ -0,0 +1,59 @@ +/* + * 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 org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class VirtualMachineScaleSetPublicIPAddressConfiguration { + + /** + * The name of the Virtual Machine Scale Set Public IP Address Configuration + */ + public abstract String name(); + + /** + * The properties of the Virtual Machine Scale Set Public IP Address Configuration + */ + public abstract VirtualMachineScaleSetPublicIPAddressProperties properties(); + + @SerializedNames({ "name", "properties" }) + public static VirtualMachineScaleSetPublicIPAddressConfiguration create( + String name, + VirtualMachineScaleSetPublicIPAddressProperties properties) { + return builder().name(name).properties(properties).build(); + } + + VirtualMachineScaleSetPublicIPAddressConfiguration() { + + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_VirtualMachineScaleSetPublicIPAddressConfiguration.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder name(String name); + public abstract Builder properties(VirtualMachineScaleSetPublicIPAddressProperties properties); + public abstract VirtualMachineScaleSetPublicIPAddressConfiguration build(); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetPublicIPAddressProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetPublicIPAddressProperties.java new file mode 100644 index 0000000000..d01e305f85 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetPublicIPAddressProperties.java @@ -0,0 +1,54 @@ +/* + * 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 org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class VirtualMachineScaleSetPublicIPAddressProperties { + + /** + * The idle timeout (in minutes) of the Virtual Machine Scale Set Public IP Address Configuration + */ + @Nullable + public abstract Integer idleTimeoutInMinutes(); + + + @SerializedNames({ "idleTimeoutInMinutes" }) + public static VirtualMachineScaleSetPublicIPAddressProperties create(final Integer idleTimeoutInMinutes) { + return builder() + .idleTimeoutInMinutes(idleTimeoutInMinutes) + .build(); + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_VirtualMachineScaleSetPublicIPAddressProperties.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + + public abstract Builder idleTimeoutInMinutes(Integer idleTimeoutInMinutes); + + public abstract VirtualMachineScaleSetPublicIPAddressProperties build(); + } + +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetSKU.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetSKU.java new file mode 100644 index 0000000000..251562dffe --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetSKU.java @@ -0,0 +1,45 @@ +/* + * 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 org.jclouds.json.SerializedNames; + + +@AutoValue +public abstract class VirtualMachineScaleSetSKU { + /** + * The name of the Virtual Machine Scale Set SKU + */ + public abstract String name(); + + /** + * The tier of the Virtual Machine Scale Set SKU + */ + public abstract String tier(); + + /** + * The capacity of the Virtual Machine Scale Set SKU + */ + public abstract int capacity(); + + @SerializedNames({"name", "tier", "capacity"}) + public static VirtualMachineScaleSetSKU create(final String name, final String tier, final int capacity) { + + return new AutoValue_VirtualMachineScaleSetSKU(name, tier, capacity); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetUpgradeMode.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetUpgradeMode.java new file mode 100644 index 0000000000..cca007fdfc --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetUpgradeMode.java @@ -0,0 +1,35 @@ +/* + * 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 org.jclouds.azurecompute.arm.util.GetEnumValue; + + +public class VirtualMachineScaleSetUpgradeMode { + /** + * VirtualMachineScaleSetUpgradeMode + * **/ + public enum Status { + Manual, + Automatic, + Unrecognized; + + public static Status fromValue(final String text) { + return (Status) GetEnumValue.fromValueOrDefault(text, Status.Unrecognized); + } + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetUpgradePolicy.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetUpgradePolicy.java new file mode 100644 index 0000000000..6945e81ae1 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetUpgradePolicy.java @@ -0,0 +1,35 @@ +/* + * 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 org.jclouds.json.SerializedNames; + + +@AutoValue +public abstract class VirtualMachineScaleSetUpgradePolicy { + /** + * The mode of the Virtual Machine Scale Set Upgrade Policy + */ + public abstract String mode(); + + @SerializedNames({"mode"}) + public static VirtualMachineScaleSetUpgradePolicy create(final String mode) { + + return new AutoValue_VirtualMachineScaleSetUpgradePolicy(mode); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetVirtualMachineProfile.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetVirtualMachineProfile.java new file mode 100644 index 0000000000..a238467d6d --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetVirtualMachineProfile.java @@ -0,0 +1,83 @@ +/* + * 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 org.jclouds.json.SerializedNames; + +/** + * A virtual machine properties for the virtual machine. + */ +@AutoValue +public abstract class VirtualMachineScaleSetVirtualMachineProfile { + + /** + * The storage profile of the Virtual Machine Scale Set Virtual Machine Profile. + */ + public abstract StorageProfile storageProfile(); + + /** + * The OS profile of the Virtual Machine Scale Set Virtual Machine Profile. + */ + public abstract VirtualMachineScaleSetOSProfile osProfile(); + + /** + * The network profile of the Virtual Machine Scale Set Virtual Machine Profile + */ + public abstract VirtualMachineScaleSetNetworkProfile networkProfile(); + + /** + * The extension profile of the Virtual Machine Scale Set Virtual Machine Profile . + */ + public abstract ExtensionProfile extensionProfile(); + + + + @SerializedNames({"storageProfile", "osProfile", "networkProfile", "extensionProfile"}) + public static VirtualMachineScaleSetVirtualMachineProfile create( + final StorageProfile storageProfile, + final VirtualMachineScaleSetOSProfile osProfile, + final VirtualMachineScaleSetNetworkProfile networkProfile, + final ExtensionProfile extensionProfile) { + return builder() + .storageProfile(storageProfile) + .osProfile(osProfile) + .networkProfile(networkProfile) + .extensionProfile(extensionProfile) + .build(); + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_VirtualMachineScaleSetVirtualMachineProfile.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + + public abstract Builder storageProfile(StorageProfile storageProfile); + + public abstract Builder osProfile(VirtualMachineScaleSetOSProfile osProfile); + + public abstract Builder networkProfile(VirtualMachineScaleSetNetworkProfile networkProfile); + + public abstract Builder extensionProfile(ExtensionProfile extensionProfile); + + public abstract VirtualMachineScaleSetVirtualMachineProfile build(); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualMachineScaleSetApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualMachineScaleSetApi.java new file mode 100644 index 0000000000..f6a237f4f4 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VirtualMachineScaleSetApi.java @@ -0,0 +1,88 @@ +/* + * 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.EmptyListOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSet; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetProperties; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetSKU; +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.RequestFilters; +import org.jclouds.rest.annotations.SelectJson; +import org.jclouds.rest.annotations.PayloadParam; +import org.jclouds.rest.annotations.MapBinder; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.binders.BindToJsonPayload; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.DELETE; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.MediaType; +import java.io.Closeable; +import java.net.URI; +import java.util.List; +import java.util.Map; + +/** + * The Virtual Machine Scale Set API includes operations for managing the virtual machines in your subscription. + * + * @see docs + */ +@Path("/resourceGroups/{resourceGroup}/providers/Microsoft.Compute/VirtualMachineScaleSets") +@RequestFilters({OAuthFilter.class, ApiVersionFilter.class}) +@Consumes(MediaType.APPLICATION_JSON) +public interface VirtualMachineScaleSetApi extends Closeable { + + @Named("virtualmachinescaleset:list") + @GET + @SelectJson("value") + @Fallback(EmptyListOnNotFoundOr404.class) + List list(); + + @Named("virtualmachinescaleset:get") + @Path("/{name}") + @GET + @Fallback(NullOnNotFoundOr404.class) + VirtualMachineScaleSet get(@PathParam("name") String name); + + @Named("virtualmachinescaleset:createOrUpdate") + @MapBinder(BindToJsonPayload.class) + @Path("/{name}") + @PUT + VirtualMachineScaleSet createOrUpdate(@PathParam("name") String name, + @PayloadParam("location") String location, + @PayloadParam("sku") VirtualMachineScaleSetSKU sku, + @Nullable @PayloadParam("tags") Map tags, + @PayloadParam("properties") VirtualMachineScaleSetProperties properties); + + @Named("virtualmachinescaleset:delete") + @Path("/{name}") + @DELETE + @ResponseParser(URIParser.class) + @Fallback(NullOnNotFoundOr404.class) + URI delete(@PathParam("name") String name); + +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineScaleSetApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineScaleSetApiLiveTest.java new file mode 100644 index 0000000000..d827d70a75 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineScaleSetApiLiveTest.java @@ -0,0 +1,297 @@ +/* + * 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 com.google.common.collect.ImmutableMap; +import org.jclouds.azurecompute.arm.domain.DataDisk; +import org.jclouds.azurecompute.arm.domain.Extension; +import org.jclouds.azurecompute.arm.domain.ExtensionProfile; +import org.jclouds.azurecompute.arm.domain.ExtensionProfileSettings; +import org.jclouds.azurecompute.arm.domain.ExtensionProperties; +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.ManagedDiskParameters; +import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; +import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCardProperties; +import org.jclouds.azurecompute.arm.domain.NetworkInterfaceConfiguration; +import org.jclouds.azurecompute.arm.domain.NetworkInterfaceConfigurationProperties; +import org.jclouds.azurecompute.arm.domain.NetworkProfile; +import org.jclouds.azurecompute.arm.domain.OSDisk; +import org.jclouds.azurecompute.arm.domain.StorageProfile; +import org.jclouds.azurecompute.arm.domain.Subnet; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSet; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetDNSSettings; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetIpConfiguration; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetIpConfigurationProperties; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetNetworkProfile; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetNetworkSecurityGroup; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetOSProfile; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetProperties; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetPublicIPAddressConfiguration; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetPublicIPAddressProperties; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetSKU; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetUpgradePolicy; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetVirtualMachineProfile; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.Arrays; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +@Test(groups = "live", testName = "VirtualMachineScaleSetApiLiveTest") +public class VirtualMachineScaleSetApiLiveTest extends BaseAzureComputeApiLiveTest { + + private String subscriptionid; + private String vmssName; + private VirtualMachineScaleSetSKU SKU; + private String nicName; + private String virtualNetworkName; + private String subnetId; + private Subnet subnet; + + @BeforeClass + @Override + public void setup() { + super.setup(); + subscriptionid = getSubscriptionId(); + + createTestResourceGroup(); //BASE: Creates a random resource group using the properties location + + 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 + assertNotNull(createDefaultVirtualNetwork(resourceGroupName, virtualNetworkName, "10.2.0.0/16", LOCATION)); + + //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")); + this.subnet = createDefaultSubnet(resourceGroupName, subnetName, virtualNetworkName, "10.2.0.0/23"); + assertNotNull(subnet); + assertNotNull(subnet.id()); + this.subnetId = subnet.id(); + + + vmssName = String.format("%3.24s", System.getProperty("user.name") + RAND + this.getClass().getSimpleName()).toLowerCase().substring(0, 15); + } + + private VirtualMachineScaleSetApi api() { + return api.getVirtualMachineScaleSetApi(resourceGroupName); + } + + @Test + public void testCreate() { + VirtualMachineScaleSet vmss = api().createOrUpdate(vmssName, LOCATIONDESCRIPTION, getSKU(), + Collections.emptyMap(), getProperties()); + assertTrue(!vmss.name().isEmpty()); +// waitUntilReady(vmssName); + } + + @Test(dependsOnMethods = "testCreate") + public void testList() throws InterruptedException { + final VirtualMachineScaleSetApi vmssAPI = api.getVirtualMachineScaleSetApi(resourceGroupName); + assertEquals(vmssAPI.list().size(), 1); + } + + @Test(dependsOnMethods = "testList") + public void testGet() { + final VirtualMachineScaleSetApi vmssAPI = api.getVirtualMachineScaleSetApi(resourceGroupName); + assertEquals(vmssAPI.get(vmssName).name(), vmssName); + } + + @Test(dependsOnMethods = "testGet", alwaysRun = true) + public void testDelete() throws Exception { + final VirtualMachineScaleSetApi vmssAPI = api.getVirtualMachineScaleSetApi(resourceGroupName); + URI uri = vmssAPI.delete(vmssName); + assertResourceDeleted(uri); + } + + protected void assertResourceDeleted(URI uri) { + if (uri != null) { + assertTrue(resourceDeleted.apply(uri), + String.format("Resource %s was not terminated in the configured timeout", uri)); + } + } + + + /** + * Create a standard SKU + * + * @return VirtualMachineScaleSetSKU + */ + public VirtualMachineScaleSetSKU getSKU() { + return VirtualMachineScaleSetSKU.create("Standard_A1", "Standard", 10); + } + + private VirtualMachineScaleSetUpgradePolicy getUpgradePolicy() { + return VirtualMachineScaleSetUpgradePolicy.create("Manual"); + } + + private List getDataDisks() { + List datadisks = new ArrayList(); + + datadisks.add(DataDisk.create(null, "10", 1, null, + null, "FromImage", + "None", getManagedDiskParameters(), + null)); + + return datadisks; + } + + private StorageProfile getStorageProfile() { + return StorageProfile.create(getWindowsImageReference(), getWindowsOSDisk(), getDataDisks()); + } + + private StorageProfile getWindowsStorageProfile_Default() { + return StorageProfile.create(getWindowsImageReference(), getWindowsOSDisk(), null); + } + + private StorageProfile getLinuxStorageProfile_Default() { + return StorageProfile.create(getLinuxImageReference(), getLinuxOSDisk(), null); + } + + private ManagedDiskParameters getManagedDiskParameters() { + return ManagedDiskParameters.create(null, "Standard_LRS"); + } + + private OSDisk getWindowsOSDisk() { + return OSDisk.create("Windows", null, null, null, "FromImage", + null, getManagedDiskParameters(), null); + } + + private OSDisk getLinuxOSDisk() { + return OSDisk.create("Linux", null, null, null, "FromImage", + null, getManagedDiskParameters(), null); + } + + private ImageReference getWindowsImageReference() { + return ImageReference.create(null, "Microsoft.Windows", "Windows2016", + "Enterprise", "latest"); + } + + private ImageReference getLinuxImageReference() { + return ImageReference.create(null, "Canonical", "UbuntuServer", + "16.04-LTS", "latest"); + } + + private VirtualMachineScaleSetOSProfile getOSProfile() { + VirtualMachineScaleSetOSProfile.LinuxConfiguration linuxConfiguration = + VirtualMachineScaleSetOSProfile.LinuxConfiguration.create(false, null); + VirtualMachineScaleSetOSProfile.WindowsConfiguration windowsConfiguration = null; + + return VirtualMachineScaleSetOSProfile.create(vmssName, "jclouds", "jClouds1!", + linuxConfiguration, windowsConfiguration, null); + } + + + private VirtualMachineScaleSetNetworkProfile getNetworkProfile() { + List networkInterfacesList = new ArrayList(); + + NetworkInterfaceCard nic = createNetworkInterfaceCard(resourceGroupName, "jc-nic-" + RAND, LOCATION, "ipConfig-" + RAND); + assertNotNull(nic); + networkInterfacesList.add(NetworkProfile.NetworkInterface.create(nic.id(), NetworkProfile.NetworkInterface.NetworkInterfaceProperties.create(true))); + + List networkInterfaceConfigurations = new ArrayList(); + List virtualMachineScaleSetIpConfigurations = new ArrayList(); + + + VirtualMachineScaleSetPublicIPAddressConfiguration publicIPAddressConfiguration = + VirtualMachineScaleSetPublicIPAddressConfiguration.create("pub1", VirtualMachineScaleSetPublicIPAddressProperties.create(15)); + + + VirtualMachineScaleSetIpConfigurationProperties virtualMachineScaleSetIpConfigurationProperties = + VirtualMachineScaleSetIpConfigurationProperties.create(publicIPAddressConfiguration, + this.subnet, "IPv4", null, + null, null); + + VirtualMachineScaleSetIpConfiguration virtualMachineScaleSetIpConfiguration = + VirtualMachineScaleSetIpConfiguration.create("ipconfig1", virtualMachineScaleSetIpConfigurationProperties); + + virtualMachineScaleSetIpConfigurations.add(virtualMachineScaleSetIpConfiguration); + + VirtualMachineScaleSetNetworkSecurityGroup networkSecurityGroup = null; + + ArrayList dnsList = new ArrayList(); + dnsList.add("8.8.8.8"); + VirtualMachineScaleSetDNSSettings dnsSettings = VirtualMachineScaleSetDNSSettings.create(dnsList); + + NetworkInterfaceConfigurationProperties networkInterfaceConfigurationProperties = + NetworkInterfaceConfigurationProperties.create(true, false, networkSecurityGroup, dnsSettings, virtualMachineScaleSetIpConfigurations); + NetworkInterfaceConfiguration networkInterfaceConfiguration = NetworkInterfaceConfiguration.create("nicconfig1", networkInterfaceConfigurationProperties); + networkInterfaceConfigurations.add(networkInterfaceConfiguration); + + return VirtualMachineScaleSetNetworkProfile.create(networkInterfaceConfigurations); + } + + + private ExtensionProfile getExtensionProfile() { + List extensions = new ArrayList(); + + List uris = new ArrayList(); + uris.add("https://mystorage1.blob.core.windows.net/winvmextekfacnt/SampleCmd_1.cmd"); + ExtensionProfileSettings extensionProfileSettings = ExtensionProfileSettings.create(uris, "SampleCmd_1.cmd"); + + Map protectedSettings = new HashMap(); + protectedSettings.put("StorageAccountKey", "jclouds-accountkey"); + + ExtensionProperties extensionProperties = ExtensionProperties.create("Microsoft.compute", "CustomScriptExtension", + "1.1", false, extensionProfileSettings, + protectedSettings); + + Extension extension = Extension.create("extensionName", extensionProperties); + extensions.add(extension); + + return ExtensionProfile.create(extensions); + } + + + private VirtualMachineScaleSetVirtualMachineProfile getVirtualMachineProfile() { + return VirtualMachineScaleSetVirtualMachineProfile.create(getLinuxStorageProfile_Default(), getOSProfile(), getNetworkProfile(), getExtensionProfile()); + } + + public VirtualMachineScaleSetProperties getProperties() { + + return VirtualMachineScaleSetProperties.create(null, null, getUpgradePolicy(), null, getVirtualMachineProfile()); + } + + private NetworkInterfaceCard createNetworkInterfaceCard(final String resourceGroupName, String networkInterfaceCardName, String locationName, String ipConfigurationName) { + //Create properties object + final NetworkInterfaceCardProperties networkInterfaceCardProperties = NetworkInterfaceCardProperties + .builder() + .ipConfigurations( + Arrays.asList(IpConfiguration.create(ipConfigurationName, null, null, null, IpConfigurationProperties + .create(null, null, "Dynamic", IdReference.create(subnetId), null, null, null)))).build(); + + final Map tags = ImmutableMap.of("jclouds", "livetest"); + return api.getNetworkInterfaceCardApi(resourceGroupName).createOrUpdate(networkInterfaceCardName, locationName, networkInterfaceCardProperties, tags); + } + + public String getSubscriptionid() { + return subscriptionid; + } + +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineScaleSetApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineScaleSetApiMockTest.java new file mode 100644 index 0000000000..e0420fae87 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineScaleSetApiMockTest.java @@ -0,0 +1,453 @@ +/* + * 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 com.google.common.collect.ImmutableMap; +import org.jclouds.azurecompute.arm.domain.DataDisk; +import org.jclouds.azurecompute.arm.domain.Extension; +import org.jclouds.azurecompute.arm.domain.ExtensionProfile; +import org.jclouds.azurecompute.arm.domain.ExtensionProfileSettings; +import org.jclouds.azurecompute.arm.domain.ExtensionProperties; +import org.jclouds.azurecompute.arm.domain.IdReference; +import org.jclouds.azurecompute.arm.domain.ImageReference; +import org.jclouds.azurecompute.arm.domain.ManagedDiskParameters; +import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; +import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCardProperties; +import org.jclouds.azurecompute.arm.domain.NetworkInterfaceConfiguration; +import org.jclouds.azurecompute.arm.domain.NetworkInterfaceConfigurationProperties; +import org.jclouds.azurecompute.arm.domain.NetworkProfile; +import org.jclouds.azurecompute.arm.domain.OSDisk; +import org.jclouds.azurecompute.arm.domain.Secrets; +import org.jclouds.azurecompute.arm.domain.StorageProfile; +import org.jclouds.azurecompute.arm.domain.Subnet; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSet; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetDNSSettings; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetIpConfiguration; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetIpConfigurationProperties; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetNetworkProfile; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetOSProfile; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetProperties; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetPublicIPAddressConfiguration; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetPublicIPAddressProperties; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetSKU; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetUpgradePolicy; +import org.jclouds.azurecompute.arm.domain.VirtualMachineScaleSetVirtualMachineProfile; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.google.common.collect.Iterables.isEmpty; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + + +@Test(groups = "unit", testName = "VirtualMachineScaleSetAPIMockTest", singleThreaded = true) +public class VirtualMachineScaleSetApiMockTest extends BaseAzureComputeApiMockTest { + + private final String resourcegroup = "myresourcegroup"; + private final String vmssname = "jclouds-vmssname"; + + public void testGet() throws InterruptedException { + server.enqueue(jsonResponse("/virtualmachinescalesetget.json").setResponseCode(200)); + final VirtualMachineScaleSetApi vmssAPI = api.getVirtualMachineScaleSetApi(resourcegroup); + assertEquals(vmssAPI.get(vmssname).name(), vmssname); + assertSent(server, + "GET", "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup/" + + "providers/Microsoft.Compute" + + "/VirtualMachineScaleSets/jclouds-vmssname?api-version=2017-03-30"); + } + + public void testGetWhen404() throws InterruptedException { + server.enqueue(jsonResponse("/virtualmachinescalesetgetwhen404.json").setResponseCode(404)); + final VirtualMachineScaleSetApi vmssAPI = api.getVirtualMachineScaleSetApi(resourcegroup); + VirtualMachineScaleSet vmss = vmssAPI.get(vmssname + 1); + assertSent(server, + "GET", + "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup/providers/" + + "Microsoft.Compute/VirtualMachineScaleSets/" + + vmssname + "1?api-version=2017-03-30"); + assertNull(vmss); + } + + public void testCreateOrUpdate() throws InterruptedException { + server.enqueue( + jsonResponse( + "/virtualmachinescalesetresponsecreateorupdate.json").setResponseCode(200)); + final VirtualMachineScaleSetApi vmssAPI = api.getVirtualMachineScaleSetApi(resourcegroup); + VirtualMachineScaleSet vmss = CreateOrUpdateVMSS(vmssAPI); + + assertNotNull(vmss); + assertSent(server, + "PUT", + "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup/providers/" + + "Microsoft.Compute" + + "/VirtualMachineScaleSets/" + vmssname + "?api-version=2017-03-30", + "{\n" + + " \"location\": \"eastus\",\n" + + " \"sku\": {\n" + + " \"name\": \"Standard_A1\",\n" + + " \"tier\": \"Standard\",\n" + + " \"capacity\": 10\n" + + " },\n" + + " \"properties\": {\n" + + " \"singlePlacementGroup\": true,\n" + + " \"overProvision\": true,\n" + + " \"upgradePolicy\": {\n" + + " \"mode\": \"Manual\"\n" + + " },\n" + + " \"virtualMachineProfile\": {\n" + + " \"storageProfile\": {\n" + + " \"imageReference\": {\n" + + " \"publisher\": \"Canonical\",\n" + + " \"offer\": \"UbuntuServer\",\n" + + " \"sku\": \"16.04-LTS\",\n" + + " \"version\": \"latest\"\n" + + " },\n" + + " \"osDisk\": {\n" + + " \"osType\": \"Windows\",\n" + + " \"createOption\": \"FromImage\",\n" + + " \"managedDisk\": {\n" + + " \"storageAccountType\": \"Standard_LRS\"\n" + + " }\n" + + " },\n" + + " \"dataDisks\": [{\n" + + " \"diskSizeGB\": \"10\",\n" + + " \"lun\": 1,\n" + + " \"createOption\": \"Unrecognized\",\n" + + " \"caching\": \"None\",\n" + + " \"managedDisk\": {\n" + + " \"storageAccountType\": \"Standard_LRS\"\n" + + " }\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"osProfile\": {\n" + + " \"computerNamePrefix\": \"jclouds-vmssname\",\n" + + " \"adminUsername\": \"admin\",\n" + + " \"adminPassword\": \"password\",\n" + + " \"linuxConfiguration\": {\n" + + " \"disablePasswordAuthentication\": false\n" + + " },\n" + + " \"secrets\": []\n" + + " },\n" + + " \"networkProfile\": {\n" + + " \"networkInterfaceConfigurations\": [{\n" + + " \"name\": \"nicconfig1\",\n" + + " \"properties\": {\n" + + " \"primary\": true,\n" + + " \"enableAcceleratedNetworking\": false,\n" + + " \"dnsSettings\": {\n" + + " \"dnsServers\": [\"8.8.8.8\"]\n" + + " },\n" + + " \"ipConfigurations\": [{\n" + + " \"name\": \"ipconfig1\",\n" + + " \"properties\": {\n" + + " \"publicIPAddressConfiguration\": {\n" + + " \"name\": \"pub1\",\n" + + " \"properties\": {\n" + + " \"idleTimeoutInMinutes\": 15\n" + + " }\n" + + " },\n" + + " \"subnet\": {\n" + + " \"name\": \"virtualNetworkName\",\n" + + " \"id\": \"/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxx/resourceGroups/" + + "jcloud-eastus/providers/Microsoft.Network/virtualNetworks/" + + "jclouds-eastus-virtualNetworkName/subnets/jclouds-eastus-subnet\",\n" + + " \"properties\": {}\n" + + " },\n" + + " \"privateIPAddressVersion\": \"IPv4\",\n" + + " \"loadBalancerBackendAddressPools\": [],\n" + + " \"loadBalancerInboundNatPools\": []\n" + + " }\n" + + " }\n" + + " ]\n" + + " }\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"extensionProfile\": {\n" + + " \"extensions\": [{\n" + + " \"name\": \"extensionName\",\n" + + " \"properties\": {\n" + + " \"publisher\": \"Microsoft.compute\",\n" + + " \"type\": \"CustomScriptExtension\",\n" + + " \"typeHandlerVersion\": \"1.1\",\n" + + " \"autoUpgradeMinorVersion\": false,\n" + + " \"settings\": {\n" + + " \"fileUris\": [\"https://mystorage1.blob.core.windows.net/winvmextekfacnt/" + + "SampleCmd_1.cmd\"],\n" + + " \"commandToExecute\": \"SampleCmd_1.cmd\"\n" + + " },\n" + + " \"protectedSettings\": {\n" + + " \"StorageAccountKey\": \"jclouds-accountkey\"\n" + + " }\n" + + " }\n" + + " }\n" + + " ]\n" + + " }\n" + + " }\n" + + " }\n" + + "}\n" + ); + } + + private VirtualMachineScaleSet CreateOrUpdateVMSS(VirtualMachineScaleSetApi vmssAPI) { + return vmssAPI.createOrUpdate( + vmssname, + "eastus", + VirtualMachineScaleSetSKU.create( + "Standard_A1", + "Standard", + 10), + null, + VirtualMachineScaleSetProperties.create( + true, + true, + VirtualMachineScaleSetUpgradePolicy.create("Manual"), + null, + VirtualMachineScaleSetVirtualMachineProfile.create( + StorageProfile.create( + ImageReference.create( + null, + "Canonical", + "UbuntuServer", + "16.04-LTS", + "latest"), + OSDisk.create( + "Windows", + null, + null, + null, + "FromImage", + null, + ManagedDiskParameters.create( + null, + "Standard_LRS"), + null), + Arrays.asList(DataDisk.create( + null, + "10", + 1, + null, + null, + "FromImage", + "None", + ManagedDiskParameters.create( + null, + "Standard_LRS"), + null))), + VirtualMachineScaleSetOSProfile.create( + "jclouds-vmssname", + "admin", + "password", + VirtualMachineScaleSetOSProfile.LinuxConfiguration.create( + false, + null), + null, + new ArrayList()), + getNetworkProfile(), + getExtensionProfile() + + ) + )); + } + + + private VirtualMachineScaleSetNetworkProfile getNetworkProfile() { + List networkInterfacesList = + new ArrayList(); + + NetworkInterfaceCard nic = + createNetworkInterfaceCard( + "jc-nic-" + 123, + "eastus"); + networkInterfacesList.add(NetworkProfile.NetworkInterface.create( + nic.id(), + NetworkProfile.NetworkInterface.NetworkInterfaceProperties.create(true))); + + List networkInterfaceConfigurations = + new ArrayList(); + List virtualMachineScaleSetIpConfigurations = + new ArrayList(); + + + VirtualMachineScaleSetPublicIPAddressConfiguration publicIPAddressConfiguration = + VirtualMachineScaleSetPublicIPAddressConfiguration.create( + "pub1", + VirtualMachineScaleSetPublicIPAddressProperties.create(15)); + + + VirtualMachineScaleSetIpConfigurationProperties virtualMachineScaleSetIpConfigurationProperties = + VirtualMachineScaleSetIpConfigurationProperties.create( + publicIPAddressConfiguration, + createDefaultSubnet( + "virtualNetworkName" + ), + "IPv4", + null, + null, + null); + + VirtualMachineScaleSetIpConfiguration virtualMachineScaleSetIpConfiguration = + VirtualMachineScaleSetIpConfiguration.create( + "ipconfig1", + virtualMachineScaleSetIpConfigurationProperties); + + virtualMachineScaleSetIpConfigurations.add(virtualMachineScaleSetIpConfiguration); + + ArrayList dnsList = new ArrayList(); + dnsList.add("8.8.8.8"); + VirtualMachineScaleSetDNSSettings dnsSettings = VirtualMachineScaleSetDNSSettings.create(dnsList); + + NetworkInterfaceConfigurationProperties networkInterfaceConfigurationProperties = + NetworkInterfaceConfigurationProperties.create( + true, + false, + null, + dnsSettings, + virtualMachineScaleSetIpConfigurations); + NetworkInterfaceConfiguration networkInterfaceConfiguration = + NetworkInterfaceConfiguration.create( + "nicconfig1", + networkInterfaceConfigurationProperties); + networkInterfaceConfigurations.add(networkInterfaceConfiguration); + + return VirtualMachineScaleSetNetworkProfile.create(networkInterfaceConfigurations); + } + + + private NetworkInterfaceCard createNetworkInterfaceCard( + String networkInterfaceCardName, String locationName) { + //Create properties object + NetworkInterfaceCardProperties networkInterfaceCardProperties = + NetworkInterfaceCardProperties.create( + null, + null, + false, + null, + IdReference.create( + "/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxx/resourceGroups/" + + "jcloud-eastus/providers/" + + "Microsoft.Network/virtualNetworks/" + + "jclouds-eastus-virtualNetworkName/subnets/" + + "jclouds-eastus-subnet") + ); + + Map tags = ImmutableMap.of("jclouds", "livetest"); + return NetworkInterfaceCard.create( + networkInterfaceCardName, + "", + null, + locationName, + networkInterfaceCardProperties, tags); + } + + protected Subnet createDefaultSubnet(final String subnetName) { + Subnet.SubnetProperties properties = Subnet.SubnetProperties.create( + null, + null, + null); + return Subnet.create( + subnetName, + "/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxx/resourceGroups/jcloud-eastus/providers/" + + "Microsoft.Network/virtualNetworks/jclouds-eastus-virtualNetworkName/subnets/" + + "jclouds-eastus-subnet", + null, + properties); + } + + private ExtensionProfile getExtensionProfile() { + List extensions = new ArrayList(); + + List uris = new ArrayList(); + uris.add("https://mystorage1.blob.core.windows.net/winvmextekfacnt/SampleCmd_1.cmd"); + + Map protectedSettings = new HashMap(); + protectedSettings.put("StorageAccountKey", "jclouds-accountkey"); + + Extension extension = Extension.create( + "extensionName", + ExtensionProperties.create( + "Microsoft.compute", + "CustomScriptExtension", + "1.1", + false, + ExtensionProfileSettings.create( + uris, + "SampleCmd_1.cmd"), + protectedSettings)); + extensions.add(extension); + + return ExtensionProfile.create(extensions); + } + + public void testList() throws InterruptedException { + server.enqueue(jsonResponse("/virtualmachinescalesetlist.json").setResponseCode(200)); + final VirtualMachineScaleSetApi vmssAPI = api.getVirtualMachineScaleSetApi(resourcegroup); + assertEquals(vmssAPI.list().size(), 1); + assertSent(server, + "GET", + "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup/providers/" + + "Microsoft.Compute" + + "/VirtualMachineScaleSets?api-version=2017-03-30"); + } + + public void testListWhen404() throws InterruptedException { + server.enqueue( + jsonResponse("/virtualmachinescalesetlistwhen404.json").setResponseCode(404)); + final VirtualMachineScaleSetApi vmssAPI = api.getVirtualMachineScaleSetApi( + resourcegroup + "1"); + List vmssList = vmssAPI.list(); + assertSent(server, + "GET", + "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup1/providers/" + + "Microsoft.Compute" + + "/VirtualMachineScaleSets?api-version=2017-03-30"); + assertTrue(isEmpty(vmssList)); + } + + + public void testDeleteWhen404() throws InterruptedException { + server.enqueue(jsonResponse("/virtualmachinescalesetlist.json").setResponseCode(404)); + final VirtualMachineScaleSetApi vmssAPI = api.getVirtualMachineScaleSetApi(resourcegroup); + assertNull(vmssAPI.delete(vmssname)); + assertSent(server, + "DELETE", + "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup/providers/" + + "Microsoft.Compute" + + "/VirtualMachineScaleSets/" + vmssname + "?api-version=2017-03-30"); + + } + + public void testDelete() throws InterruptedException { + server.enqueue(response202WithHeader()); + final VirtualMachineScaleSetApi vmssAPI = api.getVirtualMachineScaleSetApi(resourcegroup); + assertNotNull(vmssAPI.delete(vmssname)); + assertSent(server, + "DELETE", + "/subscriptions/SUBSCRIPTIONID/resourceGroups/myresourcegroup/providers/" + + "Microsoft.Compute" + + "/VirtualMachineScaleSets/jclouds-vmssname?api-version=2017-03-30"); + } +} 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 f704e5f2b7..1a83407f2b 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 @@ -75,6 +75,7 @@ public class BaseAzureComputeApiMockTest { 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; diff --git a/providers/azurecompute-arm/src/test/resources/virtualmachine.json b/providers/azurecompute-arm/src/test/resources/virtualmachine.json index 17d89b559d..e3e8d6b141 100644 --- a/providers/azurecompute-arm/src/test/resources/virtualmachine.json +++ b/providers/azurecompute-arm/src/test/resources/virtualmachine.json @@ -36,7 +36,6 @@ "id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/osDisk", "storageAccountType": "Standard_LRS" }, - "createOption":"Empty", "caching": "ReadWrite" } ] diff --git a/providers/azurecompute-arm/src/test/resources/virtualmachinescalesetget.json b/providers/azurecompute-arm/src/test/resources/virtualmachinescalesetget.json new file mode 100644 index 0000000000..c99eb39a5c --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/virtualmachinescalesetget.json @@ -0,0 +1,64 @@ +{ + "sku": { + "name": "Standard_A1", + "tier": "Standard", + "capacity": 4 + }, + "properties": { + "singlePlacementGroup": true, + "upgradePolicy": { + "mode": "Manual" + }, + "virtualMachineProfile": { + "osProfile": { + "computerNamePrefix": "vmmsprefix", + "adminUsername": "jclouds", + "linuxConfiguration": { + "disablePasswordAuthentication": false + }, + "secrets": [] + }, + "storageProfile": { + "osDisk": { + "createOption": "FromImage", + "caching": "None", + "managedDisk": { + "storageAccountType": "Standard_LRS" + } + }, + "imageReference": { + "publisher": "Canonical", + "offer": "UbuntuServer", + "sku": "16.04-LTS", + "version": "latest" + } + }, + "networkProfile": {"networkInterfaceConfigurations":[{"name":"nicconfig1","properties":{"primary":true,"enableAcceleratedNetworking":false,"dnsSettings":{"dnsServers":["8.8.8.8"]},"ipConfigurations":[{"name":"ipconfig1","properties":{"publicIPAddressConfiguration":{"name":"pub1","properties":{"idleTimeoutInMinutes":15}},"subnet":{"id":"/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxx/resourceGroups/jcloud-eastus/providers/Microsoft.Network/virtualNetworks/jclouds-eastus-virtualNetworkName/subnets/jclouds-eastus-subnet"},"privateIPAddressVersion":"IPv4"}}]}}]}, + "extensionProfile": { + "extensions": [ + { + "properties": { + "publisher": "Microsoft.compute", + "type": "CustomScriptExtension", + "typeHandlerVersion": "1.1", + "autoUpgradeMinorVersion": false, + "settings": {"fileUris":["https://mystorage1.blob.core.windows.net/winvmextekfacnt/SampleCmd_1.cmd"],"commandToExecute":"SampleCmd_1.cmd"} + }, + "name": "extensionName" + } + ] + } + }, + "provisioningState": "Creating", + "overprovision": true, + "uniqueId": "xxxxx-xxxx-xxxx-xxxx-xxxxxx" + }, + "type": "Microsoft.Compute/virtualMachineScaleSets", + "location": "eastus", + "tags": { + "test": "test" + }, + "id": "/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxx/resourceGroups/jcloud-eastus/providers/Microsoft.Compute/virtualMachineScaleSets/jclouds-vmssname", + "name": "jclouds-vmssname" +} + diff --git a/providers/azurecompute-arm/src/test/resources/virtualmachinescalesetgetwhen404.json b/providers/azurecompute-arm/src/test/resources/virtualmachinescalesetgetwhen404.json new file mode 100644 index 0000000000..b6fbeaaea6 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/virtualmachinescalesetgetwhen404.json @@ -0,0 +1,6 @@ +{ + "error": { + "code": "ResourceNotFound", + "message": "The Resource 'Microsoft.Compute/virtualMachineScaleSets/jclouds-vmssname1' under resource group 'jcloud-eastus' was not found." + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/virtualmachinescalesetlist.json b/providers/azurecompute-arm/src/test/resources/virtualmachinescalesetlist.json new file mode 100644 index 0000000000..b5bd063d8a --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/virtualmachinescalesetlist.json @@ -0,0 +1,93 @@ +{ + "value": [{ + "sku": { + "name": "Standard_A1", + "tier": "Standard", + "capacity": 4 + }, + "properties": { + "singlePlacementGroup": true, + "upgradePolicy": { + "mode": "Manual", + "automaticOSUpgrade": false + }, + "virtualMachineProfile": { + "osProfile": { + "computerNamePrefix": "vmmsprefix", + "adminUsername": "jclouds", + "linuxConfiguration": { + "disablePasswordAuthentication": false + }, + "secrets": [] + }, + "storageProfile": { + "osDisk": { + "createOption": "FromImage", + "caching": "None", + "managedDisk": { + "storageAccountType": "Standard_LRS" + } + }, + "imageReference": { + "publisher": "Canonical", + "offer": "UbuntuServer", + "sku": "16.04-LTS", + "version": "latest" + } + }, + "networkProfile": { + "networkInterfaceConfigurations": [{ + "name": "nicconfig1", + "properties": { + "primary": true, + "enableAcceleratedNetworking": false, + "dnsSettings": { + "dnsServers": ["8.8.8.8"] + }, + "ipConfigurations": [{ + "name": "ipconfig1", + "properties": { + "publicIPAddressConfiguration": { + "name": "pub1", + "properties": { + "idleTimeoutInMinutes": 15 + } + }, + "subnet": { + "id": "/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxx/resourceGroups/jcloud-eastus/providers/Microsoft.Network/virtualNetworks/jclouds-eastus-virtualNetworkName/subnets/jclouds-eastus-subnet" + }, + "privateIPAddressVersion": "IPv4" + } + }] + } + }] + }, + "extensionProfile": { + "extensions": [{ + "properties": { + "publisher": "Microsoft.compute", + "type": "CustomScriptExtension", + "typeHandlerVersion": "1.1", + "autoUpgradeMinorVersion": false, + "settings": { + "fileUris": ["https://mystorage1.blob.core.windows.net/winvmextekfacnt/SampleCmd_1.cmd"], + "commandToExecute": "SampleCmd_1.cmd" + } + }, + "name": "extensionName" + }] + } + }, + "provisioningState": "Failed", + "overprovision": true, + "uniqueId": "xxxxx-xxxx-xxxx-xxxx-xxxxxx" + }, + "type": "Microsoft.Compute/virtualMachineScaleSets", + "location": "eastus", + "tags": { + "test": "test" + }, + "id": "/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxx/resourceGroups/jcloud-eastus/providers/Microsoft.Compute/virtualMachineScaleSets/jclouds-vmssname", + "name": "jclouds-vmssname" + }] +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/virtualmachinescalesetlistwhen404.json b/providers/azurecompute-arm/src/test/resources/virtualmachinescalesetlistwhen404.json new file mode 100644 index 0000000000..635083c7a5 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/virtualmachinescalesetlistwhen404.json @@ -0,0 +1,6 @@ +{ + "error": { + "code": "ResourceGroupNotFound", + "message": "Resource group 'jcloud-eastus1' could not be found." + } +} \ No newline at end of file diff --git a/providers/azurecompute-arm/src/test/resources/virtualmachinescalesetresponsecreateorupdate.json b/providers/azurecompute-arm/src/test/resources/virtualmachinescalesetresponsecreateorupdate.json new file mode 100644 index 0000000000..20ecd71292 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/virtualmachinescalesetresponsecreateorupdate.json @@ -0,0 +1,103 @@ +{ + "location": "eastus", + "sku": { + "name": "Standard_A1", + "tier": "Standard", + "capacity": 10 + }, + "properties": { + "singlePlacementGroup": true, + "overProvision": true, + "upgradePolicy": { + "mode": "Manual" + }, + "virtualMachineProfile": { + "storageProfile": { + "imageReference": { + "publisher": "Canonical", + "offer": "UbuntuServer", + "sku": "16.04-LTS", + "version": "latest" + }, + "osDisk": { + "osType": "Windows", + "createOption": "FromImage", + "managedDisk": { + "storageAccountType": "Standard_LRS" + } + }, + "dataDisks": [{ + "diskSizeGB": "10", + "lun": 1, + "createOption": "Unrecognized", + "caching": "None", + "managedDisk": { + "storageAccountType": "Standard_LRS" + } + } + ] + }, + "osProfile": { + "computerNamePrefix": "jclouds-vmssname", + "adminUsername": "jclouds", + "adminPassword": "jClouds1!", + "linuxConfiguration": { + "disablePasswordAuthentication": "False" + }, + "secrets": [] + }, + "networkProfile": { + "networkInterfaceConfigurations": [{ + "name": "nicconfig1", + "properties": { + "primary": true, + "enableAcceleratedNetworking": false, + "dnsSettings": { + "dnsServers": ["8.8.8.8"] + }, + "ipConfigurations": [{ + "name": "ipconfig1", + "properties": { + "publicIPAddressConfiguration": { + "name": "pub1", + "properties": { + "idleTimeoutInMinutes": 15 + } + }, + "subnet": { + "name": "virtualNetworkName", + "id": "/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxx/resourceGroups/jcloud-eastus/providers/Microsoft.Network/virtualNetworks/jclouds-eastus-virtualNetworkName/subnets/jclouds-eastus-subnet", + "properties": {} + }, + "privateIPAddressVersion": "IPv4", + "loadBalancerBackendAddressPools": [], + "loadBalancerInboundNatPools": [] + } + } + ] + } + } + ] + }, + "extensionProfile": { + "extensions": [{ + "name": "extensionName", + "properties": { + "publisher": "Microsoft.compute", + "type": "CustomScriptExtension", + "typeHandlerVersion": "1.1", + "autoUpgradeMinorVersion": false, + "settings": { + "fileUris": ["https://mystorage1.blob.core.windows.net/winvmextekfacnt/SampleCmd_1.cmd"], + "commandToExecute": "SampleCmd_1.cmd" + }, + "protectedSettings": { + "StorageAccountKey": "jclouds-accountkey" + } + } + } + ] + } + } + } +} From 6c759930d77f91376ac02923ca4e5b36468ac85b Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Fri, 1 Dec 2017 11:54:58 +0100 Subject: [PATCH 83/87] Injectable current service principal --- .../azurecompute/arm/AzureComputeApi.java | 46 ++++++---- .../arm/AzureComputeProviderMetadata.java | 20 +++-- .../arm/config/AzureComputeHttpApiModule.java | 83 ++++++++++++++++++- .../arm/config/AzureOAuthConfigFactory.java | 60 ++++++++++++++ .../azurecompute/arm/config/GraphRBAC.java | 35 ++++++++ .../arm/config/OAuthResource.java | 35 ++++++++ .../azurecompute/arm/config/Tenant.java | 34 ++++++++ .../arm/domain/ServicePrincipal.java | 66 +++++++++++++++ ...hineScaleSetIpConfigurationProperties.java | 38 +++------ .../VirtualMachineScaleSetOSProfile.java | 8 +- .../CurrentServicePrincipalApiLiveTest.java | 34 ++++++++ 11 files changed, 399 insertions(+), 60 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureOAuthConfigFactory.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/GraphRBAC.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/OAuthResource.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/Tenant.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ServicePrincipal.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/CurrentServicePrincipalApiLiveTest.java 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 86235804f1..afc8413225 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 @@ -20,30 +20,34 @@ import java.io.Closeable; import javax.ws.rs.PathParam; -import org.jclouds.azurecompute.arm.features.JobApi; -import org.jclouds.azurecompute.arm.features.LocationApi; -import org.jclouds.azurecompute.arm.features.ResourceGroupApi; -import org.jclouds.azurecompute.arm.features.StorageAccountApi; -import org.jclouds.azurecompute.arm.features.SubnetApi; -import org.jclouds.azurecompute.arm.features.VirtualNetworkApi; -import org.jclouds.azurecompute.arm.features.NetworkInterfaceCardApi; -import org.jclouds.azurecompute.arm.features.PublicIPAddressApi; -import org.jclouds.azurecompute.arm.features.VirtualMachineApi; -import org.jclouds.azurecompute.arm.features.VirtualMachineScaleSetApi; -import org.jclouds.azurecompute.arm.features.VMSizeApi; -import org.jclouds.azurecompute.arm.features.OSImageApi; -import org.jclouds.azurecompute.arm.features.DeploymentApi; -import org.jclouds.azurecompute.arm.features.NetworkSecurityGroupApi; -import org.jclouds.azurecompute.arm.features.NetworkSecurityRuleApi; -import org.jclouds.azurecompute.arm.features.LoadBalancerApi; +import org.jclouds.azurecompute.arm.domain.ServicePrincipal; import org.jclouds.azurecompute.arm.features.AvailabilitySetApi; -import org.jclouds.azurecompute.arm.features.ResourceProviderApi; +import org.jclouds.azurecompute.arm.features.DeploymentApi; import org.jclouds.azurecompute.arm.features.DiskApi; import org.jclouds.azurecompute.arm.features.ImageApi; -import org.jclouds.azurecompute.arm.features.MetricsApi; +import org.jclouds.azurecompute.arm.features.JobApi; +import org.jclouds.azurecompute.arm.features.LoadBalancerApi; +import org.jclouds.azurecompute.arm.features.LocationApi; import org.jclouds.azurecompute.arm.features.MetricDefinitionsApi; +import org.jclouds.azurecompute.arm.features.MetricsApi; +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.VirtualMachineScaleSetApi; +import org.jclouds.azurecompute.arm.features.VirtualNetworkApi; import org.jclouds.rest.annotations.Delegate; +import com.google.common.base.Supplier; +import com.google.inject.Provides; + /** * The Azure Resource Manager API is a REST API for managing your services and deployments. *

@@ -237,4 +241,10 @@ public interface AzureComputeApi extends Closeable { */ @Delegate MetricDefinitionsApi getMetricsDefinitionsApi(@PathParam("resourceid") String resourceid); + + /** + * Returns the information about the current service principal. + */ + @Provides + Supplier getServicePrincipal(); } 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 8849a1fb89..6848167682 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 @@ -37,28 +37,29 @@ import static org.jclouds.oauth.v2.config.OAuthProperties.RESOURCE; import java.net.URI; import java.util.Properties; +import org.jclouds.azurecompute.arm.config.AzureComputeHttpApiModule.CurrentServicePrincipal; import org.jclouds.azurecompute.arm.domain.Region; +import org.jclouds.azurecompute.arm.features.AvailabilitySetApi; import org.jclouds.azurecompute.arm.features.DeploymentApi; +import org.jclouds.azurecompute.arm.features.DiskApi; +import org.jclouds.azurecompute.arm.features.ImageApi; +import org.jclouds.azurecompute.arm.features.LoadBalancerApi; import org.jclouds.azurecompute.arm.features.LocationApi; +import org.jclouds.azurecompute.arm.features.MetricDefinitionsApi; +import org.jclouds.azurecompute.arm.features.MetricsApi; 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.ResourceGroupApi; 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.VirtualNetworkApi; import org.jclouds.azurecompute.arm.features.VMSizeApi; import org.jclouds.azurecompute.arm.features.VirtualMachineApi; -import org.jclouds.azurecompute.arm.features.LoadBalancerApi; -import org.jclouds.azurecompute.arm.features.AvailabilitySetApi; -import org.jclouds.azurecompute.arm.features.DiskApi; -import org.jclouds.azurecompute.arm.features.ImageApi; -import org.jclouds.azurecompute.arm.features.MetricDefinitionsApi; -import org.jclouds.azurecompute.arm.features.MetricsApi; import org.jclouds.azurecompute.arm.features.VirtualMachineScaleSetApi; +import org.jclouds.azurecompute.arm.features.VirtualNetworkApi; import org.jclouds.providers.ProviderMetadata; import org.jclouds.providers.internal.BaseProviderMetadata; @@ -124,7 +125,8 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { properties.put(API_VERSION_PREFIX + MetricDefinitionsApi.class.getSimpleName(), "2017-05-01-preview"); properties.put(API_VERSION_PREFIX + MetricsApi.class.getSimpleName(), "2016-09-01"); properties.put(API_VERSION_PREFIX + VirtualMachineScaleSetApi.class.getSimpleName(), "2017-03-30"); - + properties.put(API_VERSION_PREFIX + CurrentServicePrincipal.class.getSimpleName(), "1.6"); + return properties; } 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 991c73883f..8d417ca44b 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 @@ -16,7 +16,24 @@ */ package org.jclouds.azurecompute.arm.config; +import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; +import static org.jclouds.rest.config.BinderUtils.bindHttpApi; + +import java.net.URI; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.inject.Singleton; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.MediaType; + import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.domain.ServicePrincipal; +import org.jclouds.azurecompute.arm.filters.ApiVersionFilter; import org.jclouds.azurecompute.arm.handlers.AzureComputeErrorHandler; import org.jclouds.http.HttpErrorHandler; import org.jclouds.http.annotation.ClientError; @@ -24,15 +41,31 @@ import org.jclouds.http.annotation.Redirection; import org.jclouds.http.annotation.ServerError; import org.jclouds.location.suppliers.ImplicitLocationSupplier; import org.jclouds.location.suppliers.implicit.FirstRegion; +import org.jclouds.oauth.v2.config.OAuthConfigFactory; import org.jclouds.oauth.v2.config.OAuthScopes; +import org.jclouds.oauth.v2.filters.OAuthFilter; +import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.ConfiguresHttpApi; +import org.jclouds.rest.annotations.Endpoint; +import org.jclouds.rest.annotations.OnlyElement; +import org.jclouds.rest.annotations.QueryParams; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.config.HttpApiModule; +import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; +import com.google.inject.Provides; import com.google.inject.Scopes; +import com.google.inject.name.Named; @ConfiguresHttpApi public class AzureComputeHttpApiModule extends HttpApiModule { + private static final Pattern OAUTH_TENANT_PATTERN = Pattern + .compile("https://login.microsoftonline.com/([^/]+)/oauth2/token"); + @Override protected void bindErrorHandlers() { bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(AzureComputeErrorHandler.class); @@ -46,10 +79,58 @@ public class AzureComputeHttpApiModule extends HttpApiModule { bind(ImplicitLocationSupplier.class).to(FirstRegion.class).in(Scopes.SINGLETON); } - @Override protected void configure() { super.configure(); + bindHttpApi(binder(), CurrentServicePrincipal.class); bind(OAuthScopes.class).toInstance(OAuthScopes.NoScopes.create()); + bind(OAuthConfigFactory.class).to(AzureOAuthConfigFactory.class).in(Scopes.SINGLETON); + } + + @Provides + @Singleton + @Tenant + protected String provideTenant(@Named("oauth.endpoint") final String oauthEndpoint) { + Matcher m = OAUTH_TENANT_PATTERN.matcher(oauthEndpoint); + if (!m.matches()) { + throw new IllegalArgumentException("Could not parse tenantId from: " + oauthEndpoint); + } + return m.group(1); + } + + @Provides + @Singleton + @GraphRBAC + protected Supplier graphRBACEndpoint(@Tenant String tenantId) { + return Suppliers.ofInstance(URI.create(GraphRBAC.ENDPOINT + tenantId)); + } + + @Provides + @Singleton + protected Supplier provideServicePrincipal(final CurrentServicePrincipal currentServicePrincipal, + AtomicReference authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds) { + // This supplier must be defensive against any auth exception. + return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, + new Supplier() { + @Override + public ServicePrincipal get() { + return currentServicePrincipal.get(); + } + }, seconds, TimeUnit.SECONDS); + } + + @RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) + @Consumes(MediaType.APPLICATION_JSON) + @Endpoint(GraphRBAC.class) + @OAuthResource(GraphRBAC.ENDPOINT) + public interface CurrentServicePrincipal { + + @Named("servicePrincipal:get") + @GET + @Path("/servicePrincipals") + @QueryParams(keys = "$filter", values = "appId eq '{jclouds.identity}'") + @SelectJson("value") + @OnlyElement + ServicePrincipal get(); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureOAuthConfigFactory.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureOAuthConfigFactory.java new file mode 100644 index 0000000000..9128b59498 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureOAuthConfigFactory.java @@ -0,0 +1,60 @@ +/* + * 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.config; + +import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; +import static org.jclouds.oauth.v2.config.OAuthProperties.RESOURCE; + +import org.jclouds.http.HttpRequest; +import org.jclouds.oauth.v2.config.OAuthConfigFactory; +import org.jclouds.oauth.v2.config.OAuthScopes; +import org.jclouds.rest.internal.GeneratedHttpRequest; + +import com.google.inject.Inject; +import com.google.inject.name.Named; + +public class AzureOAuthConfigFactory implements OAuthConfigFactory { + private final OAuthScopes scopes; + + @Named(AUDIENCE) + @Inject(optional = true) + private String audience; + + @Named(RESOURCE) + @Inject(optional = true) + private String resource; + + @Inject + AzureOAuthConfigFactory(OAuthScopes scopes) { + this.scopes = scopes; + } + + @Override + public OAuthConfig forRequest(HttpRequest input) { + OAuthResource customResource = null; + if (input instanceof GeneratedHttpRequest) { + GeneratedHttpRequest request = (GeneratedHttpRequest) input; + customResource = request.getInvocation().getInvokable().getAnnotation(OAuthResource.class); + if (customResource == null) { + customResource = request.getInvocation().getInvokable().getDeclaringClass() + .getAnnotation(OAuthResource.class); + } + } + String oauthResource = customResource != null ? customResource.value() : resource; + return OAuthConfig.create(scopes.forRequest(input), audience, oauthResource); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/GraphRBAC.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/GraphRBAC.java new file mode 100644 index 0000000000..6853782215 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/GraphRBAC.java @@ -0,0 +1,35 @@ +/* + * 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.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.inject.Qualifier; + +/** + * Provides the Graph RBAC API endpoint for the current tenant. + */ +@Retention(value = RetentionPolicy.RUNTIME) +@Target(value = {ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) +@Qualifier +public @interface GraphRBAC { + + String ENDPOINT = "https://graph.windows.net/"; +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/OAuthResource.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/OAuthResource.java new file mode 100644 index 0000000000..6e5a2dfdc4 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/OAuthResource.java @@ -0,0 +1,35 @@ +/* + * 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.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.inject.Qualifier; + +/** + * Configures a custom OAuth resource for certain APIs and methods. + */ +@Retention(value = RetentionPolicy.RUNTIME) +@Target(value = { ElementType.TYPE, ElementType.METHOD }) +@Qualifier +public @interface OAuthResource { + + String value(); +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/Tenant.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/Tenant.java new file mode 100644 index 0000000000..5524361dd1 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/Tenant.java @@ -0,0 +1,34 @@ +/* + * 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.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.inject.Qualifier; + +/** + * Qualifies an object that describes the current tenant. + */ +@Retention(value = RetentionPolicy.RUNTIME) +@Target(value = {ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) +@Qualifier +public @interface Tenant { + +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ServicePrincipal.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ServicePrincipal.java new file mode 100644 index 0000000000..2faba3f134 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/ServicePrincipal.java @@ -0,0 +1,66 @@ +/* + * 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 java.util.Date; +import java.util.List; + +import javax.annotation.Nullable; + +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; + +@AutoValue +public abstract class ServicePrincipal { + + @Nullable public abstract String appId(); + @Nullable public abstract Date deletionTimestamp(); + @Nullable public abstract String displayName(); + public abstract String objectId(); + public abstract String objectType(); + public abstract List servicePrincipalNames(); + + @SerializedNames({ "appId", "deletionTimestamp", "displayName", "objectId", "objectType", "servicePrincipalNames" }) + public static ServicePrincipal create(String appId, Date deletionTimestamp, String displayName, String objectId, + String objectType, List servicePrincipalNames) { + List servicePrincipals = servicePrincipalNames != null ? ImmutableList.copyOf(servicePrincipalNames) + : ImmutableList. of(); + return builder().appId(appId).deletionTimestamp(deletionTimestamp).displayName(displayName).objectId(objectId) + .objectType(objectType).servicePrincipalNames(servicePrincipals).build(); + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_ServicePrincipal.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + + public abstract Builder appId(String appId); + public abstract Builder deletionTimestamp(Date deletionTimestamp); + public abstract Builder displayName(String displayName); + public abstract Builder objectId(String objectId); + public abstract Builder objectType(String objectType); + public abstract Builder servicePrincipalNames(List servicePrincipalNames); + + public abstract ServicePrincipal build(); + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetIpConfigurationProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetIpConfigurationProperties.java index ee23152e94..739dadf3b1 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetIpConfigurationProperties.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetIpConfigurationProperties.java @@ -70,49 +70,35 @@ public abstract class VirtualMachineScaleSetIpConfigurationProperties { final String applicationGatewayBackendAddressPools) { - return builder() - .publicIPAddressConfiguration(publicIPAddressConfiguration) - .subnet(subnet) - .privateIPAddressVersion(privateIPAddressVersion) - .lbBackendAddressPools(loadBalancerBackendAddressPools) - .lbInboundNatPools(loadBalancerInboundNatPools) - .applicationGatewayBackendAddressPools(applicationGatewayBackendAddressPools) - .build(); + .publicIPAddressConfiguration(publicIPAddressConfiguration) + .subnet(subnet) + .privateIPAddressVersion(privateIPAddressVersion) + .loadBalancerBackendAddressPools( + loadBalancerBackendAddressPools != null ? ImmutableList.copyOf(loadBalancerBackendAddressPools) + : ImmutableList. of()) + .loadBalancerInboundNatPools( + loadBalancerInboundNatPools != null ? ImmutableList.copyOf(loadBalancerInboundNatPools) + : ImmutableList. of()) + .applicationGatewayBackendAddressPools(applicationGatewayBackendAddressPools).build(); } public abstract Builder toBuilder(); public static Builder builder() { - return new AutoValue_VirtualMachineScaleSetIpConfigurationProperties.Builder() - .lbBackendAddressPools(null) - .lbInboundNatPools(null); + return new AutoValue_VirtualMachineScaleSetIpConfigurationProperties.Builder(); } @AutoValue.Builder public abstract static class Builder { public abstract Builder publicIPAddressConfiguration(VirtualMachineScaleSetPublicIPAddressConfiguration publicIPAddressConfiguration); - public abstract Builder subnet(Subnet subnet); - public abstract Builder loadBalancerBackendAddressPools(List loadBalancerBackendAddressPools); - public abstract Builder loadBalancerInboundNatPools(List loadBalancerInboundNatPools); - public abstract Builder privateIPAddressVersion(String privateIPAddressVersion); - - public Builder lbBackendAddressPools(List loadBalancerBackendAddressPools) { - return loadBalancerBackendAddressPools(loadBalancerBackendAddressPools != null ? ImmutableList - .copyOf(loadBalancerBackendAddressPools) : ImmutableList.of()); - } - public Builder lbInboundNatPools(List loadBalancerInboundNatPools) { - return loadBalancerInboundNatPools(loadBalancerInboundNatPools != null ? ImmutableList - .copyOf(loadBalancerInboundNatPools) : ImmutableList.of()); - } - public abstract Builder applicationGatewayBackendAddressPools(String applicationGatewayBackendAddressPools); + public abstract VirtualMachineScaleSetIpConfigurationProperties build(); - } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetOSProfile.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetOSProfile.java index 5593457163..e417d5a97f 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetOSProfile.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VirtualMachineScaleSetOSProfile.java @@ -249,14 +249,14 @@ public abstract class VirtualMachineScaleSetOSProfile { .adminPassword(adminPassword) .linuxConfiguration(linuxConfiguration) .windowsConfiguration(windowsConfiguration) - ._secrets(secrets) + .secrets(secrets != null ? ImmutableList.copyOf(secrets) : ImmutableList. of()) .build(); } public abstract Builder toBuilder(); public static Builder builder() { - return new AutoValue_VirtualMachineScaleSetOSProfile.Builder()._secrets(null); + return new AutoValue_VirtualMachineScaleSetOSProfile.Builder(); } @AutoValue.Builder @@ -268,10 +268,6 @@ public abstract class VirtualMachineScaleSetOSProfile { public abstract Builder windowsConfiguration(WindowsConfiguration windowsConfiguration); public abstract Builder secrets(List secrets); - public Builder _secrets(List secrets) { - return secrets(secrets != null ? ImmutableList.copyOf(secrets) : ImmutableList.of()); - } - public abstract VirtualMachineScaleSetOSProfile build(); } } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/CurrentServicePrincipalApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/CurrentServicePrincipalApiLiveTest.java new file mode 100644 index 0000000000..50a1e116bb --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/CurrentServicePrincipalApiLiveTest.java @@ -0,0 +1,34 @@ +/* + * 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 static org.testng.Assert.assertEquals; + +import org.jclouds.azurecompute.arm.domain.ServicePrincipal; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; +import org.testng.annotations.Test; + +@Test(groups = "live", testName = "CurrentServicePrincipalApiLiveTest", singleThreaded = true) +public class CurrentServicePrincipalApiLiveTest extends BaseAzureComputeApiLiveTest { + + @Test + public void testGetCurrentServicePrincipal() { + ServicePrincipal currentUser = api.getServicePrincipal().get(); + assertEquals(currentUser.appId(), identity); + } + +} From 3efce9a3a5bcbcb83a0abc79999fa8228f79f84c Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Mon, 4 Dec 2017 10:06:21 +0100 Subject: [PATCH 84/87] Configure the Graph RBAC API and allow mocking service endpoints --- .../azurecompute/arm/AzureComputeApi.java | 10 +++ .../arm/AzureComputeProviderMetadata.java | 4 +- .../arm/AzureManagementApiMetadata.java | 10 ++- .../arm/config/AzureComputeHttpApiModule.java | 52 +++---------- .../azurecompute/arm/config/GraphRBAC.java | 19 +++++ .../arm/features/GraphRBACApi.java | 50 +++++++++++++ .../arm/config/ParseTenantIdTest.java | 50 +++++++++++++ .../arm/features/GraphRBACApiMockTest.java | 39 ++++++++++ .../VirtualMachineScaleSetApiLiveTest.java | 32 -------- .../internal/BaseAzureComputeApiMockTest.java | 73 +++++++++++++++---- .../src/test/resources/serviceprincipals.json | 53 ++++++++++++++ 11 files changed, 302 insertions(+), 90 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/GraphRBACApi.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/config/ParseTenantIdTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/GraphRBACApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/resources/serviceprincipals.json 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 afc8413225..1f6b72629f 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 @@ -24,6 +24,7 @@ import org.jclouds.azurecompute.arm.domain.ServicePrincipal; import org.jclouds.azurecompute.arm.features.AvailabilitySetApi; import org.jclouds.azurecompute.arm.features.DeploymentApi; import org.jclouds.azurecompute.arm.features.DiskApi; +import org.jclouds.azurecompute.arm.features.GraphRBACApi; import org.jclouds.azurecompute.arm.features.ImageApi; import org.jclouds.azurecompute.arm.features.JobApi; import org.jclouds.azurecompute.arm.features.LoadBalancerApi; @@ -242,6 +243,15 @@ public interface AzureComputeApi extends Closeable { @Delegate MetricDefinitionsApi getMetricsDefinitionsApi(@PathParam("resourceid") String resourceid); + /** + * The Azure Active Directory Graph API provides programmatic access to Azure + * AD through REST API endpoints. + * + * @see docs + */ + @Delegate + GraphRBACApi getGraphRBACApi(); + /** * Returns the information about the current service principal. */ 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 6848167682..335de98c74 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 @@ -37,11 +37,11 @@ import static org.jclouds.oauth.v2.config.OAuthProperties.RESOURCE; import java.net.URI; import java.util.Properties; -import org.jclouds.azurecompute.arm.config.AzureComputeHttpApiModule.CurrentServicePrincipal; import org.jclouds.azurecompute.arm.domain.Region; import org.jclouds.azurecompute.arm.features.AvailabilitySetApi; import org.jclouds.azurecompute.arm.features.DeploymentApi; import org.jclouds.azurecompute.arm.features.DiskApi; +import org.jclouds.azurecompute.arm.features.GraphRBACApi; import org.jclouds.azurecompute.arm.features.ImageApi; import org.jclouds.azurecompute.arm.features.LoadBalancerApi; import org.jclouds.azurecompute.arm.features.LocationApi; @@ -125,7 +125,7 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { properties.put(API_VERSION_PREFIX + MetricDefinitionsApi.class.getSimpleName(), "2017-05-01-preview"); properties.put(API_VERSION_PREFIX + MetricsApi.class.getSimpleName(), "2016-09-01"); properties.put(API_VERSION_PREFIX + VirtualMachineScaleSetApi.class.getSimpleName(), "2017-03-30"); - properties.put(API_VERSION_PREFIX + CurrentServicePrincipal.class.getSimpleName(), "1.6"); + properties.put(API_VERSION_PREFIX + GraphRBACApi.class.getSimpleName(), "1.6"); return properties; } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java index d0c3e21db8..9c73e9986b 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java @@ -16,6 +16,8 @@ */ package org.jclouds.azurecompute.arm; +import static org.jclouds.reflect.Reflection2.typeToken; + import java.net.URI; import java.util.Properties; @@ -32,8 +34,6 @@ import org.jclouds.rest.internal.BaseHttpApiMetadata; import com.google.common.collect.ImmutableSet; import com.google.inject.Module; -import static org.jclouds.reflect.Reflection2.typeToken; - /** * Implementation of {@link ApiMetadata} for Microsoft Azure Resource Manager REST API */ @@ -43,9 +43,13 @@ public class AzureManagementApiMetadata extends BaseHttpApiMetadata { private static final Pattern OAUTH_TENANT_PATTERN = Pattern - .compile("https://login.microsoftonline.com/([^/]+)/oauth2/token"); + .compile("https://login.microsoft(?:online)?.com/([^/]+)/oauth2/token"); @Override protected void bindErrorHandlers() { @@ -82,15 +71,20 @@ public class AzureComputeHttpApiModule extends HttpApiModule { @Override protected void configure() { super.configure(); - bindHttpApi(binder(), CurrentServicePrincipal.class); bind(OAuthScopes.class).toInstance(OAuthScopes.NoScopes.create()); bind(OAuthConfigFactory.class).to(AzureOAuthConfigFactory.class).in(Scopes.SINGLETON); + bindServiceEndpoints(); + } + + protected void bindServiceEndpoints() { + bind(new TypeLiteral>() { + }).annotatedWith(GraphRBAC.class).to(GraphRBACForTenant.class).in(Scopes.SINGLETON); } @Provides @Singleton @Tenant - protected String provideTenant(@Named("oauth.endpoint") final String oauthEndpoint) { + protected final String provideTenant(@Named("oauth.endpoint") final String oauthEndpoint) { Matcher m = OAUTH_TENANT_PATTERN.matcher(oauthEndpoint); if (!m.matches()) { throw new IllegalArgumentException("Could not parse tenantId from: " + oauthEndpoint); @@ -100,37 +94,15 @@ public class AzureComputeHttpApiModule extends HttpApiModule { @Provides @Singleton - @GraphRBAC - protected Supplier graphRBACEndpoint(@Tenant String tenantId) { - return Suppliers.ofInstance(URI.create(GraphRBAC.ENDPOINT + tenantId)); - } - - @Provides - @Singleton - protected Supplier provideServicePrincipal(final CurrentServicePrincipal currentServicePrincipal, + protected final Supplier provideServicePrincipal(final AzureComputeApi api, AtomicReference authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds) { // This supplier must be defensive against any auth exception. return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, new Supplier() { @Override public ServicePrincipal get() { - return currentServicePrincipal.get(); + return api.getGraphRBACApi().getCurrentServicePrincipal(); } }, seconds, TimeUnit.SECONDS); } - - @RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) - @Consumes(MediaType.APPLICATION_JSON) - @Endpoint(GraphRBAC.class) - @OAuthResource(GraphRBAC.ENDPOINT) - public interface CurrentServicePrincipal { - - @Named("servicePrincipal:get") - @GET - @Path("/servicePrincipals") - @QueryParams(keys = "$filter", values = "appId eq '{jclouds.identity}'") - @SelectJson("value") - @OnlyElement - ServicePrincipal get(); - } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/GraphRBAC.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/GraphRBAC.java index 6853782215..a7f8b4f28b 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/GraphRBAC.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/GraphRBAC.java @@ -20,9 +20,13 @@ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.net.URI; +import javax.inject.Inject; import javax.inject.Qualifier; +import com.google.common.base.Supplier; + /** * Provides the Graph RBAC API endpoint for the current tenant. */ @@ -32,4 +36,19 @@ import javax.inject.Qualifier; public @interface GraphRBAC { String ENDPOINT = "https://graph.windows.net/"; + + static class GraphRBACForTenant implements Supplier { + private final String tenantId; + + @Inject + GraphRBACForTenant(@Tenant String tenantId) { + this.tenantId = tenantId; + } + + @Override + public URI get() { + return URI.create(GraphRBAC.ENDPOINT + tenantId); + } + + } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/GraphRBACApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/GraphRBACApi.java new file mode 100644 index 0000000000..fe2bccc4b1 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/GraphRBACApi.java @@ -0,0 +1,50 @@ +/* + * 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 javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.MediaType; + +import org.jclouds.azurecompute.arm.config.GraphRBAC; +import org.jclouds.azurecompute.arm.config.OAuthResource; +import org.jclouds.azurecompute.arm.domain.ServicePrincipal; +import org.jclouds.azurecompute.arm.filters.ApiVersionFilter; +import org.jclouds.oauth.v2.filters.OAuthFilter; +import org.jclouds.rest.annotations.Endpoint; +import org.jclouds.rest.annotations.OnlyElement; +import org.jclouds.rest.annotations.QueryParams; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.SelectJson; + +import com.google.inject.name.Named; + +@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) +@Consumes(MediaType.APPLICATION_JSON) +@Endpoint(GraphRBAC.class) +@OAuthResource(GraphRBAC.ENDPOINT) +public interface GraphRBACApi { + + @Named("servicePrincipal:get") + @GET + @Path("/servicePrincipals") + @QueryParams(keys = "$filter", values = "appId eq '{jclouds.identity}'") + @SelectJson("value") + @OnlyElement + ServicePrincipal getCurrentServicePrincipal(); +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/config/ParseTenantIdTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/config/ParseTenantIdTest.java new file mode 100644 index 0000000000..5894505f89 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/config/ParseTenantIdTest.java @@ -0,0 +1,50 @@ +/* + * 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.config; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; + +import org.testng.annotations.Test; + +@Test(groups = "unit", testName = "ParseTenantIdTest") +public class ParseTenantIdTest { + + @Test + public void testParseTenantId() { + AzureComputeHttpApiModule module = new AzureComputeHttpApiModule(); + + assertEquals(module.provideTenant("https://login.microsoftonline.com/tenantId/oauth2/token"), "tenantId"); + assertEquals(module.provideTenant("https://login.microsoft.com/tenant2/oauth2/token"), "tenant2"); + + assertInvalid(module, "https://login.microsoftonline.com/a/b/c/oauth2/token"); + assertInvalid(module, "https://login.microsoft.com/a/b/c/oauth2/token"); + assertInvalid(module, "https://login.microsoftonline.com//oauth2/token"); + assertInvalid(module, "https://login.microsoft.com//oauth2/token"); + assertInvalid(module, "https://login.microsoftabc.com/tenant/oauth2/token"); + } + + private static void assertInvalid(AzureComputeHttpApiModule module, String endpoint) { + try { + module.provideTenant(endpoint); + fail("Expected an IllegalArgumentException for endpoint: " + endpoint); + } catch (IllegalArgumentException ex) { + assertEquals(ex.getMessage(), "Could not parse tenantId from: " + endpoint); + } + } + +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/GraphRBACApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/GraphRBACApiMockTest.java new file mode 100644 index 0000000000..20b95e2c1d --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/GraphRBACApiMockTest.java @@ -0,0 +1,39 @@ +/* + * 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 static org.testng.Assert.assertEquals; + +import java.io.IOException; + +import org.jclouds.azurecompute.arm.domain.ServicePrincipal; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; +import org.testng.annotations.Test; + +@Test(groups = "unit", testName = "GraphRBACApiMockTest", singleThreaded = true) +public class GraphRBACApiMockTest extends BaseAzureComputeApiMockTest { + + public void testGetCurrentServicePrincipal() throws IOException, InterruptedException { + server.enqueue(jsonResponse("/serviceprincipals.json")); + + ServicePrincipal sp = api.getGraphRBACApi().getCurrentServicePrincipal(); + + assertEquals(sp.appId(), "applicationId"); + assertSent(server, "GET", "/graphrbac/tenant-id/servicePrincipals?$filter=appId%20eq%20%27mock%27&api-version=1.6"); + } + +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineScaleSetApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineScaleSetApiLiveTest.java index d827d70a75..ff93998e73 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineScaleSetApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VirtualMachineScaleSetApiLiveTest.java @@ -17,7 +17,6 @@ package org.jclouds.azurecompute.arm.features; import com.google.common.collect.ImmutableMap; -import org.jclouds.azurecompute.arm.domain.DataDisk; import org.jclouds.azurecompute.arm.domain.Extension; import org.jclouds.azurecompute.arm.domain.ExtensionProfile; import org.jclouds.azurecompute.arm.domain.ExtensionProfileSettings; @@ -69,8 +68,6 @@ public class VirtualMachineScaleSetApiLiveTest extends BaseAzureComputeApiLiveTe private String subscriptionid; private String vmssName; - private VirtualMachineScaleSetSKU SKU; - private String nicName; private String virtualNetworkName; private String subnetId; private Subnet subnet; @@ -151,25 +148,6 @@ public class VirtualMachineScaleSetApiLiveTest extends BaseAzureComputeApiLiveTe return VirtualMachineScaleSetUpgradePolicy.create("Manual"); } - private List getDataDisks() { - List datadisks = new ArrayList(); - - datadisks.add(DataDisk.create(null, "10", 1, null, - null, "FromImage", - "None", getManagedDiskParameters(), - null)); - - return datadisks; - } - - private StorageProfile getStorageProfile() { - return StorageProfile.create(getWindowsImageReference(), getWindowsOSDisk(), getDataDisks()); - } - - private StorageProfile getWindowsStorageProfile_Default() { - return StorageProfile.create(getWindowsImageReference(), getWindowsOSDisk(), null); - } - private StorageProfile getLinuxStorageProfile_Default() { return StorageProfile.create(getLinuxImageReference(), getLinuxOSDisk(), null); } @@ -178,21 +156,11 @@ public class VirtualMachineScaleSetApiLiveTest extends BaseAzureComputeApiLiveTe return ManagedDiskParameters.create(null, "Standard_LRS"); } - private OSDisk getWindowsOSDisk() { - return OSDisk.create("Windows", null, null, null, "FromImage", - null, getManagedDiskParameters(), null); - } - private OSDisk getLinuxOSDisk() { return OSDisk.create("Linux", null, null, null, "FromImage", null, getManagedDiskParameters(), null); } - private ImageReference getWindowsImageReference() { - return ImageReference.create(null, "Microsoft.Windows", "Windows2016", - "Enterprise", "latest"); - } - private ImageReference getLinuxImageReference() { return ImageReference.create(null, "Canonical", "UbuntuServer", "16.04-LTS", "latest"); 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 1a83407f2b..9d5eab09ef 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 @@ -15,30 +15,44 @@ * limitations under the License. */ package org.jclouds.azurecompute.arm.internal; + +import static com.google.common.base.Predicates.not; +import static com.google.common.collect.Iterables.filter; import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor; +import static org.assertj.core.util.Sets.newHashSet; import static org.jclouds.oauth.v2.config.CredentialType.BEARER_TOKEN_CREDENTIALS; import static org.jclouds.oauth.v2.config.OAuthProperties.CREDENTIAL_TYPE; import static org.testng.Assert.assertEquals; import java.io.IOException; +import java.net.URI; import java.util.Properties; import java.util.Set; import org.jclouds.ContextBuilder; import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.AzureComputeProviderMetadata; +import org.jclouds.azurecompute.arm.AzureManagementApiMetadata; +import org.jclouds.azurecompute.arm.config.AzureComputeHttpApiModule; +import org.jclouds.azurecompute.arm.config.GraphRBAC; import org.jclouds.concurrent.config.ExecutorServiceModule; import org.jclouds.date.DateService; +import org.jclouds.providers.ProviderMetadata; import org.jclouds.rest.ApiContext; +import org.jclouds.rest.ConfiguresHttpApi; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import com.google.common.base.Charsets; +import com.google.common.base.Predicates; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableSet; import com.google.common.io.Resources; import com.google.gson.JsonParser; import com.google.inject.Module; +import com.google.inject.TypeLiteral; import com.squareup.okhttp.mockwebserver.MockResponse; import com.squareup.okhttp.mockwebserver.MockWebServer; import com.squareup.okhttp.mockwebserver.RecordedRequest; @@ -48,8 +62,6 @@ public class BaseAzureComputeApiMockTest { private static final String MOCK_BEARER_TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1uQ19WWmNBVGZNNXBPWWlKSE1iYTlnb0VLWSIsImtpZCI6Ik1uQ19WWmNBVGZNNXBPWWlKSE1iYTlnb0VLWSJ9"; private static final String DEFAULT_ENDPOINT = new AzureComputeProviderMetadata().getEndpoint(); - private final Set modules = ImmutableSet. of(new ExecutorServiceModule(sameThreadExecutor())); - protected MockWebServer server; protected AzureComputeApi api; protected ApiContext context; @@ -62,25 +74,42 @@ public class BaseAzureComputeApiMockTest { public void start() throws IOException { server = new MockWebServer(); server.play(); - AzureComputeProviderMetadata pm = AzureComputeProviderMetadata.builder().build(); - context = ContextBuilder.newBuilder(pm) - .credentials("", MOCK_BEARER_TOKEN) + + context = ContextBuilder.newBuilder(testProviderMetadata()) + .credentials("mock", MOCK_BEARER_TOKEN) .endpoint(server.getUrl("/").toString() + "subscriptions/SUBSCRIPTIONID") - .modules(modules) + .modules(setupModules()) .overrides(setupProperties()) .build(); api = context.getApi(); dateService = context.utils().injector().getInstance(DateService.class); } + protected ProviderMetadata testProviderMetadata() { + // Omit the default HTTP API modules to allow overriding + Set> defaultModules = newHashSet(filter( + new AzureManagementApiMetadata().getDefaultModules(), + not(Predicates.> equalTo(AzureComputeHttpApiModule.class)))); + return AzureComputeProviderMetadata.builder() + .apiMetadata(AzureManagementApiMetadata.builder().defaultModules(defaultModules).build()).build(); + } + 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; } + protected Set setupModules() { + ImmutableSet.Builder modules = ImmutableSet.builder(); + modules.add(new ExecutorServiceModule(sameThreadExecutor())); + // Override the default HTTP module to accomodate custom bindings for the + // hardcoded endpoints such as the Graph RBAC API one. + modules.add(new TestAzureComputeHttpApiModule(server)); + return modules.build(); + } + @AfterMethod(alwaysRun = true) public void stop() throws IOException { server.shutdown(); @@ -107,21 +136,22 @@ public class BaseAzureComputeApiMockTest { return new MockResponse().setStatus("HTTP/1.1 202 Accepted"); } - protected MockResponse response204() { return new MockResponse().setStatus("HTTP/1.1 204 No Content"); } protected MockResponse response202WithHeader() { return new MockResponse() - .setStatus("HTTP/1.1 202 Accepted") - .addHeader("Location", "https://management.azure.com/subscriptions/SUBSCRIPTIONID/operationresults/eyJqb2JJZCI6IlJFU09VUkNFR1JPVVBERUxFVElPTkpPQi1SVEVTVC1DRU5UUkFMVVMiLCJqb2JMb2NhdGlvbiI6ImNlbnRyYWx1cyJ9?api-version=2014-04-01"); + .setStatus("HTTP/1.1 202 Accepted") + .addHeader( + "Location", + "https://management.azure.com/subscriptions/SUBSCRIPTIONID/operationresults/eyJqb2JJZCI6IlJFU09VUkNFR1JPVVBERUxFVElPTkpPQi1SVEVTVC1DRU5UUkFMVVMiLCJqb2JMb2NhdGlvbiI6ImNlbnRyYWx1cyJ9?api-version=2014-04-01"); } protected String stringFromResource(String resourceName) { try { - return Resources.toString(getClass().getResource(resourceName), Charsets.UTF_8) - .replace(DEFAULT_ENDPOINT, url("")); + return Resources.toString(getClass().getResource(resourceName), Charsets.UTF_8).replace(DEFAULT_ENDPOINT, + url("")); } catch (IOException e) { throw Throwables.propagate(e); } @@ -137,10 +167,27 @@ public class BaseAzureComputeApiMockTest { } protected RecordedRequest assertSent(MockWebServer server, String method, String path, String json) - throws InterruptedException { + throws InterruptedException { RecordedRequest request = assertSent(server, method, path); assertEquals(request.getHeader("Content-Type"), "application/json"); assertEquals(parser.parse(new String(request.getBody(), Charsets.UTF_8)), parser.parse(json)); return request; } + + @ConfiguresHttpApi + private static class TestAzureComputeHttpApiModule extends AzureComputeHttpApiModule { + private final MockWebServer server; + + public TestAzureComputeHttpApiModule(MockWebServer server) { + this.server = server; + } + + @Override + protected void bindServiceEndpoints() { + // Override the hardcoded service URIs to allow mocking service endpoints + bind(new TypeLiteral>() { + }).annotatedWith(GraphRBAC.class).toInstance( + Suppliers.ofInstance(URI.create(server.getUrl("/graphrbac").toString() + "/tenant-id"))); + } + } } diff --git a/providers/azurecompute-arm/src/test/resources/serviceprincipals.json b/providers/azurecompute-arm/src/test/resources/serviceprincipals.json new file mode 100644 index 0000000000..cdeefa6e24 --- /dev/null +++ b/providers/azurecompute-arm/src/test/resources/serviceprincipals.json @@ -0,0 +1,53 @@ +{ + "odata.metadata": "https://graph.windows.net/tenantId/$metadata#directoryObjects/Microsoft.DirectoryServices.ServicePrincipal", + "value": [ + { + "odata.type": "Microsoft.DirectoryServices.ServicePrincipal", + "objectType": "ServicePrincipal", + "objectId": "objectId", + "deletionTimestamp": null, + "accountEnabled": true, + "addIns": [], + "alternativeNames": [], + "appDisplayName": "jclouds", + "appId": "applicationId", + "appOwnerTenantId": "tenantId", + "appRoleAssignmentRequired": false, + "appRoles": [], + "displayName": "jclouds", + "errorUrl": null, + "homepage": "https://jclouds.apache.org", + "keyCredentials": [], + "logoutUrl": null, + "oauth2Permissions": [ + { + "adminConsentDescription": "Allow the application to access jclouds on behalf of the signed-in user.", + "adminConsentDisplayName": "Access jclouds", + "id": "id", + "isEnabled": true, + "type": "User", + "userConsentDescription": "Allow the application to access jclouds on your behalf.", + "userConsentDisplayName": "Access jclouds", + "value": "user_impersonation" + } + ], + "passwordCredentials": [], + "preferredTokenSigningKeyThumbprint": null, + "publisherName": "Default Directory", + "replyUrls": [ + "https://jclouds.apache.org" + ], + "samlMetadataUrl": null, + "servicePrincipalNames": [ + "https://jclouds.onmicrosoft.com/jcloudsid", + "applicationId" + ], + "servicePrincipalType": "Application", + "tags": [ + "WindowsAzureActiveDirectoryIntegratedApp" + ], + "tokenEncryptionKeyId": null + } + ] +} + From ac5f3a1452b76d4d3d4c22ce7b4796c1965550ec Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Tue, 5 Dec 2017 09:39:39 +0100 Subject: [PATCH 85/87] Rename GraphRBAC live test class --- ...ipalApiLiveTest.java => GraphRBACApiLiveTest.java} | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) rename providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/{CurrentServicePrincipalApiLiveTest.java => GraphRBACApiLiveTest.java} (77%) diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/CurrentServicePrincipalApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/GraphRBACApiLiveTest.java similarity index 77% rename from providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/CurrentServicePrincipalApiLiveTest.java rename to providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/GraphRBACApiLiveTest.java index 50a1e116bb..ca6ce5e3cd 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/CurrentServicePrincipalApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/GraphRBACApiLiveTest.java @@ -22,13 +22,18 @@ import org.jclouds.azurecompute.arm.domain.ServicePrincipal; import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; import org.testng.annotations.Test; -@Test(groups = "live", testName = "CurrentServicePrincipalApiLiveTest", singleThreaded = true) -public class CurrentServicePrincipalApiLiveTest extends BaseAzureComputeApiLiveTest { +@Test(groups = "live", testName = "GraphRBACApiLiveTest", singleThreaded = true) +public class GraphRBACApiLiveTest extends BaseAzureComputeApiLiveTest { @Test - public void testGetCurrentServicePrincipal() { + public void testGetCurrentServicePrincipalSupplier() { ServicePrincipal currentUser = api.getServicePrincipal().get(); assertEquals(currentUser.appId(), identity); } + @Test + public void testGetCurrentServicePrincipal() { + ServicePrincipal currentUser = api.getGraphRBACApi().getCurrentServicePrincipal(); + assertEquals(currentUser.appId(), identity); + } } From a2dee2f84c96ba743e1fa81bd225b066473ea26d Mon Sep 17 00:00:00 2001 From: Jim Spring Date: Fri, 22 Dec 2017 18:37:08 -0800 Subject: [PATCH 86/87] Add Azure KeyVault support --- .../azurecompute/arm/AzureComputeApi.java | 12 +- .../arm/AzureComputeProviderMetadata.java | 2 + .../arm/AzureManagementApiMetadata.java | 2 + .../compute/AzureComputeServiceAdapter.java | 2 +- .../AzureComputeServiceContextModule.java | 269 --- .../compute/config/AzurePredicatesModule.java | 602 ++++++ .../ResourceGroupAndNameAndIngressRules.java | 5 +- .../AzureComputeImageExtension.java | 4 +- .../AzureComputeSecurityGroupExtension.java | 2 +- .../loaders/CreateSecurityGroupIfNeeded.java | 2 +- .../arm/config/AzureComputeProperties.java | 9 + .../azurecompute/arm/domain/Certificate.java | 638 +++++++ .../jclouds/azurecompute/arm/domain/Key.java | 229 +++ .../jclouds/azurecompute/arm/domain/SKU.java | 27 +- .../azurecompute/arm/domain/Secret.java | 186 ++ .../azurecompute/arm/domain/Vault.java | 112 ++ .../arm/domain/VaultProperties.java | 131 ++ .../azurecompute/arm/features/VaultApi.java | 635 +++++++ .../arm/features/LoadBalancerApiLiveTest.java | 2 +- .../arm/features/VaultApiLiveTest.java | 1057 +++++++++++ .../arm/features/VaultApiMockTest.java | 1619 +++++++++++++++++ .../internal/BaseAzureComputeApiLiveTest.java | 62 +- .../internal/BaseAzureComputeApiMockTest.java | 16 +- .../src/test/resources/getvault.json | 60 + .../src/test/resources/vaultbackupkey.json | 3 + .../src/test/resources/vaultbackupsecret.json | 3 + .../src/test/resources/vaultcreate.json | 26 + .../resources/vaultcreatecertificate.json | 11 + .../vaultcreatecertificaterequestbody.json | 21 + .../src/test/resources/vaultcreatekey.json | 15 + .../resources/vaultcreatekeyrequestbody.json | 7 + .../resources/vaultcreaterequestbody.json | 21 + .../resources/vaultdeletecertificate.json | 58 + .../vaultdeletecertificatecontacts.json | 8 + .../vaultdeletecertificateissuer.json | 21 + .../vaultdeletecertificateoperation.json | 11 + .../src/test/resources/vaultdeletekey.json | 15 + .../src/test/resources/vaultdeletesecret.json | 10 + .../src/test/resources/vaultget.json | 26 + .../test/resources/vaultgetcertificate.json | 55 + .../vaultgetcertificatecontacts.json | 8 + .../resources/vaultgetcertificateissuer.json | 21 + .../vaultgetcertificateoperation.json | 11 + .../resources/vaultgetcertificatepolicy.json | 37 + .../src/test/resources/vaultgetdeleted.json | 12 + .../resources/vaultgetdeletedcertificate.json | 55 + .../test/resources/vaultgetdeletedkey.json | 18 + .../test/resources/vaultgetdeletedsecret.json | 13 + .../src/test/resources/vaultgetkey.json | 15 + .../test/resources/vaultgetkeyversions.json | 23 + .../src/test/resources/vaultgetsecret.json | 11 + .../resources/vaultgetsecretversions.json | 25 + .../test/resources/vaultimportablecert.txt | 58 + .../resources/vaultimportcertificate.json | 52 + .../vaultimportcertificaterequestbody.json | 9 + .../resources/vaultimportkeyrequestbody.json | 18 + .../src/test/resources/vaultkeybackup.txt | 1 + .../src/test/resources/vaultkeydecrypt.json | 4 + .../resources/vaultkeydecryptrequestbody.json | 4 + .../src/test/resources/vaultkeyencrypt.json | 4 + .../resources/vaultkeyencryptrequestbody.json | 4 + .../src/test/resources/vaultkeysign.json | 4 + .../resources/vaultkeysignrequestbody.json | 4 + .../src/test/resources/vaultkeyunwrap.json | 4 + .../resources/vaultkeyunwraprequestbody.json | 4 + .../src/test/resources/vaultkeyverify.json | 3 + .../resources/vaultkeyverifyrequestbody.json | 5 + .../src/test/resources/vaultkeywrap.json | 4 + .../resources/vaultkeywraprequestbody.json | 4 + .../src/test/resources/vaultlist.json | 29 + .../vaultlistcertificateissuers.json | 7 + .../test/resources/vaultlistcertificates.json | 27 + .../vaultlistcertificateversions.json | 17 + .../src/test/resources/vaultlistdeleted.json | 15 + .../vaultlistdeletedcertificates.json | 18 + .../test/resources/vaultlistdeletedkeys.json | 15 + .../resources/vaultlistdeletedsecrets.json | 16 + .../src/test/resources/vaultlistkeys.json | 42 + .../src/test/resources/vaultlistsecrets.json | 40 + .../test/resources/vaultmergecertificate.json | 62 + .../vaultmergecertificaterequestbody.json | 10 + .../src/test/resources/vaultmergex5c-1.txt | 1 + .../src/test/resources/vaultmergex5c-2.txt | 1 + .../src/test/resources/vaultmergex5c-3.txt | 1 + .../vaultrecoverdeletedcertificate.json | 52 + .../resources/vaultrecoverdeletedkey.json | 15 + .../resources/vaultrecoverdeletedsecret.json | 10 + .../src/test/resources/vaultrestorekey.json | 15 + .../resources/vaultrestorekeyrequestbody.json | 3 + .../test/resources/vaultrestoresecret.json | 10 + .../vaultrestoresecretrequestbody.json | 3 + .../src/test/resources/vaultsamplesecret.txt | 27 + .../src/test/resources/vaultsecretbackup.txt | 1 + .../vaultsetcertificatecontacts.json | 8 + ...aultsetcertificatecontactsrequestbody.json | 7 + .../resources/vaultsetcertificateissuer.json | 21 + .../vaultsetcertificateissuerrequestbody.json | 15 + .../src/test/resources/vaultsetsecret.json | 11 + .../resources/vaultsetsecretrequestbody.json | 7 + .../resources/vaultupdatecertificate.json | 58 + .../vaultupdatecertificateissuer.json | 21 + ...ultupdatecertificateissuerrequestbody.json | 15 + .../vaultupdatecertificateoperation.json | 11 + ...updatecertificateoperationrequestbody.json | 3 + .../vaultupdatecertificatepolicy.json | 37 + ...ultupdatecertificatepolicyrequestbody.json | 8 + .../vaultupdatecertificaterequestbody.json | 1 + .../src/test/resources/vaultupdatekey.json | 18 + .../resources/vaultupdatekeyrequestbody.json | 5 + .../resources/vaultupdatekeywithversion.json | 18 + .../src/test/resources/vaultupdatesecret.json | 13 + .../vaultupdatesecretrequestbody.json | 5 + .../vaultupdatesecretwithversion.json | 13 + ...ultupdatesecretwithversionrequestbody.json | 5 + 114 files changed, 6862 insertions(+), 306 deletions(-) create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/config/AzurePredicatesModule.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Certificate.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Key.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Secret.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Vault.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VaultProperties.java create mode 100644 providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VaultApi.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VaultApiLiveTest.java create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VaultApiMockTest.java create mode 100644 providers/azurecompute-arm/src/test/resources/getvault.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultbackupkey.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultbackupsecret.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultcreate.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultcreatecertificate.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultcreatecertificaterequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultcreatekey.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultcreatekeyrequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultcreaterequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultdeletecertificate.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultdeletecertificatecontacts.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultdeletecertificateissuer.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultdeletecertificateoperation.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultdeletekey.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultdeletesecret.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultget.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultgetcertificate.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultgetcertificatecontacts.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultgetcertificateissuer.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultgetcertificateoperation.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultgetcertificatepolicy.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultgetdeleted.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultgetdeletedcertificate.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultgetdeletedkey.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultgetdeletedsecret.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultgetkey.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultgetkeyversions.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultgetsecret.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultgetsecretversions.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultimportablecert.txt create mode 100644 providers/azurecompute-arm/src/test/resources/vaultimportcertificate.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultimportcertificaterequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultimportkeyrequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultkeybackup.txt create mode 100644 providers/azurecompute-arm/src/test/resources/vaultkeydecrypt.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultkeydecryptrequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultkeyencrypt.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultkeyencryptrequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultkeysign.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultkeysignrequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultkeyunwrap.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultkeyunwraprequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultkeyverify.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultkeyverifyrequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultkeywrap.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultkeywraprequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultlist.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultlistcertificateissuers.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultlistcertificates.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultlistcertificateversions.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultlistdeleted.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultlistdeletedcertificates.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultlistdeletedkeys.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultlistdeletedsecrets.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultlistkeys.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultlistsecrets.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultmergecertificate.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultmergecertificaterequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultmergex5c-1.txt create mode 100644 providers/azurecompute-arm/src/test/resources/vaultmergex5c-2.txt create mode 100644 providers/azurecompute-arm/src/test/resources/vaultmergex5c-3.txt create mode 100644 providers/azurecompute-arm/src/test/resources/vaultrecoverdeletedcertificate.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultrecoverdeletedkey.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultrecoverdeletedsecret.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultrestorekey.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultrestorekeyrequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultrestoresecret.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultrestoresecretrequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultsamplesecret.txt create mode 100644 providers/azurecompute-arm/src/test/resources/vaultsecretbackup.txt create mode 100644 providers/azurecompute-arm/src/test/resources/vaultsetcertificatecontacts.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultsetcertificatecontactsrequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultsetcertificateissuer.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultsetcertificateissuerrequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultsetsecret.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultsetsecretrequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultupdatecertificate.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultupdatecertificateissuer.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultupdatecertificateissuerrequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultupdatecertificateoperation.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultupdatecertificateoperationrequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultupdatecertificatepolicy.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultupdatecertificatepolicyrequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultupdatecertificaterequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultupdatekey.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultupdatekeyrequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultupdatekeywithversion.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultupdatesecret.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultupdatesecretrequestbody.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultupdatesecretwithversion.json create mode 100644 providers/azurecompute-arm/src/test/resources/vaultupdatesecretwithversionrequestbody.json 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 1f6b72629f..d62a5b70e0 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 @@ -41,6 +41,7 @@ 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.VaultApi; import org.jclouds.azurecompute.arm.features.VirtualMachineApi; import org.jclouds.azurecompute.arm.features.VirtualMachineScaleSetApi; import org.jclouds.azurecompute.arm.features.VirtualNetworkApi; @@ -242,7 +243,7 @@ public interface AzureComputeApi extends Closeable { */ @Delegate MetricDefinitionsApi getMetricsDefinitionsApi(@PathParam("resourceid") String resourceid); - + /** * The Azure Active Directory Graph API provides programmatic access to Azure * AD through REST API endpoints. @@ -252,6 +253,15 @@ public interface AzureComputeApi extends Closeable { @Delegate GraphRBACApi getGraphRBACApi(); + /** + * Managing your key vaults as well as the keys, secrets, and certificates within your key vaults can be + * accomplished through a REST interface. + * + * @see docs + */ + @Delegate + VaultApi getVaultApi(@PathParam("resourcegroup") String resourcegroup); + /** * Returns the information about the current service principal. */ 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 335de98c74..c85beb984e 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 @@ -57,6 +57,7 @@ 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.VaultApi; import org.jclouds.azurecompute.arm.features.VirtualMachineApi; import org.jclouds.azurecompute.arm.features.VirtualMachineScaleSetApi; import org.jclouds.azurecompute.arm.features.VirtualNetworkApi; @@ -126,6 +127,7 @@ public class AzureComputeProviderMetadata extends BaseProviderMetadata { properties.put(API_VERSION_PREFIX + MetricsApi.class.getSimpleName(), "2016-09-01"); properties.put(API_VERSION_PREFIX + VirtualMachineScaleSetApi.class.getSimpleName(), "2017-03-30"); properties.put(API_VERSION_PREFIX + GraphRBACApi.class.getSimpleName(), "1.6"); + properties.put(API_VERSION_PREFIX + VaultApi.class.getSimpleName(), "2016-10-01"); return properties; } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java index 9c73e9986b..56cb7880f4 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/AzureManagementApiMetadata.java @@ -23,6 +23,7 @@ import java.util.Properties; import org.jclouds.apis.ApiMetadata; import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule; +import org.jclouds.azurecompute.arm.compute.config.AzurePredicatesModule; import org.jclouds.azurecompute.arm.config.AzureComputeHttpApiModule; import org.jclouds.azurecompute.arm.config.AzureComputeParserModule; import org.jclouds.azurecompute.arm.config.AzureComputeRateLimitModule; @@ -80,6 +81,7 @@ public class AzureManagementApiMetadata extends BaseHttpApiMetadata defaultResourceGroup(CacheLoader in) { return CacheBuilder.newBuilder().build(in); } - - @Provides - @Named(TIMEOUT_NODE_RUNNING) - protected VirtualMachineInStatePredicateFactory provideVirtualMachineRunningPredicate(final AzureComputeApi api, - final Timeouts timeouts, final PollPeriod pollPeriod) { - return new VirtualMachineInStatePredicateFactory(api, PowerState.RUNNING, timeouts.nodeRunning, - pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); - } - - @Provides - @Named(TIMEOUT_NODE_TERMINATED) - protected Predicate provideNodeTerminatedPredicate(final AzureComputeApi api, final Timeouts timeouts, - final PollPeriod pollPeriod) { - return retry(new ActionDonePredicate(api), timeouts.nodeTerminated, pollPeriod.pollInitialPeriod, - pollPeriod.pollMaxPeriod); - } - - @Provides - @Named(TIMEOUT_IMAGE_AVAILABLE) - protected Predicate provideImageCapturedPredicate(final AzureComputeApi api, final Timeouts timeouts, - final PollPeriod pollPeriod) { - return retry(new ImageCapturedPredicate(api), timeouts.imageAvailable, pollPeriod.pollInitialPeriod, - pollPeriod.pollMaxPeriod); - } - - @Provides - @Named(TIMEOUT_RESOURCE_DELETED) - protected Predicate provideResourceDeletedPredicate(final AzureComputeApi api, final Timeouts timeouts, - final PollPeriod pollPeriod) { - return retry(new ActionDonePredicate(api), timeouts.nodeTerminated, pollPeriod.pollInitialPeriod, - pollPeriod.pollMaxPeriod); - } - - @Provides - @Named(TIMEOUT_NODE_SUSPENDED) - protected VirtualMachineInStatePredicateFactory provideNodeSuspendedPredicate(final AzureComputeApi api, - final Timeouts timeouts, final PollPeriod pollPeriod) { - return new VirtualMachineInStatePredicateFactory(api, PowerState.STOPPED, timeouts.nodeTerminated, - pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); - } - - @Provides - protected PublicIpAvailablePredicateFactory providePublicIpAvailablePredicate(final AzureComputeApi api, - Predicate> resourceAvailable) { - return new PublicIpAvailablePredicateFactory(api, resourceAvailable); - } - - @Provides - protected SecurityGroupAvailablePredicateFactory provideSecurityGroupAvailablePredicate(final AzureComputeApi api, - Predicate> resourceAvailable) { - return new SecurityGroupAvailablePredicateFactory(api, resourceAvailable); - } - - @Provides - protected ImageAvailablePredicateFactory provideImageAvailablePredicate(final AzureComputeApi api, - Predicate> resourceAvailable, final Timeouts timeouts, final PollPeriod pollPeriod) { - return new ImageAvailablePredicateFactory(api, retry(new ResourceInStatusPredicate("Succeeded"), - timeouts.imageAvailable, pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod)); - } - - @Provides - protected Predicate> provideResourceAvailablePredicate(final AzureComputeApi api, - @Named(OPERATION_TIMEOUT) Integer operationTimeout, PollPeriod pollPeriod) { - return retry(new ResourceInStatusPredicate("Succeeded"), operationTimeout, pollPeriod.pollInitialPeriod, - pollPeriod.pollMaxPeriod); - } - - @Provides - @Named("STORAGE") - protected Predicate provideStorageAccountAvailablePredicate(final AzureComputeApi api, - @Named(OPERATION_TIMEOUT) Integer operationTimeout, PollPeriod pollPeriod) { - return retry(new ActionDonePredicate(api), operationTimeout, pollPeriod.pollInitialPeriod, - pollPeriod.pollMaxPeriod); - } - - @VisibleForTesting - static class ActionDonePredicate implements Predicate { - - private final AzureComputeApi api; - - public ActionDonePredicate(final AzureComputeApi api) { - this.api = checkNotNull(api, "api must not be null"); - } - - @Override - public boolean apply(final URI uri) { - checkNotNull(uri, "uri cannot be null"); - return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri) - || ParseJobStatus.JobStatus.NO_CONTENT == api.getJobApi().jobStatus(uri); - } - - } - - @VisibleForTesting - static class ImageCapturedPredicate implements Predicate { - - private final AzureComputeApi api; - - public ImageCapturedPredicate(final AzureComputeApi api) { - this.api = checkNotNull(api, "api must not be null"); - } - - @Override - public boolean apply(final URI uri) { - checkNotNull(uri, "uri cannot be null"); - if (api.getJobApi().jobStatus(uri) != ParseJobStatus.JobStatus.DONE) { - return false; - } - List definitions = api.getJobApi().captureStatus(uri); - return definitions != null; - } - } - - public static class VirtualMachineInStatePredicateFactory { - - private final AzureComputeApi api; - private final PowerState powerState; - private final long timeout; - private final long period; - private final long maxPeriod; - - VirtualMachineInStatePredicateFactory(final AzureComputeApi api, final PowerState powerState, final long timeout, - final long period, final long maxPeriod) { - this.api = checkNotNull(api, "api cannot be null"); - this.powerState = checkNotNull(powerState, "powerState cannot be null"); - this.timeout = timeout; - this.period = period; - this.maxPeriod = maxPeriod; - } - - public Predicate create(final String azureGroup) { - return retry(new Predicate() { - @Override - public boolean apply(final String name) { - checkNotNull(name, "name cannot be null"); - VirtualMachineInstance vmInstance = api.getVirtualMachineApi(azureGroup).getInstanceDetails(name); - if (vmInstance == null) { - return false; - } - return powerState == vmInstance.powerState(); - } - }, timeout, period, maxPeriod); - } - } - - public static class ResourceInStatusPredicate implements Predicate> { - private final String expectedStatus; - - ResourceInStatusPredicate(String expectedStatus) { - this.expectedStatus = checkNotNull(expectedStatus, "expectedStatus cannot be null"); - } - - @Override - public boolean apply(Supplier provisionableSupplier) { - checkNotNull(provisionableSupplier, "provisionableSupplier supplier cannot be null"); - Provisionable provisionable = provisionableSupplier.get(); - return provisionable != null && provisionable.provisioningState().equalsIgnoreCase(expectedStatus); - } - } - - public static class PublicIpAvailablePredicateFactory { - private final AzureComputeApi api; - private final Predicate> resourceAvailable; - - PublicIpAvailablePredicateFactory(final AzureComputeApi api, Predicate> resourceAvailable) { - this.api = checkNotNull(api, "api cannot be null"); - this.resourceAvailable = resourceAvailable; - } - - public Predicate create(final String azureGroup) { - checkNotNull(azureGroup, "azureGroup cannot be null"); - return new Predicate() { - @Override - public boolean apply(final String name) { - checkNotNull(name, "name cannot be null"); - return resourceAvailable.apply(new Supplier() { - @Override - public Provisionable get() { - PublicIPAddress publicIp = api.getPublicIPAddressApi(azureGroup).get(name); - return publicIp == null ? null : publicIp.properties(); - } - }); - } - }; - } - } - - public static class SecurityGroupAvailablePredicateFactory { - private final AzureComputeApi api; - private final Predicate> resourceAvailable; - - SecurityGroupAvailablePredicateFactory(final AzureComputeApi api, - Predicate> resourceAvailable) { - this.api = checkNotNull(api, "api cannot be null"); - this.resourceAvailable = resourceAvailable; - } - - public Predicate create(final String resourceGroup) { - checkNotNull(resourceGroup, "resourceGroup cannot be null"); - return new Predicate() { - @Override - public boolean apply(final String name) { - checkNotNull(name, "name cannot be null"); - return resourceAvailable.apply(new Supplier() { - @Override - public Provisionable get() { - NetworkSecurityGroup sg = api.getNetworkSecurityGroupApi(resourceGroup).get(name); - return sg == null ? null : sg.properties(); - } - }); - } - }; - } - } - - public static class ImageAvailablePredicateFactory { - private final AzureComputeApi api; - private final Predicate> resourceAvailable; - - ImageAvailablePredicateFactory(final AzureComputeApi api, - Predicate> resourceAvailable) { - this.api = checkNotNull(api, "api cannot be null"); - this.resourceAvailable = resourceAvailable; - } - - public Predicate create(final String resourceGroup) { - checkNotNull(resourceGroup, "resourceGroup cannot be null"); - return new Predicate() { - @Override - public boolean apply(final String name) { - checkNotNull(name, "name cannot be null"); - return resourceAvailable.apply(new Supplier() { - @Override - public Provisionable get() { - Image img = api.getVirtualMachineImageApi(resourceGroup).get(name); - return img == null ? null : img.properties(); - } - }); - } - }; - } - } - } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/config/AzurePredicatesModule.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/config/AzurePredicatesModule.java new file mode 100644 index 0000000000..c8dfd6e860 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/config/AzurePredicatesModule.java @@ -0,0 +1,602 @@ +/* + * 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 com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; +import com.google.common.collect.Iterables; +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.name.Named; + +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.compute.reference.ComputeServiceConstants.PollPeriod; + +import org.jclouds.azurecompute.arm.domain.Image; +import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; +import org.jclouds.azurecompute.arm.domain.Provisionable; +import org.jclouds.azurecompute.arm.domain.PublicIPAddress; +import org.jclouds.azurecompute.arm.domain.ResourceDefinition; +import org.jclouds.azurecompute.arm.domain.Vault; +import org.jclouds.azurecompute.arm.domain.VirtualMachineInstance; +import org.jclouds.azurecompute.arm.functions.ParseJobStatus; +import org.jclouds.azurecompute.arm.AzureComputeApi; +import org.jclouds.azurecompute.arm.domain.Key.DeletedKeyBundle; +import org.jclouds.azurecompute.arm.domain.Key.KeyBundle; +import org.jclouds.azurecompute.arm.domain.Secret.DeletedSecretBundle; +import org.jclouds.azurecompute.arm.domain.Secret.SecretBundle; +import org.jclouds.azurecompute.arm.domain.Certificate.DeletedCertificateBundle; +import org.jclouds.azurecompute.arm.domain.Certificate.CertificateBundle; +import org.jclouds.azurecompute.arm.domain.Certificate.CertificateOperation; + +import java.net.URI; +import java.util.List; + +import static org.jclouds.util.Predicates2.retry; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; +import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_IMAGE_AVAILABLE; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.OPERATION_TIMEOUT; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.VAULT_DELETE_STATUS; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.VAULT_KEY_DELETED_STATUS; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.VAULT_KEY_RECOVERABLE_STATUS; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.VAULT_SECRET_DELETE_STATUS; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.VAULT_SECRET_RECOVERABLE_STATUS; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.VAULT_CERTIFICATE_DELETE_STATUS; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.VAULT_CERTIFICATE_RECOVERABLE_STATUS; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.VAULT_CERTIFICATE_OPERATION_STATUS; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class AzurePredicatesModule extends AbstractModule { + protected void configure() { + } + + @Provides + @Named(TIMEOUT_NODE_RUNNING) + protected VirtualMachineInStatePredicateFactory provideVirtualMachineRunningPredicate(final AzureComputeApi api, + final ComputeServiceConstants.Timeouts timeouts, final PollPeriod pollPeriod) { + return new VirtualMachineInStatePredicateFactory(api, VirtualMachineInstance.PowerState.RUNNING, timeouts.nodeRunning, + pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); + } + + @Provides + @Named(TIMEOUT_NODE_TERMINATED) + protected Predicate provideNodeTerminatedPredicate(final AzureComputeApi api, final ComputeServiceConstants.Timeouts timeouts, + final PollPeriod pollPeriod) { + return retry(new ActionDonePredicate(api), timeouts.nodeTerminated, pollPeriod.pollInitialPeriod, + pollPeriod.pollMaxPeriod); + } + + @Provides + @Named(TIMEOUT_IMAGE_AVAILABLE) + protected Predicate provideImageCapturedPredicate(final AzureComputeApi api, final ComputeServiceConstants.Timeouts timeouts, + final PollPeriod pollPeriod) { + return retry(new ImageCapturedPredicate(api), timeouts.imageAvailable, pollPeriod.pollInitialPeriod, + pollPeriod.pollMaxPeriod); + } + + @Provides + @Named(TIMEOUT_RESOURCE_DELETED) + protected Predicate provideResourceDeletedPredicate(final AzureComputeApi api, final ComputeServiceConstants.Timeouts timeouts, + final PollPeriod pollPeriod) { + return retry(new ActionDonePredicate(api), timeouts.nodeTerminated, pollPeriod.pollInitialPeriod, + pollPeriod.pollMaxPeriod); + } + + @Provides + @Named(TIMEOUT_NODE_SUSPENDED) + protected VirtualMachineInStatePredicateFactory provideNodeSuspendedPredicate(final AzureComputeApi api, + final ComputeServiceConstants.Timeouts timeouts, final PollPeriod pollPeriod) { + return new VirtualMachineInStatePredicateFactory(api, VirtualMachineInstance.PowerState.STOPPED, timeouts.nodeTerminated, + pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); + } + + @Provides + protected PublicIpAvailablePredicateFactory providePublicIpAvailablePredicate(final AzureComputeApi api, + Predicate> resourceAvailable) { + return new PublicIpAvailablePredicateFactory(api, resourceAvailable); + } + + @Provides + protected SecurityGroupAvailablePredicateFactory provideSecurityGroupAvailablePredicate(final AzureComputeApi api, + Predicate> resourceAvailable) { + return new SecurityGroupAvailablePredicateFactory(api, resourceAvailable); + } + + @Provides + protected ImageAvailablePredicateFactory provideImageAvailablePredicate(final AzureComputeApi api, + Predicate> resourceAvailable, final ComputeServiceConstants.Timeouts timeouts, final PollPeriod pollPeriod) { + return new ImageAvailablePredicateFactory(api, retry(new ResourceInStatusPredicate("Succeeded"), + timeouts.imageAvailable, pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod)); + } + + @Provides + protected Predicate> provideResourceAvailablePredicate(final AzureComputeApi api, + @Named(OPERATION_TIMEOUT) Integer operationTimeout, PollPeriod pollPeriod) { + return retry(new ResourceInStatusPredicate("Succeeded"), operationTimeout, pollPeriod.pollInitialPeriod, + pollPeriod.pollMaxPeriod); + } + + @VisibleForTesting + static class ActionDonePredicate implements Predicate { + + private final AzureComputeApi api; + + public ActionDonePredicate(final AzureComputeApi api) { + this.api = checkNotNull(api, "api must not be null"); + } + + @Override + public boolean apply(final URI uri) { + checkNotNull(uri, "uri cannot be null"); + return ParseJobStatus.JobStatus.DONE == api.getJobApi().jobStatus(uri) + || ParseJobStatus.JobStatus.NO_CONTENT == api.getJobApi().jobStatus(uri); + } + } + + @VisibleForTesting + static class ImageCapturedPredicate implements Predicate { + + private final AzureComputeApi api; + + public ImageCapturedPredicate(final AzureComputeApi api) { + this.api = checkNotNull(api, "api must not be null"); + } + + @Override + public boolean apply(final URI uri) { + checkNotNull(uri, "uri cannot be null"); + if (api.getJobApi().jobStatus(uri) != ParseJobStatus.JobStatus.DONE) { + return false; + } + List definitions = api.getJobApi().captureStatus(uri); + return definitions != null; + } + } + + public static class VirtualMachineInStatePredicateFactory { + + private final AzureComputeApi api; + private final VirtualMachineInstance.PowerState powerState; + private final long timeout; + private final long period; + private final long maxPeriod; + + VirtualMachineInStatePredicateFactory(final AzureComputeApi api, final VirtualMachineInstance.PowerState powerState, final long timeout, + final long period, final long maxPeriod) { + this.api = checkNotNull(api, "api cannot be null"); + this.powerState = checkNotNull(powerState, "powerState cannot be null"); + this.timeout = timeout; + this.period = period; + this.maxPeriod = maxPeriod; + } + + public Predicate create(final String azureGroup) { + return retry(new Predicate() { + @Override + public boolean apply(final String name) { + checkNotNull(name, "name cannot be null"); + VirtualMachineInstance vmInstance = api.getVirtualMachineApi(azureGroup).getInstanceDetails(name); + if (vmInstance == null) { + return false; + } + return powerState == vmInstance.powerState(); + } + }, timeout, period, maxPeriod); + } + } + + public static class ResourceInStatusPredicate implements Predicate> { + private final String expectedStatus; + + ResourceInStatusPredicate(String expectedStatus) { + this.expectedStatus = checkNotNull(expectedStatus, "expectedStatus cannot be null"); + } + + @Override + public boolean apply(Supplier provisionableSupplier) { + checkNotNull(provisionableSupplier, "provisionableSupplier supplier cannot be null"); + Provisionable provisionable = provisionableSupplier.get(); + return provisionable != null && provisionable.provisioningState().equalsIgnoreCase(expectedStatus); + } + } + + public static class PublicIpAvailablePredicateFactory { + private final AzureComputeApi api; + private final Predicate> resourceAvailable; + + PublicIpAvailablePredicateFactory(final AzureComputeApi api, Predicate> resourceAvailable) { + this.api = checkNotNull(api, "api cannot be null"); + this.resourceAvailable = resourceAvailable; + } + + public Predicate create(final String azureGroup) { + checkNotNull(azureGroup, "azureGroup cannot be null"); + return new Predicate() { + @Override + public boolean apply(final String name) { + checkNotNull(name, "name cannot be null"); + return resourceAvailable.apply(new Supplier() { + @Override + public Provisionable get() { + PublicIPAddress publicIp = api.getPublicIPAddressApi(azureGroup).get(name); + return publicIp == null ? null : publicIp.properties(); + } + }); + } + }; + } + } + + public static class SecurityGroupAvailablePredicateFactory { + private final AzureComputeApi api; + private final Predicate> resourceAvailable; + + SecurityGroupAvailablePredicateFactory(final AzureComputeApi api, + Predicate> resourceAvailable) { + this.api = checkNotNull(api, "api cannot be null"); + this.resourceAvailable = resourceAvailable; + } + + public Predicate create(final String resourceGroup) { + checkNotNull(resourceGroup, "resourceGroup cannot be null"); + return new Predicate() { + @Override + public boolean apply(final String name) { + checkNotNull(name, "name cannot be null"); + return resourceAvailable.apply(new Supplier() { + @Override + public Provisionable get() { + NetworkSecurityGroup sg = api.getNetworkSecurityGroupApi(resourceGroup).get(name); + return sg == null ? null : sg.properties(); + } + }); + } + }; + } + } + + public static class ImageAvailablePredicateFactory { + private final AzureComputeApi api; + private final Predicate> resourceAvailable; + + ImageAvailablePredicateFactory(final AzureComputeApi api, + Predicate> resourceAvailable) { + this.api = checkNotNull(api, "api cannot be null"); + this.resourceAvailable = resourceAvailable; + } + + public Predicate create(final String resourceGroup) { + checkNotNull(resourceGroup, "resourceGroup cannot be null"); + return new Predicate() { + @Override + public boolean apply(final String name) { + checkNotNull(name, "name cannot be null"); + return resourceAvailable.apply(new Supplier() { + @Override + public Provisionable get() { + Image img = api.getVirtualMachineImageApi(resourceGroup).get(name); + return img == null ? null : img.properties(); + } + }); + } + }; + } + } + + @Provides + @Named(VAULT_DELETE_STATUS) + protected VaultPredicates.DeletedVaultStatusPredicateFactory provideDeletedVaultStatusPredicateFactory(final AzureComputeApi api, + @Named(OPERATION_TIMEOUT) Integer operationTimeout, + final PollPeriod pollPeriod) { + return new VaultPredicates.DeletedVaultStatusPredicateFactory(api, operationTimeout.longValue(), pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); + } + + public static class VaultPredicates { + public static class DeletedVaultStatusPredicateFactory { + private final AzureComputeApi api; + private final long operationTimeout; + private final long initialPeriod; + private final long maxPeriod; + + DeletedVaultStatusPredicateFactory(final AzureComputeApi api, final long operationTimeout, final long initialPeriod, final long maxPeriod) { + this.api = checkNotNull(api, "api cannot be null"); + this.operationTimeout = operationTimeout; + this.initialPeriod = initialPeriod; + this.maxPeriod = maxPeriod; + } + + public Predicate create(final String resourceGroup, final boolean shouldBePresent) { + checkNotNull(resourceGroup, "resourceGroup cannot be null"); + return retry(new Predicate() { + @Override + public boolean apply(final String name) { + checkNotNull(name, "name cannot be null"); + boolean present = false; + List vaults = api.getVaultApi(resourceGroup).listDeletedVaults(); + return shouldBePresent == Iterables.any(vaults, new Predicate() { + @Override public boolean apply(Vault.DeletedVault input) { + return input.name().equals(name); + } + }); + } + }, operationTimeout, initialPeriod, maxPeriod); + } + } + } + + @Provides + @Named(VAULT_KEY_DELETED_STATUS) + protected VaultKeyPredicates.DeletedKeyStatusPredicateFactory provideDeletedKeyStatusPredicateFactory(final AzureComputeApi api, + @Named(OPERATION_TIMEOUT) Integer operationTimeout, + final PollPeriod pollPeriod) { + return new VaultKeyPredicates.DeletedKeyStatusPredicateFactory(api, operationTimeout.longValue(), pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); + } + + @Provides + @Named(VAULT_KEY_RECOVERABLE_STATUS) + protected VaultKeyPredicates.RecoverableKeyStatusPredicateFactory provideRecoverableKeyStatusPredicateFactory(final AzureComputeApi api, + @Named(OPERATION_TIMEOUT) Integer operationTimeout, + final PollPeriod pollPeriod) { + return new VaultKeyPredicates.RecoverableKeyStatusPredicateFactory(api, operationTimeout.longValue(), pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); + } + + public static class VaultKeyPredicates { + public static class DeletedKeyStatusPredicateFactory { + private final AzureComputeApi api; + private final long operationTimeout; + private final long initialPeriod; + private final long maxPeriod; + + DeletedKeyStatusPredicateFactory(final AzureComputeApi api, final long operationTimeout, final long initialPeriod, final long maxPeriod) { + this.api = checkNotNull(api, "api cannot be null"); + this.operationTimeout = operationTimeout; + this.initialPeriod = initialPeriod; + this.maxPeriod = maxPeriod; + } + + public Predicate create(final String resourceGroup, final URI vaultUri, final boolean shouldBePresent) { + checkNotNull(resourceGroup, "resourceGroup cannot be null"); + checkNotNull(vaultUri, "vaultUri cannot be null"); + return retry(new Predicate() { + @Override + public boolean apply(final String name) { + checkNotNull(name, "name cannot be null"); + boolean present = false; + DeletedKeyBundle key = api.getVaultApi(resourceGroup).getDeletedKey(vaultUri, name); + return shouldBePresent == (key != null); + } + }, operationTimeout, initialPeriod, maxPeriod); + } + } + + public static class RecoverableKeyStatusPredicateFactory { + private final AzureComputeApi api; + private final long operationTimeout; + private final long initialPeriod; + private final long maxPeriod; + + RecoverableKeyStatusPredicateFactory(final AzureComputeApi api, final long operationTimeout, final long initialPeriod, final long maxPeriod) { + this.api = checkNotNull(api, "api cannot be null"); + this.operationTimeout = operationTimeout; + this.initialPeriod = initialPeriod; + this.maxPeriod = maxPeriod; + } + + public Predicate create(final String resourceGroup, final URI vaultUri, final boolean isRecovered) { + checkNotNull(resourceGroup, "resourceGroup cannot be null"); + checkNotNull(vaultUri, "vaultUri cannot be null"); + return retry(new Predicate() { + @Override + public boolean apply(final String name) { + checkNotNull(name, "name cannot be null"); + boolean result = false; + KeyBundle key = api.getVaultApi(resourceGroup).getKey(vaultUri, name); + return key != null ? (isRecovered ? true : key.attributes().recoveryLevel().contains("Recoverable")) : false; + } + }, operationTimeout, initialPeriod, maxPeriod); + } + } + } + + @Provides + @Named(VAULT_SECRET_DELETE_STATUS) + protected VaultSecretPredicates.DeletedSecretStatusPredicateFactory provideDeletedSecretStatusPredicateFactory(final AzureComputeApi api, + @Named(OPERATION_TIMEOUT) Integer operationTimeout, + final PollPeriod pollPeriod) { + return new VaultSecretPredicates.DeletedSecretStatusPredicateFactory(api, operationTimeout.longValue(), pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); + } + + @Provides + @Named(VAULT_SECRET_RECOVERABLE_STATUS) + protected VaultSecretPredicates.RecoverableSecretStatusPredicateFactory provideRecoverableSecretStatusPredicateFactory(final AzureComputeApi api, + @Named(OPERATION_TIMEOUT) Integer operationTimeout, + final PollPeriod pollPeriod) { + return new VaultSecretPredicates.RecoverableSecretStatusPredicateFactory(api, operationTimeout.longValue(), pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); + } + + public static class VaultSecretPredicates { + public static class DeletedSecretStatusPredicateFactory { + private final AzureComputeApi api; + private final long operationTimeout; + private final long initialPeriod; + private final long maxPeriod; + + DeletedSecretStatusPredicateFactory(final AzureComputeApi api, final long operationTimeout, final long initialPeriod, final long maxPeriod) { + this.api = checkNotNull(api, "api cannot be null"); + this.operationTimeout = operationTimeout; + this.initialPeriod = initialPeriod; + this.maxPeriod = maxPeriod; + } + + public Predicate create(final String resourceGroup, final URI vaultUri, final boolean shouldBePresent) { + checkNotNull(resourceGroup, "resourceGroup cannot be null"); + checkNotNull(vaultUri, "vaultUri cannot be null"); + return retry(new Predicate() { + @Override + public boolean apply(final String name) { + boolean present = false; + checkNotNull(name, "name cannot be null"); + DeletedSecretBundle secret = api.getVaultApi(resourceGroup).getDeletedSecret(vaultUri, name); + return shouldBePresent == (secret != null); + } + }, operationTimeout, initialPeriod, maxPeriod); + } + } + + public static class RecoverableSecretStatusPredicateFactory { + private final AzureComputeApi api; + private final long operationTimeout; + private final long initialPeriod; + private final long maxPeriod; + + RecoverableSecretStatusPredicateFactory(final AzureComputeApi api, final long operationTimeout, final long initialPeriod, final long maxPeriod) { + this.api = checkNotNull(api, "api cannot be null"); + this.operationTimeout = operationTimeout; + this.initialPeriod = initialPeriod; + this.maxPeriod = maxPeriod; + } + + public Predicate create(final String resourceGroup, final URI vaultUri, final boolean isRecovered) { + checkNotNull(resourceGroup, "resourceGroup cannot be null"); + checkNotNull(vaultUri, "vaultUri cannot be null"); + return retry(new Predicate() { + @Override + public boolean apply(final String name) { + checkNotNull(name, "name cannot be null"); + SecretBundle secret = api.getVaultApi(resourceGroup).getSecret(vaultUri, name, null); + return secret != null ? (isRecovered ? true : secret.attributes().recoveryLevel().contains("Recoverable")) : false; + } + }, operationTimeout, initialPeriod, maxPeriod); + } + } + } + + @Provides + @Named(VAULT_CERTIFICATE_DELETE_STATUS) + protected VaultCertificatePredicates.DeletedCertificateStatusPredicateFactory provideDeletedCertificateStatusPredicateFactory(final AzureComputeApi api, + @Named(OPERATION_TIMEOUT) Integer operationTimeout, + final PollPeriod pollPeriod) { + return new VaultCertificatePredicates.DeletedCertificateStatusPredicateFactory(api, operationTimeout.longValue(), pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); + } + + @Provides + @Named(VAULT_CERTIFICATE_RECOVERABLE_STATUS) + protected VaultCertificatePredicates.RecoverableCertificateStatusPredicateFactory provideRecoverableCertificateStatusPredicateFactory(final AzureComputeApi api, + @Named(OPERATION_TIMEOUT) Integer operationTimeout, + final PollPeriod pollPeriod) { + return new VaultCertificatePredicates.RecoverableCertificateStatusPredicateFactory(api, operationTimeout.longValue(), pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); + } + + @Provides + @Named(VAULT_CERTIFICATE_OPERATION_STATUS) + protected VaultCertificatePredicates.CertificateOperationStatusPredicateFactory provideCertificateOperationStatusPredicateFactory(final AzureComputeApi api, + @Named(OPERATION_TIMEOUT) Integer operationTimeout, + final PollPeriod pollPeriod) { + return new VaultCertificatePredicates.CertificateOperationStatusPredicateFactory(api, operationTimeout.longValue(), pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod); + } + + public static class VaultCertificatePredicates { + public static class DeletedCertificateStatusPredicateFactory { + private final AzureComputeApi api; + private final long operationTimeout; + private final long initialPeriod; + private final long maxPeriod; + + DeletedCertificateStatusPredicateFactory(final AzureComputeApi api, final long operationTimeout, final long initialPeriod, final long maxPeriod) { + this.api = checkNotNull(api, "api cannot be null"); + this.operationTimeout = operationTimeout; + this.initialPeriod = initialPeriod; + this.maxPeriod = maxPeriod; + } + + public Predicate create(final String resourceGroup, final URI vaultUri, final boolean shouldBePresent) { + checkNotNull(resourceGroup, "resourceGroup cannot be null"); + checkNotNull(vaultUri, "vaultUri cannot be null"); + return retry(new Predicate() { + @Override + public boolean apply(final String name) { + boolean present = false; + checkNotNull(name, "name cannot be null"); + DeletedCertificateBundle cert = api.getVaultApi(resourceGroup).getDeletedCertificate(vaultUri, name); + return shouldBePresent == (cert != null); + } + }, operationTimeout, initialPeriod, maxPeriod); + } + } + + public static class RecoverableCertificateStatusPredicateFactory { + private final AzureComputeApi api; + private final long operationTimeout; + private final long initialPeriod; + private final long maxPeriod; + + RecoverableCertificateStatusPredicateFactory(final AzureComputeApi api, final long operationTimeout, final long initialPeriod, final long maxPeriod) { + this.api = checkNotNull(api, "api cannot be null"); + this.operationTimeout = operationTimeout; + this.initialPeriod = initialPeriod; + this.maxPeriod = maxPeriod; + } + + public Predicate create(final String resourceGroup, final URI vaultUri, final boolean isImport) { + checkNotNull(resourceGroup, "resourceGroup cannot be null"); + checkNotNull(vaultUri, "vaultUri cannot be null"); + return retry(new Predicate() { + @Override + public boolean apply(final String name) { + checkNotNull(name, "name cannot be null"); + CertificateBundle cert = api.getVaultApi(resourceGroup).getCertificate(vaultUri, name, null); + return cert != null ? (isImport ? true : cert.attributes().recoveryLevel().contains("Recoverable")) : false; + + } + }, operationTimeout, initialPeriod, maxPeriod); + } + } + + public static class CertificateOperationStatusPredicateFactory { + private final AzureComputeApi api; + private final long operationTimeout; + private final long initialPeriod; + private final long maxPeriod; + + CertificateOperationStatusPredicateFactory(final AzureComputeApi api, final long operationTimeout, final long initialPeriod, final long maxPeriod) { + this.api = checkNotNull(api, "api cannot be null"); + this.operationTimeout = operationTimeout; + this.initialPeriod = initialPeriod; + this.maxPeriod = maxPeriod; + } + + public Predicate create(final String resourceGroup, final URI vaultUri, final boolean isCreate) { + checkNotNull(resourceGroup, "resourceGroup cannot be null"); + checkNotNull(vaultUri, "vaultUri cannot be null"); + return retry(new Predicate() { + @Override + public boolean apply(final String name) { + checkNotNull(name, "name cannot be null"); + boolean result = false; + CertificateOperation certOp = api.getVaultApi(resourceGroup).getCertificateOperation(vaultUri, name); + return isCreate ? ((certOp != null) ? !certOp.status().equals("inProgress") : false) : (certOp == null); + } + }, operationTimeout, initialPeriod, maxPeriod); + } + } + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/domain/ResourceGroupAndNameAndIngressRules.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/domain/ResourceGroupAndNameAndIngressRules.java index 2b07406e45..7c11642264 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/domain/ResourceGroupAndNameAndIngressRules.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/domain/ResourceGroupAndNameAndIngressRules.java @@ -18,6 +18,8 @@ package org.jclouds.azurecompute.arm.compute.domain; import static org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName.fromResourceGroupAndName; +import java.util.Arrays; + import com.google.auto.value.AutoValue; import com.google.common.base.Objects; @@ -28,6 +30,7 @@ public abstract class ResourceGroupAndNameAndIngressRules { public abstract String location(); + @SuppressWarnings("mutable") public abstract int[] inboundPorts(); ResourceGroupAndNameAndIngressRules() { @@ -37,7 +40,7 @@ public abstract class ResourceGroupAndNameAndIngressRules { public static ResourceGroupAndNameAndIngressRules create(String resourceGroup, String location, String name, int[] inboundPorts) { return new AutoValue_ResourceGroupAndNameAndIngressRules(fromResourceGroupAndName(resourceGroup, name), location, - inboundPorts); + Arrays.copyOf(inboundPorts, inboundPorts.length)); } public String name() { 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 d826a51132..6cba2c4020 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 @@ -30,8 +30,8 @@ import javax.annotation.Resource; import org.jclouds.Constants; import org.jclouds.azurecompute.arm.AzureComputeApi; -import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.ImageAvailablePredicateFactory; -import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.VirtualMachineInStatePredicateFactory; +import org.jclouds.azurecompute.arm.compute.config.AzurePredicatesModule.ImageAvailablePredicateFactory; +import org.jclouds.azurecompute.arm.compute.config.AzurePredicatesModule.VirtualMachineInStatePredicateFactory; import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName; import org.jclouds.azurecompute.arm.compute.functions.CustomImageToVMImage; import org.jclouds.azurecompute.arm.domain.IdReference; diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java index eaf820cd57..b31e2a0d84 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/extensions/AzureComputeSecurityGroupExtension.java @@ -36,7 +36,7 @@ import javax.inject.Inject; import javax.inject.Named; import org.jclouds.azurecompute.arm.AzureComputeApi; -import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.SecurityGroupAvailablePredicateFactory; +import org.jclouds.azurecompute.arm.compute.config.AzurePredicatesModule.SecurityGroupAvailablePredicateFactory; import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName; import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; import org.jclouds.azurecompute.arm.domain.NetworkProfile.NetworkInterface; diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/CreateSecurityGroupIfNeeded.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/CreateSecurityGroupIfNeeded.java index 98732d2567..baba6f9767 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/CreateSecurityGroupIfNeeded.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/loaders/CreateSecurityGroupIfNeeded.java @@ -29,7 +29,7 @@ import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.azurecompute.arm.AzureComputeApi; -import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.SecurityGroupAvailablePredicateFactory; +import org.jclouds.azurecompute.arm.compute.config.AzurePredicatesModule.SecurityGroupAvailablePredicateFactory; import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndNameAndIngressRules; import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroupProperties; 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 4ac5eaa064..abe057ddab 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 @@ -34,4 +34,13 @@ public class AzureComputeProperties { public static final String API_VERSION_PREFIX = "jclouds.azurecompute.arm.apiversion."; + // Predicate constants + public static final String VAULT_DELETE_STATUS = "jclouds.azurecompute.arm.vault.delete_status"; + public static final String VAULT_KEY_DELETED_STATUS = "jclouds.azurecompute.arm.vault.key.delete_status"; + public static final String VAULT_KEY_RECOVERABLE_STATUS = "jclouds.azurecompute.arm.vault.key.recoverable_status"; + public static final String VAULT_SECRET_DELETE_STATUS = "jclouds.azurecompute.arm.vault.secret.delete_status"; + public static final String VAULT_SECRET_RECOVERABLE_STATUS = "jclouds.azurecompute.arm.vault.secret.recoverable_status"; + public static final String VAULT_CERTIFICATE_DELETE_STATUS = "jclouds.azurecompute.arm.vault.certificate.delete_status"; + public static final String VAULT_CERTIFICATE_RECOVERABLE_STATUS = "jclouds.azurecompute.arm.vault.certificate.recoverable_status"; + public static final String VAULT_CERTIFICATE_OPERATION_STATUS = "jclouds.azurecompute.arm.vault.certificate.operation_status"; } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Certificate.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Certificate.java new file mode 100644 index 0000000000..65de40c062 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Certificate.java @@ -0,0 +1,638 @@ +/* + * 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 java.util.Map; +import java.util.List; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + + +@AutoValue +public abstract class Certificate { + @AutoValue + public abstract static class CertificateAttributes { + @Nullable + public abstract Integer created(); + + public abstract boolean enabled(); + + @Nullable + public abstract Integer expiry(); + + @Nullable + public abstract Integer notBefore(); + + @Nullable + public abstract String recoveryLevel(); + + @Nullable + public abstract Integer updated(); + + @SerializedNames({"created", "enabled", "exp", "nbf", "recoveryLevel", "updated"}) + public static CertificateAttributes create(final Integer created, + final boolean enabled, + final Integer expiry, + final Integer notBefore, + final String recoveryLevel, + final Integer updated) { + return new AutoValue_Certificate_CertificateAttributes(created, enabled, expiry, notBefore, recoveryLevel, updated); + } + } + + @AutoValue + public abstract static class IssuerParameters { + @Nullable + public abstract String certType(); + + @Nullable + public abstract String name(); + + @SerializedNames({"cty", "name"}) + public static IssuerParameters create(final String certType, + final String name) { + return new AutoValue_Certificate_IssuerParameters(certType, name); + } + } + + @AutoValue + public abstract static class KeyProperties { + @Nullable + public abstract Boolean exportable(); + + @Nullable + public abstract Integer keySize(); + + @Nullable + public abstract String keyType(); + + @Nullable + public abstract Boolean reuseKey(); + + @SerializedNames({"exportable", "key_size", "kty", "reuse_key"}) + public static KeyProperties create(final boolean exportable, + final Integer keySize, + final String keyType, + final boolean reuseKey) { + return new AutoValue_Certificate_KeyProperties(exportable, keySize, keyType, reuseKey); + } + } + + @AutoValue + public abstract static class LifetimeActionTrigger { + @Nullable + public abstract Integer daysBeforeExpiry(); + + @Nullable + public abstract Integer lifetimePercentage(); + + @SerializedNames({"days_before_expiry", "lifetime_percentage"}) + public static LifetimeActionTrigger create(final Integer daysBeforeExpiry, + final Integer lifetimePercentage) { + return new AutoValue_Certificate_LifetimeActionTrigger(daysBeforeExpiry, lifetimePercentage); + } + } + + @AutoValue + public abstract static class LifetimeActionAction { + public abstract String actionType(); + + @SerializedNames({"action_type"}) + public static LifetimeActionAction create(final String actionType) { + return new AutoValue_Certificate_LifetimeActionAction(actionType); + } + } + + @AutoValue + public abstract static class LifetimeAction { + public abstract LifetimeActionAction action(); + + public abstract LifetimeActionTrigger trigger(); + + @SerializedNames({"action", "trigger"}) + public static LifetimeAction create(final LifetimeActionAction action, + final LifetimeActionTrigger trigger) { + return new AutoValue_Certificate_LifetimeAction(action, trigger); + } + } + + @AutoValue + public abstract static class SecretProperties { + public abstract String contentType(); + + @SerializedNames({"contentType"}) + public static SecretProperties create(final String contentType) { + return new AutoValue_Certificate_SecretProperties(contentType); + } + } + + @AutoValue + public abstract static class SubjectAlternativeNames { + public abstract List dnsNames(); + + public abstract List emails(); + + public abstract List upns(); + + @SerializedNames({"dns_names", "emails", "upns"}) + public static SubjectAlternativeNames create(final List dnsNames, + final List emails, + final List upns) { + return new AutoValue_Certificate_SubjectAlternativeNames( + dnsNames != null ? ImmutableList.copyOf(dnsNames) : ImmutableList. of(), + emails != null ? ImmutableList.copyOf(emails) : ImmutableList. of(), + upns != null ? ImmutableList.copyOf(upns) : ImmutableList. of() + ); + } + } + + @AutoValue + public abstract static class X509CertificateProperties { + public abstract List enhancedKeyUsage(); + + public abstract List keyUsage(); + + @Nullable + public abstract SubjectAlternativeNames subjectAltNames(); + + @Nullable + public abstract String subject(); + + @Nullable + public abstract Integer validityMonths(); + + @SerializedNames({"ekus", "key_usage", "sans", "subject", "validity_months"}) + public static X509CertificateProperties create(final List enhancedKeyUsage, + final List keyUsage, + final SubjectAlternativeNames subjectAltNames, + final String subject, + final Integer validityMonths) { + return new AutoValue_Certificate_X509CertificateProperties( + enhancedKeyUsage != null ? ImmutableList.copyOf(enhancedKeyUsage) : ImmutableList. of(), + keyUsage != null ? ImmutableList.copyOf(keyUsage) : ImmutableList. of(), + subjectAltNames, + subject, + validityMonths + ); + } + } + + @AutoValue + public abstract static class CertificatePolicy { + @Nullable + public abstract CertificateAttributes attributes(); + + @Nullable + public abstract String id(); + + @Nullable + public abstract IssuerParameters issuer(); + + @Nullable + public abstract KeyProperties keyProps(); + + public abstract List lifetimeActions(); + + @Nullable + public abstract SecretProperties secretProps(); + + @Nullable + public abstract X509CertificateProperties x509props(); + + @SerializedNames({"attributes", "id", "issuer", "key_props", "lifetime_actions", "secret_props", "x509_props"}) + public static CertificatePolicy create(final CertificateAttributes attributes, + final String id, + final IssuerParameters issuer, + final KeyProperties keyProps, + final List lifetimeActions, + final SecretProperties secretProperties, + final X509CertificateProperties x509Props) { + return new AutoValue_Certificate_CertificatePolicy( + attributes, + id, + issuer, + keyProps, + lifetimeActions != null ? ImmutableList.copyOf(lifetimeActions) : ImmutableList.of(), + secretProperties, + x509Props + ); + } + } + + @AutoValue + public abstract static class CertificateError { + @Nullable + public abstract String code(); + + @Nullable + public abstract String message(); + + @SerializedNames({"code", "message"}) + public static CertificateError create(final String code, + final String message) { + return new AutoValue_Certificate_CertificateError(code, message); + } + } + + @AutoValue + public abstract static class CertificateOperation { + @Nullable + public abstract Boolean cancellationRequested(); + + @Nullable + public abstract String csr(); + + @Nullable + public abstract CertificateError error(); + + @Nullable + public abstract String id(); + + @Nullable + public abstract IssuerParameters issuer(); + + @Nullable + public abstract String requestId(); + + @Nullable + public abstract String status(); + + @Nullable + public abstract String statusDetails(); + + @Nullable + public abstract String target(); + + @SerializedNames({"cancellation_requested", "csr", "error", "id", "issuer", "request_id", "status", "status_details", "target"}) + public static CertificateOperation create(final boolean cancellationRequested, + final String csr, + final CertificateError error, + final String id, + final IssuerParameters issuer, + final String requestId, + final String status, + final String statusDetails, + final String target) { + return new AutoValue_Certificate_CertificateOperation( + cancellationRequested, + csr, + error, + id, + issuer, + requestId, + status, + statusDetails, + target); + } + } + + @AutoValue + public abstract static class CertificateBundle { + @Nullable + public abstract CertificateAttributes attributes(); + + @Nullable + public abstract String certificate(); + + @Nullable + public abstract String contentType(); + + @Nullable + public abstract String id(); + + @Nullable + public abstract String keyId(); + + @Nullable + public abstract CertificatePolicy policy(); + + @Nullable + public abstract String secretId(); + + @Nullable + public abstract Map tags(); + + @Nullable + public abstract String thumbprint(); + + @SerializedNames({"attributes", "cer", "contentType", "id", "kid", "policy", "sid", "tags", "x5t"}) + public static CertificateBundle create(final CertificateAttributes attributes, + final String certificate, + final String contentType, + final String id, + final String keyId, + final CertificatePolicy policy, + final String secretId, + final Map tags, + final String thumbprint) { + return new AutoValue_Certificate_CertificateBundle(attributes, + certificate, + contentType, + id, + keyId, + policy, + secretId, + tags != null ? ImmutableMap.copyOf(tags) : null, + thumbprint + ); + } + } + + @AutoValue + public abstract static class CertificateIssuer { + public abstract String id(); + + public abstract String provider(); + + @SerializedNames({"id", "provider"}) + public static CertificateIssuer create(final String id, + final String provider) { + return new AutoValue_Certificate_CertificateIssuer(id, provider); + } + } + + @AutoValue + public abstract static class IssuerAttributes { + @Nullable + public abstract Integer created(); + + @Nullable + public abstract Boolean enabled(); + + @Nullable + public abstract Integer updated(); + + @SerializedNames({"created", "enabled", "updated"}) + public static IssuerAttributes create(final Integer created, + final Boolean enabled, + final Integer updated) { + return new AutoValue_Certificate_IssuerAttributes(created, enabled, updated); + } + } + + @AutoValue + public abstract static class IssuerCredentials { + @Nullable + public abstract String accountId(); + + @Nullable + public abstract String password(); + + @SerializedNames({"account_id", "pwd"}) + public static IssuerCredentials create(final String accountId, + final String password) { + return new AutoValue_Certificate_IssuerCredentials(accountId, password); + } + } + + @AutoValue + public abstract static class OrganizationDetails { + public abstract List adminDetails(); + + @Nullable + public abstract String id(); + + @SerializedNames({"admin_details", "id"}) + public static OrganizationDetails create(final List adminDetails, + final String id) { + return new AutoValue_Certificate_OrganizationDetails( + adminDetails != null ? ImmutableList.copyOf(adminDetails) : ImmutableList. of(), + id + ); + } + } + + @AutoValue + public abstract static class AdministrationDetails { + @Nullable + public abstract String email(); + + @Nullable + public abstract String firstName(); + + @Nullable + public abstract String lastName(); + + @Nullable + public abstract String phoneNumber(); + + @SerializedNames({"email", "first_name", "last_name", "phone"}) + public static AdministrationDetails create(final String email, + final String firstName, + final String lastName, + final String phoneNumber) { + return new AutoValue_Certificate_AdministrationDetails(email, firstName, lastName, phoneNumber); + } + } + + @AutoValue + public abstract static class IssuerBundle { + @Nullable + public abstract IssuerAttributes attributes(); + + @Nullable + public abstract IssuerCredentials credentials(); + + @Nullable + public abstract String id(); + + @Nullable + public abstract OrganizationDetails organizationDetails(); + + @Nullable + public abstract String provider(); + + @SerializedNames({"attributes", "credentials", "id", "org_details", "provider"}) + public static IssuerBundle create(final IssuerAttributes attributes, + final IssuerCredentials credentials, + final String id, + final OrganizationDetails orgDetails, + final String provider) { + return new AutoValue_Certificate_IssuerBundle(attributes, credentials, id, orgDetails, provider); + } + } + + @AutoValue + public abstract static class Contact { + @Nullable + public abstract String email(); + + @Nullable + public abstract String name(); + + @Nullable + public abstract String phone(); + + @SerializedNames({"email", "name", "phone"}) + public static Contact create(final String email, + final String name, + final String phone) { + return new AutoValue_Certificate_Contact(email, name, phone); + } + } + + @AutoValue + public abstract static class Contacts { + public abstract List contacts(); + + @Nullable + public abstract String id(); + + @SerializedNames({"contacts", "id"}) + public static Contacts create(final List contacts, + final String id) { + return new AutoValue_Certificate_Contacts( + contacts != null ? ImmutableList.copyOf(contacts) : ImmutableList. of(), + id + ); + } + } + + @AutoValue + public abstract static class DeletedCertificateBundle { + @Nullable + public abstract CertificateAttributes attributes(); + + @Nullable + public abstract String bytes(); + + @Nullable + public abstract Integer deletedDate(); + + @Nullable + public abstract String id(); + + @Nullable + public abstract String keyId(); + + @Nullable + public abstract String recoveryId(); + + @Nullable + public abstract Integer scheduledPurgeDate(); + + @Nullable + public abstract String secredId(); + + @Nullable + public abstract Map tags(); + + @Nullable + public abstract String thumbprint(); + + @SerializedNames({"attributes", "cer", "deletedDate", "id", "kid", "recoveryId", "scheduledPurgeDate", "sid", "tags", "x5t"}) + public static DeletedCertificateBundle create(final CertificateAttributes attributes, + final String bytes, + final Integer deletedDate, + final String id, + final String keyId, + final String recoveryId, + final Integer scheduledPurgeDate, + final String secretId, + final Map tags, + final String thumbprint) { + return new AutoValue_Certificate_DeletedCertificateBundle( + attributes, + bytes, + deletedDate, + id, + keyId, + recoveryId, + scheduledPurgeDate, + secretId, + tags != null ? ImmutableMap.copyOf(tags) : null, + thumbprint + ); + } + } + + @AutoValue + public abstract static class DeletedCertificate { + @Nullable + public abstract CertificateAttributes attributes(); + + @Nullable + public abstract Integer deletedDate(); + + @Nullable + public abstract String id(); + + @Nullable + public abstract String recoveryId(); + + @Nullable + public abstract Integer scheduledPurgeDate(); + + @Nullable + public abstract Map tags(); + + @Nullable + public abstract String thumbprint(); + + @SerializedNames({"attributes", "deletedDate", "id", "recoveryId", "scheduledPurgeDate", "tags", "x5t"}) + public static DeletedCertificate create(final CertificateAttributes attributes, + final Integer deletedDate, + final String id, + final String recoveryId, + final Integer scheduledPurgeDate, + final Map tags, + final String thumbprint) { + return new AutoValue_Certificate_DeletedCertificate( + attributes, + deletedDate, + id, + recoveryId, + scheduledPurgeDate, + tags != null ? ImmutableMap.copyOf(tags) : null, + thumbprint + ); + } + } + + @Nullable + public abstract CertificateAttributes attributes(); + + @Nullable + public abstract String id(); + + @Nullable + public abstract Map tags(); + + @Nullable + public abstract String thumbprint(); + + @SerializedNames({"attributes", "id", "tags", "x5t"}) + public static Certificate create(final CertificateAttributes attributes, + final String id, + final Map tags, + final String thumbprint) { + return new AutoValue_Certificate( + attributes, + id, + tags != null ? ImmutableMap.copyOf(tags) : null, + thumbprint + ); + } + + Certificate() { + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Key.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Key.java new file mode 100644 index 0000000000..ed9b778e50 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Key.java @@ -0,0 +1,229 @@ +/* + * 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 java.util.Map; +import java.util.List; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class Key { + @AutoValue + public abstract static class JsonWebKey { + @Nullable + public abstract String crv(); + + @Nullable + public abstract String d(); + + @Nullable + public abstract String dp(); + + @Nullable + public abstract String dq(); + + @Nullable + public abstract String e(); + + @Nullable + public abstract String k(); + + @Nullable + public abstract String keyHsm(); + + public abstract List keyOps(); + + @Nullable + public abstract String kid(); + + @Nullable + public abstract String kty(); + + @Nullable + public abstract String n(); + + @Nullable + public abstract String p(); + + @Nullable + public abstract String q(); + + @Nullable + public abstract String qi(); + + @Nullable + public abstract String x(); + + @Nullable + public abstract String y(); + + @SerializedNames({"crv", "d", "dp", "dq", "e", "k", "key_hsm", "key_ops", "kid", "kty", "n", "p", "q", "qi", "x", "y"}) + public static JsonWebKey create(final String crv, final String d, final String dp, final String dq, + final String e, final String k, final String keyHsm, final List keyOps, + final String kid, final String kty, final String n, final String p, + final String q, final String qi, final String x, final String y) { + return new AutoValue_Key_JsonWebKey( + crv, d, dp, dq, e, k, keyHsm, + keyOps != null ? ImmutableList.copyOf(keyOps) : ImmutableList. of(), + kid, kty, n, p, q, qi, x, y); + } + } + + @AutoValue + public abstract static class KeyAttributes { + @Nullable + public abstract Boolean enabled(); + + @Nullable + public abstract Integer created(); + + @Nullable + public abstract Integer expires(); + + @Nullable + public abstract Integer notBefore(); + + @Nullable + public abstract String recoveryLevel(); + + @Nullable + public abstract Integer updated(); + + @SerializedNames({"enabled", "created", "expires", "notBefore", "recoveryLevel", "updated"}) + public static KeyAttributes create(final Boolean enabled, + final Integer created, + final Integer expires, + final Integer notBefore, + final String recoveryLevel, + final Integer updated) { + return new AutoValue_Key_KeyAttributes(enabled, created, expires, notBefore, recoveryLevel, updated); + } + + KeyAttributes() { + } + } + + @AutoValue + public abstract static class KeyBundle { + @Nullable + public abstract KeyAttributes attributes(); + + @Nullable + public abstract JsonWebKey key(); + + @Nullable + public abstract Boolean managed(); + + @Nullable + public abstract Map tags(); + + @SerializedNames({"attributes", "key", "managed", "tags"}) + public static KeyBundle create(final KeyAttributes attributes, final JsonWebKey key, final boolean managed, final Map tags) { + return new AutoValue_Key_KeyBundle( + attributes, + key, + managed, + tags != null ? ImmutableMap.copyOf(tags) : null + ); + } + } + + @AutoValue + public abstract static class DeletedKeyBundle { + @Nullable + public abstract KeyAttributes attributes(); + + @Nullable + public abstract String deletedDate(); + + @Nullable + public abstract JsonWebKey key(); + + @Nullable + public abstract Boolean managed(); + + @Nullable + public abstract String recoveryId(); + + @Nullable + public abstract String scheduledPurgeDate(); + + @Nullable + public abstract Map tags(); + + @SerializedNames({"attributes", "deletedDate", "key", "managed", "recoveryId", "scheduledPurgeDate", "tags"}) + public static DeletedKeyBundle create(final KeyAttributes attributes, final String deletedDate, final JsonWebKey key, final boolean managed, final String recoveryId, final String scheduledPurgeDate, final Map tags) { + return new AutoValue_Key_DeletedKeyBundle( + attributes, + deletedDate, + key, + managed, + recoveryId, + scheduledPurgeDate, + tags != null ? ImmutableMap.copyOf(tags) : null + + ); + } + } + + @AutoValue + public abstract static class KeyOperationResult { + @Nullable + public abstract String keyId(); + + @Nullable + public abstract String value(); + + @SerializedNames({"kid", "value"}) + public static KeyOperationResult create(final String keyId, final String value) { + return new AutoValue_Key_KeyOperationResult( + keyId, + value + ); + } + } + + @Nullable + public abstract String kid(); + + public abstract KeyAttributes attributes(); + + @Nullable + public abstract Boolean managed(); + + @Nullable + public abstract Map tags(); + + @SerializedNames({"kid", "attributes", "managed", "tags"}) + public static Key create(final String kid, final KeyAttributes attributes, final boolean managed, final Map tags) { + return new AutoValue_Key( + kid, + attributes, + managed, + tags != null ? ImmutableMap.copyOf(tags) : null + ); + } + + Key() { + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/SKU.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/SKU.java index 4c414e54d6..6af4406c71 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/SKU.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/SKU.java @@ -16,36 +16,25 @@ */ package org.jclouds.azurecompute.arm.domain; -import com.google.auto.value.AutoValue; import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; -/** - * SKU - */ +import com.google.auto.value.AutoValue; + @AutoValue public abstract class SKU { - /** - * The location of the SKU - */ @Nullable public abstract String location(); - - /** - * The name of the SKU - */ @Nullable public abstract String name(); - - /** - * The id of the SKU - */ @Nullable public abstract String id(); + @Nullable + public abstract String family(); + + @SerializedNames({"location", "name", "id", "family"}) + public static SKU create(final String location, final String name, final String id, final String family) { - @SerializedNames({"location", "name", "id"}) - public static SKU create(final String location, final String name, final String id) { - - return new AutoValue_SKU(location, name, id); + return new AutoValue_SKU(location, name, id, family); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Secret.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Secret.java new file mode 100644 index 0000000000..789a71c156 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Secret.java @@ -0,0 +1,186 @@ +/* + * 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.common.collect.ImmutableMap; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import java.util.Map; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class Secret { + + @AutoValue + public abstract static class SecretAttributes { + @Nullable + public abstract Boolean enabled(); + + @Nullable + public abstract Integer created(); + + @Nullable + public abstract Integer expires(); + + @Nullable + public abstract Integer notBefore(); + + @Nullable + public abstract String recoveryLevel(); + + @Nullable + public abstract Integer updated(); + + @SerializedNames({"enabled", "created", "expires", "notBefore", "recoveryLevel", "updated"}) + public static SecretAttributes create(final Boolean enabled, + final Integer created, + final Integer expires, + final Integer notBefore, + final String recoveryLevel, + final Integer updated) { + return new AutoValue_Secret_SecretAttributes(enabled, created, expires, notBefore, recoveryLevel, updated); + } + + SecretAttributes() { + } + } + + @AutoValue + public abstract static class DeletedSecretBundle { + @Nullable + public abstract SecretAttributes attributes(); + + @Nullable + public abstract String contentType(); + + @Nullable + public abstract String deletedDate(); + + @Nullable + public abstract String id(); + + @Nullable + public abstract String kid(); + + @Nullable + public abstract Boolean managed(); + + @Nullable + public abstract String recoveryId(); + + @Nullable + public abstract String scheduledPurgeDate(); + + @Nullable + public abstract Map tags(); + + @Nullable + public abstract String value(); + + @SerializedNames({"attributes", "contentType", "deletedDate", "id", "kid", "managed", "recoveryId", "scheduledPurgeDate", "tags", "value"}) + public static DeletedSecretBundle create(final SecretAttributes attributes, + final String contentType, + final String deletedDate, + final String id, + final String kid, + final Boolean managed, + final String recoveryId, + final String scheduledPurgeDate, + final Map tags, + String value) { + return new AutoValue_Secret_DeletedSecretBundle( + attributes, contentType, deletedDate, + id, kid, managed, recoveryId, scheduledPurgeDate, + tags != null ? ImmutableMap.copyOf(tags) : null, + value); + } + } + + @AutoValue + public abstract static class SecretBundle { + @Nullable + public abstract SecretAttributes attributes(); + + @Nullable + public abstract String contentType(); + + @Nullable + public abstract String id(); + + @Nullable + public abstract String kid(); + + @Nullable + public abstract Boolean managed(); + + @Nullable + public abstract Map tags(); + + @Nullable + public abstract String value(); + + @SerializedNames({"attributes", "contentType", "id", "kid", "managed", "tags", "value"}) + public static SecretBundle create(final SecretAttributes attributes, + final String contentType, + final String id, + final String kid, + final Boolean managed, + final Map tags, + String value) { + return new AutoValue_Secret_SecretBundle( + attributes, contentType, id, + kid, managed, + tags != null ? ImmutableMap.copyOf(tags) : null, + value); + } + } + + @Nullable + public abstract SecretAttributes attributes(); + + @Nullable + public abstract String contentType(); + + @Nullable + public abstract String id(); + + @Nullable + public abstract Boolean managed(); + + @Nullable + public abstract Map tags(); + + @SerializedNames({"attributes", "contentType", "id", "managed", "tags"}) + public static Secret create(final SecretAttributes attributes, + final String contentType, + final String id, + final Boolean managed, + final Map tags) { + return new AutoValue_Secret( + attributes, + contentType, + id, + managed, + tags != null ? ImmutableMap.copyOf(tags) : null + ); + } + + Secret() { + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Vault.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Vault.java new file mode 100644 index 0000000000..3683df669f --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Vault.java @@ -0,0 +1,112 @@ +/* + * 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 java.util.Date; +import java.util.Map; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableMap; + +@AutoValue +public abstract class Vault { + + @AutoValue + public abstract static class DeletedVault { + @Nullable public abstract String id(); + @Nullable public abstract String name(); + @Nullable public abstract String type(); + @Nullable public abstract DeletedVaultProperties properties(); + + @SerializedNames({"id", "name", "type", "properties"}) + public static DeletedVault create(final String id, final String name, + final String type, final DeletedVaultProperties properties) { + return new AutoValue_Vault_DeletedVault(id, name, type, properties); + } + } + + @AutoValue + public abstract static class DeletedVaultProperties { + @Nullable public abstract Date deletionDate(); + @Nullable public abstract String location(); + @Nullable public abstract Date scheduledPurgeDate(); + @Nullable public abstract Map tags(); + @Nullable public abstract String vaultId(); + + @SerializedNames({"deletionDate", "location", "scheduledPurgeDate", "tags", "vaultId"}) + public static DeletedVaultProperties create (final Date deletionDate, final String location, + final Date scheduledPurgeDate, final Map tags, + final String vaultId) { + return new AutoValue_Vault_DeletedVaultProperties( + deletionDate, + location, + scheduledPurgeDate, + tags != null ? ImmutableMap.copyOf(tags) : null, + vaultId + ); + } + } + + @Nullable public abstract String id(); + @Nullable public abstract String type(); + public abstract String location(); + @Nullable public abstract Map tags(); + @Nullable public abstract String name(); + public abstract VaultProperties properties(); + + @SerializedNames({"id", "name", "type", "location", "properties", "tags"}) + public static Vault create(final String id, final String name, final String type, + final String location, + final VaultProperties properties, final Map tags) { + return builder() + .id(id) + .name(name) + .type(type) + .location(location) + .properties(properties) + .tags(tags != null ? ImmutableMap.copyOf(tags) : null) + .build(); + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_Vault.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder id(String id); + public abstract Builder name(String name); + public abstract Builder type(String type); + public abstract Builder location(String location); + public abstract Builder properties(VaultProperties properties); + public abstract Builder tags(Map tags); + + abstract Map tags(); + abstract Vault autoBuild(); + + public Vault build() { + tags(tags() != null ? ImmutableMap.copyOf(tags()) : null); + return autoBuild(); + } + + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VaultProperties.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VaultProperties.java new file mode 100644 index 0000000000..5e97cf3fe6 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/VaultProperties.java @@ -0,0 +1,131 @@ +/* + * 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 java.net.URI; +import java.util.List; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; + +@AutoValue +public abstract class VaultProperties { + + @AutoValue + public abstract static class Permissions { + + public abstract List certificates(); + public abstract List keys(); + public abstract List secrets(); + public abstract List storage(); + + @SerializedNames({ "certificates", "keys", "secrets", "storage"}) + public static Permissions create(final List certificates, final List keys, final List secrets, final List storage) { + return new AutoValue_VaultProperties_Permissions( + certificates != null ? ImmutableList.copyOf(certificates) : ImmutableList. of(), + keys != null ? ImmutableList.copyOf(keys) : ImmutableList. of(), + secrets != null ? ImmutableList.copyOf(secrets) : ImmutableList. of(), + storage != null ? ImmutableList.copyOf(storage) : ImmutableList. of() + ); + } + + Permissions() { + + } + } + + @AutoValue + public abstract static class AccessPolicyEntry { + + @Nullable public abstract String applicationId(); + public abstract String objectId(); + public abstract String tenantId(); + @Nullable public abstract Permissions permissions(); + + @SerializedNames({"applicationId", "objectId", "tenantId", "permissions"}) + public static AccessPolicyEntry create(final String applicationId, final String objectId, final String tenantId, final Permissions permissions) { + return new AutoValue_VaultProperties_AccessPolicyEntry(applicationId, objectId, tenantId, permissions); + } + + AccessPolicyEntry() { + + } + } + + @Nullable + public abstract String tenantId(); + @Nullable + public abstract URI vaultUri(); + @Nullable + public abstract Boolean enabledForDeployment(); + @Nullable + public abstract Boolean enabledForTemplateDeployment(); + @Nullable + public abstract Boolean enableSoftDelete(); + @Nullable + public abstract String createMode(); + @Nullable + public abstract SKU sku(); + @Nullable + public abstract List accessPolicies(); + + @SerializedNames({"tenantId", "vaultUri", "enabledForDeployment", "enabledForTemplateDeployment", "enableSoftDelete", "createMode", "sku", "accessPolicies" }) + public static VaultProperties create(final String tenantId, final URI vaultUri, final Boolean enabledForDeployment, final Boolean enabledForTemplateDeployment, final Boolean enableSoftDelete, final String createMode, + final SKU sku, final List accessPolicies) { + return builder() + .tenantId(tenantId) + .vaultUri(vaultUri) + .enabledForDeployment(enabledForDeployment) + .enabledForTemplateDeployment(enabledForTemplateDeployment) + .enableSoftDelete(enableSoftDelete) + .createMode(createMode) + .sku(sku) + .accessPolicies(accessPolicies) + .build(); + } + + public abstract Builder toBuilder(); + + public static Builder builder() { + return new AutoValue_VaultProperties.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder tenantId(String tenantId); + public abstract Builder vaultUri(URI vaultUri); + public abstract Builder enabledForDeployment(Boolean enabledForDeployment); + public abstract Builder enabledForTemplateDeployment(Boolean enabledForTemplateDeployment); + public abstract Builder enableSoftDelete(Boolean enableSoftDelete); + public abstract Builder createMode(String createMode); + public abstract Builder sku(SKU sku); + public abstract Builder accessPolicies(List accessPolicies); + + abstract List accessPolicies(); + + abstract VaultProperties autoBuild(); + + public VaultProperties build() { + return accessPolicies(accessPolicies() != null ? ImmutableList.copyOf(accessPolicies()) : ImmutableList.of()) + .autoBuild(); + } + + } +} diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VaultApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VaultApi.java new file mode 100644 index 0000000000..5ae39ba742 --- /dev/null +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VaultApi.java @@ -0,0 +1,635 @@ +/* + * 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 java.util.List; +import java.util.Map; + +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.core.MediaType; + +import com.google.common.base.Function; + +import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; +import org.jclouds.Fallbacks.FalseOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.azurecompute.arm.config.OAuthResource; +import org.jclouds.azurecompute.arm.domain.Certificate; +import org.jclouds.azurecompute.arm.domain.Certificate.CertificateAttributes; +import org.jclouds.azurecompute.arm.domain.Certificate.CertificateBundle; +import org.jclouds.azurecompute.arm.domain.Certificate.CertificateIssuer; +import org.jclouds.azurecompute.arm.domain.Certificate.CertificateOperation; +import org.jclouds.azurecompute.arm.domain.Certificate.CertificatePolicy; +import org.jclouds.azurecompute.arm.domain.Certificate.Contact; +import org.jclouds.azurecompute.arm.domain.Certificate.Contacts; +import org.jclouds.azurecompute.arm.domain.Certificate.DeletedCertificate; +import org.jclouds.azurecompute.arm.domain.Certificate.DeletedCertificateBundle; +import org.jclouds.azurecompute.arm.domain.Certificate.IssuerAttributes; +import org.jclouds.azurecompute.arm.domain.Certificate.IssuerBundle; +import org.jclouds.azurecompute.arm.domain.Certificate.IssuerCredentials; +import org.jclouds.azurecompute.arm.domain.Certificate.IssuerParameters; +import org.jclouds.azurecompute.arm.domain.Certificate.KeyProperties; +import org.jclouds.azurecompute.arm.domain.Certificate.LifetimeAction; +import org.jclouds.azurecompute.arm.domain.Certificate.OrganizationDetails; +import org.jclouds.azurecompute.arm.domain.Certificate.SecretProperties; +import org.jclouds.azurecompute.arm.domain.Certificate.X509CertificateProperties; +import org.jclouds.azurecompute.arm.domain.Key; +import org.jclouds.azurecompute.arm.domain.Key.DeletedKeyBundle; +import org.jclouds.azurecompute.arm.domain.Key.JsonWebKey; +import org.jclouds.azurecompute.arm.domain.Key.KeyAttributes; +import org.jclouds.azurecompute.arm.domain.Key.KeyBundle; +import org.jclouds.azurecompute.arm.domain.Key.KeyOperationResult; +import org.jclouds.azurecompute.arm.domain.Secret; +import org.jclouds.azurecompute.arm.domain.Secret.DeletedSecretBundle; +import org.jclouds.azurecompute.arm.domain.Secret.SecretAttributes; +import org.jclouds.azurecompute.arm.domain.Secret.SecretBundle; +import org.jclouds.azurecompute.arm.domain.Vault; +import org.jclouds.azurecompute.arm.domain.Vault.DeletedVault; +import org.jclouds.azurecompute.arm.domain.VaultProperties; +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.EndpointParam; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.MapBinder; +import org.jclouds.rest.annotations.PATCH; +import org.jclouds.rest.annotations.PayloadParam; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.SelectJson; +import org.jclouds.rest.binders.BindToJsonPayload; +import org.jclouds.rest.annotations.ParamParser; + +@RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) +@Consumes(MediaType.APPLICATION_JSON) +public interface VaultApi { + static class PrependSlashOrEmptyString implements Function { + public String apply(Object from) { + if ((from == null) || (from.toString().length() == 0)) { + return ""; + } else { + return "/" + from.toString(); + } + } + } + + // Vault operations + @Named("vault:list") + @SelectJson("value") + @GET + @Path("/resourcegroups/{resourcegroup}/providers/Microsoft.KeyVault/vaults") + @Fallback(EmptyListOnNotFoundOr404.class) + List listVaults(); + + @Named("vault:create_or_update") + @PUT + @MapBinder(BindToJsonPayload.class) + @Path("/resourcegroups/{resourcegroup}/providers/Microsoft.KeyVault/vaults/{vaultName}") + Vault createOrUpdateVault(@PathParam("vaultName") String vaultName, @PayloadParam("location") String location, + @PayloadParam("properties") VaultProperties properties, @Nullable @PayloadParam("tags") Map tags); + + @Named("vault:get") + @Path("/resourcegroups/{resourcegroup}/providers/Microsoft.KeyVault/vaults/{vaultName}") + @GET + @Fallback(NullOnNotFoundOr404.class) + Vault getVault(@PathParam("vaultName") String vaultName); + + @Named("vault:delete") + @Path("/resourcegroups/{resourcegroup}/providers/Microsoft.KeyVault/vaults/{vaultName}") + @DELETE + @Fallback(FalseOnNotFoundOr404.class) + boolean deleteVault(@PathParam("vaultName") String vaultName); + + @Named("vault:list_deleted_vaults") + @Path("/providers/Microsoft.KeyVault/deletedVaults") + @GET + @SelectJson("value") + @Fallback(EmptyListOnNotFoundOr404.class) + List listDeletedVaults(); + + @Named("vault:get_deleted") + @GET + @Path("/providers/Microsoft.KeyVault/locations/{location}/deletedVaults/{vaultName}") + @Fallback(NullOnNotFoundOr404.class) + DeletedVault getDeletedVault(@PathParam("location") String location, @PathParam("vaultName") String vaultName); + + @Named("vault:purge") + @POST + @Fallback(FalseOnNotFoundOr404.class) + @Path("/providers/Microsoft.KeyVault/locations/{location}/deletedVaults/{vaultName}/purge") + boolean purgeVault(@PathParam("location") String location, @PathParam("vaultName") String vaultName); + + // Key operations + @Named("key:list") + @SelectJson("value") + @GET + @Fallback(EmptyListOnNotFoundOr404.class) + @Path("/keys") + @OAuthResource("https://vault.azure.net") + List listKeys(@EndpointParam URI keyVaultUri); + + @Named("key:create") + @POST + @MapBinder(BindToJsonPayload.class) + @Path("/keys/{keyName}/create") + @OAuthResource("https://vault.azure.net") + KeyBundle createKey(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName, + @Nullable @PayloadParam("attributes") KeyAttributes attributes, + @Nullable @PayloadParam("crv") String curveName, @Nullable @PayloadParam("key_ops") List keyOps, + @PayloadParam("key_size") int keySize, @PayloadParam("kty") String keyType, + @Nullable @PayloadParam("tags") Map tags); + + @Named("key:import") + @PUT + @MapBinder(BindToJsonPayload.class) + @Path("/keys/{keyName}") + @OAuthResource("https://vault.azure.net") + KeyBundle importKey(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName, + @PayloadParam("Hsm") boolean hsm, @Nullable @PayloadParam("attributes") KeyAttributes attributes, + @Nullable @PayloadParam("key") JsonWebKey key, @Nullable @PayloadParam("tags") Map tags); + + @Named("key:get") + @GET + @Path("/keys/{keyName}") + @Fallback(NullOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + KeyBundle getKey(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName); + + @Named("key:delete") + @DELETE + @Path("/keys/{keyName}") + @Fallback(NullOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + DeletedKeyBundle deleteKey(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName); + + @Named("key:get_versions") + @GET + @SelectJson("value") + @Path("/keys/{keyName}/versions") + @Fallback(EmptyListOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + List getKeyVersions(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName); + + @Named("key:update") + @PATCH + @MapBinder(BindToJsonPayload.class) + @Path("/keys/{keyName}{keyVersion}") + @OAuthResource("https://vault.azure.net") + KeyBundle updateKey(@EndpointParam URI vaultBaseUrl, + @PathParam("keyName") String keyName, + @Nullable @PathParam("keyVersion") @ParamParser(PrependSlashOrEmptyString.class) String keyVersion, + @Nullable @PayloadParam("attributes") KeyAttributes attributes, + @Nullable @PayloadParam("key_ops") List keyOps, + @Nullable @PayloadParam("tags") Map tags); + + @Named("key:backup") + @POST + @SelectJson("value") + @Path("/keys/{keyName}/backup") + @OAuthResource("https://vault.azure.net") + String backupKey(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName); + + @Named("key:restore") + @POST + @MapBinder(BindToJsonPayload.class) + @Path("/keys/restore") + @OAuthResource("https://vault.azure.net") + KeyBundle restoreKey(@EndpointParam URI vaultBaseUrl, @PayloadParam("value") String keyInfo); + + // Soft-delete key operations + @Named("key:list_deleted") + @GET + @SelectJson("value") + @Path("/deletedkeys") + @Fallback(EmptyListOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + List listDeletedKeys(@EndpointParam URI vaultBaseUrl); + + @Named("key:get_deleted") + @GET + @Path("/deletedkeys/{keyName}") + @Fallback(NullOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + DeletedKeyBundle getDeletedKey(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName); + + @Named("key:recover_deleted") + @POST + @Path("/deletedkeys/{keyName}/recover") + @OAuthResource("https://vault.azure.net") + KeyBundle recoverDeletedKey(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName); + + @Named("key:purge_deleted") + @DELETE + @Path("/deletedkeys/{keyName}") + @Fallback(FalseOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + boolean purgeDeletedKey(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName); + + // Key cryptographic operations + @Named("key:crypto_encrypt") + @POST + @Path("/keys/{keyName}{keyVersion}/encrypt") + @MapBinder(BindToJsonPayload.class) + @OAuthResource("https://vault.azure.net") + KeyOperationResult encrypt(@EndpointParam URI vaultBaseUrl, + @PathParam("keyName") String keyName, + @Nullable @PathParam("keyVersion") @ParamParser(PrependSlashOrEmptyString.class) String keyVersion, + @PayloadParam("alg") String algorithm, + @PayloadParam("value") String value); + + @Named("key:crypto_decrypt") + @POST + @Path("/keys/{keyName}{keyVersion}/decrypt") + @MapBinder(BindToJsonPayload.class) + @OAuthResource("https://vault.azure.net") + KeyOperationResult decrypt(@EndpointParam URI vaultBaseUrl, + @PathParam("keyName") String keyName, + @Nullable @PathParam("keyVersion") @ParamParser(PrependSlashOrEmptyString.class) String keyVersion, + @PayloadParam("alg") String algorithm, + @PayloadParam("value") String value); + + @Named("key:crypto_sign") + @POST + @Path("/keys/{keyName}{keyVersion}/sign") + @MapBinder(BindToJsonPayload.class) + @OAuthResource("https://vault.azure.net") + KeyOperationResult sign(@EndpointParam URI vaultBaseUrl, + @PathParam("keyName") String keyName, + @Nullable @PathParam("keyVersion") @ParamParser(PrependSlashOrEmptyString.class) String keyVersion, + @PayloadParam("alg") String algorithm, + @PayloadParam("value") String value); + + @Named("key:crypto_verify") + @POST + @Path("/keys/{keyName}{keyVersion}/verify") + @MapBinder(BindToJsonPayload.class) + @OAuthResource("https://vault.azure.net") + boolean verify(@EndpointParam URI vaultBaseUrl, + @PathParam("keyName") String keyName, + @Nullable @PathParam("keyVersion") @ParamParser(PrependSlashOrEmptyString.class) String keyVersion, + @PayloadParam("alg") String algorithm, + @PayloadParam("digest") String digest, + @PayloadParam("value") String value); + + @Named("key:crypto_wrap") + @POST + @Path("/keys/{keyName}{keyVersion}/wrapkey") + @MapBinder(BindToJsonPayload.class) + @OAuthResource("https://vault.azure.net") + KeyOperationResult wrap(@EndpointParam URI vaultBaseUrl, + @PathParam("keyName") String keyName, + @Nullable @PathParam("keyVersion") @ParamParser(PrependSlashOrEmptyString.class) String keyVersion, + @PayloadParam("alg") String algorithm, + @PayloadParam("value") String value); + + @Named("key:crypto_unwrap") + @POST + @Path("/keys/{keyName}{keyVersion}/unwrapkey") + @MapBinder(BindToJsonPayload.class) + @OAuthResource("https://vault.azure.net") + KeyOperationResult unwrap(@EndpointParam URI vaultBaseUrl, + @PathParam("keyName") String keyName, + @Nullable @PathParam("keyVersion") @ParamParser(PrependSlashOrEmptyString.class) String keyVersion, + @PayloadParam("alg") String algorithm, + @PayloadParam("value") String value); + + // Secret operations + @Named("secret:list") + @SelectJson("value") + @GET + @Fallback(EmptyListOnNotFoundOr404.class) + @Path("/secrets") + @OAuthResource("https://vault.azure.net") + List listSecrets(@EndpointParam URI keyVaultUri); + + @Named("secret:set") + @PUT + @MapBinder(BindToJsonPayload.class) + @Path("/secrets/{secretName}") + @OAuthResource("https://vault.azure.net") + SecretBundle setSecret(@EndpointParam URI keyVaultUri, @PathParam("secretName") String secretName, + @Nullable @PayloadParam("attributes") SecretAttributes attributes, + @Nullable @PayloadParam("contentType") String contentType, + @Nullable @PayloadParam("tags") Map tags, @PayloadParam("value") String value); + + @Named("secret:get") + @GET + @Path("/secrets/{secretName}{secretVersion}") + @Fallback(NullOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + SecretBundle getSecret(@EndpointParam URI vaultBaseUrl, + @PathParam("secretName") String secretName, + @Nullable @PathParam("secretVersion") @ParamParser(PrependSlashOrEmptyString.class) String secretVersion); + + @Named("secret:delete") + @DELETE + @Path("/secrets/{secretName}") + @Fallback(NullOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + DeletedSecretBundle deleteSecret(@EndpointParam URI vaultBaseUrl, @PathParam("secretName") String secretName); + + @Named("secret:get_versions") + @GET + @SelectJson("value") + @Path("/secrets/{secretName}/versions") + @Fallback(EmptyListOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + List getSecretVersions(@EndpointParam URI vaultBaseUrl, @PathParam("secretName") String secretName); + + @Named("secret:update") + @PATCH + @MapBinder(BindToJsonPayload.class) + @Path("/secrets/{secretName}{secretVersion}") + @OAuthResource("https://vault.azure.net") + SecretBundle updateSecret(@EndpointParam URI vaultBaseUrl, + @PathParam("secretName") String secretName, + @Nullable @PathParam("secretVersion") @ParamParser(PrependSlashOrEmptyString.class) String secretVersion, + @Nullable @PayloadParam("attributes") SecretAttributes attributes, + @Nullable @PayloadParam("contentType") String contentType, + @Nullable @PayloadParam("tags") Map tags); + + @Named("secret:backup") + @POST + @SelectJson("value") + @Path("/secrets/{secretName}/backup") + @OAuthResource("https://vault.azure.net") + String backupSecret(@EndpointParam URI vaultBaseUrl, @PathParam("secretName") String secretName); + + @Named("secret:restore") + @POST + @MapBinder(BindToJsonPayload.class) + @Path("/secrets/restore") + @OAuthResource("https://vault.azure.net") + SecretBundle restoreSecret(@EndpointParam URI vaultBaseUrl, @PayloadParam("value") String secretInfo); + + // Soft-delete secret operations + @Named("secret:list_deleted") + @GET + @SelectJson("value") + @Path("/deletedsecrets") + @Fallback(EmptyListOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + List listDeletedSecrets(@EndpointParam URI vaultBaseUrl); + + @Named("secret:get_deleted") + @GET + @Path("/deletedsecrets/{secretName}") + @Fallback(NullOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + DeletedSecretBundle getDeletedSecret(@EndpointParam URI vaultBaseUrl, @PathParam("secretName") String secretName); + + @Named("secret:recover_deleted") + @POST + @Path("/deletedsecrets/{secretName}/recover") + @OAuthResource("https://vault.azure.net") + SecretBundle recoverDeletedSecret(@EndpointParam URI vaultBaseUrl, @PathParam("secretName") String secretName); + + @Named("secret:purge_deleted") + @DELETE + @Path("/deletedsecrets/{secretName}") + @Fallback(FalseOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + boolean purgeDeletedSecret(@EndpointParam URI vaultBaseUrl, @PathParam("secretName") String secretName); + + // Certificate operations + @Named("certificate:create") + @POST + @MapBinder(BindToJsonPayload.class) + @Path("/certificates/{certificateName}/create") + @OAuthResource("https://vault.azure.net") + CertificateOperation createCertificate(@EndpointParam URI vaultBaseUrl, + @PathParam("certificateName") String certificateName, + @Nullable @PayloadParam("attributes") CertificateAttributes attributes, + @Nullable @PayloadParam("policy") CertificatePolicy policy, + @Nullable @PayloadParam("tags") Map tags); + + @Named("certificate:get") + @GET + @Path("/certificates/{certificateName}{certificateVersion}") + @Fallback(NullOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + CertificateBundle getCertificate(@EndpointParam URI vaultBaseUrl, + @PathParam("certificateName") String certificateName, + @Nullable @PathParam("certificateVersion") @ParamParser(PrependSlashOrEmptyString.class) String certificateVersion); + + @Named("certificate:delete") + @DELETE + @Path("/certificates/{certificateName}") + @Fallback(NullOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + DeletedCertificateBundle deleteCertificate(@EndpointParam URI vaultBaseUrl, + @PathParam("certificateName") String certificateName); + + @Named("certificate:list") + @GET + @SelectJson("value") + @Path("/certificates") + @Fallback(EmptyListOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + List getCertificates(@EndpointParam URI vaultBaseUrl); + + @Named("certificate:list_deleted") + @GET + @SelectJson("value") + @Path("/deletedcertificates") + @Fallback(EmptyListOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + List getDeletedCertificates(@EndpointParam URI vaultBaseUrl); + + @Named("certificate:get_deleted") + @GET + @Path("/deletedcertificates/{certificateName}") + @Fallback(NullOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + DeletedCertificateBundle getDeletedCertificate(@EndpointParam URI vaultBaseUrl, + @PathParam("certificateName") String certificateName); + + @Named("certificate:recover_deleted") + @POST + @Path("/deletedcertificates/{certificateName}/recover") + @OAuthResource("https://vault.azure.net") + CertificateBundle recoverDeletedCertificate(@EndpointParam URI vaultBaseUrl, + @PathParam("certificateName") String certificateName); + + @Named("certificate:purge_deleted") + @DELETE + @Path("/deletedcertificates/{certificateName}") + @Fallback(FalseOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + boolean purgeDeletedCertificate(@EndpointParam URI vaultBaseUrl, @PathParam("certificateName") String certificateName); + + @Named("certificate:get_versions") + @GET + @SelectJson("value") + @Path("/certificates/{certificateName}/versions") + @Fallback(EmptyListOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + List getCertificateVersions(@EndpointParam URI vaultBaseUrl, + @PathParam("certificateName") String certificateName); + + @Named("certificate:update") + @PATCH + @MapBinder(BindToJsonPayload.class) + @Path("/certificates/{certificateName}{certificateVersion}") + @OAuthResource("https://vault.azure.net") + CertificateBundle updateCertificate(@EndpointParam URI vaultBaseUrl, + @PathParam("certificateName") String certificateName, + @Nullable @PathParam("certificateVersion") @ParamParser(PrependSlashOrEmptyString.class) String certificateVersion, + @Nullable @PayloadParam("attributes") CertificateAttributes attributes, + @Nullable @PayloadParam("policy") CertificatePolicy policy, + @Nullable @PayloadParam("tags") Map tags); + + @Named("certificate:import") + @POST + @MapBinder(BindToJsonPayload.class) + @Path("/certificates/{certificateName}/import") + @OAuthResource("https://vault.azure.net") + CertificateBundle importCertificate(@EndpointParam URI vaultBaseUrl, + @PathParam("certificateName") String certificateName, + @Nullable @PayloadParam("attributes") CertificateAttributes attributes, + @Nullable @PayloadParam("policy") CertificatePolicy policy, @Nullable @PayloadParam("pwd") String password, + @Nullable @PayloadParam("tags") Map tags, @PayloadParam("value") String value); + + @Named("certificate:merge") + @POST + @MapBinder(BindToJsonPayload.class) + @Path("/certificates/{certificateName}/pending/merge") + @OAuthResource("https://vault.azure.net") + CertificateBundle mergeCertificate(@EndpointParam URI vaultBaseUrl, + @PathParam("certificateName") String certificateName, + @Nullable @PayloadParam("attributes") CertificateAttributes attributes, + @Nullable @PayloadParam("tags") Map tags, @PayloadParam("x5c") List value); + + @Named("certificate:get_operation") + @GET + @Path("/certificates/{certificateName}/pending") + @Fallback(NullOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + CertificateOperation getCertificateOperation(@EndpointParam URI vaultBaseUrl, + @PathParam("certificateName") String certificateName); + + @Named("certificate:update_operation") + @PATCH + @Path("/certificates/{certificateName}/pending") + @MapBinder(BindToJsonPayload.class) + @OAuthResource("https://vault.azure.net") + CertificateOperation updateCertificateOperation(@EndpointParam URI vaultBaseUrl, + @PathParam("certificateName") String certificateName, + @PayloadParam("cancellation_requested") boolean cancellationRequested); + + @Named("certificate:delete_operation") + @DELETE + @Path("/certificates/{certificateName}/pending") + @Fallback(NullOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + CertificateOperation deleteCertificateOperation(@EndpointParam URI vaultBaseUrl, + @PathParam("certificateName") String certificateName); + + @Named("certificate:set_issuer") + @PUT + @Path("/certificates/issuers/{issuerName}") + @MapBinder(BindToJsonPayload.class) + @OAuthResource("https://vault.azure.net") + IssuerBundle setCertificateIssuer(@EndpointParam URI vaultBaseUrl, @PathParam("issuerName") String issuerName, + @Nullable @PayloadParam("attributes") IssuerAttributes attributes, + @Nullable @PayloadParam("credentials") IssuerCredentials credentials, + @Nullable @PayloadParam("org_details") OrganizationDetails orgDetails, + @PayloadParam("provider") String provider); + + @Named("certificate:get_issuers") + @GET + @SelectJson("value") + @Path("/certificates/issuers") + @Fallback(EmptyListOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + List getCertificateIssuers(@EndpointParam URI vaultBaseUrl); + + @Named("certificate:get_issuer") + @GET + @Path("/certificates/issuers/{issuerName}") + @Fallback(NullOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + IssuerBundle getCertificateIssuer(@EndpointParam URI vaultBaseUrl, @PathParam("issuerName") String issuerName); + + @Named("certificate:update_issuer") + @PATCH + @Path("/certificates/issuers/{issuerName}") + @MapBinder(BindToJsonPayload.class) + @OAuthResource("https://vault.azure.net") + IssuerBundle updateCertificateIssuer(@EndpointParam URI vaultBaseUrl, @PathParam("issuerName") String issuerName, + @Nullable @PayloadParam("attributes") IssuerAttributes attributes, + @Nullable @PayloadParam("credentials") IssuerCredentials credentials, + @Nullable @PayloadParam("org_details") OrganizationDetails orgDetails, + @PayloadParam("provider") String provider); + + @Named("certificate:delete_issuer") + @DELETE + @Path("/certificates/issuers/{issuerName}") + @Fallback(NullOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + IssuerBundle deleteCertificateIssuer(@EndpointParam URI vaultBaseUrl, @PathParam("issuerName") String issuerName); + + @Named("certificate:get_contacts") + @GET + @Path("/certificates/contacts") + @Fallback(NullOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + Contacts getCertificateContacts(@EndpointParam URI vaultBaseUrl); + + @Named("certificate:set_contacts") + @PUT + @Path("/certificates/contacts") + @MapBinder(BindToJsonPayload.class) + @OAuthResource("https://vault.azure.net") + Contacts setCertificateContacts(@EndpointParam URI vaultBaseUrl, @PayloadParam("contacts") List contacts); + + @Named("certificate:delete_contacts") + @DELETE + @Path("/certificates/contacts") + @Fallback(NullOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + Contacts deleteCertificateContacts(@EndpointParam URI vaultBaseUrl); + + @Named("certificate:get_policy") + @GET + @Path("/certificates/{certificateName}/policy") + @Fallback(NullOnNotFoundOr404.class) + @OAuthResource("https://vault.azure.net") + CertificatePolicy getCertificatePolicy(@EndpointParam URI vaultBaseUrl, + @PathParam("certificateName") String certificateName); + + @Named("certificate:update_policy") + @PATCH + @MapBinder(BindToJsonPayload.class) + @Path("/certificates/{certificateName}/policy") + @OAuthResource("https://vault.azure.net") + CertificatePolicy updateCertificatePolicy(@EndpointParam URI vaultBaseUrl, + @PathParam("certificateName") String certificateName, + @Nullable @PayloadParam("attributes") CertificateAttributes attributes, + @Nullable @PayloadParam("issuer") IssuerParameters issuer, + @Nullable @PayloadParam("key_props") KeyProperties keyProps, + @Nullable @PayloadParam("lifetime_actions") List lifetimeActions, + @Nullable @PayloadParam("secret_props") SecretProperties secretProps, + @Nullable @PayloadParam("x509_props") X509CertificateProperties x509Props); +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java index 5cf42397a0..adcde2b2fc 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/LoadBalancerApiLiveTest.java @@ -39,7 +39,7 @@ import java.util.Properties; import java.util.Set; import org.jclouds.azurecompute.arm.AzureComputeApi; -import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.PublicIpAvailablePredicateFactory; +import org.jclouds.azurecompute.arm.compute.config.AzurePredicatesModule.PublicIpAvailablePredicateFactory; import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName; import org.jclouds.azurecompute.arm.domain.AvailabilitySet; import org.jclouds.azurecompute.arm.domain.AvailabilitySet.AvailabilitySetProperties; diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VaultApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VaultApiLiveTest.java new file mode 100644 index 0000000000..026aa2863a --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VaultApiLiveTest.java @@ -0,0 +1,1057 @@ +/* + * 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 java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; + +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; +import org.jclouds.azurecompute.arm.domain.Certificate; +import org.jclouds.azurecompute.arm.domain.Certificate.Contact; +import org.jclouds.azurecompute.arm.domain.Certificate.Contacts; +import org.jclouds.azurecompute.arm.domain.Certificate.AdministrationDetails; +import org.jclouds.azurecompute.arm.domain.Certificate.CertificateIssuer; +import org.jclouds.azurecompute.arm.domain.Certificate.CertificateBundle; +import org.jclouds.azurecompute.arm.domain.Certificate.CertificateOperation; +import org.jclouds.azurecompute.arm.domain.Certificate.CertificatePolicy; +import org.jclouds.azurecompute.arm.domain.Certificate.DeletedCertificate; +import org.jclouds.azurecompute.arm.domain.Certificate.DeletedCertificateBundle; +import org.jclouds.azurecompute.arm.domain.Certificate.OrganizationDetails; +import org.jclouds.azurecompute.arm.domain.Certificate.IssuerBundle; +import org.jclouds.azurecompute.arm.domain.Certificate.IssuerCredentials; +import org.jclouds.azurecompute.arm.domain.Certificate.IssuerParameters; +import org.jclouds.azurecompute.arm.domain.Certificate.KeyProperties; +import org.jclouds.azurecompute.arm.domain.Certificate.SecretProperties; +import org.jclouds.azurecompute.arm.domain.Certificate.X509CertificateProperties; +import org.jclouds.azurecompute.arm.domain.Secret; +import org.jclouds.azurecompute.arm.domain.Secret.SecretBundle; +import org.jclouds.azurecompute.arm.domain.Secret.SecretAttributes; +import org.jclouds.azurecompute.arm.domain.Secret.DeletedSecretBundle; +import org.jclouds.azurecompute.arm.domain.Key; +import org.jclouds.azurecompute.arm.domain.Key.JsonWebKey; +import org.jclouds.azurecompute.arm.domain.Key.KeyBundle; +import org.jclouds.azurecompute.arm.domain.Key.KeyAttributes; +import org.jclouds.azurecompute.arm.domain.Key.DeletedKeyBundle; +import org.jclouds.azurecompute.arm.domain.Key.KeyOperationResult; +import org.jclouds.azurecompute.arm.domain.SKU; +import org.jclouds.azurecompute.arm.domain.Vault; +import org.jclouds.azurecompute.arm.domain.Vault.DeletedVault; +import org.jclouds.azurecompute.arm.domain.VaultProperties; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiLiveTest; +import org.testng.SkipException; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; + +import static com.google.common.base.Preconditions.checkState; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertEquals; +import static org.testng.AssertJUnit.assertNull; + +@Test(groups = "live", testName = "VaultApiLiveTest") +public class VaultApiLiveTest extends BaseAzureComputeApiLiveTest { + private String vaultName; + private URI vaultUri = null; + private static String KEY_NAME = "myKey"; + private static String IMPORT_KEY_NAME = "myImportKey"; + private static String RECOVERABLE_KEY_NAME = "myRecoverableKey"; + private static String SECRET_NAME = "mySecret"; + private static String RECOVERABLE_SECRET_NAME = "myRecoverableSecret"; + private static String CERTIFICATE_NAME = "myCertificate"; + private static String TEMP_CERTIFICATE_NAME = "myTempCertificate"; + private static String RECOVERABLE_CERTIFICATE_NAME = "myRecoverableCertificate"; + private static String IMPORTABLE_CERTIFICATE_NAME = "myImportableCertificate"; + private String importableCertificatePem = stringFromResource("/vaultimportablecert.txt"); + private String sampleSecret = stringFromResource("/vaultsamplesecret.txt"); + private static String cryptoText = "R29sZCUyNTIxJTJCR29sZCUyNTIxJTJCR2" + + "9sZCUyQmZyb20lMkJ0aGUlMkJBbWVyaWNhbiUyQlJpdmVyJTI1MjE"; + private static String cryptoAlgorithm = "RSA-OAEP"; + private static String hashToSign = "FvabKT6qGwpml59iHUJ72DZ4XyJcJ8bgpgFA4_8JFmM"; + private static String signatureAlgorithm = "RS256"; + private static String contentEncryptionKey = "YxzoHR65aFwD2_IOiZ5rD08jMSALA1y7b_yYW0G3hyI"; + + @BeforeClass + @Override + public void setup() { + super.setup(); + createTestResourceGroup(); + vaultName = String.format("kv%s", this.getClass().getSimpleName().toLowerCase()); + } + + @AfterClass(alwaysRun = true) + public void forceVaultRemoval() { + // see if the vault has been deleted or not + Vault vault = api().getVault(vaultName); + if (vault != null) { + if ((vault.properties().enableSoftDelete() != null) && vault.properties().enableSoftDelete()) { + api().deleteVault(vaultName); + checkState(deletedVaultStatus.create(resourceGroupName, true).apply(vaultName), + "vault was not deleted before timeout"); + } else { + return; + } + } + + DeletedVault deletedVault = api().getDeletedVault(LOCATION, vaultName); + if (deletedVault != null) { + api().purgeVault(LOCATION, vaultName); + checkState(deletedVaultStatus.create(resourceGroupName, false).apply(vaultName), + "vault was not purged before timeout"); + } + } + + @Test + public void testCreate() { + String objectId = api.getServicePrincipal().get().objectId(); + Vault vault = api().createOrUpdateVault(vaultName, LOCATION, VaultProperties.builder() + .tenantId(tenantId) + .sku(SKU.create(LOCATION, "standard", null, "A")) + .accessPolicies(ImmutableList.of(VaultProperties.AccessPolicyEntry.create(null, objectId, tenantId, + VaultProperties.Permissions.create( + ImmutableList.of( // certificates + "Get", + "List", + "Update", + "Create", + "Import", + "Delete", + "ManageContacts", + "ManageIssuers", + "GetIssuers", + "ListIssuers", + "SetIssuers", + "DeleteIssuers", + "Purge", + "Recover" + ), + ImmutableList.of( // keys + "Get", + "List", + "Update", + "Create", + "Import", + "Delete", + "Recover", + "Backup", + "Restore", + "Purge", + "Encrypt", + "Decrypt", + "Sign", + "Verify", + "WrapKey", + "UnwrapKey" + ), + ImmutableList.of( // secrets + "Get", + "List", + "Set", + "Delete", + "Recover", + "Backup", + "Restore", + "Purge" + ), + ImmutableList.of() + )))) + .build(), + null); + vaultUri = vault.properties().vaultUri(); + assertTrue(!vault.name().isEmpty()); + } + + @Test(dependsOnMethods = "testCreate") + public void testGet() { + Vault vaultFound = api().getVault(vaultName); + assertNotNull(vaultFound); + } + + @Test(dependsOnMethods = "testCreate") + public void testList() { + for (Vault vault : api().listVaults()) { + assertTrue(!vault.name().isEmpty()); + } + } + + @Test(dependsOnMethods = {"testDeleteKey", "testDeleteSecret"}) + public void testUpdateVaultToSoftDelete() { + Vault v = api().getVault(vaultName); + assertNotNull(v); + VaultProperties newProps = VaultProperties.create(v.properties().tenantId(), + v.properties().vaultUri(), + v.properties().enabledForDeployment(), + v.properties().enabledForTemplateDeployment(), + true, + v.properties().createMode(), + v.properties().sku(), + v.properties().accessPolicies()); + Vault updatedVault = api().createOrUpdateVault(vaultName, LOCATION, newProps, null); + assertNotNull(updatedVault); + updatedVault = api().getVault(vaultName); + assertTrue(updatedVault.properties().enableSoftDelete()); + } + + @Test(dependsOnMethods = {"testPurgeDeletedKey", "testPurgeDeletedSecret"}) + public void testDelete() { + boolean result = api().deleteVault(vaultName); + assertTrue(result); + checkState(deletedVaultStatus.create(resourceGroupName, true).apply(vaultName), + "vault was not deleted before timeout"); + } + + @Test(dependsOnMethods = "testDelete") + public void testGetDeleted() { + DeletedVault dv = api().getDeletedVault(LOCATION, vaultName); + assertNotNull(dv); + } + + @Test(dependsOnMethods = "testDelete") + public void testListDeleted() { + for (DeletedVault vault : api().listDeletedVaults()) { + assertNotNull(vault.name()); + } + } + + @Test(dependsOnMethods = {"testGetDeleted", "testListDeleted"}) + public void testPurgeDeletedVault() { + api().purgeVault(LOCATION, vaultName); + checkState(deletedVaultStatus.create(resourceGroupName, true).apply(vaultName), + "vault was not purged before timeout"); + + } + + @Test(dependsOnMethods = "testGet") + public void testCreateKey() { + KeyAttributes keyAttr = KeyAttributes.create(true, 0, null, null, null, null); + KeyBundle keyBundle = api().createKey(vaultUri, + KEY_NAME, + keyAttr, + null, + null, + 2048, + "RSA", + null + ); + assertNotNull(keyBundle); + } + + @Test(dependsOnMethods = "testCreateKey") + public void testImportKey() { + KeyAttributes keyAttr = KeyAttributes.create(true, null, null, null, null, null); + List keyOps = new ArrayList(); + keyOps.add("encrypt"); + JsonWebKey keyInfo = JsonWebKey.create( + null, + "DjU54mYvHpICXHjc5-JiFqiH8NkUgOG8LL4kwt3DeBp9bP0-5hSJH8vmzwJkeGG9L79EWG4b_bfxgYdeNX7cFFagmW" + + "PRFrlxbd64VRYFawZHRJt-2cbzMVI6DL8EK4bu5Ux5qTiV44Jw19hoD9nDzCTfPzSTSGrKD3iLPdnREYaIGDVxcjB" + + "v3Tx6rrv3Z2lhHHKhEHb0RRjATcjAVKV9NZhMajJ4l9pqJ3A4IQrCBl95ux6Xm1oXP0i6aR78cjchsCpcMXdP3WMs" + + "vHgTlsZT0RZLFHrvkiNHlPiil4G2_eHkwvT__CrcbO6SmI_zCtMmypuHJqcr-Xb7GPJoa64WoQ", + "DB9nGuHplY_7Xv5a5UCs5YgxkWPtJFfbIZ1Zr-XHCCY09JIWReOGQG226OhjwixKtOK_OqmAKtMKM9OmKviJRHNbD" + + "hbTxumN3u7cL8dftjXpSryiEQlPmWyW94MneI2WNIrvh4wruQuDt8EztgOiDFxwcnUgey8iend7WmZnE7E", + "O-bSTUQ4N_UuQezgkF3TDrnBraO67leDGwRbfiE_U0ghQvqh5DA0QSPVzlWDZc9KUitvj8vxsR9o1PW9GS0an17GJ" + + "EYuetLnkShKK3NWOhBBX6d1yP9rVdH6JhgIJEy_g0Suz7TAFiFc8i7JF8u4QJ05C8bZAMhOLotqftQeVOM", + "AQAB", + null, + null, + keyOps, + null, + "RSA", + "33TqqLR3eeUmDtHS89qF3p4MP7Wfqt2Zjj3lZjLjjCGDvwr9cJNlNDiuKboODgUiT4ZdPWbOiMAfDcDzlOxA04DDnEF" + + "GAf-kDQiNSe2ZtqC7bnIc8-KSG_qOGQIVaay4Ucr6ovDkykO5Hxn7OU7sJp9TP9H0JH8zMQA6YzijYH9LsupTerrY" + + "3U6zyihVEDXXOv08vBHk50BMFJbE9iwFwnxCsU5-UZUZYw87Uu0n4LPFS9BT8tUIvAfnRXIEWCha3KbFWmdZQZlyr" + + "Fw0buUEf0YN3_Q0auBkdbDR_ES2PbgKTJdkjc_rEeM0TxvOUf7HuUNOhrtAVEN1D5uuxE1WSw", + "8K33pX90XX6PZGiv26wZm7tfvqlqWFT03nUMvOAytqdxhO2HysiPn4W58OaJd1tY4372Qpiv6enmUeI4MidCie-s-d0" + + "_B6A0xfhU5EeeaDN0xDOOl8yN-kaaVj9b4HDR3c91OAwKpDJQIeJVZtxoijxl-SRx3u7Vs_7meeSpOfE", + "7a5KnUs1pTo72A-JquJvIz4Eu794Yh3ftTk_Et-83aE_FVc6Nk-EhfnwYSNpVmM6UKdrAoy5gsCvZPxrq-eR9pEwU8M" + + "5UOlki03vWY_nqDBpJSIqwPvGHUB16zvggsPQUyQBfnN3N8XlDi12n88ltvWwEhn1LQOwMUALEfka9_s", + "InfGmkb2jNkPGuNiZ-mU0-ZrOgLza_fLL9ErZ35jUPhGFzdGxJNobklvsNoTd-E2GAU41YkJh24bncMLvJVYxHHA5iF" + + "7FBWx1SvpEyKVhhnIcuXGD7N5PbNZzEdmr9C6I7cPVkWO-sUV7zfFukexIcANmsd_oBBGKRoYzP5Tti4", + null, + null + ); + KeyBundle importedKey = api().importKey(vaultUri, IMPORT_KEY_NAME, false, keyAttr, keyInfo, null); + assertNotNull(importedKey); + } + + @Test(dependsOnMethods = "testCreateKey") + public void testListKeys() { + for (Key key : api().listKeys(vaultUri)) { + assertNotNull(key); + } + } + + @Test(dependsOnMethods = "testListKeys") + public void testGetKey() { + KeyBundle keyBundle = api().getKey(vaultUri, KEY_NAME); + assertNotNull(keyBundle); + } + + @Test(dependsOnMethods = "testGetKey") + public void testUpdateKey() { + Map tags = new HashMap(); + tags.put("purpose", "testing"); + KeyBundle updatedKey = api().updateKey(vaultUri, KEY_NAME, "", null, null, tags); + assertNotNull(updatedKey.tags()); + assertEquals(updatedKey.tags().size(), 1); + } + + @Test(dependsOnMethods = "testUpdateKey") + public void testListKeyVersions() { + // Create a second version of the key + KeyAttributes keyAttr = KeyAttributes.create(true, null, null, null, null, null); + KeyBundle keyBundle = api().createKey(vaultUri, + KEY_NAME, + keyAttr, + null, + null, + 3072, + "RSA", + null); + + // List key versions + List keys = api().getKeyVersions(vaultUri, KEY_NAME); + assertNotNull(keys); + assertTrue(keys.size() > 1); + } + + @Test(dependsOnMethods = "testListKeyVersions") + public void testUpdateKeyWithVersion() { + List keys = api().getKeyVersions(vaultUri, KEY_NAME); + assertNotNull(keys); + assertTrue(keys.size() > 1); + + // get key version to operate on + Key key = keys.get(1); + assertNotNull(key); + final String version = key.kid().substring(key.kid().lastIndexOf("/") + 1).trim(); + + Map tags = new HashMap(); + tags.put("purpose", "testing again"); + KeyBundle updatedKey = api().updateKey(vaultUri, KEY_NAME, version, null, null, tags); + assertNotNull(updatedKey); + + FluentIterable iKeys = FluentIterable.from(api().getKeyVersions(vaultUri, KEY_NAME)); + assertTrue(iKeys.anyMatch(new Predicate() { + @Override public boolean apply(Key input) { + return input.kid().contains(version); + } + })); + + assertEquals(tags, updatedKey.tags()); + } + + @Test(dependsOnMethods = "testUpdateKeyWithVersion") + public void testBackupRestoreKey() { + KeyBundle originalKey = api().getKey(vaultUri, KEY_NAME); + assertNotNull(originalKey); + + String backupKey = api().backupKey(vaultUri, KEY_NAME); + assertNotNull(backupKey); + + DeletedKeyBundle dkb = api().deleteKey(vaultUri, KEY_NAME); + assertNotNull(dkb); + + KeyBundle restoredKey = api().restoreKey(vaultUri, backupKey); + assertNotNull(restoredKey); + + KeyBundle verifyKey = api().getKey(vaultUri, KEY_NAME); + assertNotNull(verifyKey); + + assertEquals(verifyKey, originalKey); + } + + @Test(dependsOnMethods = "testBackupRestoreKey") + public void testDeleteKey() { + DeletedKeyBundle dkb = api().deleteKey(vaultUri, KEY_NAME); + assertNotNull(dkb); + } + + @Test(dependsOnMethods = "testUpdateVaultToSoftDelete") + public void testCreateRecoverableKey() { + KeyAttributes keyAttr = KeyAttributes.create(true, null, null, null, null, null); + KeyBundle keyBundle = api().createKey(vaultUri, RECOVERABLE_KEY_NAME, + keyAttr, + null, + null, + 2048, + "RSA", + null + ); + assertNotNull(keyBundle); + checkState(recoverableKeyStatus.create(resourceGroupName, vaultUri, false).apply(RECOVERABLE_KEY_NAME), + "key was not created before timeout"); + } + + @Test(dependsOnMethods = "testCreateRecoverableKey") + public void testDeleteRecoverableKey() { + DeletedKeyBundle dkb = api().deleteKey(vaultUri, RECOVERABLE_KEY_NAME); + assertNotNull(dkb.deletedDate()); + assertNotNull(dkb.recoveryId()); + checkState(deletedKeyStatus.create(resourceGroupName, vaultUri, true).apply(RECOVERABLE_KEY_NAME), + "key was not deleted before timeout"); + } + + @Test(dependsOnMethods = "testDeleteRecoverableKey") + public void testListDeletedKeys() { + for (DeletedKeyBundle key : api().listDeletedKeys(vaultUri)) { + assertNotNull(key.deletedDate()); + } + } + + @Test(dependsOnMethods = "testListDeletedKeys") + public void testGetDeletedKey() { + DeletedKeyBundle key = api().getDeletedKey(vaultUri, RECOVERABLE_KEY_NAME); + assertNotNull(key.deletedDate()); + } + + @Test(dependsOnMethods = {"testDeleteRecoverableKey", "testGetDeletedKey"}) + public void testRecoverDeletedKey() { + KeyBundle key = api().recoverDeletedKey(vaultUri, RECOVERABLE_KEY_NAME); + checkState(recoverableKeyStatus.create(resourceGroupName, vaultUri, true).apply(RECOVERABLE_KEY_NAME), + "key was not recovered before timeout"); + } + + @Test(dependsOnMethods = "testRecoverDeletedKey") + public void testPurgeDeletedKey() { + // delete the key + DeletedKeyBundle dkb = api().deleteKey(vaultUri, RECOVERABLE_KEY_NAME); + checkState(deletedKeyStatus.create(resourceGroupName, vaultUri, true).apply(RECOVERABLE_KEY_NAME), + "key was not deleted before timeout"); + + // purge the key and verify that it is no longer listed as deleted + api().purgeDeletedKey(vaultUri, RECOVERABLE_KEY_NAME); + checkState(deletedKeyStatus.create(resourceGroupName, vaultUri, false).apply(RECOVERABLE_KEY_NAME), + "key was not purged before timeout"); + } + + @Test(dependsOnMethods = "testCreateKey") + public void testEncryptDecrypt() { + // Encrypt some text + KeyOperationResult encryptResult = api().encrypt(vaultUri, + KEY_NAME, + "", + cryptoAlgorithm, + cryptoText + ); + assertNotNull(encryptResult); + assertTrue(encryptResult.value().length() > cryptoText.length()); + + // Decrypt the encrypted text + KeyOperationResult decryptResult = api().decrypt(vaultUri, + KEY_NAME, + "", + cryptoAlgorithm, + encryptResult.value() + ); + assertNotNull(decryptResult); + assertTrue(decryptResult.value().equals(cryptoText)); + } + + @Test(dependsOnMethods = "testCreateKey") + public void testSignVerify() { + // Sign a hash + KeyOperationResult signResult = api().sign(vaultUri, + KEY_NAME, + "", + signatureAlgorithm, + hashToSign + ); + assertNotNull(signResult); + assertTrue(!signResult.value().isEmpty()); + + // Verify the signature + boolean verifyResult = api().verify(vaultUri, + KEY_NAME, + "", + signatureAlgorithm, + hashToSign, + signResult.value() + ); + assertTrue(verifyResult); + } + + @Test(dependsOnMethods = "testCreateKey") + public void testWrapUnwrapKey() { + // Wrap a 256bit symmetric key + KeyOperationResult wrapResult = api().wrap(vaultUri, + KEY_NAME, + "", + cryptoAlgorithm, + contentEncryptionKey + ); + assertNotNull(wrapResult); + assertTrue(!wrapResult.value().isEmpty()); + + // Unwrap symmetric key + KeyOperationResult unwrapResult = api().unwrap(vaultUri, + KEY_NAME, + "", + cryptoAlgorithm, + wrapResult.value() + ); + assertNotNull(unwrapResult); + assertTrue(unwrapResult.value().equals(contentEncryptionKey)); + } + + @Test(dependsOnMethods = "testBackupRestoreKey") + public void testSetSecret() { + SecretAttributes attributes = SecretAttributes.create(true, null, null, null, null, null); + SecretBundle secretBundle = api().setSecret(vaultUri, + SECRET_NAME, + attributes, + "testSecretKey", + null, + sampleSecret + ); + assertNotNull(secretBundle); + } + + @Test(dependsOnMethods = "testSetSecret") + public void testGetSecret() { + SecretBundle secret = api().getSecret(vaultUri, SECRET_NAME, null); + assertNotNull(secret); + } + + @Test(dependsOnMethods = "testSetSecret") + public void testGetSecrets() { + for (Secret secret : api().listSecrets(vaultUri)) { + assertNotNull(secret); + } + } + + @Test(dependsOnMethods = {"testBackupRestoreSecret"}) + public void testDeleteSecret() { + DeletedSecretBundle dsb = api().deleteSecret(vaultUri, SECRET_NAME); + assertNotNull(dsb); + } + + @Test(dependsOnMethods = "testGetSecret") + public void testUpdateSecret() { + Map tags = new HashMap(); + tags.put("purpose", "testing"); + SecretBundle updatedSecret = api().updateSecret(vaultUri, SECRET_NAME, "", null, null, tags); + assertNotNull(updatedSecret.tags()); + assertEquals(updatedSecret.tags().size(), 1); + } + + @Test(dependsOnMethods = "testUpdateSecret") + public void testListSecretVersions() { + // Create a second version of the secret + SecretAttributes attributes = SecretAttributes.create(true, null, null, null, null, null); + SecretBundle secretBundle = api().setSecret(vaultUri, + SECRET_NAME, + attributes, + "aNewSecretKey", + null, + "-----BEGIN DSA PRIVATE KEY-----\n" + + "MIIBvAIBAAKBgQDvgcVEyeU5gfw69xY2n1zHWGp/Z8O573SiWIcy29rW382W6jvn\n" + + "X5rF/LX8AscwRhf2pUTEy64ECkd08eRgEjRIKdGSaTZpBXxM25TPb2fF9k1/ObXd\n" + + "SkNOQNlwoCHdyQlvwdkVRohJoBX9u371owXObwLiBR1V597p3PdGNYD3DQIVAPtD\n" + + "dHQQaHCYMxAIXRsaCmOZfsjdAoGBANVOovY4XqS48hvi/RzcCMbRbuHMFBXh/lEM\n" + + "FmBdZ5sczpi1S3KpEjnBPQfOTzspTlEm5y6cHbkQjh1qT1tMdPAAr5aHYVLCTR+v\n" + + "CSSALXP48YiZrJcgdyfhbyr5h/Su2QuwX2DvYrR9d88fYHU4O0njEyMd8UFwQ6Uy\n" + + "qez/catgAoGAJ2AbSklFUXYvehmCVO6XVo3bgO++C3GMycJY3HHTTFQNAb3LJkeO\n" + + "fa2ZCSqWbd85M00Lt0VEkqlb0EkjDvAgL0R78IJUmvb3FH1RiUofP/yK3g1/3I/l\n" + + "jUa1fXXn2jSFYcyzGaDnC2U/B55g9G7hXsXJuldwATfDnLtqCdNPoWcCFQDx5K/k\n" + + "Ub4xHF/4Tau8wDAkxHeJiw==\n" + + "-----END DSA PRIVATE KEY-----" + ); + + // List secret versions + List secrets = api().getSecretVersions(vaultUri, SECRET_NAME); + assertNotNull(secrets); + assertEquals(secrets.size(), 2); + } + + @Test(dependsOnMethods = "testListSecretVersions") + public void testUpdateSecretWithVersion() { + List secrets = api().getSecretVersions(vaultUri, SECRET_NAME); + assertNotNull(secrets); + assertEquals(secrets.size(), 2); + + // get secret version to operate on + Secret secret = secrets.get(1); + assertNotNull(secret); + String version = secret.id().substring(secret.id().lastIndexOf("/") + 1).trim(); + + Map tags = new HashMap(); + tags.put("purpose", "testing again"); + SecretBundle updatedSecret = api().updateSecret(vaultUri, SECRET_NAME, version, null, null, tags); + assertNotNull(updatedSecret); + + secrets = api().getSecretVersions(vaultUri, SECRET_NAME); + assertNotNull(secrets); + boolean found = false; + for (Secret s : secrets) { + if (s.id().contains(version)) { + secret = s; + found = true; + break; + } + } + assertTrue(found); + assertEquals(tags, secret.tags()); + } + + @Test(dependsOnMethods = "testUpdateSecretWithVersion") + public void testBackupRestoreSecret() { + SecretBundle originalSecret = api().getSecret(vaultUri, SECRET_NAME, null); + assertNotNull(originalSecret); + + String backupSecret = api().backupSecret(vaultUri, SECRET_NAME); + assertNotNull(backupSecret); + + DeletedSecretBundle dsb = api().deleteSecret(vaultUri, SECRET_NAME); + assertNotNull(dsb); + + SecretBundle restoredSecret = api().restoreSecret(vaultUri, backupSecret); + assertNotNull(restoredSecret); + + SecretBundle verifySecret = api().getSecret(vaultUri, SECRET_NAME, null); + assertNotNull(verifySecret); + + assertEquals(verifySecret, originalSecret); + } + + @Test(dependsOnMethods = "testUpdateVaultToSoftDelete") + public void testCreateRecoverableSecret() { + SecretAttributes attributes = SecretAttributes.create(true, null, null, null, null, null); + SecretBundle secretBundle = api().setSecret(vaultUri, + RECOVERABLE_SECRET_NAME, + attributes, + "aNewSecretKey", + null, + "-----BEGIN DSA PRIVATE KEY-----\n" + + "MIIBvAIBAAKBgQDvgcVEyeU5gfw69xY2n1zHWGp/Z8O573SiWIcy29rW382W6jvn\n" + + "X5rF/LX8AscwRhf2pUTEy64ECkd08eRgEjRIKdGSaTZpBXxM25TPb2fF9k1/ObXd\n" + + "SkNOQNlwoCHdyQlvwdkVRohJoBX9u371owXObwLiBR1V597p3PdGNYD3DQIVAPtD\n" + + "dHQQaHCYMxAIXRsaCmOZfsjdAoGBANVOovY4XqS48hvi/RzcCMbRbuHMFBXh/lEM\n" + + "FmBdZ5sczpi1S3KpEjnBPQfOTzspTlEm5y6cHbkQjh1qT1tMdPAAr5aHYVLCTR+v\n" + + "CSSALXP48YiZrJcgdyfhbyr5h/Su2QuwX2DvYrR9d88fYHU4O0njEyMd8UFwQ6Uy\n" + + "qez/catgAoGAJ2AbSklFUXYvehmCVO6XVo3bgO++C3GMycJY3HHTTFQNAb3LJkeO\n" + + "fa2ZCSqWbd85M00Lt0VEkqlb0EkjDvAgL0R78IJUmvb3FH1RiUofP/yK3g1/3I/l\n" + + "jUa1fXXn2jSFYcyzGaDnC2U/B55g9G7hXsXJuldwATfDnLtqCdNPoWcCFQDx5K/k\n" + + "Ub4xHF/4Tau8wDAkxHeJiw==\n" + + "-----END DSA PRIVATE KEY-----" + ); + assertNotNull(secretBundle); + checkState(recoverableSecretStatus.create(resourceGroupName, vaultUri, false).apply(RECOVERABLE_SECRET_NAME), + "secret was not created before timeout"); + } + + @Test(dependsOnMethods = "testCreateRecoverableSecret") + public void testDeleteRecoverableSecret() { + DeletedSecretBundle dsb = api().deleteSecret(vaultUri, RECOVERABLE_SECRET_NAME); + assertNotNull(dsb.deletedDate()); + assertNotNull(dsb.recoveryId()); + checkState(deletedSecretStatus.create(resourceGroupName, vaultUri, true).apply(RECOVERABLE_SECRET_NAME), + "secret was not deleted before timeout"); + } + + @Test(dependsOnMethods = "testDeleteRecoverableSecret") + public void testListDeletedSecrets() { + for (DeletedSecretBundle secret : api().listDeletedSecrets(vaultUri)) { + assertNotNull(secret.deletedDate()); + } + } + + @Test(dependsOnMethods = "testListDeletedSecrets") + public void testGetDeletedSecret() { + DeletedSecretBundle dsb = api().getDeletedSecret(vaultUri, RECOVERABLE_SECRET_NAME); + assertNotNull(dsb.deletedDate()); + } + + @Test(dependsOnMethods = {"testDeleteRecoverableSecret", "testGetDeletedSecret"}) + public void testRecoverDeletedSecret() { + SecretBundle secret = api().recoverDeletedSecret(vaultUri, RECOVERABLE_SECRET_NAME); + checkState(recoverableSecretStatus.create(resourceGroupName, vaultUri, true).apply(RECOVERABLE_SECRET_NAME), + "secret was not created before timeout"); + } + + @Test(dependsOnMethods = "testRecoverDeletedSecret") + public void testPurgeDeletedSecret() { + // delete the secret + DeletedSecretBundle dsb = api().deleteSecret(vaultUri, RECOVERABLE_SECRET_NAME); + checkState(deletedSecretStatus.create(resourceGroupName, vaultUri, true).apply(RECOVERABLE_SECRET_NAME), + "secret was not deleted before timeout"); + + // purge the secret and verify that it is no longer listed as deleted + api().purgeDeletedSecret(vaultUri, RECOVERABLE_SECRET_NAME); + checkState(deletedSecretStatus.create(resourceGroupName, vaultUri, false).apply(RECOVERABLE_SECRET_NAME), + "secret was not purged before timeout"); + } + + @Test(dependsOnMethods = "testGet") + public void testCreateCertificate() { + CertificatePolicy policy = Certificate.CertificatePolicy.create(null, + CERTIFICATE_NAME, + IssuerParameters.create(null, "Self"), + KeyProperties.create(false, 2048, "RSA", false), + null, + null, + X509CertificateProperties.create(null, null, null, "CN=mycertificate.foobar.com", 12) + ); + assertNotNull(policy); + + CertificateOperation certOp = api().createCertificate(vaultUri, + CERTIFICATE_NAME, + null, + policy, + null + ); + assertNotNull(certOp); + } + + @Test(dependsOnMethods = "testCreateCertificate") + public void testImportCertificate() { + String certPem = importableCertificatePem; + CertificateBundle certBundle = api().importCertificate( + vaultUri, + IMPORTABLE_CERTIFICATE_NAME, + null, + CertificatePolicy.create( + null, + null, + null, + null, + null, + SecretProperties.create("application/x-pem-file"), + null + ), + null, + null, + certPem); + assertNotNull(certBundle); + } + + @Test(dependsOnMethods = "testImportCertificate") + public void testMergeCertificate() { + /* XXX - Merging certificates is used in the case where a CSR is generated + * within the Azure Key Vault and then signed by an external entity. + * Since this requires an offline process outside the scope of automated + * tests, this test is currently not implemented. + */ + throw new SkipException("merging certificates requires an external entity, skipping"); + } + + @Test(dependsOnMethods = "testGetCertificateOperation") + public void testGetCertificate() { + CertificateBundle certBundle = api().getCertificate(vaultUri, "myCertificate", null); + assertNotNull(certBundle); + } + + @Test(dependsOnMethods = "testGetCertificateOperation") + public void testListCertificates() { + List certs = api().getCertificates(vaultUri); + assertTrue(!certs.isEmpty()); + for (Certificate cert : certs) { + assertNotNull(cert.id()); + } + } + + @Test(dependsOnMethods = "testGetCertificateOperation") + public void testListCertificateVersions() { + List certs = api().getCertificateVersions(vaultUri, CERTIFICATE_NAME); + assertNotNull(certs); + assertEquals(certs.size(), 1); + } + + @Test(dependsOnMethods = "testGetCertificatePolicy") + public void testUpdateCertificate() { + Map tags = new HashMap(); + tags.put("selfsigned", "true"); + CertificatePolicy policy = api().getCertificatePolicy( + vaultUri, + CERTIFICATE_NAME + ); + assertNotNull(policy); + CertificateBundle certBundle = api().updateCertificate( + vaultUri, + CERTIFICATE_NAME, + "", + null, + policy, + tags + ); + assertNotNull(certBundle); + assertEquals(certBundle.tags().size(), 1); + } + + @Test(dependsOnMethods = "testUpdateCertificate") + public void testUpdateCertificateVersion() { + // create a new version of the certificate + /* + * XXX -- update using version complains about needing policy (required input), yet + * passing in the same policy results in the error: + * + * Policy cannot be updated with a specific version of a certificate + * + * Will uncomment/fix once this issue is resolved. + * + */ + throw new SkipException("bug in requirements for function"); + } + + @Test(dependsOnMethods = {"testDeleteCertificateOperation", "testDeleteCertificateIssuer", + "testDeleteCertificateContacts", "testUpdateCertificatePolicy"}) + public void testDeleteCertificate() { + DeletedCertificateBundle dcb = api().deleteCertificate( + vaultUri, + CERTIFICATE_NAME + ); + assertNotNull(dcb); + } + + @Test(dependsOnMethods = "testCreateCertificate") + public void testGetCertificateOperation() { + CertificateOperation certOp = api().getCertificateOperation(vaultUri, CERTIFICATE_NAME); + assertNotNull(certOp); + checkState(certificateOperationStatus.create(resourceGroupName, vaultUri, true).apply(CERTIFICATE_NAME), + "certificate was not created before timeout"); + } + + @Test(dependsOnMethods = "testDeleteCertificateContacts") + public void testUpdateCertificateOperation() { + CertificatePolicy policy = Certificate.CertificatePolicy.create(null, + TEMP_CERTIFICATE_NAME, + IssuerParameters.create(null, "Self"), + KeyProperties.create(false, 4096, "RSA", false), + null, + null, + X509CertificateProperties.create(null, null, null, "CN=mytempcertificate.foobar.com", 12) + ); + assertNotNull(policy); + CertificateOperation certOp = api().createCertificate(vaultUri, + TEMP_CERTIFICATE_NAME, + null, + policy, + null + ); + assertNotNull(certOp); + + certOp = api().updateCertificateOperation(vaultUri, TEMP_CERTIFICATE_NAME, true); + assertNotNull(certOp); + assertTrue(certOp.cancellationRequested()); + } + + @Test(dependsOnMethods = "testUpdateCertificateOperation") + public void testDeleteCertificateOperation() { + CertificateOperation certOp = api().deleteCertificateOperation(vaultUri, TEMP_CERTIFICATE_NAME); + assertNotNull(certOp); + checkState(certificateOperationStatus.create(resourceGroupName, vaultUri, false).apply(TEMP_CERTIFICATE_NAME), + "certificate was not deleted before timeout"); + } + + @Test(dependsOnMethods = "testGetCertificate") + public void testSetCertificateIssuer() { + AdministrationDetails adminDetail = AdministrationDetails.create( + "adminguy@certsforme.com", + "Admin", + "Guy", + "867-5309" + ); + List adminDetails = new ArrayList(); + adminDetails.add(adminDetail); + OrganizationDetails orgDetails = OrganizationDetails.create( + adminDetails, + null + ); + IssuerBundle issuer = api().setCertificateIssuer( + vaultUri, + "globalsign01", + null, + IssuerCredentials.create("imauser", "This1sMyPa55wurD!"), + orgDetails, + "GlobalSign" + ); + assertNotNull(issuer); + } + + @Test(dependsOnMethods = "testSetCertificateIssuer") + public void testGetCertificateIssuers() { + List issuers = api().getCertificateIssuers(vaultUri); + assertNotNull(issuers); + assertTrue(issuers.size() > 0); + } + + @Test(dependsOnMethods = "testSetCertificateIssuer") + public void testGetCertificateIssuer() { + IssuerBundle issuer = api().getCertificateIssuer(vaultUri, "globalsign01"); + assertNotNull(issuer); + assertEquals(issuer.provider(), "GlobalSign"); + } + + @Test(dependsOnMethods = "testGetCertificateIssuer") + public void testUpdateCertificateIssuer() { + AdministrationDetails adminDetail = AdministrationDetails.create( + "adminguy@certsforme.com", + "Admin", + "Guy", + "867-5309" + ); + List adminDetails = new ArrayList(); + adminDetails.add(adminDetail); + OrganizationDetails orgDetails = OrganizationDetails.create( + adminDetails, + null + ); + IssuerBundle issuer = api().updateCertificateIssuer( + vaultUri, + "globalsign01", + null, + IssuerCredentials.create("imauser", "CanHa5P455wuRd!"), + orgDetails, + "GlobalSign" + ); + assertNotNull(issuer); + } + + @Test(dependsOnMethods = "testUpdateCertificateIssuer") + public void testDeleteCertificateIssuer() { + IssuerBundle issuer = api().deleteCertificateIssuer(vaultUri, "globalsign01"); + assertNotNull(issuer); + + issuer = api().getCertificateIssuer(vaultUri, "globalsign01"); + assertEquals(issuer, null); + } + + @Test(dependsOnMethods = "testDeleteCertificateIssuer") + public void testSetCertificateContacts() { + List contactsIn = new ArrayList(); + contactsIn.add(Contact.create("foo@bar.com", "Foo bar", "867-5309")); + Contacts contacts = api().setCertificateContacts(vaultUri, contactsIn); + assertNotNull(contacts); + } + @Test(dependsOnMethods = "testSetCertificateContacts") + public void testGetCertificateContacts() { + Contacts contacts = api().getCertificateContacts(vaultUri); + assertNotNull(contacts.id()); + assertEquals(contacts.contacts().size(), 1); + } + + @Test(dependsOnMethods = "testGetCertificateContacts") + public void testDeleteCertificateContacts() { + Contacts contacts = api().deleteCertificateContacts(vaultUri); + assertNotNull(contacts.id()); + + contacts = api().getCertificateContacts(vaultUri); + assertNull(contacts); + } + + @Test(dependsOnMethods = "testCreateCertificate") + public void testGetCertificatePolicy() { + CertificatePolicy policy = api().getCertificatePolicy(vaultUri, CERTIFICATE_NAME); + assertNotNull(policy); + } + + @Test(dependsOnMethods = "testUpdateCertificate") + public void testUpdateCertificatePolicy() { + CertificatePolicy policy = api().updateCertificatePolicy( + vaultUri, + CERTIFICATE_NAME, + null, + null, + KeyProperties.create(true, 3072, "RSA", false), + null, + null, + null + ); + assertNotNull(policy); + assertTrue(policy.keyProps().exportable()); + } + + @Test(dependsOnMethods = "testUpdateVaultToSoftDelete") + public void testImportRecoverableCertificate() { + String certPem = importableCertificatePem; + CertificateBundle certBundle = api().importCertificate( + vaultUri, + RECOVERABLE_CERTIFICATE_NAME, + null, + CertificatePolicy.create( + null, + null, + null, + null, + null, + SecretProperties.create("application/x-pem-file"), + null + ), + null, + null, + certPem); + checkState(recoverableCertificateStatus.create(resourceGroupName, vaultUri, true).apply(RECOVERABLE_CERTIFICATE_NAME), + "certificate was not imported before timeout"); + + certBundle = api().getCertificate(vaultUri, RECOVERABLE_CERTIFICATE_NAME, null); + assertNotNull(certBundle); + assertTrue(certBundle.attributes().recoveryLevel().contains("Recoverable")); + } + + @Test(dependsOnMethods = "testImportRecoverableCertificate") + public void testDeleteRecoverableCertificate() { + DeletedCertificateBundle dcb = api().deleteCertificate(vaultUri, RECOVERABLE_CERTIFICATE_NAME); + assertNotNull(dcb.deletedDate()); + assertNotNull(dcb.recoveryId()); + checkState(deletedCertificateStatus.create(resourceGroupName, vaultUri, true).apply(RECOVERABLE_CERTIFICATE_NAME), + "certificate was not deleted before timeout"); + } + + @Test(dependsOnMethods = "testDeleteRecoverableCertificate") + public void testListDeletedCertificates() { + for (DeletedCertificate dc : api().getDeletedCertificates(vaultUri)) { + assertNotNull(dc.deletedDate()); + } + } + + @Test(dependsOnMethods = "testListDeletedCertificates") + public void testGetDeletedCertificate() { + DeletedCertificateBundle dcb = api().getDeletedCertificate(vaultUri, RECOVERABLE_CERTIFICATE_NAME); + assertNotNull(dcb.deletedDate()); + } + + @Test(dependsOnMethods = "testGetDeletedCertificate") + public void testRecoverDeletedCertificate() { + CertificateBundle dcb = api().recoverDeletedCertificate(vaultUri, RECOVERABLE_CERTIFICATE_NAME); + assertNotNull(dcb); + checkState(recoverableCertificateStatus.create(resourceGroupName, vaultUri, false).apply(RECOVERABLE_CERTIFICATE_NAME), + "certificate was not recovered before timeout"); + } + + @Test(dependsOnMethods = "testRecoverDeletedCertificate") + public void testPurgeDeletedCertificate() { + // delete the certificate + DeletedCertificateBundle dcb = api().deleteCertificate(vaultUri, RECOVERABLE_CERTIFICATE_NAME); + checkState(deletedCertificateStatus.create(resourceGroupName, vaultUri, true).apply(RECOVERABLE_CERTIFICATE_NAME), + "certificate was not deleted before timeout"); + + // purge the certificate and verify that it is no longer listed as deleted + api().purgeDeletedCertificate(vaultUri, RECOVERABLE_CERTIFICATE_NAME); + checkState(deletedCertificateStatus.create(resourceGroupName, vaultUri, false).apply(RECOVERABLE_CERTIFICATE_NAME), + "certificate was not purged before timeout"); + } + + private VaultApi api() { + return api.getVaultApi(resourceGroupName); + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VaultApiMockTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VaultApiMockTest.java new file mode 100644 index 0000000000..7459f4812d --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/features/VaultApiMockTest.java @@ -0,0 +1,1619 @@ +/* + * 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 static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.Arrays; +import java.util.ArrayList; + +import org.jclouds.azurecompute.arm.domain.Certificate; +import org.jclouds.azurecompute.arm.domain.Certificate.AdministrationDetails; +import org.jclouds.azurecompute.arm.domain.Certificate.CertificateAttributes; +import org.jclouds.azurecompute.arm.domain.Certificate.CertificateBundle; +import org.jclouds.azurecompute.arm.domain.Certificate.CertificateIssuer; +import org.jclouds.azurecompute.arm.domain.Certificate.CertificateOperation; +import org.jclouds.azurecompute.arm.domain.Certificate.CertificatePolicy; +import org.jclouds.azurecompute.arm.domain.Certificate.Contact; +import org.jclouds.azurecompute.arm.domain.Certificate.Contacts; +import org.jclouds.azurecompute.arm.domain.Certificate.DeletedCertificate; +import org.jclouds.azurecompute.arm.domain.Certificate.DeletedCertificateBundle; +import org.jclouds.azurecompute.arm.domain.Certificate.IssuerBundle; +import org.jclouds.azurecompute.arm.domain.Certificate.IssuerCredentials; +import org.jclouds.azurecompute.arm.domain.Certificate.IssuerParameters; +import org.jclouds.azurecompute.arm.domain.Certificate.KeyProperties; +import org.jclouds.azurecompute.arm.domain.Certificate.OrganizationDetails; +import org.jclouds.azurecompute.arm.domain.Certificate.SecretProperties; +import org.jclouds.azurecompute.arm.domain.Certificate.X509CertificateProperties; +import org.jclouds.azurecompute.arm.domain.Key; +import org.jclouds.azurecompute.arm.domain.Key.DeletedKeyBundle; +import org.jclouds.azurecompute.arm.domain.Key.JsonWebKey; +import org.jclouds.azurecompute.arm.domain.Key.KeyAttributes; +import org.jclouds.azurecompute.arm.domain.Key.KeyBundle; +import org.jclouds.azurecompute.arm.domain.Key.KeyOperationResult; +import org.jclouds.azurecompute.arm.domain.SKU; +import org.jclouds.azurecompute.arm.domain.Secret; +import org.jclouds.azurecompute.arm.domain.Secret.DeletedSecretBundle; +import org.jclouds.azurecompute.arm.domain.Secret.SecretAttributes; +import org.jclouds.azurecompute.arm.domain.Secret.SecretBundle; +import org.jclouds.azurecompute.arm.domain.Vault; +import org.jclouds.azurecompute.arm.domain.Vault.DeletedVault; +import org.jclouds.azurecompute.arm.domain.VaultProperties; +import org.jclouds.azurecompute.arm.internal.BaseAzureComputeApiMockTest; +import org.jclouds.rest.ResourceNotFoundException; +import org.testng.SkipException; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; + + +@Test(groups = "unit", testName = "VaultApiMockTest", singleThreaded = true) +public class VaultApiMockTest extends BaseAzureComputeApiMockTest { + private final String subscriptionId = "SUBSCRIPTIONID"; + private final String resourceGroup = "myresourcegroup"; + private final String tenantId = "myTenantId"; + private final String identityObjId = "myIdentityObjectId"; + private final String vaultName = "kvvaultapimocktest"; + private final String apiVersion = "api-version=2016-10-01"; + private final String location = "westeurope"; + private URI vaultUri; + + private static String KEY_NAME = "myKey"; + private static String TEMP_KEY_NAME = "myTempKey"; + private static String IMPORT_KEY_NAME = "myImportKey"; + private static String RECOVERABLE_KEY_NAME = "myRecoverableKey"; + private static String SECRET_NAME = "mySecret"; + private static String RECOVERABLE_SECRET_NAME = "myRecoverableSecret"; + private static String CERTIFICATE_NAME = "myCertificate"; + private static String TEMP_CERTIFICATE_NAME = "myTempCertificate"; + private static String RECOVERABLE_CERTIFICATE_NAME = "myRecoverableCertificate"; + private static String IMPORTABLE_CERTIFICATE_NAME = "myImportableCertificate"; + private static String CERTIFICATE_ISSUER_NAME = "globalsign01"; + private String IMPORTABLE_CERTIFICATE_PEM = stringFromResource("/vaultimportablecert.txt"); + private String sampleSecret = stringFromResource("/vaultsamplesecret.txt"); + private String keyBackup = stringFromResource("/vaultkeybackup.txt"); + private String secretBackup = stringFromResource("/vaultsecretbackup.txt"); + private String[] mergeX5C = { + stringFromResource("/vaultmergex5c-1.txt"), + stringFromResource("/vaultmergex5c-2.txt"), + stringFromResource("/vaultmergex5c-3.txt") + }; + private static String cryptoText = "R29sZCUyNTIxJTJCR29sZCUyNTIxJTJCR2" + + "9sZCUyQmZyb20lMkJ0aGUlMkJBbWVyaWNhbiUyQlJpdmVyJTI1MjE"; + private static String cryptoAlgorithm = "RSA-OAEP"; + private static String hashToSign = "FvabKT6qGwpml59iHUJ72DZ4XyJcJ8bgpgFA4_8JFmM"; + private static String signatureAlgorithm = "RS256"; + private static String contentEncryptionKey = "YxzoHR65aFwD2_IOiZ5rD08jMSALA1y7b_yYW0G3hyI"; + private static String keyDecryptData = "0_S8pyjjnGRlcbDa-Lt0jYjMXpXrf9Fat3elx-fSO" + + "g3dj6mYgEEs6kt79OMD4MFmVyOt6umeWAfdDIkNVnqb5fgyWceveh9wN-37jc5CFgG2PF3XI" + + "A6RII-HF2BkBcVa9KcAX3_di4KQE70PXgHf-dlz_RgLOJILeG50wzFeBFCLsjEEPp3itmoai" + + "E6vfDidCRm5At8Vjka0G-N_afwkIijfQZLT0VaXvL39cIJE2QN3HJPZM8YPUlkFlYnY4GIRy" + + "RWSBpK_KYuVufzUGtDi6Sh8pUa67ppa7DHVZlixlmnVqI3Oeg6XUvMqbFFqVSrcNbRQDwVGL" + + "3cUtK-KB1PfKg"; + private static String keySignedData = "uO0r4P1cB-fKsDZ8cj5ahiNw8Tdsudt5zLCeEKOt29" + + "LAlPDpeGx9Q1SOFNaR7JlRYVelxsohdzvydwX8ao6MLnqlpdEj0Xt5Aadp-kN84AXW238gab" + + "S1AUyiWILCmdsBFeRU4wTRSxz2qGS_0ztHkaNln32P_9GJC72ZRlgZoVA4C_fowZolUoCWGj" + + "4V7fAzcSoiNYipWP0HkFe3xmuz-cSQg3CCAs-MclHHfMeSagLJZZQ9bpl5LIr-Ik89bNtqEq" + + "yP7Jb_fCgHajAx2lUFcRZhSIKuCfrLPMl6wzejQ2rQXX-ixEkDa73dYaPIrVW4IL3iC0Ufxn" + + "fxYffHJ7QCRw"; + private static String keyWrappedData = "1jcTlu3KJNDBYydhaH9POWOo0tAPGkpsZVizCkHpC" + + "3g_9Kg91Q3HKK-rfZynn5W5nVPM-SVFHA3JTankcXX8gx8GycwUh4pMoyil_DV35m2QjyuiT" + + "ln83OJXw-nMvRXyKdVfF7nyRcs256kW7gthAOsYUVBrfFS7DFFxsXqLNREsA8j85IqIXIm8p" + + "AB3C9uvl1I7SQhLvrwZZXXqjeCWMfseVJwWgsQFyyqH2P0f3-xnngV7cvik2k3Elrk3G_2Cu" + + "JCozIIrANg9zG9Z8DrwSNNm9YooxWkSu0ZeDLOJ0bMdhcPGGm5OvKz3oZqX-39yv5klNlCRb" + + "r0q7gqmI0x25w"; + + @BeforeMethod + public void start() throws IOException, URISyntaxException { + super.start(); + vaultUri = server.getUrl("").toURI(); + } + + public void createVault() throws InterruptedException { + server.enqueue(jsonResponse("/vaultcreate.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + Vault vault = vaultApi.createOrUpdateVault(vaultName, location, VaultProperties.builder() + .tenantId(this.tenantId) + .sku(SKU.create(location, "standard", null, "A")) + .accessPolicies(ImmutableList.of(VaultProperties.AccessPolicyEntry.create(null, this.identityObjId, this.tenantId, + VaultProperties.Permissions.create( + ImmutableList.of( // certificates + "Get", + "List", + "Update", + "Create", + "Import", + "Delete", + "ManageContacts", + "ManageIssuers", + "GetIssuers", + "ListIssuers", + "SetIssuers", + "DeleteIssuers", + "Purge", + "Recover" + ), + ImmutableList.of( // keys + "Get", + "List", + "Update", + "Create", + "Import", + "Delete", + "Recover", + "Backup", + "Restore", + "Purge", + "Encrypt", + "Decrypt", + "Sign", + "Verify", + "WrapKey", + "UnwrapKey" + ), + ImmutableList.of( // secrets + "Get", + "List", + "Set", + "Delete", + "Recover", + "Backup", + "Restore", + "Purge" + ), + ImmutableList.of() + )))) + .build(), + null); + + String path = String.format( + "/subscriptions/%s/resourcegroups/%s/providers/Microsoft.KeyVault/vaults/%s?%s", + subscriptionId, resourceGroup, vaultName, apiVersion + ); + assertSent(server, "PUT", path, stringFromResource("/vaultcreaterequestbody.json")); + + assertNotNull(vault); + assertNotNull(vault.properties().vaultUri()); + assertTrue(!vault.name().isEmpty()); + } + + public void listVaults() throws InterruptedException { + server.enqueue(jsonResponse("/vaultlist.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List vaults = vaultApi.listVaults(); + + String path = String.format( + "/subscriptions/%s/resourcegroups/%s/providers/Microsoft.KeyVault/vaults?%s", + subscriptionId, resourceGroup, apiVersion + ); + assertSent(server, "GET", path); + + assertNotNull(vaults); + assertTrue(vaults.size() > 0); + assertTrue(!vaults.get(0).name().isEmpty()); + } + + public void listVaultsReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List vaults = vaultApi.listVaults(); + + String path = String.format( + "/subscriptions/%s/resourcegroups/%s/providers/Microsoft.KeyVault/vaults?%s", + subscriptionId, resourceGroup, apiVersion + ); + assertSent(server, "GET", path); + + assertTrue(vaults.isEmpty()); + } + + public void getVault() throws InterruptedException { + server.enqueue(jsonResponse("/vaultget.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + Vault vault = vaultApi.getVault(vaultName); + + String path = String.format( + "/subscriptions/%s/resourcegroups/%s/providers/Microsoft.KeyVault/vaults/%s?%s", + subscriptionId, resourceGroup, vaultName, apiVersion + ); + assertSent(server, "GET", path); + + assertNotNull(vault); + assertTrue(!vault.name().isEmpty()); + } + + public void getVaultReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + Vault vault = vaultApi.getVault(vaultName); + + String path = String.format( + "/subscriptions/%s/resourcegroups/%s/providers/Microsoft.KeyVault/vaults/%s?%s", + subscriptionId, resourceGroup, vaultName, apiVersion + ); + assertSent(server, "GET", path); + + assertNull(vault); + } + + public void deleteVault() throws InterruptedException { + server.enqueue(response200()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + boolean status = vaultApi.deleteVault(vaultName); + + String path = String.format( + "/subscriptions/%s/resourcegroups/%s/providers/Microsoft.KeyVault/vaults/%s?%s", + subscriptionId, resourceGroup, vaultName, apiVersion + ); + assertSent(server, "DELETE", path); + + assertTrue(status); + } + + public void deleteVaultReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + boolean status = vaultApi.deleteVault(vaultName); + + String path = String.format( + "/subscriptions/%s/resourcegroups/%s/providers/Microsoft.KeyVault/vaults/%s?%s", + subscriptionId, resourceGroup, vaultName, apiVersion + ); + assertSent(server, "DELETE", path); + + assertFalse(status); + } + + public void purgeDeletedVault() throws InterruptedException { + server.enqueue(response200()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + boolean status = vaultApi.purgeVault(location, vaultName); + + String path = String.format( + "/subscriptions/%s/providers/Microsoft.KeyVault/locations/%s/deletedVaults/%s/purge?%s", + subscriptionId, location, vaultName, apiVersion + ); + assertSent(server, "POST", path); + + assertTrue(status); + } + + public void purgeDeletedVaultReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + boolean status = vaultApi.purgeVault(location, vaultName); + + String path = String.format( + "/subscriptions/%s/providers/Microsoft.KeyVault/locations/%s/deletedVaults/%s/purge?%s", + subscriptionId, location, vaultName, apiVersion + ); + assertSent(server, "POST", path); + + assertFalse(status); + } + + public void listDeletedVaults() throws InterruptedException { + server.enqueue(jsonResponse("/vaultlistdeleted.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List vaults = vaultApi.listDeletedVaults(); + + String path = String.format( + "/subscriptions/%s/providers/Microsoft.KeyVault/deletedVaults?%s", + subscriptionId, apiVersion + ); + assertSent(server, "GET", path); + + assertNotNull(vaults); + assertTrue(vaults.size() > 0); + } + + public void listDeletedVaultsReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List vaults = vaultApi.listDeletedVaults(); + + String path = String.format( + "/subscriptions/%s/providers/Microsoft.KeyVault/deletedVaults?%s", + subscriptionId, apiVersion + ); + assertSent(server, "GET", path); + + assertTrue(vaults.isEmpty()); + } + + public void getDeletedVault() throws InterruptedException { + server.enqueue(jsonResponse("/vaultgetdeleted.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + DeletedVault vault = vaultApi.getDeletedVault(location, vaultName); + + String path = String.format( + "/subscriptions/%s/providers/Microsoft.KeyVault/locations/%s/deletedVaults/%s?%s", + subscriptionId, location, vaultName, apiVersion + ); + assertSent(server, "GET", path); + + assertNotNull(vault); + assertTrue(!vault.name().isEmpty()); + assertTrue(!vault.properties().deletionDate().toString().isEmpty()); + } + + public void getDeletedVaultReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + DeletedVault vault = vaultApi.getDeletedVault(location, vaultName); + + String path = String.format( + "/subscriptions/%s/providers/Microsoft.KeyVault/locations/%s/deletedVaults/%s?%s", + subscriptionId, location, vaultName, apiVersion + ); + assertSent(server, "GET", path); + + assertNull(vault); + } + + + // Key mock tests + public void listKeys() throws InterruptedException { + server.enqueue(jsonResponse("/vaultlistkeys.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List keys = vaultApi.listKeys(vaultUri); + + String path = String.format("/keys?%s", apiVersion); + assertSent(server, "GET", path); + + assertNotNull(keys); + assertTrue(keys.size() > 0); + } + + public void listKeysReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List keys = vaultApi.listKeys(vaultUri); + + String path = String.format("/keys?%s", apiVersion); + assertSent(server, "GET", path); + + assertTrue(keys.isEmpty()); + } + + public void createKey() throws InterruptedException { + server.enqueue(jsonResponse("/vaultcreatekey.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + KeyAttributes keyAttr = KeyAttributes.create(true, null, null, null, null, null); + KeyBundle keyBundle = vaultApi.createKey(vaultUri, + KEY_NAME, + keyAttr, + null, + null, + 2048, + "RSA", + null + ); + + String path = String.format("/keys/%s/create?%s", KEY_NAME, apiVersion); + assertSent(server, "POST", path, stringFromResource("/vaultcreatekeyrequestbody.json")); + + assertNotNull(keyBundle); + assertNotNull(keyBundle.attributes().created()); + } + + public void importKey() throws InterruptedException { + server.enqueue(jsonResponse("/vaultcreatekey.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + KeyAttributes keyAttr = KeyAttributes.create(true, null, null, null, null, null); + List keyOps = new ArrayList(); + keyOps.add("encrypt"); + JsonWebKey keyInfo = JsonWebKey.create( + null, + "DjU54mYvHpICXHjc5-JiFqiH8NkUgOG8LL4kwt3DeBp9bP0-5hSJH8vmzwJkeGG9L79EWG4b_bfxgYdeNX7cFFagmW" + + "PRFrlxbd64VRYFawZHRJt-2cbzMVI6DL8EK4bu5Ux5qTiV44Jw19hoD9nDzCTfPzSTSGrKD3iLPdnREYaIGDVxcjB" + + "v3Tx6rrv3Z2lhHHKhEHb0RRjATcjAVKV9NZhMajJ4l9pqJ3A4IQrCBl95ux6Xm1oXP0i6aR78cjchsCpcMXdP3WMs" + + "vHgTlsZT0RZLFHrvkiNHlPiil4G2_eHkwvT__CrcbO6SmI_zCtMmypuHJqcr-Xb7GPJoa64WoQ", + "DB9nGuHplY_7Xv5a5UCs5YgxkWPtJFfbIZ1Zr-XHCCY09JIWReOGQG226OhjwixKtOK_OqmAKtMKM9OmKviJRHNbD" + + "hbTxumN3u7cL8dftjXpSryiEQlPmWyW94MneI2WNIrvh4wruQuDt8EztgOiDFxwcnUgey8iend7WmZnE7E", + "O-bSTUQ4N_UuQezgkF3TDrnBraO67leDGwRbfiE_U0ghQvqh5DA0QSPVzlWDZc9KUitvj8vxsR9o1PW9GS0an17GJ" + + "EYuetLnkShKK3NWOhBBX6d1yP9rVdH6JhgIJEy_g0Suz7TAFiFc8i7JF8u4QJ05C8bZAMhOLotqftQeVOM", + "AQAB", + null, + null, + keyOps, + null, + "RSA", + "33TqqLR3eeUmDtHS89qF3p4MP7Wfqt2Zjj3lZjLjjCGDvwr9cJNlNDiuKboODgUiT4ZdPWbOiMAfDcDzlOxA04DDnEF" + + "GAf-kDQiNSe2ZtqC7bnIc8-KSG_qOGQIVaay4Ucr6ovDkykO5Hxn7OU7sJp9TP9H0JH8zMQA6YzijYH9LsupTerrY" + + "3U6zyihVEDXXOv08vBHk50BMFJbE9iwFwnxCsU5-UZUZYw87Uu0n4LPFS9BT8tUIvAfnRXIEWCha3KbFWmdZQZlyr" + + "Fw0buUEf0YN3_Q0auBkdbDR_ES2PbgKTJdkjc_rEeM0TxvOUf7HuUNOhrtAVEN1D5uuxE1WSw", + "8K33pX90XX6PZGiv26wZm7tfvqlqWFT03nUMvOAytqdxhO2HysiPn4W58OaJd1tY4372Qpiv6enmUeI4MidCie-s-d0" + + "_B6A0xfhU5EeeaDN0xDOOl8yN-kaaVj9b4HDR3c91OAwKpDJQIeJVZtxoijxl-SRx3u7Vs_7meeSpOfE", + "7a5KnUs1pTo72A-JquJvIz4Eu794Yh3ftTk_Et-83aE_FVc6Nk-EhfnwYSNpVmM6UKdrAoy5gsCvZPxrq-eR9pEwU8M" + + "5UOlki03vWY_nqDBpJSIqwPvGHUB16zvggsPQUyQBfnN3N8XlDi12n88ltvWwEhn1LQOwMUALEfka9_s", + "InfGmkb2jNkPGuNiZ-mU0-ZrOgLza_fLL9ErZ35jUPhGFzdGxJNobklvsNoTd-E2GAU41YkJh24bncMLvJVYxHHA5iF" + + "7FBWx1SvpEyKVhhnIcuXGD7N5PbNZzEdmr9C6I7cPVkWO-sUV7zfFukexIcANmsd_oBBGKRoYzP5Tti4", + null, + null + ); + KeyBundle importedKey = vaultApi.importKey(vaultUri, IMPORT_KEY_NAME, false, keyAttr, keyInfo, null); + + String path = String.format("/keys/%s?%s", IMPORT_KEY_NAME, apiVersion); + assertSent(server, "PUT", path, stringFromResource("/vaultimportkeyrequestbody.json")); + + assertNotNull(importedKey); + assertNotNull(importedKey.attributes().created()); + } + + public void getKey() throws InterruptedException { + server.enqueue(jsonResponse("/vaultgetkey.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + KeyBundle key = vaultApi.getKey(vaultUri, KEY_NAME); + + String path = String.format("/keys/%s?%s", KEY_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNotNull(key); + assertNotNull(key.attributes().created()); + } + + public void getKeyReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + KeyBundle key = vaultApi.getKey(vaultUri, KEY_NAME); + + String path = String.format("/keys/%s?%s", KEY_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNull(key); + } + + public void deleteKey() throws InterruptedException { + server.enqueue(jsonResponse("/vaultdeletekey.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + DeletedKeyBundle key = vaultApi.deleteKey(vaultUri, KEY_NAME); + + String path = String.format("/keys/%s?%s", KEY_NAME, apiVersion); + assertSent(server, "DELETE", path); + + assertNotNull(key); + assertNotNull(key.attributes().created()); + } + + public void deleteKeyReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + DeletedKeyBundle key = vaultApi.deleteKey(vaultUri, KEY_NAME); + + String path = String.format("/keys/%s?%s", KEY_NAME, apiVersion); + assertSent(server, "DELETE", path); + + assertNull(key); + } + + public void getKeyVersions() throws InterruptedException { + server.enqueue(jsonResponse("/vaultgetkeyversions.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List keys = vaultApi.getKeyVersions(vaultUri, KEY_NAME); + + String path = String.format("/keys/%s/versions?%s", KEY_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNotNull(keys); + assertTrue(keys.size() > 0); + assertNotNull(keys.get(0).attributes().created()); + } + + public void getKeyVersionsReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List keys = vaultApi.getKeyVersions(vaultUri, KEY_NAME); + + String path = String.format("/keys/%s/versions?%s", KEY_NAME, apiVersion); + assertSent(server, "GET", path); + + assertTrue(keys.isEmpty()); + } + + public void updateKey() throws InterruptedException { + server.enqueue(jsonResponse("/vaultupdatekey.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + Map tags = new HashMap(); + tags.put("purpose", "testing"); + KeyBundle updatedKey = vaultApi.updateKey(vaultUri, KEY_NAME, null, null, null, tags); + + String path = String.format("/keys/%s?%s", KEY_NAME, apiVersion); + assertSent(server, "PATCH", path, stringFromResource("/vaultupdatekeyrequestbody.json")); + + assertNotNull(updatedKey); + assertNotNull(updatedKey.attributes().created()); + } + + public void updateKeyWithVersion() throws InterruptedException { + server.enqueue(jsonResponse("/vaultupdatekeywithversion.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + String keyVersion = "bd6566ec707e4ad89f4ab9577d9d0bef"; + Map tags = new HashMap(); + tags.put("purpose", "testing"); + KeyBundle updatedKey = vaultApi.updateKey(vaultUri, KEY_NAME, keyVersion, null, null, tags); + + String path = String.format("/keys/%s/%s?%s", KEY_NAME, keyVersion, apiVersion); + assertSent(server, "PATCH", path, stringFromResource("/vaultupdatekeyrequestbody.json")); + + assertNotNull(updatedKey); + assertNotNull(updatedKey.attributes().created()); + } + + public void backupKey() throws InterruptedException { + server.enqueue(jsonResponse("/vaultbackupkey.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + String keyBackup = vaultApi.backupKey(vaultUri, KEY_NAME); + + String path = String.format("/keys/%s/backup?%s", KEY_NAME, apiVersion); + assertSent(server, "POST", path); + + assertNotNull(keyBackup); + assertTrue(keyBackup.length() > 0); + } + + public void restoreKey() throws InterruptedException { + server.enqueue(jsonResponse("/vaultrestorekey.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + KeyBundle restoredKey = vaultApi.restoreKey(vaultUri, keyBackup); + + String path = String.format("/keys/restore?%s", apiVersion); + assertSent(server, "POST", path, stringFromResource("/vaultrestorekeyrequestbody.json")); + + assertNotNull(restoredKey); + assertNotNull(restoredKey.attributes().created()); + } + + public void listDeletedKeys() throws InterruptedException { + server.enqueue(jsonResponse("/vaultlistdeletedkeys.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List keys = vaultApi.listDeletedKeys(vaultUri); + + String path = String.format("/deletedkeys?%s", apiVersion); + assertSent(server, "GET", path); + + assertNotNull(keys); + assertTrue(keys.size() > 0); + } + + public void listDeletedKeysReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List keys = vaultApi.listDeletedKeys(vaultUri); + + String path = String.format("/deletedkeys?%s", apiVersion); + assertSent(server, "GET", path); + + assertTrue(keys.isEmpty()); + } + + public void getDeletedKey() throws InterruptedException { + server.enqueue(jsonResponse("/vaultgetdeletedkey.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + DeletedKeyBundle key = vaultApi.getDeletedKey(vaultUri, RECOVERABLE_KEY_NAME); + + String path = String.format("/deletedkeys/%s?%s", RECOVERABLE_KEY_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNotNull(key); + assertTrue(!key.deletedDate().isEmpty()); + } + + public void getDeletedKeyReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + DeletedKeyBundle key = vaultApi.getDeletedKey(vaultUri, RECOVERABLE_KEY_NAME); + + String path = String.format("/deletedkeys/%s?%s", RECOVERABLE_KEY_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNull(key); + } + + public void recoverDeletedKey() throws InterruptedException { + server.enqueue(jsonResponse("/vaultrecoverdeletedkey.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + KeyBundle key = vaultApi.recoverDeletedKey(vaultUri, RECOVERABLE_KEY_NAME); + + String path = String.format("/deletedkeys/%s/recover?%s", RECOVERABLE_KEY_NAME, apiVersion); + assertSent(server, "POST", path); + + assertNotNull(key); + assertNotNull(key.attributes().created()); + } + + public void purgeDeletedKey() throws InterruptedException { + server.enqueue(response200()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + boolean status = vaultApi.purgeDeletedKey(vaultUri, RECOVERABLE_KEY_NAME); + + String path = String.format("/deletedkeys/%s?%s", RECOVERABLE_KEY_NAME, apiVersion); + assertSent(server, "DELETE", path); + + assertTrue(status); + } + + public void purgeDeletedKeyReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + boolean status = vaultApi.purgeDeletedKey(vaultUri, RECOVERABLE_KEY_NAME); + + String path = String.format("/deletedkeys/%s?%s", RECOVERABLE_KEY_NAME, apiVersion); + assertSent(server, "DELETE", path); + + assertFalse(status); + } + + public void encrypt() throws InterruptedException { + server.enqueue(jsonResponse("/vaultkeyencrypt.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + KeyOperationResult encryptResult = vaultApi.encrypt(vaultUri, + KEY_NAME, + null, + cryptoAlgorithm, + cryptoText + ); + + String path = String.format("/keys/%s/encrypt?%s", KEY_NAME, apiVersion); + assertSent(server, "POST", path, stringFromResource("/vaultkeyencryptrequestbody.json")); + + assertNotNull(encryptResult); + assertTrue(!encryptResult.value().isEmpty()); + } + + public void decrypt() throws InterruptedException { + server.enqueue(jsonResponse("/vaultkeydecrypt.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + KeyOperationResult decryptResult = vaultApi.decrypt(vaultUri, + KEY_NAME, + null, + cryptoAlgorithm, + keyDecryptData + ); + + String path = String.format("/keys/%s/decrypt?%s", KEY_NAME, apiVersion); + assertSent(server, "POST", path, stringFromResource("/vaultkeydecryptrequestbody.json")); + + assertNotNull(decryptResult); + assertTrue(!decryptResult.value().isEmpty()); + } + + public void sign() throws InterruptedException { + server.enqueue(jsonResponse("/vaultkeysign.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + KeyOperationResult signResult = vaultApi.sign(vaultUri, + KEY_NAME, + null, + signatureAlgorithm, + hashToSign + ); + + String path = String.format("/keys/%s/sign?%s", KEY_NAME, apiVersion); + assertSent(server, "POST", path, stringFromResource("/vaultkeysignrequestbody.json")); + + assertNotNull(signResult); + assertTrue(!signResult.value().isEmpty()); + } + + public void verify() throws InterruptedException { + server.enqueue(jsonResponse("/vaultkeyverify.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + boolean verifyResult = vaultApi.verify(vaultUri, + KEY_NAME, + null, + signatureAlgorithm, + hashToSign, + keySignedData + ); + + String path = String.format("/keys/%s/verify?%s", KEY_NAME, apiVersion); + assertSent(server, "POST", path, stringFromResource("/vaultkeyverifyrequestbody.json")); + + assertTrue(verifyResult); + } + + public void wrap() throws InterruptedException { + server.enqueue(jsonResponse("/vaultkeywrap.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + KeyOperationResult wrapResult = vaultApi.wrap(vaultUri, + KEY_NAME, + null, + cryptoAlgorithm, + contentEncryptionKey + ); + + String path = String.format("/keys/%s/wrapkey?%s", KEY_NAME, apiVersion); + assertSent(server, "POST", path, stringFromResource("/vaultkeywraprequestbody.json")); + + assertNotNull(wrapResult); + assertTrue(!wrapResult.value().isEmpty()); + } + + public void unwrap() throws InterruptedException { + server.enqueue(jsonResponse("/vaultkeyunwrap.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + KeyOperationResult unwrapResult = vaultApi.unwrap(vaultUri, + KEY_NAME, + null, + cryptoAlgorithm, + keyWrappedData + ); + + String path = String.format("/keys/%s/unwrapkey?%s", KEY_NAME, apiVersion); + assertSent(server, "POST", path, stringFromResource("/vaultkeyunwraprequestbody.json")); + + assertNotNull(unwrapResult); + assertTrue(!unwrapResult.value().isEmpty()); + } + + // Secret mock tests + public void listSecrets() throws InterruptedException { + server.enqueue(jsonResponse("/vaultlistsecrets.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List secrets = vaultApi.listSecrets(vaultUri); + + String path = String.format("/secrets?%s", apiVersion); + assertSent(server, "GET", path); + + assertNotNull(secrets); + assertTrue(secrets.size() > 0); + } + + public void listSecretsReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List secrets = vaultApi.listSecrets(vaultUri); + + String path = String.format("/secrets?%s", apiVersion); + assertSent(server, "GET", path); + + assertTrue(secrets.isEmpty()); + } + + public void setSecret() throws InterruptedException { + server.enqueue(jsonResponse("/vaultsetsecret.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + SecretAttributes attributes = SecretAttributes.create(true, null, null, null, null, null); + SecretBundle secretBundle = vaultApi.setSecret(vaultUri, + SECRET_NAME, + attributes, + "testSecretKey", + null, + sampleSecret + ); + + String path = String.format("/secrets/%s?%s", SECRET_NAME, apiVersion); + assertSent(server, "PUT", path, stringFromResource("/vaultsetsecretrequestbody.json")); + + assertNotNull(secretBundle); + assertTrue(!secretBundle.id().isEmpty()); + } + + public void getSecret() throws InterruptedException { + server.enqueue(jsonResponse("/vaultgetsecret.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + SecretBundle secret = vaultApi.getSecret(vaultUri, SECRET_NAME, null); + + String path = String.format("/secrets/%s?%s", SECRET_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNotNull(secret); + assertNotNull(secret.attributes().created()); + } + + public void getSecretReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + SecretBundle secret = vaultApi.getSecret(vaultUri, SECRET_NAME, null); + + String path = String.format("/secrets/%s?%s", SECRET_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNull(secret); + } + + public void deleteSecret() throws InterruptedException { + server.enqueue(jsonResponse("/vaultdeletesecret.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + DeletedSecretBundle secret = vaultApi.deleteSecret(vaultUri, SECRET_NAME); + + String path = String.format("/secrets/%s?%s", SECRET_NAME, apiVersion); + assertSent(server, "DELETE", path); + + assertNotNull(secret); + assertNotNull(secret.attributes().created()); + } + + public void deleteSecretReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + DeletedSecretBundle secret = vaultApi.deleteSecret(vaultUri, SECRET_NAME); + + String path = String.format("/secrets/%s?%s", SECRET_NAME, apiVersion); + assertSent(server, "DELETE", path); + + assertNull(secret); + } + + public void getSecretVersions() throws InterruptedException { + server.enqueue(jsonResponse("/vaultgetsecretversions.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List secrets = vaultApi.getSecretVersions(vaultUri, SECRET_NAME); + + String path = String.format("/secrets/%s/versions?%s", SECRET_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNotNull(secrets); + assertTrue(secrets.size() > 0); + assertNotNull(secrets.get(0).attributes().created()); + } + + public void getSecretVersionsReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List secrets = vaultApi.getSecretVersions(vaultUri, SECRET_NAME); + + String path = String.format("/secrets/%s/versions?%s", SECRET_NAME, apiVersion); + assertSent(server, "GET", path); + + assertTrue(secrets.isEmpty()); + } + + public void updateSecret() throws InterruptedException { + server.enqueue(jsonResponse("/vaultupdatekey.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + Map tags = new HashMap(); + tags.put("purpose", "testing"); + SecretBundle updatedSecret = vaultApi.updateSecret(vaultUri, SECRET_NAME, null, null, null, tags); + + String path = String.format("/secrets/%s?%s", SECRET_NAME, apiVersion); + assertSent(server, "PATCH", path, stringFromResource("/vaultupdatesecretrequestbody.json")); + + assertNotNull(updatedSecret); + assertNotNull(updatedSecret.attributes().created()); + } + + public void updateSecretWithVersion() throws InterruptedException { + server.enqueue(jsonResponse("/vaultupdatesecretwithversion.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + String secretVersion = "b936ececbc674f3bb1367ae50d28ada0"; + Map tags = new HashMap(); + tags.put("purpose", "testing again"); + SecretBundle updatedSecret = vaultApi.updateSecret(vaultUri, SECRET_NAME, secretVersion, null, null, tags); + + String path = String.format("/secrets/%s/%s?%s", SECRET_NAME, secretVersion, apiVersion); + assertSent(server, "PATCH", path, stringFromResource("/vaultupdatesecretwithversionrequestbody.json")); + + assertNotNull(updatedSecret); + assertNotNull(updatedSecret.attributes().created()); + } + + public void backupSecret() throws InterruptedException { + server.enqueue(jsonResponse("/vaultbackupsecret.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + String secretBackup = vaultApi.backupSecret(vaultUri, SECRET_NAME); + + String path = String.format("/secrets/%s/backup?%s", SECRET_NAME, apiVersion); + assertSent(server, "POST", path); + + assertNotNull(secretBackup); + assertTrue(secretBackup.length() > 0); + } + + public void restoreSecret() throws InterruptedException { + server.enqueue(jsonResponse("/vaultrestoresecret.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + SecretBundle restoredSecret = vaultApi.restoreSecret(vaultUri, secretBackup); + + String path = String.format("/secrets/restore?%s", apiVersion); + assertSent(server, "POST", path, stringFromResource("/vaultrestoresecretrequestbody.json")); + + assertNotNull(restoredSecret); + assertNotNull(restoredSecret.attributes().created()); + } + + public void listDeletedSecrets() throws InterruptedException { + server.enqueue(jsonResponse("/vaultlistdeletedsecrets.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List secrets = vaultApi.listDeletedSecrets(vaultUri); + + String path = String.format("/deletedsecrets?%s", apiVersion); + assertSent(server, "GET", path); + + assertNotNull(secrets); + assertTrue(secrets.size() > 0); + } + + public void listDeletedSecretsReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List secrets = vaultApi.listDeletedSecrets(vaultUri); + + String path = String.format("/deletedsecrets?%s", apiVersion); + assertSent(server, "GET", path); + + assertTrue(secrets.isEmpty()); + } + + public void getDeletedSecret() throws InterruptedException { + server.enqueue(jsonResponse("/vaultgetdeletedsecret.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + DeletedSecretBundle secret = vaultApi.getDeletedSecret(vaultUri, RECOVERABLE_SECRET_NAME); + + String path = String.format("/deletedsecrets/%s?%s", RECOVERABLE_SECRET_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNotNull(secret); + assertTrue(!secret.deletedDate().isEmpty()); + } + + public void getDeletedSecretReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + DeletedSecretBundle secret = vaultApi.getDeletedSecret(vaultUri, RECOVERABLE_SECRET_NAME); + + String path = String.format("/deletedsecrets/%s?%s", RECOVERABLE_SECRET_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNull(secret); + } + + public void recoverDeletedSecret() throws InterruptedException { + server.enqueue(jsonResponse("/vaultrecoverdeletedsecret.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + SecretBundle secret = vaultApi.recoverDeletedSecret(vaultUri, RECOVERABLE_SECRET_NAME); + + String path = String.format("/deletedsecrets/%s/recover?%s", RECOVERABLE_SECRET_NAME, apiVersion); + assertSent(server, "POST", path); + + assertNotNull(secret); + assertNotNull(secret.attributes().created()); + } + + public void purgeDeletedSecret() throws InterruptedException { + server.enqueue(response200()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + boolean status = vaultApi.purgeDeletedSecret(vaultUri, RECOVERABLE_SECRET_NAME); + + String path = String.format("/deletedsecrets/%s?%s", RECOVERABLE_SECRET_NAME, apiVersion); + assertSent(server, "DELETE", path); + + assertTrue(status); + } + + public void purgeDeletedSecretReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + boolean status = vaultApi.purgeDeletedSecret(vaultUri, RECOVERABLE_SECRET_NAME); + + String path = String.format("/deletedsecrets/%s?%s", RECOVERABLE_SECRET_NAME, apiVersion); + assertSent(server, "DELETE", path); + + assertFalse(status); + } + + public void createCertificate() throws InterruptedException { + server.enqueue(jsonResponse("/vaultcreatecertificate.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + CertificatePolicy policy = CertificatePolicy.create(null, + CERTIFICATE_NAME, + IssuerParameters.create(null, "Self"), + KeyProperties.create(false, 2048, "RSA", false), + null, + null, + X509CertificateProperties.create(null, null, null, "CN=mycertificate.foobar.com", 12) + ); + CertificateOperation certOp = vaultApi.createCertificate(vaultUri, + CERTIFICATE_NAME, + null, + policy, + null + ); + + String path = String.format("/certificates/%s/create?%s", CERTIFICATE_NAME, apiVersion); + assertSent(server, "POST", path, stringFromResource("/vaultcreatecertificaterequestbody.json")); + + assertNotNull(certOp); + assertTrue(!certOp.id().isEmpty()); + } + + public void getCertificate() throws InterruptedException { + server.enqueue(jsonResponse("/vaultgetcertificate.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + CertificateBundle cert = vaultApi.getCertificate(vaultUri, CERTIFICATE_NAME, null); + + String path = String.format("/certificates/%s?%s", CERTIFICATE_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNotNull(cert); + assertTrue(!cert.id().isEmpty()); + } + + public void getCertificateReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + CertificateBundle cert = vaultApi.getCertificate(vaultUri, CERTIFICATE_NAME, null); + + String path = String.format("/certificates/%s?%s", CERTIFICATE_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNull(cert); + } + + public void deleteCertificate() throws InterruptedException { + server.enqueue(jsonResponse("/vaultdeletecertificate.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + DeletedCertificateBundle cert = vaultApi.deleteCertificate(vaultUri, CERTIFICATE_NAME); + + String path = String.format("/certificates/%s?%s", CERTIFICATE_NAME, apiVersion); + assertSent(server, "DELETE", path); + + assertNotNull(cert); + assertTrue(!cert.id().isEmpty()); + } + + public void deleteCertificateReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + DeletedCertificateBundle cert = vaultApi.deleteCertificate(vaultUri, CERTIFICATE_NAME); + + String path = String.format("/certificates/%s?%s", CERTIFICATE_NAME, apiVersion); + assertSent(server, "DELETE", path); + + assertNull(cert); + } + + public void listCertificates() throws InterruptedException { + server.enqueue(jsonResponse("/vaultlistcertificates.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List certs = vaultApi.getCertificates(vaultUri); + + String path = String.format("/certificates?%s", apiVersion); + assertSent(server, "GET", path); + + assertNotNull(certs); + assertTrue(certs.size() > 0); + } + + public void listCertificatesReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List certs = vaultApi.getCertificates(vaultUri); + + String path = String.format("/certificates?%s", apiVersion); + assertSent(server, "GET", path); + + assertTrue(certs.isEmpty()); + } + + public void listDeletedCertificates() throws InterruptedException { + server.enqueue(jsonResponse("/vaultlistdeletedcertificates.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List certs = vaultApi.getDeletedCertificates(vaultUri); + + String path = String.format("/deletedcertificates?%s", apiVersion); + assertSent(server, "GET", path); + + assertNotNull(certs); + assertTrue(certs.size() > 0); + } + + public void listDeletedCertificatesReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List certs = vaultApi.getDeletedCertificates(vaultUri); + + String path = String.format("/deletedcertificates?%s", apiVersion); + assertSent(server, "GET", path); + + assertTrue(certs.isEmpty()); + } + + public void getDeletedCertificate() throws InterruptedException { + server.enqueue(jsonResponse("/vaultgetdeletedcertificate.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + DeletedCertificateBundle cert = vaultApi.getDeletedCertificate(vaultUri, RECOVERABLE_CERTIFICATE_NAME); + + String path = String.format("/deletedcertificates/%s?%s", RECOVERABLE_CERTIFICATE_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNotNull(cert); + assertTrue(!cert.id().isEmpty()); + } + + public void getDeletedCertificateReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + DeletedCertificateBundle cert = vaultApi.getDeletedCertificate(vaultUri, RECOVERABLE_CERTIFICATE_NAME); + + String path = String.format("/deletedcertificates/%s?%s", RECOVERABLE_CERTIFICATE_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNull(cert); + } + + public void recoverDeletedCertificate() throws InterruptedException { + server.enqueue(jsonResponse("/vaultrecoverdeletedcertificate.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + CertificateBundle cert = vaultApi.recoverDeletedCertificate(vaultUri, RECOVERABLE_CERTIFICATE_NAME); + + String path = String.format("/deletedcertificates/%s/recover?%s", RECOVERABLE_CERTIFICATE_NAME, apiVersion); + assertSent(server, "POST", path); + + assertNotNull(cert); + assertTrue(!cert.id().isEmpty()); + } + + public void purgeDeletedCertificate() throws InterruptedException { + server.enqueue(response200()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + boolean status = vaultApi.purgeDeletedCertificate(vaultUri, RECOVERABLE_CERTIFICATE_NAME); + + String path = String.format("/deletedcertificates/%s?%s", RECOVERABLE_CERTIFICATE_NAME, apiVersion); + assertSent(server, "DELETE", path); + + assertTrue(status); + } + + public void purgeDeletedCertificateReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + boolean status = vaultApi.purgeDeletedCertificate(vaultUri, RECOVERABLE_CERTIFICATE_NAME); + + String path = String.format("/deletedcertificates/%s?%s", RECOVERABLE_CERTIFICATE_NAME, apiVersion); + assertSent(server, "DELETE", path); + + assertFalse(status); + } + + public void listCertificateVersions() throws InterruptedException { + server.enqueue(jsonResponse("/vaultlistcertificateversions.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List certs = vaultApi.getCertificateVersions(vaultUri, CERTIFICATE_NAME); + + String path = String.format("/certificates/%s/versions?%s", CERTIFICATE_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNotNull(certs); + assertTrue(certs.size() > 0); + } + + public void listCertificateVersionsReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List certs = vaultApi.getCertificateVersions(vaultUri, CERTIFICATE_NAME); + + String path = String.format("/certificates/%s/versions?%s", CERTIFICATE_NAME, apiVersion); + assertSent(server, "GET", path); + + assertTrue(certs.isEmpty()); + } + + public void updateCertificate() throws InterruptedException { + server.enqueue(jsonResponse("/vaultupdatecertificate.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + Map tags = new HashMap(); + tags.put("selfsigned", "true"); + CertificatePolicy policy = CertificatePolicy.create(null, + CERTIFICATE_NAME, + IssuerParameters.create(null, "Self"), + KeyProperties.create(false, 2048, "RSA", false), + null, + null, + X509CertificateProperties.create(null, null, null, "CN=mycertificate.foobar.com", 12) + ); + CertificateBundle certBundle = vaultApi.updateCertificate( + vaultUri, + CERTIFICATE_NAME, + null, + null, + policy, + tags + ); + + String path = String.format("/certificates/%s?%s", CERTIFICATE_NAME, apiVersion); + assertSent(server, "PATCH", path, stringFromResource("/vaultupdatecertificaterequestbody.json")); + + assertNotNull(certBundle); + assertTrue(!certBundle.id().isEmpty()); + } + + public void updateCertificateVersion() { + // Update the specific version of a certificate + + /* + * XXX -- update using version complains about needing policy (required input), yet + * passing in the same policy results in the error: + * + * Policy cannot be updated with a specific version of a certificate + * + * Will uncomment/fix once this issue is resolved. + * + */ + throw new SkipException("azure bug - update using version complains about needing policy"); + } + + public void importCertificate() throws InterruptedException { + server.enqueue(jsonResponse("/vaultimportcertificate.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + String certPem = IMPORTABLE_CERTIFICATE_PEM; + CertificateBundle certBundle = null; + try { + certBundle = vaultApi.importCertificate( + vaultUri, + RECOVERABLE_CERTIFICATE_NAME, + null, + CertificatePolicy.create( + null, + null, + null, + null, + null, + SecretProperties.create("application/x-pem-file"), + null + ), + null, + null, + certPem); + } catch (ResourceNotFoundException rnf) { + assertNotNull(rnf); + } + + String path = String.format("/certificates/%s/import?%s", RECOVERABLE_CERTIFICATE_NAME, apiVersion); + assertSent(server, "POST", path, stringFromResource("/vaultimportcertificaterequestbody.json")); + + assertNotNull(certBundle); + assertTrue(!certBundle.id().isEmpty()); + } + + public void mergeCertificate() throws InterruptedException { + // Merging a certificate is for when a CSR is signed by an external CA + server.enqueue(jsonResponse("/vaultmergecertificate.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + CertificateAttributes attributes = CertificateAttributes.create(null, true, null, null, null, null); + CertificateBundle certBundle = vaultApi.mergeCertificate( + vaultUri, + CERTIFICATE_NAME, + attributes, + null, + Arrays.asList(mergeX5C) + ); + + String path = String.format("/certificates/%s/pending/merge?%s", CERTIFICATE_NAME, apiVersion); + assertSent(server, "POST", path, stringFromResource("/vaultmergecertificaterequestbody.json")); + + assertNotNull(certBundle); + assertTrue(!certBundle.attributes().created().toString().isEmpty()); + } + + public void getCertificateOperation() throws InterruptedException { + server.enqueue(jsonResponse("/vaultgetcertificateoperation.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + CertificateOperation certOp = vaultApi.getCertificateOperation(vaultUri, CERTIFICATE_NAME); + + String path = String.format("/certificates/%s/pending?%s", CERTIFICATE_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNotNull(certOp); + assertTrue(!certOp.id().isEmpty()); + } + + public void getCertificateOperationReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + CertificateOperation certOp = vaultApi.getCertificateOperation(vaultUri, CERTIFICATE_NAME); + + String path = String.format("/certificates/%s/pending?%s", CERTIFICATE_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNull(certOp); + } + + public void updateCertificateOperation() throws InterruptedException { + server.enqueue(jsonResponse("/vaultupdatecertificateoperation.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + CertificateOperation certOp = vaultApi.updateCertificateOperation(vaultUri, CERTIFICATE_NAME, true); + + String path = String.format("/certificates/%s/pending?%s", CERTIFICATE_NAME, apiVersion); + assertSent(server, "PATCH", path, stringFromResource("/vaultupdatecertificateoperationrequestbody.json")); + + assertNotNull(certOp); + assertTrue(!certOp.id().isEmpty()); + } + + public void deleteCertificateOperation() throws InterruptedException { + server.enqueue(jsonResponse("/vaultdeletecertificateoperation.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + CertificateOperation certOp = vaultApi.deleteCertificateOperation(vaultUri, CERTIFICATE_NAME); + + String path = String.format("/certificates/%s/pending?%s", CERTIFICATE_NAME, apiVersion); + assertSent(server, "DELETE", path); + + assertNotNull(certOp); + assertTrue(!certOp.id().isEmpty()); + } + + public void deleteCertificateOperationReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + CertificateOperation certOp = vaultApi.deleteCertificateOperation(vaultUri, CERTIFICATE_NAME); + + String path = String.format("/certificates/%s/pending?%s", CERTIFICATE_NAME, apiVersion); + assertSent(server, "DELETE", path); + + assertNull(certOp); + } + + public void setCertificateIssuer() throws InterruptedException { + server.enqueue(jsonResponse("/vaultsetcertificateissuer.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + AdministrationDetails adminDetail = AdministrationDetails.create( + "adminguy@certsforme.com", + "Admin", + "Guy", + "867-5309" + ); + List adminDetails = new ArrayList(); + adminDetails.add(adminDetail); + OrganizationDetails orgDetails = OrganizationDetails.create( + adminDetails, + null + ); + IssuerBundle issuer = null; + try { + issuer = vaultApi.setCertificateIssuer( + vaultUri, + CERTIFICATE_ISSUER_NAME, + null, + IssuerCredentials.create("imauser", "This1sMyPa55wurD!"), + orgDetails, + "GlobalSign" + ); + } catch (ResourceNotFoundException rnf) { + assertNotNull(rnf); + } + + String path = String.format("/certificates/issuers/%s?%s", CERTIFICATE_ISSUER_NAME, apiVersion); + assertSent(server, "PUT", path, stringFromResource("/vaultsetcertificateissuerrequestbody.json")); + + assertNotNull(issuer); + assertTrue(!issuer.id().isEmpty()); + } + + public void listCertificateIssuers() throws InterruptedException { + server.enqueue(jsonResponse("/vaultlistcertificateissuers.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List issuers = vaultApi.getCertificateIssuers(vaultUri); + + String path = String.format("/certificates/issuers?%s", apiVersion); + assertSent(server, "GET", path); + + assertNotNull(issuers); + assertTrue(issuers.size() > 0); + } + + public void listCertificateIssuersReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List issuers = vaultApi.getCertificateIssuers(vaultUri); + + String path = String.format("/certificates/issuers?%s", apiVersion); + assertSent(server, "GET", path); + + assertTrue(issuers.isEmpty()); + } + + public void getCertificateIssuer() throws InterruptedException { + server.enqueue(jsonResponse("/vaultgetcertificateissuer.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + IssuerBundle issuer = vaultApi.getCertificateIssuer(vaultUri, CERTIFICATE_ISSUER_NAME); + + String path = String.format("/certificates/issuers/%s?%s", CERTIFICATE_ISSUER_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNotNull(issuer); + assertTrue(!issuer.id().isEmpty()); + } + + public void getCertificateIssuerReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + IssuerBundle issuer = vaultApi.getCertificateIssuer(vaultUri, CERTIFICATE_ISSUER_NAME); + + String path = String.format("/certificates/issuers/%s?%s", CERTIFICATE_ISSUER_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNull(issuer); + } + + public void updateCertificateIssuer() throws InterruptedException { + server.enqueue(jsonResponse("/vaultupdatecertificateissuer.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + AdministrationDetails adminDetail = AdministrationDetails.create( + "adminguy@certsforme.com", + "Admin", + "Guy", + "867-5309" + ); + List adminDetails = new ArrayList(); + adminDetails.add(adminDetail); + OrganizationDetails orgDetails = OrganizationDetails.create( + adminDetails, + null + ); + IssuerBundle issuer = vaultApi.updateCertificateIssuer( + vaultUri, + "globalsign01", + null, + IssuerCredentials.create("imauser", "CanHa5P455wuRd!"), + orgDetails, + "GlobalSign" + ); + + String path = String.format("/certificates/issuers/%s?%s", CERTIFICATE_ISSUER_NAME, apiVersion); + assertSent(server, "PATCH", path, stringFromResource("/vaultupdatecertificateissuerrequestbody.json")); + + assertNotNull(issuer); + assertTrue(!issuer.id().isEmpty()); + } + + public void deleteCertificateIssuer() throws InterruptedException { + server.enqueue(jsonResponse("/vaultdeletecertificateissuer.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + IssuerBundle issuer = vaultApi.deleteCertificateIssuer(vaultUri, CERTIFICATE_ISSUER_NAME); + + String path = String.format("/certificates/issuers/%s?%s", CERTIFICATE_ISSUER_NAME, apiVersion); + assertSent(server, "DELETE", path); + + assertNotNull(issuer); + assertTrue(!issuer.id().isEmpty()); + } + + public void deleteCertificateIssuerReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + IssuerBundle issuer = vaultApi.deleteCertificateIssuer(vaultUri, CERTIFICATE_ISSUER_NAME); + + String path = String.format("/certificates/issuers/%s?%s", CERTIFICATE_ISSUER_NAME, apiVersion); + assertSent(server, "DELETE", path); + + assertNull(issuer); + } + + public void getCertificateContacts() throws InterruptedException { + server.enqueue(jsonResponse("/vaultgetcertificatecontacts.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + Contacts contacts = vaultApi.getCertificateContacts(vaultUri); + + String path = String.format("/certificates/contacts?%s", apiVersion); + assertSent(server, "GET", path); + + assertNotNull(contacts); + assertTrue(!contacts.id().isEmpty()); + assertTrue(contacts.contacts().size() > 0); + } + + public void getCertificateContactsReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + IssuerBundle issuer = null; + try { + issuer = vaultApi.getCertificateIssuer(vaultUri, CERTIFICATE_ISSUER_NAME); + } catch (ResourceNotFoundException rnf) { + assertNotNull(rnf); + } + + String path = String.format("/certificates/issuers/%s?%s", CERTIFICATE_ISSUER_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNull(issuer); + } + + public void setCertificateContacts() throws InterruptedException { + server.enqueue(jsonResponse("/vaultsetcertificatecontacts.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + List contactsIn = new ArrayList(); + contactsIn.add(Contact.create("foo@bar.com", "Foo bar", "867-5309")); + Contacts contacts = vaultApi.setCertificateContacts(vaultUri, contactsIn); + + String path = String.format("/certificates/contacts?%s", apiVersion); + assertSent(server, "PUT", path, stringFromResource("/vaultsetcertificatecontactsrequestbody.json")); + + assertNotNull(contacts); + assertTrue(!contacts.id().isEmpty()); + assertTrue(contacts.contacts().size() > 0); + } + + public void deleteCertificateContacts() throws InterruptedException { + server.enqueue(jsonResponse("/vaultdeletecertificatecontacts.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + Contacts contacts = vaultApi.deleteCertificateContacts(vaultUri); + + String path = String.format("/certificates/contacts?%s", apiVersion); + assertSent(server, "DELETE", path); + + assertNotNull(contacts); + assertTrue(!contacts.id().isEmpty()); + assertTrue(contacts.contacts().size() > 0); + } + + public void deleteCertificateContactsReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + Contacts contacts = vaultApi.deleteCertificateContacts(vaultUri); + + String path = String.format("/certificates/contacts?%s", apiVersion); + assertSent(server, "DELETE", path); + + assertNull(contacts); + } + + public void getCertificatePolicy() throws InterruptedException { + server.enqueue(jsonResponse("/vaultgetcertificatepolicy.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + CertificatePolicy policy = vaultApi.getCertificatePolicy(vaultUri, CERTIFICATE_NAME); + + String path = String.format("/certificates/%s/policy?%s", CERTIFICATE_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNotNull(policy); + assertTrue(!policy.id().isEmpty()); + } + + public void getCertificatePolicyReturns404() throws InterruptedException { + server.enqueue(response404()); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + CertificatePolicy policy = vaultApi.getCertificatePolicy(vaultUri, CERTIFICATE_NAME); + + String path = String.format("/certificates/%s/policy?%s", CERTIFICATE_NAME, apiVersion); + assertSent(server, "GET", path); + + assertNull(policy); + } + + public void updateCertificatePolicy() throws InterruptedException { + server.enqueue(jsonResponse("/vaultupdatecertificatepolicy.json").setResponseCode(200)); + final VaultApi vaultApi = api.getVaultApi(resourceGroup); + CertificatePolicy policy = vaultApi.updateCertificatePolicy( + vaultUri, + CERTIFICATE_NAME, + null, + null, + KeyProperties.create(true, 3072, "RSA", false), + null, + null, + null + ); + + String path = String.format("/certificates/%s/policy?%s", CERTIFICATE_NAME, apiVersion); + assertSent(server, "PATCH", path, stringFromResource("/vaultupdatecertificatepolicyrequestbody.json")); + + assertNotNull(policy); + assertTrue(!policy.id().isEmpty()); + } +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java index f439315174..78d5425c2a 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java @@ -17,21 +17,42 @@ package org.jclouds.azurecompute.arm.internal; import static com.google.common.base.Preconditions.checkNotNull; -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.util.Predicates2.retry; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.VAULT_DELETE_STATUS; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.VAULT_SECRET_DELETE_STATUS; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.VAULT_SECRET_RECOVERABLE_STATUS; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.VAULT_KEY_DELETED_STATUS; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.VAULT_KEY_RECOVERABLE_STATUS; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.VAULT_CERTIFICATE_DELETE_STATUS; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.VAULT_CERTIFICATE_RECOVERABLE_STATUS; +import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.VAULT_CERTIFICATE_OPERATION_STATUS; +import java.io.IOException; import java.net.URI; import java.util.Arrays; import java.util.List; import java.util.Properties; import java.util.Random; +import com.google.common.base.Charsets; +import com.google.common.base.Throwables; +import com.google.common.io.Resources; import org.jclouds.apis.BaseApiLiveTest; import org.jclouds.azurecompute.arm.AzureComputeApi; -import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.PublicIpAvailablePredicateFactory; +import org.jclouds.azurecompute.arm.config.Tenant; +import org.jclouds.azurecompute.arm.compute.config.AzurePredicatesModule.VaultPredicates.DeletedVaultStatusPredicateFactory; +import org.jclouds.azurecompute.arm.compute.config.AzurePredicatesModule.VaultKeyPredicates.DeletedKeyStatusPredicateFactory; +import org.jclouds.azurecompute.arm.compute.config.AzurePredicatesModule.VaultKeyPredicates.RecoverableKeyStatusPredicateFactory; +import org.jclouds.azurecompute.arm.compute.config.AzurePredicatesModule.VaultSecretPredicates.DeletedSecretStatusPredicateFactory; +import org.jclouds.azurecompute.arm.compute.config.AzurePredicatesModule.VaultSecretPredicates.RecoverableSecretStatusPredicateFactory; +import org.jclouds.azurecompute.arm.compute.config.AzurePredicatesModule.VaultCertificatePredicates.CertificateOperationStatusPredicateFactory; +import org.jclouds.azurecompute.arm.compute.config.AzurePredicatesModule.VaultCertificatePredicates.DeletedCertificateStatusPredicateFactory; +import org.jclouds.azurecompute.arm.compute.config.AzurePredicatesModule.VaultCertificatePredicates.RecoverableCertificateStatusPredicateFactory; +import org.jclouds.azurecompute.arm.compute.config.AzurePredicatesModule.PublicIpAvailablePredicateFactory; import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup; import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroupProperties; import org.jclouds.azurecompute.arm.domain.NetworkSecurityRule; @@ -47,11 +68,11 @@ import com.google.common.base.Predicate; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; -import com.google.inject.Injector; -import com.google.inject.Key; -import com.google.inject.Module; -import com.google.inject.TypeLiteral; import com.google.inject.name.Names; +import com.google.inject.Injector; +import com.google.inject.Module; +import com.google.inject.Key; +import com.google.inject.TypeLiteral; public class BaseAzureComputeApiLiveTest extends BaseApiLiveTest { @@ -64,12 +85,22 @@ public class BaseAzureComputeApiLiveTest extends BaseApiLiveTest resourceDeleted; protected PublicIpAvailablePredicateFactory publicIpAvailable; protected Predicate> resourceAvailable; - + protected DeletedVaultStatusPredicateFactory deletedVaultStatus; + protected DeletedKeyStatusPredicateFactory deletedKeyStatus; + protected RecoverableKeyStatusPredicateFactory recoverableKeyStatus; + protected DeletedSecretStatusPredicateFactory deletedSecretStatus; + protected RecoverableSecretStatusPredicateFactory recoverableSecretStatus; + protected DeletedCertificateStatusPredicateFactory deletedCertificateStatus; + protected RecoverableCertificateStatusPredicateFactory recoverableCertificateStatus; + protected CertificateOperationStatusPredicateFactory certificateOperationStatus; + + protected String resourceGroupName; protected String vaultResourceGroup; protected String vaultName; protected String vaultCertificateUrl; + protected String tenantId; public BaseAzureComputeApiLiveTest() { provider = "azurecompute-arm"; @@ -110,6 +141,16 @@ public class BaseAzureComputeApiLiveTest extends BaseApiLiveTest>>() { })); + deletedVaultStatus = injector.getInstance(Key.get(DeletedVaultStatusPredicateFactory.class, Names.named(VAULT_DELETE_STATUS))); + deletedKeyStatus = injector.getInstance(Key.get(DeletedKeyStatusPredicateFactory.class, Names.named(VAULT_KEY_DELETED_STATUS))); + recoverableKeyStatus = injector.getInstance(Key.get(RecoverableKeyStatusPredicateFactory.class, Names.named(VAULT_KEY_RECOVERABLE_STATUS))); + deletedSecretStatus = injector.getInstance(Key.get(DeletedSecretStatusPredicateFactory.class, Names.named(VAULT_SECRET_DELETE_STATUS))); + recoverableSecretStatus = injector.getInstance(Key.get(RecoverableSecretStatusPredicateFactory.class, Names.named(VAULT_SECRET_RECOVERABLE_STATUS))); + deletedCertificateStatus = injector.getInstance(Key.get(DeletedCertificateStatusPredicateFactory.class, Names.named(VAULT_CERTIFICATE_DELETE_STATUS))); + recoverableCertificateStatus = injector.getInstance(Key.get(RecoverableCertificateStatusPredicateFactory.class, Names.named(VAULT_CERTIFICATE_RECOVERABLE_STATUS))); + certificateOperationStatus = injector.getInstance(Key.get(CertificateOperationStatusPredicateFactory.class, Names.named(VAULT_CERTIFICATE_OPERATION_STATUS))); + + tenantId = injector.getInstance(Key.get(String.class, Tenant.class)); return injector.getInstance(AzureComputeApi.class); } @@ -198,4 +239,11 @@ public class BaseAzureComputeApiLiveTest extends BaseApiLiveTest Date: Thu, 4 Jan 2018 01:44:14 +0100 Subject: [PATCH 87/87] JCLOUDS-1362: Proper password generation with custom constraints for each cloud --- .../config/AzureComputeServiceContextModule.java | 16 ++++++++++++++++ .../strategy/CreateResourcesThenCreateNodes.java | 9 ++++++--- .../CreateResourcesThenCreateNodesTest.java | 3 ++- 3 files changed, 24 insertions(+), 4 deletions(-) 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 de33fdf143..0a81ecb180 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 @@ -53,6 +53,7 @@ import org.jclouds.compute.functions.NodeAndTemplateOptionsToStatementWithoutPub import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.strategy.CreateNodesInGroupThenAddToSet; import org.jclouds.net.domain.IpPermission; +import org.jclouds.util.PasswordGenerator; import com.google.common.base.Function; import com.google.common.cache.CacheBuilder; @@ -102,6 +103,21 @@ public class AzureComputeServiceContextModule extends bind(new TypeLiteral() { }).to(AzureComputeSecurityGroupExtension.class); } + + @Provides + @Singleton + protected PasswordGenerator.Config providePasswordGenerator() { + // Guest passwords must be between 6-72 characters long. + // Must contain an upper case character. + // Must contain a lower case character. + // Must contain a numeric digit. + // Must contain a special character. Control characters are not allowed. + return new PasswordGenerator() + .lower().min(2).max(10) + .upper().min(2).max(10) + .numbers().min(2).max(10) + .symbols().min(2).max(10); + } @Provides @Singleton diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java index e5d38fbe5f..511d5315d3 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodes.java @@ -52,7 +52,7 @@ import org.jclouds.compute.strategy.ListNodesStrategy; import org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet; import org.jclouds.domain.Location; import org.jclouds.logging.Logger; -import org.jclouds.util.Passwords; +import org.jclouds.util.PasswordGenerator; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Optional; @@ -84,6 +84,7 @@ public class CreateResourcesThenCreateNodes extends CreateNodesWithGroupEncodedI private final String defaultVnetAddressPrefix; private final String defaultSubnetAddressPrefix; private final TemplateToAvailabilitySet templateToAvailabilitySet; + private final PasswordGenerator.Config passwordGenerator; @Inject protected CreateResourcesThenCreateNodes( @@ -95,7 +96,8 @@ public class CreateResourcesThenCreateNodes extends CreateNodesWithGroupEncodedI AzureComputeApi api, @Named(DEFAULT_VNET_ADDRESS_SPACE_PREFIX) String defaultVnetAddressPrefix, @Named(DEFAULT_SUBNET_ADDRESS_PREFIX) String defaultSubnetAddressPrefix, LoadingCache securityGroupMap, - TemplateToAvailabilitySet templateToAvailabilitySet) { + TemplateToAvailabilitySet templateToAvailabilitySet, + PasswordGenerator.Config passwordGenerator) { super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor, customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory); this.api = api; @@ -103,6 +105,7 @@ public class CreateResourcesThenCreateNodes extends CreateNodesWithGroupEncodedI this.defaultVnetAddressPrefix = defaultVnetAddressPrefix; this.defaultSubnetAddressPrefix = defaultSubnetAddressPrefix; this.templateToAvailabilitySet = templateToAvailabilitySet; + this.passwordGenerator = passwordGenerator; } @Override @@ -141,7 +144,7 @@ public class CreateResourcesThenCreateNodes extends CreateNodesWithGroupEncodedI TemplateOptions options = template.getOptions(); if (options.getLoginPassword() == null) { Optional passwordOptional = template.getImage().getDefaultCredentials().getOptionalPassword(); - options.overrideLoginPassword(passwordOptional.or(Passwords.generate())); + options.overrideLoginPassword(passwordOptional.or(passwordGenerator.generate())); } } diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodesTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodesTest.java index 51a45af484..45c56a317c 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodesTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/compute/strategy/CreateResourcesThenCreateNodesTest.java @@ -24,6 +24,7 @@ import org.jclouds.azurecompute.arm.domain.PublicIPAddressProperties; import org.jclouds.azurecompute.arm.domain.Subnet; import org.jclouds.azurecompute.arm.features.PublicIPAddressApi; import org.jclouds.azurecompute.arm.features.SubnetApi; +import org.jclouds.util.PasswordGenerator; import org.testng.annotations.Test; import com.google.common.collect.ImmutableList; @@ -101,7 +102,7 @@ public class CreateResourcesThenCreateNodesTest { } private static CreateResourcesThenCreateNodes strategy(AzureComputeApi api) { - return new CreateResourcesThenCreateNodes(null, null, null, null, null, api, null, null, null, null); + return new CreateResourcesThenCreateNodes(null, null, null, null, null, api, null, null, null, null, new PasswordGenerator().lower()); } private static String netResource(String resource) {