diff --git a/lib/ansible/modules/network/fortios/fortios_router_multicast.py b/lib/ansible/modules/network/fortios/fortios_router_multicast.py new file mode 100644 index 00000000000..355c75a8617 --- /dev/null +++ b/lib/ansible/modules/network/fortios/fortios_router_multicast.py @@ -0,0 +1,666 @@ +#!/usr/bin/python +from __future__ import (absolute_import, division, print_function) +# Copyright 2019 Fortinet, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# the lib use python logging can get it if the following is set in your +# Ansible config. + +__metaclass__ = type + +ANSIBLE_METADATA = {'status': ['preview'], + 'supported_by': 'community', + 'metadata_version': '1.1'} + +DOCUMENTATION = ''' +--- +module: fortios_router_multicast +short_description: Configure router multicast in Fortinet's FortiOS and FortiGate. +description: + - This module is able to configure a FortiGate or FortiOS by allowing the + user to set and modify router feature and multicast category. + Examples include all parameters and values need to be adjusted to datasources before usage. + Tested with FOS v6.0.2 +version_added: "2.8" +author: + - Miguel Angel Munoz (@mamunozgonzalez) + - Nicolas Thomas (@thomnico) +notes: + - Requires fortiosapi library developed by Fortinet + - Run as a local_action in your playbook +requirements: + - fortiosapi>=0.9.8 +options: + host: + description: + - FortiOS or FortiGate ip address. + required: true + username: + description: + - FortiOS or FortiGate username. + required: true + password: + description: + - FortiOS or FortiGate password. + default: "" + vdom: + description: + - Virtual domain, among those defined previously. A vdom is a + virtual instance of the FortiGate that can be configured and + used as a different unit. + default: root + https: + description: + - Indicates if the requests towards FortiGate must use HTTPS + protocol + type: bool + default: true + router_multicast: + description: + - Configure router multicast. + default: null + suboptions: + interface: + description: + - PIM interfaces. + suboptions: + bfd: + description: + - Enable/disable Protocol Independent Multicast (PIM) Bidirectional Forwarding Detection (BFD). + choices: + - enable + - disable + cisco-exclude-genid: + description: + - Exclude GenID from hello packets (compatibility with old Cisco IOS). + choices: + - enable + - disable + dr-priority: + description: + - DR election priority. + hello-holdtime: + description: + - Time before old neighbor information expires (0 - 65535 sec, default = 105). + hello-interval: + description: + - Interval between sending PIM hello messages (0 - 65535 sec, default = 30). + igmp: + description: + - IGMP configuration options. + suboptions: + access-group: + description: + - Groups IGMP hosts are allowed to join. Source router.access-list.name. + immediate-leave-group: + description: + - Groups to drop membership for immediately after receiving IGMPv2 leave. Source router.access-list.name. + last-member-query-count: + description: + - Number of group specific queries before removing group (2 - 7, default = 2). + last-member-query-interval: + description: + - Timeout between IGMPv2 leave and removing group (1 - 65535 msec, default = 1000). + query-interval: + description: + - Interval between queries to IGMP hosts (1 - 65535 sec, default = 125). + query-max-response-time: + description: + - Maximum time to wait for a IGMP query response (1 - 25 sec, default = 10). + query-timeout: + description: + - Timeout between queries before becoming querier for network (60 - 900, default = 255). + router-alert-check: + description: + - Enable/disable require IGMP packets contain router alert option. + choices: + - enable + - disable + version: + description: + - Maximum version of IGMP to support. + choices: + - 3 + - 2 + - 1 + join-group: + description: + - Join multicast groups. + suboptions: + address: + description: + - Multicast group IP address. + required: true + multicast-flow: + description: + - Acceptable source for multicast group. Source router.multicast-flow.name. + name: + description: + - Interface name. Source system.interface.name. + required: true + neighbour-filter: + description: + - Routers acknowledged as neighbor routers. Source router.access-list.name. + passive: + description: + - Enable/disable listening to IGMP but not participating in PIM. + choices: + - enable + - disable + pim-mode: + description: + - PIM operation mode. + choices: + - sparse-mode + - dense-mode + propagation-delay: + description: + - Delay flooding packets on this interface (100 - 5000 msec, default = 500). + rp-candidate: + description: + - Enable/disable compete to become RP in elections. + choices: + - enable + - disable + rp-candidate-group: + description: + - Multicast groups managed by this RP. Source router.access-list.name. + rp-candidate-interval: + description: + - RP candidate advertisement interval (1 - 16383 sec, default = 60). + rp-candidate-priority: + description: + - Router's priority as RP. + state-refresh-interval: + description: + - Interval between sending state-refresh packets (1 - 100 sec, default = 60). + static-group: + description: + - Statically set multicast groups to forward out. Source router.multicast-flow.name. + ttl-threshold: + description: + - Minimum TTL of multicast packets that will be forwarded (applied only to new multicast routes) (1 - 255, default = 1). + multicast-routing: + description: + - Enable/disable IP multicast routing. + choices: + - enable + - disable + pim-sm-global: + description: + - PIM sparse-mode global settings. + suboptions: + accept-register-list: + description: + - Sources allowed to register packets with this Rendezvous Point (RP). Source router.access-list.name. + accept-source-list: + description: + - Sources allowed to send multicast traffic. Source router.access-list.name. + bsr-allow-quick-refresh: + description: + - Enable/disable accept BSR quick refresh packets from neighbors. + choices: + - enable + - disable + bsr-candidate: + description: + - Enable/disable allowing this router to become a bootstrap router (BSR). + choices: + - enable + - disable + bsr-hash: + description: + - BSR hash length (0 - 32, default = 10). + bsr-interface: + description: + - Interface to advertise as candidate BSR. Source system.interface.name. + bsr-priority: + description: + - BSR priority (0 - 255, default = 0). + cisco-crp-prefix: + description: + - Enable/disable making candidate RP compatible with old Cisco IOS. + choices: + - enable + - disable + cisco-ignore-rp-set-priority: + description: + - Use only hash for RP selection (compatibility with old Cisco IOS). + choices: + - enable + - disable + cisco-register-checksum: + description: + - Checksum entire register packet(for old Cisco IOS compatibility). + choices: + - enable + - disable + cisco-register-checksum-group: + description: + - Cisco register checksum only these groups. Source router.access-list.name. + join-prune-holdtime: + description: + - Join/prune holdtime (1 - 65535, default = 210). + message-interval: + description: + - Period of time between sending periodic PIM join/prune messages in seconds (1 - 65535, default = 60). + null-register-retries: + description: + - Maximum retries of null register (1 - 20, default = 1). + register-rate-limit: + description: + - Limit of packets/sec per source registered through this RP (0 - 65535, default = 0 which means unlimited). + register-rp-reachability: + description: + - Enable/disable check RP is reachable before registering packets. + choices: + - enable + - disable + register-source: + description: + - Override source address in register packets. + choices: + - disable + - interface + - ip-address + register-source-interface: + description: + - Override with primary interface address. Source system.interface.name. + register-source-ip: + description: + - Override with local IP address. + register-supression: + description: + - Period of time to honor register-stop message (1 - 65535 sec, default = 60). + rp-address: + description: + - Statically configure RP addresses. + suboptions: + group: + description: + - Groups to use this RP. Source router.access-list.name. + id: + description: + - ID. + required: true + ip-address: + description: + - RP router address. + rp-register-keepalive: + description: + - Timeout for RP receiving data on (S,G) tree (1 - 65535 sec, default = 185). + spt-threshold: + description: + - Enable/disable switching to source specific trees. + choices: + - enable + - disable + spt-threshold-group: + description: + - Groups allowed to switch to source tree. Source router.access-list.name. + ssm: + description: + - Enable/disable source specific multicast. + choices: + - enable + - disable + ssm-range: + description: + - Groups allowed to source specific multicast. Source router.access-list.name. + route-limit: + description: + - Maximum number of multicast routes. + route-threshold: + description: + - Generate warnings when the number of multicast routes exceeds this number, must not be greater than route-limit. +''' + +EXAMPLES = ''' +- hosts: localhost + vars: + host: "192.168.122.40" + username: "admin" + password: "" + vdom: "root" + tasks: + - name: Configure router multicast. + fortios_router_multicast: + host: "{{ host }}" + username: "{{ username }}" + password: "{{ password }}" + vdom: "{{ vdom }}" + https: "False" + router_multicast: + interface: + - + bfd: "enable" + cisco-exclude-genid: "enable" + dr-priority: "6" + hello-holdtime: "7" + hello-interval: "8" + igmp: + access-group: " (source router.access-list.name)" + immediate-leave-group: " (source router.access-list.name)" + last-member-query-count: "12" + last-member-query-interval: "13" + query-interval: "14" + query-max-response-time: "15" + query-timeout: "16" + router-alert-check: "enable" + version: "3" + join-group: + - + address: "" + multicast-flow: " (source router.multicast-flow.name)" + name: "default_name_22 (source system.interface.name)" + neighbour-filter: " (source router.access-list.name)" + passive: "enable" + pim-mode: "sparse-mode" + propagation-delay: "26" + rp-candidate: "enable" + rp-candidate-group: " (source router.access-list.name)" + rp-candidate-interval: "29" + rp-candidate-priority: "30" + state-refresh-interval: "31" + static-group: " (source router.multicast-flow.name)" + ttl-threshold: "33" + multicast-routing: "enable" + pim-sm-global: + accept-register-list: " (source router.access-list.name)" + accept-source-list: " (source router.access-list.name)" + bsr-allow-quick-refresh: "enable" + bsr-candidate: "enable" + bsr-hash: "40" + bsr-interface: " (source system.interface.name)" + bsr-priority: "42" + cisco-crp-prefix: "enable" + cisco-ignore-rp-set-priority: "enable" + cisco-register-checksum: "enable" + cisco-register-checksum-group: " (source router.access-list.name)" + join-prune-holdtime: "47" + message-interval: "48" + null-register-retries: "49" + register-rate-limit: "50" + register-rp-reachability: "enable" + register-source: "disable" + register-source-interface: " (source system.interface.name)" + register-source-ip: "" + register-supression: "55" + rp-address: + - + group: " (source router.access-list.name)" + id: "58" + ip-address: "" + rp-register-keepalive: "60" + spt-threshold: "enable" + spt-threshold-group: " (source router.access-list.name)" + ssm: "enable" + ssm-range: " (source router.access-list.name)" + route-limit: "65" + route-threshold: "66" +''' + +RETURN = ''' +build: + description: Build number of the fortigate image + returned: always + type: str + sample: '1547' +http_method: + description: Last method used to provision the content into FortiGate + returned: always + type: str + sample: 'PUT' +http_status: + description: Last result given by FortiGate on last operation applied + returned: always + type: str + sample: "200" +mkey: + description: Master key (id) used in the last call to FortiGate + returned: success + type: str + sample: "id" +name: + description: Name of the table used to fulfill the request + returned: always + type: str + sample: "urlfilter" +path: + description: Path of the table used to fulfill the request + returned: always + type: str + sample: "webfilter" +revision: + description: Internal revision number + returned: always + type: str + sample: "17.0.2.10658" +serial: + description: Serial number of the unit + returned: always + type: str + sample: "FGVMEVYYQT3AB5352" +status: + description: Indication of the operation's result + returned: always + type: str + sample: "success" +vdom: + description: Virtual domain used + returned: always + type: str + sample: "root" +version: + description: Version of the FortiGate + returned: always + type: str + sample: "v5.6.3" + +''' + +from ansible.module_utils.basic import AnsibleModule + +fos = None + + +def login(data): + host = data['host'] + username = data['username'] + password = data['password'] + + fos.debug('on') + if 'https' in data and not data['https']: + fos.https('off') + else: + fos.https('on') + + fos.login(host, username, password) + + +def filter_router_multicast_data(json): + option_list = ['interface', 'multicast-routing', 'pim-sm-global', + 'route-limit', 'route-threshold'] + dictionary = {} + + for attribute in option_list: + if attribute in json and json[attribute] is not None: + dictionary[attribute] = json[attribute] + + return dictionary + + +def flatten_multilists_attributes(data): + multilist_attrs = [] + + for attr in multilist_attrs: + try: + path = "data['" + "']['".join(elem for elem in attr) + "']" + current_val = eval(path) + flattened_val = ' '.join(elem for elem in current_val) + exec(path + '= flattened_val') + except BaseException: + pass + + return data + + +def router_multicast(data, fos): + vdom = data['vdom'] + router_multicast_data = data['router_multicast'] + flattened_data = flatten_multilists_attributes(router_multicast_data) + filtered_data = filter_router_multicast_data(flattened_data) + return fos.set('router', + 'multicast', + data=filtered_data, + vdom=vdom) + + +def fortios_router(data, fos): + login(data) + + if data['router_multicast']: + resp = router_multicast(data, fos) + + fos.logout() + return not resp['status'] == "success", resp['status'] == "success", resp + + +def main(): + fields = { + "host": {"required": True, "type": "str"}, + "username": {"required": True, "type": "str"}, + "password": {"required": False, "type": "str", "no_log": True}, + "vdom": {"required": False, "type": "str", "default": "root"}, + "https": {"required": False, "type": "bool", "default": True}, + "router_multicast": { + "required": False, "type": "dict", + "options": { + "interface": {"required": False, "type": "list", + "options": { + "bfd": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "cisco-exclude-genid": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "dr-priority": {"required": False, "type": "int"}, + "hello-holdtime": {"required": False, "type": "int"}, + "hello-interval": {"required": False, "type": "int"}, + "igmp": {"required": False, "type": "dict", + "options": { + "access-group": {"required": False, "type": "str"}, + "immediate-leave-group": {"required": False, "type": "str"}, + "last-member-query-count": {"required": False, "type": "int"}, + "last-member-query-interval": {"required": False, "type": "int"}, + "query-interval": {"required": False, "type": "int"}, + "query-max-response-time": {"required": False, "type": "int"}, + "query-timeout": {"required": False, "type": "int"}, + "router-alert-check": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "version": {"required": False, "type": "str", + "choices": ["3", "2", "1"]} + }}, + "join-group": {"required": False, "type": "list", + "options": { + "address": {"required": True, "type": "str"} + }}, + "multicast-flow": {"required": False, "type": "str"}, + "name": {"required": True, "type": "str"}, + "neighbour-filter": {"required": False, "type": "str"}, + "passive": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "pim-mode": {"required": False, "type": "str", + "choices": ["sparse-mode", "dense-mode"]}, + "propagation-delay": {"required": False, "type": "int"}, + "rp-candidate": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "rp-candidate-group": {"required": False, "type": "str"}, + "rp-candidate-interval": {"required": False, "type": "int"}, + "rp-candidate-priority": {"required": False, "type": "int"}, + "state-refresh-interval": {"required": False, "type": "int"}, + "static-group": {"required": False, "type": "str"}, + "ttl-threshold": {"required": False, "type": "int"} + }}, + "multicast-routing": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "pim-sm-global": {"required": False, "type": "dict", + "options": { + "accept-register-list": {"required": False, "type": "str"}, + "accept-source-list": {"required": False, "type": "str"}, + "bsr-allow-quick-refresh": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "bsr-candidate": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "bsr-hash": {"required": False, "type": "int"}, + "bsr-interface": {"required": False, "type": "str"}, + "bsr-priority": {"required": False, "type": "int"}, + "cisco-crp-prefix": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "cisco-ignore-rp-set-priority": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "cisco-register-checksum": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "cisco-register-checksum-group": {"required": False, "type": "str"}, + "join-prune-holdtime": {"required": False, "type": "int"}, + "message-interval": {"required": False, "type": "int"}, + "null-register-retries": {"required": False, "type": "int"}, + "register-rate-limit": {"required": False, "type": "int"}, + "register-rp-reachability": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "register-source": {"required": False, "type": "str", + "choices": ["disable", "interface", "ip-address"]}, + "register-source-interface": {"required": False, "type": "str"}, + "register-source-ip": {"required": False, "type": "str"}, + "register-supression": {"required": False, "type": "int"}, + "rp-address": {"required": False, "type": "list", + "options": { + "group": {"required": False, "type": "str"}, + "id": {"required": True, "type": "int"}, + "ip-address": {"required": False, "type": "str"} + }}, + "rp-register-keepalive": {"required": False, "type": "int"}, + "spt-threshold": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "spt-threshold-group": {"required": False, "type": "str"}, + "ssm": {"required": False, "type": "str", + "choices": ["enable", "disable"]}, + "ssm-range": {"required": False, "type": "str"} + }}, + "route-limit": {"required": False, "type": "int"}, + "route-threshold": {"required": False, "type": "int"} + + } + } + } + + module = AnsibleModule(argument_spec=fields, + supports_check_mode=False) + try: + from fortiosapi import FortiOSAPI + except ImportError: + module.fail_json(msg="fortiosapi module is required") + + global fos + fos = FortiOSAPI() + + is_error, has_changed, result = fortios_router(module.params, fos) + + if not is_error: + module.exit_json(changed=has_changed, meta=result) + else: + module.fail_json(msg="Error in repo", meta=result) + + +if __name__ == '__main__': + main()