mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
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
This commit is contained in:
parent
0937196df1
commit
aca60f1776
1 changed files with 216 additions and 242 deletions
|
@ -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
|
||||||
|
register: deploy
|
||||||
|
|
||||||
#
|
# Create a VM template
|
||||||
# Create a VM and flag it as a template
|
- name: create a VM template
|
||||||
#
|
vmware_guest:
|
||||||
- name: create VM template
|
hostname: 192.0.2.88
|
||||||
vmware_guest:
|
username: administrator@vsphere.local
|
||||||
validate_certs: False
|
password: vmware
|
||||||
hostname: 192.0.2.88
|
validate_certs: no
|
||||||
username: administrator@vsphere.local
|
datacenter: datacenter1
|
||||||
password: vmware
|
cluster: vmware_cluster_esx
|
||||||
name: testvm_6
|
resource_pool: highperformance_pool
|
||||||
folder: testvms
|
folder: testvms
|
||||||
is_template: yes
|
name: testvm_6
|
||||||
guest_id: debian6_64Guest
|
is_template: yes
|
||||||
resource_pool: highperformance_pool
|
guest_id: debian6_64Guest
|
||||||
disk:
|
disk:
|
||||||
- size_gb: 10
|
- size_gb: 10
|
||||||
type: thin
|
type: thin
|
||||||
datastore: g73_datastore
|
datastore: g73_datastore
|
||||||
hardware:
|
hardware:
|
||||||
memory_mb: 512
|
memory_mb: 512
|
||||||
num_cpus: 1
|
num_cpus: 1
|
||||||
scsi: lsilogic
|
scsi: lsilogic
|
||||||
datacenter: datacenter1
|
wait_for_ip_address: yes
|
||||||
cluster: vmware_cluster_esx
|
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…
Add table
Reference in a new issue