summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDiane Wang <41371902+Tomorrow9@users.noreply.github.com>2019-02-03 21:08:35 -0800
committeransibot <ansibot@users.noreply.github.com>2019-02-04 00:08:35 -0500
commit60e37c54cc65d82aa61387a9eaa7a6a4620a37b3 (patch)
tree8a253e5871d12f2fb76e1c2f16dd835acd7751df /lib
parent2311f908d27ebaee0ff399afb32aaeeb451e1da2 (diff)
downloadansible-60e37c54cc65d82aa61387a9eaa7a6a4620a37b3.tar.gz
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
Diffstat (limited to 'lib')
-rw-r--r--lib/ansible/modules/cloud/vmware/vmware_guest.py62
1 files changed, 54 insertions, 8 deletions
diff --git a/lib/ansible/modules/cloud/vmware/vmware_guest.py b/lib/ansible/modules/cloud/vmware/vmware_guest.py
index 2c1a78ab1d..ebb26f6d2b 100644
--- a/lib/ansible/modules/cloud/vmware/vmware_guest.py
+++ b/lib/ansible/modules/cloud/vmware/vmware_guest.py
@@ -297,13 +297,15 @@ options:
version_added: '2.3'
customization:
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,
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))
- All parameters and VMware object names are case sensitive.
- Linux based OSes requires Perl package to be installed for OS customizations.
- '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_suffix) (list): List of domain suffixes, also known as DNS search path (default: C(domain) parameter).'
- ' - C(domain) (string): DNS domain name to use.'
@@ -563,6 +565,7 @@ instance:
import re
import time
+import string
HAS_PYVMOMI = False
try:
@@ -1584,7 +1587,9 @@ class PyVmomiHelper(PyVmomi):
# Setting hostName, orgName and fullName is mandatory, so we set some default when missing
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.orgName = str(self.params['customization'].get('orgname', 'ACME'))
@@ -2146,7 +2151,7 @@ class PyVmomiHelper(PyVmomi):
network_changes = True
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)
clonespec = None
@@ -2394,9 +2399,51 @@ class PyVmomiHelper(PyVmomi):
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)
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):
"""
Wait for a VMware task to complete. Terminal states are 'error' and 'success'.
@@ -2430,9 +2477,8 @@ class PyVmomiHelper(PyVmomi):
return facts
- def get_vm_events(self, eventTypeIdList):
- newvm = self.get_vm()
- byEntity = vim.event.EventFilterSpec.ByEntity(entity=newvm, recursion="self")
+ def get_vm_events(self, vm, eventTypeIdList):
+ byEntity = vim.event.EventFilterSpec.ByEntity(entity=vm, recursion="self")
filterSpec = vim.event.EventFilterSpec(entity=byEntity, eventTypeId=eventTypeIdList)
eventManager = self.content.eventManager
return eventManager.QueryEvent(filterSpec)
@@ -2440,11 +2486,11 @@ class PyVmomiHelper(PyVmomi):
def wait_for_customization(self, vm, poll=10000, sleep=10):
thispoll = 0
while thispoll <= poll:
- eventStarted = self.get_vm_events(['CustomizationStartedEvent'])
+ eventStarted = self.get_vm_events(vm, ['CustomizationStartedEvent'])
if len(eventStarted):
thispoll = 0
while thispoll <= poll:
- eventsFinishedResult = self.get_vm_events(['CustomizationSucceeded', 'CustomizationFailed'])
+ eventsFinishedResult = self.get_vm_events(vm, ['CustomizationSucceeded', 'CustomizationFailed'])
if len(eventsFinishedResult):
if not isinstance(eventsFinishedResult[0], vim.event.CustomizationSucceeded):
self.module.fail_json(msg='Customization failed with error {0}:\n{1}'.format(