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