1#!/usr/bin/python
2from __future__ import (absolute_import, division, print_function)
3# Copyright 2019 Fortinet, Inc.
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program.  If not, see <https://www.gnu.org/licenses/>.
17
18__metaclass__ = type
19
20ANSIBLE_METADATA = {'status': ['preview'],
21                    'supported_by': 'community',
22                    'metadata_version': '1.1'}
23
24DOCUMENTATION = '''
25---
26module: fortios_system_autoupdate_tunneling
27short_description: Configure web proxy tunnelling for the FDN in Fortinet's FortiOS and FortiGate.
28description:
29    - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
30      user to set and modify system_autoupdate feature and tunneling category.
31      Examples include all parameters and values need to be adjusted to datasources before usage.
32      Tested with FOS v6.0.5
33version_added: "2.9"
34author:
35    - Miguel Angel Munoz (@mamunozgonzalez)
36    - Nicolas Thomas (@thomnico)
37notes:
38    - Requires fortiosapi library developed by Fortinet
39    - Run as a local_action in your playbook
40requirements:
41    - fortiosapi>=0.9.8
42options:
43    host:
44        description:
45            - FortiOS or FortiGate IP address.
46        type: str
47        required: false
48    username:
49        description:
50            - FortiOS or FortiGate username.
51        type: str
52        required: false
53    password:
54        description:
55            - FortiOS or FortiGate password.
56        type: str
57        default: ""
58    vdom:
59        description:
60            - Virtual domain, among those defined previously. A vdom is a
61              virtual instance of the FortiGate that can be configured and
62              used as a different unit.
63        type: str
64        default: root
65    https:
66        description:
67            - Indicates if the requests towards FortiGate must use HTTPS protocol.
68        type: bool
69        default: true
70    ssl_verify:
71        description:
72            - Ensures FortiGate certificate must be verified by a proper CA.
73        type: bool
74        default: true
75    system_autoupdate_tunneling:
76        description:
77            - Configure web proxy tunnelling for the FDN.
78        default: null
79        type: dict
80        suboptions:
81            address:
82                description:
83                    - Web proxy IP address or FQDN.
84                type: str
85            password:
86                description:
87                    - Web proxy password.
88                type: str
89            port:
90                description:
91                    - Web proxy port.
92                type: int
93            status:
94                description:
95                    - Enable/disable web proxy tunnelling.
96                type: str
97                choices:
98                    - enable
99                    - disable
100            username:
101                description:
102                    - Web proxy username.
103                type: str
104'''
105
106EXAMPLES = '''
107- hosts: localhost
108  vars:
109   host: "192.168.122.40"
110   username: "admin"
111   password: ""
112   vdom: "root"
113   ssl_verify: "False"
114  tasks:
115  - name: Configure web proxy tunnelling for the FDN.
116    fortios_system_autoupdate_tunneling:
117      host:  "{{ host }}"
118      username: "{{ username }}"
119      password: "{{ password }}"
120      vdom:  "{{ vdom }}"
121      https: "False"
122      system_autoupdate_tunneling:
123        address: "<your_own_value>"
124        password: "<your_own_value>"
125        port: "5"
126        status: "enable"
127        username: "<your_own_value>"
128'''
129
130RETURN = '''
131build:
132  description: Build number of the fortigate image
133  returned: always
134  type: str
135  sample: '1547'
136http_method:
137  description: Last method used to provision the content into FortiGate
138  returned: always
139  type: str
140  sample: 'PUT'
141http_status:
142  description: Last result given by FortiGate on last operation applied
143  returned: always
144  type: str
145  sample: "200"
146mkey:
147  description: Master key (id) used in the last call to FortiGate
148  returned: success
149  type: str
150  sample: "id"
151name:
152  description: Name of the table used to fulfill the request
153  returned: always
154  type: str
155  sample: "urlfilter"
156path:
157  description: Path of the table used to fulfill the request
158  returned: always
159  type: str
160  sample: "webfilter"
161revision:
162  description: Internal revision number
163  returned: always
164  type: str
165  sample: "17.0.2.10658"
166serial:
167  description: Serial number of the unit
168  returned: always
169  type: str
170  sample: "FGVMEVYYQT3AB5352"
171status:
172  description: Indication of the operation's result
173  returned: always
174  type: str
175  sample: "success"
176vdom:
177  description: Virtual domain used
178  returned: always
179  type: str
180  sample: "root"
181version:
182  description: Version of the FortiGate
183  returned: always
184  type: str
185  sample: "v5.6.3"
186
187'''
188
189from ansible.module_utils.basic import AnsibleModule
190from ansible.module_utils.connection import Connection
191from ansible.module_utils.network.fortios.fortios import FortiOSHandler
192from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
193
194
195def login(data, fos):
196    host = data['host']
197    username = data['username']
198    password = data['password']
199    ssl_verify = data['ssl_verify']
200
201    fos.debug('on')
202    if 'https' in data and not data['https']:
203        fos.https('off')
204    else:
205        fos.https('on')
206
207    fos.login(host, username, password, verify=ssl_verify)
208
209
210def filter_system_autoupdate_tunneling_data(json):
211    option_list = ['address', 'password', 'port',
212                   'status', 'username']
213    dictionary = {}
214
215    for attribute in option_list:
216        if attribute in json and json[attribute] is not None:
217            dictionary[attribute] = json[attribute]
218
219    return dictionary
220
221
222def underscore_to_hyphen(data):
223    if isinstance(data, list):
224        for elem in data:
225            elem = underscore_to_hyphen(elem)
226    elif isinstance(data, dict):
227        new_data = {}
228        for k, v in data.items():
229            new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
230        data = new_data
231
232    return data
233
234
235def system_autoupdate_tunneling(data, fos):
236    vdom = data['vdom']
237    system_autoupdate_tunneling_data = data['system_autoupdate_tunneling']
238    filtered_data = underscore_to_hyphen(filter_system_autoupdate_tunneling_data(system_autoupdate_tunneling_data))
239
240    return fos.set('system.autoupdate',
241                   'tunneling',
242                   data=filtered_data,
243                   vdom=vdom)
244
245
246def is_successful_status(status):
247    return status['status'] == "success" or \
248        status['http_method'] == "DELETE" and status['http_status'] == 404
249
250
251def fortios_system_autoupdate(data, fos):
252
253    if data['system_autoupdate_tunneling']:
254        resp = system_autoupdate_tunneling(data, fos)
255
256    return not is_successful_status(resp), \
257        resp['status'] == "success", \
258        resp
259
260
261def main():
262    fields = {
263        "host": {"required": False, "type": "str"},
264        "username": {"required": False, "type": "str"},
265        "password": {"required": False, "type": "str", "default": "", "no_log": True},
266        "vdom": {"required": False, "type": "str", "default": "root"},
267        "https": {"required": False, "type": "bool", "default": True},
268        "ssl_verify": {"required": False, "type": "bool", "default": True},
269        "system_autoupdate_tunneling": {
270            "required": False, "type": "dict", "default": None,
271            "options": {
272                "address": {"required": False, "type": "str"},
273                "password": {"required": False, "type": "str", "no_log": True},
274                "port": {"required": False, "type": "int"},
275                "status": {"required": False, "type": "str",
276                           "choices": ["enable", "disable"]},
277                "username": {"required": False, "type": "str"}
278
279            }
280        }
281    }
282
283    module = AnsibleModule(argument_spec=fields,
284                           supports_check_mode=False)
285
286    # legacy_mode refers to using fortiosapi instead of HTTPAPI
287    legacy_mode = 'host' in module.params and module.params['host'] is not None and \
288                  'username' in module.params and module.params['username'] is not None and \
289                  'password' in module.params and module.params['password'] is not None
290
291    if not legacy_mode:
292        if module._socket_path:
293            connection = Connection(module._socket_path)
294            fos = FortiOSHandler(connection)
295
296            is_error, has_changed, result = fortios_system_autoupdate(module.params, fos)
297        else:
298            module.fail_json(**FAIL_SOCKET_MSG)
299    else:
300        try:
301            from fortiosapi import FortiOSAPI
302        except ImportError:
303            module.fail_json(msg="fortiosapi module is required")
304
305        fos = FortiOSAPI()
306
307        login(module.params, fos)
308        is_error, has_changed, result = fortios_system_autoupdate(module.params, fos)
309        fos.logout()
310
311    if not is_error:
312        module.exit_json(changed=has_changed, meta=result)
313    else:
314        module.fail_json(msg="Error in repo", meta=result)
315
316
317if __name__ == '__main__':
318    main()
319