1# Copyright: (c) 2018 Red Hat Inc.
2# Copyright: (c) 2019, Ansible Project
3# Copyright: (c) 2019, Abhijeet Kasurde <akasurde@redhat.com>
4# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
5
6from __future__ import (absolute_import, division, print_function)
7__metaclass__ = type
8
9DOCUMENTATION = '''
10---
11author: Abhijeet Kasurde (Akasurde)
12httpapi : vmware
13short_description: HttpApi Plugin for VMware REST API
14description:
15  - This HttpApi plugin provides methods to connect to VMware vCenter over a HTTP(S)-based APIs.
16'''
17
18import json
19
20from ansible.module_utils.basic import to_text
21from ansible.errors import AnsibleConnectionFailure
22from ansible.module_utils.six.moves.urllib.error import HTTPError
23from ansible.plugins.httpapi import HttpApiBase
24from ansible.module_utils.connection import ConnectionError
25
26BASE_HEADERS = {
27    'Content-Type': 'application/json',
28    'Accept': 'application/json',
29}
30
31
32class HttpApi(HttpApiBase):
33    def login(self, username, password):
34        if username and password:
35            payload = {}
36            url = '/rest/com/vmware/cis/session'
37            response, response_data = self.send_request(url, payload)
38        else:
39            raise AnsibleConnectionFailure('Username and password are required for login')
40
41        if response == 404:
42            raise ConnectionError(response_data)
43
44        if not response_data.get('value'):
45            raise ConnectionError('Server returned response without token info during connection authentication: %s' % response)
46
47        self.connection._session_uid = "vmware-api-session-id:%s" % response_data['value']
48        self.connection._token = response_data['value']
49
50    def logout(self):
51        response, dummy = self.send_request('/rest/com/vmware/cis/session', None, method='DELETE')
52
53    def get_session_uid(self):
54        return self.connection._session_uid
55
56    def get_session_token(self):
57        return self.connection._token
58
59    def send_request(self, path, body_params, method='POST'):
60        data = json.dumps(body_params) if body_params else '{}'
61
62        try:
63            self._display_request(method=method)
64            response, response_data = self.connection.send(path, data, method=method, headers=BASE_HEADERS, force_basic_auth=True)
65            response_value = self._get_response_value(response_data)
66
67            return response.getcode(), self._response_to_json(response_value)
68        except AnsibleConnectionFailure:
69            return 404, 'Object not found'
70        except HTTPError as e:
71            return e.code, json.loads(e.read())
72
73    def _display_request(self, method='POST'):
74        self.connection.queue_message('vvvv', 'Web Services: %s %s' % (method, self.connection._url))
75
76    def _get_response_value(self, response_data):
77        return to_text(response_data.getvalue())
78
79    def _response_to_json(self, response_text):
80        try:
81            return json.loads(response_text) if response_text else {}
82        # JSONDecodeError only available on Python 3.5+
83        except ValueError:
84            raise ConnectionError('Invalid JSON response: %s' % response_text)
85