1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3
4# Copyright: (c) 2018, Abhijeet Kasurde <akasurde@redhat.com>
5# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
6
7from __future__ import absolute_import, division, print_function
8__metaclass__ = type
9
10ANSIBLE_METADATA = {
11    'metadata_version': '1.1',
12    'status': ['preview'],
13    'supported_by': 'community'
14}
15
16DOCUMENTATION = r'''
17---
18module: vmware_host_lockdown
19short_description: Manage administrator permission for the local administrative account for the ESXi host
20description:
21- This module can be used to manage administrator permission for the local administrative account for the host when ESXi hostname is given.
22- All parameters and VMware objects values are case sensitive.
23- This module is destructive as administrator permission are managed using APIs used, please read options carefully and proceed.
24- Please specify C(hostname) as vCenter IP or hostname only, as lockdown operations are not possible from standalone ESXi server.
25version_added: '2.5'
26author:
27- Abhijeet Kasurde (@Akasurde)
28notes:
29- Tested on vSphere 6.5
30requirements:
31- python >= 2.6
32- PyVmomi
33options:
34  cluster_name:
35    description:
36    - Name of cluster.
37    - All host systems from given cluster used to manage lockdown.
38    - Required parameter, if C(esxi_hostname) is not set.
39    type: str
40  esxi_hostname:
41    description:
42    - List of ESXi hostname to manage lockdown.
43    - Required parameter, if C(cluster_name) is not set.
44    - See examples for specifications.
45    type: list
46  state:
47    description:
48    - State of hosts system
49    - If set to C(present), all host systems will be set in lockdown mode.
50    - If host system is already in lockdown mode and set to C(present), no action will be taken.
51    - If set to C(absent), all host systems will be removed from lockdown mode.
52    - If host system is already out of lockdown mode and set to C(absent), no action will be taken.
53    default: present
54    choices: [ present, absent ]
55    version_added: 2.5
56    type: str
57extends_documentation_fragment: vmware.documentation
58'''
59
60EXAMPLES = r'''
61- name: Enter host system into lockdown mode
62  vmware_host_lockdown:
63    hostname: '{{ vcenter_hostname }}'
64    username: '{{ vcenter_username }}'
65    password: '{{ vcenter_password }}'
66    esxi_hostname: '{{ esxi_hostname }}'
67    state: present
68  delegate_to: localhost
69
70- name: Exit host systems from lockdown mode
71  vmware_host_lockdown:
72    hostname: '{{ vcenter_hostname }}'
73    username: '{{ vcenter_username }}'
74    password: '{{ vcenter_password }}'
75    esxi_hostname: '{{ esxi_hostname }}'
76    state: absent
77  delegate_to: localhost
78
79- name: Enter host systems into lockdown mode
80  vmware_host_lockdown:
81    hostname: '{{ vcenter_hostname }}'
82    username: '{{ vcenter_username }}'
83    password: '{{ vcenter_password }}'
84    esxi_hostname:
85        - '{{ esxi_hostname_1 }}'
86        - '{{ esxi_hostname_2 }}'
87    state: present
88  delegate_to: localhost
89
90- name: Exit host systems from lockdown mode
91  vmware_host_lockdown:
92    hostname: '{{ vcenter_hostname }}'
93    username: '{{ vcenter_username }}'
94    password: '{{ vcenter_password }}'
95    esxi_hostname:
96        - '{{ esxi_hostname_1 }}'
97        - '{{ esxi_hostname_2 }}'
98    state: absent
99  delegate_to: localhost
100
101- name: Enter all host system from cluster into lockdown mode
102  vmware_host_lockdown:
103    hostname: '{{ vcenter_hostname }}'
104    username: '{{ vcenter_username }}'
105    password: '{{ vcenter_password }}'
106    cluster_name: '{{ cluster_name }}'
107    state: present
108  delegate_to: localhost
109'''
110
111RETURN = r'''
112results:
113    description: metadata about state of Host system lock down
114    returned: always
115    type: dict
116    sample: {
117                "host_lockdown_state": {
118                    "DC0_C0": {
119                        "current_state": "present",
120                        "previous_state": "absent",
121                        "desired_state": "present",
122                    },
123                }
124            }
125'''
126
127try:
128    from pyvmomi import vim
129except ImportError:
130    pass
131
132from ansible.module_utils.basic import AnsibleModule
133from ansible.module_utils.vmware import vmware_argument_spec, PyVmomi
134from ansible.module_utils._text import to_native
135
136
137class VmwareLockdownManager(PyVmomi):
138    def __init__(self, module):
139        super(VmwareLockdownManager, self).__init__(module)
140        if not self.is_vcenter():
141            self.module.fail_json(msg="Lockdown operations are performed from vCenter only. "
142                                      "hostname %s is an ESXi server. Please specify hostname "
143                                      "as vCenter server." % self.module.params['hostname'])
144        cluster_name = self.params.get('cluster_name', None)
145        esxi_host_name = self.params.get('esxi_hostname', None)
146        self.hosts = self.get_all_host_objs(cluster_name=cluster_name, esxi_host_name=esxi_host_name)
147
148    def ensure(self):
149        """
150        Function to manage internal state management
151        """
152        results = dict(changed=False, host_lockdown_state=dict())
153        change_list = []
154        desired_state = self.params.get('state')
155        for host in self.hosts:
156            results['host_lockdown_state'][host.name] = dict(current_state='',
157                                                             desired_state=desired_state,
158                                                             previous_state=''
159                                                             )
160            changed = False
161            try:
162                if host.config.adminDisabled:
163                    results['host_lockdown_state'][host.name]['previous_state'] = 'present'
164                    if desired_state == 'absent':
165                        host.ExitLockdownMode()
166                        results['host_lockdown_state'][host.name]['current_state'] = 'absent'
167                        changed = True
168                    else:
169                        results['host_lockdown_state'][host.name]['current_state'] = 'present'
170                elif not host.config.adminDisabled:
171                    results['host_lockdown_state'][host.name]['previous_state'] = 'absent'
172                    if desired_state == 'present':
173                        host.EnterLockdownMode()
174                        results['host_lockdown_state'][host.name]['current_state'] = 'present'
175                        changed = True
176                    else:
177                        results['host_lockdown_state'][host.name]['current_state'] = 'absent'
178            except vim.fault.HostConfigFault as host_config_fault:
179                self.module.fail_json(msg="Failed to manage lockdown mode for esxi"
180                                          " hostname %s : %s" % (host.name, to_native(host_config_fault.msg)))
181            except vim.fault.AdminDisabled as admin_disabled:
182                self.module.fail_json(msg="Failed to manage lockdown mode as administrator "
183                                          "permission has been disabled for "
184                                          "esxi hostname %s : %s" % (host.name, to_native(admin_disabled.msg)))
185            except Exception as generic_exception:
186                self.module.fail_json(msg="Failed to manage lockdown mode due to generic exception for esxi "
187                                          "hostname %s : %s" % (host.name, to_native(generic_exception)))
188            change_list.append(changed)
189
190        if any(change_list):
191            results['changed'] = True
192
193        self.module.exit_json(**results)
194
195
196def main():
197    argument_spec = vmware_argument_spec()
198    argument_spec.update(
199        cluster_name=dict(type='str', required=False),
200        esxi_hostname=dict(type='list', required=False),
201        state=dict(str='str', default='present', choices=['present', 'absent'], required=False),
202    )
203
204    module = AnsibleModule(
205        argument_spec=argument_spec,
206        required_one_of=[
207            ['cluster_name', 'esxi_hostname'],
208        ]
209    )
210
211    vmware_lockdown_mgr = VmwareLockdownManager(module)
212    vmware_lockdown_mgr.ensure()
213
214
215if __name__ == "__main__":
216    main()
217