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_router_policy 27short_description: Configure IPv4 routing policies 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 router feature and policy 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 router_policy: 76 description: 77 - Configure IPv4 routing policies. 78 default: null 79 type: dict 80 suboptions: 81 action: 82 description: 83 - Action of the policy route. 84 type: str 85 choices: 86 - deny 87 - permit 88 comments: 89 description: 90 - Optional comments. 91 type: str 92 dst: 93 description: 94 - Destination IP and mask (x.x.x.x/x). 95 type: list 96 suboptions: 97 subnet: 98 description: 99 - IP and mask. 100 required: true 101 type: str 102 dst_negate: 103 description: 104 - Enable/disable negating destination address match. 105 type: str 106 choices: 107 - enable 108 - disable 109 dstaddr: 110 description: 111 - Destination address name. 112 type: list 113 suboptions: 114 name: 115 description: 116 - Address/group name. Source firewall.address.name firewall.addrgrp.name. 117 required: true 118 type: str 119 end_port: 120 description: 121 - End destination port number (0 - 65535). 122 type: int 123 end_source_port: 124 description: 125 - End source port number (0 - 65535). 126 type: int 127 gateway: 128 description: 129 - IP address of the gateway. 130 type: str 131 input_device: 132 description: 133 - Incoming interface name. 134 type: list 135 suboptions: 136 name: 137 description: 138 - Interface name. Source system.interface.name. 139 required: true 140 type: str 141 input_device_negate: 142 description: 143 - Enable/disable negation of input device match. 144 type: str 145 choices: 146 - enable 147 - disable 148 internet_service_custom: 149 description: 150 - Custom Destination Internet Service name. 151 type: list 152 suboptions: 153 name: 154 description: 155 - Custom Destination Internet Service name. Source firewall.internet-service-custom.name. 156 required: true 157 type: str 158 internet_service_id: 159 description: 160 - Destination Internet Service ID. 161 type: list 162 suboptions: 163 id: 164 description: 165 - Destination Internet Service ID. Source firewall.internet-service.id. 166 required: true 167 type: int 168 output_device: 169 description: 170 - Outgoing interface name. Source system.interface.name. 171 type: str 172 protocol: 173 description: 174 - Protocol number (0 - 255). 175 type: int 176 seq_num: 177 description: 178 - Sequence number. 179 type: int 180 src: 181 description: 182 - Source IP and mask (x.x.x.x/x). 183 type: list 184 suboptions: 185 subnet: 186 description: 187 - IP and mask. 188 required: true 189 type: str 190 src_negate: 191 description: 192 - Enable/disable negating source address match. 193 type: str 194 choices: 195 - enable 196 - disable 197 srcaddr: 198 description: 199 - Source address name. 200 type: list 201 suboptions: 202 name: 203 description: 204 - Address/group name. Source firewall.address.name firewall.addrgrp.name. 205 required: true 206 type: str 207 start_port: 208 description: 209 - Start destination port number (0 - 65535). 210 type: int 211 start_source_port: 212 description: 213 - Start source port number (0 - 65535). 214 type: int 215 status: 216 description: 217 - Enable/disable this policy route. 218 type: str 219 choices: 220 - enable 221 - disable 222 tos: 223 description: 224 - Type of service bit pattern. 225 type: str 226 tos_mask: 227 description: 228 - Type of service evaluated bits. 229 type: str 230''' 231 232EXAMPLES = ''' 233- hosts: fortigates 234 collections: 235 - fortinet.fortios 236 connection: httpapi 237 vars: 238 vdom: "root" 239 ansible_httpapi_use_ssl: yes 240 ansible_httpapi_validate_certs: no 241 ansible_httpapi_port: 443 242 tasks: 243 - name: Configure IPv4 routing policies. 244 fortios_router_policy: 245 vdom: "{{ vdom }}" 246 state: "present" 247 access_token: "<your_own_value>" 248 router_policy: 249 action: "deny" 250 comments: "<your_own_value>" 251 dst: 252 - 253 subnet: "<your_own_value>" 254 dst_negate: "enable" 255 dstaddr: 256 - 257 name: "default_name_9 (source firewall.address.name firewall.addrgrp.name)" 258 end_port: "10" 259 end_source_port: "11" 260 gateway: "<your_own_value>" 261 input_device: 262 - 263 name: "default_name_14 (source system.interface.name)" 264 input_device_negate: "enable" 265 internet_service_custom: 266 - 267 name: "default_name_17 (source firewall.internet-service-custom.name)" 268 internet_service_id: 269 - 270 id: "19 (source firewall.internet-service.id)" 271 output_device: "<your_own_value> (source system.interface.name)" 272 protocol: "21" 273 seq_num: "22" 274 src: 275 - 276 subnet: "<your_own_value>" 277 src_negate: "enable" 278 srcaddr: 279 - 280 name: "default_name_27 (source firewall.address.name firewall.addrgrp.name)" 281 start_port: "28" 282 start_source_port: "29" 283 status: "enable" 284 tos: "<your_own_value>" 285 tos_mask: "<your_own_value>" 286 287''' 288 289RETURN = ''' 290build: 291 description: Build number of the fortigate image 292 returned: always 293 type: str 294 sample: '1547' 295http_method: 296 description: Last method used to provision the content into FortiGate 297 returned: always 298 type: str 299 sample: 'PUT' 300http_status: 301 description: Last result given by FortiGate on last operation applied 302 returned: always 303 type: str 304 sample: "200" 305mkey: 306 description: Master key (id) used in the last call to FortiGate 307 returned: success 308 type: str 309 sample: "id" 310name: 311 description: Name of the table used to fulfill the request 312 returned: always 313 type: str 314 sample: "urlfilter" 315path: 316 description: Path of the table used to fulfill the request 317 returned: always 318 type: str 319 sample: "webfilter" 320revision: 321 description: Internal revision number 322 returned: always 323 type: str 324 sample: "17.0.2.10658" 325serial: 326 description: Serial number of the unit 327 returned: always 328 type: str 329 sample: "FGVMEVYYQT3AB5352" 330status: 331 description: Indication of the operation's result 332 returned: always 333 type: str 334 sample: "success" 335vdom: 336 description: Virtual domain used 337 returned: always 338 type: str 339 sample: "root" 340version: 341 description: Version of the FortiGate 342 returned: always 343 type: str 344 sample: "v5.6.3" 345 346''' 347from ansible.module_utils.basic import AnsibleModule 348from ansible.module_utils.connection import Connection 349from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import FortiOSHandler 350from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_legacy_fortiosapi 351from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import schema_to_module_spec 352from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_schema_versioning 353from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG 354from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import is_same_comparison 355from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import serialize 356 357 358def filter_router_policy_data(json): 359 option_list = ['action', 'comments', 'dst', 360 'dst_negate', 'dstaddr', 'end_port', 361 'end_source_port', 'gateway', 'input_device', 362 'input_device_negate', 'internet_service_custom', 'internet_service_id', 363 'output_device', 'protocol', 'seq_num', 364 'src', 'src_negate', 'srcaddr', 365 'start_port', 'start_source_port', 'status', 366 'tos', 'tos_mask'] 367 dictionary = {} 368 369 for attribute in option_list: 370 if attribute in json and json[attribute] is not None: 371 dictionary[attribute] = json[attribute] 372 373 return dictionary 374 375 376def underscore_to_hyphen(data): 377 if isinstance(data, list): 378 for i, elem in enumerate(data): 379 data[i] = underscore_to_hyphen(elem) 380 elif isinstance(data, dict): 381 new_data = {} 382 for k, v in data.items(): 383 new_data[k.replace('_', '-')] = underscore_to_hyphen(v) 384 data = new_data 385 386 return data 387 388 389def router_policy(data, fos, check_mode=False): 390 391 vdom = data['vdom'] 392 393 state = data['state'] 394 395 router_policy_data = data['router_policy'] 396 filtered_data = underscore_to_hyphen(filter_router_policy_data(router_policy_data)) 397 398 # check_mode starts from here 399 if check_mode: 400 mkey = fos.get_mkey('system', 'interface', filtered_data, vdom=vdom) 401 current_data = fos.get('system', 'interface', vdom=vdom, mkey=mkey) 402 is_existed = current_data and current_data.get('http_status') == 200 \ 403 and isinstance(current_data.get('results'), list) \ 404 and len(current_data['results']) > 0 405 406 # 2. if it exists and the state is 'present' then compare current settings with desired 407 if state == 'present' or state is True: 408 if mkey is None: 409 return False, True, filtered_data 410 411 # if mkey exists then compare each other 412 # record exits and they're matched or not 413 if is_existed: 414 is_same = is_same_comparison( 415 serialize(current_data['results'][0]), serialize(filtered_data)) 416 return False, not is_same, filtered_data 417 418 # record does not exist 419 return False, True, filtered_data 420 421 if state == 'absent': 422 if mkey is None: 423 return False, False, filtered_data 424 425 if is_existed: 426 return False, True, filtered_data 427 return False, False, filtered_data 428 429 return True, False, {'reason: ': 'Must provide state parameter'} 430 431 if state == "present" or state is True: 432 return fos.set('router', 433 'policy', 434 data=filtered_data, 435 vdom=vdom) 436 437 elif state == "absent": 438 return fos.delete('router', 439 'policy', 440 mkey=filtered_data['seq-num'], 441 vdom=vdom) 442 else: 443 fos._module.fail_json(msg='state must be present or absent!') 444 445 446def is_successful_status(status): 447 return status['status'] == "success" or \ 448 status['http_method'] == "DELETE" and status['http_status'] == 404 449 450 451def fortios_router(data, fos, check_mode): 452 453 if data['router_policy']: 454 resp = router_policy(data, fos, check_mode) 455 else: 456 fos._module.fail_json(msg='missing task body: %s' % ('router_policy')) 457 if check_mode: 458 return resp 459 return not is_successful_status(resp), \ 460 resp['status'] == "success" and \ 461 (resp['revision_changed'] if 'revision_changed' in resp else True), \ 462 resp 463 464 465versioned_schema = { 466 "type": "list", 467 "children": { 468 "protocol": { 469 "type": "integer", 470 "revisions": { 471 "v6.0.0": True, 472 "v7.0.0": True, 473 "v6.0.5": True, 474 "v6.4.4": True, 475 "v6.4.0": True, 476 "v6.4.1": True, 477 "v6.2.0": True, 478 "v6.2.3": True, 479 "v6.2.5": True, 480 "v6.2.7": True, 481 "v6.0.11": True 482 } 483 }, 484 "end_port": { 485 "type": "integer", 486 "revisions": { 487 "v6.0.0": True, 488 "v7.0.0": True, 489 "v6.0.5": True, 490 "v6.4.4": True, 491 "v6.4.0": True, 492 "v6.4.1": True, 493 "v6.2.0": True, 494 "v6.2.3": True, 495 "v6.2.5": True, 496 "v6.2.7": True, 497 "v6.0.11": True 498 } 499 }, 500 "dst_negate": { 501 "type": "string", 502 "options": [ 503 { 504 "value": "enable", 505 "revisions": { 506 "v6.0.0": True, 507 "v7.0.0": True, 508 "v6.0.5": True, 509 "v6.4.4": True, 510 "v6.4.0": True, 511 "v6.4.1": True, 512 "v6.2.0": True, 513 "v6.2.3": True, 514 "v6.2.5": True, 515 "v6.2.7": True, 516 "v6.0.11": True 517 } 518 }, 519 { 520 "value": "disable", 521 "revisions": { 522 "v6.0.0": True, 523 "v7.0.0": True, 524 "v6.0.5": True, 525 "v6.4.4": True, 526 "v6.4.0": True, 527 "v6.4.1": True, 528 "v6.2.0": True, 529 "v6.2.3": True, 530 "v6.2.5": True, 531 "v6.2.7": True, 532 "v6.0.11": True 533 } 534 } 535 ], 536 "revisions": { 537 "v6.0.0": True, 538 "v7.0.0": True, 539 "v6.0.5": True, 540 "v6.4.4": True, 541 "v6.4.0": True, 542 "v6.4.1": True, 543 "v6.2.0": True, 544 "v6.2.3": True, 545 "v6.2.5": True, 546 "v6.2.7": True, 547 "v6.0.11": True 548 } 549 }, 550 "start_source_port": { 551 "type": "integer", 552 "revisions": { 553 "v6.0.0": True, 554 "v7.0.0": True, 555 "v6.0.5": True, 556 "v6.4.4": True, 557 "v6.4.0": True, 558 "v6.4.1": True, 559 "v6.2.0": True, 560 "v6.2.3": True, 561 "v6.2.5": True, 562 "v6.2.7": True, 563 "v6.0.11": True 564 } 565 }, 566 "internet_service_custom": { 567 "type": "list", 568 "children": { 569 "name": { 570 "type": "string", 571 "revisions": { 572 "v7.0.0": 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 } 581 } 582 }, 583 "revisions": { 584 "v7.0.0": True, 585 "v6.4.4": True, 586 "v6.4.0": True, 587 "v6.4.1": True, 588 "v6.2.0": True, 589 "v6.2.3": True, 590 "v6.2.5": True, 591 "v6.2.7": True 592 } 593 }, 594 "input_device": { 595 "type": "list", 596 "children": { 597 "name": { 598 "type": "string", 599 "revisions": { 600 "v6.0.0": True, 601 "v7.0.0": True, 602 "v6.0.5": True, 603 "v6.4.4": True, 604 "v6.4.0": True, 605 "v6.4.1": True, 606 "v6.2.0": True, 607 "v6.2.3": True, 608 "v6.2.5": True, 609 "v6.2.7": True, 610 "v6.0.11": True 611 } 612 } 613 }, 614 "revisions": { 615 "v6.0.0": True, 616 "v7.0.0": True, 617 "v6.0.5": True, 618 "v6.4.4": True, 619 "v6.4.0": True, 620 "v6.4.1": True, 621 "v6.2.0": True, 622 "v6.2.3": True, 623 "v6.2.5": True, 624 "v6.2.7": True, 625 "v6.0.11": True 626 } 627 }, 628 "gateway": { 629 "type": "string", 630 "revisions": { 631 "v6.0.0": True, 632 "v7.0.0": True, 633 "v6.0.5": True, 634 "v6.4.4": True, 635 "v6.4.0": True, 636 "v6.4.1": True, 637 "v6.2.0": True, 638 "v6.2.3": True, 639 "v6.2.5": True, 640 "v6.2.7": True, 641 "v6.0.11": True 642 } 643 }, 644 "tos": { 645 "type": "string", 646 "revisions": { 647 "v6.0.0": True, 648 "v7.0.0": True, 649 "v6.0.5": True, 650 "v6.4.4": True, 651 "v6.4.0": True, 652 "v6.4.1": True, 653 "v6.2.0": True, 654 "v6.2.3": True, 655 "v6.2.5": True, 656 "v6.2.7": True, 657 "v6.0.11": True 658 } 659 }, 660 "dst": { 661 "type": "list", 662 "children": { 663 "subnet": { 664 "type": "string", 665 "revisions": { 666 "v6.0.0": True, 667 "v7.0.0": True, 668 "v6.0.5": True, 669 "v6.4.4": True, 670 "v6.4.0": True, 671 "v6.4.1": True, 672 "v6.2.0": True, 673 "v6.2.3": True, 674 "v6.2.5": True, 675 "v6.2.7": True, 676 "v6.0.11": True 677 } 678 } 679 }, 680 "revisions": { 681 "v6.0.0": True, 682 "v7.0.0": True, 683 "v6.0.5": True, 684 "v6.4.4": True, 685 "v6.4.0": True, 686 "v6.4.1": True, 687 "v6.2.0": True, 688 "v6.2.3": True, 689 "v6.2.5": True, 690 "v6.2.7": True, 691 "v6.0.11": True 692 } 693 }, 694 "input_device_negate": { 695 "type": "string", 696 "options": [ 697 { 698 "value": "enable", 699 "revisions": { 700 "v7.0.0": True, 701 "v6.4.4": True, 702 "v6.4.0": True, 703 "v6.4.1": True, 704 "v6.2.0": True, 705 "v6.2.3": True, 706 "v6.2.5": True, 707 "v6.2.7": True 708 } 709 }, 710 { 711 "value": "disable", 712 "revisions": { 713 "v7.0.0": True, 714 "v6.4.4": True, 715 "v6.4.0": True, 716 "v6.4.1": True, 717 "v6.2.0": True, 718 "v6.2.3": True, 719 "v6.2.5": True, 720 "v6.2.7": True 721 } 722 } 723 ], 724 "revisions": { 725 "v7.0.0": True, 726 "v6.4.4": True, 727 "v6.4.0": True, 728 "v6.4.1": True, 729 "v6.2.0": True, 730 "v6.2.3": True, 731 "v6.2.5": True, 732 "v6.2.7": True 733 } 734 }, 735 "comments": { 736 "type": "string", 737 "revisions": { 738 "v6.0.0": True, 739 "v7.0.0": True, 740 "v6.0.5": True, 741 "v6.4.4": True, 742 "v6.4.0": True, 743 "v6.4.1": True, 744 "v6.2.0": True, 745 "v6.2.3": True, 746 "v6.2.5": True, 747 "v6.2.7": True, 748 "v6.0.11": True 749 } 750 }, 751 "status": { 752 "type": "string", 753 "options": [ 754 { 755 "value": "enable", 756 "revisions": { 757 "v6.0.0": True, 758 "v7.0.0": True, 759 "v6.0.5": True, 760 "v6.4.4": True, 761 "v6.4.0": True, 762 "v6.4.1": True, 763 "v6.2.0": True, 764 "v6.2.3": True, 765 "v6.2.5": True, 766 "v6.2.7": True, 767 "v6.0.11": True 768 } 769 }, 770 { 771 "value": "disable", 772 "revisions": { 773 "v6.0.0": True, 774 "v7.0.0": True, 775 "v6.0.5": True, 776 "v6.4.4": True, 777 "v6.4.0": True, 778 "v6.4.1": True, 779 "v6.2.0": True, 780 "v6.2.3": True, 781 "v6.2.5": True, 782 "v6.2.7": True, 783 "v6.0.11": True 784 } 785 } 786 ], 787 "revisions": { 788 "v6.0.0": True, 789 "v7.0.0": True, 790 "v6.0.5": True, 791 "v6.4.4": True, 792 "v6.4.0": True, 793 "v6.4.1": True, 794 "v6.2.0": True, 795 "v6.2.3": True, 796 "v6.2.5": True, 797 "v6.2.7": True, 798 "v6.0.11": True 799 } 800 }, 801 "start_port": { 802 "type": "integer", 803 "revisions": { 804 "v6.0.0": True, 805 "v7.0.0": True, 806 "v6.0.5": True, 807 "v6.4.4": True, 808 "v6.4.0": True, 809 "v6.4.1": True, 810 "v6.2.0": True, 811 "v6.2.3": True, 812 "v6.2.5": True, 813 "v6.2.7": True, 814 "v6.0.11": True 815 } 816 }, 817 "srcaddr": { 818 "type": "list", 819 "children": { 820 "name": { 821 "type": "string", 822 "revisions": { 823 "v6.0.0": True, 824 "v7.0.0": True, 825 "v6.0.5": True, 826 "v6.4.4": True, 827 "v6.4.0": True, 828 "v6.4.1": True, 829 "v6.2.0": True, 830 "v6.2.3": True, 831 "v6.2.5": True, 832 "v6.2.7": True, 833 "v6.0.11": True 834 } 835 } 836 }, 837 "revisions": { 838 "v6.0.0": True, 839 "v7.0.0": True, 840 "v6.0.5": True, 841 "v6.4.4": True, 842 "v6.4.0": True, 843 "v6.4.1": True, 844 "v6.2.0": True, 845 "v6.2.3": True, 846 "v6.2.5": True, 847 "v6.2.7": True, 848 "v6.0.11": True 849 } 850 }, 851 "tos_mask": { 852 "type": "string", 853 "revisions": { 854 "v6.0.0": True, 855 "v7.0.0": True, 856 "v6.0.5": True, 857 "v6.4.4": True, 858 "v6.4.0": True, 859 "v6.4.1": True, 860 "v6.2.0": True, 861 "v6.2.3": True, 862 "v6.2.5": True, 863 "v6.2.7": True, 864 "v6.0.11": True 865 } 866 }, 867 "src": { 868 "type": "list", 869 "children": { 870 "subnet": { 871 "type": "string", 872 "revisions": { 873 "v6.0.0": True, 874 "v7.0.0": True, 875 "v6.0.5": True, 876 "v6.4.4": True, 877 "v6.4.0": True, 878 "v6.4.1": True, 879 "v6.2.0": True, 880 "v6.2.3": True, 881 "v6.2.5": True, 882 "v6.2.7": True, 883 "v6.0.11": True 884 } 885 } 886 }, 887 "revisions": { 888 "v6.0.0": True, 889 "v7.0.0": True, 890 "v6.0.5": True, 891 "v6.4.4": True, 892 "v6.4.0": True, 893 "v6.4.1": True, 894 "v6.2.0": True, 895 "v6.2.3": True, 896 "v6.2.5": True, 897 "v6.2.7": True, 898 "v6.0.11": True 899 } 900 }, 901 "seq_num": { 902 "type": "integer", 903 "revisions": { 904 "v6.0.0": True, 905 "v7.0.0": True, 906 "v6.0.5": True, 907 "v6.4.4": True, 908 "v6.4.0": True, 909 "v6.4.1": True, 910 "v6.2.0": True, 911 "v6.2.3": True, 912 "v6.2.5": True, 913 "v6.2.7": True, 914 "v6.0.11": True 915 } 916 }, 917 "internet_service_id": { 918 "type": "list", 919 "children": { 920 "id": { 921 "type": "integer", 922 "revisions": { 923 "v7.0.0": True, 924 "v6.4.4": True, 925 "v6.4.0": True, 926 "v6.4.1": True, 927 "v6.2.0": True, 928 "v6.2.3": True, 929 "v6.2.5": True, 930 "v6.2.7": True 931 } 932 } 933 }, 934 "revisions": { 935 "v7.0.0": True, 936 "v6.4.4": True, 937 "v6.4.0": True, 938 "v6.4.1": True, 939 "v6.2.0": True, 940 "v6.2.3": True, 941 "v6.2.5": True, 942 "v6.2.7": True 943 } 944 }, 945 "src_negate": { 946 "type": "string", 947 "options": [ 948 { 949 "value": "enable", 950 "revisions": { 951 "v6.0.0": True, 952 "v7.0.0": True, 953 "v6.0.5": True, 954 "v6.4.4": True, 955 "v6.4.0": True, 956 "v6.4.1": True, 957 "v6.2.0": True, 958 "v6.2.3": True, 959 "v6.2.5": True, 960 "v6.2.7": True, 961 "v6.0.11": True 962 } 963 }, 964 { 965 "value": "disable", 966 "revisions": { 967 "v6.0.0": True, 968 "v7.0.0": True, 969 "v6.0.5": True, 970 "v6.4.4": True, 971 "v6.4.0": True, 972 "v6.4.1": True, 973 "v6.2.0": True, 974 "v6.2.3": True, 975 "v6.2.5": True, 976 "v6.2.7": True, 977 "v6.0.11": True 978 } 979 } 980 ], 981 "revisions": { 982 "v6.0.0": True, 983 "v7.0.0": True, 984 "v6.0.5": True, 985 "v6.4.4": True, 986 "v6.4.0": True, 987 "v6.4.1": True, 988 "v6.2.0": True, 989 "v6.2.3": True, 990 "v6.2.5": True, 991 "v6.2.7": True, 992 "v6.0.11": True 993 } 994 }, 995 "action": { 996 "type": "string", 997 "options": [ 998 { 999 "value": "deny", 1000 "revisions": { 1001 "v6.0.0": True, 1002 "v7.0.0": True, 1003 "v6.0.5": True, 1004 "v6.4.4": True, 1005 "v6.4.0": True, 1006 "v6.4.1": True, 1007 "v6.2.0": True, 1008 "v6.2.3": True, 1009 "v6.2.5": True, 1010 "v6.2.7": True, 1011 "v6.0.11": True 1012 } 1013 }, 1014 { 1015 "value": "permit", 1016 "revisions": { 1017 "v6.0.0": True, 1018 "v7.0.0": True, 1019 "v6.0.5": True, 1020 "v6.4.4": True, 1021 "v6.4.0": True, 1022 "v6.4.1": True, 1023 "v6.2.0": True, 1024 "v6.2.3": True, 1025 "v6.2.5": True, 1026 "v6.2.7": True, 1027 "v6.0.11": True 1028 } 1029 } 1030 ], 1031 "revisions": { 1032 "v6.0.0": True, 1033 "v7.0.0": True, 1034 "v6.0.5": True, 1035 "v6.4.4": True, 1036 "v6.4.0": True, 1037 "v6.4.1": True, 1038 "v6.2.0": True, 1039 "v6.2.3": True, 1040 "v6.2.5": True, 1041 "v6.2.7": True, 1042 "v6.0.11": True 1043 } 1044 }, 1045 "end_source_port": { 1046 "type": "integer", 1047 "revisions": { 1048 "v6.0.0": True, 1049 "v7.0.0": True, 1050 "v6.0.5": True, 1051 "v6.4.4": True, 1052 "v6.4.0": True, 1053 "v6.4.1": True, 1054 "v6.2.0": True, 1055 "v6.2.3": True, 1056 "v6.2.5": True, 1057 "v6.2.7": True, 1058 "v6.0.11": True 1059 } 1060 }, 1061 "dstaddr": { 1062 "type": "list", 1063 "children": { 1064 "name": { 1065 "type": "string", 1066 "revisions": { 1067 "v6.0.0": True, 1068 "v7.0.0": True, 1069 "v6.0.5": True, 1070 "v6.4.4": True, 1071 "v6.4.0": True, 1072 "v6.4.1": True, 1073 "v6.2.0": True, 1074 "v6.2.3": True, 1075 "v6.2.5": True, 1076 "v6.2.7": True, 1077 "v6.0.11": True 1078 } 1079 } 1080 }, 1081 "revisions": { 1082 "v6.0.0": True, 1083 "v7.0.0": True, 1084 "v6.0.5": True, 1085 "v6.4.4": True, 1086 "v6.4.0": True, 1087 "v6.4.1": True, 1088 "v6.2.0": True, 1089 "v6.2.3": True, 1090 "v6.2.5": True, 1091 "v6.2.7": True, 1092 "v6.0.11": True 1093 } 1094 }, 1095 "output_device": { 1096 "type": "string", 1097 "revisions": { 1098 "v6.0.0": True, 1099 "v7.0.0": True, 1100 "v6.0.5": True, 1101 "v6.4.4": True, 1102 "v6.4.0": True, 1103 "v6.4.1": True, 1104 "v6.2.0": True, 1105 "v6.2.3": True, 1106 "v6.2.5": True, 1107 "v6.2.7": True, 1108 "v6.0.11": True 1109 } 1110 } 1111 }, 1112 "revisions": { 1113 "v6.0.0": True, 1114 "v7.0.0": True, 1115 "v6.0.5": True, 1116 "v6.4.4": True, 1117 "v6.4.0": True, 1118 "v6.4.1": True, 1119 "v6.2.0": True, 1120 "v6.2.3": True, 1121 "v6.2.5": True, 1122 "v6.2.7": True, 1123 "v6.0.11": True 1124 } 1125} 1126 1127 1128def main(): 1129 module_spec = schema_to_module_spec(versioned_schema) 1130 mkeyname = 'seq-num' 1131 fields = { 1132 "access_token": {"required": False, "type": "str", "no_log": True}, 1133 "enable_log": {"required": False, "type": bool}, 1134 "vdom": {"required": False, "type": "str", "default": "root"}, 1135 "state": {"required": True, "type": "str", 1136 "choices": ["present", "absent"]}, 1137 "router_policy": { 1138 "required": False, "type": "dict", "default": None, 1139 "options": { 1140 } 1141 } 1142 } 1143 for attribute_name in module_spec['options']: 1144 fields["router_policy"]['options'][attribute_name] = module_spec['options'][attribute_name] 1145 if mkeyname and mkeyname == attribute_name: 1146 fields["router_policy"]['options'][attribute_name]['required'] = True 1147 1148 check_legacy_fortiosapi() 1149 module = AnsibleModule(argument_spec=fields, 1150 supports_check_mode=True) 1151 1152 versions_check_result = None 1153 if module._socket_path: 1154 connection = Connection(module._socket_path) 1155 if 'access_token' in module.params: 1156 connection.set_option('access_token', module.params['access_token']) 1157 1158 if 'enable_log' in module.params: 1159 connection.set_option('enable_log', module.params['enable_log']) 1160 else: 1161 connection.set_option('enable_log', False) 1162 fos = FortiOSHandler(connection, module, mkeyname) 1163 versions_check_result = check_schema_versioning(fos, versioned_schema, "router_policy") 1164 1165 is_error, has_changed, result = fortios_router(module.params, fos, module.check_mode) 1166 1167 else: 1168 module.fail_json(**FAIL_SOCKET_MSG) 1169 1170 if versions_check_result and versions_check_result['matched'] is False: 1171 module.warn("Ansible has detected version mismatch between FortOS system and your playbook, see more details by specifying option -vvv") 1172 1173 if not is_error: 1174 if versions_check_result and versions_check_result['matched'] is False: 1175 module.exit_json(changed=has_changed, version_check_warning=versions_check_result, meta=result) 1176 else: 1177 module.exit_json(changed=has_changed, meta=result) 1178 else: 1179 if versions_check_result and versions_check_result['matched'] is False: 1180 module.fail_json(msg="Error in repo", version_check_warning=versions_check_result, meta=result) 1181 else: 1182 module.fail_json(msg="Error in repo", meta=result) 1183 1184 1185if __name__ == '__main__': 1186 main() 1187