Update ImageExtension to work with Managed Disks

This commit is contained in:
Dani Estevez 2017-03-17 17:23:49 -04:00 committed by Ignasi Barrera
parent 37dcb87dfa
commit cc13cfeda1
52 changed files with 940 additions and 863 deletions

View File

@ -67,7 +67,11 @@
<groupId>org.apache.jclouds.api</groupId>
<artifactId>oauth</artifactId>
<version>${project.version}</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.apache.jclouds.driver</groupId>
<artifactId>jclouds-okhttp</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jclouds.api</groupId>
@ -102,27 +106,11 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.jclouds.driver</groupId>
<artifactId>jclouds-slf4j</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.jclouds.provider</groupId>
<artifactId>azureblob</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.jclouds.driver</groupId>
<artifactId>jclouds-okhttp</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp</groupId>
<artifactId>mockwebserver</artifactId>
@ -135,20 +123,13 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.jclouds</groupId>
<artifactId>jclouds-blobstore</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
<profiles>
<profile>
<id>live</id>
<build>
<defaultGoal>clean verify</defaultGoal>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>

View File

@ -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.

View File

@ -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");

View File

@ -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<Virtual
private final Supplier<Set<String>> regionIds;
private final PublicIpAvailablePredicateFactory publicIpAvailable;
private final LoadingCache<String, ResourceGroup> resourceGroupMap;
private final CustomImageToVMImage customImagetoVmImage;
@Inject
AzureComputeServiceAdapter(final AzureComputeApi api, @Named(IMAGE_PUBLISHERS) String imagePublishers,
CleanupResources cleanupResources, @Region Supplier<Set<String>> regionIds,
PublicIpAvailablePredicateFactory publicIpAvailable, LoadingCache<String, ResourceGroup> resourceGroupMap) {
CleanupResources cleanupResources, @Region Supplier<Set<String>> regionIds,
PublicIpAvailablePredicateFactory publicIpAvailable, LoadingCache<String, ResourceGroup> 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<Virtual
}
return osImages;
}
private List<VMImage> listCustomImagesByLocation(String location) {
ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(location);
List<org.jclouds.azurecompute.arm.domain.Image> customImages = api.getVirtualMachineImageApi(resourceGroup.name()).list();
return Lists.transform(customImages, customImagetoVmImage);
}
@Override
public Iterable<VMImage> listImages() {
final List<VMImage> osImages = Lists.newArrayList();
final List<String> availableLocationNames = FluentIterable.from(listLocations())
.transform(new Function<Location, String>() {
@Override public String apply(Location location) {
return location.name();
}
}).toList();
final ImmutableList.Builder<VMImage> osImages = ImmutableList.builder();
Iterable<String> availableLocationNames = transform(listLocations(), new Function<Location, String>() {
@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<StorageService> 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<VMImage> 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<Virtual
ResourceGroup resourceGroup = resourceGroupMap.getUnchecked(image.location());
if (image.custom()) {
VMImage customImage = null;
StorageServiceKeys keys = api.getStorageAccountApi(resourceGroup.name()).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<VMImage> customImagesInStorage = blobHelper.getImages(CONTAINER_NAME, resourceGroup.name(),
CUSTOM_IMAGE_OFFER, image.location());
customImage = find(customImagesInStorage, new Predicate<VMImage>() {
@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<Virtual
return VMImage.azureImage().publisher(publisher).offer(offer).sku(sku).version(version.name())
.location(location).versionProperties(version.properties()).build();
}
return null;
}
@ -458,13 +414,9 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual
}
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();
return isCustom(image.getId()) ? ImageReference.builder().customImageId(image.getProviderId()).build() : ImageReference
.builder().publisher(image.getProviderId()).offer(image.getName()).sku(image.getVersion())
.version("latest").build();
}
private OSDisk createOSDisk(Image image) {
@ -474,7 +426,7 @@ public class AzureComputeServiceAdapter implements ComputeServiceAdapter<Virtual
.osType(osType)
.caching(DataDisk.CachingTypes.READ_WRITE.toString())
.createOption(CreationData.CreateOptions.FROM_IMAGE.toString())
.managedDiskParameters(ManagedDiskParameters.create(null, ManagedDiskParameters.StorageAccountTypes.STANDARD_LRS.toString()))
.managedDiskParameters(ManagedDiskParameters.create(null, StorageAccountType.STANDARD_LRS.toString()))
.build();
}

View File

@ -40,7 +40,6 @@ import org.jclouds.azurecompute.arm.compute.extensions.AzureComputeSecurityGroup
import org.jclouds.azurecompute.arm.compute.functions.LocationToLocation;
import org.jclouds.azurecompute.arm.compute.functions.NetworkSecurityGroupToSecurityGroup;
import org.jclouds.azurecompute.arm.compute.functions.NetworkSecurityRuleToIpPermission;
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;
@ -48,6 +47,7 @@ import org.jclouds.azurecompute.arm.compute.loaders.CreateSecurityGroupIfNeeded;
import org.jclouds.azurecompute.arm.compute.loaders.ResourceGroupForLocation;
import org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions;
import org.jclouds.azurecompute.arm.compute.strategy.CreateResourceGroupThenCreateNodes;
import org.jclouds.azurecompute.arm.domain.Image;
import org.jclouds.azurecompute.arm.domain.Location;
import org.jclouds.azurecompute.arm.domain.NetworkSecurityGroup;
import org.jclouds.azurecompute.arm.domain.NetworkSecurityRule;
@ -86,7 +86,6 @@ import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.FactoryModuleBuilder;
public class AzureComputeServiceContextModule extends
ComputeServiceAdapterContextModule<VirtualMachine, VMHardware, VMImage, Location> {
@ -115,8 +114,6 @@ public class AzureComputeServiceContextModule extends
install(new LocationsFromComputeServiceAdapterModule<VirtualMachine, VMHardware, VMImage, Location>() {
});
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<URI> provideImageAvailablePredicate(final AzureComputeApi api, final Timeouts timeouts,
protected Predicate<URI> 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<Supplier<Provisionable>> resourceAvailable) {
return new SecurityGroupAvailablePredicateFactory(api, resourceAvailable);
}
@Provides
protected ImageAvailablePredicateFactory provideImageAvailablePredicate(final AzureComputeApi api,
Predicate<Supplier<Provisionable>> resourceAvailable, final Timeouts timeouts, final PollPeriod pollPeriod) {
return new ImageAvailablePredicateFactory(api, retry(new ResourceInStatusPredicate("Succeeded"),
timeouts.imageAvailable, pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod));
}
@Provides
protected Predicate<Supplier<Provisionable>> provideResourceAvailablePredicate(final AzureComputeApi api,
@ -231,11 +235,11 @@ public class AzureComputeServiceContextModule extends
}
@VisibleForTesting
static class ImageDonePredicate implements Predicate<URI> {
static class ImageCapturedPredicate implements Predicate<URI> {
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<Supplier<Provisionable>> resourceAvailable;
ImageAvailablePredicateFactory(final AzureComputeApi api,
Predicate<Supplier<Provisionable>> resourceAvailable) {
this.api = checkNotNull(api, "api cannot be null");
this.resourceAvailable = resourceAvailable;
}
public Predicate<String> create(final String resourceGroup) {
checkNotNull(resourceGroup, "resourceGroup cannot be null");
return new Predicate<String>() {
@Override
public boolean apply(final String name) {
checkNotNull(name, "name cannot be null");
return resourceAvailable.apply(new Supplier<Provisionable>() {
@Override
public Provisionable get() {
Image img = api.getVirtualMachineImageApi(resourceGroup).get(name);
return img == null ? null : img.properties();
}
});
}
};
}
}
}

View File

@ -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<URI> imageAvailablePredicate;
private final ImageAvailablePredicateFactory imageAvailablePredicate;
private final VirtualMachineInStatePredicateFactory nodeSuspendedPredicate;
private final ResourceDefinitionToCustomImage.Factory resourceDefinitionToImage;
private final CleanupResources cleanupResources;
private final LoadingCache<String, ResourceGroup> resourceGroupMap;
private final Function<VMImage, Image> vmImageToImage;
private final Predicate<URI> resourceDeleted;
private final CustomImageToVMImage customImagetoVmImage;
@Inject
AzureComputeImageExtension(AzureComputeApi api,
@Named(TIMEOUT_IMAGE_AVAILABLE) Predicate<URI> imageAvailablePredicate,
ImageAvailablePredicateFactory imageAvailablePredicate,
@Named(TIMEOUT_NODE_SUSPENDED) VirtualMachineInStatePredicateFactory nodeSuspendedPredicate,
@Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor,
ResourceDefinitionToCustomImage.Factory resourceDefinitionToImage, CleanupResources cleanupResources,
LoadingCache<String, ResourceGroup> resourceGroupMap) {
Function<VMImage, Image> vmImageToImage, LoadingCache<String, ResourceGroup> resourceGroupMap,
@Named(TIMEOUT_RESOURCE_DELETED) Predicate<URI> 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<Image> 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<ResourceDefinition> 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);
}
}

View File

@ -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<StorageProfile, String> {
public class CustomImageToVMImage implements Function<Image, VMImage> {
@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();
}
}

View File

@ -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<ResourceDefinition, Image> {
public interface Factory {
ResourceDefinitionToCustomImage create(@Assisted("nodeId") String nodeId, @Assisted("imageName") String imageName);
}
private final Function<VMImage, Image> vmImageToImage;
private final String imageName;
private final String nodeId;
private final AzureComputeApi api;
private final StorageProfileToStorageAccountName storageProfileToStorageAccountName;
private final LoadingCache<String, ResourceGroup> resourceGroupMap;
@Inject
ResourceDefinitionToCustomImage(AzureComputeApi api,
StorageProfileToStorageAccountName storageProfileToStorageAccountName,
Function<VMImage, Image> vmImageToImage, LoadingCache<String, ResourceGroup> 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<String, String> properties = (Map<String, String>) input.properties();
Object storageObject = properties.get("storageProfile");
Map<String, String> storageProperties = (Map<String, String>) storageObject;
Object osDiskObject = storageProperties.get("osDisk");
Map<String, String> osProperties = (Map<String, String>) osDiskObject;
builder.vhd1(osProperties.get("name"));
return vmImageToImage.apply(builder.build());
}
}

View File

@ -87,7 +87,8 @@ public class TemplateToAvailabilitySet implements Function<Template, Availabilit
logger.debug(">> 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());
}
}

View File

@ -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<VMImage, Image> {
private final Supplier<Set<? extends org.jclouds.domain.Location>> 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<VMImage, Image> {
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<VMImage, Image> {
}
@Inject
VMImageToImage(@Memoized final Supplier<Set<? extends Location>> locations) {
VMImageToImage(@Memoized Supplier<Set<? extends Location>> locations) {
this.locations = locations;
}
@ -110,7 +112,7 @@ public class VMImageToImage implements Function<VMImage, 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));
.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<VMImage, Image> {
// 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());
}
};

View File

@ -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<VirtualMachine, NodeMetadata> {
@Resource
@ -81,8 +74,6 @@ public class VirtualMachineToNodeMetadata implements Function<VirtualMachine, No
private final GroupNamingConvention nodeNamingConvention;
private final Supplier<Set<? extends Location>> locations;
private final Supplier<Map<String, ? extends Hardware>> hardwares;
private final Function<VMImage, Image> vmImageToImge;
private final StorageProfileToStorageAccountName storageProfileToStorageAccountName;
private final LoadingCache<String, ResourceGroup> resourceGroupMap;
private final ImageCacheSupplier imageCache;
private final VirtualMachineToStatus virtualMachineToStatus;
@ -90,16 +81,12 @@ public class VirtualMachineToNodeMetadata implements Function<VirtualMachine, No
@Inject
VirtualMachineToNodeMetadata(AzureComputeApi api, GroupNamingConvention.Factory namingConvention,
Supplier<Map<String, ? extends Hardware>> hardwares, @Memoized Supplier<Set<? extends Location>> locations,
Map<String, Credentials> credentialStore, Function<VMImage, Image> vmImageToImge,
StorageProfileToStorageAccountName storageProfileToStorageAccountName,
LoadingCache<String, ResourceGroup> resourceGroupMap, @Memoized Supplier<Set<? extends Image>> imageCache,
VirtualMachineToStatus virtualMachineToStatus) {
Map<String, Credentials> credentialStore, LoadingCache<String, ResourceGroup> resourceGroupMap,
@Memoized Supplier<Set<? extends Image>> 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<VirtualMachine, No
protected Optional<? extends Image> 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<VMImage> customImagesInStorage = blobHelper.getImages(CONTAINER_NAME, azureGroup, CUSTOM_IMAGE_OFFER,
locatioName);
Optional<VMImage> customImage = tryFind(customImagesInStorage, new Predicate<VMImage>() {
@Override
public boolean apply(VMImage input) {
return input.vhd1().equals(storageProfile.osDisk().image().uri());
}
});
return customImage.isPresent() ? Optional.of(vmImageToImge.apply(customImage.get())) : Optional
.<Image> absent();
} finally {
closeQuietly(blobHelper);
}
logger.warn("could not find image for storage profile %s", storageProfile);
return Optional.absent();
}
}

View File

@ -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<URI> resourceDeleted;
private final StorageProfileToStorageAccountName storageProfileToStorageAccountName;
private final LoadingCache<String, ResourceGroup> resourceGroupMap;
private final GroupNamingConvention.Factory namingConvention;
@Inject
CleanupResources(AzureComputeApi azureComputeApi, @Named(TIMEOUT_RESOURCE_DELETED) Predicate<URI> resourceDeleted,
StorageProfileToStorageAccountName storageProfileToStorageAccountName,
LoadingCache<String, ResourceGroup> 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);

View File

@ -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<String, String> 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<String, String> tags, AvailabilitySetProperties properties) {
return builder().id(id).name(name).type(type).location(location).tags(tags).properties(properties).build();
SKU sku, final Map<String, String> 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<String, String> 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<String, String> tags();
abstract AvailabilitySet autoBuild();

View File

@ -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<String, String> tags();
@SerializedNames({"location", "properties", "tags"})
public static Image create(final String location, final ImageProperties properties, final Map<String, String> 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<String, String> 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<String, String> tags);
abstract Map<String, String> tags();

View File

@ -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();

View File

@ -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);

View File

@ -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));
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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<String, String> tags,
@Nullable @PayloadParam("sku") SKU sku,
@PayloadParam("location") String location,
@Nullable @PayloadParam("tags") Map<String, String> tags,
@PayloadParam("properties") AvailabilitySetProperties properties);
@Named("availabilityset:delete")

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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<String, String> tags,
@PayloadParam("properties") LoadBalancerProperties properties);

View File

@ -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<String, String> tags,
@PayloadParam("properties") NetworkSecurityGroupProperties properties);

View File

@ -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);

View File

@ -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<String, String> 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<String, String> tags);

View File

@ -16,7 +16,6 @@
*/
package org.jclouds.azurecompute.arm.features;
import java.io.Closeable;
import java.util.List;

View File

@ -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<String, String> tags,

View File

@ -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);

View File

@ -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<VMImage> getImages(String containerName, String group, String offer, String location) {
List<VMImage> list = new ArrayList<VMImage>();
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;
}
}

View File

@ -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;
}
}

View File

@ -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<String, ResourceGroup> resourceGroupMap;
private Predicate<URI> resourceDeleted;
public AzureComputeServiceLiveTest() {
provider = "azurecompute-arm";
@ -61,6 +67,8 @@ public class AzureComputeServiceLiveTest extends BaseComputeServiceLiveTest {
resourceGroupMap = context.utils().injector()
.getInstance(Key.get(new TypeLiteral<LoadingCache<String, ResourceGroup>>() {
}));
resourceDeleted = context.utils().injector().getInstance(Key.get(new TypeLiteral<Predicate<URI>>() {
}, 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;
}

View File

@ -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);

View File

@ -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<String, ResourceGroup> resourceGroupMap;
private LoadingCache<String, ResourceGroup> resourceGroupMap;
private Predicate<URI> 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<LoadingCache<String, ResourceGroup>>() {
}));
resourceDeleted = context.utils().injector().getInstance(Key.get(new TypeLiteral<Predicate<URI>>() {
}, 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<String, String> 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());
}
}

View File

@ -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<String, ResourceGroup> resourceGroupMap;
private Predicate<URI> resourceDeleted;
private ResourceGroup testResourceGroup;
public AzureComputeSecurityGroupExtensionLiveTest() {
@ -73,6 +78,8 @@ public class AzureComputeSecurityGroupExtensionLiveTest extends BaseSecurityGrou
resourceGroupMap = context.utils().injector()
.getInstance(Key.get(new TypeLiteral<LoadingCache<String, ResourceGroup>>() {
}));
resourceDeleted = context.utils().injector().getInstance(Key.get(new TypeLiteral<Predicate<URI>>() {
}, 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;
}

View File

@ -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"));

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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<String, ResourceGroup> resourceGroupMap;
private Predicate<URI> 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.<String, String> emptyMap(), null);
@Override
protected void initializeContext() {
super.initializeContext();
resourceDeleted = context.utils().injector().getInstance(Key.get(new TypeLiteral<Predicate<URI>>() {
}, Names.named(TIMEOUT_RESOURCE_DELETED)));
resourceGroupMap = context.utils().injector()
.getInstance(Key.get(new TypeLiteral<LoadingCache<String, ResourceGroup>>() {
}));
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<Image> 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<Provisionable>() {
@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<Image>() {
@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());
}
}

View File

@ -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<Image> 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<Image> 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.<DataDisk> of())).provisioningState("Succeeded").build()).build();
}
}

View File

@ -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<? extends NodeMetadata> nodes = view.getComputeService()
.createNodesInGroup(group, count, availabilitySet(as));

View File

@ -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.<String, String> emptyMap(), null);
assertTrue(!vm.name().isEmpty());
//Poll until resource is ready to be used
boolean jobDone = retry(new Predicate<String>() {
@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<DataDisk> 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.<String, String> 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<ResourceDefinition> definitions = api.getJobApi().captureStatus(uri);
if (definitions != null) {
@ -219,18 +212,13 @@ public class VirtualMachineApiLiveTest extends BaseAzureComputeApiLiveTest {
Map<String, String> properties2 = (Map<String, String>) storageObject;
Object osDiskObject = properties2.get("osDisk");
Map<String, String> osProperties = (Map<String, String>) osDiskObject;
Object dataDisksObject = properties2.get("dataDisks");
List<Object> dataProperties = (List<Object>) dataDisksObject;
Map<String, String> datadiskObject = (Map<String, String>) 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<DataDisk> dataDisks = new ArrayList<DataDisk>();
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<IdReference>();
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<String, String> 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<URI>() {
@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<String>() {
@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<String>() {
@Override
public boolean apply(String name) {

View File

@ -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<DataDisk> dataDisks = new ArrayList<DataDisk>();
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);

View File

@ -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;
}
}

View File

@ -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<AzureComputeApi
@Override protected Properties setupProperties() {
Properties properties = super.setupProperties();
// for oauth
AzureLiveTestUtils.defaultProperties(properties);
AzureLiveTestUtils.defaultProperties(properties, getClass().getSimpleName().toLowerCase());
checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint");
return properties;
}
@ -139,23 +137,6 @@ public class BaseAzureComputeApiLiveTest extends BaseApiLiveTest<AzureComputeApi
return subnet;
}
protected 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<URI>() {
@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"));

View File

@ -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"
}
}

View File

@ -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"
}
}

View File

@ -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"
}
}
]
}