/** * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for * license information. */ package com.microsoft.azure.management.compute.implementation; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.microsoft.azure.Page; import com.microsoft.azure.PagedList; import com.microsoft.azure.SubResource; import com.microsoft.azure.management.apigeneration.LangDefinition; import com.microsoft.azure.management.compute.AvailabilitySet; import com.microsoft.azure.management.compute.AvailabilitySetSkuTypes; import com.microsoft.azure.management.compute.CachingTypes; import com.microsoft.azure.management.compute.DataDisk; import com.microsoft.azure.management.compute.DiagnosticsProfile; import com.microsoft.azure.management.compute.Disk; import com.microsoft.azure.management.compute.DiskCreateOptionTypes; import com.microsoft.azure.management.compute.DiskEncryptionSettings; import com.microsoft.azure.management.compute.HardwareProfile; import com.microsoft.azure.management.compute.ImageReference; import com.microsoft.azure.management.compute.InstanceViewTypes; import com.microsoft.azure.management.compute.KnownLinuxVirtualMachineImage; import com.microsoft.azure.management.compute.KnownWindowsVirtualMachineImage; import com.microsoft.azure.management.compute.LinuxConfiguration; import com.microsoft.azure.management.compute.OSDisk; import com.microsoft.azure.management.compute.OSProfile; import com.microsoft.azure.management.compute.OperatingSystemTypes; import com.microsoft.azure.management.compute.Plan; import com.microsoft.azure.management.compute.PowerState; import com.microsoft.azure.management.compute.PurchasePlan; import com.microsoft.azure.management.compute.SshConfiguration; import com.microsoft.azure.management.compute.SshPublicKey; import com.microsoft.azure.management.compute.StorageAccountTypes; import com.microsoft.azure.management.compute.StorageProfile; import com.microsoft.azure.management.compute.VirtualHardDisk; import com.microsoft.azure.management.compute.VirtualMachine; import com.microsoft.azure.management.compute.VirtualMachineDataDisk; import com.microsoft.azure.management.compute.VirtualMachineEncryption; import com.microsoft.azure.management.compute.VirtualMachineUnmanagedDataDisk; import com.microsoft.azure.management.compute.VirtualMachineExtension; import com.microsoft.azure.management.compute.VirtualMachineInstanceView; import com.microsoft.azure.management.compute.VirtualMachineSize; import com.microsoft.azure.management.compute.VirtualMachineSizeTypes; import com.microsoft.azure.management.compute.WinRMConfiguration; import com.microsoft.azure.management.compute.WinRMListener; import com.microsoft.azure.management.compute.WindowsConfiguration; import com.microsoft.azure.management.network.Network; import com.microsoft.azure.management.network.NetworkInterface; import com.microsoft.azure.management.network.PublicIPAddress; import com.microsoft.azure.management.network.implementation.NetworkManager; import com.microsoft.azure.management.resources.fluentcore.arm.ResourceUtils; import com.microsoft.azure.management.resources.fluentcore.arm.models.implementation.GroupableResourceImpl; import com.microsoft.azure.management.resources.fluentcore.model.Creatable; import com.microsoft.azure.management.resources.fluentcore.utils.PagedListConverter; import com.microsoft.azure.management.resources.fluentcore.utils.ResourceNamer; import com.microsoft.azure.management.resources.fluentcore.utils.SdkContext; import com.microsoft.azure.management.resources.fluentcore.utils.Utils; import com.microsoft.azure.management.resources.implementation.PageImpl; import com.microsoft.azure.management.storage.StorageAccount; import com.microsoft.azure.management.storage.implementation.StorageManager; import com.microsoft.rest.ServiceCallback; import com.microsoft.rest.ServiceFuture; import rx.Completable; import rx.Observable; import rx.exceptions.Exceptions; import rx.functions.Func0; import rx.functions.Func1; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; /** * The implementation for VirtualMachine and its create and update interfaces. */ @LangDefinition class VirtualMachineImpl extends GroupableResourceImpl< VirtualMachine, VirtualMachineInner, VirtualMachineImpl, ComputeManager> implements VirtualMachine, VirtualMachine.DefinitionManagedOrUnmanaged, VirtualMachine.DefinitionManaged, VirtualMachine.DefinitionUnmanaged, VirtualMachine.Update { // Clients private final StorageManager storageManager; private final NetworkManager networkManager; // the name of the virtual machine private final String vmName; // used to generate unique name for any dependency resources private final ResourceNamer namer; // unique key of a creatable storage account to be used for virtual machine child resources that // requires storage [OS disk, data disk etc..] private String creatableStorageAccountKey; // unique key of a creatable availability set that this virtual machine to put private String creatableAvailabilitySetKey; // unique key of a creatable network interface that needs to be used as virtual machine's primary network interface private String creatablePrimaryNetworkInterfaceKey; // unique key of a creatable network interfaces that needs to be used as virtual machine's secondary network interface private List<String> creatableSecondaryNetworkInterfaceKeys; // reference to an existing storage account to be used for virtual machine child resources that // requires storage [OS disk, data disk etc..] private StorageAccount existingStorageAccountToAssociate; // reference to an existing availability set that this virtual machine to put private AvailabilitySet existingAvailabilitySetToAssociate; // reference to an existing network interface that needs to be used as virtual machine's primary network interface private NetworkInterface existingPrimaryNetworkInterfaceToAssociate; // reference to a list of existing network interfaces that needs to be used as virtual machine's secondary network interface private List<NetworkInterface> existingSecondaryNetworkInterfacesToAssociate; private VirtualMachineInstanceView virtualMachineInstanceView; private boolean isMarketplaceLinuxImage; // Intermediate state of network interface definition to which private IP can be associated private NetworkInterface.DefinitionStages.WithPrimaryPrivateIP nicDefinitionWithPrivateIp; // Intermediate state of network interface definition to which subnet can be associated private NetworkInterface.DefinitionStages.WithPrimaryNetworkSubnet nicDefinitionWithSubnet; // Intermediate state of network interface definition to which public IP can be associated private NetworkInterface.DefinitionStages.WithCreate nicDefinitionWithCreate; // Virtual machine size converter private final PagedListConverter<VirtualMachineSizeInner, VirtualMachineSize> virtualMachineSizeConverter; // The entry point to manage extensions associated with the virtual machine private VirtualMachineExtensionsImpl virtualMachineExtensions; // Flag indicates native disk is selected for OS and Data disks private boolean isUnmanagedDiskSelected; // Error messages // The native data disks associated with the virtual machine private List<VirtualMachineUnmanagedDataDisk> unmanagedDataDisks; // To track the managed data disks private final ManagedDataDiskCollection managedDataDisks; VirtualMachineImpl(String name, VirtualMachineInner innerModel, final ComputeManager computeManager, final StorageManager storageManager, final NetworkManager networkManager) { super(name, innerModel, computeManager); this.storageManager = storageManager; this.networkManager = networkManager; this.vmName = name; this.isMarketplaceLinuxImage = false; this.namer = SdkContext.getResourceNamerFactory().createResourceNamer(this.vmName); this.creatableSecondaryNetworkInterfaceKeys = new ArrayList<>(); this.existingSecondaryNetworkInterfacesToAssociate = new ArrayList<>(); this.virtualMachineSizeConverter = new PagedListConverter<VirtualMachineSizeInner, VirtualMachineSize>() { @Override public VirtualMachineSize typeConvert(VirtualMachineSizeInner inner) { return new VirtualMachineSizeImpl(inner); } }; this.virtualMachineExtensions = new VirtualMachineExtensionsImpl(computeManager.inner().virtualMachineExtensions(), this); this.managedDataDisks = new ManagedDataDiskCollection(this); initializeDataDisks(); } // Verbs @Override public Observable<VirtualMachine> refreshAsync() { return super.refreshAsync().map(new Func1<VirtualMachine, VirtualMachine>() { @Override public VirtualMachine call(VirtualMachine virtualMachine) { final VirtualMachineImpl impl = (VirtualMachineImpl) virtualMachine; impl.clearCachedRelatedResources(); impl.initializeDataDisks(); // TODO - ans - We need to call refreshAsync here. impl.virtualMachineExtensions.refresh(); return impl; } }); } @Override protected Observable<VirtualMachineInner> getInnerAsync() { return this.manager().inner().virtualMachines().getByResourceGroupAsync(this.resourceGroupName(), this.name()); } @Override public void deallocate() { this.deallocateAsync().await(); } @Override public Completable deallocateAsync() { Observable<OperationStatusResponseInner> o = this.manager().inner().virtualMachines().deallocateAsync(this.resourceGroupName(), this.name()); Observable<VirtualMachine> r = this.refreshAsync(); // Refresh after deallocate to ensure the inner is updatable (due to a change in behavior in Managed Disks) return Observable.concat(o, r).toCompletable(); } @Override public ServiceFuture<Void> deallocateAsync(ServiceCallback<Void> callback) { return ServiceFuture.fromBody(this.deallocateAsync().<Void>toObservable(), callback); } @Override public void generalize() { this.generalizeAsync().await(); } @Override public Completable generalizeAsync() { return this.manager().inner().virtualMachines().generalizeAsync(this.resourceGroupName(), this.name()).toCompletable(); } @Override public ServiceFuture<Void> generalizeAsync(ServiceCallback<Void> callback) { return ServiceFuture.fromBody(this.generalizeAsync().<Void>toObservable(), callback); } @Override public void powerOff() { this.powerOffAsync().await(); } @Override public Completable powerOffAsync() { return this.manager().inner().virtualMachines().powerOffAsync(this.resourceGroupName(), this.name()).toCompletable(); } @Override public ServiceFuture<Void> powerOffAsync(ServiceCallback<Void> callback) { return ServiceFuture.fromBody(this.powerOffAsync().<Void>toObservable(), callback); } @Override public void restart() { this.manager().inner().virtualMachines().restart(this.resourceGroupName(), this.name()); } @Override public Completable restartAsync() { return null; } @Override public ServiceFuture<Void> restartAsync(ServiceCallback<Void> callback) { return null; } @Override public void start() { this.startAsync().await(); } @Override public Completable startAsync() { return this.manager().inner().virtualMachines().startAsync(this.resourceGroupName(), this.name()).toCompletable(); } @Override public ServiceFuture<Void> startAsync(ServiceCallback<Void> callback) { return ServiceFuture.fromBody(this.startAsync().<Void>toObservable(), callback); } @Override public void redeploy() { this.redeployAsync().await(); } @Override public Completable redeployAsync() { return this.manager().inner().virtualMachines().redeployAsync(this.resourceGroupName(), this.name()).toCompletable(); } @Override public ServiceFuture<Void> redeployAsync(ServiceCallback<Void> callback) { return ServiceFuture.fromBody(this.redeployAsync().<Void>toObservable(), callback); } @Override public void convertToManaged() { this.manager().inner().virtualMachines().convertToManagedDisks(this.resourceGroupName(), this.name()); this.refresh(); } @Override public VirtualMachineEncryption diskEncryption() { return new VirtualMachineEncryptionImpl(this); } @Override public PagedList<VirtualMachineSize> availableSizes() { PageImpl<VirtualMachineSizeInner> page = new PageImpl<>(); page.setItems(this.manager().inner().virtualMachines().listAvailableSizes(this.resourceGroupName(), this.name())); page.setNextPageLink(null); return this.virtualMachineSizeConverter.convert(new PagedList<VirtualMachineSizeInner>(page) { @Override public Page<VirtualMachineSizeInner> nextPage(String nextPageLink) { return null; } }); } @Override public String capture(String containerName, String vhdPrefix, boolean overwriteVhd) { VirtualMachineCaptureParametersInner parameters = new VirtualMachineCaptureParametersInner(); parameters.withDestinationContainerName(containerName); parameters.withOverwriteVhds(overwriteVhd); parameters.withVhdPrefix(vhdPrefix); VirtualMachineCaptureResultInner captureResult = this.manager().inner().virtualMachines().capture(this.resourceGroupName(), this.name(), parameters); if (captureResult == null) { return null; } ObjectMapper mapper = new ObjectMapper(); //Object to JSON string try { return mapper.writeValueAsString(captureResult.output()); } catch (JsonProcessingException e) { throw Exceptions.propagate(e); } } @Override public VirtualMachineInstanceView refreshInstanceView() { return refreshInstanceViewAsync().toBlocking().last(); } @Override public Observable<VirtualMachineInstanceView> refreshInstanceViewAsync() { return this.manager().inner().virtualMachines().getByResourceGroupAsync(this.resourceGroupName(), this.name(), InstanceViewTypes.INSTANCE_VIEW) .map(new Func1<VirtualMachineInner, VirtualMachineInstanceView>() { @Override public VirtualMachineInstanceView call(VirtualMachineInner virtualMachineInner) { if (virtualMachineInner != null) { virtualMachineInstanceView = virtualMachineInner.instanceView(); } else { virtualMachineInstanceView = null; } return virtualMachineInstanceView; } }); } // SETTERS // Fluent methods for defining virtual network association for the new primary network interface // @Override public VirtualMachineImpl withNewPrimaryNetwork(Creatable<Network> creatable) { this.nicDefinitionWithPrivateIp = this.preparePrimaryNetworkInterface(this.namer.randomName("nic", 20)) .withNewPrimaryNetwork(creatable); return this; } @Override public VirtualMachineImpl withNewPrimaryNetwork(String addressSpace) { this.nicDefinitionWithPrivateIp = this.preparePrimaryNetworkInterface(this.namer.randomName("nic", 20)) .withNewPrimaryNetwork(addressSpace); return this; } @Override public VirtualMachineImpl withExistingPrimaryNetwork(Network network) { this.nicDefinitionWithSubnet = this.preparePrimaryNetworkInterface(this.namer.randomName("nic", 20)) .withExistingPrimaryNetwork(network); return this; } @Override public VirtualMachineImpl withSubnet(String name) { this.nicDefinitionWithPrivateIp = this.nicDefinitionWithSubnet .withSubnet(name); return this; } // Fluent methods for defining private IP association for the new primary network interface // @Override public VirtualMachineImpl withPrimaryPrivateIPAddressDynamic() { this.nicDefinitionWithCreate = this.nicDefinitionWithPrivateIp .withPrimaryPrivateIPAddressDynamic(); return this; } @Override public VirtualMachineImpl withPrimaryPrivateIPAddressStatic(String staticPrivateIPAddress) { this.nicDefinitionWithCreate = this.nicDefinitionWithPrivateIp .withPrimaryPrivateIPAddressStatic(staticPrivateIPAddress); return this; } // Fluent methods for defining public IP association for the new primary network interface // @Override public VirtualMachineImpl withNewPrimaryPublicIPAddress(Creatable<PublicIPAddress> creatable) { Creatable<NetworkInterface> nicCreatable = this.nicDefinitionWithCreate .withNewPrimaryPublicIPAddress(creatable); this.creatablePrimaryNetworkInterfaceKey = nicCreatable.key(); this.addCreatableDependency(nicCreatable); return this; } @Override public VirtualMachineImpl withNewPrimaryPublicIPAddress(String leafDnsLabel) { Creatable<NetworkInterface> nicCreatable = this.nicDefinitionWithCreate .withNewPrimaryPublicIPAddress(leafDnsLabel); this.creatablePrimaryNetworkInterfaceKey = nicCreatable.key(); this.addCreatableDependency(nicCreatable); return this; } @Override public VirtualMachineImpl withExistingPrimaryPublicIPAddress(PublicIPAddress publicIPAddress) { Creatable<NetworkInterface> nicCreatable = this.nicDefinitionWithCreate .withExistingPrimaryPublicIPAddress(publicIPAddress); this.creatablePrimaryNetworkInterfaceKey = nicCreatable.key(); this.addCreatableDependency(nicCreatable); return this; } @Override public VirtualMachineImpl withoutPrimaryPublicIPAddress() { Creatable<NetworkInterface> nicCreatable = this.nicDefinitionWithCreate; this.creatablePrimaryNetworkInterfaceKey = nicCreatable.key(); this.addCreatableDependency(nicCreatable); return this; } // Virtual machine primary network interface specific fluent methods // @Override public VirtualMachineImpl withNewPrimaryNetworkInterface(Creatable<NetworkInterface> creatable) { this.creatablePrimaryNetworkInterfaceKey = creatable.key(); this.addCreatableDependency(creatable); return this; } public VirtualMachineImpl withNewPrimaryNetworkInterface(String name, String publicDnsNameLabel) { Creatable<NetworkInterface> definitionCreatable = prepareNetworkInterface(name) .withNewPrimaryPublicIPAddress(publicDnsNameLabel); return withNewPrimaryNetworkInterface(definitionCreatable); } @Override public VirtualMachineImpl withExistingPrimaryNetworkInterface(NetworkInterface networkInterface) { this.existingPrimaryNetworkInterfaceToAssociate = networkInterface; return this; } // Virtual machine image specific fluent methods // @Override public VirtualMachineImpl withStoredWindowsImage(String imageUrl) { VirtualHardDisk userImageVhd = new VirtualHardDisk(); userImageVhd.withUri(imageUrl); this.inner().storageProfile().osDisk().withCreateOption(DiskCreateOptionTypes.FROM_IMAGE); this.inner().storageProfile().osDisk().withImage(userImageVhd); // For platform image osType will be null, azure will pick it from the image metadata. this.inner().storageProfile().osDisk().withOsType(OperatingSystemTypes.WINDOWS); this.inner().osProfile().withWindowsConfiguration(new WindowsConfiguration()); // sets defaults for "Stored(User)Image" or "VM(Platform)Image" this.inner().osProfile().windowsConfiguration().withProvisionVMAgent(true); this.inner().osProfile().windowsConfiguration().withEnableAutomaticUpdates(true); return this; } @Override public VirtualMachineImpl withStoredLinuxImage(String imageUrl) { VirtualHardDisk userImageVhd = new VirtualHardDisk(); userImageVhd.withUri(imageUrl); this.inner().storageProfile().osDisk().withCreateOption(DiskCreateOptionTypes.FROM_IMAGE); this.inner().storageProfile().osDisk().withImage(userImageVhd); // For platform | custom image osType will be null, azure will pick it from the image metadata. // But for stored image, osType needs to be specified explicitly // this.inner().storageProfile().osDisk().withOsType(OperatingSystemTypes.LINUX); this.inner().osProfile().withLinuxConfiguration(new LinuxConfiguration()); return this; } @Override public VirtualMachineImpl withPopularWindowsImage(KnownWindowsVirtualMachineImage knownImage) { return withSpecificWindowsImageVersion(knownImage.imageReference()); } @Override public VirtualMachineImpl withPopularLinuxImage(KnownLinuxVirtualMachineImage knownImage) { return withSpecificLinuxImageVersion(knownImage.imageReference()); } @Override public VirtualMachineImpl withSpecificWindowsImageVersion(ImageReference imageReference) { this.inner().storageProfile().osDisk().withCreateOption(DiskCreateOptionTypes.FROM_IMAGE); this.inner().storageProfile().withImageReference(imageReference.inner()); this.inner().osProfile().withWindowsConfiguration(new WindowsConfiguration()); // sets defaults for "Stored(User)Image" or "VM(Platform)Image" this.inner().osProfile().windowsConfiguration().withProvisionVMAgent(true); this.inner().osProfile().windowsConfiguration().withEnableAutomaticUpdates(true); return this; } @Override public VirtualMachineImpl withSpecificLinuxImageVersion(ImageReference imageReference) { this.inner().storageProfile().osDisk().withCreateOption(DiskCreateOptionTypes.FROM_IMAGE); this.inner().storageProfile().withImageReference(imageReference.inner()); this.inner().osProfile().withLinuxConfiguration(new LinuxConfiguration()); this.isMarketplaceLinuxImage = true; return this; } @Override public VirtualMachineImpl withLatestWindowsImage(String publisher, String offer, String sku) { ImageReference imageReference = new ImageReference(); imageReference.withPublisher(publisher); imageReference.withOffer(offer); imageReference.withSku(sku); imageReference.withVersion("latest"); return withSpecificWindowsImageVersion(imageReference); } @Override public VirtualMachineImpl withLatestLinuxImage(String publisher, String offer, String sku) { ImageReference imageReference = new ImageReference(); imageReference.withPublisher(publisher); imageReference.withOffer(offer); imageReference.withSku(sku); imageReference.withVersion("latest"); return withSpecificLinuxImageVersion(imageReference); } @Override public VirtualMachineImpl withWindowsCustomImage(String customImageId) { ImageReferenceInner imageReferenceInner = new ImageReferenceInner(); imageReferenceInner.withId(customImageId); this.inner().storageProfile().osDisk().withCreateOption(DiskCreateOptionTypes.FROM_IMAGE); this.inner().storageProfile().withImageReference(imageReferenceInner); this.inner().osProfile().withWindowsConfiguration(new WindowsConfiguration()); // sets defaults for "Stored(User)Image", "VM(Platform | Custom)Image" this.inner().osProfile().windowsConfiguration().withProvisionVMAgent(true); this.inner().osProfile().windowsConfiguration().withEnableAutomaticUpdates(true); return this; } @Override public VirtualMachineImpl withLinuxCustomImage(String customImageId) { ImageReferenceInner imageReferenceInner = new ImageReferenceInner(); imageReferenceInner.withId(customImageId); this.inner().storageProfile().osDisk().withCreateOption(DiskCreateOptionTypes.FROM_IMAGE); this.inner().storageProfile().withImageReference(imageReferenceInner); this.inner().osProfile().withLinuxConfiguration(new LinuxConfiguration()); this.isMarketplaceLinuxImage = true; return this; } @Override public VirtualMachineImpl withSpecializedOSUnmanagedDisk(String osDiskUrl, OperatingSystemTypes osType) { VirtualHardDisk osVhd = new VirtualHardDisk(); osVhd.withUri(osDiskUrl); this.inner().storageProfile().osDisk().withCreateOption(DiskCreateOptionTypes.ATTACH); this.inner().storageProfile().osDisk().withVhd(osVhd); this.inner().storageProfile().osDisk().withOsType(osType); this.inner().storageProfile().osDisk().withManagedDisk(null); return this; } @Override public VirtualMachineImpl withSpecializedOSDisk(Disk disk, OperatingSystemTypes osType) { ManagedDiskParametersInner diskParametersInner = new ManagedDiskParametersInner(); diskParametersInner.withId(disk.id()); this.inner().storageProfile().osDisk().withCreateOption(DiskCreateOptionTypes.ATTACH); this.inner().storageProfile().osDisk().withManagedDisk(diskParametersInner); this.inner().storageProfile().osDisk().withOsType(osType); this.inner().storageProfile().osDisk().withVhd(null); return this; } // Virtual machine user name fluent methods // @Override public VirtualMachineImpl withRootUsername(String rootUserName) { this.inner().osProfile().withAdminUsername(rootUserName); return this; } @Override public VirtualMachineImpl withAdminUsername(String adminUserName) { this.inner().osProfile().withAdminUsername(adminUserName); return this; } // Virtual machine optional fluent methods // @Override public VirtualMachineImpl withSsh(String publicKeyData) { OSProfile osProfile = this.inner().osProfile(); if (osProfile.linuxConfiguration().ssh() == null) { SshConfiguration sshConfiguration = new SshConfiguration(); sshConfiguration.withPublicKeys(new ArrayList<SshPublicKey>()); osProfile.linuxConfiguration().withSsh(sshConfiguration); } SshPublicKey sshPublicKey = new SshPublicKey(); sshPublicKey.withKeyData(publicKeyData); sshPublicKey.withPath("/home/" + osProfile.adminUsername() + "/.ssh/authorized_keys"); osProfile.linuxConfiguration().ssh().publicKeys().add(sshPublicKey); return this; } @Override public VirtualMachineImpl withoutVMAgent() { this.inner().osProfile().windowsConfiguration().withProvisionVMAgent(false); return this; } @Override public VirtualMachineImpl withoutAutoUpdate() { this.inner().osProfile().windowsConfiguration().withEnableAutomaticUpdates(false); return this; } @Override public VirtualMachineImpl withTimeZone(String timeZone) { this.inner().osProfile().windowsConfiguration().withTimeZone(timeZone); return this; } @Override public VirtualMachineImpl withWinRM(WinRMListener listener) { if (this.inner().osProfile().windowsConfiguration().winRM() == null) { WinRMConfiguration winRMConfiguration = new WinRMConfiguration(); this.inner().osProfile().windowsConfiguration().withWinRM(winRMConfiguration); } this.inner().osProfile() .windowsConfiguration() .winRM() .listeners() .add(listener); return this; } @Override public VirtualMachineImpl withRootPassword(String password) { this.inner().osProfile().withAdminPassword(password); return this; } @Override public VirtualMachineImpl withAdminPassword(String password) { this.inner().osProfile().withAdminPassword(password); return this; } @Override public VirtualMachineImpl withCustomData(String base64EncodedCustomData) { this.inner().osProfile().withCustomData(base64EncodedCustomData); return this; } @Override public VirtualMachineImpl withComputerName(String computerName) { this.inner().osProfile().withComputerName(computerName); return this; } @Override public VirtualMachineImpl withSize(String sizeName) { this.inner().hardwareProfile().withVmSize(new VirtualMachineSizeTypes(sizeName)); return this; } @Override public VirtualMachineImpl withSize(VirtualMachineSizeTypes size) { this.inner().hardwareProfile().withVmSize(size); return this; } @Override public VirtualMachineImpl withOSDiskCaching(CachingTypes cachingType) { this.inner().storageProfile().osDisk().withCaching(cachingType); return this; } @Override public VirtualMachineImpl withOSDiskVhdLocation(String containerName, String vhdName) { // Sets the native (un-managed) disk backing virtual machine OS disk // if (isManagedDiskEnabled()) { return this; } StorageProfile storageProfile = this.inner().storageProfile(); OSDisk osDisk = storageProfile.osDisk(); // Setting native (un-managed) disk backing virtual machine OS disk is valid only when // the virtual machine is created from image. // if (!this.isOSDiskFromImage(osDisk)) { return this; } // Exclude custom user image as they won't support using native (un-managed) disk to back // virtual machine OS disk. // if (this.isOsDiskFromCustomImage(storageProfile)) { return this; } // OS Disk from 'Platform image' requires explicit storage account to be specified. // if (this.isOSDiskFromPlatformImage(storageProfile)) { VirtualHardDisk osVhd = new VirtualHardDisk(); osVhd.withUri(temporaryBlobUrl(containerName, vhdName)); this.inner().storageProfile().osDisk().withVhd(osVhd); return this; } // 'Stored image' and 'Bring your own feature image' has a restriction that the native // disk backing OS disk based on these images should reside in the same storage account // as the image. if (this.isOSDiskFromStoredImage(storageProfile)) { VirtualHardDisk osVhd = new VirtualHardDisk(); try { URL sourceCustomImageUrl = new URL(osDisk.image().uri()); URL destinationVhdUrl = new URL(sourceCustomImageUrl.getProtocol(), sourceCustomImageUrl.getHost(), "/" + containerName + "/" + vhdName); osVhd.withUri(destinationVhdUrl.toString()); } catch (MalformedURLException ex) { throw new RuntimeException(ex); } this.inner().storageProfile().osDisk().withVhd(osVhd); } return this; } @Override public VirtualMachineImpl withOSDiskStorageAccountType(StorageAccountTypes accountType) { if (this.inner().storageProfile().osDisk().managedDisk() == null) { this.inner() .storageProfile() .osDisk() .withManagedDisk(new ManagedDiskParametersInner()); } this.inner() .storageProfile() .osDisk() .managedDisk() .withStorageAccountType(accountType); return this; } @Override public VirtualMachineImpl withDataDiskDefaultCachingType(CachingTypes cachingType) { this.managedDataDisks.setDefaultCachingType(cachingType); return this; } @Override public VirtualMachineImpl withDataDiskDefaultStorageAccountType(StorageAccountTypes storageAccountType) { this.managedDataDisks.setDefaultStorageAccountType(storageAccountType); return this; } @Override public VirtualMachineImpl withOSDiskEncryptionSettings(DiskEncryptionSettings settings) { this.inner().storageProfile().osDisk().withEncryptionSettings(settings); return this; } @Override public VirtualMachineImpl withOSDiskSizeInGB(Integer size) { this.inner().storageProfile().osDisk().withDiskSizeGB(size); return this; } @Override public VirtualMachineImpl withOSDiskName(String name) { this.inner().storageProfile().osDisk().withName(name); return this; } // Virtual machine optional native data disk fluent methods // @Override public UnmanagedDataDiskImpl defineUnmanagedDataDisk(String name) { throwIfManagedDiskEnabled(ManagedUnmanagedDiskErrors.VM_BOTH_MANAGED_AND_UNMANAGED_DISK_NOT_ALLOWED); return UnmanagedDataDiskImpl.prepareDataDisk(name, this); } @Override public VirtualMachineImpl withNewUnmanagedDataDisk(Integer sizeInGB) { throwIfManagedDiskEnabled(ManagedUnmanagedDiskErrors.VM_BOTH_MANAGED_AND_UNMANAGED_DISK_NOT_ALLOWED); return defineUnmanagedDataDisk(null) .withNewVhd(sizeInGB) .attach(); } @Override public VirtualMachineImpl withExistingUnmanagedDataDisk(String storageAccountName, String containerName, String vhdName) { throwIfManagedDiskEnabled(ManagedUnmanagedDiskErrors.VM_BOTH_MANAGED_AND_UNMANAGED_DISK_NOT_ALLOWED); return defineUnmanagedDataDisk(null) .withExistingVhd(storageAccountName, containerName, vhdName) .attach(); } @Override public VirtualMachineImpl withoutUnmanagedDataDisk(String name) { // Its ok not to throw here, since in general 'withoutXX' can be NOP int idx = -1; for (VirtualMachineUnmanagedDataDisk dataDisk : this.unmanagedDataDisks) { idx++; if (dataDisk.name().equalsIgnoreCase(name)) { this.unmanagedDataDisks.remove(idx); this.inner().storageProfile().dataDisks().remove(idx); break; } } return this; } @Override public VirtualMachineImpl withoutUnmanagedDataDisk(int lun) { // Its ok not to throw here, since in general 'withoutXX' can be NOP int idx = -1; for (VirtualMachineUnmanagedDataDisk dataDisk : this.unmanagedDataDisks) { idx++; if (dataDisk.lun() == lun) { this.unmanagedDataDisks.remove(idx); this.inner().storageProfile().dataDisks().remove(idx); break; } } return this; } @Override public UnmanagedDataDiskImpl updateUnmanagedDataDisk(String name) { throwIfManagedDiskEnabled(ManagedUnmanagedDiskErrors.VM_NO_UNMANAGED_DISK_TO_UPDATE); for (VirtualMachineUnmanagedDataDisk dataDisk : this.unmanagedDataDisks) { if (dataDisk.name().equalsIgnoreCase(name)) { return (UnmanagedDataDiskImpl) dataDisk; } } throw new RuntimeException("A data disk with name '" + name + "' not found"); } // Virtual machine optional managed data disk fluent methods // @Override public VirtualMachineImpl withNewDataDisk(Creatable<Disk> creatable) { throwIfManagedDiskDisabled(ManagedUnmanagedDiskErrors.VM_BOTH_UNMANAGED_AND_MANAGED_DISK_NOT_ALLOWED); addCreatableDependency(creatable); this.managedDataDisks.newDisksToAttach.put(creatable.key(), new DataDisk().withLun(-1)); return this; } @Override public VirtualMachineImpl withNewDataDisk(Creatable<Disk> creatable, int lun, CachingTypes cachingType) { throwIfManagedDiskDisabled(ManagedUnmanagedDiskErrors.VM_BOTH_UNMANAGED_AND_MANAGED_DISK_NOT_ALLOWED); addCreatableDependency(creatable); this.managedDataDisks.newDisksToAttach.put(creatable.key(), new DataDisk() .withLun(lun) .withCaching(cachingType)); return this; } @Override public VirtualMachineImpl withNewDataDisk(int sizeInGB) { throwIfManagedDiskDisabled(ManagedUnmanagedDiskErrors.VM_BOTH_UNMANAGED_AND_MANAGED_DISK_NOT_ALLOWED); this.managedDataDisks.implicitDisksToAssociate.add(new DataDisk() .withLun(-1) .withDiskSizeGB(sizeInGB)); return this; } @Override public VirtualMachineImpl withNewDataDisk(int sizeInGB, int lun, CachingTypes cachingType) { throwIfManagedDiskDisabled(ManagedUnmanagedDiskErrors.VM_BOTH_UNMANAGED_AND_MANAGED_DISK_NOT_ALLOWED); this.managedDataDisks.implicitDisksToAssociate.add(new DataDisk() .withLun(lun) .withDiskSizeGB(sizeInGB) .withCaching(cachingType)); return this; } @Override public VirtualMachineImpl withNewDataDisk(int sizeInGB, int lun, CachingTypes cachingType, StorageAccountTypes storageAccountType) { throwIfManagedDiskDisabled(ManagedUnmanagedDiskErrors.VM_BOTH_UNMANAGED_AND_MANAGED_DISK_NOT_ALLOWED); ManagedDiskParametersInner managedDiskParameters = new ManagedDiskParametersInner(); managedDiskParameters.withStorageAccountType(storageAccountType); this.managedDataDisks.implicitDisksToAssociate.add(new DataDisk() .withLun(lun) .withDiskSizeGB(sizeInGB) .withCaching(cachingType) .withManagedDisk(managedDiskParameters)); return this; } @Override public VirtualMachineImpl withExistingDataDisk(Disk disk) { throwIfManagedDiskDisabled(ManagedUnmanagedDiskErrors.VM_BOTH_UNMANAGED_AND_MANAGED_DISK_NOT_ALLOWED); ManagedDiskParametersInner managedDiskParameters = new ManagedDiskParametersInner(); managedDiskParameters.withId(disk.id()); this.managedDataDisks.existingDisksToAttach.add(new DataDisk() .withLun(-1) .withManagedDisk(managedDiskParameters)); return this; } @Override public VirtualMachineImpl withExistingDataDisk(Disk disk, int lun, CachingTypes cachingType) { throwIfManagedDiskDisabled(ManagedUnmanagedDiskErrors.VM_BOTH_UNMANAGED_AND_MANAGED_DISK_NOT_ALLOWED); ManagedDiskParametersInner managedDiskParameters = new ManagedDiskParametersInner(); managedDiskParameters.withId(disk.id()); this.managedDataDisks.existingDisksToAttach.add(new DataDisk() .withLun(lun) .withManagedDisk(managedDiskParameters) .withCaching(cachingType)); return this; } @Override public VirtualMachineImpl withExistingDataDisk(Disk disk, int newSizeInGB, int lun, CachingTypes cachingType) { throwIfManagedDiskDisabled(ManagedUnmanagedDiskErrors.VM_BOTH_UNMANAGED_AND_MANAGED_DISK_NOT_ALLOWED); ManagedDiskParametersInner managedDiskParameters = new ManagedDiskParametersInner(); managedDiskParameters.withId(disk.id()); this.managedDataDisks.existingDisksToAttach.add(new DataDisk() .withLun(lun) .withDiskSizeGB(newSizeInGB) .withManagedDisk(managedDiskParameters) .withCaching(cachingType)); return this; } @Override public VirtualMachineImpl withNewDataDiskFromImage(int imageLun) { this.managedDataDisks.newDisksFromImage.add(new DataDisk() .withLun(imageLun)); return this; } @Override public VirtualMachineImpl withNewDataDiskFromImage(int imageLun, int newSizeInGB, CachingTypes cachingType) { this.managedDataDisks.newDisksFromImage.add(new DataDisk() .withLun(imageLun) .withDiskSizeGB(newSizeInGB) .withCaching(cachingType)); return this; } @Override public VirtualMachineImpl withNewDataDiskFromImage(int imageLun, int newSizeInGB, CachingTypes cachingType, StorageAccountTypes storageAccountType) { ManagedDiskParametersInner managedDiskParameters = new ManagedDiskParametersInner(); managedDiskParameters.withStorageAccountType(storageAccountType); this.managedDataDisks.newDisksFromImage.add(new DataDisk() .withLun(imageLun) .withDiskSizeGB(newSizeInGB) .withManagedDisk(managedDiskParameters) .withCaching(cachingType)); return this; } @Override public VirtualMachineImpl withoutDataDisk(int lun) { if (!isManagedDiskEnabled()) { return this; } this.managedDataDisks.diskLunsToRemove.add(lun); return this; } /* TODO: This has been disabled by Azure REST API @Override public VirtualMachineImpl withDataDiskUpdated(int lun, int newSizeInGB) { throwIfManagedDiskDisabled(ManagedUnmanagedDiskErrors.VM_NO_MANAGED_DISK_TO_UPDATE); DataDisk dataDisk = getDataDiskInner(lun); if (dataDisk == null) { throw new RuntimeException(String.format("A data disk with name '%d' not found", lun)); } dataDisk.withDiskSizeGB(newSizeInGB); return this; } @Override public VirtualMachineImpl withDataDiskUpdated(int lun, int newSizeInGB, CachingTypes cachingType) { throwIfManagedDiskDisabled(ManagedUnmanagedDiskErrors.VM_NO_MANAGED_DISK_TO_UPDATE); DataDisk dataDisk = getDataDiskInner(lun); if (dataDisk == null) { throw new RuntimeException(String.format("A data disk with name '%d' not found", lun)); } dataDisk .withDiskSizeGB(newSizeInGB) .withCaching(cachingType); return this; } @Override public VirtualMachineImpl withDataDiskUpdated(int lun, int newSizeInGB, CachingTypes cachingType, StorageAccountTypes storageAccountType) { throwIfManagedDiskDisabled(ManagedUnmanagedDiskErrors.VM_NO_MANAGED_DISK_TO_UPDATE); DataDisk dataDisk = getDataDiskInner(lun); if (dataDisk == null) { throw new RuntimeException(String.format("A data disk with name '%d' not found", lun)); } dataDisk .withDiskSizeGB(newSizeInGB) .withCaching(cachingType) .managedDisk() .withStorageAccountType(storageAccountType); return this; } private DataDisk getDataDiskInner(int lun) { if (this.inner().storageProfile().dataDisks() == null) { return null; } for (DataDisk dataDiskInner : this.storageProfile().dataDisks()) { if (dataDiskInner.lun() == lun) { return dataDiskInner; } } return null; } */ // Virtual machine optional storage account fluent methods // @Override public VirtualMachineImpl withNewStorageAccount(Creatable<StorageAccount> creatable) { // This method's effect is NOT additive. if (this.creatableStorageAccountKey == null) { this.creatableStorageAccountKey = creatable.key(); this.addCreatableDependency(creatable); } return this; } @Override public VirtualMachineImpl withNewStorageAccount(String name) { StorageAccount.DefinitionStages.WithGroup definitionWithGroup = this.storageManager .storageAccounts() .define(name) .withRegion(this.regionName()); Creatable<StorageAccount> definitionAfterGroup; if (this.creatableGroup != null) { definitionAfterGroup = definitionWithGroup.withNewResourceGroup(this.creatableGroup); } else { definitionAfterGroup = definitionWithGroup.withExistingResourceGroup(this.resourceGroupName()); } return withNewStorageAccount(definitionAfterGroup); } @Override public VirtualMachineImpl withExistingStorageAccount(StorageAccount storageAccount) { this.existingStorageAccountToAssociate = storageAccount; return this; } // Virtual machine optional availability set fluent methods // @Override public VirtualMachineImpl withNewAvailabilitySet(Creatable<AvailabilitySet> creatable) { // This method's effect is NOT additive. if (this.creatableAvailabilitySetKey == null) { this.creatableAvailabilitySetKey = creatable.key(); this.addCreatableDependency(creatable); } return this; } @Override public VirtualMachineImpl withNewAvailabilitySet(String name) { AvailabilitySet.DefinitionStages.WithGroup definitionWithGroup = super.myManager .availabilitySets() .define(name) .withRegion(this.regionName()); AvailabilitySet.DefinitionStages.WithSku definitionWithSku; if (this.creatableGroup != null) { definitionWithSku = definitionWithGroup.withNewResourceGroup(this.creatableGroup); } else { definitionWithSku = definitionWithGroup.withExistingResourceGroup(this.resourceGroupName()); } Creatable<AvailabilitySet> creatable; if (isManagedDiskEnabled()) { creatable = definitionWithSku.withSku(AvailabilitySetSkuTypes.MANAGED); } else { creatable = definitionWithSku.withSku(AvailabilitySetSkuTypes.UNMANAGED); } return withNewAvailabilitySet(creatable); } @Override public VirtualMachineImpl withExistingAvailabilitySet(AvailabilitySet availabilitySet) { this.existingAvailabilitySetToAssociate = availabilitySet; return this; } @Override public VirtualMachineImpl withNewSecondaryNetworkInterface(Creatable<NetworkInterface> creatable) { this.creatableSecondaryNetworkInterfaceKeys.add(creatable.key()); this.addCreatableDependency(creatable); return this; } @Override public VirtualMachineImpl withExistingSecondaryNetworkInterface(NetworkInterface networkInterface) { this.existingSecondaryNetworkInterfacesToAssociate.add(networkInterface); return this; } // Virtual machine optional extension settings @Override public VirtualMachineExtensionImpl defineNewExtension(String name) { return this.virtualMachineExtensions.define(name); } @Override public VirtualMachineImpl withoutSecondaryNetworkInterface(String name) { if (this.inner().networkProfile() != null && this.inner().networkProfile().networkInterfaces() != null) { int idx = -1; for (NetworkInterfaceReferenceInner nicReference : this.inner().networkProfile().networkInterfaces()) { idx++; if (!nicReference.primary() && name.equalsIgnoreCase(ResourceUtils.nameFromResourceId(nicReference.id()))) { this.inner().networkProfile().networkInterfaces().remove(idx); break; } } } return this; } @Override public VirtualMachineExtensionImpl updateExtension(String name) { return this.virtualMachineExtensions.update(name); } @Override public VirtualMachineImpl withoutExtension(String name) { this.virtualMachineExtensions.remove(name); return this; } @Override public VirtualMachineImpl withPlan(PurchasePlan plan) { this.inner().withPlan(new Plan()); this.inner().plan() .withPublisher(plan.publisher()) .withProduct(plan.product()) .withName(plan.name()); return this; } @Override public VirtualMachineImpl withPromotionalPlan(PurchasePlan plan, String promotionCode) { this.withPlan(plan); this.inner().plan().withPromotionCode(promotionCode); return this; } @Override public VirtualMachineImpl withUnmanagedDisks() { this.isUnmanagedDiskSelected = true; return this; } // GETTERS @Override public boolean isManagedDiskEnabled() { if (isOsDiskFromCustomImage(this.inner().storageProfile())) { return true; } if (isOSDiskAttachedManaged(this.inner().storageProfile().osDisk())) { return true; } if (isOSDiskFromStoredImage(this.inner().storageProfile())) { return false; } if (isOSDiskAttachedUnmanaged(this.inner().storageProfile().osDisk())) { return false; } if (isOSDiskFromPlatformImage(this.inner().storageProfile())) { if (this.isUnmanagedDiskSelected) { return false; } } if (isInCreateMode()) { return true; } else { return this.inner().storageProfile().osDisk().vhd() == null; } } @Override public String computerName() { if (inner().osProfile() == null) { // VM created by attaching a specialized OS Disk VHD will not have the osProfile. return null; } return inner().osProfile().computerName(); } @Override public VirtualMachineSizeTypes size() { return inner().hardwareProfile().vmSize(); } @Override public OperatingSystemTypes osType() { return inner().storageProfile().osDisk().osType(); } @Override public String osUnmanagedDiskVhdUri() { if (isManagedDiskEnabled()) { return null; } return inner().storageProfile().osDisk().vhd().uri(); } @Override public CachingTypes osDiskCachingType() { return inner().storageProfile().osDisk().caching(); } @Override public int osDiskSize() { return Utils.toPrimitiveInt(inner().storageProfile().osDisk().diskSizeGB()); } @Override public StorageAccountTypes osDiskStorageAccountType() { if (!isManagedDiskEnabled() || this.storageProfile().osDisk().managedDisk() == null) { return null; } return this.storageProfile().osDisk().managedDisk().storageAccountType(); } @Override public String osDiskId() { if (!isManagedDiskEnabled()) { return null; } return this.storageProfile().osDisk().managedDisk().id(); } @Override public Map<Integer, VirtualMachineUnmanagedDataDisk> unmanagedDataDisks() { Map<Integer, VirtualMachineUnmanagedDataDisk> dataDisks = new HashMap<>(); if (!isManagedDiskEnabled()) { for (VirtualMachineUnmanagedDataDisk dataDisk : this.unmanagedDataDisks) { dataDisks.put(dataDisk.lun(), dataDisk); } } return Collections.unmodifiableMap(dataDisks); } @Override public Map<Integer, VirtualMachineDataDisk> dataDisks() { Map<Integer, VirtualMachineDataDisk> dataDisks = new HashMap<>(); if (isManagedDiskEnabled()) { List<DataDisk> innerDataDisks = this.inner().storageProfile().dataDisks(); if (innerDataDisks != null) { for (DataDisk innerDataDisk : innerDataDisks) { dataDisks.put(innerDataDisk.lun(), new VirtualMachineDataDiskImpl(innerDataDisk)); } } } return Collections.unmodifiableMap(dataDisks); } @Override public NetworkInterface getPrimaryNetworkInterface() { return this.networkManager.networkInterfaces().getById(primaryNetworkInterfaceId()); } @Override public PublicIPAddress getPrimaryPublicIPAddress() { return this.getPrimaryNetworkInterface().primaryIPConfiguration().getPublicIPAddress(); } @Override public String getPrimaryPublicIPAddressId() { return this.getPrimaryNetworkInterface().primaryIPConfiguration().publicIPAddressId(); } @Override public List<String> networkInterfaceIds() { List<String> nicIds = new ArrayList<>(); for (NetworkInterfaceReferenceInner nicRef : inner().networkProfile().networkInterfaces()) { nicIds.add(nicRef.id()); } return nicIds; } @Override public String primaryNetworkInterfaceId() { final List<NetworkInterfaceReferenceInner> nicRefs = this.inner().networkProfile().networkInterfaces(); String primaryNicRefId = null; if (nicRefs.size() == 1) { // One NIC so assume it to be primary primaryNicRefId = nicRefs.get(0).id(); } else if (nicRefs.size() == 0) { // No NICs so null primaryNicRefId = null; } else { // Find primary interface as flagged by Azure for (NetworkInterfaceReferenceInner nicRef : inner().networkProfile().networkInterfaces()) { if (nicRef.primary() != null && nicRef.primary()) { primaryNicRefId = nicRef.id(); break; } } // If Azure didn't flag any NIC as primary then assume the first one if (primaryNicRefId == null) { primaryNicRefId = nicRefs.get(0).id(); } } return primaryNicRefId; } @Override public String availabilitySetId() { if (inner().availabilitySet() != null) { return inner().availabilitySet().id(); } return null; } @Override public String provisioningState() { return inner().provisioningState(); } @Override public String licenseType() { return inner().licenseType(); } @Override public Observable<VirtualMachineExtension> listExtensionsAsync() { return this.virtualMachineExtensions.listAsync(); } @Override public Map<String, VirtualMachineExtension> listExtensions() { return this.virtualMachineExtensions.asMap(); } @Override public Plan plan() { return inner().plan(); } @Override public StorageProfile storageProfile() { return inner().storageProfile(); } @Override public OSProfile osProfile() { return inner().osProfile(); } @Override public DiagnosticsProfile diagnosticsProfile() { return inner().diagnosticsProfile(); } @Override public String vmId() { return inner().vmId(); } @Override public VirtualMachineInstanceView instanceView() { if (this.virtualMachineInstanceView == null) { this.refreshInstanceView(); } return this.virtualMachineInstanceView; } @Override public PowerState powerState() { return PowerState.fromInstanceView(this.instanceView()); } // CreateUpdateTaskGroup.ResourceCreator.createResourceAsync implementation // @Override public Observable<VirtualMachine> createResourceAsync() { if (isInCreateMode()) { setOSDiskDefaults(); setOSProfileDefaults(); setHardwareProfileDefaults(); } if (isManagedDiskEnabled()) { managedDataDisks.setDataDisksDefaults(); } else { UnmanagedDataDiskImpl.setDataDisksDefaults(this.unmanagedDataDisks, this.vmName); } final VirtualMachineImpl self = this; final VirtualMachinesInner client = this.manager().inner().virtualMachines(); return handleStorageSettingsAsync() .flatMap(new Func1<StorageAccount, Observable<? extends VirtualMachine>>() { @Override public Observable<? extends VirtualMachine> call(StorageAccount storageAccount) { handleNetworkSettings(); handleAvailabilitySettings(); return client.createOrUpdateAsync(resourceGroupName(), vmName, inner()) .map(new Func1<VirtualMachineInner, VirtualMachine>() { @Override public VirtualMachine call(VirtualMachineInner virtualMachineInner) { self.setInner(virtualMachineInner); clearCachedRelatedResources(); initializeDataDisks(); return self; } }); } }).flatMap(new Func1<VirtualMachine, Observable<? extends VirtualMachine>>() { @Override public Observable<? extends VirtualMachine> call(VirtualMachine virtualMachine) { return self.virtualMachineExtensions.commitAndGetAllAsync() .map(new Func1<List<VirtualMachineExtensionImpl>, VirtualMachine>() { @Override public VirtualMachine call(List<VirtualMachineExtensionImpl> virtualMachineExtensions) { return self; } }); } }); } // Helpers VirtualMachineImpl withExtension(VirtualMachineExtensionImpl extension) { this.virtualMachineExtensions.addExtension(extension); return this; } VirtualMachineImpl withUnmanagedDataDisk(UnmanagedDataDiskImpl dataDisk) { this.inner() .storageProfile() .dataDisks() .add(dataDisk.inner()); this.unmanagedDataDisks .add(dataDisk); return this; } private void setOSDiskDefaults() { if (isInUpdateMode()) { return; } StorageProfile storageProfile = this.inner().storageProfile(); OSDisk osDisk = storageProfile.osDisk(); if (isOSDiskFromImage(osDisk)) { // ODDisk CreateOption: FROM_IMAGE // if (isManagedDiskEnabled()) { // Note: // Managed disk // Supported: PlatformImage and CustomImage // UnSupported: StoredImage // if (osDisk.managedDisk() == null) { osDisk.withManagedDisk(new ManagedDiskParametersInner()); } if (osDisk.managedDisk().storageAccountType() == null) { osDisk.managedDisk() .withStorageAccountType(StorageAccountTypes.STANDARD_LRS); } osDisk.withVhd(null); // We won't set osDisk.name() explicitly for managed disk, if it is null CRP generates unique // name for the disk resource within the resource group. } else { // Note: // Native (un-managed) disk // Supported: PlatformImage and StoredImage // UnSupported: CustomImage // if (isOSDiskFromPlatformImage(storageProfile) || isOSDiskFromStoredImage(storageProfile)) { if (osDisk.vhd() == null) { String osDiskVhdContainerName = "vhds"; String osDiskVhdName = this.vmName + "-os-disk-" + UUID.randomUUID().toString() + ".vhd"; withOSDiskVhdLocation(osDiskVhdContainerName, osDiskVhdName); } osDisk.withManagedDisk(null); } if (osDisk.name() == null) { withOSDiskName(this.vmName + "-os-disk"); } } } else { // ODDisk CreateOption: ATTACH // if (isManagedDiskEnabled()) { // In case of attach, it is not allowed to change the storage account type of the // managed disk. // if (osDisk.managedDisk() != null) { osDisk.managedDisk().withStorageAccountType(null); } osDisk.withVhd(null); } else { osDisk.withManagedDisk(null); if (osDisk.name() == null) { withOSDiskName(this.vmName + "-os-disk"); } } } if (osDisk.caching() == null) { withOSDiskCaching(CachingTypes.READ_WRITE); } } private void setOSProfileDefaults() { if (isInUpdateMode()) { return; } StorageProfile storageProfile = this.inner().storageProfile(); OSDisk osDisk = storageProfile.osDisk(); if (isOSDiskFromImage(osDisk)) { // ODDisk CreateOption: FROM_IMAGE // if (osDisk.osType() == OperatingSystemTypes.LINUX || this.isMarketplaceLinuxImage) { // linux image: PlatformImage | CustomImage | StoredImage // OSProfile osProfile = this.inner().osProfile(); if (osProfile.linuxConfiguration() == null) { osProfile.withLinuxConfiguration(new LinuxConfiguration()); } this.inner().osProfile() .linuxConfiguration() .withDisablePasswordAuthentication(osProfile.adminPassword() == null); } if (this.inner().osProfile().computerName() == null) { // VM name cannot contain only numeric values and cannot exceed 15 chars // if (vmName.matches("[0-9]+")) { this.inner().osProfile() .withComputerName(SdkContext.randomResourceName("vm", 15)); } else if (vmName.length() <= 15) { this.inner().osProfile() .withComputerName(vmName); } else { this.inner().osProfile() .withComputerName(SdkContext.randomResourceName("vm", 15)); } } } else { // ODDisk CreateOption: ATTACH // // OS Profile must be set to null when an VM's OS disk is ATTACH-ed to a managed disk or // Specialized VHD // this.inner().withOsProfile(null); } } private void setHardwareProfileDefaults() { if (!isInCreateMode()) { return; } HardwareProfile hardwareProfile = this.inner().hardwareProfile(); if (hardwareProfile.vmSize() == null) { hardwareProfile.withVmSize(VirtualMachineSizeTypes.BASIC_A0); } } private Observable<StorageAccount> handleStorageSettingsAsync() { final Func1<StorageAccount, StorageAccount> onStorageAccountReady = new Func1<StorageAccount, StorageAccount>() { @Override public StorageAccount call(StorageAccount storageAccount) { if (!isManagedDiskEnabled()) { if (isInCreateMode()) { if (isOSDiskFromPlatformImage(inner().storageProfile())) { String uri = inner() .storageProfile() .osDisk().vhd().uri() .replaceFirst("\\{storage-base-url}", storageAccount.endPoints().primary().blob()); inner().storageProfile().osDisk().vhd().withUri(uri); } UnmanagedDataDiskImpl.ensureDisksVhdUri(unmanagedDataDisks, storageAccount, vmName); } else { if (storageAccount != null) { UnmanagedDataDiskImpl.ensureDisksVhdUri(unmanagedDataDisks, storageAccount, vmName); } else { UnmanagedDataDiskImpl.ensureDisksVhdUri(unmanagedDataDisks, vmName); } } } return storageAccount; } }; if (this.creatableStorageAccountKey != null) { return Observable.just((StorageAccount) this.createdResource(this.creatableStorageAccountKey)) .map(onStorageAccountReady); } else if (this.existingStorageAccountToAssociate != null) { return Observable.just(this.existingStorageAccountToAssociate) .map(onStorageAccountReady); } else if (osDiskRequiresImplicitStorageAccountCreation() || dataDisksRequiresImplicitStorageAccountCreation()) { return Utils.<StorageAccount>rootResource(this.storageManager.storageAccounts() .define(this.namer.randomName("stg", 24).replace("-", "")) .withRegion(this.regionName()) .withExistingResourceGroup(this.resourceGroupName()) .createAsync()) .map(onStorageAccountReady); } return Observable.just(null); } private void handleNetworkSettings() { if (isInCreateMode()) { NetworkInterface primaryNetworkInterface = null; if (this.creatablePrimaryNetworkInterfaceKey != null) { primaryNetworkInterface = (NetworkInterface) this.createdResource(this.creatablePrimaryNetworkInterfaceKey); } else if (this.existingPrimaryNetworkInterfaceToAssociate != null) { primaryNetworkInterface = this.existingPrimaryNetworkInterfaceToAssociate; } if (primaryNetworkInterface != null) { NetworkInterfaceReferenceInner nicReference = new NetworkInterfaceReferenceInner(); nicReference.withPrimary(true); nicReference.withId(primaryNetworkInterface.id()); this.inner().networkProfile().networkInterfaces().add(nicReference); } } // sets the virtual machine secondary network interfaces // for (String creatableSecondaryNetworkInterfaceKey : this.creatableSecondaryNetworkInterfaceKeys) { NetworkInterface secondaryNetworkInterface = (NetworkInterface) this.createdResource(creatableSecondaryNetworkInterfaceKey); NetworkInterfaceReferenceInner nicReference = new NetworkInterfaceReferenceInner(); nicReference.withPrimary(false); nicReference.withId(secondaryNetworkInterface.id()); this.inner().networkProfile().networkInterfaces().add(nicReference); } for (NetworkInterface secondaryNetworkInterface : this.existingSecondaryNetworkInterfacesToAssociate) { NetworkInterfaceReferenceInner nicReference = new NetworkInterfaceReferenceInner(); nicReference.withPrimary(false); nicReference.withId(secondaryNetworkInterface.id()); this.inner().networkProfile().networkInterfaces().add(nicReference); } } private void handleAvailabilitySettings() { if (!isInCreateMode()) { return; } AvailabilitySet availabilitySet = null; if (this.creatableAvailabilitySetKey != null) { availabilitySet = (AvailabilitySet) this.createdResource(this.creatableAvailabilitySetKey); } else if (this.existingAvailabilitySetToAssociate != null) { availabilitySet = this.existingAvailabilitySetToAssociate; } if (availabilitySet != null) { if (this.inner().availabilitySet() == null) { this.inner().withAvailabilitySet(new SubResource()); } this.inner().availabilitySet().withId(availabilitySet.id()); } } private boolean osDiskRequiresImplicitStorageAccountCreation() { if (isManagedDiskEnabled()) { return false; } if (this.creatableStorageAccountKey != null || this.existingStorageAccountToAssociate != null || !isInCreateMode()) { return false; } return isOSDiskFromPlatformImage(this.inner().storageProfile()); } private boolean dataDisksRequiresImplicitStorageAccountCreation() { if (isManagedDiskEnabled()) { return false; } if (this.creatableStorageAccountKey != null || this.existingStorageAccountToAssociate != null || this.unmanagedDataDisks.size() == 0) { return false; } boolean hasEmptyVhd = false; for (VirtualMachineUnmanagedDataDisk dataDisk : this.unmanagedDataDisks) { if (dataDisk.creationMethod() == DiskCreateOptionTypes.EMPTY || dataDisk.creationMethod() == DiskCreateOptionTypes.FROM_IMAGE) { if (dataDisk.inner().vhd() == null) { hasEmptyVhd = true; break; } } } if (isInCreateMode()) { return hasEmptyVhd; } if (hasEmptyVhd) { // In update mode, if any of the data disk has vhd uri set then use same container // to store this disk, no need to create a storage account implicitly. for (VirtualMachineUnmanagedDataDisk dataDisk : this.unmanagedDataDisks) { if (dataDisk.creationMethod() == DiskCreateOptionTypes.ATTACH && dataDisk.inner().vhd() != null) { return false; } } return true; } return false; } /** * Checks whether the OS disk is directly attached to a unmanaged VHD. * * @param osDisk the osDisk value in the storage profile * @return true if the OS disk is attached to a unmanaged VHD, false otherwise */ private boolean isOSDiskAttachedUnmanaged(OSDisk osDisk) { return osDisk.createOption() == DiskCreateOptionTypes.ATTACH && osDisk.vhd() != null && osDisk.vhd().uri() != null; } /** * Checks whether the OS disk is directly attached to a managed disk. * * @param osDisk the osDisk value in the storage profile * @return true if the OS disk is attached to a managed disk, false otherwise */ private boolean isOSDiskAttachedManaged(OSDisk osDisk) { return osDisk.createOption() == DiskCreateOptionTypes.ATTACH && osDisk.managedDisk() != null && osDisk.managedDisk().id() != null; } /** * Checks whether the OS disk is based on an image (image from PIR or custom image [captured, bringYourOwnFeature]). * * @param osDisk the osDisk value in the storage profile * @return true if the OS disk is configured to use image from PIR or custom image */ private boolean isOSDiskFromImage(OSDisk osDisk) { return osDisk.createOption() == DiskCreateOptionTypes.FROM_IMAGE; } /** * Checks whether the OS disk is based on an platform image (image in PIR). * * @param storageProfile the storage profile * @return true if the OS disk is configured to be based on platform image. */ private boolean isOSDiskFromPlatformImage(StorageProfile storageProfile) { ImageReferenceInner imageReference = storageProfile.imageReference(); return isOSDiskFromImage(storageProfile.osDisk()) && imageReference != null && imageReference.publisher() != null && imageReference.offer() != null && imageReference.sku() != null && imageReference.version() != null; } /** * Checks whether the OS disk is based on a CustomImage. * <p> * A custom image is represented by {@link com.microsoft.azure.management.compute.VirtualMachineCustomImage}. * * @param storageProfile the storage profile * @return true if the OS disk is configured to be based on custom image. */ private boolean isOsDiskFromCustomImage(StorageProfile storageProfile) { ImageReferenceInner imageReference = storageProfile.imageReference(); return isOSDiskFromImage(storageProfile.osDisk()) && imageReference != null && imageReference.id() != null; } /** * Checks whether the OS disk is based on a stored image ('captured' or 'bring your own feature'). * <p> * A stored image is created by calling {@link VirtualMachine#capture(String, String, boolean)}. * * @param storageProfile the storage profile * @return true if the OS disk is configured to use custom image ('captured' or 'bring your own feature') */ private boolean isOSDiskFromStoredImage(StorageProfile storageProfile) { OSDisk osDisk = storageProfile.osDisk(); return isOSDiskFromImage(osDisk) && osDisk.image() != null && osDisk.image().uri() != null; } private String temporaryBlobUrl(String containerName, String blobName) { return "{storage-base-url}" + containerName + "/" + blobName; } private NetworkInterface.DefinitionStages.WithPrimaryPublicIPAddress prepareNetworkInterface(String name) { NetworkInterface.DefinitionStages.WithGroup definitionWithGroup = this.networkManager .networkInterfaces() .define(name) .withRegion(this.regionName()); NetworkInterface.DefinitionStages.WithPrimaryNetwork definitionWithNetwork; if (this.creatableGroup != null) { definitionWithNetwork = definitionWithGroup.withNewResourceGroup(this.creatableGroup); } else { definitionWithNetwork = definitionWithGroup.withExistingResourceGroup(this.resourceGroupName()); } return definitionWithNetwork .withNewPrimaryNetwork("vnet" + name) .withPrimaryPrivateIPAddressDynamic(); } private void initializeDataDisks() { if (this.inner().storageProfile().dataDisks() == null) { this.inner() .storageProfile() .withDataDisks(new ArrayList<DataDisk>()); } this.isUnmanagedDiskSelected = false; this.managedDataDisks.clear(); this.unmanagedDataDisks = new ArrayList<>(); if (!isManagedDiskEnabled()) { for (DataDisk dataDiskInner : this.storageProfile().dataDisks()) { this.unmanagedDataDisks.add(new UnmanagedDataDiskImpl(dataDiskInner, this)); } } } private NetworkInterface.DefinitionStages.WithPrimaryNetwork preparePrimaryNetworkInterface(String name) { NetworkInterface.DefinitionStages.WithGroup definitionWithGroup = this.networkManager.networkInterfaces() .define(name) .withRegion(this.regionName()); NetworkInterface.DefinitionStages.WithPrimaryNetwork definitionAfterGroup; if (this.creatableGroup != null) { definitionAfterGroup = definitionWithGroup.withNewResourceGroup(this.creatableGroup); } else { definitionAfterGroup = definitionWithGroup.withExistingResourceGroup(this.resourceGroupName()); } return definitionAfterGroup; } private void clearCachedRelatedResources() { this.virtualMachineInstanceView = null; } private void throwIfManagedDiskEnabled(String message) { if (this.isManagedDiskEnabled()) { throw new UnsupportedOperationException(message); } } private void throwIfManagedDiskDisabled(String message) { if (!this.isManagedDiskEnabled()) { throw new UnsupportedOperationException(message); } } private boolean isInUpdateMode() { return !this.isInCreateMode(); } /** * Class to manage Data disk collection. */ private class ManagedDataDiskCollection { private final Map<String, DataDisk> newDisksToAttach = new HashMap<>(); private final List<DataDisk> existingDisksToAttach = new ArrayList<>(); private final List<DataDisk> implicitDisksToAssociate = new ArrayList<>(); private final List<Integer> diskLunsToRemove = new ArrayList<>(); private final List<DataDisk> newDisksFromImage = new ArrayList<>(); private final VirtualMachineImpl vm; private CachingTypes defaultCachingType; private StorageAccountTypes defaultStorageAccountType; ManagedDataDiskCollection(VirtualMachineImpl vm) { this.vm = vm; } void setDefaultCachingType(CachingTypes cachingType) { this.defaultCachingType = cachingType; } void setDefaultStorageAccountType(StorageAccountTypes defaultStorageAccountType) { this.defaultStorageAccountType = defaultStorageAccountType; } void setDataDisksDefaults() { VirtualMachineInner vmInner = this.vm.inner(); if (isPending()) { if (vmInner.storageProfile().dataDisks() == null) { vmInner.storageProfile().withDataDisks(new ArrayList<DataDisk>()); } List<DataDisk> dataDisks = vmInner.storageProfile().dataDisks(); final List<Integer> usedLuns = new ArrayList<>(); // Get all used luns // for (DataDisk dataDisk : dataDisks) { if (dataDisk.lun() != -1) { usedLuns.add(dataDisk.lun()); } } for (DataDisk dataDisk : this.newDisksToAttach.values()) { if (dataDisk.lun() != -1) { usedLuns.add(dataDisk.lun()); } } for (DataDisk dataDisk : this.existingDisksToAttach) { if (dataDisk.lun() != -1) { usedLuns.add(dataDisk.lun()); } } for (DataDisk dataDisk : this.implicitDisksToAssociate) { if (dataDisk.lun() != -1) { usedLuns.add(dataDisk.lun()); } } for (DataDisk dataDisk : this.newDisksFromImage) { if (dataDisk.lun() != -1) { usedLuns.add(dataDisk.lun()); } } // Func to get the next available lun // Func0<Integer> nextLun = new Func0<Integer>() { @Override public Integer call() { Integer lun = 0; while (usedLuns.contains(lun)) { lun++; } usedLuns.add(lun); return lun; } }; setAttachableNewDataDisks(nextLun); setAttachableExistingDataDisks(nextLun); setImplicitDataDisks(nextLun); setImageBasedDataDisks(); removeDataDisks(); } if (vmInner.storageProfile().dataDisks() != null && vmInner.storageProfile().dataDisks().size() == 0) { if (vm.isInCreateMode()) { // If there is no data disks at all, then setting it to null rather than [] is necessary. // This is for take advantage of CRP's implicit creation of the data disks if the image has // more than one data disk image(s). // vmInner.storageProfile().withDataDisks(null); } } this.clear(); } private void clear() { newDisksToAttach.clear(); existingDisksToAttach.clear(); implicitDisksToAssociate.clear(); diskLunsToRemove.clear(); newDisksFromImage.clear(); } private boolean isPending() { return newDisksToAttach.size() > 0 || existingDisksToAttach.size() > 0 || implicitDisksToAssociate.size() > 0 || diskLunsToRemove.size() > 0 || newDisksFromImage.size() > 0; } private void setAttachableNewDataDisks(Func0<Integer> nextLun) { List<DataDisk> dataDisks = vm.inner().storageProfile().dataDisks(); for (Map.Entry<String, DataDisk> entry : this.newDisksToAttach.entrySet()) { Disk managedDisk = (Disk) vm.createdResource(entry.getKey()); DataDisk dataDisk = entry.getValue(); dataDisk.withCreateOption(DiskCreateOptionTypes.ATTACH); if (dataDisk.lun() == -1) { dataDisk.withLun(nextLun.call()); } dataDisk.withManagedDisk(new ManagedDiskParametersInner()); dataDisk.managedDisk().withId(managedDisk.id()); if (dataDisk.caching() == null) { dataDisk.withCaching(getDefaultCachingType()); } // Don't set default storage account type for the attachable managed disks, it is already // defined in the managed disk and not allowed to change. dataDisk.withName(null); dataDisks.add(dataDisk); } } private void setAttachableExistingDataDisks(Func0<Integer> nextLun) { List<DataDisk> dataDisks = vm.inner().storageProfile().dataDisks(); for (DataDisk dataDisk : this.existingDisksToAttach) { dataDisk.withCreateOption(DiskCreateOptionTypes.ATTACH); if (dataDisk.lun() == -1) { dataDisk.withLun(nextLun.call()); } if (dataDisk.caching() == null) { dataDisk.withCaching(getDefaultCachingType()); } // Don't set default storage account type for the attachable managed disks, it is already // defined in the managed disk and not allowed to change. dataDisk.withName(null); dataDisks.add(dataDisk); } } private void setImplicitDataDisks(Func0<Integer> nextLun) { List<DataDisk> dataDisks = vm.inner().storageProfile().dataDisks(); for (DataDisk dataDisk : this.implicitDisksToAssociate) { dataDisk.withCreateOption(DiskCreateOptionTypes.EMPTY); if (dataDisk.lun() == -1) { dataDisk.withLun(nextLun.call()); } if (dataDisk.caching() == null) { dataDisk.withCaching(getDefaultCachingType()); } if (dataDisk.managedDisk() == null) { dataDisk.withManagedDisk(new ManagedDiskParametersInner()); } if (dataDisk.managedDisk().storageAccountType() == null) { dataDisk.managedDisk().withStorageAccountType(getDefaultStorageAccountType()); } dataDisk.withName(null); dataDisks.add(dataDisk); } } private void setImageBasedDataDisks() { List<DataDisk> dataDisks = vm.inner().storageProfile().dataDisks(); for (DataDisk dataDisk : this.newDisksFromImage) { dataDisk.withCreateOption(DiskCreateOptionTypes.FROM_IMAGE); // Don't set default storage account type for the disk, either user has to specify it explicitly or let // CRP pick it from the image dataDisk.withName(null); dataDisks.add(dataDisk); } } private void removeDataDisks() { List<DataDisk> dataDisks = vm.inner().storageProfile().dataDisks(); for (Integer lun : this.diskLunsToRemove) { int indexToRemove = 0; for (DataDisk dataDisk : dataDisks) { if (dataDisk.lun() == lun) { dataDisks.remove(indexToRemove); break; } indexToRemove++; } } } private CachingTypes getDefaultCachingType() { if (defaultCachingType == null) { return CachingTypes.READ_WRITE; } return defaultCachingType; } private StorageAccountTypes getDefaultStorageAccountType() { if (defaultStorageAccountType == null) { return StorageAccountTypes.STANDARD_LRS; } return defaultStorageAccountType; } } }