mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-06-04 07:19:10 -07:00
Some users have problems using the VMware modules because they use the vCenter as target, and Ansible uses SSH to connect to the targets. Eventually we need to update the VMware guide to explain how the modules work, but the first fix is to update the examples. (We should backport to v2.6 and v2.5 too)
337 lines
12 KiB
Python
337 lines
12 KiB
Python
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
#
|
|
# Copyright: (c) 2018, Ansible Project
|
|
# Copyright: (c) 2018, Abhijeet Kasurde <akasurde@redhat.com>
|
|
#
|
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
|
|
from __future__ import absolute_import, division, print_function
|
|
__metaclass__ = type
|
|
|
|
ANSIBLE_METADATA = {
|
|
'metadata_version': '1.1',
|
|
'status': ['preview'],
|
|
'supported_by': 'community'
|
|
}
|
|
|
|
DOCUMENTATION = '''
|
|
---
|
|
module: vmware_guest_boot_manager
|
|
short_description: Manage boot options for the given virtual machine
|
|
description:
|
|
- This module can be used to manage boot options for the given virtual machine.
|
|
version_added: 2.7
|
|
author:
|
|
- Abhijeet Kasurde (@Akasurde) <akasurde@redhat.com>
|
|
notes:
|
|
- Tested on vSphere 6.5
|
|
requirements:
|
|
- "python >= 2.6"
|
|
- PyVmomi
|
|
options:
|
|
name:
|
|
description:
|
|
- Name of the VM to work with.
|
|
- This is required if C(uuid) parameter is not supplied.
|
|
uuid:
|
|
description:
|
|
- UUID of the instance to manage if known, this is VMware's BIOS UUID.
|
|
- This is required if C(name) parameter is not supplied.
|
|
boot_order:
|
|
description:
|
|
- List of the boot devices.
|
|
default: []
|
|
name_match:
|
|
description:
|
|
- If multiple virtual machines matching the name, use the first or last found.
|
|
default: 'first'
|
|
choices: ['first', 'last']
|
|
boot_delay:
|
|
description:
|
|
- Delay in milliseconds before starting the boot sequence.
|
|
default: 0
|
|
enter_bios_setup:
|
|
description:
|
|
- If set to C(True), the virtual machine automatically enters BIOS setup the next time it boots.
|
|
- The virtual machine resets this flag, so that the machine boots proceeds normally.
|
|
type: 'bool'
|
|
default: False
|
|
boot_retry_enabled:
|
|
description:
|
|
- If set to C(True), the virtual machine that fails to boot, will try to boot again after C(boot_retry_delay) is expired.
|
|
- If set to C(False), the virtual machine waits indefinitely for user intervention.
|
|
type: 'bool'
|
|
default: False
|
|
boot_retry_delay:
|
|
description:
|
|
- Specify the time in milliseconds between virtual machine boot failure and subsequent attempt to boot again.
|
|
- If set, will automatically set C(boot_retry_enabled) to C(True) as this parameter is required.
|
|
default: 0
|
|
boot_firmware:
|
|
description:
|
|
- Choose which firmware should be used to boot the virtual machine.
|
|
choices: ["bios", "efi"]
|
|
extends_documentation_fragment: vmware.documentation
|
|
'''
|
|
|
|
EXAMPLES = r'''
|
|
- name: Change virtual machine's boot order and related parameters
|
|
vmware_guest_boot_manager:
|
|
hostname: "{{ vcenter_server }}"
|
|
username: "{{ vcenter_user }}"
|
|
password: "{{ vcenter_pass }}"
|
|
name: testvm
|
|
boot_delay: 2000
|
|
enter_bios_setup: True
|
|
boot_retry_enabled: True
|
|
boot_retry_delay: 22300
|
|
boot_firmware: bios
|
|
boot_order:
|
|
- floppy
|
|
- cdrom
|
|
- ethernet
|
|
- disk
|
|
delegate_to: localhost
|
|
register: vm_boot_order
|
|
'''
|
|
|
|
RETURN = r"""
|
|
vm_boot_status:
|
|
description: metadata about boot order of virtual machine
|
|
returned: always
|
|
type: dict
|
|
sample: {
|
|
"current_boot_order": [
|
|
"floppy",
|
|
"disk",
|
|
"ethernet",
|
|
"cdrom"
|
|
],
|
|
"current_boot_delay": 2000,
|
|
"current_boot_retry_delay": 22300,
|
|
"current_boot_retry_enabled": true,
|
|
"current_enter_bios_setup": true,
|
|
"current_boot_firmware": "bios",
|
|
"previous_boot_delay": 10,
|
|
"previous_boot_retry_delay": 10000,
|
|
"previous_boot_retry_enabled": true,
|
|
"previous_enter_bios_setup": false,
|
|
"previous_boot_firmware": "bios",
|
|
"previous_boot_order": [
|
|
"ethernet",
|
|
"cdrom",
|
|
"floppy",
|
|
"disk"
|
|
],
|
|
}
|
|
"""
|
|
|
|
|
|
from ansible.module_utils.basic import AnsibleModule
|
|
from ansible.module_utils._text import to_native
|
|
from ansible.module_utils.vmware import PyVmomi, vmware_argument_spec, find_vm_by_id, wait_for_task, TaskError
|
|
|
|
try:
|
|
from pyVmomi import vim
|
|
except ImportError:
|
|
pass
|
|
|
|
|
|
class VmBootManager(PyVmomi):
|
|
def __init__(self, module):
|
|
super(VmBootManager, self).__init__(module)
|
|
self.name = self.params['name']
|
|
self.uuid = self.params['uuid']
|
|
self.vm = None
|
|
|
|
def _get_vm(self):
|
|
vms = []
|
|
|
|
if self.uuid:
|
|
vm_obj = find_vm_by_id(self.content, vm_id=self.uuid, vm_id_type="uuid")
|
|
if vm_obj is None:
|
|
self.module.fail_json(msg="Failed to find the virtual machine with UUID : %s" % self.uuid)
|
|
vms = [vm_obj]
|
|
|
|
elif self.name:
|
|
objects = self.get_managed_objects_properties(vim_type=vim.VirtualMachine, properties=['name'])
|
|
for temp_vm_object in objects:
|
|
if temp_vm_object.obj.name == self.name:
|
|
vms.append(temp_vm_object.obj)
|
|
|
|
if vms:
|
|
if self.params.get('name_match') == 'first':
|
|
self.vm = vms[0]
|
|
elif self.params.get('name_match') == 'last':
|
|
self.vm = vms[-1]
|
|
else:
|
|
self.module.fail_json(msg="Failed to find virtual machine using %s" % (self.name or self.uuid))
|
|
|
|
@staticmethod
|
|
def humanize_boot_order(boot_order):
|
|
results = []
|
|
for device in boot_order:
|
|
if isinstance(device, vim.vm.BootOptions.BootableCdromDevice):
|
|
results.append('cdrom')
|
|
elif isinstance(device, vim.vm.BootOptions.BootableDiskDevice):
|
|
results.append('disk')
|
|
elif isinstance(device, vim.vm.BootOptions.BootableEthernetDevice):
|
|
results.append('ethernet')
|
|
elif isinstance(device, vim.vm.BootOptions.BootableFloppyDevice):
|
|
results.append('floppy')
|
|
return results
|
|
|
|
def ensure(self):
|
|
self._get_vm()
|
|
|
|
valid_device_strings = ['cdrom', 'disk', 'ethernet', 'floppy']
|
|
|
|
boot_order_list = []
|
|
for device_order in self.params.get('boot_order'):
|
|
if device_order not in valid_device_strings:
|
|
self.module.fail_json(msg="Invalid device found [%s], please specify device from ['%s']" % (device_order,
|
|
"', '".join(valid_device_strings)))
|
|
if device_order == 'cdrom':
|
|
first_cdrom = [device for device in self.vm.config.hardware.device if isinstance(device, vim.vm.device.VirtualCdrom)]
|
|
if first_cdrom:
|
|
boot_order_list.append(vim.vm.BootOptions.BootableCdromDevice())
|
|
elif device_order == 'disk':
|
|
first_hdd = [device for device in self.vm.config.hardware.device if isinstance(device, vim.vm.device.VirtualDisk)]
|
|
if first_hdd:
|
|
boot_order_list.append(vim.vm.BootOptions.BootableDiskDevice(deviceKey=first_hdd[0].key))
|
|
elif device_order == 'ethernet':
|
|
first_ether = [device for device in self.vm.config.hardware.device if isinstance(device, vim.vm.device.VirtualEthernetCard)]
|
|
if first_ether:
|
|
boot_order_list.append(vim.vm.BootOptions.BootableEthernetDevice(deviceKey=first_ether[0].key))
|
|
elif device_order == 'floppy':
|
|
first_floppy = [device for device in self.vm.config.hardware.device if isinstance(device, vim.vm.device.VirtualFloppy)]
|
|
if first_floppy:
|
|
boot_order_list.append(vim.vm.BootOptions.BootableFloppyDevice())
|
|
|
|
change_needed = False
|
|
kwargs = dict()
|
|
if len(boot_order_list) != len(self.vm.config.bootOptions.bootOrder):
|
|
kwargs.update({'bootOrder': boot_order_list})
|
|
change_needed = True
|
|
else:
|
|
for i in range(0, len(boot_order_list)):
|
|
boot_device_type = type(boot_order_list[i])
|
|
vm_boot_device_type = type(self.vm.config.bootOptions.bootOrder[i])
|
|
if boot_device_type != vm_boot_device_type:
|
|
kwargs.update({'bootOrder': boot_order_list})
|
|
change_needed = True
|
|
|
|
if self.vm.config.bootOptions.bootDelay != self.params.get('boot_delay'):
|
|
kwargs.update({'bootDelay': self.params.get('boot_delay')})
|
|
change_needed = True
|
|
|
|
if self.vm.config.bootOptions.enterBIOSSetup != self.params.get('enter_bios_setup'):
|
|
kwargs.update({'enterBIOSSetup': self.params.get('enter_bios_setup')})
|
|
change_needed = True
|
|
|
|
if self.vm.config.bootOptions.bootRetryEnabled != self.params.get('boot_retry_enabled'):
|
|
kwargs.update({'bootRetryEnabled': self.params.get('boot_retry_enabled')})
|
|
change_needed = True
|
|
|
|
if self.vm.config.bootOptions.bootRetryDelay != self.params.get('boot_retry_delay'):
|
|
if not self.vm.config.bootOptions.bootRetryEnabled:
|
|
kwargs.update({'bootRetryEnabled': True})
|
|
kwargs.update({'bootRetryDelay': self.params.get('boot_retry_delay')})
|
|
change_needed = True
|
|
|
|
boot_firmware_required = False
|
|
if self.vm.config.firmware != self.params.get('boot_firmware'):
|
|
change_needed = True
|
|
boot_firmware_required = True
|
|
|
|
changed = False
|
|
results = dict(
|
|
previous_boot_order=self.humanize_boot_order(self.vm.config.bootOptions.bootOrder),
|
|
previous_boot_delay=self.vm.config.bootOptions.bootDelay,
|
|
previous_enter_bios_setup=self.vm.config.bootOptions.enterBIOSSetup,
|
|
previous_boot_retry_enabled=self.vm.config.bootOptions.bootRetryEnabled,
|
|
previous_boot_retry_delay=self.vm.config.bootOptions.bootRetryDelay,
|
|
previous_boot_firmware=self.vm.config.firmware,
|
|
current_boot_order=[],
|
|
)
|
|
|
|
if change_needed:
|
|
vm_conf = vim.vm.ConfigSpec()
|
|
vm_conf.bootOptions = vim.vm.BootOptions(**kwargs)
|
|
if boot_firmware_required:
|
|
vm_conf.firmware = self.params.get('boot_firmware')
|
|
task = self.vm.ReconfigVM_Task(vm_conf)
|
|
|
|
try:
|
|
changed, result = wait_for_task(task)
|
|
except TaskError as e:
|
|
self.module.fail_json(msg="Failed to perform reconfigure virtual"
|
|
" machine %s for boot order due to: %s" % (self.name or self.uuid,
|
|
to_native(e)))
|
|
|
|
results.update(
|
|
{
|
|
'current_boot_order': self.humanize_boot_order(self.vm.config.bootOptions.bootOrder),
|
|
'current_boot_delay': self.vm.config.bootOptions.bootDelay,
|
|
'current_enter_bios_setup': self.vm.config.bootOptions.enterBIOSSetup,
|
|
'current_boot_retry_enabled': self.vm.config.bootOptions.bootRetryEnabled,
|
|
'current_boot_retry_delay': self.vm.config.bootOptions.bootRetryDelay,
|
|
'current_boot_firmware': self.vm.config.firmware,
|
|
}
|
|
)
|
|
|
|
self.module.exit_json(changed=changed, vm_boot_status=results)
|
|
|
|
|
|
def main():
|
|
argument_spec = vmware_argument_spec()
|
|
argument_spec.update(
|
|
name=dict(type='str'),
|
|
uuid=dict(type='str'),
|
|
boot_order=dict(
|
|
type='list',
|
|
default=[],
|
|
),
|
|
name_match=dict(
|
|
choices=['first', 'last'],
|
|
default='first'
|
|
),
|
|
boot_delay=dict(
|
|
type='int',
|
|
default=0,
|
|
),
|
|
enter_bios_setup=dict(
|
|
type='bool',
|
|
default=False,
|
|
),
|
|
boot_retry_enabled=dict(
|
|
type='bool',
|
|
default=False,
|
|
),
|
|
boot_retry_delay=dict(
|
|
type='int',
|
|
default=0,
|
|
),
|
|
boot_firmware=dict(
|
|
type='str',
|
|
choices=['efi', 'bios'],
|
|
)
|
|
)
|
|
|
|
module = AnsibleModule(
|
|
argument_spec=argument_spec,
|
|
required_one_of=[
|
|
['name', 'uuid']
|
|
],
|
|
mutually_exclusive=[
|
|
['name', 'uuid']
|
|
],
|
|
)
|
|
|
|
pyv = VmBootManager(module)
|
|
pyv.ensure()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|