From 57f6abdb8460f8501eb9668004f4d7722bda5570 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Sat, 12 May 2018 21:09:53 +0530 Subject: [PATCH] VMware: new module: vmware_host_powerstate (#36577) Signed-off-by: Abhijeet Kasurde --- .../cloud/vmware/vmware_host_powerstate.py | 227 ++++++++++++++++++ .../targets/vmware_host_powerstate/aliases | 2 + .../vmware_host_powerstate/tasks/main.yml | 62 +++++ 3 files changed, 291 insertions(+) create mode 100644 lib/ansible/modules/cloud/vmware/vmware_host_powerstate.py create mode 100644 test/integration/targets/vmware_host_powerstate/aliases create mode 100644 test/integration/targets/vmware_host_powerstate/tasks/main.yml diff --git a/lib/ansible/modules/cloud/vmware/vmware_host_powerstate.py b/lib/ansible/modules/cloud/vmware/vmware_host_powerstate.py new file mode 100644 index 00000000000..d7765d90b7d --- /dev/null +++ b/lib/ansible/modules/cloud/vmware/vmware_host_powerstate.py @@ -0,0 +1,227 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2018, Ansible Project +# Copyright: (c) 2018, Abhijeet Kasurde +# +# 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 = r''' +--- +module: vmware_host_powerstate +short_description: Manages power states of host systems in vCenter +description: +- This module can be used to manage power states of host systems in given vCenter infrastructure. +- User can set power state to 'power-down-to-standby', 'power-up-from-standby', 'shutdown-host' and 'reboot-host'. +- State 'reboot-host', 'shutdown-host' and 'power-down-to-standby' are not supported by all the host systems. +version_added: 2.6 +author: +- Abhijeet Kasurde (@akasurde) +requirements: +- python >= 2.6 +- PyVmomi +options: + state: + description: + - Set the state of the host system. + choices: [ 'power-down-to-standby', 'power-up-from-standby', 'shutdown-host', 'reboot-host' ] + default: 'shutdown-host' + esxi_hostname: + description: + - Name of the host system to work with. + - This is required parameter if C(cluster_name) is not specified. + cluster_name: + description: + - Name of the cluster from which all host systems will be used. + - This is required parameter if C(esxi_hostname) is not specified. + force: + description: + - 'This parameter specify if the host should be proceeding with user defined powerstate + regardless of whether it is in maintenance mode.' + - 'If C(state) set to C(reboot-host) and C(force) as C(true), then host system is rebooted regardless of whether it is in maintenance mode.' + - 'If C(state) set to C(shutdown-host) and C(force) as C(true), then host system is shutdown regardless of whether it is in maintenance mode.' + - 'If C(state) set to C(power-down-to-standby) and C(force) to C(true), then all powered off VMs will evacuated.' + - 'Not applicable if C(state) set to C(power-up-from-standby).' + type: bool + default: False + timeout: + description: + - 'This parameter defines timeout for C(state) set to C(power-down-to-standby) or C(power-up-from-standby).' + - 'Ignored if C(state) set to C(reboot-host) or C(shutdown-host).' + - 'This parameter is defined in seconds.' + default: 600 +extends_documentation_fragment: vmware.documentation +''' + +EXAMPLES = r''' +- name: Set the state of a host system to reboot + vmware_host_powerstate: + hostname: 192.0.2.44 + username: administrator@vsphere.local + password: vmware + validate_certs: no + esxi_hostname: esxi01 + state: reboot-host + delegate_to: localhost + register: reboot_host + +- name: Set the state of a host system to power down to standby + vmware_host_powerstate: + hostname: 192.0.2.44 + username: administrator@vsphere.local + password: vmware + validate_certs: no + esxi_hostname: power-down-to-standby + state: power-down-to-standby + delegate_to: localhost + register: power_down + +- name: Set the state of all host systems from cluster to reboot + vmware_host_powerstate: + hostname: 192.0.2.44 + username: administrator@vsphere.local + password: vmware + validate_certs: no + cluster_name: DC0_C0 + state: reboot-host + delegate_to: localhost + register: reboot_host + +''' + +RETURN = r''' +result: + description: metadata about host system's state + returned: always + type: dict + sample: { + "esxi01": { + "msg": "power down 'esxi01' to standby", + "error": "", + }, + } +''' + +try: + from pyVmomi import vim, vmodl +except ImportError: + pass + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.vmware import PyVmomi, vmware_argument_spec, wait_for_task, TaskError +from ansible.module_utils._text import to_native + + +class VmwareHostPowerManager(PyVmomi): + def __init__(self, module): + super(VmwareHostPowerManager, self).__init__(module) + cluster_name = self.params.get('cluster_name') + esxi_host_name = self.params.get('esxi_hostname') + self.hosts = self.get_all_host_objs(cluster_name=cluster_name, esxi_host_name=esxi_host_name) + if not self.hosts: + self.module.fail_json(msg="Failed to find host system with given configuration.") + + def ensure(self): + """ + Function to manage internal state of host system + + """ + results = dict(changed=False, result=dict()) + state = self.params.get('state') + force = self.params.get('force') + timeout = self.params.get('timeout') + host_change_list = [] + for host in self.hosts: + changed = False + if not host.runtime.inMaintenanceMode and not force: + self.module.fail_json(msg="Current host system '%s' is not in maintenance mode," + " please specify 'force' as True to proceed." % host.name) + if host.runtime.connectionState == 'notResponding': + self.module.fail_json(msg="Current host system '%s' can not be set in '%s'" + " mode as the host system is not responding." % (host.name, state)) + + results['result'][host.name] = dict(msg='', error='') + if state == 'reboot-host' and not host.capability.rebootSupported: + self.module.fail_json(msg="Current host '%s' can not be rebooted as the host system" + " does not have capability to reboot." % host.name) + elif state == 'shutdown-host' and not host.capability.shutdownSupported: + self.module.fail_json(msg="Current host '%s' can not be shut down as the host system" + " does not have capability to shut down." % host.name) + elif state in ['power-down-to-standby', 'power-up-from-standby'] and not host.capability.standbySupported: + self.module.fail_json(msg="Current host '%s' can not be '%s' as the host system" + " does not have capability to standby supported." % (host.name, state)) + + if state == 'reboot-host': + task = host.RebootHost_Task(force) + verb = "reboot '%s'" % host.name + elif state == 'shutdown-host': + task = host.ShutdownHost_Task(force) + verb = "shutdown '%s'" % host.name + elif state == 'power-down-to-standby': + task = host.PowerDownHostToStandBy_Task(timeout, force) + verb = "power down '%s' to standby" % host.name + elif state == 'power-up-from-standby': + task = host.PowerUpHostFromStandBy_Task(timeout) + verb = "power up '%s' from standby" % host.name + + if not self.module.check_mode: + try: + success, result = wait_for_task(task) + if success: + changed = True + results['result'][host.name]['msg'] = verb + else: + results['result'][host.name]['error'] = result + except TaskError as task_error: + self.module.fail_json(msg="Failed to %s as host system due to : %s" % (verb, + str(task_error))) + except Exception as generic_exc: + self.module.fail_json(msg="Failed to %s due to generic exception : %s" % (host.name, + to_native(generic_exc))) + else: + # Check mode + changed = True + results['result'][host.name]['msg'] = verb + + host_change_list.append(changed) + + if any(host_change_list): + results['changed'] = True + self.module.exit_json(**results) + + +def main(): + argument_spec = vmware_argument_spec() + argument_spec.update( + state=dict(type='str', default='shutdown-host', + choices=['power-down-to-standby', 'power-up-from-standby', 'shutdown-host', 'reboot-host']), + esxi_hostname=dict(type='str', required=False), + cluster_name=dict(type='str', required=False), + force=dict(type='bool', default=False), + timeout=dict(type='int', default=600), + + ) + + module = AnsibleModule(argument_spec=argument_spec, + supports_check_mode=True, + required_one_of=[ + ['cluster_name', 'esxi_hostname'], + ] + ) + + host_power_manager = VmwareHostPowerManager(module) + host_power_manager.ensure() + + +if __name__ == '__main__': + main() diff --git a/test/integration/targets/vmware_host_powerstate/aliases b/test/integration/targets/vmware_host_powerstate/aliases new file mode 100644 index 00000000000..845e8a6dad5 --- /dev/null +++ b/test/integration/targets/vmware_host_powerstate/aliases @@ -0,0 +1,2 @@ +cloud/vcenter +unsupported diff --git a/test/integration/targets/vmware_host_powerstate/tasks/main.yml b/test/integration/targets/vmware_host_powerstate/tasks/main.yml new file mode 100644 index 00000000000..a2d9047b370 --- /dev/null +++ b/test/integration/targets/vmware_host_powerstate/tasks/main.yml @@ -0,0 +1,62 @@ +# Test code for the vmware_host_powerstate module. +# Copyright: (c) 2018, Abhijeet Kasurde +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# TODO: vcsim does not support Powerstate related to operations +- name: store the vcenter container ip + set_fact: + vcsim: "{{ lookup('env', 'vcenter_host') }}" + +- debug: var=vcsim + +- name: Wait for Flask controller to come up online + wait_for: + host: "{{ vcsim }}" + port: 5000 + state: started + +- name: kill vcsim + uri: + url: http://{{ vcsim }}:5000/killall + +- name: start vcsim + uri: + url: http://{{ vcsim }}:5000/spawn?cluster=2 + register: vcsim_instance + +- debug: + var: vcsim_instance + +- name: Wait for vcsim server to come up online + wait_for: + host: "{{ vcsim }}" + port: 443 + state: started + +- name: get a list of hosts from vcsim + uri: + url: http://{{ vcsim }}:5000/govc_find?filter=H + register: hosts + +- name: get a host + set_fact: + host1: "{{ hosts.json[0] | basename }}" + +- debug: var=host1 + +- name: Restart Host + vmware_host_powerstate: + hostname: "{{ vcsim }}" + username: "{{ vcsim_instance.json.username }}" + password: "{{ vcsim_instance.json.password }}" + validate_certs: False + state: power-down-to-standby + esxi_hostname: "{{ host1 }}" + force: True + register: host_powerstate + +- debug: var=host_powerstate + +- assert: + that: + - host_powerstate.results is changed