mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
VMware: add support for customize existing VM directly (#51215)
* add support for customize existing VM * modify space issue * move customize existing vm after reconfigure * delete one debug line
This commit is contained in:
parent
2311f908d2
commit
60e37c54cc
1 changed files with 54 additions and 8 deletions
|
@ -297,13 +297,15 @@ options:
|
||||||
version_added: '2.3'
|
version_added: '2.3'
|
||||||
customization:
|
customization:
|
||||||
description:
|
description:
|
||||||
- Parameters for OS customization when cloning from the template or the virtual machine.
|
- Parameters for OS customization when cloning from the template or the virtual machine, or apply to the existing virtual machine directly.
|
||||||
- Not all operating systems are supported for customization with respective vCenter version,
|
- Not all operating systems are supported for customization with respective vCenter version,
|
||||||
please check VMware documentation for respective OS customization.
|
please check VMware documentation for respective OS customization.
|
||||||
- For supported customization operating system matrix, (see U(http://partnerweb.vmware.com/programs/guestOS/guest-os-customization-matrix.pdf))
|
- For supported customization operating system matrix, (see U(http://partnerweb.vmware.com/programs/guestOS/guest-os-customization-matrix.pdf))
|
||||||
- All parameters and VMware object names are case sensitive.
|
- All parameters and VMware object names are case sensitive.
|
||||||
- Linux based OSes requires Perl package to be installed for OS customizations.
|
- Linux based OSes requires Perl package to be installed for OS customizations.
|
||||||
- 'Common parameters (Linux/Windows):'
|
- 'Common parameters (Linux/Windows):'
|
||||||
|
- ' - C(existing_vm) (bool): If set to C(True), do OS customization on the specified virtual machine directly.
|
||||||
|
If set to C(False) or not specified, do OS customization when cloning from the template or the virtual machine. version_added: 2.8'
|
||||||
- ' - C(dns_servers) (list): List of DNS servers to configure.'
|
- ' - C(dns_servers) (list): List of DNS servers to configure.'
|
||||||
- ' - C(dns_suffix) (list): List of domain suffixes, also known as DNS search path (default: C(domain) parameter).'
|
- ' - C(dns_suffix) (list): List of domain suffixes, also known as DNS search path (default: C(domain) parameter).'
|
||||||
- ' - C(domain) (string): DNS domain name to use.'
|
- ' - C(domain) (string): DNS domain name to use.'
|
||||||
|
@ -563,6 +565,7 @@ instance:
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
import string
|
||||||
|
|
||||||
HAS_PYVMOMI = False
|
HAS_PYVMOMI = False
|
||||||
try:
|
try:
|
||||||
|
@ -1584,7 +1587,9 @@ class PyVmomiHelper(PyVmomi):
|
||||||
|
|
||||||
# Setting hostName, orgName and fullName is mandatory, so we set some default when missing
|
# Setting hostName, orgName and fullName is mandatory, so we set some default when missing
|
||||||
ident.userData.computerName = vim.vm.customization.FixedName()
|
ident.userData.computerName = vim.vm.customization.FixedName()
|
||||||
ident.userData.computerName.name = str(self.params['customization'].get('hostname', self.params['name'].split('.')[0]))
|
# computer name will be truncated to 15 characters if using VM name
|
||||||
|
default_name = self.params['name'].translate(None, string.punctuation)
|
||||||
|
ident.userData.computerName.name = str(self.params['customization'].get('hostname', default_name[0:15]))
|
||||||
ident.userData.fullName = str(self.params['customization'].get('fullname', 'Administrator'))
|
ident.userData.fullName = str(self.params['customization'].get('fullname', 'Administrator'))
|
||||||
ident.userData.orgName = str(self.params['customization'].get('orgname', 'ACME'))
|
ident.userData.orgName = str(self.params['customization'].get('orgname', 'ACME'))
|
||||||
|
|
||||||
|
@ -2146,7 +2151,7 @@ class PyVmomiHelper(PyVmomi):
|
||||||
network_changes = True
|
network_changes = True
|
||||||
break
|
break
|
||||||
|
|
||||||
if len(self.params['customization']) > 0 or network_changes or self.params.get('customization_spec'):
|
if len(self.params['customization']) > 0 or network_changes or self.params.get('customization_spec') is not None:
|
||||||
self.customize_vm(vm_obj=vm_obj)
|
self.customize_vm(vm_obj=vm_obj)
|
||||||
|
|
||||||
clonespec = None
|
clonespec = None
|
||||||
|
@ -2394,9 +2399,51 @@ class PyVmomiHelper(PyVmomi):
|
||||||
|
|
||||||
self.change_detected = True
|
self.change_detected = True
|
||||||
|
|
||||||
|
# add customize existing VM after VM re-configure
|
||||||
|
if 'existing_vm' in self.params['customization'] and self.params['customization']['existing_vm']:
|
||||||
|
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:
|
||||||
|
self.module.fail_json(msg="VM is not in poweroff state, can not do guest OS customization.")
|
||||||
|
cus_result = self.customize_exist_vm()
|
||||||
|
if cus_result['failed']:
|
||||||
|
return cus_result
|
||||||
|
|
||||||
vm_facts = self.gather_facts(self.current_vm_obj)
|
vm_facts = self.gather_facts(self.current_vm_obj)
|
||||||
return {'changed': self.change_applied, 'failed': False, 'instance': vm_facts}
|
return {'changed': self.change_applied, 'failed': False, 'instance': vm_facts}
|
||||||
|
|
||||||
|
def customize_exist_vm(self):
|
||||||
|
task = None
|
||||||
|
# Find if we need network customizations (find keys in dictionary that requires customizations)
|
||||||
|
network_changes = False
|
||||||
|
for nw in self.params['networks']:
|
||||||
|
for key in nw:
|
||||||
|
# We don't need customizations for these keys
|
||||||
|
if key not in ('device_type', 'mac', 'name', 'vlan', 'type', 'start_connected'):
|
||||||
|
network_changes = True
|
||||||
|
break
|
||||||
|
if len(self.params['customization']) > 1 or network_changes or self.params.get('customization_spec'):
|
||||||
|
self.customize_vm(vm_obj=self.current_vm_obj)
|
||||||
|
try:
|
||||||
|
task = self.current_vm_obj.CustomizeVM_Task(self.customspec)
|
||||||
|
except vim.fault.CustomizationFault as e:
|
||||||
|
self.module.fail_json(msg="Failed to customization virtual machine due to CustomizationFault: %s" % to_native(e.msg))
|
||||||
|
except vim.fault.RuntimeFault as e:
|
||||||
|
self.module.fail_json(msg="failed to customization virtual machine due to RuntimeFault: %s" % to_native(e.msg))
|
||||||
|
except Exception as e:
|
||||||
|
self.module.fail_json(msg="failed to customization virtual machine due to fault: %s" % to_native(e.msg))
|
||||||
|
self.wait_for_task(task)
|
||||||
|
if task.info.state == 'error':
|
||||||
|
return {'changed': self.change_applied, 'failed': True, 'msg': task.info.error.msg, 'op': 'customize_exist'}
|
||||||
|
|
||||||
|
if self.params['wait_for_customization']:
|
||||||
|
set_vm_power_state(self.content, self.current_vm_obj, 'poweredon', force=False)
|
||||||
|
is_customization_ok = self.wait_for_customization(self.current_vm_obj)
|
||||||
|
if not is_customization_ok:
|
||||||
|
return {'changed': self.change_applied, 'failed': True, 'op': 'wait_for_customize_exist'}
|
||||||
|
|
||||||
|
return {'changed': self.change_applied, 'failed': False}
|
||||||
|
|
||||||
def wait_for_task(self, task, poll_interval=1):
|
def wait_for_task(self, task, poll_interval=1):
|
||||||
"""
|
"""
|
||||||
Wait for a VMware task to complete. Terminal states are 'error' and 'success'.
|
Wait for a VMware task to complete. Terminal states are 'error' and 'success'.
|
||||||
|
@ -2430,9 +2477,8 @@ class PyVmomiHelper(PyVmomi):
|
||||||
|
|
||||||
return facts
|
return facts
|
||||||
|
|
||||||
def get_vm_events(self, eventTypeIdList):
|
def get_vm_events(self, vm, eventTypeIdList):
|
||||||
newvm = self.get_vm()
|
byEntity = vim.event.EventFilterSpec.ByEntity(entity=vm, recursion="self")
|
||||||
byEntity = vim.event.EventFilterSpec.ByEntity(entity=newvm, recursion="self")
|
|
||||||
filterSpec = vim.event.EventFilterSpec(entity=byEntity, eventTypeId=eventTypeIdList)
|
filterSpec = vim.event.EventFilterSpec(entity=byEntity, eventTypeId=eventTypeIdList)
|
||||||
eventManager = self.content.eventManager
|
eventManager = self.content.eventManager
|
||||||
return eventManager.QueryEvent(filterSpec)
|
return eventManager.QueryEvent(filterSpec)
|
||||||
|
@ -2440,11 +2486,11 @@ class PyVmomiHelper(PyVmomi):
|
||||||
def wait_for_customization(self, vm, poll=10000, sleep=10):
|
def wait_for_customization(self, vm, poll=10000, sleep=10):
|
||||||
thispoll = 0
|
thispoll = 0
|
||||||
while thispoll <= poll:
|
while thispoll <= poll:
|
||||||
eventStarted = self.get_vm_events(['CustomizationStartedEvent'])
|
eventStarted = self.get_vm_events(vm, ['CustomizationStartedEvent'])
|
||||||
if len(eventStarted):
|
if len(eventStarted):
|
||||||
thispoll = 0
|
thispoll = 0
|
||||||
while thispoll <= poll:
|
while thispoll <= poll:
|
||||||
eventsFinishedResult = self.get_vm_events(['CustomizationSucceeded', 'CustomizationFailed'])
|
eventsFinishedResult = self.get_vm_events(vm, ['CustomizationSucceeded', 'CustomizationFailed'])
|
||||||
if len(eventsFinishedResult):
|
if len(eventsFinishedResult):
|
||||||
if not isinstance(eventsFinishedResult[0], vim.event.CustomizationSucceeded):
|
if not isinstance(eventsFinishedResult[0], vim.event.CustomizationSucceeded):
|
||||||
self.module.fail_json(msg='Customization failed with error {0}:\n{1}'.format(
|
self.module.fail_json(msg='Customization failed with error {0}:\n{1}'.format(
|
||||||
|
|
Loading…
Reference in a new issue