Skip to content

Commit

Permalink
vmware_guest: add option force_reconfigure
Browse files Browse the repository at this point in the history
  • Loading branch information
parsa97 committed Feb 18, 2024
1 parent 322f0c2 commit b46ab19
Showing 1 changed file with 88 additions and 14 deletions.
102 changes: 88 additions & 14 deletions plugins/modules/vmware_guest.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@
- Whether to use the VMware instance UUID rather than the BIOS UUID.
default: false
type: bool
force_reconfigure:
description:
- By default reconfiguration, only happens when the VM is in a "present" state.
- When C(force_reconfigure) is true and If the reconfigure process requires a shutdown, the module will power down the VM, apply the changes, and then start it.
default: false
type: bool
version_added: '4.1.1'
template:
description:
- Template or existing virtual machine used to create new virtual machine.
Expand Down Expand Up @@ -1230,6 +1237,7 @@ def __init__(self, module):
self.tracked_changes = {} # dict of changes made or would-be-made in check mode, updated when change_applied is set
self.customspec = None
self.cache = PyVmomiCache(self.content, dc_name=self.params['datacenter'])
self.force_reconfigure_shutdown_require = False

def gather_facts(self, vm):
return gather_vm_facts(self.content, vm)
Expand Down Expand Up @@ -1354,16 +1362,27 @@ def configure_resource_alloc_info(self, vm_obj):

def configure_cpu_and_memory(self, vm_obj, vm_creation=False):
# set cpu/memory/etc
self.force_reconfigure_shutdown_require = False
num_cpus = self.params['hardware']['num_cpus']
if num_cpus is not None:
# check VM power state and cpu hot-add/hot-remove state before re-config VM
# Allow VM to be powered on during this check when in check mode, when no changes will actually be made
if vm_obj and vm_obj.runtime.powerState == vim.VirtualMachinePowerState.poweredOn and not self.module.check_mode:
if vm_obj and vm_obj.runtime.powerState == vim.VirtualMachinePowerState.poweredOn and not self.module.check_mode and not self.params['force_reconfigure']:
if not vm_obj.config.cpuHotRemoveEnabled and num_cpus < vm_obj.config.hardware.numCPU:
self.module.fail_json(msg="Configured cpu number is less than the cpu number of the VM, "
if self.params['force_reconfigure']:
self.module.warn("Configured cpu number is more than the cpu number of the VM, "
"cpuHotRemove is not enabled, force_reconfigre is true. The virtual machine will be shut down to apply the changes.")
self.force_reconfigure_shutdown_require = True
else:
self.module.fail_json(msg="Configured cpu number is less than the cpu number of the VM, "
"cpuHotRemove is not enabled")
if not vm_obj.config.cpuHotAddEnabled and num_cpus > vm_obj.config.hardware.numCPU:
self.module.fail_json(msg="Configured cpu number is more than the cpu number of the VM, "
if self.params['force_reconfigure']:
self.module.warn("Configured cpu number is more than the cpu number of the VM, "
"cpuHotAdd is not enabled, force_reconfigre is true. The virtual machine will be shut down to apply the changes.")
self.force_reconfigure_shutdown_require = True
else:
self.module.fail_json(msg="Configured cpu number is more than the cpu number of the VM, "
"cpuHotAdd is not enabled")

num_cpu_cores_per_socket = self.params['hardware']['num_cpu_cores_per_socket']
Expand All @@ -1386,11 +1405,20 @@ def configure_cpu_and_memory(self, vm_obj, vm_creation=False):
# check VM power state and memory hotadd state before re-config VM
if vm_obj and vm_obj.runtime.powerState == vim.VirtualMachinePowerState.poweredOn:
if vm_obj.config.memoryHotAddEnabled and memory_mb < vm_obj.config.hardware.memoryMB:
self.module.fail_json(msg="Configured memory is less than memory size of the VM, "
if self.params['force_reconfigure']:
self.module.warn("Configured memory is less than memory size of the VM, "
"operation is not supported, force_reconfigre is true. The virtual machine will be shut down to apply the changes.")
self.force_reconfigure_shutdown_require = True
else:
self.module.fail_json(msg="Configured memory is less than memory size of the VM, "
"operation is not supported")
# Allow VM to be powered on during this check when in check mode, when no changes will actually be made
elif not vm_obj.config.memoryHotAddEnabled and memory_mb != vm_obj.config.hardware.memoryMB and not self.module.check_mode:
self.module.fail_json(msg="memoryHotAdd is not enabled")
if self.params['force_reconfigure']:
self.module.warn("memoryHotAdd is not enabled, force_reconfigre is true. The virtual machine will be shut down to apply the changes.")
self.force_reconfigure_shutdown_require = True
else:
self.module.fail_json(msg="memoryHotAdd is not enabled")
if vm_obj is None or memory_mb != vm_obj.config.hardware.memoryMB:
self.change_detected = True
self.configspec.memoryMB = memory_mb
Expand All @@ -1403,7 +1431,12 @@ def configure_cpu_and_memory(self, vm_obj, vm_creation=False):
# Allow VM to be powered on during this check when in check mode, when no changes will actually be made
if vm_obj and vm_obj.runtime.powerState == vim.VirtualMachinePowerState.poweredOn and \
vm_obj.config.memoryHotAddEnabled != hotadd_memory and not self.module.check_mode:
self.module.fail_json(msg="Configure hotadd memory operation is not supported when VM is power on")
if self.params['force_reconfigure']:
self.module.warn("Configure hotadd memory operation is not supported when VM is power on"
", force_reconfigre is true. The virtual machine will be shut down to apply the changes.")
self.force_reconfigure_shutdown_require = True
else:
self.module.fail_json(msg="Configure hotadd memory operation is not supported when VM is power on")
if vm_obj is None or hotadd_memory != vm_obj.config.memoryHotAddEnabled:
self.change_detected = True
self.configspec.memoryHotAddEnabled = hotadd_memory
Expand All @@ -1413,7 +1446,12 @@ def configure_cpu_and_memory(self, vm_obj, vm_creation=False):
# Allow VM to be powered on during this check when in check mode, when no changes will actually be made
if vm_obj and vm_obj.runtime.powerState == vim.VirtualMachinePowerState.poweredOn and \
vm_obj.config.cpuHotAddEnabled != hotadd_cpu and not self.module.check_mode:
self.module.fail_json(msg="Configure hotadd cpu operation is not supported when VM is power on")
if self.params['force_reconfigure']:
self.module.warn("Configure hotadd cpu operation is not supported when VM is power on"
", force_reconfigre is true. The virtual machine will be shut down to apply the changes.")
self.force_reconfigure_shutdown_require = True
else:
self.module.fail_json(msg="Configure hotadd cpu operation is not supported when VM is power on")
if vm_obj is None or hotadd_cpu != vm_obj.config.cpuHotAddEnabled:
self.change_detected = True
self.configspec.cpuHotAddEnabled = hotadd_cpu
Expand All @@ -1423,7 +1461,12 @@ def configure_cpu_and_memory(self, vm_obj, vm_creation=False):
# Allow VM to be powered on during this check when in check mode, when no changes will actually be made
if vm_obj and vm_obj.runtime.powerState == vim.VirtualMachinePowerState.poweredOn and \
vm_obj.config.cpuHotRemoveEnabled != hotremove_cpu and not self.module.check_mode:
self.module.fail_json(msg="Configure hotremove cpu operation is not supported when VM is power on")
if self.params['force_reconfigure']:
self.module.warn("Configure hotremove cpu operation is not supported when VM is power on"
", force_reconfigre is true. The virtual machine will be shut down to apply the changes.")
self.force_reconfigure_shutdown_require = True
else:
self.module.fail_json(msg="Configure hotremove cpu operation is not supported when VM is power on")
if vm_obj is None or hotremove_cpu != vm_obj.config.cpuHotRemoveEnabled:
self.change_detected = True
self.configspec.cpuHotRemoveEnabled = hotremove_cpu
Expand All @@ -1439,7 +1482,12 @@ def configure_cpu_and_memory(self, vm_obj, vm_creation=False):
# Allow VM to be powered on during this check when in check mode, when no changes will actually be made
if vm_obj and vm_obj.runtime.powerState == vim.VirtualMachinePowerState.poweredOn and \
vm_obj.config.vPMCEnabled != vpmc_enabled and not self.module.check_mode:
self.module.fail_json(msg="Configure vPMC cpu operation is not supported when VM is power on")
if self.params['force_reconfigure']:
self.module.warn("Configure vPMC cpu operation is not supported when VM is power on"
", force_reconfigre is true. The virtual machine will be shut down to apply the changes.")
self.force_reconfigure_shutdown_require = True
else:
self.module.fail_json(msg="Configure vPMC cpu operation is not supported when VM is power on")
if vm_obj is None or vpmc_enabled != vm_obj.config.vPMCEnabled:
self.change_detected = True
self.configspec.vPMCEnabled = vpmc_enabled
Expand Down Expand Up @@ -1559,7 +1607,12 @@ def configure_cdrom_list(self, vm_obj):
# Allow VM to be powered on during this check when in check mode, when no changes will actually be made
if vm_obj and vm_obj.runtime.powerState == vim.VirtualMachinePowerState.poweredOn and \
isinstance(ctl_device, vim.vm.device.VirtualIDEController) and not self.module.check_mode:
self.module.fail_json(msg='CD-ROM attach to IDE controller not support hot-add.')
if self.params['force_reconfigure']:
self.module.warn("CD-ROM attach to IDE controller not support hot-add."
", force_reconfigre is true. The virtual machine will be shut down to apply the changes.")
self.force_reconfigure_shutdown_require = True
else:
self.module.fail_json(msg='CD-ROM attach to IDE controller not support hot-add.')
if len(ctl_device.device) == 2 and isinstance(ctl_device, vim.vm.device.VirtualIDEController):
self.module.fail_json(msg='Maximum number of CD-ROMs attached to IDE controller is 2.')
if len(ctl_device.device) == 30 and isinstance(ctl_device, vim.vm.device.VirtualAHCIController):
Expand All @@ -1584,7 +1637,12 @@ def configure_cdrom_list(self, vm_obj):
# Allow VM to be powered on during this check when in check mode, when no changes will actually be made
if vm_obj and vm_obj.runtime.powerState != vim.VirtualMachinePowerState.poweredOff and \
isinstance(ctl_device, vim.vm.device.VirtualIDEController) and not self.module.check_mode:
self.module.fail_json(msg='CD-ROM attach to IDE controller not support hot-remove.')
if self.params['force_reconfigure']:
self.module.warn("CD-ROM attach to IDE controller not support hot-remove."
", force_reconfigre is true. The virtual machine will be shut down to apply the changes.")
self.force_reconfigure_shutdown_require = True
else:
self.module.fail_json(msg='CD-ROM attach to IDE controller not support hot-remove.')
cdrom_spec = self.device_helper.remove_cdrom(cdrom_device)
self.change_detected = True
self.configspec.deviceChange.append(cdrom_spec)
Expand Down Expand Up @@ -1738,7 +1796,12 @@ def configure_nvdimm(self, vm_obj):
if vm_obj and not vm_obj.config.template:
# Allow VM to be powered on during this check when in check mode, when no changes will actually be made
if vm_obj.runtime.powerState != vim.VirtualMachinePowerState.poweredOff and not self.module.check_mode:
self.module.fail_json(msg="VM is not in power off state, can not do virtual NVDIMM configuration.")
if self.params['force_reconfigure']:
self.module.warn("VM is not in power off state, can not do virtual NVDIMM configuration."
", force_reconfigre is true. The virtual machine will be shut down to apply the changes.")
self.force_reconfigure_shutdown_require = True
else:
self.module.fail_json(msg="VM is not in power off state, can not do virtual NVDIMM configuration.")

nvdimm_ctl_exists = False
if vm_obj and not vm_obj.config.template:
Expand Down Expand Up @@ -3224,6 +3287,8 @@ def reconfigure_vm(self):
if self.module.check_mode:
self.change_applied = True
else:
if self.force_reconfigure_shutdown_require:
set_vm_power_state(self.content, self.current_vm_obj, 'poweredoff', force=False)
task = None
try:
task = self.current_vm_obj.ReconfigVM_Task(spec=self.configspec)
Expand Down Expand Up @@ -3293,7 +3358,12 @@ def reconfigure_vm(self):
if self.current_vm_obj.config.template:
self.module.fail_json(msg="VM is template, not support guest OS customization.")
if self.current_vm_obj.runtime.powerState != vim.VirtualMachinePowerState.poweredOff and not self.module.check_mode:
self.module.fail_json(msg="VM is not in poweroff state, can not do guest OS customization.")
if self.params['force_reconfigure']:
self.module.warn("VM is not in poweroff state, can not do guest OS customization."
", force_reconfigre is true. The virtual machine will be shut down to apply the changes.")
self.force_reconfigure_shutdown_require = True
else:
self.module.fail_json(msg="VM is not in poweroff state, can not do guest OS customization.")
# TODO not sure if it is possible to query the current customspec to compare against the one being provided to check in check mode.
# Maybe by breaking down the individual fields and querying, but it needs more research.
# For now, assume changed...
Expand All @@ -3305,6 +3375,9 @@ def reconfigure_vm(self):
if cus_result['failed']:
return cus_result

if self.force_reconfigure_shutdown_require:
set_vm_power_state(self.content, self.current_vm_obj, 'poweredon', force=False)

vm_facts = self.gather_facts(self.current_vm_obj)
return {'changed': self.change_applied, 'failed': False, 'instance': vm_facts, 'changes': self.tracked_changes}

Expand Down Expand Up @@ -3415,6 +3488,7 @@ def main():
name_match=dict(type='str', choices=['first', 'last'], default='first'),
uuid=dict(type='str'),
use_instance_uuid=dict(type='bool', default=False),
force_reconfigure=dict(type='bool', default=False),
folder=dict(type='str'),
guest_id=dict(type='str'),
disk=dict(
Expand Down Expand Up @@ -3581,7 +3655,7 @@ def main():
# has to be poweredoff first
set_vm_power_state(pyv.content, vm, 'poweredoff', module.params['force'])
result = pyv.remove_vm(vm, module.params['delete_from_inventory'])
elif module.params['state'] == 'present':
elif module.params['state'] == 'present' or module.params['force_reconfigure']:
# Note that check_mode is handled inside reconfigure_vm
result = pyv.reconfigure_vm()
elif module.params['state'] in ['poweredon', 'powered-on', 'poweredoff',
Expand Down

0 comments on commit b46ab19

Please sign in to comment.