1#!/usr/local/bin/python3.8
2from __future__ import (absolute_import, division, print_function)
3# Copyright 2019-2020 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_webfilter_status
27short_description: Display rating info 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 webfilter feature and status category.
31      Examples include all parameters and values need to be adjusted to datasources before usage.
32      Tested with FOS v6.0.0
33version_added: "2.10"
34author:
35    - Link Zheng (@chillancezen)
36    - Jie Xue (@JieX19)
37    - Hongbin Lu (@fgtdev-hblu)
38    - Frank Shen (@frankshen01)
39    - Miguel Angel Munoz (@mamunozgonzalez)
40    - Nicolas Thomas (@thomnico)
41notes:
42    - Legacy fortiosapi has been deprecated, httpapi is the preferred way to run playbooks
43
44requirements:
45    - ansible>=2.9.0
46options:
47    access_token:
48        description:
49            - Token-based authentication.
50              Generated from GUI of Fortigate.
51        type: str
52        required: false
53    enable_log:
54        description:
55            - Enable/Disable logging for task.
56        type: bool
57        required: false
58        default: false
59    vdom:
60        description:
61            - Virtual domain, among those defined previously. A vdom is a
62              virtual instance of the FortiGate that can be configured and
63              used as a different unit.
64        type: str
65        default: root
66
67    webfilter_status:
68        description:
69            - Display rating info.
70        default: null
71        type: dict
72        suboptions:
73            <refresh_rate>:
74                description:
75                    - Frequency to refresh the server list (sec).
76                type: str
77'''
78
79EXAMPLES = '''
80- hosts: fortigates
81  collections:
82    - fortinet.fortios
83  connection: httpapi
84  vars:
85   vdom: "root"
86   ansible_httpapi_use_ssl: yes
87   ansible_httpapi_validate_certs: no
88   ansible_httpapi_port: 443
89  tasks:
90  - name: Display rating info.
91    fortios_webfilter_status:
92      vdom:  "{{ vdom }}"
93      webfilter_status:
94        <refresh_rate>: "<your_own_value>"
95
96'''
97
98RETURN = '''
99build:
100  description: Build number of the fortigate image
101  returned: always
102  type: str
103  sample: '1547'
104http_method:
105  description: Last method used to provision the content into FortiGate
106  returned: always
107  type: str
108  sample: 'PUT'
109http_status:
110  description: Last result given by FortiGate on last operation applied
111  returned: always
112  type: str
113  sample: "200"
114mkey:
115  description: Master key (id) used in the last call to FortiGate
116  returned: success
117  type: str
118  sample: "id"
119name:
120  description: Name of the table used to fulfill the request
121  returned: always
122  type: str
123  sample: "urlfilter"
124path:
125  description: Path of the table used to fulfill the request
126  returned: always
127  type: str
128  sample: "webfilter"
129revision:
130  description: Internal revision number
131  returned: always
132  type: str
133  sample: "17.0.2.10658"
134serial:
135  description: Serial number of the unit
136  returned: always
137  type: str
138  sample: "FGVMEVYYQT3AB5352"
139status:
140  description: Indication of the operation's result
141  returned: always
142  type: str
143  sample: "success"
144vdom:
145  description: Virtual domain used
146  returned: always
147  type: str
148  sample: "root"
149version:
150  description: Version of the FortiGate
151  returned: always
152  type: str
153  sample: "v5.6.3"
154
155'''
156from ansible.module_utils.basic import AnsibleModule
157from ansible.module_utils.connection import Connection
158from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import FortiOSHandler
159from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_legacy_fortiosapi
160from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import schema_to_module_spec
161from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_schema_versioning
162from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
163from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import is_same_comparison
164from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import serialize
165
166
167def filter_webfilter_status_data(json):
168    option_list = ['<refresh_rate>']
169    dictionary = {}
170
171    for attribute in option_list:
172        if attribute in json and json[attribute] is not None:
173            dictionary[attribute] = json[attribute]
174
175    return dictionary
176
177
178def underscore_to_hyphen(data):
179    if isinstance(data, list):
180        for i, elem in enumerate(data):
181            data[i] = underscore_to_hyphen(elem)
182    elif isinstance(data, dict):
183        new_data = {}
184        for k, v in data.items():
185            new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
186        data = new_data
187
188    return data
189
190
191def webfilter_status(data, fos):
192    vdom = data['vdom']
193    webfilter_status_data = data['webfilter_status']
194    filtered_data = underscore_to_hyphen(filter_webfilter_status_data(webfilter_status_data))
195
196    return fos.set('webfilter',
197                   'status',
198                   data=filtered_data,
199                   vdom=vdom)
200
201
202def is_successful_status(status):
203    return status['status'] == "success" or \
204        status['http_method'] == "DELETE" and status['http_status'] == 404
205
206
207def fortios_webfilter(data, fos):
208
209    if data['webfilter_status']:
210        resp = webfilter_status(data, fos)
211    else:
212        fos._module.fail_json(msg='missing task body: %s' % ('webfilter_status'))
213
214    return not is_successful_status(resp), \
215        resp['status'] == "success" and \
216        (resp['revision_changed'] if 'revision_changed' in resp else True), \
217        resp
218
219
220versioned_schema = {
221    "type": "dict",
222    "children": {
223        "<refresh_rate>": {
224            "type": "string",
225            "revisions": {
226                "v7.0.0": True,
227                "v6.4.4": True,
228                "v6.4.0": True,
229                "v6.4.1": True,
230                "v6.2.0": True,
231                "v6.2.5": True,
232                "v6.2.7": True
233            }
234        }
235    },
236    "revisions": {
237        "v7.0.0": True,
238        "v6.4.4": True,
239        "v6.4.0": True,
240        "v6.4.1": True,
241        "v6.2.0": True,
242        "v6.2.5": True,
243        "v6.2.7": True
244    }
245}
246
247
248def main():
249    module_spec = schema_to_module_spec(versioned_schema)
250    mkeyname = None
251    fields = {
252        "access_token": {"required": False, "type": "str", "no_log": True},
253        "enable_log": {"required": False, "type": bool},
254        "vdom": {"required": False, "type": "str", "default": "root"},
255        "webfilter_status": {
256            "required": False, "type": "dict", "default": None,
257            "options": {
258            }
259        }
260    }
261    for attribute_name in module_spec['options']:
262        fields["webfilter_status"]['options'][attribute_name] = module_spec['options'][attribute_name]
263        if mkeyname and mkeyname == attribute_name:
264            fields["webfilter_status"]['options'][attribute_name]['required'] = True
265
266    check_legacy_fortiosapi()
267    module = AnsibleModule(argument_spec=fields,
268                           supports_check_mode=False)
269
270    versions_check_result = None
271    if module._socket_path:
272        connection = Connection(module._socket_path)
273        if 'access_token' in module.params:
274            connection.set_option('access_token', module.params['access_token'])
275
276        if 'enable_log' in module.params:
277            connection.set_option('enable_log', module.params['enable_log'])
278        else:
279            connection.set_option('enable_log', False)
280        fos = FortiOSHandler(connection, module, mkeyname)
281        versions_check_result = check_schema_versioning(fos, versioned_schema, "webfilter_status")
282
283        is_error, has_changed, result = fortios_webfilter(module.params, fos)
284
285    else:
286        module.fail_json(**FAIL_SOCKET_MSG)
287
288    if versions_check_result and versions_check_result['matched'] is False:
289        module.warn("Ansible has detected version mismatch between FortOS system and your playbook, see more details by specifying option -vvv")
290
291    if not is_error:
292        if versions_check_result and versions_check_result['matched'] is False:
293            module.exit_json(changed=has_changed, version_check_warning=versions_check_result, meta=result)
294        else:
295            module.exit_json(changed=has_changed, meta=result)
296    else:
297        if versions_check_result and versions_check_result['matched'] is False:
298            module.fail_json(msg="Error in repo", version_check_warning=versions_check_result, meta=result)
299        else:
300            module.fail_json(msg="Error in repo", meta=result)
301
302
303if __name__ == '__main__':
304    main()
305