|
|
@ -1,16 +1,18 @@
|
|
|
|
#!/usr/bin/python
|
|
|
|
#!/usr/bin/python
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
# Copyright: (c) 2015, VMware, Inc.
|
|
|
|
# (c) 2015, VMware, Inc.
|
|
|
|
# Copyright: (c) 2018, Ansible Project
|
|
|
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
|
|
# 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
|
|
|
|
from __future__ import absolute_import, division, print_function
|
|
|
|
__metaclass__ = type
|
|
|
|
__metaclass__ = type
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
|
|
ANSIBLE_METADATA = {
|
|
|
|
|
|
|
|
'metadata_version': '1.1',
|
|
|
|
'status': ['preview'],
|
|
|
|
'status': ['preview'],
|
|
|
|
'supported_by': 'community'}
|
|
|
|
'supported_by': 'community'
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DOCUMENTATION = '''
|
|
|
|
DOCUMENTATION = '''
|
|
|
@ -18,23 +20,25 @@ DOCUMENTATION = '''
|
|
|
|
module: vmware_maintenancemode
|
|
|
|
module: vmware_maintenancemode
|
|
|
|
short_description: Place a host into maintenance mode
|
|
|
|
short_description: Place a host into maintenance mode
|
|
|
|
description:
|
|
|
|
description:
|
|
|
|
- Place an ESXI host into maintenance mode
|
|
|
|
- This module can be used for placing a ESXi host into maintenance mode.
|
|
|
|
- Support for VSAN compliant maintenance mode when selected
|
|
|
|
- Support for VSAN compliant maintenance mode when selected.
|
|
|
|
author: "Jay Jahns <jjahns@vmware.com>"
|
|
|
|
author:
|
|
|
|
|
|
|
|
- "Jay Jahns <jjahns@vmware.com>"
|
|
|
|
|
|
|
|
- "Abhijeet Kasurde (@akasurde)"
|
|
|
|
version_added: "2.1"
|
|
|
|
version_added: "2.1"
|
|
|
|
notes:
|
|
|
|
notes:
|
|
|
|
- Tested on vSphere 5.5 and 6.0
|
|
|
|
- Tested on vSphere 5.5, 6.0 and 6.5
|
|
|
|
requirements:
|
|
|
|
requirements:
|
|
|
|
- "python >= 2.6"
|
|
|
|
- "python >= 2.6"
|
|
|
|
- PyVmomi
|
|
|
|
- PyVmomi
|
|
|
|
options:
|
|
|
|
options:
|
|
|
|
esxi_hostname:
|
|
|
|
esxi_hostname:
|
|
|
|
description:
|
|
|
|
description:
|
|
|
|
- Name of the host as defined in vCenter
|
|
|
|
- Name of the host as defined in vCenter.
|
|
|
|
required: True
|
|
|
|
required: True
|
|
|
|
vsan_mode:
|
|
|
|
vsan_mode:
|
|
|
|
description:
|
|
|
|
description:
|
|
|
|
- Specify which VSAN compliant mode to enter
|
|
|
|
- Specify which VSAN compliant mode to enter.
|
|
|
|
choices:
|
|
|
|
choices:
|
|
|
|
- 'ensureObjectAccessibility'
|
|
|
|
- 'ensureObjectAccessibility'
|
|
|
|
- 'evacuateAllData'
|
|
|
|
- 'evacuateAllData'
|
|
|
@ -42,7 +46,7 @@ options:
|
|
|
|
required: False
|
|
|
|
required: False
|
|
|
|
evacuate:
|
|
|
|
evacuate:
|
|
|
|
description:
|
|
|
|
description:
|
|
|
|
- If True, evacuate all powered off VMs
|
|
|
|
- If True, evacuate all powered off VMs.
|
|
|
|
choices:
|
|
|
|
choices:
|
|
|
|
- True
|
|
|
|
- True
|
|
|
|
- False
|
|
|
|
- False
|
|
|
@ -50,12 +54,12 @@ options:
|
|
|
|
required: False
|
|
|
|
required: False
|
|
|
|
timeout:
|
|
|
|
timeout:
|
|
|
|
description:
|
|
|
|
description:
|
|
|
|
- Specify a timeout for the operation
|
|
|
|
- Specify a timeout for the operation.
|
|
|
|
required: False
|
|
|
|
required: False
|
|
|
|
default: 0
|
|
|
|
default: 0
|
|
|
|
state:
|
|
|
|
state:
|
|
|
|
description:
|
|
|
|
description:
|
|
|
|
- Enter or exit maintenance mode
|
|
|
|
- Enter or exit maintenance mode.
|
|
|
|
choices:
|
|
|
|
choices:
|
|
|
|
- present
|
|
|
|
- present
|
|
|
|
- absent
|
|
|
|
- absent
|
|
|
@ -66,8 +70,7 @@ extends_documentation_fragment: vmware.documentation
|
|
|
|
|
|
|
|
|
|
|
|
EXAMPLES = '''
|
|
|
|
EXAMPLES = '''
|
|
|
|
- name: Enter VSAN-Compliant Maintenance Mode
|
|
|
|
- name: Enter VSAN-Compliant Maintenance Mode
|
|
|
|
local_action:
|
|
|
|
vmware_maintenancemode:
|
|
|
|
module: vmware_maintenancemode
|
|
|
|
|
|
|
|
hostname: vc_host
|
|
|
|
hostname: vc_host
|
|
|
|
username: vc_user
|
|
|
|
username: vc_user
|
|
|
|
password: vc_pass
|
|
|
|
password: vc_pass
|
|
|
@ -77,6 +80,7 @@ EXAMPLES = '''
|
|
|
|
timeout: 3600
|
|
|
|
timeout: 3600
|
|
|
|
state: present
|
|
|
|
state: present
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
RETURN = '''
|
|
|
|
RETURN = '''
|
|
|
|
hostsystem:
|
|
|
|
hostsystem:
|
|
|
|
description: Name of vim reference
|
|
|
|
description: Name of vim reference
|
|
|
@ -97,109 +101,96 @@ status:
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
from pyVmomi import vim
|
|
|
|
from pyVmomi import vim
|
|
|
|
HAS_PYVMOMI = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
except ImportError:
|
|
|
|
except ImportError:
|
|
|
|
HAS_PYVMOMI = False
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
from ansible.module_utils.basic import AnsibleModule
|
|
|
|
from ansible.module_utils.basic import AnsibleModule
|
|
|
|
from ansible.module_utils.vmware import (HAS_PYVMOMI, TaskError, connect_to_api, find_hostsystem_by_name,
|
|
|
|
from ansible.module_utils.vmware import PyVmomi, TaskError, vmware_argument_spec, wait_for_task
|
|
|
|
vmware_argument_spec, wait_for_task)
|
|
|
|
from ansible.module_utils._text import to_native
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def EnterMaintenanceMode(module, host):
|
|
|
|
class VmwareMaintenanceMgr(PyVmomi):
|
|
|
|
|
|
|
|
def __init__(self, module):
|
|
|
|
if host.runtime.inMaintenanceMode:
|
|
|
|
super(VmwareMaintenanceMgr, self).__init__(module)
|
|
|
|
module.exit_json(
|
|
|
|
self.esxi_hostname = self.module.params.get('esxi_hostname')
|
|
|
|
changed=False,
|
|
|
|
self.vsan = self.module.params.get('vsan', None)
|
|
|
|
hostsystem=str(host),
|
|
|
|
self.host = self.find_hostsystem_by_name(host_name=self.esxi_hostname)
|
|
|
|
hostname=module.params['esxi_hostname'],
|
|
|
|
if not self.host:
|
|
|
|
|
|
|
|
self.module.fail_json(msg='Host %s not found in vCenter' % self.esxi_hostname)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def EnterMaintenanceMode(self):
|
|
|
|
|
|
|
|
if self.host.runtime.inMaintenanceMode:
|
|
|
|
|
|
|
|
self.module.exit_json(changed=False,
|
|
|
|
|
|
|
|
hostsystem=str(self.host),
|
|
|
|
|
|
|
|
hostname=self.esxi_hostname,
|
|
|
|
status='NO_ACTION',
|
|
|
|
status='NO_ACTION',
|
|
|
|
msg='Host already in maintenance mode')
|
|
|
|
msg='Host %s already in maintenance mode' % self.esxi_hostname)
|
|
|
|
|
|
|
|
|
|
|
|
spec = vim.host.MaintenanceSpec()
|
|
|
|
spec = vim.host.MaintenanceSpec()
|
|
|
|
|
|
|
|
|
|
|
|
if module.params['vsan']:
|
|
|
|
if self.vsan:
|
|
|
|
spec.vsanMode = vim.vsan.host.DecommissionMode()
|
|
|
|
spec.vsanMode = vim.vsan.host.DecommissionMode()
|
|
|
|
spec.vsanMode.objectAction = module.params['vsan']
|
|
|
|
spec.vsanMode.objectAction = self.vsan
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
task = host.EnterMaintenanceMode_Task(
|
|
|
|
task = self.host.EnterMaintenanceMode_Task(self.module.params['timeout'],
|
|
|
|
module.params['timeout'],
|
|
|
|
self.module.params['evacuate'],
|
|
|
|
module.params['evacuate'],
|
|
|
|
|
|
|
|
spec)
|
|
|
|
spec)
|
|
|
|
|
|
|
|
|
|
|
|
success, result = wait_for_task(task)
|
|
|
|
success, result = wait_for_task(task)
|
|
|
|
|
|
|
|
|
|
|
|
return dict(changed=success,
|
|
|
|
self.module.exit_json(changed=success,
|
|
|
|
hostsystem=str(host),
|
|
|
|
hostsystem=str(self.host),
|
|
|
|
hostname=module.params['esxi_hostname'],
|
|
|
|
hostname=self.esxi_hostname,
|
|
|
|
status='ENTER',
|
|
|
|
status='ENTER',
|
|
|
|
msg='Host entered maintenance mode')
|
|
|
|
msg='Host %s entered maintenance mode' % self.esxi_hostname)
|
|
|
|
|
|
|
|
|
|
|
|
except TaskError:
|
|
|
|
except TaskError as e:
|
|
|
|
module.fail_json(
|
|
|
|
self.module.fail_json(msg='Host %s failed to enter maintenance mode due to %s' % (self.esxi_hostname, to_native(e)))
|
|
|
|
msg='Host failed to enter maintenance mode')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def ExitMaintenanceMode(self):
|
|
|
|
def ExitMaintenanceMode(module, host):
|
|
|
|
if not self.host.runtime.inMaintenanceMode:
|
|
|
|
if not host.runtime.inMaintenanceMode:
|
|
|
|
self.module.exit_json(changed=False,
|
|
|
|
module.exit_json(
|
|
|
|
hostsystem=str(self.host),
|
|
|
|
changed=False,
|
|
|
|
hostname=self.esxi_hostname,
|
|
|
|
hostsystem=str(host),
|
|
|
|
|
|
|
|
hostname=module.params['esxi_hostname'],
|
|
|
|
|
|
|
|
status='NO_ACTION',
|
|
|
|
status='NO_ACTION',
|
|
|
|
msg='Host not in maintenance mode')
|
|
|
|
msg='Host %s not in maintenance mode' % self.esxi_hostname)
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
task = host.ExitMaintenanceMode_Task(
|
|
|
|
task = self.host.ExitMaintenanceMode_Task(self.module.params['timeout'])
|
|
|
|
module.params['timeout'])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
success, result = wait_for_task(task)
|
|
|
|
success, result = wait_for_task(task)
|
|
|
|
|
|
|
|
|
|
|
|
return dict(changed=success,
|
|
|
|
self.module.exit_json(changed=success,
|
|
|
|
hostsystem=str(host),
|
|
|
|
hostsystem=str(self.host),
|
|
|
|
hostname=module.params['esxi_hostname'],
|
|
|
|
hostname=self.esxi_hostname,
|
|
|
|
status='EXIT',
|
|
|
|
status='EXIT',
|
|
|
|
msg='Host exited maintenance mode')
|
|
|
|
msg='Host %s exited maintenance mode' % self.esxi_hostname)
|
|
|
|
|
|
|
|
except TaskError as e:
|
|
|
|
except TaskError:
|
|
|
|
self.module.fail_json(msg='Host %s failed to exit maintenance mode due to %s' % (self.esxi_hostname, to_native(e)))
|
|
|
|
module.fail_json(
|
|
|
|
|
|
|
|
msg='Host failed to exit maintenance mode')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
def main():
|
|
|
|
spec = vmware_argument_spec()
|
|
|
|
spec = vmware_argument_spec()
|
|
|
|
spec.update(dict(
|
|
|
|
spec.update(dict(esxi_hostname=dict(type='str', required=True),
|
|
|
|
esxi_hostname=dict(required=True),
|
|
|
|
vsan=dict(type='str', choices=['ensureObjectAccessibility',
|
|
|
|
vsan=dict(required=False, choices=['ensureObjectAccessibility',
|
|
|
|
|
|
|
|
'evacuateAllData',
|
|
|
|
'evacuateAllData',
|
|
|
|
'noAction']),
|
|
|
|
'noAction']
|
|
|
|
evacuate=dict(required=False, type='bool', default=False),
|
|
|
|
),
|
|
|
|
timeout=dict(required=False, default=0, type='int'),
|
|
|
|
evacuate=dict(type='bool', default=False),
|
|
|
|
state=dict(required=False,
|
|
|
|
timeout=dict(default=0, type='int'),
|
|
|
|
default='present',
|
|
|
|
state=dict(required=False, default='present', choices=['present', 'absent'])
|
|
|
|
choices=['present', 'absent'])))
|
|
|
|
)
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
module = AnsibleModule(argument_spec=spec)
|
|
|
|
module = AnsibleModule(argument_spec=spec)
|
|
|
|
|
|
|
|
|
|
|
|
if not HAS_PYVMOMI:
|
|
|
|
host_maintenance_mgr = VmwareMaintenanceMgr(module=module)
|
|
|
|
module.fail_json(msg='pyvmomi is required for this module')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
content = connect_to_api(module)
|
|
|
|
|
|
|
|
host = find_hostsystem_by_name(content, module.params['esxi_hostname'])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if not host:
|
|
|
|
|
|
|
|
module.fail_json(
|
|
|
|
|
|
|
|
msg='Host not found in vCenter')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if module.params['state'] == 'present':
|
|
|
|
if module.params['state'] == 'present':
|
|
|
|
result = EnterMaintenanceMode(module, host)
|
|
|
|
host_maintenance_mgr.EnterMaintenanceMode()
|
|
|
|
|
|
|
|
|
|
|
|
elif module.params['state'] == 'absent':
|
|
|
|
elif module.params['state'] == 'absent':
|
|
|
|
result = ExitMaintenanceMode(module, host)
|
|
|
|
host_maintenance_mgr.ExitMaintenanceMode()
|
|
|
|
|
|
|
|
|
|
|
|
module.exit_json(**result)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
if __name__ == '__main__':
|
|
|
|