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_dlp_settings
27short_description: Designate logical storage for DLP fingerprint database 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 dlp feature and settings 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    dlp_settings:
68        description:
69            - Designate logical storage for DLP fingerprint database.
70        default: null
71        type: dict
72        suboptions:
73            cache_mem_percent:
74                description:
75                    - Maximum percentage of available memory allocated to caching (1 - 15%).
76                type: int
77            chunk_size:
78                description:
79                    - Maximum fingerprint chunk size.  **Changing will flush the entire database**.
80                type: int
81            db_mode:
82                description:
83                    - Behaviour when the maximum size is reached.
84                type: str
85                choices:
86                    - stop-adding
87                    - remove-modified-then-oldest
88                    - remove-oldest
89            size:
90                description:
91                    - Maximum total size of files within the storage (MB).
92                type: int
93            storage_device:
94                description:
95                    - Storage device name. Source system.storage.name.
96                type: str
97'''
98
99EXAMPLES = '''
100- hosts: fortigates
101  collections:
102    - fortinet.fortios
103  connection: httpapi
104  vars:
105   vdom: "root"
106   ansible_httpapi_use_ssl: yes
107   ansible_httpapi_validate_certs: no
108   ansible_httpapi_port: 443
109  tasks:
110  - name: Designate logical storage for DLP fingerprint database.
111    fortios_dlp_settings:
112      vdom:  "{{ vdom }}"
113      dlp_settings:
114        cache_mem_percent: "3"
115        chunk_size: "4"
116        db_mode: "stop-adding"
117        size: "6"
118        storage_device: "<your_own_value> (source system.storage.name)"
119
120'''
121
122RETURN = '''
123build:
124  description: Build number of the fortigate image
125  returned: always
126  type: str
127  sample: '1547'
128http_method:
129  description: Last method used to provision the content into FortiGate
130  returned: always
131  type: str
132  sample: 'PUT'
133http_status:
134  description: Last result given by FortiGate on last operation applied
135  returned: always
136  type: str
137  sample: "200"
138mkey:
139  description: Master key (id) used in the last call to FortiGate
140  returned: success
141  type: str
142  sample: "id"
143name:
144  description: Name of the table used to fulfill the request
145  returned: always
146  type: str
147  sample: "urlfilter"
148path:
149  description: Path of the table used to fulfill the request
150  returned: always
151  type: str
152  sample: "webfilter"
153revision:
154  description: Internal revision number
155  returned: always
156  type: str
157  sample: "17.0.2.10658"
158serial:
159  description: Serial number of the unit
160  returned: always
161  type: str
162  sample: "FGVMEVYYQT3AB5352"
163status:
164  description: Indication of the operation's result
165  returned: always
166  type: str
167  sample: "success"
168vdom:
169  description: Virtual domain used
170  returned: always
171  type: str
172  sample: "root"
173version:
174  description: Version of the FortiGate
175  returned: always
176  type: str
177  sample: "v5.6.3"
178
179'''
180from ansible.module_utils.basic import AnsibleModule
181from ansible.module_utils.connection import Connection
182from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import FortiOSHandler
183from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_legacy_fortiosapi
184from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import schema_to_module_spec
185from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_schema_versioning
186from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
187from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import is_same_comparison
188from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import serialize
189
190
191def filter_dlp_settings_data(json):
192    option_list = ['cache_mem_percent', 'chunk_size', 'db_mode',
193                   'size', 'storage_device']
194    dictionary = {}
195
196    for attribute in option_list:
197        if attribute in json and json[attribute] is not None:
198            dictionary[attribute] = json[attribute]
199
200    return dictionary
201
202
203def underscore_to_hyphen(data):
204    if isinstance(data, list):
205        for i, elem in enumerate(data):
206            data[i] = underscore_to_hyphen(elem)
207    elif isinstance(data, dict):
208        new_data = {}
209        for k, v in data.items():
210            new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
211        data = new_data
212
213    return data
214
215
216def dlp_settings(data, fos):
217    vdom = data['vdom']
218    dlp_settings_data = data['dlp_settings']
219    filtered_data = underscore_to_hyphen(filter_dlp_settings_data(dlp_settings_data))
220
221    return fos.set('dlp',
222                   'settings',
223                   data=filtered_data,
224                   vdom=vdom)
225
226
227def is_successful_status(status):
228    return status['status'] == "success" or \
229        status['http_method'] == "DELETE" and status['http_status'] == 404
230
231
232def fortios_dlp(data, fos):
233
234    if data['dlp_settings']:
235        resp = dlp_settings(data, fos)
236    else:
237        fos._module.fail_json(msg='missing task body: %s' % ('dlp_settings'))
238
239    return not is_successful_status(resp), \
240        resp['status'] == "success" and \
241        (resp['revision_changed'] if 'revision_changed' in resp else True), \
242        resp
243
244
245versioned_schema = {
246    "type": "dict",
247    "children": {
248        "cache_mem_percent": {
249            "type": "integer",
250            "revisions": {
251                "v6.0.0": True,
252                "v7.0.0": True,
253                "v6.0.5": True,
254                "v6.4.4": True,
255                "v6.4.0": True,
256                "v6.4.1": True,
257                "v6.2.0": True,
258                "v6.2.3": True,
259                "v6.2.5": True,
260                "v6.2.7": True,
261                "v6.0.11": True
262            }
263        },
264        "storage_device": {
265            "type": "string",
266            "revisions": {
267                "v6.0.0": True,
268                "v7.0.0": True,
269                "v6.0.5": True,
270                "v6.4.4": True,
271                "v6.4.0": True,
272                "v6.4.1": True,
273                "v6.2.0": True,
274                "v6.2.3": True,
275                "v6.2.5": True,
276                "v6.2.7": True,
277                "v6.0.11": True
278            }
279        },
280        "db_mode": {
281            "type": "string",
282            "options": [
283                {
284                    "value": "stop-adding",
285                    "revisions": {
286                        "v6.0.0": True,
287                        "v7.0.0": True,
288                        "v6.0.5": True,
289                        "v6.4.4": True,
290                        "v6.4.0": True,
291                        "v6.4.1": True,
292                        "v6.2.0": True,
293                        "v6.2.3": True,
294                        "v6.2.5": True,
295                        "v6.2.7": True,
296                        "v6.0.11": True
297                    }
298                },
299                {
300                    "value": "remove-modified-then-oldest",
301                    "revisions": {
302                        "v6.0.0": True,
303                        "v7.0.0": True,
304                        "v6.0.5": True,
305                        "v6.4.4": True,
306                        "v6.4.0": True,
307                        "v6.4.1": True,
308                        "v6.2.0": True,
309                        "v6.2.3": True,
310                        "v6.2.5": True,
311                        "v6.2.7": True,
312                        "v6.0.11": True
313                    }
314                },
315                {
316                    "value": "remove-oldest",
317                    "revisions": {
318                        "v6.0.0": True,
319                        "v7.0.0": True,
320                        "v6.0.5": True,
321                        "v6.4.4": True,
322                        "v6.4.0": True,
323                        "v6.4.1": True,
324                        "v6.2.0": True,
325                        "v6.2.3": True,
326                        "v6.2.5": True,
327                        "v6.2.7": True,
328                        "v6.0.11": True
329                    }
330                }
331            ],
332            "revisions": {
333                "v6.0.0": True,
334                "v7.0.0": True,
335                "v6.0.5": True,
336                "v6.4.4": True,
337                "v6.4.0": True,
338                "v6.4.1": True,
339                "v6.2.0": True,
340                "v6.2.3": True,
341                "v6.2.5": True,
342                "v6.2.7": True,
343                "v6.0.11": True
344            }
345        },
346        "chunk_size": {
347            "type": "integer",
348            "revisions": {
349                "v6.0.0": True,
350                "v7.0.0": True,
351                "v6.0.5": True,
352                "v6.4.4": True,
353                "v6.4.0": True,
354                "v6.4.1": True,
355                "v6.2.0": True,
356                "v6.2.3": True,
357                "v6.2.5": True,
358                "v6.2.7": True,
359                "v6.0.11": True
360            }
361        },
362        "size": {
363            "type": "integer",
364            "revisions": {
365                "v6.0.0": True,
366                "v7.0.0": True,
367                "v6.0.5": True,
368                "v6.4.4": True,
369                "v6.4.0": True,
370                "v6.4.1": True,
371                "v6.2.0": True,
372                "v6.2.3": True,
373                "v6.2.5": True,
374                "v6.2.7": True,
375                "v6.0.11": True
376            }
377        }
378    },
379    "revisions": {
380        "v6.0.0": True,
381        "v7.0.0": True,
382        "v6.0.5": True,
383        "v6.4.4": True,
384        "v6.4.0": True,
385        "v6.4.1": True,
386        "v6.2.0": True,
387        "v6.2.3": True,
388        "v6.2.5": True,
389        "v6.2.7": True,
390        "v6.0.11": True
391    }
392}
393
394
395def main():
396    module_spec = schema_to_module_spec(versioned_schema)
397    mkeyname = None
398    fields = {
399        "access_token": {"required": False, "type": "str", "no_log": True},
400        "enable_log": {"required": False, "type": bool},
401        "vdom": {"required": False, "type": "str", "default": "root"},
402        "dlp_settings": {
403            "required": False, "type": "dict", "default": None,
404            "options": {
405            }
406        }
407    }
408    for attribute_name in module_spec['options']:
409        fields["dlp_settings"]['options'][attribute_name] = module_spec['options'][attribute_name]
410        if mkeyname and mkeyname == attribute_name:
411            fields["dlp_settings"]['options'][attribute_name]['required'] = True
412
413    check_legacy_fortiosapi()
414    module = AnsibleModule(argument_spec=fields,
415                           supports_check_mode=False)
416
417    versions_check_result = None
418    if module._socket_path:
419        connection = Connection(module._socket_path)
420        if 'access_token' in module.params:
421            connection.set_option('access_token', module.params['access_token'])
422
423        if 'enable_log' in module.params:
424            connection.set_option('enable_log', module.params['enable_log'])
425        else:
426            connection.set_option('enable_log', False)
427        fos = FortiOSHandler(connection, module, mkeyname)
428        versions_check_result = check_schema_versioning(fos, versioned_schema, "dlp_settings")
429
430        is_error, has_changed, result = fortios_dlp(module.params, fos)
431
432    else:
433        module.fail_json(**FAIL_SOCKET_MSG)
434
435    if versions_check_result and versions_check_result['matched'] is False:
436        module.warn("Ansible has detected version mismatch between FortOS system and your playbook, see more details by specifying option -vvv")
437
438    if not is_error:
439        if versions_check_result and versions_check_result['matched'] is False:
440            module.exit_json(changed=has_changed, version_check_warning=versions_check_result, meta=result)
441        else:
442            module.exit_json(changed=has_changed, meta=result)
443    else:
444        if versions_check_result and versions_check_result['matched'] is False:
445            module.fail_json(msg="Error in repo", version_check_warning=versions_check_result, meta=result)
446        else:
447            module.fail_json(msg="Error in repo", meta=result)
448
449
450if __name__ == '__main__':
451    main()
452