From 07fec47a8661a2ae4d939f4bf2efb806116333e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Serta=C3=A7=20=C3=96zercan?= Date: Tue, 29 Aug 2017 14:24:45 -0700 Subject: [PATCH] Azure Virtual Machine data disks and managed OS disk support (#28132) * added managed os disk support for vms * added managed_disk_type to documentation * added data disk (storage account and managed disk) support * deleting data disk blob when absent * update differences * update docs * fix test failures * fix test failure * multiple data disk support * fix test failures * fix test failures * fix for multiple vm data disk name conflict * changed data disks naming syntax * fix data disk caching --- .../cloud/azure/azure_rm_virtualmachine.py | 280 ++++++++++++++++-- 1 file changed, 262 insertions(+), 18 deletions(-) diff --git a/lib/ansible/modules/cloud/azure/azure_rm_virtualmachine.py b/lib/ansible/modules/cloud/azure/azure_rm_virtualmachine.py index 5bd2f9aad2a..d9fd315bf62 100644 --- a/lib/ansible/modules/cloud/azure/azure_rm_virtualmachine.py +++ b/lib/ansible/modules/cloud/azure/azure_rm_virtualmachine.py @@ -112,6 +112,13 @@ options: the VM name + '.vhd'. If you provide a name, it must end with '.vhd' aliases: - storage_blob + managed_disk_type: + description: + - Managed OS disk type + choices: + - Standard_LRS + - Premium_LRS + version_added: "2.4" os_disk_caching: description: - Type of OS disk caching. @@ -129,6 +136,53 @@ options: - Linux default: - Linux + data_disks: + description: + - Describes list of data disks. + required: false + default: null + version_added: "2.4" + suboptions: + lun: + description: + - The logical unit number for data disk + default: 0 + version_added: "2.4" + disk_size_gb: + description: + - The initial disk size in GB for blank data disks + version_added: "2.4" + managed_disk_type: + description: + - Managed data disk type + choices: + - Standard_LRS + - Premium_LRS + version_added: "2.4" + storage_account_name: + description: + - Name of an existing storage account that supports creation of VHD blobs. If not specified for a new VM, + a new storage account named 01 will be created using storage type 'Standard_LRS'. + version_added: "2.4" + storage_container_name: + description: + - Name of the container to use within the storage account to store VHD blobs. If no name is specified a + default container will created. + default: vhds + version_added: "2.4" + storage_blob_name: + description: + - Name fo the storage blob used to hold the VM's OS disk image. If no name is provided, defaults to + the VM name + '.vhd'. If you provide a name, it must end with '.vhd' + version_added: "2.4" + caching: + description: + - Type of data disk caching. + choices: + - ReadOnly + - ReadWrite + default: ReadOnly + version_added: "2.4" public_ip_allocation_method: description: - If a public IP address is created when creating the VM (because a Network Interface was not provided), @@ -201,7 +255,23 @@ EXAMPLES = ''' sku: '7.1' version: latest -- name: Create a VM with exiting storage account and NIC +- name: Create a VM with managed disk + azure_rm_virtualmachine: + resource_group: Testing + name: testvm001 + vm_size: Standard_D4 + managed_disk_type: Standard_LRS + admin_username: adminUser + ssh_public_keys: + - path: /home/adminUser/.ssh/authorized_keys + key_data: < insert yor ssh public key here... > + image: + offer: CoreOS + publisher: CoreOS + sku: Stable + version: latest + +- name: Create a VM with existing storage account and NIC azure_rm_virtualmachine: resource_group: Testing name: testvm002 @@ -218,6 +288,57 @@ EXAMPLES = ''' sku: '7.1' version: latest +- name: Create a VM with OS and multiple data managed disks + azure_rm_virtualmachine: + resource_group: Testing + name: testvm001 + vm_size: Standard_D4 + managed_disk_type: Standard_LRS + admin_username: adminUser + ssh_public_keys: + - path: /home/adminUser/.ssh/authorized_keys + key_data: < insert yor ssh public key here... > + image: + offer: CoreOS + publisher: CoreOS + sku: Stable + version: latest + data_disks: + - lun: 0 + disk_size_gb: 64 + managed_disk_type: Standard_LRS + - lun: 1 + disk_size_gb: 128 + managed_disk_type: Premium_LRS + +- name: Create a VM with OS and multiple data storage accounts + azure_rm_virtualmachine: + resource_group: Testing + name: testvm001 + vm_size: Standard_DS1_v2 + admin_username: adminUser + ssh_password_enabled: false + ssh_public_keys: + - path: /home/adminUser/.ssh/authorized_keys + key_data: < insert yor ssh public key here... > + network_interfaces: testvm001 + storage_container: osdisk + storage_blob: osdisk.vhd + image: + offer: CoreOS + publisher: CoreOS + sku: Stable + version: latest + data_disks: + - lun: 0 + disk_size_gb: 64 + storage_container_name: datadisk1 + storage_blob_name: datadisk1.vhd + - lun: 1 + disk_size_gb: 128 + storage_container_name: datadisk2 + storage_blob_name: datadisk2.vhd + - name: Power Off azure_rm_virtualmachine: resource_group: Testing @@ -380,7 +501,18 @@ azure_vm: }, "provisioningState": "Succeeded", "storageProfile": { - "dataDisks": [], + "dataDisks": [ + { + "caching": "ReadWrite", + "createOption": "empty", + "diskSizeGB": 64, + "lun": 0, + "name": "datadisk1.vhd", + "vhd": { + "uri": "https://testvm10sa1.blob.core.windows.net/datadisk/datadisk1.vhd" + } + } + ], "imageReference": { "offer": "CentOS", "publisher": "OpenLogic", @@ -409,15 +541,15 @@ try: from msrestazure.azure_exceptions import CloudError from azure.mgmt.compute.models import NetworkInterfaceReference, \ VirtualMachine, HardwareProfile, \ - StorageProfile, OSProfile, OSDisk, \ - VirtualHardDisk, ImageReference,\ - NetworkProfile, LinuxConfiguration, \ - SshConfiguration, SshPublicKey + StorageProfile, OSProfile, OSDisk, DataDisk, \ + VirtualHardDisk, ManagedDiskParameters, \ + ImageReference, NetworkProfile, LinuxConfiguration, \ + SshConfiguration, SshPublicKey, VirtualMachineSizeTypes, \ + DiskCreateOptionTypes from azure.mgmt.network.models import PublicIPAddress, NetworkSecurityGroup, NetworkInterface, \ NetworkInterfaceIPConfiguration, Subnet from azure.mgmt.storage.models import StorageAccountCreateParameters, Sku from azure.mgmt.storage.models import Kind, SkuTier, SkuName - from azure.mgmt.compute.models import VirtualMachineSizeTypes, DiskCreateOptionTypes except ImportError: # This is handled in azure_rm_common pass @@ -461,6 +593,7 @@ class AzureRMVirtualMachine(AzureRMModuleBase): storage_blob_name=dict(type='str', aliases=['storage_blob']), os_disk_caching=dict(type='str', aliases=['disk_caching'], choices=['ReadOnly', 'ReadWrite'], default='ReadOnly'), + managed_disk_type=dict(type='str', choices=['Standard_LRS', 'Premium_LRS']), os_type=dict(type='str', choices=['Linux', 'Windows'], default='Linux'), public_ip_allocation_method=dict(type='str', choices=['Dynamic', 'Static'], default='Static', aliases=['public_ip_allocation']), @@ -473,6 +606,7 @@ class AzureRMVirtualMachine(AzureRMModuleBase): allocated=dict(type='bool', default=True), restarted=dict(type='bool', default=False), started=dict(type='bool', default=True), + data_disks=dict(type='list'), ) self.resource_group = None @@ -491,6 +625,7 @@ class AzureRMVirtualMachine(AzureRMModuleBase): self.storage_blob_name = None self.os_type = None self.os_disk_caching = None + self.managed_disk_type = None self.network_interface_names = None self.remove_on_absent = set() self.tags = None @@ -504,6 +639,7 @@ class AzureRMVirtualMachine(AzureRMModuleBase): self.restarted = None self.started = None self.differences = None + self.data_disks = None self.results = dict( changed=False, @@ -529,6 +665,7 @@ class AzureRMVirtualMachine(AzureRMModuleBase): vm = None network_interfaces = [] requested_vhd_uri = None + data_disk_requested_vhd_uri = None disable_ssh_password = None vm_dict = None @@ -568,10 +705,12 @@ class AzureRMVirtualMachine(AzureRMModuleBase): self.image['version'] = image_version.name self.log("Using image version {0}".format(self.image['version'])) - if not self.storage_blob_name: + if not self.storage_blob_name and not self.managed_disk_type: self.storage_blob_name = self.name + '.vhd' + elif self.managed_disk_type: + self.storage_blob_name = self.name - if self.storage_account_name: + if self.storage_account_name and not self.managed_disk_type: self.get_storage_account(self.storage_account_name) requested_vhd_uri = 'https://{0}.blob.{1}/{2}/{3}'.format(self.storage_account_name, @@ -686,7 +825,8 @@ class AzureRMVirtualMachine(AzureRMModuleBase): self.log(self.serialize_obj(default_nic, 'NetworkInterface'), pretty_print=True) network_interfaces = [default_nic.id] - if not self.storage_account_name: + # os disk + if not self.storage_account_name and not self.managed_disk_type: storage_account = self.create_default_storage_account() self.log("storage account:") self.log(self.serialize_obj(storage_account, 'StorageAccount'), pretty_print=True) @@ -700,7 +840,15 @@ class AzureRMVirtualMachine(AzureRMModuleBase): self.short_hostname = self.name nics = [NetworkInterfaceReference(id=id) for id in network_interfaces] - vhd = VirtualHardDisk(uri=requested_vhd_uri) + + # os disk + if not self.managed_disk_type: + managed_disk = None + vhd = VirtualHardDisk(uri=requested_vhd_uri) + else: + vhd = None + managed_disk = ManagedDiskParameters(storage_account_type=self.managed_disk_type) + vm_resource = VirtualMachine( self.location, tags=self.tags, @@ -715,6 +863,7 @@ class AzureRMVirtualMachine(AzureRMModuleBase): os_disk=OSDisk( name=self.storage_blob_name, vhd=vhd, + managed_disk=managed_disk, create_option=DiskCreateOptionTypes.from_image, caching=self.os_disk_caching, ), @@ -743,6 +892,60 @@ class AzureRMVirtualMachine(AzureRMModuleBase): [SshPublicKey(path=key['path'], key_data=key['key_data']) for key in self.ssh_public_keys] vm_resource.os_profile.linux_configuration.ssh = ssh_config + # data disk + if self.data_disks: + data_disks = [] + count = 0 + + for data_disk in self.data_disks: + if not data_disk.get('managed_disk_type'): + if not data_disk.get('storage_blob_name'): + data_disk['storage_blob_name'] = self.name + '-data-' + str(count) + '.vhd' + count += 1 + + if data_disk.get('storage_account_name'): + self.get_storage_account(data_disk['storage_account_name']) + data_disk_storage_account.name = data_disk['storage_account_name'] + else: + data_disk_storage_account = self.create_default_storage_account() + self.log("data disk storage account:") + self.log(self.serialize_obj(data_disk_storage_account, 'StorageAccount'), pretty_print=True) + + if not data_disk.get('storage_container_name'): + data_disk['storage_container_name'] = 'vhds' + + data_disk_requested_vhd_uri = 'https://{0}.blob.core.windows.net/{1}/{2}'.format( + data_disk_storage_account.name, + data_disk['storage_container_name'], + data_disk['storage_blob_name'] + ) + + if not data_disk.get('managed_disk_type'): + data_disk_managed_disk = None + disk_name = data_disk['storage_blob_name'] + data_disk_vhd = VirtualHardDisk(uri=data_disk_requested_vhd_uri) + else: + data_disk_vhd = None + data_disk_managed_disk = ManagedDiskParameters(storage_account_type=data_disk['managed_disk_type']) + disk_name = self.name + "-datadisk-" + str(count) + count += 1 + + data_disk['caching'] = data_disk.get( + 'caching', 'ReadOnly' + ) + + data_disks.append(DataDisk( + lun=data_disk['lun'], + name=disk_name, + vhd=data_disk_vhd, + caching=data_disk['caching'], + create_option=DiskCreateOptionTypes.empty, + disk_size_gb=data_disk['disk_size_gb'], + managed_disk=data_disk_managed_disk, + )) + + vm_resource.storage_profile.data_disks = data_disks + self.log("Create virtual machine with parameters:") self.create_or_update_vm(vm_resource) @@ -754,7 +957,17 @@ class AzureRMVirtualMachine(AzureRMModuleBase): nics = [NetworkInterfaceReference(id=interface['id']) for interface in vm_dict['properties']['networkProfile']['networkInterfaces']] - vhd = VirtualHardDisk(uri=vm_dict['properties']['storageProfile']['osDisk']['vhd']['uri']) + + # os disk + if not vm_dict['properties']['storageProfile']['osDisk'].get('managedDisk'): + managed_disk = None + vhd = VirtualHardDisk(uri=vm_dict['properties']['storageProfile']['osDisk']['vhd']['uri']) + else: + vhd = None + managed_disk = ManagedDiskParameters( + storage_account_type=vm_dict['properties']['storageProfile']['osDisk']['managedDisk']['storageAccountType'] + ) + vm_resource = VirtualMachine( vm_dict['location'], os_profile=OSProfile( @@ -766,11 +979,12 @@ class AzureRMVirtualMachine(AzureRMModuleBase): ), storage_profile=StorageProfile( os_disk=OSDisk( - vm_dict['properties']['storageProfile']['osDisk']['name'], - vhd, - vm_dict['properties']['storageProfile']['osDisk']['createOption'], - vm_dict['properties']['storageProfile']['osDisk']['osType'], - caching=vm_dict['properties']['storageProfile']['osDisk']['caching'] + name=vm_dict['properties']['storageProfile']['osDisk']['name'], + vhd=vhd, + managed_disk=managed_disk, + create_option=vm_dict['properties']['storageProfile']['osDisk']['createOption'], + os_type=vm_dict['properties']['storageProfile']['osDisk']['osType'], + caching=vm_dict['properties']['storageProfile']['osDisk']['caching'], ), image_reference=ImageReference( publisher=vm_dict['properties']['storageProfile']['imageReference']['publisher'], @@ -806,6 +1020,31 @@ class AzureRMVirtualMachine(AzureRMModuleBase): vm_resource.os_profile.linux_configuration.ssh.public_keys.append( SshPublicKey(path=key['path'], key_data=key['keyData']) ) + + # data disk + if vm_dict['properties']['storageProfile'].get('dataDisks'): + data_disks = [] + + for data_disk in vm_dict['properties']['storageProfile']['dataDisks']: + if data_disk.get('managedDisk'): + managed_disk_type = data_disk['managedDisk']['storageAccountType'] + data_disk_managed_disk = ManagedDiskParameters(storage_account_type=managed_disk_type) + data_disk_vhd = None + else: + data_disk_vhd = data_disk['vhd']['uri'] + data_disk_managed_disk = None + + data_disks.append(DataDisk( + lun=int(data_disk['lun']), + name=data_disk.get('name'), + vhd=data_disk_vhd, + caching=data_disk.get('caching'), + create_option=data_disk.get('createOption'), + disk_size_gb=int(data_disk['diskSizeGB']), + managed_disk=data_disk_managed_disk, + )) + vm_resource.storage_profile.data_disks = data_disks + self.log("Update virtual machine with parameters:") self.create_or_update_vm(vm_resource) @@ -950,6 +1189,11 @@ class AzureRMVirtualMachine(AzureRMModuleBase): # store the attached vhd info so we can nuke it after the VM is gone self.log('Storing VHD URI for deletion') vhd_uris.append(vm.storage_profile.os_disk.vhd.uri) + + data_disks = vm.storage_profile.data_disks + for data_disk in data_disks: + vhd_uris.append(data_disk.vhd.uri) + self.log("VHD URIs to delete: {0}".format(', '.join(vhd_uris))) self.results['deleted_vhd_uris'] = vhd_uris @@ -1075,7 +1319,7 @@ class AzureRMVirtualMachine(AzureRMModuleBase): name) return account except Exception as exc: - self.fail("Error fetching storage account {0} - {1}".format(self.storage_account_name, str(exc))) + self.fail("Error fetching storage account {0} - {1}".format(name, str(exc))) def create_or_update_vm(self, params): try: