vmware_guest: various customizations changes and fixes (#19975)

* vmware_guest: various changes and fixes

Most of my queued changes were already implemented by @aperigault !

This was still open
- Typos
- Various fixes to dict.get() without quotes
- Defaults to fullname and orgname (so they are no longer mandatory)
- Add missing timezone implementation
- Remove the customize flag from the options
- Rename 'customizations' to 'customization' (cfr VMware docs and fora)

* Important fixes for idempotency and customization

- A password is mandatory for customization to work on Windows !
- An important fix for idempotency related to guestId
- Support all types of Windows guestId entries

* Suggestion by @aperigault

* Small documentation fixes
pull/20052/head
Dag Wieers 8 years ago committed by jctanner
parent 0937196df1
commit aca60f1776

@ -25,31 +25,31 @@ ANSIBLE_METADATA = {'status': ['preview'],
DOCUMENTATION = ''' DOCUMENTATION = '''
--- ---
module: vmware_guest module: vmware_guest
short_description: Manages virtualmachines in vcenter short_description: Manages virtual machines in vcenter
description: description:
- Uses pyvmomi to ... - Create new virtual machines (from templates or not)
- copy a template to a new virtualmachine - Power on/power off/restart a virtual machine
- poweron/poweroff/restart a virtualmachine - Modify an existing virtual machine
- remove a virtualmachine - Remove a virtual machine
version_added: 2.2 version_added: 2.2
author: author:
- James Tanner (@jctanner) <tanner.jc@gmail.com> - James Tanner (@jctanner) <tanner.jc@gmail.com>
- Loic Blot (@nerzhul) <loic.blot@unix-experience.fr> - Loic Blot (@nerzhul) <loic.blot@unix-experience.fr>
notes: notes:
- Tested on vSphere 6.0 - Tested on vSphere 5.5 and 6.0
requirements: requirements:
- "python >= 2.6" - "python >= 2.6"
- PyVmomi - PyVmomi
options: options:
state: state:
description: description:
- What state should the virtualmachine be in? - What state should the virtual machine be in?
- if state is set to present and VM exists, ensure the VM configuration if conform to task arguments - If C(state) is set to C(present) and VM exists, ensure the VM configuration conforms to task arguments
required: True required: True
choices: ['present', 'absent', 'poweredon', 'poweredoff', 'restarted', 'suspended'] choices: ['present', 'absent', 'poweredon', 'poweredoff', 'restarted', 'suspended']
name: name:
description: description:
- Name of the newly deployed guest - Name of the VM to work with
required: True required: True
new_name: new_name:
description: description:
@ -59,20 +59,20 @@ options:
version_added: "2.3" version_added: "2.3"
name_match: name_match:
description: description:
- If multiple vms matching the name, use the first or last found - If multiple VMs matching the name, use the first or last found
required: False required: False
default: 'first' default: 'first'
choices: ['first', 'last'] choices: ['first', 'last']
uuid: uuid:
description: description:
- UUID of the instance to manage if known, this is vmware's unique identifier. - UUID of the instance to manage if known, this is VMware's unique identifier.
- This is required if name is not supplied. - This is required if name is not supplied.
required: False required: False
template: template:
description: description:
- Template used to create guest. - Template used to create VM.
- If this value is not set, VM is created without using a template. - If this value is not set, VM is created without using a template.
- If the guest exists already this setting will be ignored. - If the VM exists already this setting will be ignored.
required: False required: False
is_template: is_template:
description: description:
@ -82,7 +82,7 @@ options:
version_added: "2.3" version_added: "2.3"
folder: folder:
description: description:
- Destination folder path for the new guest - Destination folder path for the new VM
required: False required: False
hardware: hardware:
description: description:
@ -114,7 +114,8 @@ options:
version_added: "2.3" version_added: "2.3"
wait_for_ip_address: wait_for_ip_address:
description: description:
- Wait until vcenter detects an IP address for the guest - Wait until vCenter detects an IP address for the VM
- This requires vmware-tools (vmtoolsd) to properly work after creation
required: False required: False
force: force:
description: description:
@ -141,228 +142,200 @@ options:
networks: networks:
description: description:
- Network to use should include VM network name or VLAN, ip and gateway - Network to use should include VM network name or VLAN, ip and gateway
- "You can add 'mac' optional field to customize mac address" - Add an optional field C(mac) to customize mac address
- "Yan can add 'domain' optinal field to configure different dns domain on windows network interfaces" - Add an optional field C(domain) to configure a different dns domain on windows network interfaces
required: False required: False
version_added: "2.3" version_added: "2.3"
snapshot_op: snapshot_op:
description: description:
- A key, value pair of snapshot operation types and their additional required parameters. - A key, value pair of snapshot operation types and their additional required parameters.
- Beware that this functionality will disappear in v2.3 and move into module C(vmware_guest_snapshot)
required: False required: False
version_added: "2.3" version_added: "2.3"
customizations: customization:
description: description:
- "Parameters to customize template" - "Parameters to customize template"
- "Common parameters (linux/Windows):" - "Common parameters (Linux/Windows):"
- " hostname (string): Computer hostname (Default: name parameter)" - " dns_servers (list): List of DNS servers to configure"
- " domain (string)" - " dns_suffix (list): List of domain suffixes, aka DNS search path (default: C(domain) parameter)"
- " dns_servers (list)" - " domain (string): DNS domain name to use"
- " dns_suffix (list): Default: domain parameter" - " hostname (string): Computer hostname (default: C(name) parameter)"
- "Parameters related to windows customizations:" - "Parameters related to windows customization:"
- " autologon (bool): Auto logon after VM customizations (Default: False)" - " autologon (bool): Auto logon after VM customization (default: False)"
- " autologoncount (int): Number of autologon after reboot (Default: 1)" - " autologoncount (int): Number of autologon after reboot (default: 1)"
- " fullname (string): Server owner name (Mandatory)" - " domainadmin (string): User used to join in AD domain (mandatory with joindomain)"
- " orgname (string): Organisation name (Mandatory)" - " domainadminpassword (string): Password used to join in AD domain (mandatory with joindomain)"
- " timezone (int): See https://msdn.microsoft.com/en-us/library/ms912391(v=winembedded.11).aspx" - " fullname (string): Server owner name (default: Administrator)"
- " password (string): Local administrator password" - " joindomain (string): AD domain to join (Not compatible with C(joinworkgroup))"
- " productid (string): Product ID" - " joinworkgroup (string): Workgroup to join (Not compatible with C(joindomain), default: WORKGROUP)"
- " joindomain (string): AD domain to join" - " orgname (string): Organisation name (default: ACME)"
- " domainadmin (string): User used to join in AD domain (mandatory with joindomain)" - " password (string): Local administrator password (mandatory)"
- " domainadminpassword (string): Password used to join in AD domain (mandatory with joindomain)" - " productid (string): Product ID"
- " joinworkgroup (string): Workgroup to join (Not compatible with joindomain)" - " runonce (list): List of commands to run at first user logon"
- " runonce (list): Command to run at first user logon" - " timezone (int): Timezone (default: 85) See https://msdn.microsoft.com/en-us/library/ms912391(v=winembedded.11).aspx"
required: False required: False
version_added: "2.3" version_added: "2.3"
extends_documentation_fragment: vmware.documentation extends_documentation_fragment: vmware.documentation
''' '''
EXAMPLES = ''' EXAMPLES = '''
Example from Ansible playbook
#
# Create a VM from a template # Create a VM from a template
# - name: create the VM
- name: create the VM vmware_guest:
vmware_guest: hostname: 192.0.2.44
validate_certs: False username: administrator@vsphere.local
hostname: 192.0.2.44 password: vmware
username: administrator@vsphere.local validate_certs: no
password: vmware esxi_hostname: 192.0.2.117
name: testvm_2 datacenter: datacenter1
state: poweredon folder: testvms
folder: testvms name: testvm_2
guest_id: centos64guest state: poweredon
disk: guest_id: centos64guest
- size_gb: 10 disk:
type: thin - size_gb: 10
datastore: g73_datastore type: thin
hardware: datastore: g73_datastore
memory_mb: 512 hardware:
num_cpus: 1 memory_mb: 512
scsi: paravirtual num_cpus: 1
datacenter: datacenter1 scsi: paravirtual
esxi_hostname: 192.0.2.117 networks:
template: template_el7 '192.168.1.0/24':
wait_for_ip_address: yes network: VM Network
register: deploy mac: 'aa:bb:dd:aa:00:14'
template: template_el7
# wait_for_ip_address: yes
# Create a VM and flag it as a template register: deploy
#
- name: create VM template # Create a VM template
vmware_guest: - name: create a VM template
validate_certs: False vmware_guest:
hostname: 192.0.2.88 hostname: 192.0.2.88
username: administrator@vsphere.local username: administrator@vsphere.local
password: vmware password: vmware
name: testvm_6 validate_certs: no
folder: testvms datacenter: datacenter1
is_template: yes cluster: vmware_cluster_esx
guest_id: debian6_64Guest resource_pool: highperformance_pool
resource_pool: highperformance_pool folder: testvms
disk: name: testvm_6
- size_gb: 10 is_template: yes
type: thin guest_id: debian6_64Guest
datastore: g73_datastore disk:
hardware: - size_gb: 10
memory_mb: 512 type: thin
num_cpus: 1 datastore: g73_datastore
scsi: lsilogic hardware:
datacenter: datacenter1 memory_mb: 512
cluster: vmware_cluster_esx num_cpus: 1
wait_for_ip_address: yes scsi: lsilogic
register: deploy wait_for_ip_address: yes
register: deploy
#
# Clone Template
#
- name: Clone template
vmware_guest:
hostname: "192.168.1.209"
username: "administrator@vsphere.local"
password: "vmware"
validate_certs: False
name: testvm-2
datacenter: datacenter1
cluster: cluster
validate_certs: False
template: template_el7
networks:
'192.168.1.0/24':
network: 'VM Network'
mac: "aa:bb:dd:aa:00:14"
#
# Clone Template and customize # Clone Template and customize
# - name: Clone template and customize
- name: Clone template and customize vmware_guest:
vmware_guest: hostname: 192.168.1.209
hostname: "192.168.1.209" username: administrator@vsphere.local
username: "administrator@vsphere.local" password: vmware
password: "vmware" validate_certs: no
validate_certs: False datacenter: datacenter1
name: testvm-2 cluster: cluster
datacenter: datacenter1 name: testvm-2
cluster: cluster template: template_windows
validate_certs: False networks:
template: template_windows '192.168.1.0/24':
customize: True network: VM Network
networks: gateway: 192.168.1.1
'192.168.1.0/24': ip: 192.168.1.100
network: 'VM Network' mac: 'aa:bb:dd:aa:00:14'
gateway: '192.168.1.1' domain: my_domain
ip: "192.168.1.100" dns_servers:
mac: "aa:bb:dd:aa:00:14" - 192.168.1.1
domain: "my_domain" - 192.168.1.2
dns_servers: ['192.168.1.1','192.168.1.2'] customization:
customizations: autologon: True
autologon: True dns_servers:
fullname: Jack - 192.168.1.1
orgname: My_org - 192.168.1.2
password: new_vm_password domain: my_domain
dns_servers: ['192.168.1.1','192.168.1.2'] password: new_vm_password
domain: my_domain runonce:
guirunonce: - powershell.exe -ExecutionPolicy Unrestricted -File C:\Windows\Temp\Enable-WinRM.ps1 -ForceNewSSLCert
- route add -P 10.10.10.10/24 1.1.1.1
- shutdown /l
#
# Gather facts only # Gather facts only
# - name: gather the VM facts
- name: gather the VM facts vmware_guest:
vmware_guest: hostname: 192.168.1.209
validate_certs: False username: administrator@vsphere.local
hostname: 192.168.1.209 password: vmware
username: administrator@vsphere.local validate_certs: no
password: vmware name: testvm_2
name: testvm_2 esxi_hostname: 192.168.1.117
esxi_hostname: 192.168.1.117 state: gatherfacts
state: gatherfacts register: facts
register: facts
### Snapshot Operations ### Snapshot Operations
###
### BEWARE: This functionality will move into vmware_guest_snapshot before release !
# Create snapshot # Create snapshot
- vmware_guest: - vmware_guest:
hostname: 192.168.1.209 hostname: 192.168.1.209
username: administrator@vsphere.local username: administrator@vsphere.local
password: vmware password: vmware
validate_certs: False name: dummy_vm
name: dummy_vm snapshot_op:
snapshot_op: op_type: create
op_type: create name: snap1
name: snap1 description: snap1_description
description: snap1_description
# Remove a snapshot # Remove a snapshot
- vmware_guest: - vmware_guest:
hostname: 192.168.1.209 hostname: 192.168.1.209
username: administrator@vsphere.local username: administrator@vsphere.local
password: vmware password: vmware
validate_certs: False name: dummy_vm
name: dummy_vm snapshot_op:
snapshot_op: op_type: remove
op_type: remove name: snap1
name: snap1
# Revert to a snapshot # Revert to a snapshot
- vmware_guest: - vmware_guest:
hostname: 192.168.1.209 hostname: 192.168.1.209
username: administrator@vsphere.local username: administrator@vsphere.local
password: vmware password: vmware
validate_certs: False name: dummy_vm
name: dummy_vm snapshot_op:
snapshot_op: op_type: revert
op_type: revert name: snap1
name: snap1
# List all snapshots of a VM # List all snapshots of a VM
- vmware_guest: - vmware_guest:
hostname: 192.168.1.209 hostname: 192.168.1.209
username: administrator@vsphere.local username: administrator@vsphere.local
password: vmware password: vmware
validate_certs: False name: dummy_vm
name: dummy_vm snapshot_op:
snapshot_op: op_type: list_all
op_type: list_all
# List current snapshot of a VM # List current snapshot of a VM
- vmware_guest: - vmware_guest:
hostname: 192.168.1.209 hostname: 192.168.1.209
username: administrator@vsphere.local username: administrator@vsphere.local
password: vmware password: vmware
validate_certs: False name: dummy_vm
name: dummy_vm snapshot_op:
snapshot_op: op_type: list_current
op_type: list_current
# Remove all snapshots of a VM # Remove all snapshots of a VM
- vmware_guest: - vmware_guest:
hostname: 192.168.1.209 hostname: 192.168.1.209
username: administrator@vsphere.local username: administrator@vsphere.local
password: vmware password: vmware
validate_certs: False name: dummy_vm
name: dummy_vm snapshot_op:
snapshot_op: op_type: remove_all
op_type: remove_all
''' '''
RETURN = """ RETURN = """
@ -467,7 +440,7 @@ class PyVmomiDeviceHelper(object):
nic = vim.vm.device.VirtualDeviceSpec() nic = vim.vm.device.VirtualDeviceSpec()
if device_type == 'pcnet32': if device_type == 'pcnet32':
nic.device = vim.vm.device.VirtualPCNet32() nic.device = vim.vm.device.VirtualPCNet32()
if device_type == 'vmxnet2': elif device_type == 'vmxnet2':
nic.device = vim.vm.device.VirtualVmxnet2() nic.device = vim.vm.device.VirtualVmxnet2()
elif device_type == 'vmxnet3': elif device_type == 'vmxnet3':
nic.device = vim.vm.device.VirtualVmxnet3() nic.device = vim.vm.device.VirtualVmxnet3()
@ -844,7 +817,7 @@ class PyVmomiHelper(object):
if vm_creation and self.params['guest_id'] is None: if vm_creation and self.params['guest_id'] is None:
self.module.fail_json(msg="guest_id attribute is mandatory for VM creation") self.module.fail_json(msg="guest_id attribute is mandatory for VM creation")
if vm_obj is None or self.configspec.guestId != vm_obj.summary.guest.guestId: if vm_obj is None or self.params['guest_id'] != vm_obj.summary.config.guestId:
self.change_detected = True self.change_detected = True
self.configspec.guestId = self.params['guest_id'] self.configspec.guestId = self.params['guest_id']
@ -992,71 +965,76 @@ class PyVmomiHelper(object):
# https://pubs.vmware.com/vi3/sdk/ReferenceGuide/vim.vm.customization.IPSettings.html # https://pubs.vmware.com/vi3/sdk/ReferenceGuide/vim.vm.customization.IPSettings.html
if 'domain' in self.params['networks'][network]: if 'domain' in self.params['networks'][network]:
guest_map.adapter.dnsDomain = self.params['networks'][network]['domain'] guest_map.adapter.dnsDomain = self.params['networks'][network]['domain']
elif self.params['customizations'].get('domain'): elif self.params['customization'].get('domain'):
guest_map.adapter.dnsDomain = self.params['customizations']['domain'] guest_map.adapter.dnsDomain = self.params['customization']['domain']
if 'dns_servers' in self.params['networks'][network]: if 'dns_servers' in self.params['networks'][network]:
guest_map.adapter.dnsServerList = self.params['networks'][network]['dns_servers'] guest_map.adapter.dnsServerList = self.params['networks'][network]['dns_servers']
elif self.params['customizations'].get('dns_servers'): elif self.params['customization'].get('dns_servers'):
guest_map.adapter.dnsServerList = self.params['customizations']['dns_servers'] guest_map.adapter.dnsServerList = self.params['customization']['dns_servers']
adaptermaps.append(guest_map) adaptermaps.append(guest_map)
# Global DNS settings # Global DNS settings
globalip = vim.vm.customization.GlobalIPSettings() globalip = vim.vm.customization.GlobalIPSettings()
globalip.dnsServerList = self.params['customizations']['dns_servers'] if 'dns_servers' in self.params['customization']:
globalip.dnsSuffixList = self.params['customizations'].get(dns_suffix, self.params['customizations']['domain']) globalip.dnsServerList = self.params['customization'].get('dns_servers')
# TODO: Maybe list the different domains from the interfaces here by default ?
if 'dns_suffix' in self.params['customization'] or 'domain' in self.params['customization']:
globalip.dnsSuffixList = self.params['customization'].get('dns_suffix', self.params['customization']['domain'])
if self.params['guest_id']: if self.params['guest_id']:
guest_id = self.params['guest_id'] guest_id = self.params['guest_id']
else: else:
guest_id = vm_obj.summary.guest.guestId guest_id = vm_obj.summary.config.guestId
# If I install a Windows use Sysprep # If I install a Windows use Sysprep
# https://pubs.vmware.com/vi3/sdk/ReferenceGuide/vim.vm.customization.Sysprep.html#field_detail # https://pubs.vmware.com/vi3/sdk/ReferenceGuide/vim.vm.customization.Sysprep.html#field_detail
if 'windows' in guest_id: if 'win' in guest_id:
ident = vim.vm.customization.Sysprep() ident = vim.vm.customization.Sysprep()
if 'fullname' not in self.params['customizations']:
self.module.fail_json(msg="You need to define fullname to use Windows customization")
if 'orgname' not in self.params['customizations']:
self.module.fail_json(msg="You need to define orgname to use Windows customization")
ident.userData = vim.vm.customization.UserData() ident.userData = vim.vm.customization.UserData()
ident.userData.computerName = vim.vm.customization.FixedName() ident.userData.computerName = vim.vm.customization.FixedName()
ident.userData.computerName.name = self.params['customizations'].get(hostname, self.params['name']) ident.userData.computerName.name = str(self.params['customization'].get('hostname', self.params['name']))
ident.userData.fullName = str(self.params['customizations']['fullname']) ident.userData.fullName = str(self.params['customization'].get('fullname', 'Administrator'))
ident.userData.orgName = str(self.params['customizations']['orgname']) ident.userData.orgName = str(self.params['customization'].get('orgname', 'ACME'))
ident.guiUnattended = vim.vm.customization.GuiUnattended() ident.guiUnattended = vim.vm.customization.GuiUnattended()
ident.guiUnattended.autoLogon = self.params['customizations'].get(autologon, False) ident.guiUnattended.autoLogon = self.params['customization'].get('autologon', False)
ident.guiUnattended.autoLogonCount = self.params['customizations'].get(autologoncount, 1) ident.guiUnattended.autoLogonCount = self.params['customization'].get('autologoncount', 1)
ident.guiUnattended.timeZone = self.params['customization'].get('timezone', 85)
ident.identification = vim.vm.customization.Identification() ident.identification = vim.vm.customization.Identification()
if 'password' in self.params['customizations']: if self.params['customization'].get('password'):
ident.guiUnattended.password = vim.vm.customization.Password() ident.guiUnattended.password = vim.vm.customization.Password()
ident.guiUnattended.password.value = str(self.params['customizations']['password']) ident.guiUnattended.password.value = str(self.params['customization']['password'])
ident.guiUnattended.password.plainText = True ident.guiUnattended.password.plainText = True
else:
self.module.fail_json(msg="A 'password' entry is mandatory in the 'customization' section.")
if 'productid' in self.params['customizations']: if 'productid' in self.params['customization']:
ident.userData.orgName = str(self.params['customizations']['productid']) ident.userData.orgName = str(self.params['customization']['productid'])
if 'joindomain' in self.params['customizations']: if 'joindomain' in self.params['customization']:
ident.identification.domainadmin = str(self.params['customizations']['domainadmin']) # TODO: Escalate if domainAdmin and domainPassword are not provided
ident.identification.domainadminpassword = str(self.params['customizations']['domainadminpassword']) ident.identification.domainAdmin = str(self.params['customization'].get('domainadmin'))
ident.identification.joindomain = str(self.params['customizations']['joindomain']) ident.identification.domainAdminPassword = str(self.params['customization'].get('domainadminpassword'))
elif 'joinworkgroup' in self.params['customizations']: ident.identification.joinDomain = str(self.params['customization'].get('joindomain'))
ident.identification.joinworkgroup = str(self.params['customizations']['joinworkgroup']) elif 'joinworkgroup' in self.params['customization']:
ident.identification.joinWorkgroup = str(self.params['customization'].get('joinworkgroup'))
if 'runonce' in self.params['customizations']: if 'runonce' in self.params['customization']:
ident.guiRunOnce = vim.vm.customization.GuiRunOnce() ident.guiRunOnce = vim.vm.customization.GuiRunOnce()
ident.guiRunOnce.commandList = self.params['customizations']['runonce'] ident.guiRunOnce.commandList = self.params['customization']['runonce']
else: else:
# Else use LinuxPrep # Else use LinuxPrep
# https://pubs.vmware.com/vi3/sdk/ReferenceGuide/vim.vm.customization.LinuxPrep.html # https://pubs.vmware.com/vi3/sdk/ReferenceGuide/vim.vm.customization.LinuxPrep.html
ident = vim.vm.customization.LinuxPrep() ident = vim.vm.customization.LinuxPrep()
ident.domain = str(self.params['customizations']['domain']) # TODO: Maybe add domain from interface if missing ?
if 'domain' in self.params['customization']:
ident.domain = str(self.params['customization'].get('domain'))
ident.hostName = vim.vm.customization.FixedName() ident.hostName = vim.vm.customization.FixedName()
ident.hostName.name = self.params['customizations'].get(hostname, self.params['name']) ident.hostName.name = str(self.params['customization'].get('hostname', self.params['name']))
self.customspec = vim.vm.customization.Specification() self.customspec = vim.vm.customization.Specification()
self.customspec.nicSettingMap = adaptermaps self.customspec.nicSettingMap = adaptermaps
@ -1161,7 +1139,7 @@ class PyVmomiHelper(object):
# VMWare doesn't allow to reduce disk sizes # VMWare doesn't allow to reduce disk sizes
if kb < diskspec.device.capacityInKB: if kb < diskspec.device.capacityInKB:
self.module.fail_json( self.module.fail_json(
msg="given disk size is lesser than found (%d < %d). Reducing disks is not allowed." % msg="Given disk size is lesser than found (%d < %d). Reducing disks is not allowed." %
(kb, diskspec.device.capacityInKB)) (kb, diskspec.device.capacityInKB))
if kb != diskspec.device.capacityInKB or disk_modified: if kb != diskspec.device.capacityInKB or disk_modified:
@ -1280,7 +1258,7 @@ class PyVmomiHelper(object):
# - multiple templates by the same name # - multiple templates by the same name
# - static IPs # - static IPs
datacenters = get_all_objs(self.content, [vim.Datacenter]) #datacenters = get_all_objs(self.content, [vim.Datacenter])
datacenter = get_obj(self.content, [vim.Datacenter], self.params['datacenter']) datacenter = get_obj(self.content, [vim.Datacenter], self.params['datacenter'])
if not datacenter: if not datacenter:
self.module.fail_json(msg='No datacenter named %(datacenter)s was found' % self.params) self.module.fail_json(msg='No datacenter named %(datacenter)s was found' % self.params)
@ -1321,7 +1299,8 @@ class PyVmomiHelper(object):
self.configure_cpu_and_memory(vm_obj=vm_obj, vm_creation=True) self.configure_cpu_and_memory(vm_obj=vm_obj, vm_creation=True)
self.configure_disks(vm_obj=vm_obj) self.configure_disks(vm_obj=vm_obj)
self.configure_network(vm_obj=vm_obj) self.configure_network(vm_obj=vm_obj)
if self.should_deploy_from_template() and len(self.params['customizations']) > 0:
if len(self.params['customization']) > 0:
self.customize_vm(vm_obj=vm_obj) self.customize_vm(vm_obj=vm_obj)
try: try:
@ -1332,9 +1311,8 @@ class PyVmomiHelper(object):
relospec.datastore = datastore relospec.datastore = datastore
relospec.pool = resource_pool relospec.pool = resource_pool
clonespec = vim.vm.CloneSpec(template=self.params['is_template'], clonespec = vim.vm.CloneSpec(template=self.params['is_template'], location=relospec)
location=relospec) if self.customspec:
if len(self.params['customizations']) > 0:
clonespec.customization = self.customspec clonespec.customization = self.customspec
clonespec.config = self.configspec clonespec.config = self.configspec
@ -1768,7 +1746,7 @@ def main():
wait_for_ip_address=dict(required=False, type='bool', default=True), wait_for_ip_address=dict(required=False, type='bool', default=True),
networks=dict(required=False, type='dict', default={}), networks=dict(required=False, type='dict', default={}),
resource_pool=dict(required=False, type='str', default=None), resource_pool=dict(required=False, type='str', default=None),
customizations=dict(required=False, type='dict', no_log=True, default={}) customization=dict(required=False, type='dict', no_log=True, default={}),
), ),
supports_check_mode=True, supports_check_mode=True,
mutually_exclusive=[ mutually_exclusive=[
@ -1787,10 +1765,6 @@ def main():
module.params['folder'] = '/vm%(folder)s' % module.params module.params['folder'] = '/vm%(folder)s' % module.params
module.params['folder'] = module.params['folder'].rstrip('/') module.params['folder'] = module.params['folder'].rstrip('/')
# Fail check, customizations require template to be defined
if len(module.params['customizations']) > 0 and not module.params['template']:
module.fail_json(msg="customizations option is only valid when template option is defined")
pyv = PyVmomiHelper(module) pyv = PyVmomiHelper(module)
# Check if the VM exists before continuing # Check if the VM exists before continuing
vm = pyv.getvm(name=module.params['name'], vm = pyv.getvm(name=module.params['name'],
@ -1834,7 +1808,7 @@ def main():
# Create it ... # Create it ...
result = pyv.deploy_vm() result = pyv.deploy_vm()
elif module.params['state'] == 'gatherfacts': elif module.params['state'] == 'gatherfacts':
module.fail_json(msg="Unable to gather facts for inexistant VM %s" % module.params['name']) module.fail_json(msg="Unable to gather facts for non-existing VM %(name)s" % module.params)
if 'failed' not in result: if 'failed' not in result:
result['failed'] = False result['failed'] = False

Loading…
Cancel
Save