VMware: add new module vmware_guest_video (#50590)
This commit is contained in:
parent
d59bc9ae48
commit
955e960f45
1 changed files with 326 additions and 0 deletions
326
lib/ansible/modules/cloud/vmware/vmware_guest_video.py
Normal file
326
lib/ansible/modules/cloud/vmware/vmware_guest_video.py
Normal file
|
@ -0,0 +1,326 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright: (c) 2018, Ansible Project
|
||||
# Copyright: (c) 2018, Diane Wang <dianew@vmware.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_video
|
||||
short_description: Modify video card configurations of specified virtual machine in given vCenter infrastructure
|
||||
description:
|
||||
- This module is used to reconfigure video card settings of given virtual machine.
|
||||
- All parameters and VMware object names are case sensitive.
|
||||
version_added: '2.8'
|
||||
author:
|
||||
- Diane Wang (@Tomorrow9) <dianew@vmware.com>
|
||||
notes:
|
||||
- Tested on vSphere 6.0, 6.5 and 6.7
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
- PyVmomi
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Name of the virtual machine.
|
||||
- This is a required parameter, if parameter C(uuid) is not supplied.
|
||||
uuid:
|
||||
description:
|
||||
- UUID of the instance to gather facts if known, this is VMware's unique identifier.
|
||||
- This is a required parameter, if parameter C(name) is not supplied.
|
||||
folder:
|
||||
description:
|
||||
- Destination folder, absolute or relative path to find an existing guest.
|
||||
- This is a required parameter, only if multiple VMs are found with same name.
|
||||
- The folder should include the datacenter. ESXi server's datacenter is ha-datacenter.
|
||||
- 'Examples:'
|
||||
- ' folder: /ha-datacenter/vm'
|
||||
- ' folder: ha-datacenter/vm'
|
||||
- ' folder: /datacenter1/vm'
|
||||
- ' folder: datacenter1/vm'
|
||||
- ' folder: /datacenter1/vm/folder1'
|
||||
- ' folder: datacenter1/vm/folder1'
|
||||
- ' folder: /folder1/datacenter1/vm'
|
||||
- ' folder: folder1/datacenter1/vm'
|
||||
- ' folder: /folder1/datacenter1/vm/folder2'
|
||||
datacenter:
|
||||
default: ha-datacenter
|
||||
description:
|
||||
- The datacenter name to which virtual machine belongs to.
|
||||
- This parameter is case sensitive.
|
||||
gather_video_facts:
|
||||
description:
|
||||
- If set to True, return settings of the video card, other attributes are ignored.
|
||||
- If set to False, will do reconfiguration and return video card settings.
|
||||
type: bool
|
||||
default: 'no'
|
||||
use_auto_detect:
|
||||
description:
|
||||
- 'If set to True, applies common video settings to the guest operating system, attributes C(display_number) and C(video_memory_mb) are ignored.'
|
||||
- 'If set to False, the number of display and the total video memory will be reconfigured using C(display_number) and C(video_memory_mb).'
|
||||
type: bool
|
||||
display_number:
|
||||
description:
|
||||
- The number of display. Valid value from 1 to 10. The maximum display number is 4 on vCenter 6.0, 6.5 web UI.
|
||||
video_memory_mb:
|
||||
description:
|
||||
- 'Valid total MB of video memory range of virtual machine is from 1.172 MB to 256 MB on ESXi 6.7U1,
|
||||
from 1.172 MB to 128 MB on ESXi 6.7 and previous versions.'
|
||||
- For specific guest OS, supported minimum and maximum video memory are different, please be careful on setting this.
|
||||
enable_3D:
|
||||
description:
|
||||
- Enable 3D for guest operating systems on which VMware supports 3D.
|
||||
type: bool
|
||||
renderer_3D:
|
||||
description:
|
||||
- 'If set to C(automatic), selects the appropriate option (software or hardware) for this virtual machine automatically.'
|
||||
- 'If set to C(software), uses normal CPU processing for 3D calculations.'
|
||||
- 'If set to C(hardware), requires graphics hardware (GPU) for faster 3D calculations.'
|
||||
choices: [ automatic, software, hardware ]
|
||||
memory_3D_mb:
|
||||
description:
|
||||
- The value of 3D Memory must be power of 2 and valid value is from 32 MB to 2048 MB.
|
||||
extends_documentation_fragment: vmware.documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Change video card settings of virtual machine
|
||||
vmware_guest_video:
|
||||
hostname: "{{ vcenter_hostname }}"
|
||||
username: "{{ vcenter_username }}"
|
||||
password: "{{ vcenter_password }}"
|
||||
datacenter: "{{ datacenter_name }}"
|
||||
validate_certs: no
|
||||
name: test-vm
|
||||
gather_video_facts: false
|
||||
use_auto_detect: false
|
||||
display_number: 2
|
||||
video_memory_mb: 8.0
|
||||
enable_3D: true
|
||||
renderer_3D: automatic
|
||||
memory_3D_mb: 512
|
||||
delegate_to: localhost
|
||||
register: video_facts
|
||||
'''
|
||||
|
||||
RETURN = """
|
||||
video_status:
|
||||
description: metadata about the virtual machine's video card after managing them
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
"auto_detect": false,
|
||||
"display_number": 2,
|
||||
"enable_3D_support": true,
|
||||
"memory_3D": 524288,
|
||||
"renderer_3D": "automatic",
|
||||
"video_memory": 8192
|
||||
}
|
||||
"""
|
||||
|
||||
try:
|
||||
from pyVmomi import vim
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
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, wait_for_task
|
||||
|
||||
|
||||
class PyVmomiHelper(PyVmomi):
|
||||
def __init__(self, module):
|
||||
super(PyVmomiHelper, self).__init__(module)
|
||||
self.change_detected = False
|
||||
self.config_spec = vim.vm.ConfigSpec()
|
||||
self.config_spec.deviceChange = []
|
||||
self.video_card_facts = None
|
||||
|
||||
@staticmethod
|
||||
def is_power_of_2(num):
|
||||
return num != 0 and ((num & (num - 1)) == 0)
|
||||
|
||||
def gather_video_card_facts(self, vm_obj):
|
||||
"""
|
||||
Gather facts about VM's video card settings
|
||||
Args:
|
||||
vm_obj: Managed object of virtual machine
|
||||
Returns: Video Card device and a list of dict video card configuration
|
||||
"""
|
||||
video_facts = dict()
|
||||
video_card = None
|
||||
for device in vm_obj.config.hardware.device:
|
||||
if isinstance(device, vim.vm.device.VirtualVideoCard):
|
||||
video_card = device
|
||||
video_facts = dict(
|
||||
auto_detect=device.useAutoDetect,
|
||||
display_number=device.numDisplays,
|
||||
video_memory=device.videoRamSizeInKB,
|
||||
enable_3D_support=device.enable3DSupport,
|
||||
renderer_3D=device.use3dRenderer,
|
||||
memory_3D=device.graphicsMemorySizeInKB,
|
||||
)
|
||||
break
|
||||
return video_card, video_facts
|
||||
|
||||
def get_video_card_spec(self, vm_obj):
|
||||
"""
|
||||
Get device changes of virtual machine
|
||||
Args:
|
||||
vm_obj: Managed object of virtual machine
|
||||
Returns: virtual device spec
|
||||
"""
|
||||
video_card, video_card_facts = self.gather_video_card_facts(vm_obj)
|
||||
self.video_card_facts = video_card_facts
|
||||
if video_card is None:
|
||||
self.module.fail_json(msg='Not get video card device of specified virtual machine.')
|
||||
video_spec = vim.vm.device.VirtualDeviceSpec()
|
||||
video_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit
|
||||
video_spec.device = video_card
|
||||
auto_detect = False
|
||||
enabled_3d = False
|
||||
|
||||
if self.params['gather_video_facts']:
|
||||
return None
|
||||
if self.params['use_auto_detect'] is not None:
|
||||
if video_card_facts['auto_detect'] and self.params['use_auto_detect']:
|
||||
auto_detect = True
|
||||
elif not video_card_facts['auto_detect'] and self.params['use_auto_detect']:
|
||||
video_spec.device.useAutoDetect = True
|
||||
self.change_detected = True
|
||||
auto_detect = True
|
||||
elif video_card_facts['auto_detect'] and not self.params['use_auto_detect']:
|
||||
video_spec.device.useAutoDetect = False
|
||||
self.change_detected = True
|
||||
else:
|
||||
if video_card_facts['auto_detect']:
|
||||
auto_detect = True
|
||||
# useAutoDetect set to False then display number and video memory config can be changed
|
||||
if not auto_detect:
|
||||
if self.params['display_number'] is not None:
|
||||
if self.params['display_number'] < 1:
|
||||
self.module.fail_json(msg="display_number attribute valid value: 1-10.")
|
||||
if self.params['display_number'] != video_card_facts['display_number']:
|
||||
video_spec.device.numDisplays = self.params['display_number']
|
||||
self.change_detected = True
|
||||
|
||||
if self.params['video_memory_mb'] is not None:
|
||||
if self.params['video_memory_mb'] < 1.172:
|
||||
self.module.fail_json(msg="video_memory_mb attribute valid value: ESXi 6.7U1(1.172-256 MB),"
|
||||
"ESXi 6.7/6.5/6.0(1.172-128 MB).")
|
||||
if int(self.params['video_memory_mb'] * 1024) != video_card_facts['video_memory']:
|
||||
video_spec.device.videoRamSizeInKB = int(self.params['video_memory_mb'] * 1024)
|
||||
self.change_detected = True
|
||||
else:
|
||||
if self.params['display_number'] is not None or self.params['video_memory_mb'] is not None:
|
||||
self.module.fail_json(msg="display_number and video_memory_mb can not be changed if use_auto_detect is true.")
|
||||
# useAutoDetect value not control 3D config
|
||||
if self.params['enable_3D'] is not None:
|
||||
if self.params['enable_3D'] != video_card_facts['enable_3D_support']:
|
||||
video_spec.device.enable3DSupport = self.params['enable_3D']
|
||||
self.change_detected = True
|
||||
if self.params['enable_3D']:
|
||||
enabled_3d = True
|
||||
else:
|
||||
if video_card_facts['enable_3D_support']:
|
||||
enabled_3d = True
|
||||
else:
|
||||
if video_card_facts['enable_3D_support']:
|
||||
enabled_3d = True
|
||||
# 3D is enabled then 3D memory and renderer method can be set
|
||||
if enabled_3d:
|
||||
if self.params['renderer_3D'] is not None:
|
||||
renderer = self.params['renderer_3D'].lower()
|
||||
if renderer not in ['automatic', 'software', 'hardware']:
|
||||
self.module.fail_json(msg="renderer_3D attribute valid value: automatic, software, hardware.")
|
||||
if renderer != video_card_facts['renderer_3D']:
|
||||
video_spec.device.use3dRenderer = renderer
|
||||
self.change_detected = True
|
||||
if self.params['memory_3D_mb'] is not None:
|
||||
memory_3d = self.params['memory_3D_mb']
|
||||
if not self.is_power_of_2(memory_3d):
|
||||
self.module.fail_json(msg="memory_3D_mb attribute should be an integer value and power of 2(32-2048).")
|
||||
else:
|
||||
if memory_3d < 32 or memory_3d > 2048:
|
||||
self.module.fail_json(msg="memory_3D_mb attribute should be an integer value and power of 2(32-2048).")
|
||||
if memory_3d * 1024 != video_card_facts['memory_3D']:
|
||||
video_spec.device.graphicsMemorySizeInKB = memory_3d * 1024
|
||||
self.change_detected = True
|
||||
else:
|
||||
if self.params['renderer_3D'] is not None or self.params['memory_3D_mb'] is not None:
|
||||
self.module.fail_json(msg='3D renderer or 3D memory can not be configured if 3D is not enabled.')
|
||||
if not self.change_detected:
|
||||
return None
|
||||
return video_spec
|
||||
|
||||
def reconfigure_vm_video(self, vm_obj):
|
||||
"""
|
||||
Reconfigure video card settings of virtual machine
|
||||
Args:
|
||||
vm_obj: Managed object of virtual machine
|
||||
Returns: Reconfigure results
|
||||
"""
|
||||
video_card_spec = self.get_video_card_spec(vm_obj)
|
||||
if video_card_spec is None:
|
||||
return {'changed': False, 'failed': False, 'instance': self.video_card_facts}
|
||||
self.config_spec.deviceChange.append(video_card_spec)
|
||||
try:
|
||||
task = vm_obj.ReconfigVM_Task(spec=self.config_spec)
|
||||
wait_for_task(task)
|
||||
except vim.fault.InvalidDeviceSpec as invalid_device_spec:
|
||||
self.module.fail_json(msg="Failed to configure video card on given virtual machine due to invalid"
|
||||
" device spec : %s" % (to_native(invalid_device_spec.msg)),
|
||||
details="Please check ESXi server logs for more details.")
|
||||
except vim.fault.RestrictedVersion as e:
|
||||
self.module.fail_json(msg="Failed to reconfigure virtual machine due to"
|
||||
" product versioning restrictions: %s" % to_native(e.msg))
|
||||
if task.info.state == 'error':
|
||||
return {'changed': self.change_detected, 'failed': True, 'msg': task.info.error.msg}
|
||||
video_card_facts = self.gather_video_card_facts(vm_obj)[1]
|
||||
return {'changed': self.change_detected, 'failed': False, 'instance': video_card_facts}
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = vmware_argument_spec()
|
||||
argument_spec.update(
|
||||
name=dict(type='str'),
|
||||
uuid=dict(type='str'),
|
||||
folder=dict(type='str'),
|
||||
datacenter=dict(type='str', default='ha-datacenter'),
|
||||
gather_video_facts=dict(type='bool', default=False),
|
||||
use_auto_detect=dict(type='bool'),
|
||||
display_number=dict(type='int'),
|
||||
video_memory_mb=dict(type='float'),
|
||||
enable_3D=dict(type='bool'),
|
||||
renderer_3D=dict(type='str', choices=['automatic', 'software', 'hardware']),
|
||||
memory_3D_mb=dict(type='int'),
|
||||
)
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
required_one_of=[['name', 'uuid']])
|
||||
pyv = PyVmomiHelper(module)
|
||||
vm = pyv.get_vm()
|
||||
if not vm:
|
||||
module.fail_json(msg='Unable to find the specified virtual machine : %s' % (module.params.get('uuid') or module.params.get('name')))
|
||||
|
||||
vm_facts = pyv.gather_facts(vm)
|
||||
vm_power_state = vm_facts['hw_power_status'].lower()
|
||||
if vm_power_state != 'poweredoff':
|
||||
module.fail_json(msg='VM state should be poweredoff to reconfigure video card settings.')
|
||||
result = pyv.reconfigure_vm_video(vm_obj=vm)
|
||||
if result['failed']:
|
||||
module.fail_json(**result)
|
||||
else:
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in a new issue