-
Notifications
You must be signed in to change notification settings - Fork 339
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a VM DRS Override module (#2229)
Fixes #2026 SUMMARY This PR contains a new Ansible module, vmware_drs_override, to the community.vmware collection. The module allows users to configure Distributed Resource Scheduler (DRS) behavior overrides for individual VMs within a VMware vSphere cluster. This provides users with enhanced control over VM placement, resource allocation, and automation behavior by enabling DRS settings specific to each VM rather than relying solely on cluster-wide configurations. Key design decisions include: Encapsulating functionality in a class to streamline the connection, VM lookup, and DRS configuration processes. Ensuring the module aligns with other community.vmware modules in terms of structure, error handling, and documentation. ISSUE TYPE New Module Pull Request COMPONENT NAME vmware_drs_override ADDITIONAL INFORMATION The vmware_drs_override module provides the following parameters: hostname, username, password, and port for vCenter server access. validate_certs to handle SSL verification. vm_name and drs_behavior to specify the VM and desired DRS configuration (options include manual, partiallyAutomated, and fullyAutomated). This module was tested using a local vCenter environment to verify correct DRS behavior application and task handling. Example playbook and command output are provided below to demonstrate module functionality. # Example playbook: - name: Test VMware DRS Override Module hosts: localhost gather_facts: false tasks: - name: Apply DRS override to VM community.vmware.vmware_drs_override: hostname: "vcenter.example.com" username: "[email protected]" password: "yourpassword" port: 443 validate_certs: False vm_name: "my_vm_name" drs_behavior: "manual" register: result - name: Show Result debug: var: result Reviewed-by: Alexander Nikitin <[email protected]> Reviewed-by: svg1007 Reviewed-by: Mario Lenz <[email protected]>
- Loading branch information
Showing
4 changed files
with
206 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
#!/usr/bin/python | ||
# -*- coding: utf-8 -*- | ||
|
||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
# SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
DOCUMENTATION = ''' | ||
--- | ||
module: vmware_drs_override | ||
version_added: '5.2.0' | ||
short_description: Configure DRS behavior for a specific VM in vSphere | ||
description: | ||
- This module allows setting a DRS behavior override for individual VMs within a DRS-enabled VMware vSphere cluster. | ||
options: | ||
vm_name: | ||
description: | ||
- Name of the VM for which the DRS override is set. | ||
required: true | ||
type: str | ||
drs_behavior: | ||
description: | ||
- Desired DRS behavior for the VM. | ||
choices: ['manual', 'partiallyAutomated', 'fullyAutomated'] | ||
default: 'manual' | ||
type: str | ||
extends_documentation_fragment: | ||
- community.vmware.vmware.documentation | ||
author: | ||
- Sergey Goncharov (@svg1007) | ||
''' | ||
|
||
EXAMPLES = ''' | ||
- name: Set DRS behavior for a VM | ||
vmware_drs_override: | ||
hostname: "vcenter.example.com" | ||
username: "[email protected]" | ||
password: "yourpassword" | ||
port: 443 | ||
validate_certs: False | ||
vm_name: "my_vm_name" | ||
drs_behavior: "manual" | ||
''' | ||
|
||
RETURN = ''' | ||
changed: | ||
description: Whether the DRS behavior was changed. | ||
type: bool | ||
returned: always | ||
msg: | ||
description: A message describing the outcome of the task. | ||
type: str | ||
returned: always | ||
''' | ||
|
||
try: | ||
from pyVmomi import vim, vmodl | ||
except ImportError: | ||
pass | ||
|
||
from ansible.module_utils.basic import AnsibleModule | ||
from ansible_collections.community.vmware.plugins.module_utils.vmware import vmware_argument_spec, wait_for_task, PyVmomi | ||
|
||
|
||
class VmwareDrsOverride(PyVmomi): | ||
def __init__(self, module): | ||
super(VmwareDrsOverride, self).__init__(module) | ||
self.vm_name = self.params.get('vm_name', None) | ||
self.drs_behavior = module.params['drs_behavior'] | ||
self.params['name'] = self.vm_name | ||
self.vm = self.get_vm() | ||
if not self.vm: | ||
self.module.fail_json(msg="VM '%s' not found." % self.vm_name) | ||
|
||
if not self.is_vcenter(): | ||
self.module.fail_json(msg="DRS configuration is only supported in vCenter environments.") | ||
|
||
def set_drs_override(self): | ||
cluster = self.vm.runtime.host.parent | ||
|
||
# Check current DRS settings | ||
existing_config = next((config for config in cluster.configuration.drsVmConfig if config.key == self.vm), None) | ||
if existing_config and existing_config.behavior == self.drs_behavior: | ||
self.module.exit_json(changed=False, msg="DRS behavior is already set to the desired state.") | ||
|
||
# Create DRS VM config spec | ||
drs_vm_config_spec = vim.cluster.DrsVmConfigSpec( | ||
operation='add', | ||
info=vim.cluster.DrsVmConfigInfo( | ||
key=self.vm, | ||
enabled=True, | ||
behavior=self.drs_behavior | ||
) | ||
) | ||
|
||
# Apply the cluster reconfiguration | ||
cluster_config_spec = vim.cluster.ConfigSpec() | ||
cluster_config_spec.drsVmConfigSpec = [drs_vm_config_spec] | ||
try: | ||
task = cluster.ReconfigureCluster_Task(spec=cluster_config_spec, modify=True) | ||
wait_for_task(task) | ||
self.module.exit_json(changed=True, msg="DRS override applied successfully.") | ||
except vmodl.MethodFault as error: | ||
self.module.fail_json(msg="Failed to set DRS override: %s" % error.msg) | ||
|
||
|
||
def main(): | ||
argument_spec = vmware_argument_spec() | ||
argument_spec.update(dict( | ||
vm_name=dict(type='str', required=True), | ||
drs_behavior=dict(type='str', choices=['manual', 'partiallyAutomated', 'fullyAutomated'], default='manual') | ||
)) | ||
|
||
module = AnsibleModule( | ||
argument_spec=argument_spec, | ||
supports_check_mode=True | ||
) | ||
|
||
drs_override = VmwareDrsOverride(module) | ||
drs_override.set_drs_override() | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
cloud/vcenter | ||
needs/target/prepare_vmware_tests | ||
zuul/vmware/vcenter_1esxi |
79 changes: 79 additions & 0 deletions
79
tests/integration/targets/vmware_drs_override/tasks/main.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
# Test code for the vmware_drs_override module | ||
|
||
- import_role: | ||
name: prepare_vmware_tests | ||
vars: | ||
setup_attach_host: true | ||
setup_virtualmachines: true | ||
|
||
# Gather information about available VMs | ||
- name: Get info about available VMs | ||
vmware_vm_info: | ||
validate_certs: false | ||
hostname: "{{ vcenter_hostname }}" | ||
username: "{{ vcenter_username }}" | ||
password: "{{ vcenter_password }}" | ||
register: vm_info | ||
|
||
- name: Set fact for the first VM name | ||
set_fact: | ||
first_vm_name: "{{ vm_info.virtual_machines[0].guest_name }}" | ||
|
||
# Test case: Add DRS Override - DRS enabled | ||
- name: Add DRS override 'manual' for a VM in a DRS-enabled cluster | ||
vmware_drs_override: | ||
validate_certs: false | ||
hostname: "{{ vcenter_hostname }}" | ||
username: "{{ vcenter_username }}" | ||
password: "{{ vcenter_password }}" | ||
vm_name: "{{ first_vm_name }}" | ||
drs_behavior: "manual" | ||
register: drs_override_result | ||
when: drs_enabled is defined and drs_enabled | ||
|
||
- name: Assert DRS override applied successfully | ||
assert: | ||
that: | ||
- drs_override_result.changed == true | ||
- "'DRS override applied successfully' in drs_override_result.msg" | ||
when: drs_enabled is defined and drs_enabled | ||
|
||
# Test case: Ensure proper error for standalone ESXi without DRS | ||
- name: Attempt to add DRS override for VM in a non-DRS environment | ||
vmware_drs_override: | ||
validate_certs: false | ||
hostname: "{{ standalone_esxi_hostname }}" | ||
username: "{{ esxi_username }}" | ||
password: "{{ esxi_password }}" | ||
vm_name: "{{ first_vm_name }}" | ||
drs_behavior: "manual" | ||
register: drs_override_non_drs_result | ||
ignore_errors: true | ||
when: standalone_esxi_hostname is defined | ||
|
||
- name: Assert error for non-DRS environment | ||
assert: | ||
that: | ||
- drs_override_non_drs_result.failed == true | ||
- "'DRS configuration is only supported in vCenter environments' in drs_override_non_drs_result.msg" | ||
when: standalone_esxi_hostname is defined | ||
|
||
# Test case: Check behavior for a vCenter cluster with DRS disabled | ||
- name: Attempt to add DRS override for VM in a vCenter cluster with DRS disabled | ||
vmware_drs_override: | ||
validate_certs: false | ||
hostname: "{{ vcenter_hostname }}" | ||
username: "{{ vcenter_username }}" | ||
password: "{{ vcenter_password }}" | ||
vm_name: "{{ first_vm_name }}" | ||
drs_behavior: "manual" | ||
register: drs_override_drs_disabled_result | ||
ignore_errors: true | ||
when: drs_disabled is defined and drs_disabled | ||
|
||
- name: Assert error for DRS-disabled cluster | ||
assert: | ||
that: | ||
- drs_override_drs_disabled_result.failed == true | ||
- "'DRS is not enabled on the cluster' in drs_override_drs_disabled_result.msg" | ||
when: drs_disabled is defined and drs_disabled |