Support for generalizing VMs (#49704)
This commit is contained in:
parent
aec98b6aab
commit
b89eb7a8c9
3 changed files with 60 additions and 7 deletions
|
@ -68,6 +68,12 @@ options:
|
|||
- Toggle that controls if the machine is allocated/deallocated, only useful with state='present'.
|
||||
default: True
|
||||
type: bool
|
||||
generalized:
|
||||
description:
|
||||
- Use with state 'present' to generalize the machine. Set to true to generalize the machine.
|
||||
- Please note that this operation is irreversible.
|
||||
type: bool
|
||||
version_added: "2.8"
|
||||
restarted:
|
||||
description:
|
||||
- Use with state 'present' to restart a running VM.
|
||||
|
@ -496,7 +502,7 @@ EXAMPLES = '''
|
|||
|
||||
RETURN = '''
|
||||
powerstate:
|
||||
description: Indicates if the state is running, stopped, deallocated
|
||||
description: Indicates if the state is running, stopped, deallocated, generalized
|
||||
returned: always
|
||||
type: string
|
||||
example: running
|
||||
|
@ -666,6 +672,7 @@ import re
|
|||
try:
|
||||
from msrestazure.azure_exceptions import CloudError
|
||||
from msrestazure.tools import parse_resource_id
|
||||
from msrest.polling import LROPoller
|
||||
except ImportError:
|
||||
# This is handled in azure_rm_common
|
||||
pass
|
||||
|
@ -727,6 +734,7 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
|
|||
allocated=dict(type='bool', default=True),
|
||||
restarted=dict(type='bool', default=False),
|
||||
started=dict(type='bool', default=True),
|
||||
generalized=dict(type='bool', default=False),
|
||||
data_disks=dict(type='list'),
|
||||
plan=dict(type='dict'),
|
||||
accept_terms=dict(type='bool', default=False)
|
||||
|
@ -765,6 +773,7 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
|
|||
self.allocated = None
|
||||
self.restarted = None
|
||||
self.started = None
|
||||
self.generalized = None
|
||||
self.differences = None
|
||||
self.data_disks = None
|
||||
self.plan = None
|
||||
|
@ -954,6 +963,10 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
|
|||
self.log("CHANGED: virtual machine {0} running and requested state 'stopped'".format(self.name))
|
||||
changed = True
|
||||
powerstate_change = 'poweroff'
|
||||
elif self.generalized and vm_dict['powerstate'] != 'generalized':
|
||||
self.log("CHANGED: virtual machine {0} requested to be 'generalized'".format(self.name))
|
||||
changed = True
|
||||
powerstate_change = 'generalized'
|
||||
|
||||
self.differences = differences
|
||||
|
||||
|
@ -1298,6 +1311,9 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
|
|||
|
||||
elif powerstate_change == 'deallocated':
|
||||
self.deallocate_vm()
|
||||
elif powerstate_change == 'generalized':
|
||||
self.power_off_vm()
|
||||
self.generalize_vm()
|
||||
|
||||
self.results['ansible_facts']['azure_vm'] = self.serialize_vm(self.get_vm())
|
||||
|
||||
|
@ -1343,6 +1359,9 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
|
|||
if vm.instance_view:
|
||||
result['powerstate'] = next((s.code.replace('PowerState/', '')
|
||||
for s in vm.instance_view.statuses if s.code.startswith('PowerState')), None)
|
||||
for s in vm.instance_view.statuses:
|
||||
if s.code.lower() == "osstate/generalized":
|
||||
result['powerstate'] = 'generalized'
|
||||
|
||||
# Expand network interfaces to include config properties
|
||||
for interface in vm.network_profile.network_interfaces:
|
||||
|
@ -1414,6 +1433,17 @@ class AzureRMVirtualMachine(AzureRMModuleBase):
|
|||
self.fail("Error deallocating virtual machine {0} - {1}".format(self.name, str(exc)))
|
||||
return True
|
||||
|
||||
def generalize_vm(self):
|
||||
self.results['actions'].append("Generalize virtual machine {0}".format(self.name))
|
||||
self.log("Generalize virtual machine {0}".format(self.name))
|
||||
try:
|
||||
response = self.compute_client.virtual_machines.generalize(self.resource_group, self.name)
|
||||
if isinstance(response, LROPoller):
|
||||
self.get_poller_result(response)
|
||||
except Exception as exc:
|
||||
self.fail("Error generalizing virtual machine {0} - {1}".format(self.name, str(exc)))
|
||||
return True
|
||||
|
||||
def delete_vm(self, vm):
|
||||
vhd_uris = []
|
||||
managed_disk_ids = []
|
||||
|
|
|
@ -305,6 +305,9 @@ class AzureRMVirtualMachineFacts(AzureRMModuleBase):
|
|||
code = instance['statuses'][index]['code'].split('/')
|
||||
if code[0] == 'PowerState':
|
||||
power_state = code[1]
|
||||
elif code[0] == 'OSState' and code[1] == 'generalized':
|
||||
power_state = 'generalized'
|
||||
break
|
||||
|
||||
new_result = {}
|
||||
new_result['power_state'] = power_state
|
||||
|
@ -317,12 +320,17 @@ class AzureRMVirtualMachineFacts(AzureRMModuleBase):
|
|||
new_result['admin_username'] = result['properties']['osProfile']['adminUsername']
|
||||
image = result['properties']['storageProfile'].get('imageReference')
|
||||
if image is not None:
|
||||
if image.get('publisher', None) is not None:
|
||||
new_result['image'] = {
|
||||
'publisher': image['publisher'],
|
||||
'sku': image['sku'],
|
||||
'offer': image['offer'],
|
||||
'version': image['version']
|
||||
}
|
||||
else:
|
||||
new_result['image'] = {
|
||||
'id': image.get('id', None)
|
||||
}
|
||||
|
||||
vhd = result['properties']['storageProfile']['osDisk'].get('vhd')
|
||||
if vhd is not None:
|
||||
|
|
|
@ -382,6 +382,21 @@
|
|||
- assert:
|
||||
that: not output.changed
|
||||
|
||||
- name: Generalize VM
|
||||
azure_rm_virtualmachine:
|
||||
resource_group: "{{ resource_group }}"
|
||||
name: "{{ vm_name2 }}"
|
||||
generalized: yes
|
||||
|
||||
- name: Gather facts and check if machine is generalized
|
||||
azure_rm_virtualmachine_facts:
|
||||
resource_group: "{{ resource_group }}"
|
||||
name: "{{ vm_name2 }}"
|
||||
register: generalized_output
|
||||
|
||||
- assert:
|
||||
that: generalized_output.vms[0].power_state == 'generalized'
|
||||
|
||||
- name: Delete dual NIC VM
|
||||
azure_rm_virtualmachine:
|
||||
resource_group: "{{ resource_group }}"
|
||||
|
|
Loading…
Reference in a new issue