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_dnsfilter_profile 27short_description: Configure DNS domain filter profiles 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 dnsfilter feature and profile 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 state: 68 description: 69 - Indicates whether to create or remove the object. 70 type: str 71 required: true 72 choices: 73 - present 74 - absent 75 dnsfilter_profile: 76 description: 77 - Configure DNS domain filter profiles. 78 default: null 79 type: dict 80 suboptions: 81 block_action: 82 description: 83 - Action to take for blocked domains. 84 type: str 85 choices: 86 - block 87 - redirect 88 block_botnet: 89 description: 90 - Enable/disable blocking botnet C&C DNS lookups. 91 type: str 92 choices: 93 - disable 94 - enable 95 comment: 96 description: 97 - Comment. 98 type: str 99 dns_translation: 100 description: 101 - DNS translation settings. 102 type: list 103 suboptions: 104 addr_type: 105 description: 106 - DNS translation type (IPv4 or IPv6). 107 type: str 108 choices: 109 - ipv4 110 - ipv6 111 dst: 112 description: 113 - IPv4 address or subnet on the external network to substitute for the resolved address in DNS query replies. Can be single IP 114 address or subnet on the external network, but number of addresses must equal number of mapped IP addresses in src. 115 type: str 116 dst6: 117 description: 118 - IPv6 address or subnet on the external network to substitute for the resolved address in DNS query replies. Can be single IP 119 address or subnet on the external network, but number of addresses must equal number of mapped IP addresses in src6. 120 type: str 121 id: 122 description: 123 - ID. 124 required: true 125 type: int 126 netmask: 127 description: 128 - If src and dst are subnets rather than single IP addresses, enter the netmask for both src and dst. 129 type: str 130 prefix: 131 description: 132 - If src6 and dst6 are subnets rather than single IP addresses, enter the prefix for both src6 and dst6 (1 - 128). 133 type: int 134 src: 135 description: 136 - IPv4 address or subnet on the internal network to compare with the resolved address in DNS query replies. If the resolved 137 address matches, the resolved address is substituted with dst. 138 type: str 139 src6: 140 description: 141 - IPv6 address or subnet on the internal network to compare with the resolved address in DNS query replies. If the resolved 142 address matches, the resolved address is substituted with dst6. 143 type: str 144 status: 145 description: 146 - Enable/disable this DNS translation entry. 147 type: str 148 choices: 149 - enable 150 - disable 151 domain_filter: 152 description: 153 - Domain filter settings. 154 type: dict 155 suboptions: 156 domain_filter_table: 157 description: 158 - DNS domain filter table ID. Source dnsfilter.domain-filter.id. 159 type: int 160 external_ip_blocklist: 161 description: 162 - One or more external IP block lists. 163 type: list 164 suboptions: 165 name: 166 description: 167 - External domain block list name. Source system.external-resource.name. 168 required: true 169 type: str 170 ftgd_dns: 171 description: 172 - FortiGuard DNS Filter settings. 173 type: dict 174 suboptions: 175 filters: 176 description: 177 - FortiGuard DNS domain filters. 178 type: list 179 suboptions: 180 action: 181 description: 182 - Action to take for DNS requests matching the category. 183 type: str 184 choices: 185 - block 186 - monitor 187 category: 188 description: 189 - Category number. 190 type: int 191 id: 192 description: 193 - ID number. 194 required: true 195 type: int 196 log: 197 description: 198 - Enable/disable DNS filter logging for this DNS profile. 199 type: str 200 choices: 201 - enable 202 - disable 203 options: 204 description: 205 - FortiGuard DNS filter options. 206 type: str 207 choices: 208 - error-allow 209 - ftgd-disable 210 log_all_domain: 211 description: 212 - Enable/disable logging of all domains visited (detailed DNS logging). 213 type: str 214 choices: 215 - enable 216 - disable 217 name: 218 description: 219 - Profile name. 220 required: true 221 type: str 222 redirect_portal: 223 description: 224 - IP address of the SDNS redirect portal. 225 type: str 226 redirect_portal6: 227 description: 228 - IPv6 address of the SDNS redirect portal. 229 type: str 230 safe_search: 231 description: 232 - Enable/disable Google, Bing, and YouTube safe search. 233 type: str 234 choices: 235 - disable 236 - enable 237 sdns_domain_log: 238 description: 239 - Enable/disable domain filtering and botnet domain logging. 240 type: str 241 choices: 242 - enable 243 - disable 244 sdns_ftgd_err_log: 245 description: 246 - Enable/disable FortiGuard SDNS rating error logging. 247 type: str 248 choices: 249 - enable 250 - disable 251 youtube_restrict: 252 description: 253 - Set safe search for YouTube restriction level. 254 type: str 255 choices: 256 - strict 257 - moderate 258''' 259 260EXAMPLES = ''' 261- hosts: fortigates 262 collections: 263 - fortinet.fortios 264 connection: httpapi 265 vars: 266 vdom: "root" 267 ansible_httpapi_use_ssl: yes 268 ansible_httpapi_validate_certs: no 269 ansible_httpapi_port: 443 270 tasks: 271 - name: Configure DNS domain filter profiles. 272 fortios_dnsfilter_profile: 273 vdom: "{{ vdom }}" 274 state: "present" 275 access_token: "<your_own_value>" 276 dnsfilter_profile: 277 block_action: "block" 278 block_botnet: "disable" 279 comment: "Comment." 280 dns_translation: 281 - 282 addr_type: "ipv4" 283 dst: "<your_own_value>" 284 dst6: "<your_own_value>" 285 id: "10" 286 netmask: "<your_own_value>" 287 prefix: "12" 288 src: "<your_own_value>" 289 src6: "<your_own_value>" 290 status: "enable" 291 domain_filter: 292 domain_filter_table: "17 (source dnsfilter.domain-filter.id)" 293 external_ip_blocklist: 294 - 295 name: "default_name_19 (source system.external-resource.name)" 296 ftgd_dns: 297 filters: 298 - 299 action: "block" 300 category: "23" 301 id: "24" 302 log: "enable" 303 options: "error-allow" 304 log_all_domain: "enable" 305 name: "default_name_28" 306 redirect_portal: "<your_own_value>" 307 redirect_portal6: "<your_own_value>" 308 safe_search: "disable" 309 sdns_domain_log: "enable" 310 sdns_ftgd_err_log: "enable" 311 youtube_restrict: "strict" 312 313''' 314 315RETURN = ''' 316build: 317 description: Build number of the fortigate image 318 returned: always 319 type: str 320 sample: '1547' 321http_method: 322 description: Last method used to provision the content into FortiGate 323 returned: always 324 type: str 325 sample: 'PUT' 326http_status: 327 description: Last result given by FortiGate on last operation applied 328 returned: always 329 type: str 330 sample: "200" 331mkey: 332 description: Master key (id) used in the last call to FortiGate 333 returned: success 334 type: str 335 sample: "id" 336name: 337 description: Name of the table used to fulfill the request 338 returned: always 339 type: str 340 sample: "urlfilter" 341path: 342 description: Path of the table used to fulfill the request 343 returned: always 344 type: str 345 sample: "webfilter" 346revision: 347 description: Internal revision number 348 returned: always 349 type: str 350 sample: "17.0.2.10658" 351serial: 352 description: Serial number of the unit 353 returned: always 354 type: str 355 sample: "FGVMEVYYQT3AB5352" 356status: 357 description: Indication of the operation's result 358 returned: always 359 type: str 360 sample: "success" 361vdom: 362 description: Virtual domain used 363 returned: always 364 type: str 365 sample: "root" 366version: 367 description: Version of the FortiGate 368 returned: always 369 type: str 370 sample: "v5.6.3" 371 372''' 373from ansible.module_utils.basic import AnsibleModule 374from ansible.module_utils.connection import Connection 375from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import FortiOSHandler 376from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_legacy_fortiosapi 377from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import schema_to_module_spec 378from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_schema_versioning 379from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG 380from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import is_same_comparison 381from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import serialize 382 383 384def filter_dnsfilter_profile_data(json): 385 option_list = ['block_action', 'block_botnet', 'comment', 386 'dns_translation', 'domain_filter', 'external_ip_blocklist', 387 'ftgd_dns', 'log_all_domain', 'name', 388 'redirect_portal', 'redirect_portal6', 'safe_search', 389 'sdns_domain_log', 'sdns_ftgd_err_log', 'youtube_restrict'] 390 dictionary = {} 391 392 for attribute in option_list: 393 if attribute in json and json[attribute] is not None: 394 dictionary[attribute] = json[attribute] 395 396 return dictionary 397 398 399def flatten_single_path(data, path, index): 400 if not data or index == len(path) or path[index] not in data or not data[path[index]]: 401 return 402 403 if index == len(path) - 1: 404 data[path[index]] = ' '.join(str(elem) for elem in data[path[index]]) 405 elif isinstance(data[path[index]], list): 406 for value in data[path[index]]: 407 flatten_single_path(value, path, index + 1) 408 else: 409 flatten_single_path(data[path[index]], path, index + 1) 410 411 412def flatten_multilists_attributes(data): 413 multilist_attrs = [[u'ftgd_dns', u'options']] 414 415 for attr in multilist_attrs: 416 flatten_single_path(data, attr, 0) 417 418 return data 419 420 421def underscore_to_hyphen(data): 422 if isinstance(data, list): 423 for i, elem in enumerate(data): 424 data[i] = underscore_to_hyphen(elem) 425 elif isinstance(data, dict): 426 new_data = {} 427 for k, v in data.items(): 428 new_data[k.replace('_', '-')] = underscore_to_hyphen(v) 429 data = new_data 430 431 return data 432 433 434def dnsfilter_profile(data, fos, check_mode=False): 435 436 vdom = data['vdom'] 437 438 state = data['state'] 439 440 dnsfilter_profile_data = data['dnsfilter_profile'] 441 dnsfilter_profile_data = flatten_multilists_attributes(dnsfilter_profile_data) 442 filtered_data = underscore_to_hyphen(filter_dnsfilter_profile_data(dnsfilter_profile_data)) 443 444 # check_mode starts from here 445 if check_mode: 446 mkey = fos.get_mkey('system', 'interface', filtered_data, vdom=vdom) 447 current_data = fos.get('system', 'interface', vdom=vdom, mkey=mkey) 448 is_existed = current_data and current_data.get('http_status') == 200 \ 449 and isinstance(current_data.get('results'), list) \ 450 and len(current_data['results']) > 0 451 452 # 2. if it exists and the state is 'present' then compare current settings with desired 453 if state == 'present' or state is True: 454 if mkey is None: 455 return False, True, filtered_data 456 457 # if mkey exists then compare each other 458 # record exits and they're matched or not 459 if is_existed: 460 is_same = is_same_comparison( 461 serialize(current_data['results'][0]), serialize(filtered_data)) 462 return False, not is_same, filtered_data 463 464 # record does not exist 465 return False, True, filtered_data 466 467 if state == 'absent': 468 if mkey is None: 469 return False, False, filtered_data 470 471 if is_existed: 472 return False, True, filtered_data 473 return False, False, filtered_data 474 475 return True, False, {'reason: ': 'Must provide state parameter'} 476 477 if state == "present" or state is True: 478 return fos.set('dnsfilter', 479 'profile', 480 data=filtered_data, 481 vdom=vdom) 482 483 elif state == "absent": 484 return fos.delete('dnsfilter', 485 'profile', 486 mkey=filtered_data['name'], 487 vdom=vdom) 488 else: 489 fos._module.fail_json(msg='state must be present or absent!') 490 491 492def is_successful_status(status): 493 return status['status'] == "success" or \ 494 status['http_method'] == "DELETE" and status['http_status'] == 404 495 496 497def fortios_dnsfilter(data, fos, check_mode): 498 499 if data['dnsfilter_profile']: 500 resp = dnsfilter_profile(data, fos, check_mode) 501 else: 502 fos._module.fail_json(msg='missing task body: %s' % ('dnsfilter_profile')) 503 if check_mode: 504 return resp 505 return not is_successful_status(resp), \ 506 resp['status'] == "success" and \ 507 (resp['revision_changed'] if 'revision_changed' in resp else True), \ 508 resp 509 510 511versioned_schema = { 512 "type": "list", 513 "children": { 514 "comment": { 515 "type": "string", 516 "revisions": { 517 "v6.0.0": True, 518 "v7.0.0": True, 519 "v6.0.5": True, 520 "v6.4.4": True, 521 "v6.4.0": True, 522 "v6.4.1": True, 523 "v6.2.0": True, 524 "v6.2.3": True, 525 "v6.2.5": True, 526 "v6.2.7": True, 527 "v6.0.11": True 528 } 529 }, 530 "external_ip_blocklist": { 531 "type": "list", 532 "children": { 533 "name": { 534 "type": "string", 535 "revisions": { 536 "v6.0.0": True, 537 "v7.0.0": True, 538 "v6.0.5": True, 539 "v6.4.4": True, 540 "v6.4.0": True, 541 "v6.4.1": True, 542 "v6.2.0": True, 543 "v6.2.3": True, 544 "v6.2.5": True, 545 "v6.2.7": True, 546 "v6.0.11": True 547 } 548 } 549 }, 550 "revisions": { 551 "v6.0.0": True, 552 "v7.0.0": True, 553 "v6.0.5": True, 554 "v6.4.4": True, 555 "v6.4.0": True, 556 "v6.4.1": True, 557 "v6.2.0": True, 558 "v6.2.3": True, 559 "v6.2.5": True, 560 "v6.2.7": True, 561 "v6.0.11": True 562 } 563 }, 564 "domain_filter": { 565 "type": "dict", 566 "children": { 567 "domain_filter_table": { 568 "type": "integer", 569 "revisions": { 570 "v6.0.0": True, 571 "v7.0.0": True, 572 "v6.0.5": True, 573 "v6.4.4": True, 574 "v6.4.0": True, 575 "v6.4.1": True, 576 "v6.2.0": True, 577 "v6.2.3": True, 578 "v6.2.5": True, 579 "v6.2.7": True, 580 "v6.0.11": True 581 } 582 } 583 }, 584 "revisions": { 585 "v6.0.0": True, 586 "v7.0.0": True, 587 "v6.0.5": True, 588 "v6.4.4": True, 589 "v6.4.0": True, 590 "v6.4.1": True, 591 "v6.2.0": True, 592 "v6.2.3": True, 593 "v6.2.5": True, 594 "v6.2.7": True, 595 "v6.0.11": True 596 } 597 }, 598 "name": { 599 "type": "string", 600 "revisions": { 601 "v6.0.0": True, 602 "v7.0.0": True, 603 "v6.0.5": True, 604 "v6.4.4": True, 605 "v6.4.0": True, 606 "v6.4.1": True, 607 "v6.2.0": True, 608 "v6.2.3": True, 609 "v6.2.5": True, 610 "v6.2.7": True, 611 "v6.0.11": True 612 } 613 }, 614 "youtube_restrict": { 615 "type": "string", 616 "options": [ 617 { 618 "value": "strict", 619 "revisions": { 620 "v6.0.0": True, 621 "v7.0.0": True, 622 "v6.0.5": True, 623 "v6.4.4": True, 624 "v6.4.0": True, 625 "v6.4.1": True, 626 "v6.2.0": True, 627 "v6.2.3": True, 628 "v6.2.5": True, 629 "v6.2.7": True, 630 "v6.0.11": True 631 } 632 }, 633 { 634 "value": "moderate", 635 "revisions": { 636 "v6.0.0": True, 637 "v7.0.0": True, 638 "v6.0.5": True, 639 "v6.4.4": True, 640 "v6.4.0": True, 641 "v6.4.1": True, 642 "v6.2.0": True, 643 "v6.2.3": True, 644 "v6.2.5": True, 645 "v6.2.7": True, 646 "v6.0.11": True 647 } 648 } 649 ], 650 "revisions": { 651 "v6.0.0": True, 652 "v7.0.0": True, 653 "v6.0.5": True, 654 "v6.4.4": True, 655 "v6.4.0": True, 656 "v6.4.1": True, 657 "v6.2.0": True, 658 "v6.2.3": True, 659 "v6.2.5": True, 660 "v6.2.7": True, 661 "v6.0.11": True 662 } 663 }, 664 "log_all_domain": { 665 "type": "string", 666 "options": [ 667 { 668 "value": "enable", 669 "revisions": { 670 "v6.0.0": True, 671 "v7.0.0": True, 672 "v6.0.5": True, 673 "v6.4.4": True, 674 "v6.4.0": True, 675 "v6.4.1": True, 676 "v6.2.0": True, 677 "v6.2.3": True, 678 "v6.2.5": True, 679 "v6.2.7": True, 680 "v6.0.11": True 681 } 682 }, 683 { 684 "value": "disable", 685 "revisions": { 686 "v6.0.0": True, 687 "v7.0.0": True, 688 "v6.0.5": True, 689 "v6.4.4": True, 690 "v6.4.0": True, 691 "v6.4.1": True, 692 "v6.2.0": True, 693 "v6.2.3": True, 694 "v6.2.5": True, 695 "v6.2.7": True, 696 "v6.0.11": True 697 } 698 } 699 ], 700 "revisions": { 701 "v6.0.0": True, 702 "v7.0.0": True, 703 "v6.0.5": True, 704 "v6.4.4": True, 705 "v6.4.0": True, 706 "v6.4.1": True, 707 "v6.2.0": True, 708 "v6.2.3": True, 709 "v6.2.5": True, 710 "v6.2.7": True, 711 "v6.0.11": True 712 } 713 }, 714 "safe_search": { 715 "type": "string", 716 "options": [ 717 { 718 "value": "disable", 719 "revisions": { 720 "v6.0.0": True, 721 "v7.0.0": True, 722 "v6.0.5": True, 723 "v6.4.4": True, 724 "v6.4.0": True, 725 "v6.4.1": True, 726 "v6.2.0": True, 727 "v6.2.3": True, 728 "v6.2.5": True, 729 "v6.2.7": True, 730 "v6.0.11": True 731 } 732 }, 733 { 734 "value": "enable", 735 "revisions": { 736 "v6.0.0": True, 737 "v7.0.0": True, 738 "v6.0.5": True, 739 "v6.4.4": True, 740 "v6.4.0": True, 741 "v6.4.1": True, 742 "v6.2.0": True, 743 "v6.2.3": True, 744 "v6.2.5": True, 745 "v6.2.7": True, 746 "v6.0.11": True 747 } 748 } 749 ], 750 "revisions": { 751 "v6.0.0": True, 752 "v7.0.0": True, 753 "v6.0.5": True, 754 "v6.4.4": True, 755 "v6.4.0": True, 756 "v6.4.1": True, 757 "v6.2.0": True, 758 "v6.2.3": True, 759 "v6.2.5": True, 760 "v6.2.7": True, 761 "v6.0.11": True 762 } 763 }, 764 "redirect_portal6": { 765 "type": "string", 766 "revisions": { 767 "v7.0.0": True, 768 "v6.4.4": True, 769 "v6.4.0": True, 770 "v6.4.1": True, 771 "v6.2.0": True, 772 "v6.2.3": True, 773 "v6.2.5": True, 774 "v6.2.7": True 775 } 776 }, 777 "block_botnet": { 778 "type": "string", 779 "options": [ 780 { 781 "value": "disable", 782 "revisions": { 783 "v6.0.0": True, 784 "v7.0.0": True, 785 "v6.0.5": True, 786 "v6.4.4": True, 787 "v6.4.0": True, 788 "v6.4.1": True, 789 "v6.2.0": True, 790 "v6.2.3": True, 791 "v6.2.5": True, 792 "v6.2.7": True, 793 "v6.0.11": True 794 } 795 }, 796 { 797 "value": "enable", 798 "revisions": { 799 "v6.0.0": True, 800 "v7.0.0": True, 801 "v6.0.5": True, 802 "v6.4.4": True, 803 "v6.4.0": True, 804 "v6.4.1": True, 805 "v6.2.0": True, 806 "v6.2.3": True, 807 "v6.2.5": True, 808 "v6.2.7": True, 809 "v6.0.11": True 810 } 811 } 812 ], 813 "revisions": { 814 "v6.0.0": True, 815 "v7.0.0": True, 816 "v6.0.5": True, 817 "v6.4.4": True, 818 "v6.4.0": True, 819 "v6.4.1": True, 820 "v6.2.0": True, 821 "v6.2.3": True, 822 "v6.2.5": True, 823 "v6.2.7": True, 824 "v6.0.11": True 825 } 826 }, 827 "sdns_ftgd_err_log": { 828 "type": "string", 829 "options": [ 830 { 831 "value": "enable", 832 "revisions": { 833 "v6.0.0": True, 834 "v7.0.0": True, 835 "v6.0.5": True, 836 "v6.4.4": True, 837 "v6.4.0": True, 838 "v6.4.1": True, 839 "v6.2.0": True, 840 "v6.2.3": True, 841 "v6.2.5": True, 842 "v6.2.7": True, 843 "v6.0.11": True 844 } 845 }, 846 { 847 "value": "disable", 848 "revisions": { 849 "v6.0.0": True, 850 "v7.0.0": True, 851 "v6.0.5": True, 852 "v6.4.4": True, 853 "v6.4.0": True, 854 "v6.4.1": True, 855 "v6.2.0": True, 856 "v6.2.3": True, 857 "v6.2.5": True, 858 "v6.2.7": True, 859 "v6.0.11": True 860 } 861 } 862 ], 863 "revisions": { 864 "v6.0.0": True, 865 "v7.0.0": True, 866 "v6.0.5": True, 867 "v6.4.4": True, 868 "v6.4.0": True, 869 "v6.4.1": True, 870 "v6.2.0": True, 871 "v6.2.3": True, 872 "v6.2.5": True, 873 "v6.2.7": True, 874 "v6.0.11": True 875 } 876 }, 877 "block_action": { 878 "type": "string", 879 "options": [ 880 { 881 "value": "block", 882 "revisions": { 883 "v6.0.0": True, 884 "v7.0.0": True, 885 "v6.0.5": True, 886 "v6.4.4": True, 887 "v6.4.0": True, 888 "v6.4.1": True, 889 "v6.2.0": True, 890 "v6.2.3": True, 891 "v6.2.5": True, 892 "v6.2.7": True, 893 "v6.0.11": True 894 } 895 }, 896 { 897 "value": "redirect", 898 "revisions": { 899 "v6.0.0": True, 900 "v7.0.0": True, 901 "v6.0.5": True, 902 "v6.4.4": True, 903 "v6.4.0": True, 904 "v6.4.1": True, 905 "v6.2.0": True, 906 "v6.2.3": True, 907 "v6.2.5": True, 908 "v6.2.7": True, 909 "v6.0.11": True 910 } 911 } 912 ], 913 "revisions": { 914 "v6.0.0": True, 915 "v7.0.0": True, 916 "v6.0.5": True, 917 "v6.4.4": True, 918 "v6.4.0": True, 919 "v6.4.1": True, 920 "v6.2.0": True, 921 "v6.2.3": True, 922 "v6.2.5": True, 923 "v6.2.7": True, 924 "v6.0.11": True 925 } 926 }, 927 "redirect_portal": { 928 "type": "string", 929 "revisions": { 930 "v6.0.0": True, 931 "v7.0.0": True, 932 "v6.0.5": True, 933 "v6.4.4": True, 934 "v6.4.0": True, 935 "v6.4.1": True, 936 "v6.2.0": True, 937 "v6.2.3": True, 938 "v6.2.5": True, 939 "v6.2.7": True, 940 "v6.0.11": True 941 } 942 }, 943 "ftgd_dns": { 944 "type": "dict", 945 "children": { 946 "options": { 947 "multiple_values": True, 948 "type": "list", 949 "options": [ 950 { 951 "value": "error-allow", 952 "revisions": { 953 "v6.0.0": True, 954 "v7.0.0": True, 955 "v6.0.5": True, 956 "v6.4.4": True, 957 "v6.4.0": True, 958 "v6.4.1": True, 959 "v6.2.0": True, 960 "v6.2.3": True, 961 "v6.2.5": True, 962 "v6.2.7": True, 963 "v6.0.11": True 964 } 965 }, 966 { 967 "value": "ftgd-disable", 968 "revisions": { 969 "v6.0.0": True, 970 "v7.0.0": True, 971 "v6.0.5": True, 972 "v6.4.4": True, 973 "v6.4.0": True, 974 "v6.4.1": True, 975 "v6.2.0": True, 976 "v6.2.3": True, 977 "v6.2.5": True, 978 "v6.2.7": True, 979 "v6.0.11": True 980 } 981 } 982 ], 983 "revisions": { 984 "v6.0.0": True, 985 "v7.0.0": True, 986 "v6.0.5": True, 987 "v6.4.4": True, 988 "v6.4.0": True, 989 "v6.4.1": True, 990 "v6.2.0": True, 991 "v6.2.3": True, 992 "v6.2.5": True, 993 "v6.2.7": True, 994 "v6.0.11": True 995 } 996 }, 997 "filters": { 998 "type": "list", 999 "children": { 1000 "category": { 1001 "type": "integer", 1002 "revisions": { 1003 "v6.0.0": True, 1004 "v7.0.0": True, 1005 "v6.0.5": True, 1006 "v6.4.4": True, 1007 "v6.4.0": True, 1008 "v6.4.1": True, 1009 "v6.2.0": True, 1010 "v6.2.3": True, 1011 "v6.2.5": True, 1012 "v6.2.7": True, 1013 "v6.0.11": True 1014 } 1015 }, 1016 "action": { 1017 "type": "string", 1018 "options": [ 1019 { 1020 "value": "block", 1021 "revisions": { 1022 "v6.0.0": True, 1023 "v7.0.0": True, 1024 "v6.0.5": True, 1025 "v6.4.4": True, 1026 "v6.4.0": True, 1027 "v6.4.1": True, 1028 "v6.2.0": True, 1029 "v6.2.3": True, 1030 "v6.2.5": True, 1031 "v6.2.7": True, 1032 "v6.0.11": True 1033 } 1034 }, 1035 { 1036 "value": "monitor", 1037 "revisions": { 1038 "v6.0.0": True, 1039 "v7.0.0": True, 1040 "v6.0.5": True, 1041 "v6.4.4": True, 1042 "v6.4.0": True, 1043 "v6.4.1": True, 1044 "v6.2.0": True, 1045 "v6.2.3": True, 1046 "v6.2.5": True, 1047 "v6.2.7": True, 1048 "v6.0.11": True 1049 } 1050 } 1051 ], 1052 "revisions": { 1053 "v6.0.0": True, 1054 "v7.0.0": True, 1055 "v6.0.5": True, 1056 "v6.4.4": True, 1057 "v6.4.0": True, 1058 "v6.4.1": True, 1059 "v6.2.0": True, 1060 "v6.2.3": True, 1061 "v6.2.5": True, 1062 "v6.2.7": True, 1063 "v6.0.11": True 1064 } 1065 }, 1066 "id": { 1067 "type": "integer", 1068 "revisions": { 1069 "v6.0.0": True, 1070 "v7.0.0": True, 1071 "v6.0.5": True, 1072 "v6.4.4": True, 1073 "v6.4.0": True, 1074 "v6.4.1": True, 1075 "v6.2.0": True, 1076 "v6.2.3": True, 1077 "v6.2.5": True, 1078 "v6.2.7": True, 1079 "v6.0.11": True 1080 } 1081 }, 1082 "log": { 1083 "type": "string", 1084 "options": [ 1085 { 1086 "value": "enable", 1087 "revisions": { 1088 "v6.0.0": True, 1089 "v7.0.0": True, 1090 "v6.0.5": True, 1091 "v6.4.4": True, 1092 "v6.4.0": True, 1093 "v6.4.1": True, 1094 "v6.2.0": True, 1095 "v6.2.3": True, 1096 "v6.2.5": True, 1097 "v6.2.7": True, 1098 "v6.0.11": True 1099 } 1100 }, 1101 { 1102 "value": "disable", 1103 "revisions": { 1104 "v6.0.0": True, 1105 "v7.0.0": True, 1106 "v6.0.5": True, 1107 "v6.4.4": True, 1108 "v6.4.0": True, 1109 "v6.4.1": True, 1110 "v6.2.0": True, 1111 "v6.2.3": True, 1112 "v6.2.5": True, 1113 "v6.2.7": True, 1114 "v6.0.11": True 1115 } 1116 } 1117 ], 1118 "revisions": { 1119 "v6.0.0": True, 1120 "v7.0.0": True, 1121 "v6.0.5": True, 1122 "v6.4.4": True, 1123 "v6.4.0": True, 1124 "v6.4.1": True, 1125 "v6.2.0": True, 1126 "v6.2.3": True, 1127 "v6.2.5": True, 1128 "v6.2.7": True, 1129 "v6.0.11": True 1130 } 1131 } 1132 }, 1133 "revisions": { 1134 "v6.0.0": True, 1135 "v7.0.0": True, 1136 "v6.0.5": True, 1137 "v6.4.4": True, 1138 "v6.4.0": True, 1139 "v6.4.1": True, 1140 "v6.2.0": True, 1141 "v6.2.3": True, 1142 "v6.2.5": True, 1143 "v6.2.7": True, 1144 "v6.0.11": True 1145 } 1146 } 1147 }, 1148 "revisions": { 1149 "v6.0.0": True, 1150 "v7.0.0": True, 1151 "v6.0.5": True, 1152 "v6.4.4": True, 1153 "v6.4.0": True, 1154 "v6.4.1": True, 1155 "v6.2.0": True, 1156 "v6.2.3": True, 1157 "v6.2.5": True, 1158 "v6.2.7": True, 1159 "v6.0.11": True 1160 } 1161 }, 1162 "dns_translation": { 1163 "type": "list", 1164 "children": { 1165 "status": { 1166 "type": "string", 1167 "options": [ 1168 { 1169 "value": "enable", 1170 "revisions": { 1171 "v7.0.0": True, 1172 "v6.4.4": True, 1173 "v6.4.0": True, 1174 "v6.4.1": True, 1175 "v6.2.0": True, 1176 "v6.2.3": True, 1177 "v6.2.5": True, 1178 "v6.2.7": True 1179 } 1180 }, 1181 { 1182 "value": "disable", 1183 "revisions": { 1184 "v7.0.0": True, 1185 "v6.4.4": True, 1186 "v6.4.0": True, 1187 "v6.4.1": True, 1188 "v6.2.0": True, 1189 "v6.2.3": True, 1190 "v6.2.5": True, 1191 "v6.2.7": True 1192 } 1193 } 1194 ], 1195 "revisions": { 1196 "v7.0.0": True, 1197 "v6.4.4": True, 1198 "v6.4.0": True, 1199 "v6.4.1": True, 1200 "v6.2.0": True, 1201 "v6.2.3": True, 1202 "v6.2.5": True, 1203 "v6.2.7": True 1204 } 1205 }, 1206 "src": { 1207 "type": "string", 1208 "revisions": { 1209 "v7.0.0": True, 1210 "v6.4.4": True, 1211 "v6.4.0": True, 1212 "v6.4.1": True, 1213 "v6.2.0": True, 1214 "v6.2.3": True, 1215 "v6.2.5": True, 1216 "v6.2.7": True 1217 } 1218 }, 1219 "dst6": { 1220 "type": "string", 1221 "revisions": { 1222 "v7.0.0": True, 1223 "v6.4.4": True, 1224 "v6.4.0": True, 1225 "v6.4.1": True, 1226 "v6.2.0": True, 1227 "v6.2.3": True, 1228 "v6.2.5": True, 1229 "v6.2.7": True 1230 } 1231 }, 1232 "dst": { 1233 "type": "string", 1234 "revisions": { 1235 "v7.0.0": True, 1236 "v6.4.4": True, 1237 "v6.4.0": True, 1238 "v6.4.1": True, 1239 "v6.2.0": True, 1240 "v6.2.3": True, 1241 "v6.2.5": True, 1242 "v6.2.7": True 1243 } 1244 }, 1245 "prefix": { 1246 "type": "integer", 1247 "revisions": { 1248 "v7.0.0": True, 1249 "v6.4.4": True, 1250 "v6.4.0": True, 1251 "v6.4.1": True, 1252 "v6.2.0": True, 1253 "v6.2.3": True, 1254 "v6.2.5": True, 1255 "v6.2.7": True 1256 } 1257 }, 1258 "id": { 1259 "type": "integer", 1260 "revisions": { 1261 "v7.0.0": True, 1262 "v6.4.4": True, 1263 "v6.4.0": True, 1264 "v6.4.1": True, 1265 "v6.2.0": True, 1266 "v6.2.3": True, 1267 "v6.2.5": True, 1268 "v6.2.7": True 1269 } 1270 }, 1271 "netmask": { 1272 "type": "string", 1273 "revisions": { 1274 "v7.0.0": True, 1275 "v6.4.4": True, 1276 "v6.4.0": True, 1277 "v6.4.1": True, 1278 "v6.2.0": True, 1279 "v6.2.3": True, 1280 "v6.2.5": True, 1281 "v6.2.7": True 1282 } 1283 }, 1284 "src6": { 1285 "type": "string", 1286 "revisions": { 1287 "v7.0.0": True, 1288 "v6.4.4": True, 1289 "v6.4.0": True, 1290 "v6.4.1": True, 1291 "v6.2.0": True, 1292 "v6.2.3": True, 1293 "v6.2.5": True, 1294 "v6.2.7": True 1295 } 1296 }, 1297 "addr_type": { 1298 "type": "string", 1299 "options": [ 1300 { 1301 "value": "ipv4", 1302 "revisions": { 1303 "v7.0.0": True, 1304 "v6.4.4": True, 1305 "v6.4.0": True, 1306 "v6.4.1": True, 1307 "v6.2.0": True, 1308 "v6.2.3": True, 1309 "v6.2.5": True, 1310 "v6.2.7": True 1311 } 1312 }, 1313 { 1314 "value": "ipv6", 1315 "revisions": { 1316 "v7.0.0": True, 1317 "v6.4.4": True, 1318 "v6.4.0": True, 1319 "v6.4.1": True, 1320 "v6.2.0": True, 1321 "v6.2.3": True, 1322 "v6.2.5": True, 1323 "v6.2.7": True 1324 } 1325 } 1326 ], 1327 "revisions": { 1328 "v7.0.0": True, 1329 "v6.4.4": True, 1330 "v6.4.0": True, 1331 "v6.4.1": True, 1332 "v6.2.0": True, 1333 "v6.2.3": True, 1334 "v6.2.5": True, 1335 "v6.2.7": True 1336 } 1337 } 1338 }, 1339 "revisions": { 1340 "v7.0.0": True, 1341 "v6.4.4": True, 1342 "v6.4.0": True, 1343 "v6.4.1": True, 1344 "v6.2.0": True, 1345 "v6.2.3": True, 1346 "v6.2.5": True, 1347 "v6.2.7": True 1348 } 1349 }, 1350 "sdns_domain_log": { 1351 "type": "string", 1352 "options": [ 1353 { 1354 "value": "enable", 1355 "revisions": { 1356 "v6.0.0": True, 1357 "v7.0.0": True, 1358 "v6.0.5": True, 1359 "v6.4.4": True, 1360 "v6.4.0": True, 1361 "v6.4.1": True, 1362 "v6.2.0": True, 1363 "v6.2.3": True, 1364 "v6.2.5": True, 1365 "v6.2.7": True, 1366 "v6.0.11": True 1367 } 1368 }, 1369 { 1370 "value": "disable", 1371 "revisions": { 1372 "v6.0.0": True, 1373 "v7.0.0": True, 1374 "v6.0.5": True, 1375 "v6.4.4": True, 1376 "v6.4.0": True, 1377 "v6.4.1": True, 1378 "v6.2.0": True, 1379 "v6.2.3": True, 1380 "v6.2.5": True, 1381 "v6.2.7": True, 1382 "v6.0.11": True 1383 } 1384 } 1385 ], 1386 "revisions": { 1387 "v6.0.0": True, 1388 "v7.0.0": True, 1389 "v6.0.5": True, 1390 "v6.4.4": True, 1391 "v6.4.0": True, 1392 "v6.4.1": True, 1393 "v6.2.0": True, 1394 "v6.2.3": True, 1395 "v6.2.5": True, 1396 "v6.2.7": True, 1397 "v6.0.11": True 1398 } 1399 } 1400 }, 1401 "revisions": { 1402 "v6.0.0": True, 1403 "v7.0.0": True, 1404 "v6.0.5": True, 1405 "v6.4.4": True, 1406 "v6.4.0": True, 1407 "v6.4.1": True, 1408 "v6.2.0": True, 1409 "v6.2.3": True, 1410 "v6.2.5": True, 1411 "v6.2.7": True, 1412 "v6.0.11": True 1413 } 1414} 1415 1416 1417def main(): 1418 module_spec = schema_to_module_spec(versioned_schema) 1419 mkeyname = 'name' 1420 fields = { 1421 "access_token": {"required": False, "type": "str", "no_log": True}, 1422 "enable_log": {"required": False, "type": bool}, 1423 "vdom": {"required": False, "type": "str", "default": "root"}, 1424 "state": {"required": True, "type": "str", 1425 "choices": ["present", "absent"]}, 1426 "dnsfilter_profile": { 1427 "required": False, "type": "dict", "default": None, 1428 "options": { 1429 } 1430 } 1431 } 1432 for attribute_name in module_spec['options']: 1433 fields["dnsfilter_profile"]['options'][attribute_name] = module_spec['options'][attribute_name] 1434 if mkeyname and mkeyname == attribute_name: 1435 fields["dnsfilter_profile"]['options'][attribute_name]['required'] = True 1436 1437 check_legacy_fortiosapi() 1438 module = AnsibleModule(argument_spec=fields, 1439 supports_check_mode=True) 1440 1441 versions_check_result = None 1442 if module._socket_path: 1443 connection = Connection(module._socket_path) 1444 if 'access_token' in module.params: 1445 connection.set_option('access_token', module.params['access_token']) 1446 1447 if 'enable_log' in module.params: 1448 connection.set_option('enable_log', module.params['enable_log']) 1449 else: 1450 connection.set_option('enable_log', False) 1451 fos = FortiOSHandler(connection, module, mkeyname) 1452 versions_check_result = check_schema_versioning(fos, versioned_schema, "dnsfilter_profile") 1453 1454 is_error, has_changed, result = fortios_dnsfilter(module.params, fos, module.check_mode) 1455 1456 else: 1457 module.fail_json(**FAIL_SOCKET_MSG) 1458 1459 if versions_check_result and versions_check_result['matched'] is False: 1460 module.warn("Ansible has detected version mismatch between FortOS system and your playbook, see more details by specifying option -vvv") 1461 1462 if not is_error: 1463 if versions_check_result and versions_check_result['matched'] is False: 1464 module.exit_json(changed=has_changed, version_check_warning=versions_check_result, meta=result) 1465 else: 1466 module.exit_json(changed=has_changed, meta=result) 1467 else: 1468 if versions_check_result and versions_check_result['matched'] is False: 1469 module.fail_json(msg="Error in repo", version_check_warning=versions_check_result, meta=result) 1470 else: 1471 module.fail_json(msg="Error in repo", meta=result) 1472 1473 1474if __name__ == '__main__': 1475 main() 1476