Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a VM DRS Override module #2229

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions meta/runtime.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ action_groups:
- vmware_drs_group
- vmware_drs_group_info
- vmware_drs_group_manager
- vmware_drs_override
- vmware_drs_rule_info
- vmware_dvs_host
- vmware_dvs_portgroup
Expand Down
150 changes: 150 additions & 0 deletions plugins/modules/vmware_drs_override.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

DOCUMENTATION = '''
---
module: vmware_drs_override
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:
hostname:
description:
- The hostname or IP address of the vCenter server.
required: true
type: str
username:
description:
- The username for vCenter authentication.
required: true
type: str
password:
description:
- The password for vCenter authentication.
required: true
type: str
port:
description:
- The port number for the vCenter server.
required: false
type: int
default: 443
validate_certs:
description:
- If C(false), SSL certificates will not be validated.
type: bool
default: False
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
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
'''

from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.vmware.plugins.module_utils.vmware import (
PyVmomi,
vmware_argument_spec,
)
from pyVmomi import vim, vmodl


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)
self.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 wait_for_task(self, task):
while task.info.state == vim.TaskInfo.State.running:
pass
if task.info.state == vim.TaskInfo.State.success:
return task.info.result
else:
raise Exception("Task failed: %s" % task.info.error.localizedMessage)


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()
3 changes: 3 additions & 0 deletions tests/integration/targets/vmware_drs_override/aliases
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 tests/integration/targets/vmware_drs_override/tasks/main.yml
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