|
|
|
@ -276,9 +276,11 @@ options:
|
|
|
|
|
- subnet
|
|
|
|
|
remove_on_absent:
|
|
|
|
|
description:
|
|
|
|
|
- When removing a VM using state 'absent', also remove associated resources
|
|
|
|
|
- "It can be 'all' or a list with any of the following: ['network_interfaces', 'virtual_storage', 'public_ips']"
|
|
|
|
|
- Any other input will be ignored
|
|
|
|
|
- "When removing a VM using state 'absent', also remove associated resources."
|
|
|
|
|
- "It can be 'all' or 'all_autocreated' or a list with any of the following: ['network_interfaces', 'virtual_storage', 'public_ips']."
|
|
|
|
|
- "To remove all resources referred by VM use 'all'."
|
|
|
|
|
- "To remove all resources that were automatically created while provisioning VM use 'all_autocreated'."
|
|
|
|
|
- Any other input will be ignored.
|
|
|
|
|
default: ['all']
|
|
|
|
|
plan:
|
|
|
|
|
description:
|
|
|
|
@ -497,15 +499,6 @@ EXAMPLES = '''
|
|
|
|
|
name: testvm002
|
|
|
|
|
restarted: yes
|
|
|
|
|
|
|
|
|
|
- name: remove vm and all resources except public ips
|
|
|
|
|
azure_rm_virtualmachine:
|
|
|
|
|
resource_group: Testing
|
|
|
|
|
name: testvm002
|
|
|
|
|
state: absent
|
|
|
|
|
remove_on_absent:
|
|
|
|
|
- network_interfaces
|
|
|
|
|
- virtual_storage
|
|
|
|
|
|
|
|
|
|
- name: Create a VM with an Availability Zone
|
|
|
|
|
azure_rm_virtualmachine:
|
|
|
|
|
resource_group: Testing
|
|
|
|
@ -515,6 +508,13 @@ EXAMPLES = '''
|
|
|
|
|
admin_password: password01
|
|
|
|
|
image: customimage001
|
|
|
|
|
zones: [1]
|
|
|
|
|
|
|
|
|
|
- name: Remove a VM and all resources that were autocreated
|
|
|
|
|
azure_rm_virtualmachine:
|
|
|
|
|
resource_group: Testing
|
|
|
|
|
name: testvm002
|
|
|
|
|
remove_on_absent: all_autocreated
|
|
|
|
|
state: absent
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
RETURN = '''
|
|
|
|
@ -1210,7 +1210,7 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
|
|
|
|
|
"from the marketplace. - {2}").format(self.name, self.plan, str(exc)))
|
|
|
|
|
|
|
|
|
|
self.log("Create virtual machine with parameters:")
|
|
|
|
|
self.create_or_update_vm(vm_resource)
|
|
|
|
|
self.create_or_update_vm(vm_resource, 'all_autocreated' in self.remove_on_absent)
|
|
|
|
|
|
|
|
|
|
elif self.differences and len(self.differences) > 0:
|
|
|
|
|
# Update the VM based on detected config differences
|
|
|
|
@ -1342,7 +1342,7 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
|
|
|
|
|
vm_resource.storage_profile.data_disks = data_disks
|
|
|
|
|
|
|
|
|
|
self.log("Update virtual machine with parameters:")
|
|
|
|
|
self.create_or_update_vm(vm_resource)
|
|
|
|
|
self.create_or_update_vm(vm_resource, False)
|
|
|
|
|
|
|
|
|
|
# Make sure we leave the machine in requested power state
|
|
|
|
|
if (powerstate_change == 'poweron' and
|
|
|
|
@ -1421,7 +1421,6 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
|
|
|
|
|
nic_dict = self.serialize_obj(nic, 'NetworkInterface')
|
|
|
|
|
interface_dict['name'] = int_dict['networkInterfaces']
|
|
|
|
|
interface_dict['properties'] = nic_dict['properties']
|
|
|
|
|
|
|
|
|
|
# Expand public IPs to include config properties
|
|
|
|
|
for interface in result['properties']['networkProfile']['networkInterfaces']:
|
|
|
|
|
for config in interface['properties']['ipConfigurations']:
|
|
|
|
@ -1493,53 +1492,69 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
|
|
|
|
|
self.fail("Error generalizing virtual machine {0} - {1}".format(self.name, str(exc)))
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def remove_autocreated_resources(self, tags):
|
|
|
|
|
if tags:
|
|
|
|
|
sa_name = tags.get('_own_sa_')
|
|
|
|
|
nic_name = tags.get('_own_nic_')
|
|
|
|
|
pip_name = tags.get('_own_pip_')
|
|
|
|
|
nsg_name = tags.get('_own_nsg_')
|
|
|
|
|
if sa_name:
|
|
|
|
|
self.delete_storage_account(self.resource_group, sa_name)
|
|
|
|
|
if nic_name:
|
|
|
|
|
self.delete_nic(self.resource_group, nic_name)
|
|
|
|
|
if pip_name:
|
|
|
|
|
self.delete_pip(self.resource_group, pip_name)
|
|
|
|
|
if nsg_name:
|
|
|
|
|
self.delete_nsg(self.resource_group, nsg_name)
|
|
|
|
|
|
|
|
|
|
def delete_vm(self, vm):
|
|
|
|
|
vhd_uris = []
|
|
|
|
|
managed_disk_ids = []
|
|
|
|
|
nic_names = []
|
|
|
|
|
pip_names = []
|
|
|
|
|
|
|
|
|
|
if self.remove_on_absent.intersection(set(['all', 'virtual_storage'])):
|
|
|
|
|
# store the attached vhd info so we can nuke it after the VM is gone
|
|
|
|
|
if(vm.storage_profile.os_disk.managed_disk):
|
|
|
|
|
self.log('Storing managed disk ID for deletion')
|
|
|
|
|
managed_disk_ids.append(vm.storage_profile.os_disk.managed_disk.id)
|
|
|
|
|
elif(vm.storage_profile.os_disk.vhd):
|
|
|
|
|
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:
|
|
|
|
|
if data_disk is not None:
|
|
|
|
|
if(data_disk.vhd):
|
|
|
|
|
vhd_uris.append(data_disk.vhd.uri)
|
|
|
|
|
elif(data_disk.managed_disk):
|
|
|
|
|
managed_disk_ids.append(data_disk.managed_disk.id)
|
|
|
|
|
|
|
|
|
|
# FUTURE enable diff mode, move these there...
|
|
|
|
|
self.log("VHD URIs to delete: {0}".format(', '.join(vhd_uris)))
|
|
|
|
|
self.results['deleted_vhd_uris'] = vhd_uris
|
|
|
|
|
self.log("Managed disk IDs to delete: {0}".format(', '.join(managed_disk_ids)))
|
|
|
|
|
self.results['deleted_managed_disk_ids'] = managed_disk_ids
|
|
|
|
|
|
|
|
|
|
if self.remove_on_absent.intersection(set(['all', 'network_interfaces'])):
|
|
|
|
|
# store the attached nic info so we can nuke them after the VM is gone
|
|
|
|
|
self.log('Storing NIC names for deletion.')
|
|
|
|
|
for interface in vm.network_profile.network_interfaces:
|
|
|
|
|
id_dict = azure_id_to_dict(interface.id)
|
|
|
|
|
nic_names.append(dict(name=id_dict['networkInterfaces'], resource_group=id_dict['resourceGroups']))
|
|
|
|
|
self.log('NIC names to delete {0}'.format(str(nic_names)))
|
|
|
|
|
self.results['deleted_network_interfaces'] = nic_names
|
|
|
|
|
if self.remove_on_absent.intersection(set(['all', 'public_ips'])):
|
|
|
|
|
# also store each nic's attached public IPs and delete after the NIC is gone
|
|
|
|
|
for nic_dict in nic_names:
|
|
|
|
|
nic = self.get_network_interface(nic_dict['resource_group'], nic_dict['name'])
|
|
|
|
|
for ipc in nic.ip_configurations:
|
|
|
|
|
if ipc.public_ip_address:
|
|
|
|
|
pip_dict = azure_id_to_dict(ipc.public_ip_address.id)
|
|
|
|
|
pip_names.append(dict(name=pip_dict['publicIPAddresses'], resource_group=pip_dict['resourceGroups']))
|
|
|
|
|
self.log('Public IPs to delete are {0}'.format(str(pip_names)))
|
|
|
|
|
self.results['deleted_public_ips'] = pip_names
|
|
|
|
|
if 'all_autocreated' not in self.remove_on_absent:
|
|
|
|
|
if self.remove_on_absent.intersection(set(['all', 'virtual_storage'])):
|
|
|
|
|
# store the attached vhd info so we can nuke it after the VM is gone
|
|
|
|
|
if(vm.storage_profile.os_disk.managed_disk):
|
|
|
|
|
self.log('Storing managed disk ID for deletion')
|
|
|
|
|
managed_disk_ids.append(vm.storage_profile.os_disk.managed_disk.id)
|
|
|
|
|
elif(vm.storage_profile.os_disk.vhd):
|
|
|
|
|
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:
|
|
|
|
|
if data_disk is not None:
|
|
|
|
|
if(data_disk.vhd):
|
|
|
|
|
vhd_uris.append(data_disk.vhd.uri)
|
|
|
|
|
elif(data_disk.managed_disk):
|
|
|
|
|
managed_disk_ids.append(data_disk.managed_disk.id)
|
|
|
|
|
|
|
|
|
|
# FUTURE enable diff mode, move these there...
|
|
|
|
|
self.log("VHD URIs to delete: {0}".format(', '.join(vhd_uris)))
|
|
|
|
|
self.results['deleted_vhd_uris'] = vhd_uris
|
|
|
|
|
self.log("Managed disk IDs to delete: {0}".format(', '.join(managed_disk_ids)))
|
|
|
|
|
self.results['deleted_managed_disk_ids'] = managed_disk_ids
|
|
|
|
|
|
|
|
|
|
if self.remove_on_absent.intersection(set(['all', 'network_interfaces'])):
|
|
|
|
|
# store the attached nic info so we can nuke them after the VM is gone
|
|
|
|
|
self.log('Storing NIC names for deletion.')
|
|
|
|
|
for interface in vm.network_profile.network_interfaces:
|
|
|
|
|
id_dict = azure_id_to_dict(interface.id)
|
|
|
|
|
nic_names.append(dict(name=id_dict['networkInterfaces'], resource_group=id_dict['resourceGroups']))
|
|
|
|
|
self.log('NIC names to delete {0}'.format(str(nic_names)))
|
|
|
|
|
self.results['deleted_network_interfaces'] = nic_names
|
|
|
|
|
if self.remove_on_absent.intersection(set(['all', 'public_ips'])):
|
|
|
|
|
# also store each nic's attached public IPs and delete after the NIC is gone
|
|
|
|
|
for nic_dict in nic_names:
|
|
|
|
|
nic = self.get_network_interface(nic_dict['resource_group'], nic_dict['name'])
|
|
|
|
|
for ipc in nic.ip_configurations:
|
|
|
|
|
if ipc.public_ip_address:
|
|
|
|
|
pip_dict = azure_id_to_dict(ipc.public_ip_address.id)
|
|
|
|
|
pip_names.append(dict(name=pip_dict['publicIPAddresses'], resource_group=pip_dict['resourceGroups']))
|
|
|
|
|
self.log('Public IPs to delete are {0}'.format(str(pip_names)))
|
|
|
|
|
self.results['deleted_public_ips'] = pip_names
|
|
|
|
|
|
|
|
|
|
self.log("Deleting virtual machine {0}".format(self.name))
|
|
|
|
|
self.results['actions'].append("Deleted virtual machine {0}".format(self.name))
|
|
|
|
@ -1550,23 +1565,27 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
self.fail("Error deleting virtual machine {0} - {1}".format(self.name, str(exc)))
|
|
|
|
|
|
|
|
|
|
# TODO: parallelize nic, vhd, and public ip deletions with begin_deleting
|
|
|
|
|
# TODO: best-effort to keep deleting other linked resources if we encounter an error
|
|
|
|
|
if self.remove_on_absent.intersection(set(['all', 'virtual_storage'])):
|
|
|
|
|
self.log('Deleting VHDs')
|
|
|
|
|
self.delete_vm_storage(vhd_uris)
|
|
|
|
|
self.log('Deleting managed disks')
|
|
|
|
|
self.delete_managed_disks(managed_disk_ids)
|
|
|
|
|
|
|
|
|
|
if self.remove_on_absent.intersection(set(['all', 'network_interfaces'])):
|
|
|
|
|
self.log('Deleting network interfaces')
|
|
|
|
|
for nic_dict in nic_names:
|
|
|
|
|
self.delete_nic(nic_dict['resource_group'], nic_dict['name'])
|
|
|
|
|
|
|
|
|
|
if self.remove_on_absent.intersection(set(['all', 'public_ips'])):
|
|
|
|
|
self.log('Deleting public IPs')
|
|
|
|
|
for pip_dict in pip_names:
|
|
|
|
|
self.delete_pip(pip_dict['resource_group'], pip_dict['name'])
|
|
|
|
|
if 'all_autocreated' in self.remove_on_absent:
|
|
|
|
|
self.remove_autocreated_resources(vm.tags)
|
|
|
|
|
else:
|
|
|
|
|
# TODO: parallelize nic, vhd, and public ip deletions with begin_deleting
|
|
|
|
|
# TODO: best-effort to keep deleting other linked resources if we encounter an error
|
|
|
|
|
if self.remove_on_absent.intersection(set(['all', 'virtual_storage'])):
|
|
|
|
|
self.log('Deleting VHDs')
|
|
|
|
|
self.delete_vm_storage(vhd_uris)
|
|
|
|
|
self.log('Deleting managed disks')
|
|
|
|
|
self.delete_managed_disks(managed_disk_ids)
|
|
|
|
|
|
|
|
|
|
if self.remove_on_absent.intersection(set(['all', 'network_interfaces'])):
|
|
|
|
|
self.log('Deleting network interfaces')
|
|
|
|
|
for nic_dict in nic_names:
|
|
|
|
|
self.delete_nic(nic_dict['resource_group'], nic_dict['name'])
|
|
|
|
|
|
|
|
|
|
if self.remove_on_absent.intersection(set(['all', 'public_ips'])):
|
|
|
|
|
self.log('Deleting public IPs')
|
|
|
|
|
for pip_dict in pip_names:
|
|
|
|
|
self.delete_pip(pip_dict['resource_group'], pip_dict['name'])
|
|
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def get_network_interface(self, resource_group, name):
|
|
|
|
@ -1575,6 +1594,7 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
|
|
|
|
|
return nic
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
self.fail("Error fetching network interface {0} - {1}".format(name, str(exc)))
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def delete_nic(self, resource_group, name):
|
|
|
|
|
self.log("Deleting network interface {0}".format(name))
|
|
|
|
@ -1597,6 +1617,15 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
|
|
|
|
|
# Delete returns nada. If we get here, assume that all is well.
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def delete_nsg(self, resource_group, name):
|
|
|
|
|
self.results['actions'].append("Deleted NSG {0}".format(name))
|
|
|
|
|
try:
|
|
|
|
|
poller = self.network_client.network_security_groups.delete(resource_group, name)
|
|
|
|
|
self.get_poller_result(poller)
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
self.fail("Error deleting {0} - {1}".format(name, str(exc)))
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def delete_managed_disks(self, managed_disk_ids):
|
|
|
|
|
for mdi in managed_disk_ids:
|
|
|
|
|
try:
|
|
|
|
@ -1604,6 +1633,16 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
|
|
|
|
|
self.get_poller_result(poller)
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
self.fail("Error deleting managed disk {0} - {1}".format(mdi, str(exc)))
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def delete_storage_account(self, resource_group, name):
|
|
|
|
|
self.log("Delete storage account {0}".format(name))
|
|
|
|
|
self.results['actions'].append("Deleted storage account {0}".format(name))
|
|
|
|
|
try:
|
|
|
|
|
self.storage_client.storage_accounts.delete(self.resource_group, name)
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
self.fail("Error deleting storage account {0} - {2}".format(name, str(exc)))
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def delete_vm_storage(self, vhd_uris):
|
|
|
|
|
# FUTURE: figure out a cloud_env indepdendent way to delete these
|
|
|
|
@ -1625,6 +1664,7 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
|
|
|
|
|
blob_client.delete_blob(container_name, blob_name)
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
self.fail("Error deleting blob {0}:{1} - {2}".format(container_name, blob_name, str(exc)))
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def get_marketplace_image_version(self):
|
|
|
|
|
try:
|
|
|
|
@ -1681,11 +1721,13 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
self.fail("Error fetching storage account {0} - {1}".format(name, str(exc)))
|
|
|
|
|
|
|
|
|
|
def create_or_update_vm(self, params):
|
|
|
|
|
def create_or_update_vm(self, params, remove_autocreated_on_failure):
|
|
|
|
|
try:
|
|
|
|
|
poller = self.compute_client.virtual_machines.create_or_update(self.resource_group, self.name, params)
|
|
|
|
|
self.get_poller_result(poller)
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
if remove_autocreated_on_failure:
|
|
|
|
|
self.remove_autocreated_resources(params.tags)
|
|
|
|
|
self.fail("Error creating or updating virtual machine {0} - {1}".format(self.name, str(exc)))
|
|
|
|
|
|
|
|
|
|
def vm_size_is_valid(self):
|
|
|
|
@ -1712,6 +1754,8 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
|
|
|
|
|
'''
|
|
|
|
|
account = None
|
|
|
|
|
valid_name = False
|
|
|
|
|
if self.tags is None:
|
|
|
|
|
self.tags = {}
|
|
|
|
|
|
|
|
|
|
# Attempt to find a valid storage account name
|
|
|
|
|
storage_account_name_base = re.sub('[^a-zA-Z0-9]', '', self.name[:20].lower())
|
|
|
|
@ -1746,6 +1790,7 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
|
|
|
|
|
self.get_poller_result(poller)
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
self.fail("Failed to create storage account: {0} - {1}".format(storage_account_name, str(exc)))
|
|
|
|
|
self.tags['_own_sa_'] = storage_account_name
|
|
|
|
|
return self.get_storage_account(storage_account_name)
|
|
|
|
|
|
|
|
|
|
def check_storage_account_name(self, name):
|
|
|
|
@ -1769,6 +1814,8 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
|
|
|
|
|
|
|
|
|
|
network_interface_name = self.name + '01'
|
|
|
|
|
nic = None
|
|
|
|
|
if self.tags is None:
|
|
|
|
|
self.tags = {}
|
|
|
|
|
|
|
|
|
|
self.log("Create default NIC {0}".format(network_interface_name))
|
|
|
|
|
self.log("Check to see if NIC {0} exists".format(network_interface_name))
|
|
|
|
@ -1849,10 +1896,12 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
|
|
|
|
|
sku = self.network_models.PublicIPAddressSku(name="Standard") if self.zones else None
|
|
|
|
|
pip_info = self.create_default_pip(self.resource_group, self.location, self.name + '01', self.public_ip_allocation_method, sku=sku)
|
|
|
|
|
pip = self.network_models.PublicIPAddress(id=pip_info.id, location=pip_info.location, resource_guid=pip_info.resource_guid, sku=sku)
|
|
|
|
|
self.tags['_own_pip_'] = self.name + '01'
|
|
|
|
|
|
|
|
|
|
self.results['actions'].append('Created default security group {0}'.format(self.name + '01'))
|
|
|
|
|
group = self.create_default_securitygroup(self.resource_group, self.location, self.name + '01', self.os_type,
|
|
|
|
|
self.open_ports)
|
|
|
|
|
self.tags['_own_nsg_'] = self.name + '01'
|
|
|
|
|
|
|
|
|
|
parameters = self.network_models.NetworkInterface(
|
|
|
|
|
location=self.location,
|
|
|
|
@ -1877,6 +1926,7 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
|
|
|
|
|
network_interface_name,
|
|
|
|
|
parameters)
|
|
|
|
|
new_nic = self.get_poller_result(poller)
|
|
|
|
|
self.tags['_own_nic_'] = network_interface_name
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
self.fail("Error creating network interface {0} - {1}".format(network_interface_name, str(exc)))
|
|
|
|
|
return new_nic
|
|
|
|
|