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