summaryrefslogtreecommitdiff
path: root/lib/ansible/modules/cloud/vmware/vmware_host.py
blob: cf6f1cc9ad99646180cc0dfb0dbfa31da2d73e1e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
#!/usr/bin/python
# -*- coding: utf-8 -*-

# (c) 2015, Joseph Callen <jcallen () csc.com>
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.

ANSIBLE_METADATA = {'metadata_version': '1.0',
                    'status': ['preview'],
                    'supported_by': 'community'}


DOCUMENTATION = '''
---
module: vmware_host
short_description: Add/remove ESXi host to/from vCenter
description:
    - This module can be used to add/remove an ESXi host to/from vCenter
version_added: 2.0
author: "Joseph Callen (@jcpowermac), Russell Teague (@mtnbikenc)"
notes:
    - Tested on vSphere 5.5
requirements:
    - "python >= 2.6"
    - PyVmomi
options:
    datacenter_name:
        description:
            - Name of the datacenter to add the host
        required: True
    cluster_name:
        description:
            - Name of the cluster to add the host
        required: True
    esxi_hostname:
        description:
            - ESXi hostname to manage
        required: True
    esxi_username:
        description:
            - ESXi username
        required: True
    esxi_password:
        description:
            - ESXi password
        required: True
    state:
        description:
            - Add or remove the host
        default: 'present'
        choices:
            - 'present'
            - 'absent'
        required: False
extends_documentation_fragment: vmware.documentation
'''

EXAMPLES = '''
# Example from Ansible playbook

    - name: Add ESXi Host to VCSA
      local_action:
        module: vmware_host
        hostname: vcsa_host
        username: vcsa_user
        password: vcsa_pass
        datacenter_name: datacenter_name
        cluster_name: cluster_name
        esxi_hostname: esxi_hostname
        esxi_username: esxi_username
        esxi_password: esxi_password
        state: present
'''

try:
    from pyVmomi import vim, vmodl
    HAS_PYVMOMI = True
except ImportError:
    HAS_PYVMOMI = False


class VMwareHost(object):
    def __init__(self, module):
        self.module = module
        self.datacenter_name = module.params['datacenter_name']
        self.cluster_name = module.params['cluster_name']
        self.esxi_hostname = module.params['esxi_hostname']
        self.esxi_username = module.params['esxi_username']
        self.esxi_password = module.params['esxi_password']
        self.state = module.params['state']
        self.dc = None
        self.cluster = None
        self.host = None
        self.content = connect_to_api(module)

    def process_state(self):
        try:
            # Currently state_update_dvs is not implemented.
            host_states = {
                'absent': {
                    'present': self.state_remove_host,
                    'absent': self.state_exit_unchanged,
                },
                'present': {
                    'present': self.state_exit_unchanged,
                    'absent': self.state_add_host,
                }
            }

            host_states[self.state][self.check_host_state()]()

        except vmodl.RuntimeFault as runtime_fault:
            self.module.fail_json(msg=runtime_fault.msg)
        except vmodl.MethodFault as method_fault:
            self.module.fail_json(msg=method_fault.msg)
        except Exception as e:
            self.module.fail_json(msg=str(e))

    def find_host_by_cluster_datacenter(self):
        self.dc = find_datacenter_by_name(self.content, self.datacenter_name)
        self.cluster = find_cluster_by_name_datacenter(self.dc, self.cluster_name)

        for host in self.cluster.host:
            if host.name == self.esxi_hostname:
                return host, self.cluster

        return None, self.cluster

    def add_host_to_vcenter(self):
        host_connect_spec = vim.host.ConnectSpec()
        host_connect_spec.hostName = self.esxi_hostname
        host_connect_spec.userName = self.esxi_username
        host_connect_spec.password = self.esxi_password
        host_connect_spec.force = True
        host_connect_spec.sslThumbprint = ""
        as_connected = True
        esxi_license = None
        resource_pool = None

        try:
            task = self.cluster.AddHost_Task(host_connect_spec, as_connected, resource_pool, esxi_license)
            success, result = wait_for_task(task)
            return success, result
        except TaskError as add_task_error:
            # This is almost certain to fail the first time.
            # In order to get the sslThumbprint we first connect
            # get the vim.fault.SSLVerifyFault then grab the sslThumbprint
            # from that object.
            #
            # args is a tuple, selecting the first tuple
            ssl_verify_fault = add_task_error.args[0]
            host_connect_spec.sslThumbprint = ssl_verify_fault.thumbprint

        task = self.cluster.AddHost_Task(host_connect_spec, as_connected, resource_pool, esxi_license)
        success, result = wait_for_task(task)
        return success, result

    def state_exit_unchanged(self):
        self.module.exit_json(changed=False)

    def state_remove_host(self):
        changed = True
        result = None
        if not self.module.check_mode:
            if not self.host.runtime.inMaintenanceMode:
                maintenance_mode_task = self.host.EnterMaintenanceMode_Task(300, True, None)
                changed, result = wait_for_task(maintenance_mode_task)

            if changed:
                task = self.host.Destroy_Task()
                changed, result = wait_for_task(task)
            else:
                raise Exception(result)
        self.module.exit_json(changed=changed, result=str(result))

    def state_update_host(self):
        self.module.exit_json(changed=False, msg="Currently not implemented.")

    def state_add_host(self):
        changed = True
        result = None

        if not self.module.check_mode:
            changed, result = self.add_host_to_vcenter()
        self.module.exit_json(changed=changed, result=str(result))

    def check_host_state(self):
        self.host, self.cluster = self.find_host_by_cluster_datacenter()

        if self.host is None:
            return 'absent'
        else:
            return 'present'


def main():
    argument_spec = vmware_argument_spec()
    argument_spec.update(dict(datacenter_name=dict(required=True, type='str'),
                              cluster_name=dict(required=True, type='str'),
                              esxi_hostname=dict(required=True, type='str'),
                              esxi_username=dict(required=True, type='str'),
                              esxi_password=dict(required=True, type='str', no_log=True),
                              state=dict(default='present', choices=['present', 'absent'], type='str')))

    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)

    if not HAS_PYVMOMI:
        module.fail_json(msg='pyvmomi is required for this module')

    vmware_host = VMwareHost(module)
    vmware_host.process_state()

from ansible.module_utils.vmware import *
from ansible.module_utils.basic import *

if __name__ == '__main__':
    main()