JCLOUDS-664 Azurecompute-arm ImageExtension

This commit is contained in:
Janne Koskinen 2016-07-07 13:50:59 +03:00 committed by Ignasi Barrera
parent 4f62f40036
commit 3c790ae3ae
9 changed files with 300 additions and 75 deletions

View File

@ -113,6 +113,11 @@
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.apache.jclouds.provider</groupId>
<artifactId>azureblob</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency> <dependency>
<groupId>ch.qos.logback</groupId> <groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId> <artifactId>logback-classic</artifactId>
@ -135,6 +140,11 @@
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency>
<groupId>org.apache.jclouds</groupId>
<artifactId>jclouds-blobstore</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies> </dependencies>
<profiles> <profiles>

View File

@ -18,7 +18,6 @@ package org.jclouds.azurecompute.arm.compute;
import static java.lang.String.format; import static java.lang.String.format;
import static java.util.concurrent.TimeUnit.SECONDS; 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 static org.jclouds.util.Predicates2.retry;
import java.util.ArrayList; 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.DeploymentProperties;
import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard;
import org.jclouds.azurecompute.arm.domain.ResourceProviderMetaData; 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.VMImage;
import org.jclouds.azurecompute.arm.domain.VMHardware; import org.jclouds.azurecompute.arm.domain.VMHardware;
import org.jclouds.azurecompute.arm.domain.Location; 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.domain.VirtualMachineInstance;
import org.jclouds.azurecompute.arm.features.DeploymentApi; import org.jclouds.azurecompute.arm.features.DeploymentApi;
import org.jclouds.azurecompute.arm.features.OSImageApi; import org.jclouds.azurecompute.arm.features.OSImageApi;
import org.jclouds.azurecompute.arm.util.BlobHelper;
import org.jclouds.azurecompute.arm.util.DeploymentTemplateBuilder; import org.jclouds.azurecompute.arm.util.DeploymentTemplateBuilder;
import org.jclouds.compute.ComputeServiceAdapter; import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
@ -97,7 +98,6 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<VMDeplo
this.api = api; this.api = api;
this.azureComputeConstants = azureComputeConstants; this.azureComputeConstants = azureComputeConstants;
this.azureGroup = azureComputeConstants.azureResourceGroup(); this.azureGroup = azureComputeConstants.azureResourceGroup();
logger.debug("AzureComputeServiceAdapter set azuregroup to: " + azureGroup); logger.debug("AzureComputeServiceAdapter set azuregroup to: " + azureGroup);
@ -219,7 +219,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<VMDeplo
for (SKU sku : skuList) { for (SKU sku : skuList) {
Iterable<Version> versionList = osImageApi.listVersions(publisherName, offer.name(), sku.name()); Iterable<Version> versionList = osImageApi.listVersions(publisherName, offer.name(), sku.name());
for (Version version : versionList) { 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); osImagesRef.add(vmImage);
} }
} }
@ -247,6 +247,17 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<VMDeplo
osImages.addAll(listImagesByLocation(location.name())); osImages.addAll(listImagesByLocation(location.name()));
} }
checkAndSetImageAvailability(osImages, Sets.newHashSet(locationIds)); checkAndSetImageAvailability(osImages, Sets.newHashSet(locationIds));
// list custom images
List<StorageService> storages = api.getStorageAccountApi(azureGroup).list();
for (StorageService storage : storages) {
String name = storage.name();
String key = api.getStorageAccountApi(azureGroup).getKeys(name).key1();
List<VMImage> images = BlobHelper.getImages("jclouds", azureGroup, storage.name(), key,
"custom", storage.location());
osImages.addAll(images);
}
return osImages; return osImages;
} }
@ -264,24 +275,25 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<VMDeplo
@Override @Override
public VMImage getImage(final String id) { public VMImage getImage(final String id) {
String[] fields = VMImageToImage.decodeFieldsFromUniqueId(id); VMImage image = VMImageToImage.decodeFieldsFromUniqueId(id);
if (fields[2].startsWith(CUSTOM_IMAGE_PREFIX)) { if (image.custom()) {
String name = fields[2].substring(CUSTOM_IMAGE_PREFIX.length()); String key = api.getStorageAccountApi(azureGroup).getKeys(image.storage()).key1();
String sku = fields[3]; if (BlobHelper.customImageExists(image.storage(), key))
String version = "1"; return image;
VMImage ref = VMImage.create(CUSTOM_IMAGE_PREFIX + azureGroup, CUSTOM_IMAGE_PREFIX + name, sku, version, fields[0], false); else
return ref; return null;
} }
String location = fields[0]; String location = image.location();
String publisher = fields[1]; String publisher = image.publisher();
String offer = fields[2]; String offer = image.offer();
String sku = fields[3]; String sku = image.sku();
OSImageApi osImageApi = api.getOSImageApi(location); OSImageApi osImageApi = api.getOSImageApi(location);
List<Version> versions = osImageApi.listVersions(publisher, offer, sku); List<Version> versions = osImageApi.listVersions(publisher, offer, sku);
if (!versions.isEmpty()) { 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; return null;
} }
@ -415,8 +427,18 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<VMDeplo
List<VMDeployment> vmDeployments = new ArrayList<VMDeployment>(); List<VMDeployment> vmDeployments = new ArrayList<VMDeployment>();
for (Deployment d : deployments){ 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; return vmDeployments;
} }

View File

@ -17,18 +17,24 @@
package org.jclouds.azurecompute.arm.compute.extensions; package org.jclouds.azurecompute.arm.compute.extensions;
import com.google.common.base.Predicate; 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.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.UncheckedTimeoutException;
import com.google.gson.internal.LinkedTreeMap; import com.google.gson.internal.LinkedTreeMap;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.name.Named; import com.google.inject.name.Named;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.View;
import org.jclouds.azurecompute.arm.AzureComputeApi; import org.jclouds.azurecompute.arm.AzureComputeApi;
import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule; import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule;
import org.jclouds.azurecompute.arm.compute.functions.VMImageToImage; import org.jclouds.azurecompute.arm.compute.functions.VMImageToImage;
import org.jclouds.azurecompute.arm.domain.ResourceDefinition; 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.VMImage;
import org.jclouds.azurecompute.arm.domain.VirtualMachine; 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.CloneImageTemplate;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.ImageTemplate; 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.compute.extensions.ImageExtension;
import org.jclouds.azurecompute.arm.compute.config.AzureComputeServiceContextModule.AzureComputeConstants; 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.net.URI;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable; 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 { public class AzureComputeImageExtension implements ImageExtension {
private final AzureComputeApi api; private final AzureComputeApi api;
private final ListeningExecutorService userExecutor;
private final Supplier<View> blobstore = null;
private final String group;
private final Predicate<URI> imageAvailablePredicate; private final Predicate<URI> imageAvailablePredicate;
private final Predicate<String> nodeSuspendedPredicate; private final Predicate<String> nodeSuspendedPredicate;
private final AzureComputeConstants azureComputeConstants; private final AzureComputeConstants azureComputeConstants;
private final ListeningExecutorService userExecutor;
private final String group;
private final VMImageToImage imageReferenceToImage; 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 = "#"; public static final String CUSTOM_IMAGE_PREFIX = "#";
@Inject @Inject
@ -69,29 +73,28 @@ public class AzureComputeImageExtension implements ImageExtension {
this.userExecutor = userExecutor; this.userExecutor = userExecutor;
this.group = azureComputeConstants.azureResourceGroup(); this.group = azureComputeConstants.azureResourceGroup();
this.imageReferenceToImage = imageReferenceToImage; this.imageReferenceToImage = imageReferenceToImage;
this.api = api;
this.imageAvailablePredicate = imageAvailablePredicate; this.imageAvailablePredicate = imageAvailablePredicate;
this.nodeSuspendedPredicate = nodeSuspendedPredicate; this.nodeSuspendedPredicate = nodeSuspendedPredicate;
this.azureComputeConstants = azureComputeConstants; this.azureComputeConstants = azureComputeConstants;
this.api = api;
} }
@Override @Override
public ImageTemplate buildImageTemplateFromNode(String name, String id) { public ImageTemplate buildImageTemplateFromNode(String name, String id) {
String imageName = name.toLowerCase(); String nameLowerCase = name.toLowerCase();
return new ImageTemplateBuilder.CloneImageTemplateBuilder().nodeId(id).name(imageName).build(); return new ImageTemplateBuilder.CloneImageTemplateBuilder().nodeId(id).name(nameLowerCase).build();
} }
@Override @Override
public ListenableFuture<Image> createImage(ImageTemplate template) { public ListenableFuture<Image> createImage(ImageTemplate template) {
final CloneImageTemplate cloneTemplate = (CloneImageTemplate) template; final CloneImageTemplate cloneTemplate = (CloneImageTemplate) template;
final String id = cloneTemplate.getSourceNodeId(); final String id = cloneTemplate.getSourceNodeId();
final String name = cloneTemplate.getName(); final String name = cloneTemplate.getName();
final String storageAccountName = id.replaceAll("[^A-Za-z0-9 ]", "") + "stor"; 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); api.getVirtualMachineApi(group).stop(id);
//Poll until resource is ready to be used
if (nodeSuspendedPredicate.apply(id)) { if (nodeSuspendedPredicate.apply(id)) {
return userExecutor.submit(new Callable<Image>() { return userExecutor.submit(new Callable<Image>() {
@Override @Override
@ -118,26 +121,36 @@ public class AzureComputeImageExtension implements ImageExtension {
disks[1] = datadiskObject.get("name"); disks[1] = datadiskObject.get("name");
VirtualMachine vm = api.getVirtualMachineApi(group).get(id); VirtualMachine vm = api.getVirtualMachineApi(group).get(id);
String location = vm.location(); final VMImage ref = VMImage.create(group, storageAccountName, disks[0], disks[1], name, "custom", vm.location());
final VMImage ref = VMImage.create(CUSTOM_IMAGE_PREFIX + group, CUSTOM_IMAGE_PREFIX + name, disks[0], disks[1], location, false);
return imageReferenceToImage.apply(ref); return imageReferenceToImage.apply(ref);
} }
} }
} }
} }
throw new UncheckedTimeoutException("Image was not created within the time limit: " throw new UncheckedTimeoutException("Image was not created within the time limit: "
+ cloneTemplate.getName()); + cloneTemplate.getName());
} }
}); });
} else { } else {
final String illegalStateExceptionMessage = format("Node %s was not suspended within %sms.", final String illegalStateExceptionMessage = format("Node %s was not suspended within %sms.",
id, azureComputeConstants.operationTimeout()); id, azureComputeConstants.operationTimeout());
throw new IllegalStateException(illegalStateExceptionMessage); throw new IllegalStateException(illegalStateExceptionMessage);
} }
} }
@Override @Override
public boolean deleteImage(String id) { 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; return false;
} }
} }

View File

@ -210,7 +210,7 @@ public class DeploymentToNodeMetadata implements Function<VMDeployment, NodeMeta
if (imageReference != null) { if (imageReference != null) {
VMImage vmImage = VMImage.create(imageReference.publisher(), imageReference.offer(), imageReference.sku(), VMImage vmImage = VMImage.create(imageReference.publisher(), imageReference.offer(), imageReference.sku(),
imageReference.version(), locationName, false); imageReference.version(), locationName);
Image image = vmImageToImage.apply(vmImage); Image image = vmImageToImage.apply(vmImage);
builder.imageId(image.getId()); builder.imageId(image.getId());
} }

View File

@ -17,7 +17,6 @@
package org.jclouds.azurecompute.arm.compute.functions; package org.jclouds.azurecompute.arm.compute.functions;
import static com.google.common.base.Preconditions.checkNotNull; 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_PASSWORD;
import static org.jclouds.azurecompute.arm.compute.functions.DeploymentToNodeMetadata.AZURE_LOGIN_USERNAME; import static org.jclouds.azurecompute.arm.compute.functions.DeploymentToNodeMetadata.AZURE_LOGIN_USERNAME;
@ -67,8 +66,33 @@ public class VMImageToImage implements Function<VMImage, Image> {
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) { public static String encodeFieldsToUniqueIdCustom(VMImage imageReference){
return checkNotNull(id, "id").split("/"); 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 @Inject
@ -80,26 +104,41 @@ public class VMImageToImage implements Function<VMImage, Image> {
public Image apply(final VMImage image) { public Image apply(final VMImage image) {
Credentials credentials = new Credentials(AZURE_LOGIN_USERNAME, AZURE_LOGIN_PASSWORD); Credentials credentials = new Credentials(AZURE_LOGIN_USERNAME, AZURE_LOGIN_PASSWORD);
String name = ""; if (image.custom()) {
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());
final OperatingSystem.Builder osBuilder = osFamily().apply(image); final ImageBuilder builder = new ImageBuilder()
return builder.operatingSystem(osBuilder.build()).build(); .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<VMImage, OperatingSystem.Builder> osFamily() { public static Function<VMImage, OperatingSystem.Builder> osFamily() {
@ -124,12 +163,16 @@ public class VMImageToImage implements Function<VMImage, Image> {
family = OsFamily.OEL; family = OsFamily.OEL;
} }
String sku = image.sku();
if (image.custom())
sku = image.vhd1();
// only 64bit OS images are supported by Azure ARM // only 64bit OS images are supported by Azure ARM
return OperatingSystem.builder(). return OperatingSystem.builder().
family(family). family(family).
is64Bit(true). is64Bit(true).
description(image.sku()). description(sku).
version(image.sku()); version(sku);
} }
}; };
} }

View File

@ -17,34 +17,39 @@
package org.jclouds.azurecompute.arm.domain; package org.jclouds.azurecompute.arm.domain;
import com.google.auto.value.AutoValue; import com.google.auto.value.AutoValue;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames; import org.jclouds.json.SerializedNames;
@AutoValue @AutoValue
public abstract class VMImage { public abstract class VMImage {
/** /**
* The publisher of the image reference. * The publisher of the image reference.
*/ */
@Nullable
public abstract String publisher(); public abstract String publisher();
/** /**
* The offer of the image reference. * The offer of the image reference.
*/ */
@Nullable
public abstract String offer(); public abstract String offer();
/** /**
* The sku of the image reference. * The sku of the image reference.
*/ */
@Nullable
public abstract String sku(); public abstract String sku();
/** /**
* The version of the image reference. * The version of the image reference.
*/ */
@Nullable
public abstract String version(); public abstract String version();
/** /**
* The location from where Image was fetched * The location from where Image was fetched
*/ */
@Nullable
public abstract String location(); public abstract String location();
/** /**
@ -52,9 +57,50 @@ public abstract class VMImage {
*/ */
public abstract 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) { * 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);
} }
} }

View File

@ -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<VMImage> getImages(String containerName, String group,
String storageAccountName, String key, String offer, String location) {
final AzureBlobClient azureBlob = ContextBuilder.newBuilder("azureblob")
.credentials(storageAccountName, key)
.buildApi(AzureBlobClient.class);
List<VMImage> list = new ArrayList<VMImage>();
try {
BoundedSet<ContainerProperties> containerList = azureBlob.listContainers();
for (ContainerProperties props : containerList) {
if (props.getName().equals("system")) {
ListBlobsResponse blobList = azureBlob.listBlobs("system");
String osDisk = "";
String dataDisk = "";
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;
}
}

View File

@ -182,7 +182,7 @@ public class DeploymentTemplateBuilder {
String imageName = template.getImage().getName(); String imageName = template.getImage().getName();
if (imageName.startsWith(CUSTOM_IMAGE_PREFIX)) { if (imageName.startsWith(CUSTOM_IMAGE_PREFIX)) {
storageAccountName = imageName.substring(CUSTOM_IMAGE_PREFIX.length()); // get group name storageAccountName = template.getImage().getVersion();
} }
if (Strings.isNullOrEmpty(storageAccountName)) { if (Strings.isNullOrEmpty(storageAccountName)) {
@ -414,13 +414,12 @@ public class DeploymentTemplateBuilder {
boolean usingMarketplaceImage = true; boolean usingMarketplaceImage = true;
String cusotomImageUri = ""; String cusotomImageUri = "";
// TODO: make new fields for group information // Handle custom image case if description starts with CUSTOM_IMAGE_PREFIX
String publisher = template.getImage().getProviderId(); String vhd1 = template.getImage().getProviderId();
String storageName = template.getImage().getName(); String description = template.getImage().getDescription();
String sku = template.getImage().getDescription(); // this is actual VHD if (description.substring(0, CUSTOM_IMAGE_PREFIX.length()).equals(CUSTOM_IMAGE_PREFIX)) {
if (storageName.startsWith(CUSTOM_IMAGE_PREFIX)) { String storageName = template.getImage().getVersion();
storageName = storageName.substring(CUSTOM_IMAGE_PREFIX.length()); // get group name cusotomImageUri = vhd1;
cusotomImageUri = sku;
cusotomImageUri = "https://" + storageName + ".blob.core.windows.net/system/Microsoft.Compute/Images/" + AzureComputeImageExtension.CONTAINER_NAME + "/" + cusotomImageUri; cusotomImageUri = "https://" + storageName + ".blob.core.windows.net/system/Microsoft.Compute/Images/" + AzureComputeImageExtension.CONTAINER_NAME + "/" + cusotomImageUri;
} }

View File

@ -63,7 +63,7 @@ public class AzureComputeImageExtensionLiveTest extends BaseImageExtensionLiveTe
properties.setProperty(TIMEOUT_PORT_OPEN, scriptTimeout + ""); properties.setProperty(TIMEOUT_PORT_OPEN, scriptTimeout + "");
properties.setProperty(TIMEOUT_NODE_TERMINATED, scriptTimeout + ""); properties.setProperty(TIMEOUT_NODE_TERMINATED, scriptTimeout + "");
properties.setProperty(TIMEOUT_NODE_SUSPENDED, 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_INITIAL_PERIOD, 1000);
properties.put(ComputeServiceProperties.POLL_MAX_PERIOD, 10000); properties.put(ComputeServiceProperties.POLL_MAX_PERIOD, 10000);
@ -86,4 +86,5 @@ public class AzureComputeImageExtensionLiveTest extends BaseImageExtensionLiveTe
return pm; return pm;
} }
} }