diff options
Diffstat (limited to 'ansible_collections/cisco/ios/plugins/module_utils')
62 files changed, 5242 insertions, 2031 deletions
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_address_family/bgp_address_family.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_address_family/bgp_address_family.py index a52e3787c..18fed7891 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_address_family/bgp_address_family.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_address_family/bgp_address_family.py @@ -340,7 +340,7 @@ class Bgp_address_familyArgs(object): # pylint: disable=R0903 "type": "dict", "options": { "set": {"type": "bool"}, - "number": {"type": "int"}, + "number": {"type": "str"}, "dual_as": {"type": "bool"}, "no_prepend": { "type": "dict", @@ -367,7 +367,6 @@ class Bgp_address_familyArgs(object): # pylint: disable=R0903 "warning_only": {"type": "bool"}, }, }, - "next_hop_self": {"type": "bool"}, "nexthop_self": { "type": "dict", "options": {"set": {"type": "bool"}, "all": {"type": "bool"}}, @@ -440,7 +439,7 @@ class Bgp_address_familyArgs(object): # pylint: disable=R0903 "out": {"type": "bool"}, }, }, - "remote_as": {"type": "int"}, + "remote_as": {"type": "str"}, "remove_private_as": { "type": "dict", "options": { @@ -814,6 +813,19 @@ class Bgp_address_familyArgs(object): # pylint: disable=R0903 "type": "dict", "options": {"name": {"type": "str"}, "filter": {"type": "bool"}}, }, + "advertise": { + "type": "dict", + "options": { + "afi": { + "type": "str", + "choices": ["l2vpn"], + }, + "safi": { + "type": "str", + "choices": ["evpn"], + }, + }, + }, }, }, }, diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_global/bgp_global.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_global/bgp_global.py index 38c4e1ab3..21bb051c3 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_global/bgp_global.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_global/bgp_global.py @@ -940,6 +940,7 @@ class Bgp_globalArgs(object): # pylint: disable=R0903 "choices": [ "merged", "replaced", + "overridden", "deleted", "purged", "gathered", diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/evpn_evi/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/evpn_evi/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/evpn_evi/__init__.py diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/evpn_evi/evpn_evi.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/evpn_evi/evpn_evi.py new file mode 100644 index 000000000..021e1ed81 --- /dev/null +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/evpn_evi/evpn_evi.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- +# Copyright 2023 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the +# ansible.content_builder. +# +# Manually editing this file is not advised. +# +# To update the argspec make the desired changes +# in the documentation in the module file and re-run +# ansible.content_builder commenting out +# the path to external 'docstring' in build.yaml. +# +############################################## + +""" +The arg spec for the ios_evpn_evi module +""" + + +class Evpn_eviArgs(object): # pylint: disable=R0903 + """The arg spec for the ios_evpn_evi module""" + + argument_spec = { + "config": { + "type": "list", + "elements": "dict", + "options": { + "evi": {"type": "int", "required": True}, + "default_gateway": { + "type": "dict", + "options": { + "advertise": { + "type": "dict", + "options": { + "enable": {"type": "bool"}, + "disable": {"type": "bool"}, + }, + }, + }, + }, + "ip": { + "type": "dict", + "options": { + "local_learning": { + "type": "dict", + "options": { + "enable": {"type": "bool"}, + "disable": {"type": "bool"}, + }, + }, + }, + }, + "encapsulation": { + "type": "str", + "choices": ["vxlan"], + "default": "vxlan", + }, + "replication_type": { + "type": "str", + "choices": ["ingress", "static"], + }, + "route_distinguisher": {"type": "str"}, + }, + }, + "running_config": {"type": "str"}, + "state": { + "type": "str", + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "gathered", + "rendered", + "parsed", + ], + "default": "merged", + }, + } # pylint: disable=C0301 diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/evpn_global/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/evpn_global/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/evpn_global/__init__.py diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/evpn_global/evpn_global.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/evpn_global/evpn_global.py new file mode 100644 index 000000000..acdb0c759 --- /dev/null +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/evpn_global/evpn_global.py @@ -0,0 +1,93 @@ +# -*- coding: utf-8 -*- +# Copyright 2023 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the +# ansible.content_builder. +# +# Manually editing this file is not advised. +# +# To update the argspec make the desired changes +# in the documentation in the module file and re-run +# ansible.content_builder commenting out +# the path to external 'docstring' in build.yaml. +# +############################################## + +""" +The arg spec for the ios_evpn_global module +""" + + +class Evpn_globalArgs(object): # pylint: disable=R0903 + """The arg spec for the ios_evpn_global module""" + + argument_spec = { + "config": { + "type": "dict", + "options": { + "default_gateway": { + "type": "dict", + "options": {"advertise": {"type": "bool"}}, + }, + "flooding_suppression": { + "type": "dict", + "options": { + "address_resolution": { + "type": "dict", + "options": {"disable": {"type": "bool"}}, + }, + }, + }, + "ip": { + "type": "dict", + "options": { + "local_learning": { + "type": "dict", + "options": {"disable": {"type": "bool"}}, + }, + }, + }, + "replication_type": { + "type": "str", + "choices": ["ingress", "static"], + }, + "route_target": { + "type": "dict", + "options": { + "auto": { + "type": "dict", + "options": {"vni": {"type": "bool"}}, + }, + }, + }, + "router_id": { + "type": "str", + }, + }, + }, + "running_config": {"type": "str"}, + "state": { + "type": "str", + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "rendered", + "gathered", + "parsed", + ], + "default": "merged", + }, + } # pylint: disable=C0301 diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp/lacp.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp/lacp.py index 3e346db12..dff90d45f 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp/lacp.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp/lacp.py @@ -50,7 +50,15 @@ class LacpArgs(object): }, "running_config": {"type": "str"}, "state": { - "choices": ["merged", "replaced", "deleted", "rendered", "parsed", "gathered"], + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "rendered", + "parsed", + "gathered", + ], "default": "merged", "type": "str", }, diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_global/lldp_global.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_global/lldp_global.py index 841e34bed..f7b699826 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_global/lldp_global.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_global/lldp_global.py @@ -61,7 +61,15 @@ class Lldp_globalArgs(object): }, "running_config": {"type": "str"}, "state": { - "choices": ["merged", "replaced", "deleted", "rendered", "parsed", "gathered"], + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "rendered", + "parsed", + "gathered", + ], "default": "merged", "type": "str", }, diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ping/ping.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ping/ping.py index f89779d06..8de060b50 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ping/ping.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ping/ping.py @@ -37,6 +37,7 @@ class PingArgs(object): # pylint: disable=R0903 "dest": {"required": True, "type": "str"}, "df_bit": {"default": False, "type": "bool"}, "source": {"type": "str"}, + "size": {"type": "int"}, "ingress": {"type": "str"}, "egress": {"type": "str"}, "timeout": {"type": "int"}, diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/service/service.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/service/service.py index 76d2a3e34..238fc64a2 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/service/service.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/service/service.py @@ -110,6 +110,7 @@ class ServiceArgs(object): # pylint: disable=R0903 "choices": [ "merged", "replaced", + "overridden", "deleted", "gathered", "rendered", diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/snmp_server/snmp_server.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/snmp_server/snmp_server.py index d0473cc97..446a8225b 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/snmp_server/snmp_server.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/snmp_server/snmp_server.py @@ -13,15 +13,16 @@ __metaclass__ = type ############################################# # # This file is auto generated by the -# cli_rm_builder. +# ansible.content_builder. # # Manually editing this file is not advised. # # To update the argspec make the desired changes -# in the module docstring and re-run -# cli_rm_builder. +# in the documentation in the module file and re-run +# ansible.content_builder commenting out +# the path to external 'docstring' in build.yaml. # -############################################# +############################################## """ The arg spec for the ios_snmp_server module @@ -34,7 +35,10 @@ class Snmp_serverArgs(object): # pylint: disable=R0903 argument_spec = { "config": { "options": { - "accounting": {"options": {"command": {"type": "str"}}, "type": "dict"}, + "accounting": { + "options": {"command": {"type": "str"}}, + "type": "dict", + }, "cache": {"type": "int"}, "chassis_id": {"type": "str"}, "communities": { @@ -52,7 +56,10 @@ class Snmp_serverArgs(object): # pylint: disable=R0903 "contact": {"type": "str"}, "context": {"elements": "str", "type": "list"}, "drop": { - "options": {"unknown_user": {"type": "bool"}, "vrf_traffic": {"type": "bool"}}, + "options": { + "unknown_user": {"type": "bool"}, + "vrf_traffic": {"type": "bool"}, + }, "type": "dict", }, "engine_id": { @@ -82,7 +89,11 @@ class Snmp_serverArgs(object): # pylint: disable=R0903 "elements": "dict", "options": { "context": {"type": "str"}, - "version_option": {"choices": ["auth", "noauth", "priv"], "type": "str"}, + "match": {"choices": ["exact", "prefix"], "type": "str"}, + "version_option": { + "choices": ["auth", "noauth", "priv"], + "type": "str", + }, "group": {"type": "str"}, "notify": {"type": "str"}, "read": {"type": "str"}, @@ -101,7 +112,10 @@ class Snmp_serverArgs(object): # pylint: disable=R0903 "community_string": {"type": "str"}, "traps": {"type": "list", "elements": "str"}, "version": {"choices": ["1", "2c", "3"], "type": "str"}, - "version_option": {"choices": ["auth", "noauth", "priv"], "type": "str"}, + "version_option": { + "choices": ["auth", "noauth", "priv"], + "type": "str", + }, "vrf": {"type": "str"}, }, "type": "list", @@ -116,7 +130,10 @@ class Snmp_serverArgs(object): # pylint: disable=R0903 "type": "dict", }, "ip": { - "options": {"dscp": {"type": "int"}, "precedence": {"type": "int"}}, + "options": { + "dscp": {"type": "int"}, + "precedence": {"type": "int"}, + }, "type": "dict", }, "location": {"type": "str"}, @@ -145,6 +162,7 @@ class Snmp_serverArgs(object): # pylint: disable=R0903 "trap_timeout": {"type": "int"}, "traps": { "options": { + "aaa_server": {"type": "bool"}, "auth_framework": { "options": { "sec_violation": {"type": "bool"}, @@ -188,6 +206,22 @@ class Snmp_serverArgs(object): # pylint: disable=R0903 }, "type": "dict", }, + "bulkstat": { + "options": { + "enable": {"type": "bool"}, + "collection": {"type": "bool"}, + "transfer": {"type": "bool"}, + }, + "type": "dict", + }, + "call_home": { + "options": { + "enable": {"type": "bool"}, + "message_send_fail": {"type": "bool"}, + "server_fail": {"type": "bool"}, + }, + "type": "dict", + }, "casa": {"type": "bool"}, "cef": { "options": { @@ -204,7 +238,10 @@ class Snmp_serverArgs(object): # pylint: disable=R0903 "config_copy": {"type": "bool"}, "config_ctid": {"type": "bool"}, "cpu": { - "options": {"enable": {"type": "bool"}, "threshold": {"type": "bool"}}, + "options": { + "enable": {"type": "bool"}, + "threshold": {"type": "bool"}, + }, "type": "dict", }, "dhcp": {"type": "bool"}, @@ -218,19 +255,39 @@ class Snmp_serverArgs(object): # pylint: disable=R0903 }, "eigrp": {"type": "bool"}, "entity": {"type": "bool"}, + "entity_diag": { + "options": { + "boot_up_fail": {"type": "bool"}, + "enable": {"type": "bool"}, + "hm_test_recover": {"type": "bool"}, + "hm_thresh_reached": {"type": "bool"}, + "scheduled_test_fail": {"type": "bool"}, + }, + "type": "dict", + }, + "entity_perf": { + "options": { + "enable": {"type": "bool"}, + "throughput_notif": {"type": "bool"}, + }, + "type": "dict", + }, + "entity_state": {"type": "bool"}, "energywise": {"type": "bool"}, "envmon": { "options": { + "enable": {"type": "bool"}, "fan": { "options": { - "shutdown": {"type": "bool"}, "enable": {"type": "bool"}, + "shutdown": {"type": "bool"}, "status": {"type": "bool"}, "supply": {"type": "bool"}, "temperature": {"type": "bool"}, }, "type": "dict", }, + "fan_enable": {"type": "bool"}, "shutdown": {"type": "bool"}, "status": {"type": "bool"}, "supply": {"type": "bool"}, @@ -238,6 +295,7 @@ class Snmp_serverArgs(object): # pylint: disable=R0903 }, "type": "dict", }, + "errdisable": {"type": "bool"}, "ethernet": { "options": { "cfm": { @@ -275,8 +333,24 @@ class Snmp_serverArgs(object): # pylint: disable=R0903 }, "type": "dict", }, + "ether_oam": {"type": "bool"}, "event_manager": {"type": "bool"}, - "flowmon": {"type": "bool"}, + "flash": { + "options": { + "enable": {"type": "bool"}, + "insertion": {"type": "bool"}, + "lowspace": {"type": "bool"}, + "removal": {"type": "bool"}, + }, + "type": "dict", + }, + "flex_links": { + "options": { + "enable": {"type": "bool"}, + "status": {"type": "bool"}, + }, + "type": "dict", + }, "firewall": { "options": { "enable": {"type": "bool"}, @@ -284,6 +358,7 @@ class Snmp_serverArgs(object): # pylint: disable=R0903 }, "type": "dict", }, + "flowmon": {"type": "bool"}, "frame_relay": { "options": { "enable": {"type": "bool"}, @@ -343,6 +418,15 @@ class Snmp_serverArgs(object): # pylint: disable=R0903 "type": "dict", }, "ipsla": {"type": "bool"}, + "isis": {"type": "bool"}, + "l2tc": { + "options": { + "enable": {"type": "bool"}, + "sys_threshold": {"type": "bool"}, + "threshold": {"type": "bool"}, + }, + "type": "dict", + }, "l2tun": { "options": { "pseudowire_status": {"type": "bool"}, @@ -350,9 +434,141 @@ class Snmp_serverArgs(object): # pylint: disable=R0903 }, "type": "dict", }, + "license": {"type": "bool"}, + "lisp": {"type": "bool"}, + "local_auth": {"type": "bool"}, + "mac_notification": { + "options": { + "enable": {"type": "bool"}, + "change": {"type": "bool"}, + "move": {"type": "bool"}, + "threshold": {"type": "bool"}, + }, + "type": "dict", + }, + "memory": { + "options": { + "enable": {"type": "bool"}, + "bufferpeak": {"type": "bool"}, + }, + "type": "dict", + }, + "mpls": { + "options": { + "fast_reroute": { + "options": { + "enable": {"type": "bool"}, + "protected": {"type": "bool"}, + }, + "type": "dict", + }, + "ldp": { + "options": { + "enable": {"type": "bool"}, + "pv_limit": {"type": "bool"}, + "session_down": {"type": "bool"}, + "session_up": {"type": "bool"}, + "threshold": {"type": "bool"}, + }, + "type": "dict", + }, + "rfc": { + "options": { + "ldp": { + "options": { + "enable": {"type": "bool"}, + "pv_limit": {"type": "bool"}, + "session_down": {"type": "bool"}, + "session_up": {"type": "bool"}, + "threshold": {"type": "bool"}, + }, + "type": "dict", + }, + "traffic_eng": { + "options": { + "enable": {"type": "bool"}, + "down": {"type": "bool"}, + "reoptimized": {"type": "bool"}, + "reroute": {"type": "bool"}, + "up": {"type": "bool"}, + }, + "type": "dict", + }, + "vpn": { + "options": { + "enable": {"type": "bool"}, + "illegal_label": {"type": "bool"}, + "max_thresh_cleared": { + "type": "bool", + }, + "max_threshold": {"type": "bool"}, + "mid_threshold": {"type": "bool"}, + "vrf_down": {"type": "bool"}, + "vrf_up": {"type": "bool"}, + }, + "type": "dict", + }, + }, + "type": "dict", + }, + "traffic_eng": { + "options": { + "enable": {"type": "bool"}, + "down": {"type": "bool"}, + "reroute": {"type": "bool"}, + "up": {"type": "bool"}, + }, + "type": "dict", + }, + "vpn": { + "options": { + "enable": {"type": "bool"}, + "illegal_label": {"type": "bool"}, + "max_thresh_cleared": {"type": "bool"}, + "max_threshold": {"type": "bool"}, + "mid_threshold": {"type": "bool"}, + "vrf_down": {"type": "bool"}, + "vrf_up": {"type": "bool"}, + }, + "type": "dict", + }, + }, + "type": "dict", + }, + "mpls_vpn": {"type": "bool"}, "msdp": {"type": "bool"}, "mvpn": {"type": "bool"}, - "mpls_vpn": {"type": "bool"}, + "nhrp": { + "options": { + "enable": {"type": "bool"}, + "nhc": { + "options": { + "enable": {"type": "bool"}, + "down": {"type": "bool"}, + "up": {"type": "bool"}, + }, + "type": "dict", + }, + "nhp": { + "options": { + "enable": {"type": "bool"}, + "down": {"type": "bool"}, + "up": {"type": "bool"}, + }, + "type": "dict", + }, + "nhs": { + "options": { + "enable": {"type": "bool"}, + "down": {"type": "bool"}, + "up": {"type": "bool"}, + }, + "type": "dict", + }, + "quota_exceeded": {"type": "bool"}, + }, + "type": "dict", + }, "ospf": { "options": { "cisco_specific": { @@ -362,11 +578,17 @@ class Snmp_serverArgs(object): # pylint: disable=R0903 "retransmit": {"type": "bool"}, "state_change": { "options": { - "nssa_trans_change": {"type": "bool"}, + "nssa_trans_change": { + "type": "bool", + }, "shamlink": { "options": { - "interface": {"type": "bool"}, - "neighbor": {"type": "bool"}, + "interface": { + "type": "bool", + }, + "neighbor": { + "type": "bool", + }, }, "type": "dict", }, @@ -383,6 +605,42 @@ class Snmp_serverArgs(object): # pylint: disable=R0903 }, "type": "dict", }, + "ospfv3": { + "options": { + "errors": { + "options": { + "enable": {"type": "bool"}, + "bad_packet": {"type": "bool"}, + "config_error": {"type": "bool"}, + "virt_bad_packet": {"type": "bool"}, + "virt_config_error": {"type": "bool"}, + }, + "type": "dict", + }, + "rate_limit": {"type": "int"}, + "state_change": { + "options": { + "enable": {"type": "bool"}, + "if_state_change": {"type": "bool"}, + "neighbor_restart_helper_status_change": { + "type": "bool", + }, + "neighbor_state_change": {"type": "bool"}, + "nssa_translator_status_change": { + "type": "bool", + }, + "restart_status_change": {"type": "bool"}, + "virtif_state_change": {"type": "bool"}, + "vn_restart_helper_status_change": { + "type": "bool", + }, + "vn_state_change": {"type": "bool"}, + }, + "type": "dict", + }, + }, + "type": "dict", + }, "pim": { "options": { "invalid_pim_message": {"type": "bool"}, @@ -392,19 +650,35 @@ class Snmp_serverArgs(object): # pylint: disable=R0903 }, "type": "dict", }, - "vrfmib": { + "pki": {"type": "bool"}, + "port_security": {"type": "bool"}, + "power_ethernet": { "options": { - "vrf_up": {"type": "bool"}, - "vrf_down": {"type": "bool"}, - "vnet_trunk_up": {"type": "bool"}, - "vnet_trunk_down": {"type": "bool"}, + "enable": {"type": "bool"}, + "group": { + "options": { + "slot_id": {"type": "int"}, + "threshold": {"type": "int"}, + }, + "elements": "dict", + "type": "list", + }, + "police": {"type": "bool"}, }, "type": "dict", }, - "pki": {"type": "bool"}, - "rsvp": {"type": "bool"}, - "isis": {"type": "bool"}, "pw_vc": {"type": "bool"}, + "rep": {"type": "bool"}, + "rsvp": {"type": "bool"}, + "rf": {"type": "bool"}, + "smart_license": { + "options": { + "enable": {"type": "bool"}, + "entitlement": {"type": "bool"}, + "global": {"type": "bool"}, + }, + "type": "dict", + }, "snmp": { "options": { "authentication": {"type": "bool"}, @@ -415,10 +689,103 @@ class Snmp_serverArgs(object): # pylint: disable=R0903 }, "type": "dict", }, + "stackwise": {"type": "bool"}, + "stpx": { + "options": { + "enable": {"type": "bool"}, + "inconsistency": {"type": "bool"}, + "loop_inconsistency": {"type": "bool"}, + "root_inconsistency": {"type": "bool"}, + }, + "type": "dict", + }, "syslog": {"type": "bool"}, "transceiver_all": {"type": "bool"}, + "trustsec": { + "options": { + "authz_file_error": {"type": "bool"}, + "cache_file_error": {"type": "bool"}, + "enable": {"type": "bool"}, + "keystore_file_error": {"type": "bool"}, + "keystore_sync_fail": {"type": "bool"}, + "random_number_fail": {"type": "bool"}, + "src_entropy_fail": {"type": "bool"}, + }, + "type": "dict", + }, + "trustsec_interface": { + "options": { + "enable": {"type": "bool"}, + "authc_fail": {"type": "bool"}, + "authz_fail": {"type": "bool"}, + "sap_fail": {"type": "bool"}, + "supplicant_fail": {"type": "bool"}, + "unauthorized": {"type": "bool"}, + }, + "type": "dict", + }, + "trustsec_policy": { + "options": { + "enable": {"type": "bool"}, + "authz_sgacl_fail": {"type": "bool"}, + "peer_policy_updated": {"type": "bool"}, + }, + "type": "dict", + }, + "trustsec_server": { + "options": { + "enable": {"type": "bool"}, + "provision_secret": {"type": "bool"}, + "radius_server": {"type": "bool"}, + }, + "type": "dict", + }, + "trustsec_sxp": { + "options": { + "enable": {"type": "bool"}, + "binding_conflict": {"type": "bool"}, + "binding_err": {"type": "bool"}, + "binding_expn_fail": {"type": "bool"}, + "conn_config_err": {"type": "bool"}, + "conn_down": {"type": "bool"}, + "conn_srcaddr_err": {"type": "bool"}, + "conn_up": {"type": "bool"}, + "msg_parse_err": {"type": "bool"}, + "oper_nodeid_change": {"type": "bool"}, + }, + "type": "dict", + }, "tty": {"type": "bool"}, + "udld": { + "options": { + "enable": {"type": "bool"}, + "link_fail_rpt": {"type": "bool"}, + "status_change": {"type": "bool"}, + }, + "type": "dict", + }, + "vlan_membership": {"type": "bool"}, + "vlancreate": {"type": "bool"}, + "vlandelete": {"type": "bool"}, + "vrfmib": { + "options": { + "vrf_up": {"type": "bool"}, + "vrf_down": {"type": "bool"}, + "vnet_trunk_up": {"type": "bool"}, + "vnet_trunk_down": {"type": "bool"}, + }, + "type": "dict", + }, "vrrp": {"type": "bool"}, + "vswitch": { + "options": { + "dual_active": {"type": "bool"}, + "enable": {"type": "bool"}, + "vsl": {"type": "bool"}, + }, + "type": "dict", + }, + "vtp": {"type": "bool"}, }, "type": "dict", }, @@ -431,17 +798,29 @@ class Snmp_serverArgs(object): # pylint: disable=R0903 "no_log": False, "type": "dict", "options": { - "algorithm": {"type": "str", "choices": ["md5", "sha"]}, - "password": {"type": "str", "no_log": True}, + "algorithm": { + "type": "str", + "choices": ["md5", "sha"], + }, + "password": { + "type": "str", + "no_log": True, + }, }, }, "encryption": { "no_log": False, "type": "dict", "options": { - "priv": {"type": "str", "choices": ["3des", "aes", "des"]}, + "priv": { + "type": "str", + "choices": ["3des", "aes", "des"], + }, "priv_option": {"type": "str"}, - "password": {"type": "str", "no_log": True}, + "password": { + "type": "str", + "no_log": True, + }, }, }, "group": {"type": "str"}, @@ -449,7 +828,10 @@ class Snmp_serverArgs(object): # pylint: disable=R0903 "udp_port": {"type": "int"}, "username": {"type": "str"}, "version": {"choices": ["v1", "v2c", "v3"], "type": "str"}, - "version_option": {"choices": ["encrypted"], "type": "str"}, + "version_option": { + "choices": ["encrypted"], + "type": "str", + }, "vrf": {"type": "str"}, }, "type": "list", diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vlans/vlans.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vlans/vlans.py index a3b0b6acd..9db593dcc 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vlans/vlans.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vlans/vlans.py @@ -55,9 +55,17 @@ class VlansArgs(object): "associated": {"type": "list", "elements": "int"}, }, }, + "member": { + "type": "dict", + "options": { + "vni": {"type": "int", "required": True}, + "evi": {"type": "int"}, + }, + }, }, "type": "list", }, + "configuration": {"type": "bool"}, "running_config": {"type": "str"}, "state": { "choices": [ diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vxlan_vtep/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vxlan_vtep/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vxlan_vtep/__init__.py diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vxlan_vtep/vxlan_vtep.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vxlan_vtep/vxlan_vtep.py new file mode 100644 index 000000000..b5eb35c07 --- /dev/null +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vxlan_vtep/vxlan_vtep.py @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- +# Copyright 2023 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the +# ansible.content_builder. +# +# Manually editing this file is not advised. +# +# To update the argspec make the desired changes +# in the documentation in the module file and re-run +# ansible.content_builder commenting out +# the path to external 'docstring' in build.yaml. +# +############################################## + +""" +The arg spec for the ios_vxlan_vtep module +""" + + +class Vxlan_vtepArgs(object): # pylint: disable=R0903 + """The arg spec for the ios_vxlan_vtep module""" + + argument_spec = { + "config": { + "type": "list", + "elements": "dict", + "options": { + "interface": {"type": "str", "required": True}, + "source_interface": {"type": "str"}, + "host_reachability_bgp": { + "type": "bool", + }, + "member": { + "type": "dict", + "options": { + "vni": { + "type": "dict", + "options": { + "l2vni": { + "type": "list", + "elements": "dict", + "options": { + "vni": {"type": "int"}, + "replication": { + "type": "dict", + "options": { + "type": { + "type": "str", + "choices": ["ingress", "static"], + }, + "mcast_group": { + "type": "dict", + "options": { + "ipv4": {"type": "str"}, + "ipv6": {"type": "str"}, + }, + }, + }, + }, + }, + }, + "l3vni": { + "type": "list", + "elements": "dict", + "options": { + "vni": {"type": "int"}, + "vrf": {"type": "str"}, + }, + }, + }, + }, + }, + }, + }, + }, + "running_config": {"type": "str"}, + "state": { + "type": "str", + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "rendered", + "gathered", + "parsed", + ], + "default": "merged", + }, + } # pylint: disable=C0301 diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acls/acls.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acls/acls.py index 9d29555cc..164c75c40 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acls/acls.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acls/acls.py @@ -15,6 +15,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type +from ansible.module_utils._text import to_text from ansible.module_utils.six import iteritems from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import ( ResourceModule, @@ -149,11 +150,28 @@ class Acls(ResourceModule): entry["afi"] = afi return entry + def pop_remark(r_entry, afi): + """Takes out remarks from ace entry as remarks not same + does not mean the ace entry to be re-introduced + """ + if r_entry.get("remarks"): + return r_entry.pop("remarks") + else: + return {} + for wseq, wentry in iteritems(want): hentry = have.pop(wseq, {}) + rem_hentry, rem_wentry = {}, {} + if hentry: hentry = self.sanitize_protocol_options(wentry, hentry) - if hentry != wentry: + + if hentry != wentry: # will let in if ace is same but remarks is not same + if hentry: + rem_hentry["remarks"] = pop_remark(hentry, afi) + if wentry: + rem_wentry["remarks"] = pop_remark(wentry, afi) + if hentry: if self.state == "merged": self._module.fail_json( @@ -164,24 +182,51 @@ class Acls(ResourceModule): ), ) else: # other action states - if hentry.get("remarks"): # remove remark if not in want - for rems in hentry.get("remarks"): - if rems not in wentry.get("remarks", {}): - self.addcmd({"remarks": rems}, "remarks", negate=True) - else: # remove ace if not in want + if rem_hentry.get("remarks"): # remove remark if not in want + for k_hrems, hrems in rem_hentry.get("remarks").items(): + if k_hrems not in rem_wentry.get("remarks", {}).keys(): + if self.state in ["replaced", "overridden"]: + self.addcmd( + { + "remarks": hrems, + "sequence": hentry.get("sequence", ""), + }, + "remarks_no_data", + negate=True, + ) + break + else: + self.addcmd( + { + "remarks": hrems, + "sequence": hentry.get("sequence", ""), + }, + "remarks", + negate=True, + ) + # remove ace if not in want + if hentry != wentry: self.addcmd(add_afi(hentry, afi), "aces", negate=True) - if wentry.get("remarks"): # add remark if not in have - for rems in wentry.get("remarks"): - if rems not in hentry.get("remarks", {}): - self.addcmd({"remarks": rems}, "remarks") - else: # add ace if not in have + if rem_wentry.get("remarks"): # add remark if not in have + for k_wrems, wrems in rem_wentry.get("remarks").items(): + if k_wrems not in rem_hentry.get("remarks", {}).keys(): + self.addcmd( + {"remarks": wrems, "sequence": hentry.get("sequence", "")}, + "remarks", + ) + # add ace if not in have + if hentry != wentry: self.addcmd(add_afi(wentry, afi), "aces") # remove remaining entries from have aces list for hseq in have.values(): if hseq.get("remarks"): # remove remarks that are extra in have - for rems in hseq.get("remarks"): - self.addcmd({"remarks": rems}, "remarks", negate=True) + for krems, rems in hseq.get("remarks").items(): + self.addcmd( + {"remarks": rems, "sequence": hseq.get("sequence", "")}, + "remarks", + negate=True, + ) else: # remove extra aces self.addcmd(add_afi(hseq, afi), "aces", negate=True) @@ -192,6 +237,7 @@ class Acls(ResourceModule): list(wace.get("protocol_options"))[0] == hace.get("protocol") ): hace.pop("protocol") + hace["protocol_options"] = wace.get("protocol_options") return hace def acl_name_cmd(self, name, afi, acl_type): @@ -224,11 +270,17 @@ class Acls(ResourceModule): for acl in each.get("acls"): # check each acl for aces temp_aces = {} if acl.get("aces"): - temp_rem = [] # remarks if defined in an ace + rem_idx = 0 # remarks if defined in an ace for ace in acl.get("aces"): # each ace turned to dict - if ace.get("destination") and ace.get("destination", {}).get( - "port_protocol", - {}, + if ( + ace.get("destination") + and ace.get("destination", {}).get( + "port_protocol", + {}, + ) + and not ace.get("destination", {}) + .get("port_protocol", {}) + .get("range") ): for k, v in ( ace.get("destination", {}).get("port_protocol", {}).items() @@ -251,18 +303,25 @@ class Acls(ResourceModule): ), ) - if ace.get("remarks"): - en_name = str(acl.get("name")) + "remark" - temp_rem.extend(ace.pop("remarks")) + if ace.get( + "remarks", + ): # index aces inside of each ace don't cluster them all + rem_ace = {} + # en_name = str(acl.get("name")) + "remark" + # temp_rem.extend(ace.pop("remarks")) + for remks in ace.get("remarks"): + rem_ace[remks.replace(" ", "_")] = remks + rem_idx += 1 + ace["remarks"] = rem_ace if ace.get("sequence"): temp_aces.update({ace.get("sequence"): ace}) elif ace: count += 1 - temp_aces.update({"_" + str(count): ace}) + temp_aces.update({"_" + to_text(count): ace}) - if temp_rem: # add remarks to the temp ace - temp_aces.update({en_name: {"remarks": temp_rem}}) + # if temp_rem: # add remarks to the temp ace + # temp_aces.update({en_name: {"remarks": temp_rem}}) if acl.get("acl_type"): # update acl dict with req info temp_acls.update( diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_address_family/bgp_address_family.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_address_family/bgp_address_family.py index 36ea3e963..17cdd11fc 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_address_family/bgp_address_family.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_address_family/bgp_address_family.py @@ -39,6 +39,7 @@ class Bgp_address_family(ResourceModule): """ parsers = [ + "advertise", "as_number", # generic "aggregate_addresses", "auto_summary", @@ -336,9 +337,6 @@ class Bgp_address_family(ResourceModule): neib["neighbor_address"] = neib.pop("ipv6_address") if neib.get("ipv6_adddress"): neib["neighbor_address"] = neib.pop("ipv6_adddress") - # next_hop_self deprecated added nexthop_self - if neib.get("next_hop_self"): - neib["nexthop_self"] = {"set": neib.pop("next_hop_self")} # prefix_list and prefix_lists if neib.get("prefix_list"): # deprecated made list neib["prefix_lists"] = [neib.pop("prefix_list")] @@ -356,6 +354,12 @@ class Bgp_address_family(ResourceModule): # slow_peer to slow_peer_options if neib.get("slow_peer"): # only one slow_peer is allowed neib["slow_peer_options"] = neib.pop("slow_peer")[0] + # we can skip deprecating these by handling the int to str conversion here + # int to float is not considered considering the size of as numbers + if neib.get("remote_as"): + neib["remote_as"] = str(neib.get("remote_as")) + if neib.get("local_as") and neib.get("local_as", {}).get("number"): + neib["local_as"]["number"] = str(neib["local_as"]["number"]) # make dict neighbors dict tmp[neib[p_key[k]]] = neib _af["neighbors"] = tmp diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_global/bgp_global.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_global/bgp_global.py index 59881d622..c48cac946 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_global/bgp_global.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_global/bgp_global.py @@ -148,7 +148,7 @@ class Bgp_global(ResourceModule): """Generate configuration commands to send based on want, have and desired state. """ - if self.state in ["merged", "replaced"]: + if self.state in ["merged", "replaced", "overridden"]: w_asn = self.want.get("as_number") h_asn = self.have.get("as_number") diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/evpn_evi/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/evpn_evi/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/evpn_evi/__init__.py diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/evpn_evi/evpn_evi.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/evpn_evi/evpn_evi.py new file mode 100644 index 000000000..240906637 --- /dev/null +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/evpn_evi/evpn_evi.py @@ -0,0 +1,103 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2023 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The ios_evpn_evi config file. +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to its desired end-state is +created. +""" + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import ( + ResourceModule, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_merge, +) + +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import Facts +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.evpn_evi import ( + Evpn_eviTemplate, +) + + +class Evpn_evi(ResourceModule): + """ + The ios_evpn_evi config class + """ + + def __init__(self, module): + super(Evpn_evi, self).__init__( + empty_fact_val={}, + facts_module=Facts(module), + module=module, + resource="evpn_evi", + tmplt=Evpn_eviTemplate(), + ) + self.parsers = [ + "default_gateway.advertise.enable", + "default_gateway.advertise.disable", + "encapsulation", + "ip.local_learning.enable", + "ip.local_learning.disable", + "replication_type", + "route_distinguisher", + ] + + def execute_module(self): + """Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + if self.state not in ["parsed", "gathered"]: + self.generate_commands() + self.run_commands() + return self.result + + def generate_commands(self): + """Generate configuration commands to send based on + want, have and desired state. + """ + wantd = {entry["evi"]: entry for entry in self.want} + haved = {entry["evi"]: entry for entry in self.have} + + # if state is merged, merge want onto have and then compare + if self.state == "merged": + wantd = dict_merge(haved, wantd) + + # if state is deleted, empty out wantd and set haved to wantd + if self.state == "deleted": + haved = {k: v for k, v in iteritems(haved) if k in wantd or not wantd} + wantd = {} + + # remove superfluous config for overridden and deleted + if self.state in ["overridden", "deleted"]: + for k, have in iteritems(haved): + if k not in wantd: + self.addcmd(have, "evi", negate=True) + + for k, want in iteritems(wantd): + self._compare(want=want, have=haved.pop(k, {})) + + def _compare(self, want, have): + """Leverages the base class `compare()` method and + populates the list of commands to be run by comparing + the `want` and `have` data with the `parsers` defined + for the Evpn_evi network resource. + """ + begin = len(self.commands) + self.compare(parsers=self.parsers, want=want, have=have) + if len(self.commands) != begin: + self.commands.insert(begin, self._tmplt.render(want or have, "evi", False)) diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/evpn_global/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/evpn_global/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/evpn_global/__init__.py diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/evpn_global/evpn_global.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/evpn_global/evpn_global.py new file mode 100644 index 000000000..bd6e10321 --- /dev/null +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/evpn_global/evpn_global.py @@ -0,0 +1,98 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2023 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The ios_evpn_global config file. +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to its desired end-state is +created. +""" + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import ( + ResourceModule, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_merge, +) + +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import Facts +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.evpn_global import ( + Evpn_globalTemplate, +) + + +EVPN_GLOBAL_PARENT = "l2vpn evpn" + + +class Evpn_global(ResourceModule): + """ + The ios_evpn_global config class + """ + + def __init__(self, module): + super(Evpn_global, self).__init__( + empty_fact_val={}, + facts_module=Facts(module), + module=module, + resource="evpn_global", + tmplt=Evpn_globalTemplate(), + ) + self.parsers = [ + "default_gateway.advertise", + "flooding_suppression.address_resolution.disable", + "ip.local_learning.disable", + "replication_type", + "route_target.auto.vni", + "router_id", + ] + + def execute_module(self): + """Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + if self.state not in ["parsed", "gathered"]: + self.generate_commands() + self.run_commands() + return self.result + + def generate_commands(self): + """Generate configuration commands to send based on + want, have and desired state. + """ + wantd = self.want + haved = self.have + + # if state is merged, merge want onto have and then compare + if self.state == "merged": + wantd = dict_merge(haved, wantd) + + # remove superfluous config for deleted + if self.state == "deleted": + if haved: + self.commands.append("no " + EVPN_GLOBAL_PARENT) + wantd, haved = {}, {} + + self._compare(want=wantd, have=haved) + + def _compare(self, want, have): + """Leverages the base class `compare()` method and + populates the list of commands to be run by comparing + the `want` and `have` data with the `parsers` defined + for the Evpn_global network resource. + """ + begin = len(self.commands) + self.compare(parsers=self.parsers, want=want, have=have) + if len(self.commands) != begin: + self.commands.insert(begin, EVPN_GLOBAL_PARENT) diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp/lacp.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp/lacp.py index 0420c347b..e09a53869 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp/lacp.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp/lacp.py @@ -126,7 +126,7 @@ class Lacp(ConfigBase): :returns: the commands necessary to migrate the current configuration to the desired configuration """ - if self.state in ("merged", "replaced", "rendered") and not want: + if self.state in ("merged", "replaced", "overridden", "rendered") and not want: self._module.fail_json( msg="value of config parameter must not be empty for state {0}".format(self.state), ) @@ -135,7 +135,7 @@ class Lacp(ConfigBase): commands = self._state_deleted(want, have) elif self.state in ("merged", "rendered"): commands = self._state_merged(want, have) - elif self.state == "replaced": + elif self.state in ["replaced", "overridden"]: commands = self._state_replaced(want, have) return commands diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_global/lldp_global.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_global/lldp_global.py index c575bc7b0..34b466c52 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_global/lldp_global.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_global/lldp_global.py @@ -140,24 +140,22 @@ class Lldp_global(ConfigBase): to the desired configuration """ commands = [] - if self.state in ("merged", "replaced", "rendered") and not want: + if self.state in ("merged", "replaced", "overridden", "rendered") and not want: self._module.fail_json( msg="value of config parameter must not be empty for state {0}".format(self.state), ) - if self.state == "overridden": - commands = self._state_overridden(want, have) elif self.state == "deleted": commands = self._state_deleted(want, have) elif self.state in ("merged", "rendered"): commands = self._state_merged(want, have) - elif self.state == "replaced": + elif self.state in ["replaced", "overridden"]: commands = self._state_replaced(want, have) return commands def _state_replaced(self, want, have): - """The command generator when state is replaced + """The command generator when state is replaced/overridden :param want: the desired configuration as a dictionary :param have: the current configuration as a dictionary diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/logging_global/logging_global.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/logging_global/logging_global.py index 4eb442a0c..bfaab013b 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/logging_global/logging_global.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/logging_global/logging_global.py @@ -108,9 +108,9 @@ class Logging_global(ResourceModule): the `want` and `have` data with the `parsers` defined for the Logging_global network resource. """ + self._compare_complex_attrs(want, have) self.compare(parsers=self.parsers, want=want, have=have) self._compare_lists_attrs(want, have) - self._compare_complex_attrs(want, have) def _compare_lists_attrs(self, want, have): """Compare list of dict""" diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv2/ospfv2.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv2/ospfv2.py index 2cbc53e17..1dd26f356 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv2/ospfv2.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv2/ospfv2.py @@ -33,10 +33,6 @@ class Ospfv2(ResourceModule): The ios_ospfv2 class """ - gather_subset = ["!all", "!min"] - - gather_network_resources = ["ospfv2"] - def __init__(self, module): super(Ospfv2, self).__init__( empty_fact_val={}, @@ -46,39 +42,97 @@ class Ospfv2(ResourceModule): tmplt=Ospfv2Template(), ) + self.parsers = [ + "adjacency", + "address_family", + "auto_cost", + "bfd", + "capability.lls", + "capability.opaque", + "capability.transit", + "capability.vrf_lite", + "compatible", + "default_information", + "default_metric", + "discard_route", + "distance.admin_distance", + "distance.ospf", + "distribute_list.prefix", + "distribute_list.route_map", + "domain_id", + "domain_tag", + "event_log", + "help", + "ignore", + "interface_id", + "ispf", + "limit", + "local_rib_criteria", + "log_adjacency_changes", + "max_lsa", + "max_metric", + "maximum_paths", + "mpls.ldp.autoconfig", + "mpls.ldp.sync", + "mpls.traffic_eng", + "neighbor", + "nsf.cisco", + "nsf.ietf.disable", + "nsf.ietf.strict_lsa_checking", + "prefix_suppression", + "priority", + "queue_depth.hello.max_packets", + "queue_depth.hello.unlimited", + "queue_depth.update.max_packets", + "queue_depth.update.unlimited", + "router_id", + "shutdown", + "summary_address.not_advertise", + "summary_address.nssa_only", + "timers.throttle.lsa", + "timers.pacing.flood", + "timers.pacing.lsa_group", + "timers.pacing.retransmission", + "timers.throttle.spf", + "traffic_share", + "ttl_security", + ] + def execute_module(self): """Execute the module :rtype: A dictionary :returns: The result from module execution """ - self.gen_config() - self.run_commands() + if self.state not in ["parsed", "gathered"]: + self.generate_commands() + self.run_commands() return self.result - def gen_config(self): + def generate_commands(self): """Select the appropriate function based on the state provided :rtype: A list :returns: the commands necessary to migrate the current configuration to the desired configuration """ + haved, wantd = dict(), dict() + if self.want: - wantd = {} for entry in self.want.get("processes", []): + entry = self._handle_deprecated(entry) wantd.update({(entry["process_id"], entry.get("vrf")): entry}) - else: - wantd = {} + if self.have: - haved = {} for entry in self.have.get("processes", []): + # entry = self._handle_deprecated(entry) haved.update({(entry["process_id"], entry.get("vrf")): entry}) - else: - haved = {} # turn all lists of dicts into dicts prior to merge for each in wantd, haved: - self.list_to_dict(each) + if each: + self._list_to_dict(each) + # if state is merged, merge want onto have if self.state == "merged": wantd = dict_merge(haved, wantd) @@ -103,61 +157,32 @@ class Ospfv2(ResourceModule): self._compare(want=want, have=haved.pop(k, {})) def _compare(self, want, have): - parsers = [ - "adjacency", - "address_family", - "auto_cost", - "bfd", - "capability", - "compatible", - "default_information", - "default_metric", - "discard_route", - "distance.admin_distance", - "distance.ospf", - "distribute_list.acls", - "distribute_list.prefix", - "distribute_list.route_map", - "domain_id", - "domain_tag", - "event_log", - "help", - "ignore", - "interface_id", - "ispf", - "limit", - "local_rib_criteria", - "log_adjacency_changes", - "max_lsa", - "max_metric", - "maximum_paths", - "mpls.ldp", - "mpls.traffic_eng", - "neighbor", - "network", - "nsf.cisco", - "nsf.ietf", - "passive_interface", - "prefix_suppression", - "priority", - "queue_depth.hello", - "queue_depth.update", - "router_id", - "shutdown", - "summary_address", - "timers.throttle.lsa", - "timers.throttle.spf", - "traffic_share", - "ttl_security", - ] - if want != have: self.addcmd(want or have, "pid", False) - self.compare(parsers, want, have) + self.compare(self.parsers, want, have) self._areas_compare(want, have) + self._complex_compare(want, have) if want.get("passive_interfaces"): self._passive_interfaces_compare(want, have) + def _complex_compare(self, want, have): + complex_parsers = ["distribute_list.acls", "network"] + for _parser in complex_parsers: + if _parser == "distribute_list.acls": + wdist = want.get("distribute_list", {}).get("acls", {}) + hdist = have.get("distribute_list", {}).get("acls", {}) + else: + wdist = want.get(_parser, {}) + hdist = have.get(_parser, {}) + for key, wanting in iteritems(wdist): + haveing = hdist.pop(key, {}) + if wanting != haveing: + if haveing and self.state in ["overridden", "replaced"]: + self.addcmd(haveing, _parser, negate=True) + self.addcmd(wanting, _parser, False) + for key, haveing in iteritems(hdist): + self.addcmd(haveing, _parser, negate=True) + def _areas_compare(self, want, have): wareas = want.get("areas", {}) hareas = have.get("areas", {}) @@ -168,42 +193,40 @@ class Ospfv2(ResourceModule): def _area_compare(self, want, have): parsers = [ - "area.authentication", - "area.capability", - "area.default_cost", - "area.nssa", - "area.nssa.translate", - "area.ranges", - "area.sham_link", - "area.stub", + "authentication", + "capability", + "default_cost", + "nssa", + "nssa.translate", + "sham_link", + "stub", ] self.compare(parsers=parsers, want=want, have=have) - self._area_compare_filters(want, have) + self._area_complex_compare(want, have, want.get("area_id")) - def _area_compare_filters(self, wantd, haved): - for name, entry in iteritems(wantd): - h_item = haved.pop(name, {}) - if entry != h_item and name == "filter_list": - filter_list_entry = {} - filter_list_entry["area_id"] = wantd["area_id"] - if h_item: - li_diff = [ - item for item in entry + h_item if item not in entry or item not in h_item - ] - else: - li_diff = entry - filter_list_entry["filter_list"] = li_diff - self.addcmd(filter_list_entry, "area.filter_list", False) - for name, entry in iteritems(haved): - if name == "filter_list": - self.addcmd(entry, "area.filter_list", True) + def _area_complex_compare(self, want, have, area_id): + area_complex_parsers = ["filter_list", "ranges"] + for _parser in area_complex_parsers: + wantr = want.get(_parser, {}) + haver = have.get(_parser, {}) + for key, wanting in iteritems(wantr): + haveing = have.pop(key, {}) + haveing["area_id"] = area_id + wanting["area_id"] = area_id + if wanting != haveing: + if haveing and self.state in ["overridden", "replaced"]: + self.addcmd(haveing, _parser, negate=True) + self.addcmd(wanting, _parser, False) + for key, haveing in iteritems(haver): + haveing["area_id"] = area_id + self.addcmd(haveing, _parser, negate=True) def _passive_interfaces_compare(self, want, have): - parsers = ["passive_interfaces"] + parsers = ["passive_interfaces.default", "passive_interfaces.interface"] h_pi = None for k, v in iteritems(want["passive_interfaces"]): - h_pi = have.get("passive_interfaces", []) - if h_pi and h_pi.get(k) and h_pi.get(k) != v: + h_pi = have.get("passive_interfaces", {}) + if h_pi.get(k) and h_pi.get(k) != v: for each in v["name"]: h_interface_name = h_pi[k].get("name", []) if each not in h_interface_name: @@ -243,42 +266,51 @@ class Ospfv2(ResourceModule): } self.compare( parsers=parsers, - want={"passive_interface": temp}, + want={"passive_interfaces": temp}, have=dict(), ) elif k == "default": self.compare( parsers=parsers, want=dict(), - have={"passive_interface": {"default": True}}, + have={"passive_interfaces": {"default": True}}, ) - def list_to_dict(self, param): - if param: - for _pid, proc in iteritems(param): - for area in proc.get("areas", []): - ranges = {} - for entry in area.get("ranges", []): - ranges.update({entry["address"]: entry}) - if bool(ranges): - area["ranges"] = ranges - filter_list = {} - for entry in area.get("filter_list", []): - filter_list.update({entry["direction"]: entry}) - if bool(filter_list): - area["filter_list"] = filter_list - temp = {} - for entry in proc.get("areas", []): - temp.update({entry["area_id"]: entry}) - proc["areas"] = temp - if proc.get("distribute_list"): - if "acls" in proc.get("distribute_list"): - temp = {} - for entry in proc["distribute_list"].get("acls", []): - temp.update({entry["name"]: entry}) - proc["distribute_list"]["acls"] = temp - if proc.get("passive_interfaces") and proc["passive_interfaces"].get("interface"): - temp = {} - for entry in proc["passive_interfaces"]["interface"].get("name", []): - temp.update({entry: entry}) - proc["passive_interfaces"]["interface"]["name"] = temp + def _list_to_dict(self, param): + for _pid, proc in param.items(): + # convert list to dict for areas + for area in proc.get("areas", []): + area["ranges"] = {entry["address"]: entry for entry in area.get("ranges", [])} + area["filter_list"] = { + entry["direction"]: entry for entry in area.get("filter_list", []) + } + + proc["areas"] = {entry["area_id"]: entry for entry in proc.get("areas", [])} + + # list to dict for distribute_list + distribute_list = proc.get("distribute_list", {}) + if "acls" in distribute_list: + distribute_list["acls"] = { + entry["name"]: entry for entry in distribute_list["acls"] + } + + # list to dict for passive_interfaces + passive_interfaces = proc.get("passive_interfaces", {}).get("interface", {}) + if passive_interfaces.get("name"): + passive_interfaces["name"] = {entry: entry for entry in passive_interfaces["name"]} + + # list to dict for network + if proc.get("network"): + proc["network"] = {entry["address"]: entry for entry in proc["network"]} + + def _handle_deprecated(self, config): + if config.get("passive_interface"): + passive_interfaces = config.get("passive_interfaces", {}) + interface = passive_interfaces.get("interface", {}) + name_list = interface.get("name", []) + if not name_list: + name_list.append(config["passive_interface"]) + else: + name_list.extend(config["passive_interface"]) + del config["passive_interface"] + return config diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ping/ping.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ping/ping.py index f2417f596..138cd5715 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ping/ping.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ping/ping.py @@ -81,7 +81,7 @@ class Ping: Returns the percent of packet loss, received packets, transmitted packets, and RTT data. """ - if type(ping_results) == list: + if isinstance(ping_results, list): ping_results = ping_results[0] ping_data = PingTemplate(lines=ping_results.splitlines()) diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/prefix_lists/prefix_lists.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/prefix_lists/prefix_lists.py index 7c4ebe5ec..210fb234d 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/prefix_lists/prefix_lists.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/prefix_lists/prefix_lists.py @@ -63,12 +63,10 @@ class Prefix_lists(ResourceModule): want, have and desired state. """ wantd = {entry["afi"]: entry for entry in self.want} - haved = {entry["afi"]: entry for entry in self.have} - # Convert each of config list to dict - for each in wantd, haved: - self.list_to_dict(each) + self._prefix_list_transform(wantd) + self._prefix_list_transform(haved) # if state is merged, merge want onto have and then compare if self.state == "merged": @@ -76,44 +74,24 @@ class Prefix_lists(ResourceModule): # if state is deleted, empty out wantd and set haved to wantd if self.state == "deleted": - temp = None - for k, v in iteritems(haved): - if k in wantd: - if wantd[k].get("prefix_lists"): - want_afi_name = wantd[k].get("prefix_lists", {}) - haved[k]["prefix_lists"] = { - key: val - for key, val in iteritems(v.get("prefix_lists")) - if key in want_afi_name - } - elif wantd: - temp = k - if temp: - haved.pop(k) - wantd = {} - for k, have in iteritems(haved): - for key, val in iteritems(have["prefix_lists"]): - if k == "ipv4": - k = "ip" - self.commands.append("no {0} prefix-list {1}".format(k, key)) + haved = {k: v for k, v in iteritems(haved) if k in wantd or not wantd} + for key, hvalue in iteritems(haved): + wvalue = wantd.pop(key, {}) + if wvalue: + wplists = wvalue.get("prefix_lists", {}) + hplists = hvalue.get("prefix_lists", {}) + hvalue["prefix_lists"] = { + k: v for k, v in iteritems(hplists) if k in wplists or not wplists + } # remove superfluous config for overridden and deleted if self.state in ["overridden", "deleted"]: for k, have in iteritems(haved): - want_afi = wantd.get(k, {}) - for key, val in iteritems(have["prefix_lists"]): - if k == "ipv4": - k = "ip" - if want_afi and key not in want_afi.get("prefix_lists"): - self.commands.append("no {0} prefix-list {1}".format(k, key)) + if k not in wantd: + self._compare(want={}, have=have) for k, want in iteritems(wantd): self._compare(want=want, have=haved.pop(k, {})) - # alligning cmd with negate cmd 1st followed by config cmd - if self.state in ["overridden", "replaced"]: - self.commands = [each for each in self.commands if "no" in each] + [ - each for each in self.commands if "no" not in each - ] def _compare(self, want, have): """Leverages the base class `compare()` method and @@ -121,130 +99,48 @@ class Prefix_lists(ResourceModule): the `want` and `have` data with the `parsers` defined for the Prefix_lists network resource. """ - if want != have and self.state != "deleted": - for k, v in iteritems(want["prefix_lists"]): - if have.get("prefix_lists") and have["prefix_lists"].get(k): - have_prefix = have["prefix_lists"].pop(k, {}) - for key, val in iteritems(v.get("entries")): - if have_prefix.get("entries"): - have_prefix_param = have_prefix["entries"].pop(key, {}) - else: - have_prefix_param = None - if have_prefix.get("description"): - self.compare( - parsers=self.parsers, - want={ - "afi": want["afi"], - "name": k, - "prefix_list": {"description": v["description"]}, - }, - have={ - "afi": want["afi"], - "name": k, - "prefix_list": {"description": have_prefix.pop("description")}, - }, - ) - if have_prefix_param and val != have_prefix_param: - if key == "description": - # Code snippet should be removed when Description param is removed from - # entries level as this supports deprecated level of Description - self.compare( - parsers=self.parsers, - want={"afi": want["afi"], "name": k, "prefix_list": {key: val}}, - have={ - "afi": have["afi"], - "name": k, - "prefix_list": {key: have_prefix_param}, - }, - ) - else: - if self.state == "merged" and have_prefix_param.get( - "sequence", - ) == val.get("sequence"): - self._module.fail_json( - "Cannot update existing sequence {0} of Prefix Lists {1} with state merged.".format( - val.get("sequence"), - k, - ) - + " Please use state replaced or overridden.", - ) - self.compare( - parsers=self.parsers, - want=dict(), - have={ - "afi": have["afi"], - "name": k, - "prefix_list": have_prefix_param, - }, - ) - self.compare( - parsers=self.parsers, - want={"afi": want["afi"], "name": k, "prefix_list": val}, - have={ - "afi": have["afi"], - "name": k, - "prefix_list": have_prefix_param, - }, - ) - elif val and val != have_prefix_param: - self.compare( - parsers=self.parsers, - want={"afi": want["afi"], "name": k, "prefix_list": val}, - have=dict(), - ) - if have_prefix and (self.state == "replaced" or self.state == "overridden"): - if have_prefix.get("description"): - # Code snippet should be removed when Description param is removed from - # entries level as this supports deprecated level of Description - self.compare( - parsers=self.parsers, - want=dict(), - have={ - "afi": want["afi"], - "name": k, - "prefix_list": {"description": have_prefix["description"]}, - }, - ) - for key, val in iteritems(have_prefix.get("entries")): - self.compare( - parsers=self.parsers, - want=dict(), - have={"afi": have["afi"], "name": k, "prefix_list": val}, - ) - elif v: - if v.get("description"): - self.compare( - parsers=self.parsers, - want={ - "afi": want["afi"], - "name": k, - "prefix_list": {"description": v["description"]}, - }, - have=dict(), - ) - for key, val in iteritems(v.get("entries")): - self.compare( - parsers=self.parsers, - want={"afi": want["afi"], "name": k, "prefix_list": val}, - have=dict(), - ) + wplists = want.get("prefix_lists", {}) + hplists = have.get("prefix_lists", {}) + for wk, wentry in iteritems(wplists): + hentry = hplists.pop(wk, {}) + self.compare(["description"], want=wentry, have=hentry) + # compare sequences + self._compare_seqs(wentry.pop("entries", {}), hentry.pop("entries", {})) - def list_to_dict(self, param): - if param: - for key, val in iteritems(param): - if val.get("prefix_lists"): - temp_prefix_list = {} - for each in val["prefix_lists"]: - temp_entries = dict() - if each.get("entries"): - for every in each["entries"]: - temp_entries.update({str(every["sequence"]): every}) - temp_prefix_list.update( - { - each["name"]: { - "description": each.get("description"), - "entries": temp_entries, - }, - }, + if self.state in ["overridden", "deleted"]: + # remove remaining prefix lists + for h in hplists.values(): + self.commands.append( + "no {0} prefix-list {1}".format(h["afi"].replace("ipv4", "ip"), h["name"]), + ) + + def _compare_seqs(self, want, have): + for wseq, wentry in iteritems(want): + hentry = have.pop(wseq, {}) + if hentry != wentry: + if hentry: + if self.state == "merged": + self._module.fail_json( + msg="Cannot update existing sequence {0} of prefix list {1} with state merged." + " Please use state replaced or overridden.".format( + hentry["sequence"], + hentry["name"], + ), ) - val["prefix_lists"] = temp_prefix_list + else: + self.addcmd(hentry, "entry", negate=True) + self.addcmd(wentry, "entry") + # remove remaining entries from have prefix list + for hseq in have.values(): + self.addcmd(hseq, "entry", negate=True) + + def _prefix_list_transform(self, entry): + for afi, value in iteritems(entry): + if "prefix_lists" in value: + for plist in value["prefix_lists"]: + plist.update({"afi": afi}) + if "entries" in plist: + for seq in plist["entries"]: + seq.update({"afi": afi, "name": plist["name"]}) + plist["entries"] = {x["sequence"]: x for x in plist["entries"]} + value["prefix_lists"] = {entry["name"]: entry for entry in value["prefix_lists"]} diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/service/service.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/service/service.py index 23e3329be..6a4c8a1ff 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/service/service.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/service/service.py @@ -103,9 +103,11 @@ class Service(ResourceModule): "prompt": True, "slave_log": True, "password_recovery": True, - "private_config_encryption": True, } + if "private_config_encryption" in haved: + service_default["private_config_encryption"] = True + # if state is merged, merge want onto have and then compare if self.state == "merged": wantd = dict_merge(haved, wantd) @@ -115,7 +117,7 @@ class Service(ResourceModule): wantd = self._service_list_to_dict(service_default) # if state is replaced - elif self.state == "replaced": + elif self.state in ["replaced", "overridden"]: wantd = dict_merge(self._service_list_to_dict(service_default), wantd) self._compare(want=wantd, have=haved) diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/snmp_server/snmp_server.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/snmp_server/snmp_server.py index ff45f7b5f..187d0779d 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/snmp_server/snmp_server.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/snmp_server/snmp_server.py @@ -77,72 +77,121 @@ class Snmp_server(ResourceModule): "views", ] self.complex_parsers = [ + "traps.aaa_server", "traps.auth_framework", "traps.bfd", "traps.bgp", + "traps.bgp.cbgp2", "traps.bridge", + "traps.bulkstat", + "traps.call_home", "traps.casa", + "traps.cef", "traps.cnpd", "traps.config", "traps.config_copy", "traps.config_ctid", + "traps.cpu", "traps.dhcp", + "traps.dlsw", "traps.eigrp", - "traps.entity", "traps.energywise", + "traps.entity", + "traps.entity_diag", + "traps.entity_perf", + "traps.entity_state", + "traps.envmon", + "traps.errdisable", + "traps.ether_oam", + "traps.ethernet.cfm.alarm", + "traps.ethernet.cfm.cc", + "traps.ethernet.cfm.crosscheck", + "traps.ethernet.evc", "traps.event_manager", + "traps.flash", + "traps.flex_links", + "traps.firewall", "traps.flowmon", + "traps.frame_relay", + "traps.frame_relay.subif", "traps.fru_ctrl", "traps.hsrp", - "traps.ipsla", - "traps.isis", - "traps.msdp", - "traps.mvpn", - "traps.mpls_vpn", - "traps.pki", - "traps.pw_vc", - "traps.rsvp", - "traps.syslog", - "traps.transceiver_all", - "traps.tty", - "traps.vrrp", - "traps.vrfmib", - "traps.ipmulticast", "traps.ike.policy.add", "traps.ike.policy.delete", "traps.ike.tunnel.start", "traps.ike.tunnel.stop", + "traps.ipmulticast", "traps.ipsec.cryptomap.add", - "traps.ipsec.cryptomap.delete", "traps.ipsec.cryptomap.attach", + "traps.ipsec.cryptomap.delete", "traps.ipsec.cryptomap.detach", + "traps.ipsec.too_many_sas", "traps.ipsec.tunnel.start", "traps.ipsec.tunnel.stop", - "traps.ipsec.too_many_sas", + "traps.ipsla", + "traps.isis", + "traps.l2tc", + "traps.l2tun.pseudowire_status", + "traps.l2tun.session", + "traps.lisp", + "traps.license", + "traps.local_auth", + "traps.mac_notification", + "traps.memory", + "traps.mpls.fast_reroute", + "traps.mpls.ldp", + "traps.mpls.rfc.ldp", + "traps.mpls.rfc.traffic_eng", + "traps.mpls.rfc.vpn", + "traps.mpls.traffic_eng", + "traps.mpls.vpn", + "traps.msdp", + "traps.mvpn", + "traps.nhrp.nhc", + "traps.nhrp.nhp", + "traps.nhrp.nhs", + "traps.nhrp.quota_exceeded", "traps.ospf.cisco_specific.error", - "traps.ospf.cisco_specific.retransmit", "traps.ospf.cisco_specific.lsa", + "traps.ospf.cisco_specific.retransmit", "traps.ospf.cisco_specific.state_change.nssa_trans_change", "traps.ospf.cisco_specific.state_change.shamlink.interface", "traps.ospf.cisco_specific.state_change.shamlink.neighbor", "traps.ospf.error", - "traps.ospf.retransmit", "traps.ospf.lsa", + "traps.ospf.retransmit", "traps.ospf.state_change", - "traps.l2tun.pseudowire_status", - "traps.l2tun.session", - "traps.cpu", - "traps.firewall", + "traps.ospfv3.errors", + "traps.ospfv3.rate_limit", + "traps.ospfv3.state_change", "traps.pim", + "traps.pki", + "traps.port_security", + "traps.power_ethernet", + "traps.pw_vc", + "traps.rep", + "traps.rsvp", + "traps.rf", + "traps.smart_license", "traps.snmp", - "traps.frame_relay", - "traps.frame_relay.subif", - "traps.cef", - "traps.dlsw", - "traps.ethernet.evc", - "traps.ethernet.cfm.alarm", - "traps.ethernet.cfm.cc", - "traps.ethernet.cfm.crosscheck", + "traps.stackwise", + "traps.stpx", + "traps.syslog", + "traps.transceiver_all", + "traps.trustsec", + "traps.trustsec_interface", + "traps.trustsec_policy", + "traps.trustsec_server", + "traps.trustsec_sxp", + "traps.tty", + "traps.udld", + "traps.vlan_membership", + "traps.vlancreate", + "traps.vlandelete", + "traps.vrfmib", + "traps.vrrp", + "traps.vswitch", + "traps.vtp", ] def execute_module(self): @@ -163,6 +212,8 @@ class Snmp_server(ResourceModule): wantd = self._snmp_list_to_dict(self.want) haved = self._snmp_list_to_dict(self.have) + wantd = self._handle_deprecates(want=wantd) + # if state is merged, merge want onto have and then compare if self.state == "merged": wantd = dict_merge(haved, wantd) @@ -186,16 +237,39 @@ class Snmp_server(ResourceModule): def _compare_lists_attrs(self, want, have): """Compare list of dict""" for _parser in self.list_parsers: - i_want = want.get(_parser, {}) - i_have = have.get(_parser, {}) - for key, wanting in iteritems(i_want): - haveing = i_have.pop(key, {}) - if wanting != haveing: - if haveing and self.state in ["overridden", "replaced"]: - self.addcmd(haveing, _parser, negate=True) - self.addcmd(wanting, _parser) - for key, haveing in iteritems(i_have): - self.addcmd(haveing, _parser, negate=True) + if _parser == "users": + i_want = want.get(_parser, {}) + i_have = have.get(_parser, {}) + for key, wanting in iteritems(i_want): + wanting_compare = deepcopy(wanting) + if ( + "authentication" in wanting_compare + and "password" in wanting_compare["authentication"] + ): + wanting_compare["authentication"].pop("password") + if ( + "encryption" in wanting_compare + and "password" in wanting_compare["encryption"] + ): + wanting_compare["encryption"].pop("password") + haveing = i_have.pop(key, {}) + if wanting_compare != haveing: + if haveing and self.state in ["overridden", "replaced"]: + self.addcmd(haveing, _parser, negate=True) + self.addcmd(wanting, _parser) + for key, haveing in iteritems(i_have): + self.addcmd(haveing, _parser, negate=True) + else: + i_want = want.get(_parser, {}) + i_have = have.get(_parser, {}) + for key, wanting in iteritems(i_want): + haveing = i_have.pop(key, {}) + if wanting != haveing: + if haveing and self.state in ["overridden", "replaced"]: + self.addcmd(haveing, _parser, negate=True) + self.addcmd(wanting, _parser) + for key, haveing in iteritems(i_have): + self.addcmd(haveing, _parser, negate=True) def _snmp_list_to_dict(self, data): """Convert all list of dicts to dicts of dicts""" @@ -242,7 +316,8 @@ class Snmp_server(ResourceModule): tmp_data[k]["protocol"] = tmp elif k == "groups": tmp_data[k] = { - str(i[p_key.get(k)] + i.get("version_option", "")): i for i in tmp_data[k] + str(i[p_key.get(k)] + i.get("version_option", "") + i.get("context", "")): i + for i in tmp_data[k] } elif k == "views": tmp_data[k] = { @@ -251,3 +326,23 @@ class Snmp_server(ResourceModule): else: tmp_data[k] = {str(i[p_key.get(k)]): i for i in tmp_data[k]} return tmp_data + + def _handle_deprecates(self, want): + """Remove deprecated attributes and set the replacment""" + + # Take in count the traps config mpls_vpn which is DEPRECATED and replaced by mpls.vpn + if "traps" in want: + if "mpls_vpn" in want["traps"]: + want["traps"] = dict_merge( + want["traps"], + {"mpls": {"vpn": {"enable": want["traps"]["mpls_vpn"]}}}, + ) + want["traps"].pop("mpls_vpn") + if "envmon" in want["traps"] and "fan" in want["traps"]["envmon"]: + want["traps"]["envmon"]["fan_enable"] = want["traps"]["envmon"]["fan"].get( + "enable", + False, + ) + want["traps"]["envmon"].pop("fan") + + return want diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/static_routes/static_routes.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/static_routes/static_routes.py index 79b63c8fe..e6c1336d6 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/static_routes/static_routes.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/static_routes/static_routes.py @@ -71,7 +71,7 @@ class Static_routes(ResourceModule): if delete_spcl and haved and self.state == "deleted": for pk, to_rem in delete_spcl.items(): if pk in ["ipv4", "ipv6"]: - _afis = haved.get("_afis_") + _afis = haved.get("(_afis_)") for k, v in _afis.get(pk, {}).items(): for each_dest in to_rem: if k.split("_")[0] == each_dest: @@ -184,5 +184,5 @@ class Static_routes(ResourceModule): _routes[_key] = dummy_sr _srts[_afi] = _routes - _static_rts[_vrf if _vrf else "_afis_"] = _srts + _static_rts[_vrf if _vrf else "(_afis_)"] = _srts return _static_rts, _delete_spc diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vlans/vlans.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vlans/vlans.py index 9d206f509..ad95b680a 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vlans/vlans.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vlans/vlans.py @@ -20,7 +20,10 @@ __metaclass__ = type from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import ( ConfigBase, ) -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + remove_empties, + to_list, +) from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import Facts from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import dict_to_set @@ -44,6 +47,7 @@ class Vlans(ConfigBase): :rtype: A dictionary :returns: The current configuration as a dictionary """ + facts, _warnings = Facts(self._module).get_facts( self.gather_subset, self.gather_network_resources, @@ -63,7 +67,12 @@ class Vlans(ConfigBase): result = {"changed": False} commands = list() warnings = list() - + self.have_now = list() + self.configuration = self._module.params["configuration"] + if not self.configuration: + self.vlan_parent = "vlan {0}" + else: + self.vlan_parent = "vlan configuration {0}" if self.state in self.ACTION_STATES: existing_vlans_facts = self.get_vlans_facts() else: @@ -110,7 +119,10 @@ class Vlans(ConfigBase): :returns: the commands necessary to migrate the current configuration to the desired configuration """ - want = self._module.params["config"] + want = [] + if self._module.params.get("config"): + for cfg in self._module.params["config"]: + want.append(remove_empties(cfg)) have = existing_vlans_facts resp = self.set_state(want, have) return to_list(resp) @@ -173,6 +185,7 @@ class Vlans(ConfigBase): commands = [] want_local = want + self.have_now = have.copy() for each in have: count = 0 for every in want_local: @@ -264,7 +277,8 @@ class Vlans(ConfigBase): def _set_config(self, want, have): # Set the interface config based on the want and have config commands = [] - vlan = "vlan {0}".format(want.get("vlan_id")) + + vlan = self.vlan_parent.format(want.get("vlan_id")) def negate_have_config(want_diff, have_diff, vlan, commands): name = dict(have_diff).get("name") @@ -294,8 +308,9 @@ class Vlans(ConfigBase): self.remove_command_from_config_list(vlan, "private-vlan association", commands) # Get the diff b/w want n have - want_dict = dict_to_set(want) - have_dict = dict_to_set(have) + + want_dict = dict_to_set(want, sort_dictionary=True) + have_dict = dict_to_set(have, sort_dictionary=True) diff = want_dict - have_dict have_diff = have_dict - want_dict @@ -303,69 +318,140 @@ class Vlans(ConfigBase): if have_diff and (self.state == "replaced" or self.state == "overridden"): negate_have_config(diff, have_diff, vlan, commands) - name = dict(diff).get("name") - state = dict(diff).get("state") - shutdown = dict(diff).get("shutdown") - mtu = dict(diff).get("mtu") - remote_span = dict(diff).get("remote_span") - private_vlan = dict(diff).get("private_vlan") - - if name: - self.add_command_to_config_list(vlan, "name {0}".format(name), commands) - if state: - self.add_command_to_config_list(vlan, "state {0}".format(state), commands) - if mtu: - self.add_command_to_config_list(vlan, "mtu {0}".format(mtu), commands) - if remote_span: - self.add_command_to_config_list(vlan, "remote-span", commands) - - if private_vlan: - private_vlan_type = dict(private_vlan).get("type") - private_vlan_associated = dict(private_vlan).get("associated") - if private_vlan_type: - self.add_command_to_config_list( - vlan, - "private-vlan {0}".format(private_vlan_type), - commands, + if not self.configuration: + name = dict(diff).get("name") + state = dict(diff).get("state") + shutdown = dict(diff).get("shutdown") + mtu = dict(diff).get("mtu") + remote_span = dict(diff).get("remote_span") + private_vlan = dict(diff).get("private_vlan") + + if name: + self.add_command_to_config_list(vlan, "name {0}".format(name), commands) + if state: + self.add_command_to_config_list(vlan, "state {0}".format(state), commands) + if mtu: + self.add_command_to_config_list(vlan, "mtu {0}".format(mtu), commands) + if remote_span: + self.add_command_to_config_list(vlan, "remote-span", commands) + + if private_vlan: + private_vlan_type = dict(private_vlan).get("type") + private_vlan_associated = dict(private_vlan).get("associated") + if private_vlan_type: + self.add_command_to_config_list( + vlan, + "private-vlan {0}".format(private_vlan_type), + commands, + ) + if private_vlan_associated: + associated_list = ",".join( + str(e) for e in private_vlan_associated + ) # Convert python list to string with elements separated by a comma + self.add_command_to_config_list( + vlan, + "private-vlan association {0}".format(associated_list), + commands, + ) + if shutdown == "enabled": + self.add_command_to_config_list(vlan, "shutdown", commands) + elif shutdown == "disabled": + self.add_command_to_config_list(vlan, "no shutdown", commands) + else: + member_dict = dict(diff).get("member") + if member_dict: + member_dict = dict(member_dict) + member_vni = member_dict.get("vni") + member_evi = member_dict.get("evi") + commands.extend( + self._remove_vlan_vni_evi_mapping( + want, + ), ) - if private_vlan_associated: - associated_list = ",".join( - str(e) for e in private_vlan_associated - ) # Convert python list to string with elements separated by a comma - self.add_command_to_config_list( - vlan, - "private-vlan association {0}".format(associated_list), - commands, + commands.extend( + [ + vlan, + self._get_member_cmds(member_dict), + ], ) - if shutdown == "enabled": - self.add_command_to_config_list(vlan, "shutdown", commands) - elif shutdown == "disabled": - self.add_command_to_config_list(vlan, "no shutdown", commands) elif have_diff and (self.state == "replaced" or self.state == "overridden"): negate_have_config(diff, have_diff, vlan, commands) - return commands def _clear_config(self, want, have): # Delete the interface config based on the want and have config commands = [] - vlan = "vlan {0}".format(have.get("vlan_id")) + vlan = self.vlan_parent.format(have.get("vlan_id")) if ( have.get("vlan_id") - and "default" not in have.get("name") + and "default" not in have.get("name", "") and (have.get("vlan_id") != want.get("vlan_id") or self.state == "deleted") ): self.remove_command_from_config_list(vlan, "vlan", commands) - elif "default" not in have.get("name"): - if have.get("mtu") != want.get("mtu"): - self.remove_command_from_config_list(vlan, "mtu", commands) - if have.get("remote_span") != want.get("remote_span") and want.get("remote_span"): - self.remove_command_from_config_list(vlan, "remote-span", commands) - if have.get("shutdown") != want.get("shutdown") and want.get("shutdown"): - self.remove_command_from_config_list(vlan, "shutdown", commands) - if have.get("state") != want.get("state") and want.get("state"): - self.remove_command_from_config_list(vlan, "state", commands) + if self.configuration and self.state == "overridden": + self.have_now.remove(have) + elif "default" not in have.get("name", ""): + if not self.configuration: + if have.get("mtu") != want.get("mtu"): + self.remove_command_from_config_list(vlan, "mtu", commands) + if have.get("remote_span") != want.get("remote_span") and want.get("remote_span"): + self.remove_command_from_config_list(vlan, "remote-span", commands) + if have.get("shutdown") != want.get("shutdown") and want.get("shutdown"): + self.remove_command_from_config_list(vlan, "shutdown", commands) + if have.get("state") != want.get("state") and want.get("state"): + self.remove_command_from_config_list(vlan, "state", commands) + return commands + def _remove_vlan_vni_evi_mapping(self, want_dict): + commands = [] + have_copy = self.have_now.copy() + vlan = want_dict["vlan_id"] + for vlan_dict in have_copy: + if vlan_dict["vlan_id"] == vlan: + if "member" in vlan_dict: + commands.extend( + [ + self.vlan_parent.format(vlan), + self._get_member_cmds( + vlan_dict.get("member", {}), + prefix="no", + ), + ], + ) + vlan_dict.pop("member") + if vlan_dict["vlan_id"] != vlan: + delete_member = False + have_vni = vlan_dict.get("member", {}).get("vni") + have_evi = vlan_dict.get("member", {}).get("evi") + if have_vni and (have_vni == want_dict["member"].get("vni")): + delete_member = True + if have_evi and (have_evi == want_dict["member"].get("evi")): + delete_member = True + if delete_member: + commands.extend( + [ + self.vlan_parent.format(vlan_dict["vlan_id"]), + self._get_member_cmds( + vlan_dict.get("member", {}), + prefix="no", + ), + ], + ) + self.have_now.remove(vlan_dict) return commands + + def _get_member_cmds(self, member_dict, prefix=""): + cmd = "" + if prefix: + prefix = prefix + " " + member_vni = member_dict.get("vni") + member_evi = member_dict.get("evi") + + if member_evi: + cmd = prefix + "member evpn-instance {0} vni {1}".format(member_evi, member_vni) + elif member_vni: + cmd = prefix + "member vni {0}".format(member_vni) + + return cmd diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vxlan_vtep/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vxlan_vtep/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vxlan_vtep/__init__.py diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vxlan_vtep/vxlan_vtep.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vxlan_vtep/vxlan_vtep.py new file mode 100644 index 000000000..bb35b04e4 --- /dev/null +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vxlan_vtep/vxlan_vtep.py @@ -0,0 +1,190 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2023 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The ios_vxlan_vtep config file. +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to its desired end-state is +created. +""" + +from ansible.module_utils.six import iteritems +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import ( + ResourceModule, +) +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( + dict_merge, + param_list_to_dict, +) + +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import Facts +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.vxlan_vtep import ( + Vxlan_vtepTemplate, +) + + +class Vxlan_vtep(ResourceModule): + """ + The ios_vxlan_vtep config class + """ + + def __init__(self, module): + super(Vxlan_vtep, self).__init__( + empty_fact_val={}, + facts_module=Facts(module), + module=module, + resource="vxlan_vtep", + tmplt=Vxlan_vtepTemplate(), + ) + self.parsers = [ + "source_interface", + "host_reachability_bgp", + ] + + def execute_module(self): + """Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + + if self.state not in ["parsed", "gathered"]: + self.generate_commands() + self.run_commands() + return self.result + + def generate_commands(self): + """Generate configuration commands to send based on + want, have and desired state. + """ + + wantd, haved = self._interface_list_to_dict(self.want, self.have) + + # if state is merged, merge want onto have and then compare + if self.state == "merged": + wantd = dict_merge(haved, wantd) + + # if state is deleted, empty out wantd and set haved to wantd + if self.state == "deleted": + haved = {k: v for k, v in iteritems(haved) if k in wantd or not wantd} + wantd_copy = wantd.copy() + wantd = {} + + # remove superfluous config for deleted + if self.state in ["overridden", "deleted"]: + for k, have in iteritems(haved): + if k not in wantd: + have = self._filtered_dict(wantd_copy.get(k), have) + self._compare(want={}, have=have) + + for k, want in iteritems(wantd): + self._compare(want=want, have=haved.pop(k, {})) + + def _compare(self, want, have): + """Leverages the base class `compare()` method and + populates the list of commands to be run by comparing + the `want` and `have` data with the `parsers` defined + for the Vxlan_vtep network resource. + """ + + begin = len(self.commands) + self.compare(parsers=self.parsers, want=want, have=have) + + self._compare_member_vnis( + want.pop("member", {}).get("vni", {}), + have.pop("member", {}).get("vni", {}), + ) + + if len(self.commands) != begin: + self.commands.insert( + begin, + self._tmplt.render(want or have, "interface", False), + ) + + def _compare_member_vnis(self, wantmv, havemv): + """Compare member VNIs dict""" + + PARSER_DICT = { + "l2vni": "replication", + "l3vni": "vrf", + } + + for vni_type in ["l2vni", "l3vni"]: + wantd = wantmv.get(vni_type, {}) + haved = havemv.get(vni_type, {}) + undel_vnis = haved.copy() + + for wvni, want in wantd.items(): + have = haved.pop(wvni, {}) + if want != have: + # remove exiting config of the member VNI + self.addcmd(undel_vnis.pop(wvni, {}), PARSER_DICT[vni_type], True) + if vni_type == "l3vni": + undel_vnis = self._remove_existing_vnis_vrfs(want["vrf"], undel_vnis) + self.addcmd(want, PARSER_DICT[vni_type]) + + # remove remaining configs in have for replaced state + for hvni, have in haved.items(): + if hvni in undel_vnis: + self.addcmd(have, PARSER_DICT[vni_type], True) + + def _interface_list_to_dict(self, want, have): + """Convert all list of dicts to dicts of dicts""" + + wantd = {entry["interface"]: entry for entry in want} + haved = {entry["interface"]: entry for entry in have} + + for each in wantd, haved: + if each: + for nvi, nvid in each.items(): + member_vni = nvid.get("member", {}).get("vni") + if member_vni: + for vni_type in member_vni: + member_vni[vni_type] = param_list_to_dict( + member_vni[vni_type], + unique_key="vni", + remove_key=False, + ) + + return wantd, haved + + def _remove_existing_vnis_vrfs(self, want_vrf, haved): + """Remove member VNIs of corresponding VRF""" + + vrf_haved = next( + (h for h in haved.values() if h["vrf"] == want_vrf), + None, + ) + if vrf_haved: + self.addcmd(haved.pop(vrf_haved["vni"]), "vrf", True) + return haved + + def _filtered_dict(self, want, have): + """Remove other config from 'have' if 'member' key is present""" + + if "member" in want: + have_member = {} + want_vni_dict = want.get("member", {}).get("vni", {}) + have_vni_dict = have.get("member", {}).get("vni", {}) + + for vni_type, have_vnis in have_vni_dict.items(): + want_vnis = want_vni_dict.get(vni_type, {}) + have_member[vni_type] = { + vni: have_vni_dict[vni_type].get(vni) for vni in have_vnis if vni in want_vnis + } + have = { + "interface": have["interface"], + "member": {"vni": have_member}, + } + + return have diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acls/acls.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acls/acls.py index 6037d99e1..2be369a7a 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acls/acls.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acls/acls.py @@ -17,6 +17,7 @@ __metaclass__ = type import re +from ansible.module_utils._text import to_text from ansible.module_utils.six import iteritems from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( @@ -34,28 +35,49 @@ from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates class AclsFacts(object): """The ios_acls fact class""" - def __init__(self, module, subspec="config", options="options"): + def __init__(self, module): self._module = module self.argument_spec = AclsArgs.argument_spec def get_acl_data(self, connection): - # Get the access-lists from the ios router - # Get the remarks on access-lists from the ios router - # alternate command 'sh run partition access-list' but has a lot of ordering issues - # and incomplete ACLs are not viewed correctly - _acl_data = connection.get("show access-list") - _remarks_data = connection.get("show running-config | include ip(v6)* access-list|remark") - if _remarks_data: - _acl_data += "\n" + _remarks_data - return _acl_data + # Removed the show access-list + # Removed the show running-config | include ip(v6)* access-list|remark + return connection.get("show running-config | section access-list") + + def get_acl_names(self, connection): + # this information is required to scoop out the access lists which has no aces + return connection.get("show access-lists | include access list") + + def populate_empty_acls(self, raw_acls, raw_acls_name): + # this would update empty acls to the full acls entry + if raw_acls and raw_acls_name: + for aclnames, acldata in raw_acls_name.get("acls").items(): + if aclnames not in raw_acls.get("acls").keys(): + if not raw_acls.get("acls"): + raw_acls["acls"] = {} + raw_acls["acls"][aclnames] = acldata + elif raw_acls_name and not raw_acls: + for aclnames, acldata in raw_acls_name.get("acls").items(): + if not raw_acls.get("acls"): + raw_acls["acls"] = {} + raw_acls["acls"][aclnames] = acldata + return raw_acls def sanitize_data(self, data): """removes matches or extra config info that is added on acl match""" re_data = "" + remarks_idx = 0 for da in data.split("\n"): if "match" in da: mod_da = re.sub(r"\([^()]*\)", "", da) re_data += mod_da[:-1] + "\n" + elif re.match(r"\s*\d+\sremark.+", da, re.IGNORECASE) or re.match( + r"\s*remark.+", + da, + re.IGNORECASE, + ): + remarks_idx += 1 + re_data += to_text(remarks_idx) + " " + da + "\n" else: re_data += da + "\n" return re_data @@ -68,21 +90,30 @@ class AclsFacts(object): :rtype: dictionary :returns: facts """ + namedata = "" if not data: data = self.get_acl_data(connection) + namedata = self.get_acl_names(connection) if data: data = self.sanitize_data(data) - rmmod = NetworkTemplate(lines=data.splitlines(), tmplt=AclsTemplate()) - current = rmmod.parse() + # parse main information + templateObjMain = NetworkTemplate(lines=data.splitlines(), tmplt=AclsTemplate()) + raw_acls = templateObjMain.parse() + + if namedata: + # parse just names to update empty acls + templateObjName = NetworkTemplate(lines=namedata.splitlines(), tmplt=AclsTemplate()) + raw_acl_names = templateObjName.parse() + raw_acls = self.populate_empty_acls(raw_acls, raw_acl_names) temp_v4 = [] temp_v6 = [] - if current.get("acls"): - for k, v in iteritems(current.get("acls")): + if raw_acls.get("acls"): + for k, v in iteritems(raw_acls.get("acls")): if v.get("afi") == "ipv4" and v.get("acl_type") in ["standard", "extended"]: del v["afi"] temp_v4.append(v) @@ -99,6 +130,14 @@ class AclsFacts(object): _temp_addr = temp.get("address", "") ace[typ]["address"] = _temp_addr.split(" ")[0] ace[typ]["wildcard_bits"] = _temp_addr.split(" ")[1] + if temp.get("ipv6_address"): + _temp_addr = temp.get("ipv6_address", "") + if len(_temp_addr.split(" ")) == 2: + ipv6_add = ace[typ].pop("ipv6_address") + ace[typ]["address"] = ipv6_add.split(" ")[0] + ace[typ]["wildcard_bits"] = ipv6_add.split(" ")[1] + else: + ace[typ]["address"] = ace[typ].pop("ipv6_address") def process_protocol_options(each): for each_ace in each.get("aces"): @@ -131,14 +170,25 @@ class AclsFacts(object): def collect_remarks(aces): """makes remarks list per ace""" ace_entry = [] - rem = [] + ace_rem = [] + rem = {} for i in aces: - if i.get("remarks"): - rem.append(i.pop("remarks")) + if i.get("is_remark_for"): + if not rem.get(i.get("is_remark_for")): + rem[i.get("is_remark_for")] = {"remarks": []} + rem[i.get("is_remark_for")]["remarks"].append(i.get("the_remark")) + else: + rem[i.get("is_remark_for")]["remarks"].append(i.get("the_remark")) else: + if rem: + if rem.get(i.get("sequence")): + ace_rem = rem.pop(i.get("sequence")) + i["remarks"] = ace_rem.get("remarks") ace_entry.append(i) - if rem: - ace_entry.append({"remarks": rem}) + + if rem: # pending remarks + pending_rem = rem.get("remark") + ace_entry.append({"remarks": pending_rem.get("remarks")}) return ace_entry for each in temp_v4: @@ -148,7 +198,7 @@ class AclsFacts(object): for each in temp_v6: if each.get("aces"): - each["aces"] = collect_remarks(each.get("aces")) + # each["aces"] = collect_remarks(each.get("aces")) process_protocol_options(each) objs = [] diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_global/bgp_global.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_global/bgp_global.py index 68ff93636..37bbfabfd 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_global/bgp_global.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_global/bgp_global.py @@ -51,7 +51,10 @@ class Bgp_globalFacts(object): data = self.get_bgp_global_data(connection) # parse native config using the Bgp_global template - bgp_global_parser = Bgp_globalTemplate(lines=data.splitlines(), module=self._module) + bgp_global_parser = Bgp_globalTemplate( + lines=data.splitlines(), + module=self._module, + ) objs = bgp_global_parser.parse() neighbor_list = objs.get("neighbors", {}) if neighbor_list: @@ -64,7 +67,11 @@ class Bgp_globalFacts(object): ansible_facts["ansible_network_resources"].pop("bgp_global", None) params = utils.remove_empties( - bgp_global_parser.validate_config(self.argument_spec, {"config": obj}, redact=True), + bgp_global_parser.validate_config( + self.argument_spec, + {"config": obj}, + redact=True, + ), ) facts["bgp_global"] = params.get("config", {}) diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/evpn_evi/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/evpn_evi/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/evpn_evi/__init__.py diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/evpn_evi/evpn_evi.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/evpn_evi/evpn_evi.py new file mode 100644 index 000000000..be6cfb3bf --- /dev/null +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/evpn_evi/evpn_evi.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- +# Copyright 2023 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The ios evpn_evi fact class +It is in this file the configuration is collected from the device +for a given resource, parsed, and the facts tree is populated +based on the configuration. +""" + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.evpn_evi.evpn_evi import ( + Evpn_eviArgs, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.evpn_evi import ( + Evpn_eviTemplate, +) + + +class Evpn_eviFacts(object): + """The ios evpn_evi facts class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = Evpn_eviArgs.argument_spec + + def get_evpn_evi_data(self, connection): + return connection.get("show running-config | section ^l2vpn evpn instance .+$") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for Evpn_evi network resource + + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + + :rtype: dictionary + :returns: facts + """ + facts = {} + objs = [] + + if not data: + data = self.get_evpn_evi_data(connection) + + # parse native config using the Evpn_evi template + evpn_evi_parser = Evpn_eviTemplate(lines=data.splitlines(), module=self._module) + objs = list(evpn_evi_parser.parse().values()) + + ansible_facts["ansible_network_resources"].pop("evpn_evi", None) + + params = utils.remove_empties( + evpn_evi_parser.validate_config(self.argument_spec, {"config": objs}, redact=True), + ) + + facts["evpn_evi"] = params.get("config", []) + ansible_facts["ansible_network_resources"].update(facts) + + return ansible_facts diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/evpn_global/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/evpn_global/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/evpn_global/__init__.py diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/evpn_global/evpn_global.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/evpn_global/evpn_global.py new file mode 100644 index 000000000..68ecfc711 --- /dev/null +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/evpn_global/evpn_global.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +# Copyright 2023 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The ios evpn_global fact class +It is in this file the configuration is collected from the device +for a given resource, parsed, and the facts tree is populated +based on the configuration. +""" + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.evpn_global.evpn_global import ( + Evpn_globalArgs, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.evpn_global import ( + Evpn_globalTemplate, +) + + +class Evpn_globalFacts(object): + """The ios evpn_global facts class""" + + def __init__(self, module): + self._module = module + self.argument_spec = Evpn_globalArgs.argument_spec + + def get_evpn_global_data(self, connection): + return connection.get("show running-config | section ^l2vpn evpn$") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for Evpn_global network resource + + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + + :rtype: dictionary + :returns: facts + """ + facts = {} + objs = [] + + if not data: + data = self.get_evpn_global_data(connection) + + # parse native config using the Evpn_global template + evpn_global_parser = Evpn_globalTemplate(lines=data.splitlines(), module=self._module) + objs = evpn_global_parser.parse() + obj = utils.remove_empties(objs) + + ansible_facts["ansible_network_resources"].pop("evpn_global", None) + + params = utils.remove_empties( + evpn_global_parser.validate_config(self.argument_spec, {"config": obj}, redact=True), + ) + + facts["evpn_global"] = params.get("config", {}) + ansible_facts["ansible_network_resources"].update(facts) + + return ansible_facts diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/facts.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/facts.py index 6a28043bf..7718b474d 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/facts.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/facts.py @@ -29,6 +29,12 @@ from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.bgp_ad from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.bgp_global.bgp_global import ( Bgp_globalFacts, ) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.evpn_evi.evpn_evi import ( + Evpn_eviFacts, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.evpn_global.evpn_global import ( + Evpn_globalFacts, +) from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.hostname.hostname import ( HostnameFacts, ) @@ -93,6 +99,9 @@ from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.static from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.vlans.vlans import ( VlansFacts, ) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.vxlan_vtep.vxlan_vtep import ( + Vxlan_vtepFacts, +) FACT_LEGACY_SUBSETS = dict(default=Default, hardware=Hardware, interfaces=Interfaces, config=Config) @@ -122,6 +131,9 @@ FACT_RESOURCE_SUBSETS = dict( service=ServiceFacts, snmp_server=Snmp_serverFacts, hostname=HostnameFacts, + vxlan_vtep=Vxlan_vtepFacts, + evpn_global=Evpn_globalFacts, + evpn_evi=Evpn_eviFacts, ) diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/legacy/base.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/legacy/base.py index de92f1ed5..5344ca627 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/legacy/base.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/legacy/base.py @@ -125,26 +125,31 @@ class Default(FactsBase): class Hardware(FactsBase): - COMMANDS = ["dir", "show memory statistics"] + COMMANDS = ["dir", "show memory statistics", "show processes cpu | include CPU utilization"] def populate(self): warnings = list() super(Hardware, self).populate() + data = self.responses[0] if data: self.facts["filesystems"] = self.parse_filesystems(data) self.facts["filesystems_info"] = self.parse_filesystems_info(data) + self.facts["cpu_utilization"] = self.parse_cpu_utilization(self.responses[2]) data = self.responses[1] if data: if "Invalid input detected" in data: warnings.append("Unable to gather memory statistics") else: - processor_line = [line for line in data.splitlines() if "Processor" in line].pop() - match = re.findall(r"\s(\d+)\s", processor_line) - if match: - self.facts["memtotal_mb"] = int(match[0]) / 1048576 - self.facts["memfree_mb"] = int(match[2]) / 1048576 + for line in data.splitlines(): + match = re.match( + r"Processor\s+(\S+|\d+)\s+(?P<total>\d+)\s+\d+\s+(?P<free>\d+)", + line, + ) + if match: + self.facts["memtotal_mb"] = int(match.group("total")) / 1048576 + self.facts["memfree_mb"] = int(match.group("free")) / 1048576 def parse_filesystems(self, data): return re.findall(r"^Directory of (\S+)/", data, re.M) @@ -164,6 +169,37 @@ class Hardware(FactsBase): facts[fs]["spacefree_kb"] = int(match.group(2)) / 1024 return facts + def parse_cpu_utilization(self, data): + facts = {} + regex_cpu_utilization = re.compile( + r""" + (^Core\s(?P<core>\d+)?:)? + (^|\s)CPU\sutilization\sfor\sfive\sseconds: + (\s(?P<f_sec>\d+)?%)? + (\s(?P<f_se_nom>\d+)%/(?P<f_s_denom>\d+)%\)?)? + ;\sone\sminute:\s(?P<a_min>\d+)?% + ;\sfive\sminutes:\s(?P<f_min>\d+)?% + """, + re.VERBOSE, + ) + for line in data.split("\n"): + match_cpu_utilization = regex_cpu_utilization.match(line) + if match_cpu_utilization: + _core = "core" + if match_cpu_utilization.group("core"): + _core = "core_" + str(match_cpu_utilization.group("core")) + facts[_core] = {} + facts[_core]["five_seconds"] = int( + match_cpu_utilization.group("f_se_nom") or match_cpu_utilization.group("f_sec"), + ) + facts[_core]["one_minute"] = int(match_cpu_utilization.group("a_min")) + facts[_core]["five_minutes"] = int(match_cpu_utilization.group("f_min")) + if match_cpu_utilization.group("f_s_denom"): + facts[_core]["five_seconds_interrupt"] = int( + match_cpu_utilization.group("f_s_denom"), + ) + return facts + class Config(FactsBase): COMMANDS = ["show running-config"] diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/logging_global/logging_global.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/logging_global/logging_global.py index 639d43dba..5e955217c 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/logging_global/logging_global.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/logging_global/logging_global.py @@ -58,17 +58,17 @@ class Logging_globalFacts(object): if objFinal: for k, v in iteritems(objFinal): - if type(v) == list and k not in ["hosts", "source_interface", "filter"]: + if isinstance(v, list) and k not in ["hosts", "source_interface", "filter"]: v.sort() objFinal[k] = v - elif type(v) == list and k == "hosts": + elif isinstance(v, list) and k == "hosts": objFinal[k] = sorted( objFinal[k], key=lambda item: item["host"] if item.get("host") else item.get("ipv6"), ) - elif type(v) == list and k == "source_interface": + elif isinstance(v, list) and k == "source_interface": objFinal[k] = sorted(objFinal[k], key=lambda item: item["interface"]) - elif type(v) == list and k == "filter": + elif isinstance(v, list) and k == "filter": objFinal[k] = sorted(objFinal[k], key=lambda item: item["url"]) ansible_facts["ansible_network_resources"].pop("logging_global", None) diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv2/ospfv2.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv2/ospfv2.py index 48a77de99..66fc35d2c 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv2/ospfv2.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv2/ospfv2.py @@ -37,6 +37,27 @@ class Ospfv2Facts(object): def get_ospfv2_data(self, connection): return connection.get("show running-config | section ^router ospf") + def dict_to_list(self, ospf_data): + """Converts areas, interfaces in each process to list + :param ospf_data: ospf data + :rtype: dictionary + :returns: facts_output + """ + + facts_output = {"processes": []} + + for process in ospf_data.get("processes", []): + if "passive_interfaces" in process and process["passive_interfaces"].get("default"): + if process.get("passive_interfaces", {}).get("interface"): + process["passive_interfaces"]["interface"]["name"] = [ + each for each in process["passive_interfaces"]["interface"]["name"] if each + ] + if "areas" in process: + process["areas"] = list(process["areas"].values()) + facts_output["processes"].append(process) + + return facts_output + def populate_facts(self, connection, ansible_facts, data=None): """Populate the facts for ospfv2 :param connection: the device connection @@ -45,42 +66,28 @@ class Ospfv2Facts(object): :rtype: dictionary :returns: facts """ + + facts = {} + if not data: data = self.get_ospfv2_data(connection) - ipv4 = {"processes": []} - rmmod = NetworkTemplate(lines=data.splitlines(), tmplt=Ospfv2Template()) - current = rmmod.parse() + ospf_temp_obj = NetworkTemplate(lines=data.splitlines(), tmplt=Ospfv2Template()) + ospf_parsed = ospf_temp_obj.parse() - # convert some of the dicts to lists - for key, sortv in [("processes", "process_id")]: - if key in current and current[key]: - current[key] = current[key].values() - current[key] = sorted(current[key], key=lambda k, sk=sortv: k[sk]) + # Convert dict to list + ospf_parsed["processes"] = ( + ospf_parsed["processes"].values() if "processes" in ospf_parsed else [] + ) - for process in current.get("processes", []): - if "passive_interfaces" in process and process["passive_interfaces"].get("default"): - if process["passive_interfaces"].get("interface"): - temp = [] - for each in process["passive_interfaces"]["interface"]["name"]: - if each: - temp.append(each) - process["passive_interfaces"]["interface"]["name"] = temp - if "areas" in process: - process["areas"] = list(process["areas"].values()) - process["areas"] = sorted(process["areas"], key=lambda k, sk="area_id": k[sk]) - for area in process["areas"]: - if "filters" in area: - area["filters"].sort() - ipv4["processes"].append(process) + # converts areas, interfaces in each process to list + facts_output = self.dict_to_list(ospf_parsed) ansible_facts["ansible_network_resources"].pop("ospfv2", None) - facts = {} - if current: - params = utils.validate_config(self.argument_spec, {"config": ipv4}) - params = utils.remove_empties(params) + if ospf_parsed["processes"]: + params = utils.validate_config(self.argument_spec, {"config": facts_output}) + params = utils.remove_empties(params) facts["ospfv2"] = params["config"] - ansible_facts["ansible_network_resources"].update(facts) return ansible_facts diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/prefix_lists/prefix_lists.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/prefix_lists/prefix_lists.py index 167f68c73..80a73e18c 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/prefix_lists/prefix_lists.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/prefix_lists/prefix_lists.py @@ -15,9 +15,6 @@ for a given resource, parsed, and the facts tree is populated based on the configuration. """ -from copy import copy - -from ansible.module_utils.six import iteritems from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.prefix_lists.prefix_lists import ( @@ -59,50 +56,18 @@ class Prefix_listsFacts(object): objs = prefix_lists_parser.parse() final_objs = [] - temp = {} - temp["afi"] = None - temp["prefix_lists"] = [] + + _prefix_list = {"ipv4": [], "ipv6": []} if objs: - for k, v in iteritems(objs): - temp_prefix_list = {} - temp_prefix_list["entries"] = [] - if not temp["afi"] or v["afi"] != temp["afi"]: - if temp and temp["afi"]: - temp["prefix_lists"] = sorted( - temp["prefix_lists"], - key=lambda k, sk="name": str(k[sk]), - ) - # additional check for py3.5 - if len(final_objs) == 2: - for each in final_objs: - if v["afi"] == each["afi"]: - each["prefix_lists"].extend(temp["prefix_lists"]) - else: - final_objs.append(copy(temp)) - temp["prefix_lists"] = [] - temp["afi"] = v["afi"] - for each in v["prefix_lists"]: - if not temp_prefix_list.get("name"): - temp_prefix_list["name"] = each["name"] - if not temp_prefix_list.get("description") and each.get("description"): - temp_prefix_list["description"] = each["description"] - if each["entries"] and not each["entries"].get("description"): - temp_prefix_list["entries"].append(each["entries"]) - temp["prefix_lists"].append(temp_prefix_list) - if temp and temp["afi"]: - temp["prefix_lists"] = sorted( - temp["prefix_lists"], - key=lambda k, sk="name": str(k[sk]), + for prefixes in list(objs.values()): + _afi = prefixes.pop("afi") + _prefix_list[_afi].append( + prefixes, ) - # additional check for py3.5 - if len(final_objs) == 2: - for each in final_objs: - if v["afi"] == each["afi"]: - each["prefix_lists"].extend(temp["prefix_lists"]) - else: - final_objs.append(copy(temp)) - - final_objs = sorted(final_objs, key=lambda k, sk="afi": k[sk]) + if _prefix_list.get("ipv4"): + final_objs.append({"afi": "ipv4", "prefix_lists": _prefix_list.pop("ipv4")}) + if _prefix_list.get("ipv6"): + final_objs.append({"afi": "ipv6", "prefix_lists": _prefix_list.pop("ipv6")}) ansible_facts["ansible_network_resources"].pop("prefix_lists", None) diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/snmp_server/snmp_server.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/snmp_server/snmp_server.py index 2fc1042e7..a153ac0a8 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/snmp_server/snmp_server.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/snmp_server/snmp_server.py @@ -15,6 +15,8 @@ for a given resource, parsed, and the facts tree is populated based on the configuration. """ +import re + from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.snmp_server.snmp_server import ( @@ -33,7 +35,7 @@ class Snmp_serverFacts(object): self.argument_spec = Snmp_serverArgs.argument_spec def get_snmp_data(self, connection): - _get_snmp_data = connection.get("show running-config | section ^snmp-server") + _get_snmp_data = connection.get("show running-config | section ^snmp") return _get_snmp_data def get_snmpv3_user_data(self, connection): @@ -46,7 +48,12 @@ class Snmp_serverFacts(object): Note: The seperate method is needed because the snmpv3 user data is not returned within the snmp-server config """ - _get_snmpv3_user = connection.get("show snmp user") + try: + _get_snmpv3_user = connection.get("show snmp user") + except Exception as e: + if "agent not enabled" in str(e): + return "" + raise Exception("Unable to get snmp user data: %s" % str(e)) return _get_snmpv3_user def sort_list_dicts(self, objs): @@ -87,18 +94,36 @@ class Snmp_serverFacts(object): """ user_sets = snmpv3_user.split("User ") user_list = [] + re_snmp_auth = re.compile(r"^Authentication Protocol:\s*(MD5|SHA)") + re_snmp_priv = re.compile(r"^Privacy Protocol:\s*(3DES|AES|DES)([0-9]*)") + re_snmp_acl = re.compile(r"^.*active\s+(access-list: (\S+)|)\s*(IPv6 access-list: (\S+)|)") for user_set in user_sets: one_set = {} lines = user_set.splitlines() for line in lines: if line.startswith("name"): one_set["username"] = line.split(": ")[1] + continue if line.startswith("Group-name:"): one_set["group"] = line.split(": ")[1] - if "IPv6 access-list:" in line: - one_set["acl_v6"] = line.split(": ")[-1] - if "active\taccess-list:" in line: - one_set["acl_v4"] = line.split(": ")[-1] + continue + re_match = re_snmp_auth.search(line) + if re_match: + one_set["authentication"] = {"algorithm": re_match.group(1).lower()} + continue + re_match = re_snmp_priv.search(line) + if re_match: + one_set["encryption"] = {"priv": re_match.group(1).lower()} + if re_match.group(2): + one_set["encryption"]["priv_option"] = re_match.group(2) + continue + re_match = re_snmp_acl.search(line) + if re_match: + if re_match.group(2): + one_set["acl_v4"] = re_match.group(2) + if re_match.group(4): + one_set["acl_v6"] = re_match.group(4) + continue one_set["version"] = "v3" # defaults to version 3 data if len(one_set): user_list.append(one_set) diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vlans/vlans.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vlans/vlans.py index 73f73a5a2..9b506fa90 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vlans/vlans.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vlans/vlans.py @@ -16,6 +16,8 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type +import re + from copy import deepcopy from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils @@ -42,14 +44,18 @@ class VlansFacts(object): self.generated_spec = utils.generate_dict(facts_argument_spec) - def get_vlans_data(self, connection): + def get_vlans_data(self, connection, configuration): """Checks device is L2/L3 and returns facts gracefully. Does not fail module. """ + if configuration: + cmd = "show running-config | sec ^vlan configuration .+" + else: + cmd = "show vlan" check_os_type = connection.get_device_info() if check_os_type.get("network_os_type") == "L3": return "" - return connection.get("show vlan") + return connection.get(cmd) def populate_facts(self, connection, ansible_facts, data=None): """Populate the facts for vlans @@ -59,14 +65,134 @@ class VlansFacts(object): :rtype: dictionary :returns: facts """ + configuration = self._module.params["configuration"] + objs = [] + + if not data: + data = self.get_vlans_data(connection, configuration) + if not configuration: + objs = self.parse_vlan(data) + else: + objs = self.parse_vlan_config(data) + + facts = {} + if objs: + facts["vlans"] = [] + params = utils.validate_config(self.argument_spec, {"config": objs}) + + for cfg in params["config"]: + facts["vlans"].append(utils.remove_empties(cfg)) + ansible_facts["ansible_network_resources"].update(facts) + return ansible_facts + + def render_config(self, spec, conf, vlan_info): + """ + Render config as dictionary structure and delete keys + from spec for null values + + :param spec: The facts tree, generated from the argspec + :param conf: The configuration + :rtype: dictionary + :returns: The generated config + """ + config = deepcopy(spec) + + if vlan_info == "Name" and "VLAN Name" not in conf: + conf = list(filter(None, conf.split(" "))) + config["vlan_id"] = int(conf[0]) + config["name"] = conf[1] + state_idx = 2 + for i in range(2, len(conf)): # check for index where state starts + if conf[i] in ["suspended", "active"]: + state_idx = i + break + elif conf[i].split("/")[0] in ["sus", "act"]: + state_idx = i + break + config["name"] += " " + conf[i] + try: + if len(conf[state_idx].split("/")) > 1: + _state = conf[state_idx].split("/")[0] + if _state == "sus": + config["state"] = "suspend" + elif _state == "act": + config["state"] = "active" + config["shutdown"] = "enabled" + else: + if conf[state_idx] == "suspended": + config["state"] = "suspend" + elif conf[state_idx] == "active": + config["state"] = "active" + config["shutdown"] = "disabled" + except IndexError: + pass + elif vlan_info == "Type" and "VLAN Type" not in conf: + conf = list(filter(None, conf.split(" "))) + config["mtu"] = int(conf[3]) + elif vlan_info == "Remote": + if len(conf.split(",")) > 1 or conf.isdigit(): + remote_span_vlan = [] + if len(conf.split(",")) > 1: + remote_span_vlan = conf.split(",") + else: + remote_span_vlan.append(conf) + remote_span = [] + for each in remote_span_vlan: + split_sp_list = each.split("-") + if len(split_sp_list) > 1: # break range + for r_sp in range(int(split_sp_list[0]), int(split_sp_list[1]) + 1): + remote_span.append(r_sp) + else: + remote_span.append(int(each)) + config["remote_span"] = remote_span + + elif vlan_info == "Private" and "Primary Secondary" not in conf: + conf = list(filter(None, conf.split(" "))) + + pri_idx = 0 + sec_idx = 1 + priv_type_idx = 2 + + config["tmp_pvlans"] = { + "primary": conf[pri_idx], + "secondary": conf[sec_idx], + "sec_type": conf[priv_type_idx], + } + return utils.remove_empties(config) + + def parse_vlan_config(self, vlan_conf): + vlan_list = list() + + re1 = re.compile(r"^vlan configuration +(?P<vlan>\d+)$") + re2 = re.compile(r"^member +(evpn\-instance +(?P<evi>\d+) )?vni (?P<vni>[\d\-]+)$") + + for line in vlan_conf.splitlines(): + line = line.strip() + m = re1.match(line) + if m: + vlan = m.groupdict()["vlan"] + vlan_dict = {"vlan_id": vlan} + continue + + m = re2.match(line) + if m: + group = m.groupdict() + vlan_dict.update({"member": {}}) + vlan_dict["member"].update({"vni": group["vni"]}) + if group["evi"]: + vlan_dict["member"].update({"evi": group["evi"]}) + vlan_list.append(vlan_dict) + + return vlan_list + + def parse_vlan(self, data): objs = [] mtu_objs = [] remote_objs = [] final_objs = [] pvlan_objs = [] - if not data: - data = self.get_vlans_data(connection) + # operate on a collection of resource x config = data.split("\n") # Get individual vlan configs separately @@ -124,6 +250,7 @@ class VlansFacts(object): pvlan_final = {} if len(pvlan_objs) > 0: # Sanitize and structure everything + for data in pvlan_objs: pvdata = data.get("tmp_pvlans") privlan = pvdata.get("primary") @@ -151,89 +278,7 @@ class VlansFacts(object): if vlan_id == every.get("vlan_id"): every.update(data) - facts = {} if final_objs: - facts["vlans"] = [] - params = utils.validate_config(self.argument_spec, {"config": objs}) - - for cfg in params["config"]: - facts["vlans"].append(utils.remove_empties(cfg)) - ansible_facts["ansible_network_resources"].update(facts) - - return ansible_facts - - def render_config(self, spec, conf, vlan_info): - """ - Render config as dictionary structure and delete keys - from spec for null values - - :param spec: The facts tree, generated from the argspec - :param conf: The configuration - :rtype: dictionary - :returns: The generated config - """ - config = deepcopy(spec) - - if vlan_info == "Name" and "VLAN Name" not in conf: - conf = list(filter(None, conf.split(" "))) - config["vlan_id"] = int(conf[0]) - config["name"] = conf[1] - state_idx = 2 - for i in range(2, len(conf)): # check for index where state starts - if conf[i] in ["suspended", "active"]: - state_idx = i - break - elif conf[i].split("/")[0] in ["sus", "act"]: - state_idx = i - break - config["name"] += " " + conf[i] - try: - if len(conf[state_idx].split("/")) > 1: - _state = conf[state_idx].split("/")[0] - if _state == "sus": - config["state"] = "suspend" - elif _state == "act": - config["state"] = "active" - config["shutdown"] = "enabled" - else: - if conf[state_idx] == "suspended": - config["state"] = "suspend" - elif conf[state_idx] == "active": - config["state"] = "active" - config["shutdown"] = "disabled" - except IndexError: - pass - elif vlan_info == "Type" and "VLAN Type" not in conf: - conf = list(filter(None, conf.split(" "))) - config["mtu"] = int(conf[3]) - elif vlan_info == "Remote": - if len(conf.split(",")) > 1 or conf.isdigit(): - remote_span_vlan = [] - if len(conf.split(",")) > 1: - remote_span_vlan = conf.split(",") - else: - remote_span_vlan.append(conf) - remote_span = [] - for each in remote_span_vlan: - split_sp_list = each.split("-") - if len(split_sp_list) > 1: # break range - for r_sp in range(int(split_sp_list[0]), int(split_sp_list[1]) + 1): - remote_span.append(r_sp) - else: - remote_span.append(int(each)) - config["remote_span"] = remote_span - - elif vlan_info == "Private" and "Primary Secondary" not in conf: - conf = list(filter(None, conf.split(" "))) - - pri_idx = 0 - sec_idx = 1 - priv_type_idx = 2 - - config["tmp_pvlans"] = { - "primary": conf[pri_idx], - "secondary": conf[sec_idx], - "sec_type": conf[priv_type_idx], - } - - return utils.remove_empties(config) + return objs + else: + return {} diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vxlan_vtep/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vxlan_vtep/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vxlan_vtep/__init__.py diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vxlan_vtep/vxlan_vtep.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vxlan_vtep/vxlan_vtep.py new file mode 100644 index 000000000..0027504e4 --- /dev/null +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vxlan_vtep/vxlan_vtep.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- +# Copyright 2023 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The ios vxlan_vtep fact class +It is in this file the configuration is collected from the device +for a given resource, parsed, and the facts tree is populated +based on the configuration. +""" + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils + +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.vxlan_vtep.vxlan_vtep import ( + Vxlan_vtepArgs, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.vxlan_vtep import ( + Vxlan_vtepTemplate, +) + + +class Vxlan_vtepFacts(object): + """The ios vxlan_vtep facts class""" + + def __init__(self, module): + self._module = module + self.argument_spec = Vxlan_vtepArgs.argument_spec + + def get_vxlan_vtep_data(self, connection): + return connection.get("show running-config | section ^interface nve") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for Vxlan_vtep network resource + + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + + :rtype: dictionary + :returns: facts + """ + facts = {} + objs = [] + + if not data: + data = self.get_vxlan_vtep_data(connection) + + # parse native config using the Vxlan_vtep template + vxlan_vtep_parser = Vxlan_vtepTemplate(lines=data.splitlines(), module=self._module) + objs = list(vxlan_vtep_parser.parse().values()) + + ansible_facts["ansible_network_resources"].pop("vxlan_vtep", None) + + params = utils.remove_empties( + vxlan_vtep_parser.validate_config(self.argument_spec, {"config": objs}, redact=True), + ) + + facts["vxlan_vtep"] = params.get("config", {}) + ansible_facts["ansible_network_resources"].update(facts) + + return ansible_facts diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/acls.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/acls.py index 164c93caf..b3afd65f9 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/acls.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/acls.py @@ -16,11 +16,21 @@ the given network resource. """ import re +from ansible.module_utils._text import to_text from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( NetworkTemplate, ) +def remarks_with_sequence(remarks_data): + cmd = "remark " + if remarks_data.get("remarks"): + cmd += remarks_data.get("remarks") + if remarks_data.get("sequence"): + cmd = to_text(remarks_data.get("sequence")) + " " + cmd + return cmd + + def _tmplt_access_list_entries(aces): def source_destination_common_config(config_data, command, attr): if config_data[attr].get("address"): @@ -63,7 +73,9 @@ def _tmplt_access_list_entries(aces): command += " {protocol_number}".format(**aces["protocol_options"]) else: command += " {0}".format(list(aces["protocol_options"])[0]) - proto_option = aces["protocol_options"].get(list(aces["protocol_options"])[0]) + proto_option = aces["protocol_options"].get( + list(aces["protocol_options"])[0], + ) elif aces.get("protocol"): command += " {protocol}".format(**aces) if aces.get("source"): @@ -120,7 +132,7 @@ class AclsTemplate(NetworkTemplate): PARSERS = [ { - "name": "acls_name", + "name": "only_acls_name", "getval": re.compile( r"""^(?P<acl_type>Standard|Extended|Reflexive)* \s*(?P<afi>IP|IPv6)* @@ -130,8 +142,7 @@ class AclsTemplate(NetworkTemplate): $""", re.VERBOSE, ), - "compval": "name", - "setval": "name", + "setval": "", "result": { "acls": { "{{ acl_name|d() }}": { @@ -141,80 +152,95 @@ class AclsTemplate(NetworkTemplate): }, }, }, - "shared": True, }, { - "name": "_acls_name", + "name": "acls_name", "getval": re.compile( - r"""^(ip|ipv6) + r"""^(?P<afi>ip|ipv6|mac) (\s(access-list)) - (\s(standard|extended)) - (\s(?P<acl_name_r>\S+))? + (\s(?P<acl_type>standard|extended|reflexive))? + (\s(?P<acl_name>\S+)) $""", re.VERBOSE, ), - "compval": "name", - "setval": "ip access-list", - "result": {}, + "setval": "name", + "result": { + "acls": { + "{{ acl_name|d() }}": { + "name": "{{ acl_name }}", + "acl_type": "{{ acl_type.lower() if acl_type is defined }}", + "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}", + }, + }, + }, "shared": True, }, { - "name": "_mac_acls_name", # + "name": "remarks", "getval": re.compile( - r"""^(?P<acl_type>Standard|Extended|Reflexive)* - \s*(?P<afi>MAC)* - \s*access - \s*list* - \s*(?P<acl_name>.+)* + r"""((?P<order>^\d+)) + (\s*(?P<sequence>\d+)) + (\sremark\s(?P<remarks>.+)) $""", re.VERBOSE, ), - "compval": "name", - "setval": "", + "setval": remarks_with_sequence, "result": { "acls": { "{{ acl_name|d() }}": { "name": "{{ acl_name }}", - "acl_type": "{{ acl_type.lower() if acl_type is defined }}", - "afi": "{{ afi }}", + "aces": [ + { + "the_remark": "{{ remarks }}", + "order": "{{ order }}", + "is_remark_for": "{{ sequence }}", + }, + ], }, }, }, - "shared": True, }, { - "name": "remarks", + "name": "remarks_no_data", "getval": re.compile( - r"""\s+remark - (\s(?P<remarks>.+))? - $""", + r"""(?P<order>^\d+)\s*remark\s(?P<remarks>.+)$""", re.VERBOSE, ), - "setval": "remark {{ remarks }}", + "setval": "{{ sequence }} remark", "result": { "acls": { - "{{ acl_name_r|d() }}": { - "name": "{{ acl_name_r }}", - "aces": [{"remarks": "{{ remarks }}"}], + "{{ acl_name|d() }}": { + "name": "{{ acl_name }}", + "aces": [ + { + "the_remark": "{{ remarks }}", + "order": "{{ order }}", + "is_remark_for": "remark", + }, + ], }, }, }, }, { - "name": "remarks_type_linear", + "name": "remarks_ipv6", "getval": re.compile( - r"""^(access-list) - (\s(?P<acl_name_linear>\S+))? - (\sremark\s(?P<remarks>.+))? + r"""\s*(sequence\s(?P<sequence>\d+)) + (\sremark\s(?P<remarks>.+)) $""", re.VERBOSE, ), "setval": "remark {{ remarks }}", "result": { "acls": { - "{{ acl_name_linear|d() }}": { - "name": "{{ acl_name_linear }}", - "aces": [{"remarks": "{{ remarks }}"}], + "{{ acl_name|d() }}": { + "name": "{{ acl_name }}", + "aces": [ + { + "sequence": "{{ sequence }}", + "remarks": ["{{ remarks }}"], + }, + ], }, }, }, @@ -222,12 +248,11 @@ class AclsTemplate(NetworkTemplate): { "name": "aces_ipv4_standard", "getval": re.compile( - r"""\s*(?P<sequence>\d+)* - \s(?P<grant>deny|permit)? - (\s+(?P<address>(?!ahp|eigrp|esp|gre|icmp|igmp|ipv6|ipinip|ip|nos|object-group|ospf|pcp|pim|sctp|tcp|udp)\S+|\S+,))? + r"""(\s*(?P<sequence>\d+))? + (\s(?P<grant>deny|permit)) + (\s+(?P<address>((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)))? + (\s(?P<wildcard>((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)))? (\s*(?P<any>any))? - (\swildcard\sbits\s(?P<wildcard>\S+))? - (\shost\s(?P<host>\S+))? (\s(?P<log>log))? $""", re.VERBOSE, @@ -245,7 +270,6 @@ class AclsTemplate(NetworkTemplate): "address": "{{ address }}", "wildcard_bits": "{{ wildcard }}", "any": "{{ not not any }}", - "host": "{{ host }}", }, "log": {"set": "{{ not not log }}"}, }, @@ -257,28 +281,39 @@ class AclsTemplate(NetworkTemplate): { "name": "aces", "getval": re.compile( - r"""\s*((?P<sequence>\d+))? + r"""(\s*(?P<sequence>\d+))? + (\s*sequence\s(?P<sequence_ipv6>\d+))? (\s*(?P<grant>deny|permit)) (\sevaluate\s(?P<evaluate>\S+))? (\s(?P<protocol_num>\d+))? - (\s(?P<protocol>ahp|eigrp|esp|gre|icmp|igmp|ipv6|ipinip|ip|nos|ospf|pcp|pim|sctp|tcp|udp))? + (\s*(?P<protocol>ahp|eigrp|esp|gre|icmp|igmp|ipinip|ipv6|ip|nos|ospf|pcp|pim|sctp|tcp|ip|udp))? ((\s(?P<source_any>any))| (\sobject-group\s(?P<source_obj_grp>\S+))| (\shost\s(?P<source_host>\S+))| + (\s(?P<ipv6_source_address>\S+/\d+))| (\s(?P<source_address>(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})\s\S+)))? - (\s(?P<source_port_protocol>(eq|gts|gt|lt|neq)\s(\S+|\d+)))? + (\seq\s(?P<seq>(\S+|\d+)))? + (\sgt\s(?P<sgt>(\S+|\d+)))? + (\slt\s(?P<slt>(\S+|\d+)))? + (\sneq\s(?P<sneq>(\S+|\d+)))? (\srange\s(?P<srange_start>\d+)\s(?P<srange_end>\d+))? (\s(?P<dest_any>any))? (\sobject-group\s(?P<dest_obj_grp>\S+))? (\shost\s(?P<dest_host>\S+))? + (\s(?P<ipv6_dest_address>\S+/\d+))? (\s(?P<dest_address>(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})\s\S+))? - (\s(?P<dest_port_protocol>(eq|gts|lt|neq)\s(\S+|\d+)))? + (\seq\s(?P<deq>(\S+|\d+)))? + (\sgt\s(?P<dgt>(\S+|\d+)))? + (\slt\s(?P<dlt>(\S+|\d+)))? + (\sneq\s(?P<dneq>(\S+|\d+)))? (\srange\s(?P<drange_start>\d+)\s(?P<drange_end>\d+))? (\s(?P<icmp_igmp_tcp_protocol>administratively-prohibited|alternate-address|conversion-error|dod-host-prohibited|dod-net-prohibited|echo-reply|echo|general-parameter-problem|host-isolated|host-precedence-unreachable|host-redirect|host-tos-redirect|host-tos-unreachable|host-unknown|host-unreachable|information-reply|information-request|mask-reply|mask-request|mobile-redirect|net-redirect|net-tos-redirect|net-tos-unreachable|net-unreachable|network-unknown|no-room-for-option|option-missing|packet-too-big|parameter-problem|port-unreachable|precedence-unreachable|protocol-unreachable|reassembly-timeout|redirect|router-advertisement|router-solicitation|source-quench|source-route-failed|time-exceeded|timestamp-reply|timestamp-request|traceroute|ttl-exceeded|unreachable|dvmrp|host-query|mtrace-resp|mtrace-route|pim|trace|v1host-report|v2host-report|v2leave-group|v3host-report|ack|established|fin|psh|rst|syn|urg))? (\sdscp\s(?P<dscp>\S+))? (\s(?P<enable_fragments>fragments))? - (\s(?P<log_input>log-input\s\(tag\s=\s\S+\)|log-input))? - (\s(?P<log>log\s\(tag\s=\s\S+\)|log))? + (\slog-input\s\(tag\s=\s(?P<log_input>\S+\)|log-input))? + (\s(?P<log_input_only>log-input))? + (\slog\s\(tag\s=\s(?P<log>\S+\)|log))? + (\s(?P<log_only>log))? (\soption\s(?P<option>\S+|\d+))? (\sprecedence\s(?P<precedence>\S+))? (\stime-range\s(?P<time_range>\S+))? @@ -287,7 +322,6 @@ class AclsTemplate(NetworkTemplate): (\sttl\sgt\s(?P<ttl_gt>\d+))? (\sttl\slt\s(?P<ttl_lt>\d+))? (\sttl\sneg\s(?P<ttl_neg>\d+))? - (\ssequence\s(?P<sequence_ipv6>\d+))? """, re.VERBOSE, ), @@ -308,12 +342,15 @@ class AclsTemplate(NetworkTemplate): "icmp_igmp_tcp_protocol": "{{ icmp_igmp_tcp_protocol }}", "source": { "address": "{{ source_address }}", + "ipv6_address": "{{ ipv6_source_address }}", "any": "{{ not not source_any }}", "host": "{{ source_host }}", "object_group": "{{ source_obj_grp }}", "port_protocol": { - "{{ source_port_protocol.split(' ')[0] if source_port_protocol is defined else None }}": "{{\ - source_port_protocol.split(' ')[1] if source_port_protocol is defined else None }}", + "eq": "{{ seq }}", + "gt": "{{ sgt }}", + "lt": "{{ slt }}", + "neq": "{{ sneq }}", "range": { "start": "{{ srange_start if srange_start is defined else None }}", "end": "{{ srange_end if srange_end is defined else None }}", @@ -322,12 +359,15 @@ class AclsTemplate(NetworkTemplate): }, "destination": { "address": "{{ dest_address }}", + "ipv6_address": "{{ ipv6_dest_address }}", "any": "{{ not not dest_any }}", "host": "{{ dest_host }}", "object_group": "{{ dest_obj_grp }}", "port_protocol": { - "{{ dest_port_protocol.split(' ')[0] if dest_port_protocol is defined else None }}": "{{\ - dest_port_protocol.split(' ')[1] if dest_port_protocol is defined else None }}", + "eq": "{{ deq }}", + "gt": "{{ dgt }}", + "lt": "{{ dlt }}", + "neq": "{{ dneq }}", "range": { "start": "{{ drange_start if drange_start is defined else None }}", "end": "{{ drange_end if drange_end is defined else None }}", @@ -337,12 +377,12 @@ class AclsTemplate(NetworkTemplate): "dscp": "{{ dscp }}", "enable_fragments": "{{ True if enable_fragments is defined else None }}", "log": { - "set": "{{ True if log is defined and 'tag' not in log else '' }}", - "user_cookie": "{{ log.split(' ')[-1].split(')')[0] if log is defined and 'tag' in log else '' }}", + "set": "{{ True if log_only is defined or log is defined }}", + "user_cookie": "{{ log.split(')')[0] if log is defined }}", }, "log_input": { - "set": "{{ True if log_input is defined and 'tag' not in log_input else '' }}", - "user_cookie": "{{ log_input.split(' ')[-1].split(')')[0] if log_input is defined and 'tag' in log_input }}", + "set": "{{ True if log_input_only is defined or log_input is defined }}", + "user_cookie": "{{ log_input.split(')')[0] if log_input is defined }}", }, "option": { "{{ option if option is defined else None }}": "{{ True if option is defined else None }}", diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/bgp_address_family.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/bgp_address_family.py index b9654956c..ca85440b2 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/bgp_address_family.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/bgp_address_family.py @@ -1145,7 +1145,7 @@ class Bgp_address_familyTemplate(NetworkTemplate): re.VERBOSE, ), "setval": "neighbor {{ neighbor_address }} filter-list" - "{{ (' ' + filter_list.as_path_acl) if filter_list.as_path_acl is defined else '' }}" + "{{ (' ' + filter_list.as_path_acl|string) if filter_list.as_path_acl is defined else '' }}" "{{ (' in') if filter_list.in|d(False) else '' }}" "{{ (' out') if filter_list.out|d(False) else '' }}", "result": { @@ -1251,12 +1251,12 @@ class Bgp_address_familyTemplate(NetworkTemplate): "name": "inherit", "getval": re.compile( r""" - \s\sneighbor\s(?P<neighbor_address>\S+)\sinherit\speer-session + \s\sneighbor\s(?P<neighbor_address>\S+)\sinherit\speer-policy \s(?P<inherit>\S+) $""", re.VERBOSE, ), - "setval": "neighbor {{ neighbor_address }} inherit peer-session" + "setval": "neighbor {{ neighbor_address }} inherit peer-policy" "{{ (' ' + inherit) if inherit is defined else '' }}", "result": { "address_family": { @@ -2670,4 +2670,26 @@ class Bgp_address_familyTemplate(NetworkTemplate): }, }, # redistribute ends + { + "name": "advertise", + "getval": re.compile( + r""" + \s\sadvertise\s(?P<ad_afi>l2vpn) + (\s(?P<ad_safi>evpn))? + $""", + re.VERBOSE, + ), + "setval": "advertise {{ advertise.afi }}" + "{{ (' ' + advertise.safi ) if advertise.safi is defined else '' }}", + "result": { + "address_family": { + UNIQUE_AFI: { + "advertise": { + "afi": "{{ ad_afi }}", + "safi": "{{ ad_safi }}", + }, + }, + }, + }, + }, ] diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/bgp_global.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/bgp_global.py index 477cbc679..39fd548bc 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/bgp_global.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/bgp_global.py @@ -160,7 +160,9 @@ class Bgp_globalTemplate(NetworkTemplate): "{{ bmp.server_options.address.host }} port-number {{ bmp.server_options.address.port|string }}\nexit-bmp-server-mode", "result": { "bmp": { - "server_options": {"address": {"host": "{{ host }}", "port": "{{ port }}"}}, + "server_options": { + "address": {"host": "{{ host }}", "port": "{{ port }}"}, + }, }, }, }, @@ -449,7 +451,10 @@ class Bgp_globalTemplate(NetworkTemplate): }, { "name": "synchronization", - "getval": re.compile(r"""\s(?P<synchronization>synchronization)""", re.VERBOSE), + "getval": re.compile( + r"""\s(?P<synchronization>synchronization)""", + re.VERBOSE, + ), "setval": "synchronization", "result": {"synchronization": "{{ not not synchronization }}"}, }, @@ -466,7 +471,9 @@ class Bgp_globalTemplate(NetworkTemplate): "setval": "table-map" "{{ (' ' + name) if name is defined else '' }}" "{{ (' filter' ) if filter|d(False) else '' }}", - "result": {"table_map": {"name": "{{ name }}", "filter": "{{ not not filter }}"}}, + "result": { + "table_map": {"name": "{{ name }}", "filter": "{{ not not filter }}"}, + }, }, { "name": "timers", @@ -558,19 +565,28 @@ class Bgp_globalTemplate(NetworkTemplate): }, { "name": "bgp.bestpath_options.compare_routerid", - "getval": re.compile(r"""\s(bgp\sbestpath\scompare-routerid)""", re.VERBOSE), + "getval": re.compile( + r"""\s(bgp\sbestpath\scompare-routerid)""", + re.VERBOSE, + ), "setval": "{{ ('bgp bestpath compare-routerid' ) if bgp.bestpath_options.compare_routerid|d(False) else '' }}", "result": {"bgp": {"bestpath_options": {"compare_routerid": True}}}, }, { "name": "bgp.bestpath_options.cost_community", - "getval": re.compile(r"""\s(bgp\sbestpath\scost-community\signore)""", re.VERBOSE), + "getval": re.compile( + r"""\s(bgp\sbestpath\scost-community\signore)""", + re.VERBOSE, + ), "setval": "{{ ('bgp bestpath cost-community ignore' ) if bgp.bestpath_options.cost_community|d(False) else '' }}", "result": {"bgp": {"bestpath_options": {"cost_community": True}}}, }, { "name": "bgp.bestpath_options.igp_metric", - "getval": re.compile(r"""\s(bgp\sbestpath\sigp-metric\signore)""", re.VERBOSE), + "getval": re.compile( + r"""\s(bgp\sbestpath\sigp-metric\signore)""", + re.VERBOSE, + ), "setval": "bgp bestpath igp-metric ignore", "result": {"bgp": {"bestpath_options": {"igp_metric": True}}}, }, @@ -790,7 +806,9 @@ class Bgp_globalTemplate(NetworkTemplate): re.VERBOSE, ), "setval": "bgp graceful-restart restart-time {{ bgp.graceful_restart.restart_time|string }}", - "result": {"bgp": {"graceful_restart": {"restart_time": "{{ restart_time }}"}}}, + "result": { + "bgp": {"graceful_restart": {"restart_time": "{{ restart_time }}"}}, + }, }, { "name": "bgp.graceful_restart.stalepath_time", @@ -802,7 +820,9 @@ class Bgp_globalTemplate(NetworkTemplate): re.VERBOSE, ), "setval": "bgp graceful-restart stalepath-time {{ bgp.graceful_restart.stalepath_time|string }}", - "result": {"bgp": {"graceful_restart": {"stalepath_time": "{{ stalepath_time }}"}}}, + "result": { + "bgp": {"graceful_restart": {"stalepath_time": "{{ stalepath_time }}"}}, + }, }, { "name": "bgp.graceful_shutdown.neighbors", @@ -824,7 +844,10 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "bgp": { "graceful_shutdown": { - "neighbors": {"time": "{{ time }}", "activate": "{{ not not activate }}"}, + "neighbors": { + "time": "{{ time }}", + "activate": "{{ not not activate }}", + }, "community": "{{ community }}", "local_preference": "{{ local_preference }}", }, @@ -851,7 +874,10 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "bgp": { "graceful_shutdown": { - "vrfs": {"time": "{{ time }}", "activate": "{{ not not activate }}"}, + "vrfs": { + "time": "{{ time }}", + "activate": "{{ not not activate }}", + }, "community": "{{ community }}", "local_preference": "{{ local_preference }}", }, @@ -1008,7 +1034,9 @@ class Bgp_globalTemplate(NetworkTemplate): re.VERBOSE, ), "setval": "bgp nopeerup-delay cold-boot {{ bgp.nopeerup_delay_options.cold_boot|string }}", - "result": {"bgp": {"nopeerup_delay_options": {"cold_boot": "{{ cold_boot }}"}}}, + "result": { + "bgp": {"nopeerup_delay_options": {"cold_boot": "{{ cold_boot }}"}}, + }, }, { "name": "bgp.nopeerup_delay_options.post_boot", @@ -1020,7 +1048,9 @@ class Bgp_globalTemplate(NetworkTemplate): re.VERBOSE, ), "setval": "bgp nopeerup-delay post-boot {{ bgp.nopeerup_delay_options.post_boot|string }}", - "result": {"bgp": {"nopeerup_delay_options": {"post_boot": "{{ post_boot }}"}}}, + "result": { + "bgp": {"nopeerup_delay_options": {"post_boot": "{{ post_boot }}"}}, + }, }, { "name": "bgp.nopeerup_delay_options.nsf_switchover", @@ -1033,7 +1063,9 @@ class Bgp_globalTemplate(NetworkTemplate): ), "setval": "bgp nopeerup-delay nsf-switchover {{ bgp.nopeerup_delay_options.nsf_switchover|string }}", "result": { - "bgp": {"nopeerup_delay_options": {"nsf_switchover": "{{ nsf_switchover }}"}}, + "bgp": { + "nopeerup_delay_options": {"nsf_switchover": "{{ nsf_switchover }}"}, + }, }, }, { @@ -1047,7 +1079,9 @@ class Bgp_globalTemplate(NetworkTemplate): ), "setval": "bgp nopeerup-delay user-initiated {{ bgp.nopeerup_delay_options.user_initiated|string }}", "result": { - "bgp": {"nopeerup_delay_options": {"user_initiated": "{{ user_initiated }}"}}, + "bgp": { + "nopeerup_delay_options": {"user_initiated": "{{ user_initiated }}"}, + }, }, }, { @@ -1165,7 +1199,9 @@ class Bgp_globalTemplate(NetworkTemplate): re.VERBOSE, ), "setval": "bgp slow-peer detection threshold {{ bgp.slow_peer.detection.threshold|string }}", - "result": {"bgp": {"slow_peer": {"detection": {"threshold": "{{ threshold }}"}}}}, + "result": { + "bgp": {"slow_peer": {"detection": {"threshold": "{{ threshold }}"}}}, + }, }, { "name": "bgp.slow_peer.split_update_group", @@ -1356,7 +1392,10 @@ class Bgp_globalTemplate(NetworkTemplate): "setval": "neighbor {{ neighbor_address }} bmp-activate", "result": { "neighbors": { - "{{ neighbor_address }}": {"bmp_activate": "{{ not not bmp_activate }}"}, + "{{ neighbor_address }}": { + "bmp_activate": "{{ not not bmp_activate }}", + "neighbor_address": "{{ neighbor_address }}", + }, }, }, }, @@ -1371,7 +1410,12 @@ class Bgp_globalTemplate(NetworkTemplate): ), "setval": "neighbor {{ neighbor_address }} cluster-id", "result": { - "neighbors": {"{{ neighbor_address }}": {"cluster_id": "{{ not not cluster_id }}"}}, + "neighbors": { + "{{ neighbor_address }}": { + "cluster_id": "{{ not not cluster_id }}", + "neighbor_address": "{{ neighbor_address }}", + }, + }, }, }, { @@ -1408,6 +1452,7 @@ class Bgp_globalTemplate(NetworkTemplate): "neighbors": { "{{ neighbor_address }}": { "disable_connected_check": "{{ not not disable_connected_check }}", + "neighbor_address": "{{ neighbor_address }}", }, }, }, @@ -1431,6 +1476,7 @@ class Bgp_globalTemplate(NetworkTemplate): "enable": "{{ not not enable }}", "hop_count": "{{ hop_count }}", }, + "neighbor_address": "{{ neighbor_address }}", }, }, }, @@ -1460,6 +1506,7 @@ class Bgp_globalTemplate(NetworkTemplate): "single_hop": "{{ not not single_hop }}", }, }, + "neighbor_address": "{{ neighbor_address }}", }, }, }, @@ -1477,7 +1524,10 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { - "fall_over": {"route_map": "{{ not not route_map }}"}, + "fall_over": { + "route_map": "{{ not not route_map }}", + "neighbor_address": "{{ neighbor_address }}", + }, }, }, }, @@ -1498,7 +1548,11 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { - "ha_mode": {"set": "{{ not not set }}", "disable": "{{ not not disable }}"}, + "ha_mode": { + "set": "{{ not not set }}", + "disable": "{{ not not disable }}", + }, + "neighbor_address": "{{ neighbor_address }}", }, }, }, @@ -1514,7 +1568,14 @@ class Bgp_globalTemplate(NetworkTemplate): ), "setval": "neighbor {{ neighbor_address }} inherit peer-session" "{{ (' ' + inherit) if inherit is defined else '' }}", - "result": {"neighbors": {"{{ neighbor_address }}": {"inherit": "{{ inherit }}"}}}, + "result": { + "neighbors": { + "{{ neighbor_address }}": { + "inherit": "{{ inherit }}", + "neighbor_address": "{{ neighbor_address }}", + }, + }, + }, }, { "name": "local_as", @@ -1536,6 +1597,7 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", "local_as": { "set": "{{ not not local_as }}", "number": "{{ number }}", @@ -1618,6 +1680,7 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", "path_attribute": { "discard": { "type": "{{ type }}", @@ -1648,6 +1711,7 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", "path_attribute": { "treat_as_withdraw": { "type": "{{ type }}", @@ -1678,6 +1742,7 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", "shutdown": { "set": True, "graceful": "{{ graceful }}", @@ -1698,7 +1763,14 @@ class Bgp_globalTemplate(NetworkTemplate): ), "setval": "neighbor {{ neighbor_address }}" "{{ (' soft-reconfiguration inbound') if soft_reconfiguration|d(False) else '' }}", - "result": {"neighbors": {"{{ neighbor_address }}": {"soft_reconfiguration": True}}}, + "result": { + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "soft_reconfiguration": True, + }, + }, + }, }, { "name": "ntimers", @@ -1718,6 +1790,7 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", "timers": { "interval": "{{ interval }}", "holdtime": "{{ holdtime }}", @@ -1743,6 +1816,7 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", "transport": { "connection_mode": { "active": "{{ not not active }}", @@ -1786,8 +1860,12 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", "transport": { - "path_mtu_discovery": {"set": True, "disable": "{{ not not disable }}"}, + "path_mtu_discovery": { + "set": True, + "disable": "{{ not not disable }}", + }, }, }, }, @@ -1805,7 +1883,12 @@ class Bgp_globalTemplate(NetworkTemplate): "setval": "neighbor {{ neighbor_address }} ttl-security" "{{ (' hops '+ ttl_security|string) if ttl_security is defined else '' }}", "result": { - "neighbors": {"{{ neighbor_address }}": {"ttl_security": "{{ ttl_security }}"}}, + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "ttl_security": "{{ ttl_security }}", + }, + }, }, }, { @@ -1820,7 +1903,12 @@ class Bgp_globalTemplate(NetworkTemplate): "setval": "neighbor {{ neighbor_address }} unsuppress-map" "{{ (' ' + unsuppress_map) if unsuppress_map is defined else '' }}", "result": { - "neighbors": {"{{ neighbor_address }}": {"unsuppress_map": "{{ unsuppress_map }}"}}, + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "unsuppress_map": "{{ unsuppress_map }}", + }, + }, }, }, { @@ -1874,7 +1962,14 @@ class Bgp_globalTemplate(NetworkTemplate): ), "setval": "neighbor {{ neighbor_address }} weight" "{{ (' ' + weight|string) if weight is defined else '' }}", - "result": {"neighbors": {"{{ neighbor_address }}": {"weight": "{{ weight }}"}}}, + "result": { + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "weight": "{{ weight }}", + }, + }, + }, }, # neighbor remote-as ends # neighbor peer-group starts @@ -1915,6 +2010,7 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", "additional_paths": { "disable": "{{ not not disable }}", "receive": "{{ not not receive }}", @@ -1942,6 +2038,7 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", "advertise": { "additional_paths": { "all": "{{ not not all }}", @@ -1964,7 +2061,12 @@ class Bgp_globalTemplate(NetworkTemplate): "setval": "neighbor {{ neighbor_address }}" "{{ (' advertise best-external') if advertise.best_external|d(False) else '' }}", "result": { - "neighbors": {"{{ neighbor_address }}": {"advertise": {"best-external": True}}}, + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "advertise": {"best-external": True}, + }, + }, }, }, { @@ -1983,6 +2085,7 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", "advertise": { "diverse_path": { "backup": "{{ not not backup }}", @@ -2011,6 +2114,7 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", "advertise_map": { "name": "{{ name }}", "exist_map": "{{ exist_map }}", @@ -2034,6 +2138,7 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", "advertisement_interval": "{{ advertisement_interval }}", }, }, @@ -2048,7 +2153,14 @@ class Bgp_globalTemplate(NetworkTemplate): re.VERBOSE, ), "setval": "{{ ('neighbor ' + neighbor_address + ' aigp') if aigp.enable|d(False) else '' }}", - "result": {"neighbors": {"{{ neighbor_address }}": {"aigp": {"enable": True}}}}, + "result": { + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "aigp": {"enable": True}, + }, + }, + }, }, { "name": "aigp.send.cost_community", @@ -2070,6 +2182,7 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", "aigp": { "send": { "cost_community": { @@ -2096,7 +2209,14 @@ class Bgp_globalTemplate(NetworkTemplate): ), "setval": "neighbor {{ neighbor_address }}" "{{ (' aigp send med') if aigp.send.med|d(False) else '' }}", - "result": {"neighbors": {"{{ neighbor_address }}": {"aigp": {"send": {"med": True}}}}}, + "result": { + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "aigp": {"send": {"med": True}}, + }, + }, + }, }, { "name": "allow_policy", @@ -2107,7 +2227,14 @@ class Bgp_globalTemplate(NetworkTemplate): re.VERBOSE, ), "setval": "{{ ('neighbor ' + neighbor_address + ' allow-policy') if allow_policy|d(False) else '' }}", - "result": {"neighbors": {"{{ neighbor_address }}": {"allow_policy": True}}}, + "result": { + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "allow_policy": True, + }, + }, + }, }, { "name": "allowas_in", @@ -2120,7 +2247,14 @@ class Bgp_globalTemplate(NetworkTemplate): ), "setval": "neighbor {{ neighbor_address }}" "{{ (' allowas-in ' + allowas_in|string) if allowas_in is defined else '' }}", - "result": {"neighbors": {"{{ neighbor_address }}": {"allowas_in": "{{ allowas_in }}"}}}, + "result": { + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "allowas_in": "{{ allowas_in }}", + }, + }, + }, }, { "name": "as_override", @@ -2132,7 +2266,14 @@ class Bgp_globalTemplate(NetworkTemplate): ), "setval": "neighbor {{ neighbor_address }}" "{{ (' as-override') if as_override|d(False) else '' }}", - "result": {"neighbors": {"{{ neighbor_address }}": {"as_override": True}}}, + "result": { + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "as_override": True, + }, + }, + }, }, { "name": "bmp_activate", @@ -2151,7 +2292,10 @@ class Bgp_globalTemplate(NetworkTemplate): "neighbors": { "{{ neighbor_address }}": { "neighbor_address": "{{ neighbor_address }}", - "bmp_activate": {"server": "{{ server }}", "all": "{{ not not all }}"}, + "bmp_activate": { + "server": "{{ server }}", + "all": "{{ not not all }}", + }, }, }, }, @@ -2174,6 +2318,7 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", "capability": { "both": "{{ not not both }}", "receive": "{{ not not receive }}", @@ -2193,7 +2338,12 @@ class Bgp_globalTemplate(NetworkTemplate): ), "setval": "{{ ('neighbor ' + neighbor_address + ' default-originate') if default_originate.set|d(False) else '' }}", "result": { - "neighbors": {"{{ neighbor_address }}": {"default_originate": {"set": True}}}, + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "default_originate": {"set": True}, + }, + }, }, }, { @@ -2210,6 +2360,7 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", "default-originate": {"route_map": "{{ route_map }}"}, }, }, @@ -2233,6 +2384,7 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", "distribute_list": { "acl": "{{ acl }}", "in": "{{ not not in }}", @@ -2251,7 +2403,14 @@ class Bgp_globalTemplate(NetworkTemplate): re.VERBOSE, ), "setval": "{{ ('neighbor ' + neighbor_address + ' dmzlink-bw') if dmzlink_bw|d(False) else '' }}", - "result": {"neighbors": {"{{ neighbor_address }}": {"dmzlink_bw": True}}}, + "result": { + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "dmzlink_bw": True, + }, + }, + }, }, { "name": "filter_list", @@ -2271,6 +2430,7 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", "filter_list": { "path_acl": "{{ acl }}", "in": "{{ not not in }}", @@ -2300,6 +2460,7 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", "maximum_prefix": { "max_no": "{{ max_no }}", "threshold_val": "{{ threshold_val }}", @@ -2319,7 +2480,14 @@ class Bgp_globalTemplate(NetworkTemplate): re.VERBOSE, ), "setval": "{{ ('neighbor ' + neighbor_address + ' next-hop-self') if next_hop_self.set|d(False) else '' }}", - "result": {"neighbors": {"{{ neighbor_address }}": {"next_hop_self": {"set": True}}}}, + "result": { + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "next_hop_self": {"set": True}, + }, + }, + }, }, { "name": "next_hop_self.all", @@ -2330,7 +2498,14 @@ class Bgp_globalTemplate(NetworkTemplate): re.VERBOSE, ), "setval": "{{ ('neighbor ' + neighbor_address + ' next-hop-self all') if next_hop_self.all|d(False) else '' }}", - "result": {"neighbors": {"{{ neighbor_address }}": {"next_hop_self": {"all": True}}}}, + "result": { + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "next_hop_self": {"all": True}, + }, + }, + }, }, { "name": "next_hop_unchanged.set", @@ -2342,7 +2517,12 @@ class Bgp_globalTemplate(NetworkTemplate): ), "setval": "{{ ('neighbor ' + neighbor_address + ' next-hop-unchanged') if next_hop_unchanged.set|d(False) else ''}}", "result": { - "neighbors": {"{{ neighbor_address }}": {"next_hop_unchanged": {"set": True}}}, + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "next_hop_unchanged": {"set": True}, + }, + }, }, }, { @@ -2355,7 +2535,12 @@ class Bgp_globalTemplate(NetworkTemplate): ), "setval": "{{ ('neighbor ' + neighbor_address + ' next-hop-unchanged allpaths') if next_hop_unchanged.allpaths|d(False) else ''}}", "result": { - "neighbors": {"{{ neighbor_address }}": {"next_hop_unchanged": {"allpaths": True}}}, + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "next_hop_unchanged": {"allpaths": True}, + }, + }, }, }, { @@ -2368,7 +2553,12 @@ class Bgp_globalTemplate(NetworkTemplate): ), "setval": "{{ ('neighbor ' + neighbor_address + ' remove-private-as') if remove_private_as.set|d(False) else '' }}", "result": { - "neighbors": {"{{ neighbor_address }}": {"remove_private_as": {"set": True}}}, + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "remove_private_as": {"set": True}, + }, + }, }, }, { @@ -2381,7 +2571,12 @@ class Bgp_globalTemplate(NetworkTemplate): ), "setval": "{{ ('neighbor ' + neighbor_address + ' remove-private-as all') if remove_private_as.all|d(False) else '' }}", "result": { - "neighbors": {"{{ neighbor_address }}": {"remove_private_as": {"all": True}}}, + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "remove_private_as": {"all": True}, + }, + }, }, }, { @@ -2395,7 +2590,12 @@ class Bgp_globalTemplate(NetworkTemplate): "setval": "{{ ('neighbor ' + neighbor_address + ' remove-private-as replace-as') if remove_private_as.replace_as|d(False) else ''}}", "result": { "neighbors": { - "{{ neighbor_address }}": {"remove_private_as": {"replace_as": True}}, + "{{ neighbor_address }}": { + "remove_private_as": { + "neighbor_address": "{{ neighbor_address }}", + "replace_as": True, + }, + }, }, }, }, @@ -2456,7 +2656,12 @@ class Bgp_globalTemplate(NetworkTemplate): ), "setval": "{{ ('neighbor ' + neighbor_address + ' route-server-client') if route_server_client.set|d(False) else '' }}", "result": { - "neighbors": {"{{ neighbor_address }}": {"route_server_client": {"set": True}}}, + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "route_server_client": {"set": True}, + }, + }, }, }, { @@ -2472,7 +2677,10 @@ class Bgp_globalTemplate(NetworkTemplate): "{{ (' context ' + route_server_client.context) if route_server_client.context is defined else '' }}", "result": { "neighbors": { - "{{ neighbor_address }}": {"route_server_client": {"context": "{{ context }}"}}, + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "route_server_client": {"context": "{{ context }}"}, + }, }, }, }, @@ -2485,7 +2693,14 @@ class Bgp_globalTemplate(NetworkTemplate): re.VERBOSE, ), "setval": "{{ ('neighbor ' + neighbor_address + ' send-community') if send_community.set|d(False) else '' }}", - "result": {"neighbors": {"{{ neighbor_address }}": {"send_community": {"set": True}}}}, + "result": { + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "send_community": {"set": True}, + }, + }, + }, }, { "name": "send_community.both", @@ -2497,7 +2712,14 @@ class Bgp_globalTemplate(NetworkTemplate): ), "setval": "neighbor {{ neighbor_address }} send-community" "{{ (' both') if send_community.both|d(False) else '' }}", - "result": {"neighbors": {"{{ neighbor_address }}": {"send_community": {"both": True}}}}, + "result": { + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "send_community": {"both": True}, + }, + }, + }, }, { "name": "send_community.extended", @@ -2510,7 +2732,12 @@ class Bgp_globalTemplate(NetworkTemplate): "setval": "neighbor {{ neighbor_address }} send-community" "{{ (' extended') if send_community.extended|d(False) else '' }}", "result": { - "neighbors": {"{{ neighbor_address }}": {"send_community": {"extended": True}}}, + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "send_community": {"extended": True}, + }, + }, }, }, { @@ -2524,7 +2751,12 @@ class Bgp_globalTemplate(NetworkTemplate): "setval": "neighbor {{ neighbor_address }} send-community" "{{ (' standard') if send_community.standard|d(False) else '' }}", "result": { - "neighbors": {"{{ neighbor_address }}": {"send_community": {"standard": True}}}, + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "send_community": {"standard": True}, + }, + }, }, }, { @@ -2536,7 +2768,14 @@ class Bgp_globalTemplate(NetworkTemplate): re.VERBOSE, ), "setval": "{{ ('neighbor ' + neighbor_address + ' send-label') if send_label.set|d(False) else '' }}", - "result": {"neighbors": {"{{ neighbor_address }}": {"send_label": {"set": True}}}}, + "result": { + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "send_label": {"set": True}, + }, + }, + }, }, { "name": "send_label.explicit_null", @@ -2549,7 +2788,12 @@ class Bgp_globalTemplate(NetworkTemplate): "setval": "neighbor {{ neighbor_address }} send-label" "{{ (' explicit-null') if send_label.explicit_null|d(False) else '' }}", "result": { - "neighbors": {"{{ neighbor_address }}": {"send_label": {"explicit_null": True}}}, + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "send_label": {"explicit_null": True}, + }, + }, }, }, { @@ -2570,6 +2814,7 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", "slow_peer": { "detection": { "enable": "{{ not not enable }}", @@ -2601,6 +2846,7 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", "slow_peer": { "split_update_group": { "static": "{{ not not static }}", @@ -2625,7 +2871,12 @@ class Bgp_globalTemplate(NetworkTemplate): ), "setval": "{{ ('neighbor ' + neighbor_address + ' translate_update') if translate_update.set|d(False) else '' }}", "result": { - "neighbors": {"{{ neighbor_address }}": {"translate_update": {"set": True}}}, + "neighbors": { + "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", + "translate_update": {"set": True}, + }, + }, }, }, { @@ -2644,6 +2895,7 @@ class Bgp_globalTemplate(NetworkTemplate): "result": { "neighbors": { "{{ neighbor_address }}": { + "neighbor_address": "{{ neighbor_address }}", "translate_update": { "nlri": { "multicast": "{{ not not multicast }}", @@ -2806,7 +3058,12 @@ class Bgp_globalTemplate(NetworkTemplate): "remval": "redistribute iso-igrp {{ iso_igrp.area_tag }}", "result": { "redistribute": [ - {"iso_igrp": {"area_tag": "{{ name }}", "route_map": "{{ route_map }}"}}, + { + "iso_igrp": { + "area_tag": "{{ name }}", + "route_map": "{{ route_map }}", + }, + }, ], }, }, @@ -3049,7 +3306,9 @@ class Bgp_globalTemplate(NetworkTemplate): "{{ (' global') if vrf.global|d(False) else '' }}", "remval": "redistribute vrf {{ vrf.name }}", "result": { - "redistribute": [{"vrf": {"name": "{{ name }}", "global": "{{ not not global }}"}}], + "redistribute": [ + {"vrf": {"name": "{{ name }}", "global": "{{ not not global }}"}}, + ], }, }, # redistribute ends diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/evpn_evi.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/evpn_evi.py new file mode 100644 index 000000000..e58445ba3 --- /dev/null +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/evpn_evi.py @@ -0,0 +1,121 @@ +# -*- coding: utf-8 -*- +# Copyright 2023 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The Evpn_evi parser templates file. This contains +a list of parser definitions and associated functions that +facilitates both facts gathering and native command generation for +the given network resource. +""" + +import re + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( + NetworkTemplate, +) + + +class Evpn_eviTemplate(NetworkTemplate): + def __init__(self, lines=None, module=None): + super(Evpn_eviTemplate, self).__init__(lines=lines, tmplt=self, module=module) + + # fmt: off + PARSERS = [ + { + "name": "evi", + "getval": re.compile( + r"""^l2vpn\sevpn\sinstance\s + (?P<evi>\d+)\svlan-based + $""", + re.VERBOSE, + ), + "setval": "l2vpn evpn instance {{ evi }} vlan-based", + "result": {"{{ evi }}": {"evi": "{{ evi }}"}}, + "shared": True, + }, + { + "name": "default_gateway.advertise.enable", + "getval": re.compile( + r""" + \s+default-gateway\sadvertise\senable + $""", + re.VERBOSE, + ), + "setval": "default-gateway advertise enable", + "result": {"{{ evi }}": {"default_gateway": {"advertise": {"enable": True}}}}, + }, + { + "name": "default_gateway.advertise.disable", + "getval": re.compile( + r""" + \s+default-gateway\sadvertise\sdisable + $""", + re.VERBOSE, + ), + "setval": "default-gateway advertise disable", + "result": {"{{ evi }}": {"default_gateway": {"advertise": {"disable": True}}}}, + }, + { + "name": "encapsulation", + "getval": re.compile( + r""" + \s+encapsulation\s(?P<encapsulation>\S+) + $""", + re.VERBOSE, + ), + "setval": "encapsulation {{encapsulation}}", + "result": {"{{ evi }}": {"encapsulation": "{{ encapsulation }}"}}, + }, + { + "name": "ip.local_learning.enable", + "getval": re.compile( + r""" + \s+ip\slocal-learning\senable + $""", + re.VERBOSE, + ), + "setval": "ip local-learning enable", + "result": {"{{ evi }}": {"ip": {"local_learning": {"enable": True}}}}, + }, + { + "name": "ip.local_learning.disable", + "getval": re.compile( + r""" + \s+ip\slocal-learning\sdisable + $""", + re.VERBOSE, + ), + "setval": "ip local-learning disable", + "result": {"{{ evi }}": {"ip": {"local_learning": {"disable": True}}}}, + }, + { + "name": "replication_type", + "getval": re.compile( + r""" + \s+replication-type\s(?P<replication_type>\S+) + $""", + re.VERBOSE, + ), + "setval": "replication-type {{ replication_type }}", + "result": {"{{ evi }}": {"replication_type": "{{ replication_type }}"}}, + }, + { + "name": "route_distinguisher", + "getval": re.compile( + r""" + \s+rd\s(?P<route_distinguisher>\S+) + $""", + re.VERBOSE, + ), + "setval": "rd {{ route_distinguisher }}", + "result": {"{{ evi }}": {"route_distinguisher": "{{ route_distinguisher }}"}}, + }, + ] + # fmt: on diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/evpn_global.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/evpn_global.py new file mode 100644 index 000000000..2dfae2a11 --- /dev/null +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/evpn_global.py @@ -0,0 +1,115 @@ +# -*- coding: utf-8 -*- +# Copyright 2023 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The Evpn_global parser templates file. This contains +a list of parser definitions and associated functions that +facilitates both facts gathering and native command generation for +the given network resource. +""" + +import re + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( + NetworkTemplate, +) + + +class Evpn_globalTemplate(NetworkTemplate): + def __init__(self, lines=None, module=None): + super(Evpn_globalTemplate, self).__init__(lines=lines, tmplt=self, module=module) + + # fmt: off + PARSERS = [ + { + "name": "default_gateway.advertise", + "getval": re.compile( + r""" + \sdefault-gateway\sadvertise + $""", + re.VERBOSE, + ), + "setval": "default-gateway advertise", + "result": {"default_gateway": {"advertise": True}}, + }, + { + "name": "flooding_suppression.address_resolution.disable", + "getval": re.compile( + r""" + \sflooding-suppression\saddress-resolution\sdisable + $""", + re.VERBOSE, + ), + "setval": "flooding-suppression address-resolution disable", + "result": { + "flooding_suppression": { + "address_resolution": { + "disable": True, + }, + }, + }, + "shared": True, + }, + { + "name": "ip.local_learning.disable", + "getval": re.compile( + r""" + \sip\slocal-learning\sdisable + $""", + re.VERBOSE, + ), + "setval": "ip local-learning disable", + "result": { + "ip": { + "local_learning": { + "disable": True, + }, + }, + }, + "shared": True, + }, + { + "name": "replication_type", + "getval": re.compile( + r""" + \sreplication-type\s(?P<replication_type>\S+) + $""", + re.VERBOSE, + ), + "setval": "replication-type {{replication_type}}", + "result": {"replication_type": "{{replication_type}}"}, + "shared": True, + }, + { + "name": "route_target.auto.vni", + "getval": re.compile( + r""" + \sroute-target\sauto\svni + $""", + re.VERBOSE, + ), + "setval": "route-target auto vni", + "result": {"route_target": {"auto": {"vni": True}}}, + "shared": True, + }, + { + "name": "router_id", + "getval": re.compile( + r""" + \srouter-id\s(?P<router_id>\S+) + $""", + re.VERBOSE, + ), + "setval": "router-id {{ router_id }}", + "result": {"router_id": "{{router_id}}"}, + "shared": True, + }, + ] + # fmt: on diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospfv2.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospfv2.py index 5b746e507..74b380cc5 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospfv2.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospfv2.py @@ -5,31 +5,11 @@ __metaclass__ = type import re -from ansible.module_utils.six import iteritems from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( NetworkTemplate, ) -def _tmplt_ospf_vrf_cmd(process): - command = "router ospf {process_id}".format(**process) - if "vrf" in process: - command += " vrf {vrf}".format(**process) - return command - - -def _tmplt_ospf_adjacency_cmd(config_data): - if "adjacency" in config_data: - command = "adjacency stagger " - if "none" in config_data["adjacency"]: - command += " none" - else: - command += " {min_adjacency}".format(**config_data["adjacency"]) - if "max_adjacency" in config_data["adjacency"]: - command += " {min_adjacency}".format(**config_data["adjacency"]) - return command - - def _tmplt_ospf_address_family_cmd(config_data): if "address_family" in config_data: command = ["address-family ipv4 multicast", "exit-address-family"] @@ -44,207 +24,30 @@ def _tmplt_ospf_address_family_cmd(config_data): return command -def _tmplt_ospf_area_authentication(config_data): - if "authentication" in config_data: - command = "area {area_id} authentication".format(**config_data) - if config_data["authentication"].get("message_digest"): - command += " message-digest" - return command - - -def _tmplt_ospf_area_filter(config_data): - if "filter_list" in config_data: - command = [] - for key, value in iteritems(config_data.get("filter_list")): - cmd = "area {area_id}".format(**config_data) - if value.get("name") and value.get("direction"): - cmd += " filter-list prefix {name} {direction}".format(**value) - command.append(cmd) - return command - - def _tmplt_ospf_area_nssa(config_data): if "nssa" in config_data: + nssa_data = config_data["nssa"] command = "area {area_id} nssa".format(**config_data) - if "default_information_originate" in config_data["nssa"]: + if "default_information_originate" in nssa_data: + default_info = nssa_data["default_information_originate"] command += " default-information-originate" - if "metric" in config_data["nssa"]["default_information_originate"]: - command += " metric {metric}".format( - **config_data["nssa"]["default_information_originate"] - ) - if "metric_type" in config_data["nssa"]["default_information_originate"]: - command += " metric-type {metric_type}".format( - **config_data["nssa"]["default_information_originate"] - ) - if "nssa_only" in config_data["nssa"]["default_information_originate"]: + metric = default_info.get("metric") + if metric is not None: + command += " metric {metric}".format(metric=metric) + metric_type = default_info.get("metric_type") + if metric_type is not None: + command += " metric-type {metric_type}".format(metric_type=metric_type) + if default_info.get("nssa_only"): command += " nssa-only" - if config_data["nssa"].get("no_ext_capability"): + if nssa_data.get("no_ext_capability"): command += " no-ext-capability" - if config_data["nssa"].get("no_redistribution"): + if nssa_data.get("no_redistribution"): command += " no-redistribution" - if config_data["nssa"].get("no_summary"): - command += " no-summary" - return command - - -def _tmplt_ospf_area_nssa_translate(config_data): - if "nssa" in config_data: - command = "area {area_id} nssa".format(**config_data) - if "translate" in config_data["nssa"]: - command += " translate type7 {translate}".format(**config_data["nssa"]) - return command - - -def _tmplt_ospf_area_ranges(config_data): - if "ranges" in config_data: - commands = [] - for k, v in iteritems(config_data["ranges"]): - cmd = "area {area_id} range".format(**config_data) - temp_cmd = " {address} {netmask}".format(**v) - if "advertise" in v: - temp_cmd += " advertise" - elif "not_advertise" in v: - temp_cmd += " not-advertise" - if "cost" in v: - temp_cmd += " cost {cost}".format(**v) - cmd += temp_cmd - commands.append(cmd) - return commands - - -def _tmplt_ospf_area_sham_link(config_data): - if "sham_link" in config_data: - command = "area {area_id} sham-link".format(**config_data) - if "source" in config_data["sham_link"]: - command += " {source} {destination}".format(**config_data["sham_link"]) - if "cost" in config_data["sham_link"]: - command += " cost {cost}".format(**config_data["sham_link"]) - if "ttl_security" in config_data["sham_link"]: - command += " ttl-security hops {ttl_security}".format(**config_data["sham_link"]) - return command - - -def _tmplt_ospf_area_stub_link(config_data): - if "stub" in config_data: - command = "area {area_id} stub".format(**config_data) - if "no_ext_capability" in config_data["stub"]: - command += " no-ext-capability" - if "no_summary" in config_data["stub"]: + if nssa_data.get("no_summary"): command += " no-summary" return command -def _tmplt_ospf_auto_cost(config_data): - if "auto_cost" in config_data: - command = "auto-cost" - if "reference_bandwidth" in config_data["auto_cost"]: - command += " reference-bandwidth {reference_bandwidth}".format( - **config_data["auto_cost"] - ) - return command - - -def _tmplt_ospf_capability(config_data): - if "capability" in config_data: - if "lls" in config_data["capability"]: - command = "capability lls" - elif "opaque" in config_data["capability"]: - command = "capability opaque" - elif "transit" in config_data["capability"]: - command = "capability transit" - elif "vrf_lite" in config_data["capability"]: - command = "capability vrf-lite" - return command - - -def _tmplt_ospf_compatible(config_data): - if "compatible" in config_data: - if "rfc1583" in config_data["compatible"]: - command = "compatible rfc1583" - elif "rfc1587" in config_data["compatible"]: - command = "compatible rfc1587" - elif "rfc5243" in config_data["compatible"]: - command = "compatible rfc5243" - return command - - -def _tmplt_ospf_default_information(config_data): - if "default_information" in config_data: - command = "default-information" - if "originate" in config_data["default_information"]: - command += " originate" - if "always" in config_data["default_information"]: - command += " always" - if "metric" in config_data["default_information"]: - command += " metric {metric}".format(**config_data["default_information"]) - if "metric_type" in config_data["default_information"]: - command += " metric-type {metric_type}".format(**config_data["default_information"]) - if "metric" in config_data["default_information"]: - command += " route-map {route_map}".format(**config_data["default_information"]) - return command - - -def _tmplt_ospf_discard_route(config_data): - if "discard_route" in config_data: - command = "discard-route" - if "external" in config_data["discard_route"]: - command += " external {external}".format(**config_data["discard_route"]) - if "internal" in config_data["discard_route"]: - command += " internal {internal}".format(**config_data["discard_route"]) - return command - - -def _tmplt_ospf_distance_admin_distance(config_data): - if "admin_distance" in config_data["distance"]: - command = "distance {distance}".format(**config_data["distance"]["admin_distance"]) - if "address" in config_data["distance"]["admin_distance"]: - command += " {address} {wildcard_bits}".format( - **config_data["distance"]["admin_distance"] - ) - if "acl" in config_data["distance"]["admin_distance"]: - command += " {acl}".format(**config_data["distance"]["admin_distance"]) - return command - - -def _tmplt_ospf_distance_ospf(config_data): - if "ospf" in config_data["distance"]: - command = "distance ospf" - if "inter_area" in config_data["distance"]["ospf"]: - command += " inter-area {inter_area}".format(**config_data["distance"]["ospf"]) - if config_data["distance"].get("ospf").get("intra_area"): - command += " intra-area {intra_area}".format(**config_data["distance"]["ospf"]) - if config_data["distance"].get("ospf").get("external"): - command += " external {external}".format(**config_data["distance"]["ospf"]) - return command - - -def _tmplt_ospf_distribute_list_acls(config_data): - if "acls" in config_data.get("distribute_list"): - command = [] - for k, v in iteritems(config_data["distribute_list"]["acls"]): - cmd = "distribute-list {name} {direction}".format(**v) - if "interface" in v: - cmd += " {interface}".format(**v) - if "protocol" in v: - cmd += " {protocol}".format(**v) - command.append(cmd) - return command - - -def _tmplt_ospf_distribute_list_prefix(config_data): - if "prefix" in config_data.get("distribute_list"): - command = "distribute-list prefix {name}".format(**config_data["distribute_list"]["prefix"]) - if "gateway_name" in config_data["distribute_list"]["prefix"]: - command += " gateway {gateway_name}".format(**config_data["distribute_list"]["prefix"]) - if "direction" in config_data["distribute_list"]["prefix"]: - command += " {direction}".format(**config_data["distribute_list"]["prefix"]) - if "interface" in config_data["distribute_list"]["prefix"]: - command += " {interface}".format(**config_data["distribute_list"]["prefix"]) - if "protocol" in config_data["distribute_list"]["prefix"]: - command += " {protocol}".format(**config_data["distribute_list"]["prefix"]) - return command - - def _tmplt_ospf_domain_id(config_data): if "domain_id" in config_data: command = "domain-id" @@ -252,76 +55,12 @@ def _tmplt_ospf_domain_id(config_data): if "address" in config_data["domain_id"]["ip_address"]: command += " {address}".format(**config_data["domain_id"]["ip_address"]) if "secondary" in config_data["domain_id"]["ip_address"]: - command += " {secondary}".format(**config_data["domain_id"]["ip_address"]) + command += " secondary".format(**config_data["domain_id"]["ip_address"]) elif "null" in config_data["domain_id"]: command += " null" return command -def _tmplt_ospf_event_log(config_data): - if "event_log" in config_data: - command = "event-log" - if "one_shot" in config_data["event_log"]: - command += " one-shot" - if "pause" in config_data["event_log"]: - command += " pause" - if "size" in config_data["event_log"]: - command += " size {size}".format(**config_data["event_log"]) - return command - - -def _tmplt_ospf_limit(config_data): - if "limit" in config_data: - command = "limit retransmissions" - if "dc" in config_data["limit"]: - if "number" in config_data["limit"]["dc"]: - command += " dc {number}".format(**config_data["limit"]["dc"]) - if "disable" in config_data["limit"]["dc"]: - command += " dc disable" - if "non_dc" in config_data["limit"]: - if "number" in config_data["limit"]["non_dc"]: - command += " non-dc {number}".format(**config_data["limit"]["non_dc"]) - if "disable" in config_data["limit"]["dc"]: - command += " non-dc disable" - return command - - -def _tmplt_ospf_vrf_local_rib_criteria(config_data): - if "local_rib_criteria" in config_data: - command = "local-rib-criteria" - if "forwarding_address" in config_data["local_rib_criteria"]: - command += " forwarding-address" - if "inter_area_summary" in config_data["local_rib_criteria"]: - command += " inter-area-summary" - if "nssa_translation" in config_data["local_rib_criteria"]: - command += " nssa-translation" - return command - - -def _tmplt_ospf_log_adjacency_changes(config_data): - if "log_adjacency_changes" in config_data: - command = "log-adjacency-changes" - if "detail" in config_data["log_adjacency_changes"]: - command += " detail" - return command - - -def _tmplt_ospf_max_lsa(config_data): - if "max_lsa" in config_data: - command = "max-lsa {number}".format(**config_data["max_lsa"]) - if "threshold_value" in config_data["max_lsa"]: - command += " {threshold_value}".format(**config_data["max_lsa"]) - if "ignore_count" in config_data["max_lsa"]: - command += " ignore-count {ignore_count}".format(**config_data["max_lsa"]) - if "ignore_time" in config_data["max_lsa"]: - command += " ignore-time {ignore_time}".format(**config_data["max_lsa"]) - if "reset_time" in config_data["max_lsa"]: - command += " reset-time {reset_time}".format(**config_data["max_lsa"]) - if "warning_only" in config_data["max_lsa"]: - command += " warning-only" - return command - - def _tmplt_ospf_max_metric(config_data): if "max_metric" in config_data: command = "max-metric" @@ -341,18 +80,6 @@ def _tmplt_ospf_max_metric(config_data): return command -def _tmplt_ospf_mpls_ldp(config_data): - if "ldp" in config_data["mpls"]: - command = "mpls ldp" - if "autoconfig" in config_data["mpls"]["ldp"]: - command += " autoconfig" - if "area" in config_data["mpls"]["ldp"]["autoconfig"]: - command += " area {area}".format(**config_data["mpls"]["ldp"]["autoconfig"]) - elif "sync" in config_data["mpls"]["ldp"]: - command += " sync" - return command - - def _tmplt_ospf_mpls_traffic_eng(config_data): if "traffic_eng" in config_data["mpls"]: command = "mpls traffic-eng" @@ -360,17 +87,17 @@ def _tmplt_ospf_mpls_traffic_eng(config_data): command += " area {area}".format(**config_data["mpls"]["traffic_eng"]) elif "autoroute_exclude" in config_data["mpls"]["traffic_eng"]: command += " autoroute-exclude prefix-list {autoroute_exclude}".format( - **config_data["mpls"]["traffic_eng"] + **config_data["mpls"]["traffic_eng"], ) elif "interface" in config_data["mpls"]["traffic_eng"]: command += " interface {int_type}".format( - **config_data["mpls"]["traffic_eng"]["interface"] + **config_data["mpls"]["traffic_eng"]["interface"], ) if "area" in config_data["mpls"]["traffic_eng"]["interface"]: command += " area {area}".format(**config_data["mpls"]["traffic_eng"]["interface"]) elif "mesh_group" in config_data["mpls"]["traffic_eng"]: command += " mesh-group {id} {interface}".format( - **config_data["mpls"]["traffic_eng"]["mesh_group"] + **config_data["mpls"]["traffic_eng"]["mesh_group"], ) if "area" in config_data["mpls"]["traffic_eng"]["mesh_group"]: command += " area {area}".format(**config_data["mpls"]["traffic_eng"]["mesh_group"]) @@ -378,7 +105,7 @@ def _tmplt_ospf_mpls_traffic_eng(config_data): command += " multicast-intact" elif "router_id_interface" in config_data["mpls"]["traffic_eng"]: command += " router-id {router_id_interface}".format( - **config_data["mpls"]["traffic_eng"] + **config_data["mpls"]["traffic_eng"], ) return command @@ -399,61 +126,8 @@ def _tmplt_ospf_neighbor(config_data): return command -def _tmplt_ospf_network(config_data): - if "network" in config_data: - command = [] - for each in config_data["network"]: - cmd = "network" - if "address" in each: - cmd += " {address} {wildcard_bits}".format(**each) - if "area" in each: - cmd += " area {area}".format(**each) - command.append(cmd) - return command - - -def _tmplt_ospf_nsf_cisco(config_data): - if "cisco" in config_data["nsf"]: - command = "nsf cisco helper" - if "disable" in config_data["nsf"]["cisco"]: - command += " disable" - return command - - -def _tmplt_ospf_nsf_ietf(config_data): - if "ietf" in config_data["nsf"]: - command = "nsf ietf helper" - if "disable" in config_data["nsf"]["ietf"]: - command += " disable" - elif "strict_lsa_checking" in config_data["nsf"]["ietf"]: - command += " strict-lsa-checking" - return command - - -def _tmplt_ospf_queue_depth_hello(config_data): - if "hello" in config_data["queue_depth"]: - command = "queue-depth hello" - if "max_packets" in config_data["queue_depth"]["hello"]: - command += " {max_packets}".format(**config_data["queue_depth"]["hello"]) - elif "unlimited" in config_data["queue_depth"]["hello"]: - command += " unlimited" - return command - - -def _tmplt_ospf_queue_depth_update(config_data): - if "update" in config_data["queue_depth"]: - command = "queue-depth update" - if "max_packets" in config_data["queue_depth"]["update"]: - command += " {max_packets}".format(**config_data["queue_depth"]["update"]) - elif "unlimited" in config_data["queue_depth"]["update"]: - command += " unlimited" - return command - - def _tmplt_ospf_passive_interfaces(config_data): if "passive_interfaces" in config_data: - if config_data["passive_interfaces"].get("default"): - cmd = "passive-interface default" if config_data["passive_interfaces"].get("interface"): if config_data["passive_interfaces"].get("set_interface"): for each in config_data["passive_interfaces"]["interface"]: @@ -464,38 +138,6 @@ def _tmplt_ospf_passive_interfaces(config_data): return cmd -def _tmplt_ospf_summary_address(config_data): - if "summary_address" in config_data: - command = "summary-address {address} {mask}".format(**config_data["summary_address"]) - if "not_advertise" in config_data["summary_address"]: - command += " not-advertise" - elif "nssa_only" in config_data["summary_address"]: - command += " nssa-only" - if "tag" in config_data["summary_address"]: - command += " tag {tag}".format(**config_data["summary_address"]) - return command - - -def _tmplt_ospf_timers_pacing(config_data): - if "pacing" in config_data["timers"]: - command = "timers pacing" - if "flood" in config_data["timers"]["pacing"]: - command += " flood {flood}".format(**config_data["timers"]["pacing"]) - elif "lsa_group" in config_data["timers"]["pacing"]: - command += " lsa-group {lsa_group}".format(**config_data["timers"]["pacing"]) - elif "retransmission" in config_data["timers"]["pacing"]: - command += " retransmission {retransmission}".format(**config_data["timers"]["pacing"]) - return command - - -def _tmplt_ospf_ttl_security(config_data): - if "ttl_security" in config_data: - command = "ttl-security all-interfaces" - if "hops" in config_data["ttl_security"]: - command += " hops {hops}".format(**config_data["ttl_security"]) - return command - - class Ospfv2Template(NetworkTemplate): def __init__(self, lines=None): super(Ospfv2Template, self).__init__(lines=lines, tmplt=self) @@ -505,52 +147,40 @@ class Ospfv2Template(NetworkTemplate): "name": "pid", "getval": re.compile( r""" - ^router\s - ospf* - \s(?P<pid>\S+) - \svrf - \s(?P<vrf>\S+) - $""", + ^router\sospf + (\s(?P<pid>\d+)) + (\s(vrf\s(?P<vrf_value>\S+)))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_vrf_cmd, + "setval": "router ospf {{ process_id }}" + "{{ (' vrf ' + vrf ) if vrf is defined else '' }}", "result": { - "processes": {"{{ pid }}": {"process_id": "{{ pid|int }}", "vrf": "{{ vrf }}"}}, + "processes": { + "{{ pid }}": {"process_id": "{{ pid|int }}", "vrf": "{{ vrf_value }}"}, + }, }, "shared": True, }, { - "name": "pid", - "getval": re.compile( - r""" - ^router\s - ospf* - \s(?P<pid>\S+) - $""", - re.VERBOSE, - ), - "setval": _tmplt_ospf_vrf_cmd, - "result": {"processes": {"{{ pid }}": {"process_id": "{{ pid|int }}"}}}, - "shared": True, - }, - { "name": "adjacency", "getval": re.compile( - r"""\s+adjacency - \sstagger* - \s*((?P<min>\d+)|(?P<none_adj>none))* - \s*(?P<max>\S+) - *$""", + r""" + \sadjacency\sstagger + (\s(?P<min>\d+))? + (\s(?P<none>none))? + (\s(?P<max>\d+))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_adjacency_cmd, + "setval": "adjacency stagger {{ 'none' if adjacency.none else adjacency.min_adjacency }} {{ adjacency.max_adjacency }}", "result": { "processes": { "{{ pid }}": { "adjacency": { "min_adjacency": "{{ min|int }}", "max_adjacency": "{{ max|int }}", - "none": "{{ True if none_adj is defined else None }}", + "none": "{{ True if none_adj is defined else False }}", }, }, }, @@ -559,11 +189,12 @@ class Ospfv2Template(NetworkTemplate): { "name": "address_family", "getval": re.compile( - r"""\s+topology - \s(?P<base>base)* - \s*(?P<name>\S+)* - \s*(?P<tid>tid\s\d+) - *$""", + r""" + \stopology + (\s(?P<base>base))? + (\s(?P<name>\S+))? + (\stid\s(?P<tid>\S+))? + $""", re.VERBOSE, ), "setval": _tmplt_ospf_address_family_cmd, @@ -574,7 +205,7 @@ class Ospfv2Template(NetworkTemplate): "topology": { "base": "{{ True if base is defined }}", "name": "{{ name }}", - "tid": "{{ tid.split(" ")[1] }}", + "tid": "{{ tid }}", }, }, }, @@ -582,17 +213,18 @@ class Ospfv2Template(NetworkTemplate): }, }, { - "name": "area.authentication", + "name": "authentication", "getval": re.compile( - r"""\s+area - \s(?P<area_id>\S+)* - \s*(?P<auth>authentication)* - \s*(?P<md>message-digest) - *$""", + r""" + \sarea + (\s(?P<area_id>\S+))? + (\s(?P<auth>authentication))? + (\s(?P<md>message-digest))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_area_authentication, - "compval": "authentication", + "setval": "area {{ area_id }} authentication" + "{{ ' message-digest' if authentication.message_digest else '' }}", "result": { "processes": { "{{ pid }}": { @@ -610,17 +242,17 @@ class Ospfv2Template(NetworkTemplate): }, }, { - "name": "area.capability", + "name": "capability", "getval": re.compile( - r"""\s+area - \s(?P<area_id>\S+)* - \s*(?P<capability>capability)* - \s*(?P<df>default-exclusion) - *$""", + r""" + \sarea + (\s(?P<area_id>\S+))? + (\s(?P<capability>capability))? + \sdefault-exclusion + $""", re.VERBOSE, ), "setval": "area {{ area_id }} capability default-exclusion", - "compval": "capability", "result": { "processes": { "{{ pid }}": { @@ -635,17 +267,17 @@ class Ospfv2Template(NetworkTemplate): }, }, { - "name": "area.default_cost", + "name": "default_cost", "getval": re.compile( - r"""\s+area - \s(?P<area_id>\S+)* - \sdefault-cost* - \s*(?P<default_cost>\S+) - *$""", + r""" + \sarea + (\s(?P<area_id>\S+))? + \sdefault-cost + (\s(?P<default_cost>\S+))? + $""", re.VERBOSE, ), "setval": "area {{ area_id }} default-cost {{ default_cost }}", - "compval": "default_cost", "result": { "processes": { "{{ pid }}": { @@ -660,25 +292,30 @@ class Ospfv2Template(NetworkTemplate): }, }, { - "name": "area.filter_list", + "name": "filter_list", "getval": re.compile( - r"""\s+area - \s*(?P<area_id>\S+)* - \s*filter-list\sprefix* - \s*(?P<name>\S+)* - \s*(?P<dir>\S+) - *$""", + r""" + \s+area + (\s(?P<area_id>\S+))? + \sfilter-list\sprefix + (\s(?P<name>\S+))? + (\s(?P<dir>\S+))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_area_filter, - "compval": "filter_list", + "setval": "area {{ area_id }}" " filter-list prefix {{ name }} {{ direction }}", "result": { "processes": { "{{ pid }}": { "areas": { "{{ area_id }}": { "area_id": "{{ area_id }}", - "filter_list": [{"name": "{{ name }}", "direction": "{{ dir }}"}], + "filter_list": [ + { + "name": "{{ name }}", + "direction": "{{ dir }}", + }, + ], }, }, }, @@ -686,20 +323,23 @@ class Ospfv2Template(NetworkTemplate): }, }, { - "name": "area.nssa", + "name": "nssa", "getval": re.compile( - r"""\s+area\s(?P<area_id>\S+) - \s(?P<nssa>nssa)* - \s*(?P<no_redis>no-redistribution)* - \s*(?P<def_origin>default-information-originate)* - \s*(?P<metric>metric\s\d+)* - \s*(?P<metric_type>metric-type\s\d+)* - \s*(?P<no_summary>no-summary)* - \s*(?P<no_ext>no-ext-capability)*$""", + r""" + \sarea + (\s(?P<area_id>\S+))? + (\s(?P<nssa>nssa))? + (\s(?P<no_redis>no-redistribution))? + (\s(?P<def_origin>default-information-originate))? + (\smetric\s(?P<metric>\d+))? + (\smetric-type\s(?P<metric_type>\d+))? + (\s(?P<no_summary>no-summary))? + (\s(?P<nssa_only>nssa-only))? + (\s(?P<no_ext>no-ext-capability))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_area_nssa_translate, - "compval": "nssa", + "setval": _tmplt_ospf_area_nssa, "result": { "processes": { "{{ pid }}": { @@ -707,13 +347,11 @@ class Ospfv2Template(NetworkTemplate): "{{ area_id }}": { "area_id": "{{ area_id }}", "nssa": { - "set": "{{ True if nssa is defined and def_origin is undefined and " + "set": "{{ True if def_origin is undefined and " "no_ext is undefined and no_redis is undefined and nssa_only is undefined }}", "default_information_originate": { - "set": "{{ True if def_origin is defined and metric is undefined and " - "metric_type is undefined and nssa_only is undefined }}", - "metric": "{{ metric.split(" ")[1]|int }}", - "metric_type": "{{ metric_type.split(" ")[1]|int }}", + "metric": "{{ metric|int }}", + "metric_type": "{{ metric_type|int }}", "nssa_only": "{{ True if nssa_only is defined }}", }, "no_ext_capability": "{{ True if no_ext is defined }}", @@ -727,19 +365,19 @@ class Ospfv2Template(NetworkTemplate): }, }, { - "name": "area.nssa.translate", + "name": "nssa.translate", "getval": re.compile( - r"""\s+area* - \s*(?P<area_id>\S+)* - \s*(?P<nssa>nssa)* - \stranslate\stype7* - \s(?P<translate_always>always)* - \s* (?P<translate_supress>suppress-fa) - *$""", + r""" + \sarea + (\s(?P<area_id>\S+))? + \snssa + \stranslate\stype7 + (\s(?P<translate_always>always|suppress-fa))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_area_nssa, - "compval": "nssa.translate", + "setval": "area {{ area_id }} nssa " + "translate type7 {{ nssa.translate if nssa.translate is defined }}", "result": { "processes": { "{{ pid }}": { @@ -747,7 +385,7 @@ class Ospfv2Template(NetworkTemplate): "{{ area_id }}": { "area_id": "{{ area_id }}", "nssa": { - "translate": "{{ translate_always if translate_always is defined else translate_supress if translate_supress is defined }}", + "translate": "{{ translate_always }}", }, }, }, @@ -756,19 +394,24 @@ class Ospfv2Template(NetworkTemplate): }, }, { - "name": "area.ranges", + "name": "ranges", "getval": re.compile( - r"""\s+area\s(?P<area_id>\S+) - \srange - \s(?P<address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) - \s(?P<netmask>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})* - \s*((?P<advertise>advertise)|(?P<not_advertise>not-advertise))* - \s*(?P<cost>cost\s\d+) - *$""", + r""" + \sarea + (\s(?P<area_id>\S+)) + \srange + (\s(?P<address>\S+)) + (\s(?P<netmask>\S+)) + (\s(?P<advertise>advertise))? + (\s(?P<not_advertise>not-advertise))? + (\s(cost\s(?P<cost>\d+))) + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_area_ranges, - "compval": "ranges", + "setval": "area {{ area_id }} range {{ address }} {{ netmask }}" + "{{ (' advertise') if advertise is defined and advertise else '' }}" + "{{ (' not-advertise') if not_advertise is defined and not_advertise else '' }}" + "{{ (' cost ' + cost|string) if cost is defined else '' }}", "result": { "processes": { "{{ pid }}": { @@ -780,7 +423,7 @@ class Ospfv2Template(NetworkTemplate): "address": "{{ address }}", "netmask": "{{ netmask }}", "advertise": "{{ True if advertise is defined }}", - "cost": "{{ cost.split(" ")[1]|int }}", + "cost": "{{ cost }}", "not_advertise": "{{ True if not_advertise is defined }}", }, ], @@ -791,19 +434,22 @@ class Ospfv2Template(NetworkTemplate): }, }, { - "name": "area.sham_link", + "name": "sham_link", "getval": re.compile( - r"""\s+area\s(?P<area_id>\S+) - \ssham-link - \s(?P<source>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) - \s(?P<destination>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})* - \s*(?P<cost>cost\s\d+)* - \s*(?P<ttl_security>ttl-security\shops\s\d+) - *$""", + r""" + \sarea + (\s(?P<area_id>\S+))? + \ssham-link + (\s(?P<source>\S+))? + (\s(?P<destination>\S+))? + (\s(cost\s(?P<cost>\d+)))? + (\s(ttl-security\shops\s(?P<ttl_security>\d+)))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_area_sham_link, - "compval": "sham_link", + "setval": "area {{ area_id }} sham-link {{ sham_link.source }} {{ sham_link.destination }}" + "{{ (' cost ' + sham_link.cost|string) if sham_link.cost is defined else '' }}" + "{{ (' ttl-security hops ' + sham_link.ttl_security|string) if sham_link.ttl_security is defined else '' }}", "result": { "processes": { "{{ pid }}": { @@ -813,8 +459,8 @@ class Ospfv2Template(NetworkTemplate): "sham_link": { "source": "{{ source }}", "destination": "{{ destination }}", - "cost": "{{ cost.split(" ")[1]|int }}", - "ttl_security": '{{ ttl_security.split("hops ")[1] }}', + "cost": "{{ cost }}", + "ttl_security": "{{ ttl_security }}", }, }, }, @@ -823,17 +469,20 @@ class Ospfv2Template(NetworkTemplate): }, }, { - "name": "area.stub", + "name": "stub", "getval": re.compile( - r"""\s+area\s(?P<area_id>\S+) - \s(?P<stub>stub)* - \s*(?P<no_ext>no-ext-capability)* - \s*(?P<no_sum>no-summary) - *$""", + r""" + \sarea + (\s(?P<area_id>\S+))? + (\s(?P<stub>stub))? + (\s(?P<no_ext>no-ext-capability))? + (\s(?P<no_sum>no-summary))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_area_stub_link, - "compval": "stub", + "setval": "area {{ area_id }} stub" + "{{ (' no-ext-capability') if stub.no_ext_capability else ''}}" + "{{ (' no-summary') if stub.no_summary else ''}}", "result": { "processes": { "{{ pid }}": { @@ -854,18 +503,20 @@ class Ospfv2Template(NetworkTemplate): { "name": "auto_cost", "getval": re.compile( - r"""\s+(?P<auto_cost>auto-cost)* - \s*(?P<ref_band>reference-bandwidth\s\d+) - *$""", + r""" + (\s(?P<auto_cost>auto-cost)) + (\sreference-bandwidth\s(?P<ref_band>\d+))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_auto_cost, + "setval": "auto-cost" + "{{ ' reference-bandwidth ' + auto_cost.reference_bandwidth|string if auto_cost.reference_bandwidth is defined }}", "result": { "processes": { "{{ pid }}": { "auto_cost": { - "set": "{{ True if auto_cost is defined and ref_band is undefined }}", - "reference_bandwidth": '{{ ref_band.split(" ")[1] }}', + "set": True, + "reference_bandwidth": "{{ ref_band }}", }, }, }, @@ -874,31 +525,90 @@ class Ospfv2Template(NetworkTemplate): { "name": "bfd", "getval": re.compile( - r"""\s+bfd* - \s*(?P<bfd>all-interfaces) - *$""", + r""" + \sbfd + (\s(?P<bfd>all-interfaces))? + $""", re.VERBOSE, ), "setval": "bfd all-interfaces", "result": {"processes": {"{{ pid }}": {"bfd": "{{ True if bfd is defined }}"}}}, }, { - "name": "capability", + "name": "capability.lls", "getval": re.compile( - r"""\s+capability* - \s*((?P<lls>lls)|(?P<opaque>opaque)|(?P<transit>transit)|(?P<vrf_lite>vrf-lite)) - *$""", + r""" + \scapability + (\s(?P<lls>lls)) + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_capability, + "setval": "capability lls", "result": { "processes": { "{{ pid }}": { "capability": { - "lls": "{{ True if lls is defined }}", - "opaque": "{{ True if opaque is defined }}", - "transit": "{{ True if transit is defined }}", - "vrf_lite": "{{ True if vrf_lite is defined }}", + "lls": True, + }, + }, + }, + }, + }, + { + "name": "capability.opaque", + "getval": re.compile( + r""" + \scapability + (\s(?P<opaque>opaque)) + $""", + re.VERBOSE, + ), + "setval": "capability opaque", + "result": { + "processes": { + "{{ pid }}": { + "capability": { + "opaque": True, + }, + }, + }, + }, + }, + { + "name": "capability.transit", + "getval": re.compile( + r""" + \scapability + (\s(?P<transit>transit)) + $""", + re.VERBOSE, + ), + "setval": "capability transit", + "result": { + "processes": { + "{{ pid }}": { + "capability": { + "transit": True, + }, + }, + }, + }, + }, + { + "name": "capability.vrf_lite", + "getval": re.compile( + r""" + \scapability + (\s(?P<vrf_lite>vrf-lite)) + $""", + re.VERBOSE, + ), + "setval": "capability vrf-lite", + "result": { + "processes": { + "{{ pid }}": { + "capability": { + "vrf_lite": True, }, }, }, @@ -907,19 +617,23 @@ class Ospfv2Template(NetworkTemplate): { "name": "compatible", "getval": re.compile( - r"""\s+compatible* - \s*((?P<rfc1583>rfc1583)|(?P<rfc1587>rfc1587)|(?P<rfc5243>rfc5243)) - *$""", + r""" + \scompatible + (\s(?P<rfc>rfc1583|rfc1587|rfc5243))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_compatible, + "setval": "compatible" + "{{ (' rfc1583') if compatible.rfc1583 else ''}}" + "{{ (' rfc1587') if compatible.rfc1587 else ''}}" + "{{ (' rfc5243') if compatible.rfc5243 else ''}}", "result": { "processes": { "{{ pid }}": { "compatible": { - "rfc1583": "{{ True if rfc1583 is defined }}", - "rfc1587": "{{ True if rfc1587 is defined }}", - "rfc5243": "{{ True if rfc5243 is defined }}", + "rfc1583": "{{ True if 'rfc1583' in rfc else False }}", + "rfc1587": "{{ True if 'rfc1587' in rfc else False }}", + "rfc5243": "{{ True if 'rfc5243' in rfc else False }}", }, }, }, @@ -928,25 +642,31 @@ class Ospfv2Template(NetworkTemplate): { "name": "default_information", "getval": re.compile( - r"""\s+default-information* - \s*(?P<originate>originate)* - \s*(?P<always>always)* - \s*(?P<metric>metric\s\d+)* - \s*(?P<metric_type>metric-type\s\d+)* - \s*(?P<route_map>route-map\s\S+) - *$""", + r""" + \sdefault-information + (\s(?P<originate>originate))? + (\s(?P<always>always))? + (\smetric\s(?P<metric>\d+))? + (\smetric-type\s(?P<metric_type>\d+))? + (\sroute-map\s(?P<route_map>\S+))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_default_information, + "setval": "default-information" + "{{ ' originate' if default_information.originate is defined else ''}}" + "{{ ' always' if default_information.always is defined else '' }}" + "{{ (' metric ' + default_information.metric|string) if default_information.metric is defined else '' }}" + "{{ (' metric-type ' + default_information.metric_type|string) if default_information.metric_type is defined else '' }}" + "{{ ' route-map ' + default_information.route_map if default_information.route_map is defined and default_information.metric is defined else '' }}", "result": { "processes": { "{{ pid }}": { "default_information": { "originate": "{{ True if originate is defined }}", "always": "{{ True if always is defined }}", - "metric": "{{ metric.split(" ")[1]|int }}", - "metric_type": "{{ metric_type.split(" ")[1]|int }}", - "route_map": "{{ route_map.split(" ")[1] }}", + "metric": "{{ metric }}", + "metric_type": "{{ metric_type }}", + "route_map": "{{ route_map }}", }, }, }, @@ -955,30 +675,35 @@ class Ospfv2Template(NetworkTemplate): { "name": "default_metric", "getval": re.compile( - r"""\s+default-metric(?P<default_metric>\s\d+) - *$""", + r""" + \sdefault-metric + \s(?P<default_metric>\d+)? + $""", re.VERBOSE, ), - "setval": "default-metric {{ default_metric }}", - "result": {"processes": {"{{ pid }}": {"default_metric": "{{ default_metric| int}}"}}}, + "setval": "default-metric {{ default_metric|string }}", + "result": {"processes": {"{{ pid }}": {"default_metric": "{{ default_metric }}"}}}, }, { "name": "discard_route", "getval": re.compile( - r"""\s+(?P<discard_route>discard-route)* - \s*(?P<external>external\s\d+)* - \s*(?P<internal>internal\s\d+) - *$""", + r""" + (\s(?P<discard_route>discard-route)) + (\sexternal\s(?P<external>\d+))? + (\sinternal\s(?P<internal>\d+))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_discard_route, + "setval": "discard-route" + "{{ ' external ' + discard_route.external|string if discard_route.external is defined else '' }}" + "{{ ' internal ' + discard_route.internal|string if discard_route.internal is defined else '' }}", "result": { "processes": { "{{ pid }}": { "discard_route": { - "set": "{{ True if discard_route is defined and external is undefined and internal is undefined }}", - "external": "{{ external.split(" ")[1]|int }}", - "internal": "{{ internal.split(" ")[1]|int }}", + "set": True, + "external": "{{ external }}", + "internal": "{{ internal }}", }, }, }, @@ -987,16 +712,18 @@ class Ospfv2Template(NetworkTemplate): { "name": "distance.admin_distance", "getval": re.compile( - r"""\s+distance - \s(?P<admin_dist>\S+)* - \s*(?P<source>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})* - \s*(?P<wildcard>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})* - \s*(?P<acl>\S+) - *$""", + r""" + \sdistance + (\s(?P<admin_dist>\S+)) + (\s(?P<source>\S+))? + (\s(?P<wildcard>\S+))? + (\s(?P<acl>\S+))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_distance_admin_distance, - "compval": "admin_distance", + "setval": "distance {{ admin_distance.distance }} " + "{{ ( admin_distance.address + ' ' + admin_distance.wildcard_bits ) if admin_distance.address is defined else '' }}" + "{{ ' ' + admin_distance.acl if admin_distance.acl is defined else '' }}", "result": { "processes": { "{{ pid }}": { @@ -1015,24 +742,26 @@ class Ospfv2Template(NetworkTemplate): { "name": "distance.ospf", "getval": re.compile( - r"""\s+distance - \sospf* - \s*(?P<intra>intra-area\s\d+)* - \s*(?P<inter>inter-area\s\d+)* - \s*(?P<external>external\s\d+) - *$""", + r""" + \sdistance\sospf + (\sintra-area\s(?P<intra>\d+)) + (\sinter-area\s(?P<inter>\d+)) + (\sexternal\s(?P<external>\d+)) + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_distance_ospf, - "compval": "ospf", + "setval": "distance ospf" + "{{ ' inter-area ' + distance.ospf.inter_area|string if distance.ospf.inter_area is defined else '' }}" + "{{ ' intra-area ' + distance.ospf.intra_area|string if distance.ospf.intra_area is defined else '' }}" + "{{ ' external ' + distance.ospf.external|string if distance.ospf.external is defined else '' }}", "result": { "processes": { "{{ pid }}": { "distance": { "ospf": { - "inter_area": "{{ inter.split(" ")[1]|int }}", - "intra_area": "{{ intra.split(" ")[1]|int }}", - "external": "{{ external.split(" ")[1]|int }}", + "inter_area": "{{ inter|int }}", + "intra_area": "{{ intra|int }}", + "external": "{{ external|int }}", }, }, }, @@ -1042,15 +771,15 @@ class Ospfv2Template(NetworkTemplate): { "name": "distribute_list.acls", "getval": re.compile( - r"""\s+distribute-list - \s(?P<name>\S+)* - \s*(?P<dir>\S+)* - \s*(?P<int_pro>\S+\s\d+) - *$""", + r""" + \sdistribute-list + (\s(?P<name>\S+)) + (\s(?P<dir>\S+)) + (\s(?P<int_pro>\S+\s\d+))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_distribute_list_acls, - "compval": "distribute_list.acls", + "setval": "distribute-list {{ name }} {{ direction }}", "result": { "processes": { "{{ pid }}": { @@ -1071,23 +800,27 @@ class Ospfv2Template(NetworkTemplate): { "name": "distribute_list.prefix", "getval": re.compile( - r"""\s+distribute-list - \s(?P<prefix>prefix\s\S+)* - \s*(?P<gateway>gateway\s\S+)* - \s*(?P<dir>\S+)* - \s*(?P<int_pro>\S+\s\S+) - *$""", + r""" + \sdistribute-list + (\sprefix\s(?P<prefix>\S+)) + (\sgateway\s(?P<gateway>\S+))? + (\s(?P<dir>\S+))? + (\s(?P<int_pro>\S+\s\S+))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_distribute_list_prefix, - "compval": "distribute_list.prefix", + "setval": "distribute-list prefix {{ distribute_list.prefix.name }}" + "{{ ' gateway ' + distribute_list.prefix.gateway_name if distribute_list.prefix.gateway_name is defined else '' }}" + "{{ ' ' + distribute_list.prefix.direction if distribute_list.prefix.direction is defined else '' }}" + "{{ ' ' + distribute_list.prefix.interface if distribute_list.prefix.interface is defined else '' }}" + "{{ ' ' + distribute_list.prefix.protocol if distribute_list.prefix.protocol is defined else '' }}", "result": { "processes": { "{{ pid }}": { "distribute_list": { "prefix": { - "name": "{{ prefix.split(" ")[1] }}", - "gateway_name": "{{ gateway.split(" ")[1] if prefix is defined }}", + "name": "{{ prefix }}", + "gateway_name": "{{ gateway }}", "direction": "{{ dir if gateway is undefined }}", "interface": '{{ int_pro if dir == "in" }}', "protocol": '{{ int_pro if dir == "out" }}', @@ -1100,18 +833,18 @@ class Ospfv2Template(NetworkTemplate): { "name": "distribute_list.route_map", "getval": re.compile( - r"""\s+distribute-list - \s(?P<route_map>route-map\s\S+)* - \s*(?P<dir>\S+) - *$""", + r""" + \sdistribute-list + (\sroute-map\s(?P<route_map>\S+)) + (\s(?P<dir>\S+)) + $""", re.VERBOSE, ), "setval": "distribute-list route-map {{ distribute_list.route_map.name }} in", - "compval": "distribute_list.route_map", "result": { "processes": { "{{ pid }}": { - "distribute_list": {"route_map": {"name": "{{ route_map.split(" ")[1] }}"}}, + "distribute_list": {"route_map": {"name": "{{ route_map }}"}}, }, }, }, @@ -1119,11 +852,12 @@ class Ospfv2Template(NetworkTemplate): { "name": "domain_id", "getval": re.compile( - r"""\s+domain-id - \s(?P<address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})* - \s*(?P<secondary>secondary)* - \s*(?P<null>null) - *$""", + r""" + \sdomain-id + (\s(?P<address>\S+)) + (\s(?P<secondary>secondary))? + (\s(?P<null>null))? + $""", re.VERBOSE, ), "setval": _tmplt_ospf_domain_id, @@ -1144,9 +878,10 @@ class Ospfv2Template(NetworkTemplate): { "name": "domain_tag", "getval": re.compile( - r"""\s+domain-tag - \s(?P<tag>\d+) - *$""", + r""" + \sdomain-tag + (\s(?P<tag>\d+)) + $""", re.VERBOSE, ), "setval": "domain-tag {{ domain_tag }}", @@ -1155,14 +890,18 @@ class Ospfv2Template(NetworkTemplate): { "name": "event_log", "getval": re.compile( - r"""\s+(?P<event_log>event-log)* - \s*(?P<one_shot>one-shot)* - \s*(?P<pause>pause)* - \s*(?P<size>size\s\d+) - *$""", + r""" + (\s(?P<event_log>event-log))? + (\s(?P<one_shot>one-shot))? + (\s(?P<pause>pause))? + (\ssize\s(?P<size>\d+))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_event_log, + "setval": "event-log" + "{{ ' one-shot' if event_log.one_shot else '' }}" + "{{ ' pause' if event_log.pause else '' }}" + "{{ ' size ' + event_log.size|string if event_log.size is defined else '' }}", "result": { "processes": { "{{ pid }}": { @@ -1170,7 +909,7 @@ class Ospfv2Template(NetworkTemplate): "enable": "{{ True if event_log is defined and one_shot is undefined and pause is undefined and size is undefined }}", "one_shot": "{{ True if one_shot is defined }}", "pause": "{{ True if pause is defined }}", - "size": "{{ size.split(" ")[1]|int }}", + "size": "{{ size }}", }, }, }, @@ -1179,8 +918,9 @@ class Ospfv2Template(NetworkTemplate): { "name": "help", "getval": re.compile( - r"""\s+(?P<help>help) - *$""", + r""" + \s(?P<help>help) + $""", re.VERBOSE, ), "setval": "help", @@ -1189,8 +929,9 @@ class Ospfv2Template(NetworkTemplate): { "name": "ignore", "getval": re.compile( - r"""\s+(?P<ignore>ignore) - *$""", + r""" + \s(?P<ignore>ignore) + $""", re.VERBOSE, ), "setval": "ignore lsa mospf", @@ -1199,8 +940,9 @@ class Ospfv2Template(NetworkTemplate): { "name": "interface_id", "getval": re.compile( - r"""\s+(?P<interface_id>interface-id\ssnmp-if-index) - *$""", + r""" + (\s(?P<interface_id>interface-id\ssnmp-if-index))? + $""", re.VERBOSE, ), "setval": "interface-id snmp-if-index", @@ -1213,8 +955,9 @@ class Ospfv2Template(NetworkTemplate): { "name": "ispf", "getval": re.compile( - r"""\s+(?P<ispf>ispf) - *$""", + r""" + \s(?P<ispf>ispf) + $""", re.VERBOSE, ), "setval": "ispf", @@ -1223,24 +966,31 @@ class Ospfv2Template(NetworkTemplate): { "name": "limit", "getval": re.compile( - r"""\s+limit\sretransmissions - \s((?P<dc_num>dc\s\d+)|(?P<dc_disable>dc\sdisable))* - \s*((?P<non_dc_num>non-dc\s\d+)|(?P<non_dc_disable>non-dc\sdisable)) - *$""", + r""" + \slimit\sretransmissions + (\sdc\s(?P<dc_num>\d+))? + (\sdc\sdisable(?P<dc_disable>))? + (\snon-dc\s(?P<non_dc_num>\d+))? + (\snon-dc\sdisable(?P<non_dc_disable>))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_limit, + "setval": "limit retransmissions" + "{{ ' dc ' + limit.dc.number|string if limit.dc.number is defined }}" + "{{ ' dc disable' if limit.dc.disable and limit.dc.number is not defined }}" + "{{ ' non-dc ' + limit.non_dc.number|string if limit.non_dc.number is defined }}" + "{{ ' non-dc disable' if limit.non_dc.disable and limit.non_dc.number is not defined }}", "result": { "processes": { "{{ pid }}": { "limit": { "dc": { - "number": "{{ dc_num.split(" ")[1]|int }}", + "number": "{{ dc_num|int }}", "disable": "{{ True if dc_disable is defined }}", }, "non_dc": { - "number": "{{ non_dc_num.split(" ")[1]|int }}", - "disable": "{{ True if dc_disable is defined }}", + "number": "{{ non_dc_num|int }}", + "disable": "{{ True if non_dc_disable is defined }}", }, }, }, @@ -1250,14 +1000,18 @@ class Ospfv2Template(NetworkTemplate): { "name": "local_rib_criteria", "getval": re.compile( - r"""\s+(?P<local>local-rib-criteria)* - \s*(?P<forward>forwarding-address)* - \s*(?P<inter>inter-area-summary)* - \s*(?P<nssa>nssa-translation) - *$""", + r""" + (\s(?P<local>local-rib-criteria))? + (\s(?P<forward>forwarding-address))? + (\s(?P<inter>inter-area-summary))? + (\s(?P<nssa>nssa-translation))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_vrf_local_rib_criteria, + "setval": "local-rib-criteria" + "{{ ' forwarding-address' if local_rib_criteria.forwarding_address else '' }}" + "{{ ' inter-area-summary' if local_rib_criteria.inter_area_summary else '' }}" + "{{ ' nssa-translation' if local_rib_criteria.nssa_translation else '' }}", "result": { "processes": { "{{ pid }}": { @@ -1274,12 +1028,14 @@ class Ospfv2Template(NetworkTemplate): { "name": "log_adjacency_changes", "getval": re.compile( - r"""\s+(?P<log>log-adjacency-changes)* - \s*(?P<detail>detail) - *$""", + r""" + (\s(?P<log>log-adjacency-changes))? + (\s(?P<detail>detail))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_log_adjacency_changes, + "setval": "log-adjacency-changes" + "{{ ' detail' if log_adjacency_changes.detail else '' }}", "result": { "processes": { "{{ pid }}": { @@ -1294,25 +1050,31 @@ class Ospfv2Template(NetworkTemplate): { "name": "max_lsa", "getval": re.compile( - r"""\s+max-lsa - \s(?P<number>\d+)* - \s*(?P<threshold>\d+)* - \s*(?P<ignore_count>ignore-count\s\d+)* - \s*(?P<ignore_time>ignore-time\s\d+)* - \s*(?P<reset_time>reset-time\s\d+) - *$""", + r"""\smax-lsa + (\s(?P<number>\d+))? + (\s(?P<threshold>\d+))? + (\s(?P<warning>warning-only))? + (\signore-count\s(?P<ignore_count>\d+))? + (\signore-time\s(?P<ignore_time>\d+))? + (\sreset-time\s(?P<reset_time>\d+))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_max_lsa, + "setval": "max-lsa {{ max_lsa.number|string }}" + "{{ ' ' + max_lsa.threshold_value|string if max_lsa.threshold_value is defined else '' }}" + "{{ ' warning-only' if max_lsa.warning_only else '' }}" + "{{ ' ignore-count ' + max_lsa.ignore_count|string if max_lsa.ignore_count is defined and not max_lsa.warning_only else '' }}" + "{{ ' ignore-time ' + max_lsa.ignore_time|string if max_lsa.ignore_time is defined and not max_lsa.warning_only else '' }}" + "{{ ' reset-time ' + max_lsa.reset_time|string if max_lsa.reset_time is defined and not max_lsa.warning_only else '' }}", "result": { "processes": { "{{ pid }}": { "max_lsa": { "number": "{{ number }}", "threshold_value": "{{ threshold }}", - "ignore_count": "{{ ignore_count.split(" ")[1] }}", - "ignore_time": "{{ ignore_time.split(" ")[1] }}", - "reset_time": "{{ reset_time.split(" ")[1] }}", + "ignore_count": "{{ ignore_count }}", + "ignore_time": "{{ ignore_time }}", + "reset_time": "{{ reset_time }}", "warning_only": "{{ True if warning is defined }}", }, }, @@ -1322,14 +1084,15 @@ class Ospfv2Template(NetworkTemplate): { "name": "max_metric", "getval": re.compile( - r"""\s+max-metric* - \s*(?P<router_lsa>router-lsa)* - \s*(?P<include_stub>include-stub)* - \s*(?P<external_lsa>external-lsa\s\d+)* - \s*(?P<startup_time>on-startup\s\d+)* - \s*(?P<startup_wait>on-startup\s\S+)* - \s*(?P<summary_lsa>summary-lsa\s\d+) - *$""", + r""" + \smax-metric + (\s(?P<router_lsa>router-lsa))? + (\s(?P<include_stub>include-stub))? + (\sexternal-lsa\s(?P<external_lsa>\d+))? + (\son-startup\s(?P<startup_time>\d+))? + (\son-startup\s(?P<startup_wait>\S+))? + (\ssummary-lsa\s(?P<summary_lsa>\d+))? + $""", re.VERBOSE, ), "setval": _tmplt_ospf_max_metric, @@ -1338,13 +1101,13 @@ class Ospfv2Template(NetworkTemplate): "{{ pid }}": { "max_metric": { "router_lsa": "{{ True if router_lsa is defined }}", - "external_lsa": "{{ external_lsa.split(" ")[1] }}", - "include_stub": "{{ ignore_count.split(" ")[1] }}", + "external_lsa": "{{ external_lsa }}", + "include_stub": "{{ ignore_count }}", "on_startup": { - "time": "{{ startup_time.split(" ")[1] }}", + "time": "{{ startup_time }}", "wait_for_bgp": "{{ True if startup_wait is defined }}", }, - "summary_lsa": "{{ summary_lsa.split(" ")[1] }}", + "summary_lsa": "{{ summary_lsa }}", }, }, }, @@ -1353,26 +1116,27 @@ class Ospfv2Template(NetworkTemplate): { "name": "maximum_paths", "getval": re.compile( - r"""\s+maximum-paths* - \s+(?P<paths>\d+) - *$""", + r""" + \smaximum-paths + \s(?P<paths>\d+) + $""", re.VERBOSE, ), - "setval": "maximum-paths {{ maximum_paths }}", + "setval": "maximum-paths {{ maximum_paths|string }}", "result": {"processes": {"{{ pid }}": {"maximum_paths": "{{ paths }}"}}}, }, { - "name": "mpls.ldp", + "name": "mpls.ldp.autoconfig", "getval": re.compile( - r"""\s+mpls - \sldp* - \s*(?P<autoconfig>autoconfig*\s*(?P<area>area\s\S+))* - \s*(?P<sync>sync) - *$""", + r""" + \smpls\sldp + (\s(?P<autoconfig>autoconfig)) + (\sarea\s(?P<area>\S+))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_mpls_ldp, - "compval": "ldp", + "setval": "mpls ldp autoconfig" + "{{ ' area ' + mpls.ldp.autoconfig.area if mpls.ldp.autoconfig.area is defined }}", "result": { "processes": { "{{ pid }}": { @@ -1380,9 +1144,30 @@ class Ospfv2Template(NetworkTemplate): "ldp": { "autoconfig": { "set": "{{ True if autoconfig is defined and area is undefined }}", - "area": "{{ area.split(" ")[1] }}", + "area": "{{ area }}", }, - "sync": "{{ True if sync is defined }}", + }, + }, + }, + }, + }, + }, + { + "name": "mpls.ldp.sync", + "getval": re.compile( + r""" + \smpls\sldp + (\s(?P<sync>sync)) + $""", + re.VERBOSE, + ), + "setval": "mpls ldp sync", + "result": { + "processes": { + "{{ pid }}": { + "mpls": { + "ldp": { + "sync": True, }, }, }, @@ -1404,7 +1189,6 @@ class Ospfv2Template(NetworkTemplate): re.VERBOSE, ), "setval": _tmplt_ospf_mpls_traffic_eng, - "compval": "traffic_eng", "result": { "processes": { "{{ pid }}": { @@ -1432,13 +1216,14 @@ class Ospfv2Template(NetworkTemplate): { "name": "neighbor", "getval": re.compile( - r"""\s+neighbor - \s(?P<address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})* - \s*(?P<cost>cost\s\d+)* - \s*(?P<db_filter>database-filter\sall\sout)* - \s*(?P<poll>poll-interval\s\d+)* - \s*(?P<priority>priority\s\d+) - *$""", + r""" + \sneighbor + (\s(?P<address>\S+)) + (\scost\s(?P<cost>\d+)) + (\sdatabase-filter\sall\sout\s(?P<db_filter>))? + (\spoll-interval\s(?P<poll>\d+))? + (\spriority\s(?P<priority>\d+))? + $""", re.VERBOSE, ), "setval": _tmplt_ospf_neighbor, @@ -1447,10 +1232,10 @@ class Ospfv2Template(NetworkTemplate): "{{ pid }}": { "neighbor": { "address": "{{ address }}", - "cost": "{{ cost.split(" ")[1] }}", + "cost": "{{ cost }}", "database_filter": "{{ True if db_filter is defined }}", - "poll_interval": "{{ poll.split(" ")[1] }}", - "priority": "{{ priority.split(" ")[1] }}", + "poll_interval": "{{ poll }}", + "priority": "{{ priority }}", }, }, }, @@ -1459,14 +1244,17 @@ class Ospfv2Template(NetworkTemplate): { "name": "network", "getval": re.compile( - r"""\s+network - \s(?P<address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})* - \s*(?P<wildcard>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})* - \s*(?P<area>area\s\S+) - *$""", + r""" + \snetwork + (\s(?P<address>\S+))? + (\s(?P<wildcard>\S+))? + (\sarea\s(?P<area>\S+))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_network, + "setval": "network" + "{{ (' ' + address + ' ' + wildcard_bits) if address is defined }}" + "{{ ' area ' + area if area is defined }}", "result": { "processes": { "{{ pid }}": { @@ -1474,7 +1262,7 @@ class Ospfv2Template(NetworkTemplate): { "address": "{{ address }}", "wildcard_bits": "{{ wildcard }}", - "area": "{{ area.split(" ")[1] }}", + "area": "{{ area }}", }, ], }, @@ -1484,15 +1272,15 @@ class Ospfv2Template(NetworkTemplate): { "name": "nsf.cisco", "getval": re.compile( - r"""\s+nsf - \s(?P<cisco>cisco)* - \s*(?P<helper>helper)* - \s*(?P<disable>disable) - *$""", + r""" + \snsf + (\s(?P<cisco>cisco)) + (\s(?P<helper>helper))? + (\s(?P<disable>disable))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_nsf_cisco, - "compval": "cisco", + "setval": "nsf cisco helper" "{{ ' disable' if nsf.cisco.disable }}", "result": { "processes": { "{{ pid }}": { @@ -1507,26 +1295,24 @@ class Ospfv2Template(NetworkTemplate): }, }, { - "name": "nsf.ietf", + "name": "nsf.ietf.disable", "getval": re.compile( - r"""\s+nsf - \s(?P<ietf>ietf)* - \s*(?P<helper>helper)* - \s*(?P<disable>disable)* - \s*(?P<strict>strict-lsa-checking) - *$""", + r""" + \snsf + (\s(?P<ietf>ietf)) + (\s(?P<helper>helper)) + (\s(?P<disable>disable)) + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_nsf_ietf, - "compval": "ietf", + "setval": "nsf ietf helper disable", "result": { "processes": { "{{ pid }}": { "nsf": { "ietf": { - "helper": "{{ True if helper is defined }}", - "disable": "{{ True if disable is defined }}", - "strict_lsa_checking": "{{ True if strict is defined }}", + "helper": True, + "disable": True, }, }, }, @@ -1534,23 +1320,24 @@ class Ospfv2Template(NetworkTemplate): }, }, { - "name": "passive_interfaces", + "name": "nsf.ietf.strict_lsa_checking", "getval": re.compile( - r"""\s*(?P<no>no)* - \s*passive-interface* - \s*(?P<interface>\S+\s\S+|\S+) - *$""", + r""" + \snsf + (\s(?P<ietf>ietf)) + (\s(?P<helper>helper)) + (\s(?P<strict>strict-lsa-checking)) + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_passive_interfaces, + "setval": "nsf ietf helper strict-lsa-checking", "result": { "processes": { "{{ pid }}": { - "passive_interfaces": { - "default": "{{ True if 'default' in interface }}", - "interface": { - "set_interface": "{% if no is defined %}{{ False }}{% elif 'default' not in interface %}{{ True }}{% endif %}", - "name": ["{{ interface if 'default' not in interface }}"], + "nsf": { + "ietf": { + "helper": "{{ True }}", + "strict_lsa_checking": True, }, }, }, @@ -1558,21 +1345,55 @@ class Ospfv2Template(NetworkTemplate): }, }, { - "name": "passive_interface", + "name": "passive_interfaces.default", "getval": re.compile( - r"""\s+passive-interface - \s(?P<interface>\S+\s\S+) - *$""", + r""" + \spassive-interface + \s(?P<default_value>default) + $""", + re.VERBOSE, + ), + "setval": "passive-interface" "{{ ' default' if passive_interfaces.default }}", + "result": { + "processes": { + "{{ pid }}": { + "passive_interfaces": { + "default": "{{ True if default_value is defined }}", + }, + }, + }, + }, + }, + { + "name": "passive_interfaces.interface", + "getval": re.compile( + r""" + (\s(?P<no>no))? + \spassive-interface + \s(?P<interface>\S+) + $""", re.VERBOSE, ), - "setval": "passive-interface {{ passive_interface }}", - "result": {"processes": {"{{ pid }}": {"passive_interface": "{{ interface }}"}}}, + "setval": _tmplt_ospf_passive_interfaces, + "result": { + "processes": { + "{{ pid }}": { + "passive_interfaces": { + "interface": { + "set_interface": "{{ not no }}", + "name": ["{{ interface if 'default' not in interface }}"], + }, + }, + }, + }, + }, }, { "name": "prefix_suppression", "getval": re.compile( - r"""\s+(?P<prefix_sup>prefix-suppression) - *$""", + r""" + \s(?P<prefix_sup>prefix-suppression) + $""", re.VERBOSE, ), "setval": "prefix-suppression", @@ -1585,33 +1406,31 @@ class Ospfv2Template(NetworkTemplate): { "name": "priority", "getval": re.compile( - r"""\s+priority - \s(?P<priority>\d+) - *$""", + r""" + \spriority + \s(?P<priority>\d+) + $""", re.VERBOSE, ), "setval": "priority {{ priority }}", "result": {"processes": {"{{ pid }}": {"priority": "{{ priority }}"}}}, }, { - "name": "queue_depth.hello", + "name": "queue_depth.hello.max_packets", "getval": re.compile( - r"""\s+queue-depth - \shello* - \s*(?P<max_packets>\d+)* - \s*(?P<unlimited>unlimited) - *$""", + r""" + \squeue-depth\shello + (\s(?P<max_packets>\d+)) + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_queue_depth_hello, - "compval": "hello", + "setval": "queue-depth hello " "{{ queue_depth.hello.max_packets|string }}", "result": { "processes": { "{{ pid }}": { "queue_depth": { "hello": { "max_packets": "{{ max_packets }}", - "unlimited": "{{ True if unlimited is defined }}", }, }, }, @@ -1619,24 +1438,65 @@ class Ospfv2Template(NetworkTemplate): }, }, { - "name": "queue_depth.update", + "name": "queue_depth.hello.unlimited", "getval": re.compile( - r"""\s+queue-depth - \supdate* - \s*(?P<max_packets>\d+)* - \s*(?P<unlimited>unlimited) - *$""", + r""" + \squeue-depth\shello + (\s(?P<unlimited>unlimited)) + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_queue_depth_update, - "compval": "update", + "setval": "queue-depth hello unlimited", + "result": { + "processes": { + "{{ pid }}": { + "queue_depth": { + "hello": { + "unlimited": True, + }, + }, + }, + }, + }, + }, + { + "name": "queue_depth.update.max_packets", + "getval": re.compile( + r""" + \squeue-depth\supdate + (\s(?P<max_packets>\d+))? + $""", + re.VERBOSE, + ), + "setval": "queue-depth update " "{{ queue_depth['update'].max_packets|string }}", "result": { "processes": { "{{ pid }}": { "queue_depth": { "update": { "max_packets": "{{ max_packets }}", - "unlimited": "{{ True if unlimited is defined }}", + }, + }, + }, + }, + }, + }, + { + "name": "queue_depth.update.unlimited", + "getval": re.compile( + r""" + \squeue-depth\supdate + (\s(?P<unlimited>unlimited)) + $""", + re.VERBOSE, + ), + "setval": "queue-depth update unlimited", + "result": { + "processes": { + "{{ pid }}": { + "queue_depth": { + "update": { + "unlimited": True, }, }, }, @@ -1646,9 +1506,10 @@ class Ospfv2Template(NetworkTemplate): { "name": "router_id", "getval": re.compile( - r"""\s+router-id - \s(?P<id>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) - *$""", + r""" + \srouter-id + (\s(?P<id>\S+))? + $""", re.VERBOSE, ), "setval": "router-id {{ router_id }}", @@ -1657,8 +1518,9 @@ class Ospfv2Template(NetworkTemplate): { "name": "shutdown", "getval": re.compile( - r"""\s+(?P<shutdown>shutdown) - *$""", + r""" + \s(?P<shutdown>shutdown) + $""", re.VERBOSE, ), "setval": "shutdown", @@ -1667,27 +1529,53 @@ class Ospfv2Template(NetworkTemplate): }, }, { - "name": "summary_address", + "name": "summary_address.not_advertise", "getval": re.compile( - r"""\s+summary-address - \s(?P<address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})* - \s*(?P<mask>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})* - \s*(?P<not_adv>not-advertise)* - \s*(?P<nssa>nssa-only)* - \s*(?P<tag>tag\s\d+) - *$""", + r""" + \ssummary-address + (\s(?P<address>\S+)) + (\s(?P<mask>\S+)) + (\s(?P<not_adv>not-advertise)) + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_summary_address, + "setval": "summary-address " + "{{ summary_address.address + ' ' + summary_address.mask }} not-advertise", "result": { "processes": { "{{ pid }}": { "summary_address": { "address": "{{ address }}", "mask": "{{ mask }}", - "not_advertise": "{{ True if not_adv is defined }}", - "nssa_only": "{{ True if nssa is defined }}", - "tag": "{{ tag.split(" ")[1] }}", + "not_advertise": True, + }, + }, + }, + }, + }, + { + "name": "summary_address.nssa_only", + "getval": re.compile( + r""" + \ssummary-address + (\s(?P<address>\S+)) + (\s(?P<mask>\S+)) + (\s(?P<nssa>nssa-only)) + (\stag\s(?P<tag>\d+))? + $""", + re.VERBOSE, + ), + "setval": "summary-address " + "{{ summary_address.address + ' ' + summary_address.mask }} nssa-only" + "{{ ' tag ' + summary_address.tag|string if summary_address.tag is defined else '' }}", + "result": { + "processes": { + "{{ pid }}": { + "summary_address": { + "address": "{{ address }}", + "mask": "{{ mask }}", + "nssa_only": True, + "tag": "{{ tag }}", }, }, }, @@ -1696,38 +1584,80 @@ class Ospfv2Template(NetworkTemplate): { "name": "timers.lsa", "getval": re.compile( - r"""\s+timers - \slsa - \sarrival - \s(?P<lsa>\d+) - *$""", + r""" + \stimers + \slsa + \sarrival + (\s(?P<lsa>\d+))? + $""", re.VERBOSE, ), "setval": "timers lsa arrival {{ timers.lsa }}", - "compval": "lsa", "result": {"processes": {"{{ pid }}": {"timers": {"lsa": "{{ lsa }}"}}}}, }, { - "name": "timers.pacing", + "name": "timers.pacing.flood", "getval": re.compile( - r"""\s+timers - \spacing - \s(?P<flood>flood\s\d+)* - \s*(?P<lsa_group>lsa-group\s\d+)* - \s*(?P<retransmission>retransmission\s\d+) - *$""", + r""" + \stimers\spacing + (\sflood\s(?P<flood>\d+)) + $""", + re.VERBOSE, + ), + "setval": "timers pacing" + "{{ ' flood ' + timers.pacing.flood|string if timers.pacing.flood is defined else '' }}", + "result": { + "processes": { + "{{ pid }}": { + "timers": { + "pacing": { + "flood": "{{ flood }}", + }, + }, + }, + }, + }, + }, + { + "name": "timers.pacing.lsa_group", + "getval": re.compile( + r""" + \stimers\spacing + (\slsa-group\s(?P<lsa_group>\d+)) + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_timers_pacing, - "compval": "pacing", + "setval": "timers pacing" + "{{ ' lsa-group ' + timers.pacing.lsa_group|string if timers.pacing.lsa_group is defined else '' }}", "result": { "processes": { "{{ pid }}": { "timers": { "pacing": { - "flood": "{{ flood.split(" ")[1] }}", - "lsa_group": "{{ lsa_group.split(" ")[1] }}", - "retransmission": "{{ retransmission.split(" ")[1] }}", + "lsa_group": "{{ lsa_group }}", + }, + }, + }, + }, + }, + }, + { + "name": "timers.pacing.retransmission", + "getval": re.compile( + r""" + \stimers\spacing + (\sretransmission\s(?P<retransmission>\d+))? + $""", + re.VERBOSE, + ), + "setval": "timers pacing" + "{{ ' retransmission ' + timers.pacing.retransmission|string if timers.pacing.retransmission is defined else '' }}", + "result": { + "processes": { + "{{ pid }}": { + "timers": { + "pacing": { + "retransmission": "{{ retransmission }}", }, }, }, @@ -1737,17 +1667,16 @@ class Ospfv2Template(NetworkTemplate): { "name": "timers.throttle.lsa", "getval": re.compile( - r"""\s+timers - \sthrottle - \s*(?P<lsa>lsa)* - \s*(?P<first_delay>\d+)* - \s*(?P<min_delay>\d+)* - \s*(?P<max_delay>\d+) - *$""", + r""" + \stimers\sthrottle + (\s(?P<lsa>lsa))? + (\s(?P<first_delay>\d+))? + (\s(?P<min_delay>\d+))? + (\s(?P<max_delay>\d+))? + $""", re.VERBOSE, ), "setval": "timers throttle lsa {{ throttle.lsa.first_delay }} {{ throttle.lsa.min_delay }} {{ throttle.lsa.max_delay }}", - "compval": "throttle.lsa", "result": { "processes": { "{{ pid }}": { @@ -1767,17 +1696,16 @@ class Ospfv2Template(NetworkTemplate): { "name": "timers.throttle.spf", "getval": re.compile( - r"""\s+timers - \sthrottle - \s*(?P<spf>spf)* - \s*(?P<first_delay>\d+)* - \s*(?P<min_delay>\d+)* - \s*(?P<max_delay>\d+) - *$""", + r""" + \stimers\sthrottle + (\s(?P<spf>spf))? + (\s(?P<first_delay>\d+))? + (\s(?P<min_delay>\d+))? + (\s(?P<max_delay>\d+))? + $""", re.VERBOSE, ), "setval": "timers throttle spf {{ throttle.spf.receive_delay }} {{ throttle.spf.between_delay }} {{ throttle.spf.max_delay }}", - "compval": "throttle.spf", "result": { "processes": { "{{ pid }}": { @@ -1797,8 +1725,9 @@ class Ospfv2Template(NetworkTemplate): { "name": "traffic_share", "getval": re.compile( - r"""\s+(?P<traffic>traffic-share\smin\sacross-interfaces) - *$""", + r""" + \s(?P<traffic>traffic-share\smin\sacross-interfaces) + $""", re.VERBOSE, ), "setval": "traffic-share min across-interfaces", @@ -1809,19 +1738,21 @@ class Ospfv2Template(NetworkTemplate): { "name": "ttl_security", "getval": re.compile( - r"""\s+ttl-security - \s(?P<interfaces>all-interfaces)* - \s*(?P<hops>hops\s\d+) - *$""", + r""" + \sttl-security + (\s(?P<interfaces>all-interfaces))? + (\shops\s(?P<hops>\d+))? + $""", re.VERBOSE, ), - "setval": _tmplt_ospf_ttl_security, + "setval": "ttl-security all-interfaces" + "{{ ' hops ' + ttl_security.hops|string if ttl_security.hops is defined }}", "result": { "processes": { "{{ pid }}": { "ttl_security": { "set": "{{ True if interfaces is defined and hops is undefined }}", - "hops": "{{ hops.split(" ")[1] }}", + "hops": "{{ hops }}", }, }, }, diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospfv3.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospfv3.py index 874eed614..1dbe0fc94 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospfv3.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospfv3.py @@ -81,11 +81,11 @@ def _tmplt_ospf_area_nssa(config_data): command += " default-information-originate" if "metric" in config_data["nssa"]["default_information_originate"]: command += " metric {metric}".format( - **config_data["nssa"]["default_information_originate"] + **config_data["nssa"]["default_information_originate"], ) if "metric_type" in config_data["nssa"]["default_information_originate"]: command += " metric-type {metric_type}".format( - **config_data["nssa"]["default_information_originate"] + **config_data["nssa"]["default_information_originate"], ) if "nssa_only" in config_data["nssa"]["default_information_originate"]: command += " nssa-only" @@ -150,7 +150,7 @@ def _tmplt_ospf_auto_cost(config_data): command = "auto-cost" if "reference_bandwidth" in config_data["auto_cost"]: command += " reference-bandwidth {reference_bandwidth}".format( - **config_data["auto_cost"] + **config_data["auto_cost"], ) return command @@ -210,7 +210,7 @@ def _tmplt_ospf_distance_admin_distance(config_data): command = "distance {distance}".format(**config_data["distance"]["admin_distance"]) if "address" in config_data["distance"]["admin_distance"]: command += " {address} {wildcard_bits}".format( - **config_data["distance"]["admin_distance"] + **config_data["distance"]["admin_distance"], ) if "acl" in config_data["distance"]["admin_distance"]: command += " {acl}".format(**config_data["distance"]["admin_distance"]) @@ -395,17 +395,17 @@ def _tmplt_ospf_mpls_traffic_eng(config_data): command += " area {area}".format(**config_data["mpls"]["traffic_eng"]) elif "autoroute_exclude" in config_data["mpls"]["traffic_eng"]: command += " autoroute-exclude prefix-list {autoroute_exclude}".format( - **config_data["mpls"]["traffic_eng"] + **config_data["mpls"]["traffic_eng"], ) elif "interface" in config_data["mpls"]["traffic_eng"]: command += " interface {int_type}".format( - **config_data["mpls"]["traffic_eng"]["interface"] + **config_data["mpls"]["traffic_eng"]["interface"], ) if "area" in config_data["mpls"]["traffic_eng"]["interface"]: command += " area {area}".format(**config_data["mpls"]["traffic_eng"]["interface"]) elif "mesh_group" in config_data["mpls"]["traffic_eng"]: command += " mesh-group {id} {interface}".format( - **config_data["mpls"]["traffic_eng"]["mesh_group"] + **config_data["mpls"]["traffic_eng"]["mesh_group"], ) if "area" in config_data["mpls"]["traffic_eng"]["mesh_group"]: command += " area {area}".format(**config_data["mpls"]["traffic_eng"]["mesh_group"]) @@ -413,7 +413,7 @@ def _tmplt_ospf_mpls_traffic_eng(config_data): command += " multicast-intact" elif "router_id_interface" in config_data["mpls"]["traffic_eng"]: command += " router-id {router_id_interface}".format( - **config_data["mpls"]["traffic_eng"] + **config_data["mpls"]["traffic_eng"], ) return command diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ping.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ping.py index d7f375b71..1b7bde1ae 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ping.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ping.py @@ -47,6 +47,7 @@ class PingTemplate(NetworkTemplate): "{{ (' repeat ' + count|string ) if count is defined else '' }}" "{{ (' df-bit' ) if df_bit|d(False) else '' }}" "{{ (' timeout ' + timeout|string) if timeout is defined else '' }}" + "{{ (' size ' + size|string) if size is defined else '' }}" "{{ (' ingress ' + ingress) if ingress is defined else '' }}" "{{ (' egress ' + egress) if egress is defined else '' }}" "{{ (' source ' + source) if source is defined else '' }}", diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/prefix_lists.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/prefix_lists.py index 041d926f5..43d163c5d 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/prefix_lists.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/prefix_lists.py @@ -22,66 +22,66 @@ from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.r ) -def _tmplt_set_prefix_lists(config_data): - if "prefix_list" in config_data: - if config_data.get("afi") == "ipv4": - config_data["afi"] = "ip" - cmd = "{afi} prefix-list {name}".format(**config_data) - if config_data.get("prefix_list"): - if config_data["prefix_list"].get("description"): - cmd += " description {description}".format(**config_data["prefix_list"]) - else: - cmd += " seq {sequence} {action} {prefix}".format(**config_data["prefix_list"]) - if config_data["prefix_list"].get("ge"): - cmd += " ge {ge}".format(**config_data["prefix_list"]) - if config_data["prefix_list"].get("le"): - cmd += " le {le}".format(**config_data["prefix_list"]) - return cmd - - class Prefix_listsTemplate(NetworkTemplate): def __init__(self, lines=None): super(Prefix_listsTemplate, self).__init__(lines=lines, tmplt=self) PARSERS = [ { - "name": "prefix_list", + "name": "entry", "getval": re.compile( r""" - ^(?P<afi>ip|ipv6)* - \s*prefix-list* - \s*(?P<name>\S+)* - \s*(?P<description>description\s\S.*)* - \s*(?P<sequence>seq\s\S+)* - \s*(?P<action>deny|permit)* - \s*(?P<prefix>(?:[0-9]{1,3}\.){3}[0-9]{1,3}/\d+|(([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}/\d+))* - \s*(?P<ge>ge\s\d+)* - \s*(?P<le>le\s\d+)* + ^(?P<afi>ip|ipv6)\sprefix-list + (\s(?P<name>\S+)) + (\sseq\s(?P<sequence>\d+))? + (\s(?P<action>deny|permit))? + (\s(?P<prefix>\S+))? + (\sge\s(?P<ge>\d+))? + (\sle\s(?P<le>\d+))? $""", re.VERBOSE, ), - "setval": _tmplt_set_prefix_lists, + "setval": "{{ 'ip' if afi == 'ipv4' else afi }} prefix-list {{ name }}" + "{{ (' seq ' + sequence|string) if sequence|d('') else '' }}" + " {{ action }}" + " {{ prefix }}" + "{{ (' ge ' + ge|string) if ge|d('') else '' }}" + "{{ (' le ' + le|string) if le|d('') else '' }}", + "shared": True, "result": { - "{{ afi + '_' + name }}": { + "{{ afi + name }}": { "afi": "{{ 'ipv4' if afi is defined and afi=='ip' else 'ipv6' }}", - "prefix_lists": [ + "name": "{{ name }}", + "entries": [ { - "name": "{{ name if name is defined }}", - "description": "{{ description.split('description ')[1] if description is defined }}", - "entries": { - # Description at this level is deprecated, should be removed when we plan to remove the - # Description from entries level - "description": "{{ description.split('description ')[1] if description is defined }}", - "sequence": "{{ sequence.split(' ')[1] if sequence is defined }}", - "action": "{{ action if action is defined }}", - "prefix": "{{ prefix if prefix is defined }}", - "ge": "{{ ge.split(' ')[1] if ge is defined }}", - "le": "{{ le.split(' ')[1] if le is defined }}", - }, + "sequence": "{{ sequence }}", + "action": "{{ action }}", + "prefix": "{{ prefix }}", + "ge": "{{ ge }}", + "le": "{{ le }}", }, ], }, }, + }, + { + "name": "description", + "getval": re.compile( + r""" + ^(?P<afi>ip|ipv6)\sprefix-list + (\s(?P<name>\S+)) + (\sdescription\s(?P<description>.+$))? + """, + re.VERBOSE, + ), + "setval": "{{ 'ip' if afi == 'ipv4' else afi }} prefix-list {{ name }} description {{ description }}", "shared": True, + "result": { + "{{ afi + name }}": { + "name": "{{ name }}", + "afi": "{{ 'ipv4' if afi is defined and afi=='ip' else 'ipv6' }}", + "description": "{{ description }}", + }, + }, }, ] diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/route_maps.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/route_maps.py index 47b4402b6..1e569ccca 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/route_maps.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/route_maps.py @@ -41,11 +41,11 @@ def _tmplt_route_map_match(config_data): cmd += " best-range" if config_data["match"]["additional_paths"]["best_range"].get("lower_limit"): cmd += " lower-limit {lower_limit}".format( - **config_data["match"]["additional_paths"]["best_range"] + **config_data["match"]["additional_paths"]["best_range"], ) if config_data["match"]["additional_paths"]["best_range"].get("upper_limit"): cmd += " upper-limit {upper_limit}".format( - **config_data["match"]["additional_paths"]["best_range"] + **config_data["match"]["additional_paths"]["best_range"], ) if config_data["match"]["additional_paths"].get("group_best"): cmd += " group-best" @@ -294,7 +294,7 @@ def _tmplt_route_map_match_ipv6(config_data): cmd += " address" if config_data["match"]["ipv6"]["address"].get("prefix_list"): cmd += " prefix-list {prefix_list}".format( - **config_data["match"]["ipv6"]["address"] + **config_data["match"]["ipv6"]["address"], ) elif config_data["match"]["ipv6"]["address"].get("acl"): cmd += " {acl}".format(**config_data["match"]["ipv6"]["address"]) @@ -306,7 +306,7 @@ def _tmplt_route_map_match_ipv6(config_data): cmd += " src-pfx" if config_data["match"]["ipv6"]["flowspec"].get("prefix_list"): cmd += " prefix-list {prefix_list}".format( - **config_data["match"]["ipv6"]["flowspec"] + **config_data["match"]["ipv6"]["flowspec"], ) elif config_data["match"]["ipv6"]["flowspec"].get("acl"): cmd += " {acl}".format(**config_data["match"]["ipv6"]["flowspec"]) @@ -314,7 +314,7 @@ def _tmplt_route_map_match_ipv6(config_data): cmd += " next-hop" if config_data["match"]["ipv6"]["next_hop"].get("prefix_list"): cmd += " prefix-list {prefix_list}".format( - **config_data["match"]["ipv6"]["next_hop"] + **config_data["match"]["ipv6"]["next_hop"], ) elif config_data["match"]["ipv6"]["next_hop"].get("acl"): cmd += " {acl}".format(**config_data["match"]["ipv6"]["next_hop"]) @@ -322,7 +322,7 @@ def _tmplt_route_map_match_ipv6(config_data): cmd += " route-source" if config_data["match"]["ipv6"]["route_source"].get("prefix_list"): cmd += " prefix-list {prefix_list}".format( - **config_data["match"]["ipv6"]["route_source"] + **config_data["match"]["ipv6"]["route_source"], ) elif config_data["match"]["ipv6"]["route_source"].get("acl"): cmd += " {acl}".format(**config_data["match"]["ipv6"]["route_source"]) @@ -380,7 +380,7 @@ def _tmplt_route_map_set(config_data): if set.get("dampening"): command.append( "set dampening {penalty_half_time} {reuse_route_val} {suppress_route_val} {max_suppress}".format( - **set["dampening"] + **set["dampening"], ), ) if set.get("default"): @@ -403,7 +403,7 @@ def _tmplt_route_map_set(config_data): cmd = "set extcommunity rt" if set["extcommunity"]["rt"].get("range"): cmd += " range {lower_limit} {upper_limit}".format( - **set["extcommunity"]["rt"]["range"] + **set["extcommunity"]["rt"]["range"], ) elif set["extcommunity"]["rt"].get("address"): cmd += " {address}".format(**set["extcommunity"]["rt"]) @@ -416,7 +416,7 @@ def _tmplt_route_map_set(config_data): cmd = "set extcommunity vpn-distinguisher" if set["extcommunity"]["vpn_distinguisher"].get("range"): cmd += " range {lower_limit} {upper_limit}".format( - **set["extcommunity"]["vpn_distinguisher"]["range"] + **set["extcommunity"]["vpn_distinguisher"]["range"], ) elif set["extcommunity"]["vpn_distinguisher"].get("address"): cmd += " {address}".format(**set["extcommunity"]["vpn_distinguisher"]) @@ -454,13 +454,13 @@ def _tmplt_route_map_set(config_data): if set["metric"]["deviation"] == "plus": cmd += ( " +{eigrp_delay} {metric_reliability} {metric_bandwidth} {mtu}".format( - **set["metric"] + **set["metric"], ) ) elif set["metric"]["deviation"] == "minus": cmd += ( " -{eigrp_delay} {metric_reliability} {metric_bandwidth} {mtu}".format( - **set["metric"] + **set["metric"], ) ) if set["metric"].get("deviation") and not set["metric"].get("eigrp_delay"): @@ -512,7 +512,7 @@ def _tmplt_route_map_set_ip(config_data): cmd += " global next-hop" if set_ip["global_route"].get("verify_availability"): cmd += " verify-availability {address} {sequence} track {track}".format( - **set_ip["global_route"]["verify_availability"] + **set_ip["global_route"]["verify_availability"], ) elif set_ip["global_route"].get("address"): cmd += " {address}".format(**set_ip["global_route"]) @@ -543,7 +543,8 @@ def _tmplt_route_map_set_ip(config_data): if set_ip["next_hop"].get("verify_availability"): command.append( "{0} verify-availability {address} {sequence} track {track}".format( - cmd, **set_ip["next_hop"]["verify_availability"] + cmd, + **set_ip["next_hop"]["verify_availability"], ), ) if set_ip.get("precedence"): @@ -584,7 +585,7 @@ def _tmplt_route_map_set_ip(config_data): cmd += " vrf {vrf} next-hop".format(**set_ip) if set_ip["vrf"].get("verify_availability").get("address"): cmd += " verify-availability {address} {sequence} track {track}".format( - **set_ip["vrf"]["verify_availability"] + **set_ip["vrf"]["verify_availability"], ) elif set_ip["vrf"].get("address"): cmd += " {address}".format(**set_ip["vrf"]) @@ -604,7 +605,7 @@ def _tmplt_route_map_set_ipv6(config_data): cmd += " global next-hop" if set_ipv6["global_route"].get("verify_availability"): cmd += " verify-availability {address} {sequence} track {track}".format( - **set_ipv6["global_route"]["verify_availability"] + **set_ipv6["global_route"]["verify_availability"], ) elif set_ipv6["global_route"].get("address"): cmd += " {address}".format(**set_ipv6["global_route"]) @@ -621,7 +622,7 @@ def _tmplt_route_map_set_ipv6(config_data): if set_ipv6.get("vrf"): cmd += ( " vrf {vrf} next-hop verify-availability {address} {sequence} track {track}".format( - **set_ipv6["vrf"]["verify_availability"] + **set_ipv6["vrf"]["verify_availability"], ) ) return cmd diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/snmp_server.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/snmp_server.py index 87f9e7c07..5107612eb 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/snmp_server.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/snmp_server.py @@ -85,8 +85,6 @@ def cmd_option_trap_bgp(config_data): if conf: if conf.get("enable"): cmd += "snmp-server enable traps bgp" - if conf.get("cbgp2"): - cmd += " cbgp2" if conf.get("state_changes"): if conf.get("state_changes").get("enable"): cmd += " state-changes" @@ -281,6 +279,7 @@ class Snmp_serverTemplate(NetworkTemplate): (\s(?P<version>v1|v3|v2c))? (\s(?P<version_option>auth|noauth|priv))? (\scontext\s(?P<context>\S+))? + (\smatch\s(?P<match>\S+))? (\sread\s(?P<read>\S+))? (\swrite\s(?P<write>\S+))? (\snotify\s(?P<notify>\S+))? @@ -293,6 +292,7 @@ class Snmp_serverTemplate(NetworkTemplate): "{{ (' ' + version) if version is defined else '' }}" "{{ (' ' + version_option) if version_option is defined else '' }}" "{{ (' context ' + context) if context is defined else '' }}" + "{{ (' match ' + match) if match is defined else '' }}" "{{ (' read ' + read) if read is defined else '' }}" "{{ (' write ' + write) if write is defined else '' }}" "{{ (' notify ' + notify) if notify is defined else '' }}" @@ -305,6 +305,7 @@ class Snmp_serverTemplate(NetworkTemplate): "version": "{{ version }}", "version_option": "{{ version_option }}", "context": "{{ context }}", + "match": "{{ match }}", "notify": "{{ notify }}", "read": "{{ read }}", "write": "{{ write }}", @@ -396,7 +397,7 @@ class Snmp_serverTemplate(NetworkTemplate): (\sremote\s(?P<remote>\S+))? (\sudp-port\s(?P<udp_port>\d+))? (\s(?P<version>v1|v3|v2c))? - (\s(?P<version_option>auth|encrypted))? + (\s(?P<version_option>encrypted))? (\saccess\sipv6\s(?P<acl_v6>\S+))? (\saccess\s(?P<acl_v4>\S+|\d+))? (\svrf\s(?P<vrf>\S+))? @@ -409,13 +410,17 @@ class Snmp_serverTemplate(NetworkTemplate): "{{ (' udp-port ' + udp_port|string) if udp_port is defined else '' }}" "{{ (' ' + version) if version is defined else '' }}" "{{ (' ' + version_option) if version_option is defined else '' }}" - "{{ (' auth ' + authentication.algorithm) if authentication is defined and authentication.algorithm is defined else '' }}" - "{{ (' ' + authentication.password) if authentication is defined and authentication.password is defined else '' }}" - "{{ (' priv ' + encryption.priv) if encryption is defined and encryption.priv is defined else '' }}" - "{{ (' ' + encryption.priv_option) if encryption is defined and encryption.priv_option is defined else '' }}" - "{{ (' ' + encryption.password) if encryption is defined and encryption.password is defined else '' }}" - "{{ (' access ' + acl_v4|string) if acl_v4 is defined else '' }}" - "{{ (' access ipv6 ' + acl_v6) if acl_v6 is defined else '' }}" + "{% if authentication is defined and 'algorithm' in authentication and 'password' in authentication %}" + "{{ (' auth ' + authentication.algorithm + ' ' + authentication.password) }}" + "{% if encryption is defined and 'priv' in encryption and 'password' in encryption %}" + "{{ (' priv ' + encryption.priv) }}" + "{{ (' ' + encryption.priv_option) if 'priv_option' in encryption else '' }}" + "{{ (' ' + encryption.password) }}" + "{% endif %}" + "{% endif %}" + "{{ (' access') if acl_v6 is defined or acl_v4 is defined else '' }}" + "{{ (' ipv6 ' + acl_v6) if acl_v6 is defined else '' }}" + "{{ (' ' + acl_v4|string) if acl_v4 is defined else '' }}" "{{ (' vrf ' + vrf) if vrf is defined else '' }}", "result": { "users": [ @@ -464,7 +469,7 @@ class Snmp_serverTemplate(NetworkTemplate): "name": "if_index", "getval": re.compile( r""" - ^snmp-server\sifindex + ^snmp(-server|\sifmib)\sifindex (\s(?P<if_index>persist))? """, re.VERBOSE, ), @@ -501,7 +506,7 @@ class Snmp_serverTemplate(NetworkTemplate): r""" ^snmp-server\sip\sdscp (\s(?P<dscp>\d+))? - (\sprecedence(?P<precedence>\d+))? + (\sprecedence\s(?P<precedence>\d+))? """, re.VERBOSE, ), "setval": "snmp-server ip dscp " @@ -605,8 +610,22 @@ class Snmp_serverTemplate(NetworkTemplate): "trap_source": "{{ interface }}", }, }, - - { # only traps + # only traps + { + "name": "traps.aaa_server", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\saaa_server + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps aaa_server", + "result": { + "traps": { + "aaa_server": True, + }, + }, + }, + { "name": "traps.auth_framework", "getval": re.compile( r""" @@ -614,14 +633,13 @@ class Snmp_serverTemplate(NetworkTemplate): (\s(?P<sec_violation>sec-violation))? """, re.VERBOSE, ), - "setval": "snmp-server enable traps" - "{{ (' auth-framework') if traps.auth_framework.enable is defined else '' }}" - "{{ (' sec-violation') if traps.auth_framework.sec_violation is defined else '' }}", + "setval": "snmp-server enable traps auth-framework" + "{{ (' sec-violation') if traps.auth_framework.sec_violation|d(False) is defined else '' }}", "result": { "traps": { "auth_framework": { "enable": True, - "sec_violation": "{{ not not excluded }}", + "sec_violation": "{{ not not sec_violation }}", }, }, }, @@ -653,12 +671,11 @@ class Snmp_serverTemplate(NetworkTemplate): "getval": re.compile( r""" ^snmp-server\senable\straps\sbgp - (\s(?P<cbgp2>cbgp2))? (\s(?P<state_changes>state-changes))? (\s(?P<all>all))? (\s(?P<backward_trans>backward-trans))? (\s(?P<limited>limited))? - (\sthreshold(?P<prefix>prefix))? + (\sthreshold(?P<prefix>prefix))?\s*$ """, re.VERBOSE, ), "setval": cmd_option_trap_bgp, @@ -666,7 +683,6 @@ class Snmp_serverTemplate(NetworkTemplate): "result": { "traps": { "bgp": { - "cbgp2": "{{ not not cbgp2 }}", "enable": True, "state_changes": { "enable": "{{ not not state_changes }}", @@ -682,6 +698,22 @@ class Snmp_serverTemplate(NetworkTemplate): }, }, { + "name": "traps.bgp.cbgp2", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\sbgp\scbgp2 + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps bgp cbgp2", + "result": { + "traps": { + "bgp": { + "cbgp2": True, + }, + }, + }, + }, + { "name": "traps.bridge", "getval": re.compile( r""" @@ -704,6 +736,50 @@ class Snmp_serverTemplate(NetworkTemplate): }, }, { + "name": "traps.bulkstat", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\sbulkstat + (\s(?P<collection>collection))? + (\s(?P<transfer>transfer))? + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps bulkstat" + "{{ ' collection' if traps.bulkstat.collection|d(False) else '' }}" + "{{ ' transfer' if traps.bulkstat.transfer|d(False) else '' }}", + "result": { + "traps": { + "bulkstat": { + "enable": True, + "collection": "{{ not not collection }}", + "transfer": "{{ not not transfer }}", + }, + }, + }, + }, + { + "name": "traps.call_home", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\scall-home + (\s(?P<message_send_fail>message-send-fail))? + (\s(?P<server_fail>server-fail))? + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps call-home" + "{{ ' message-send-fail' if traps.call_home.message_send_fail|d(False) else '' }}" + "{{ ' server-fail' if traps.call_home.server_fail|d(False) else '' }}", + "result": { + "traps": { + "call_home": { + "enable": True, + "message_send_fail": "{{ not not message_send_fail }}", + "server_fail": "{{ not not server_fail }}", + }, + }, + }, + }, + { "name": "traps.casa", "getval": re.compile( r""" @@ -718,44 +794,58 @@ class Snmp_serverTemplate(NetworkTemplate): }, }, { - "name": "traps.cnpd", + "name": "traps.cef", "getval": re.compile( r""" - ^snmp-server\senable\straps\scnpd + ^snmp-server\senable\straps\scef + (\s(?P<resource_failure>resource-failure))? + (\s(?P<peer_state_change>peer-state-change))? + (\s(?P<peer_fib_state_change>peer-fib-state-change))? + (\s(?P<inconsistency>inconsistency))? """, re.VERBOSE, ), - "setval": "snmp-server enable traps cnpd", + "setval": "snmp-server enable traps cef" + "{{ ' resource-failure' if traps.cef.resource_failure|d(False) else '' }}" + "{{ ' peer-state-change' if traps.cef.peer_state_change|d(False) else '' }}" + "{{ ' peer-fib-state-change' if traps.cef.peer_fib_state_change|d(False) else '' }}" + "{{ ' inconsistency' if traps.cef.inconsistency|d(False) else '' }}", "result": { "traps": { - "cnpd": True, + "cef": { + "enable": True, + "inconsistency": "{{ not not inconsistency }}", + "peer_fib_state_change": "{{ not not peer_fib_state_change }}", + "peer_state_change": "{{ not not peer_state_change }}", + "resource_failure": "{{ not not resource_failure }}", + }, }, }, }, { - "name": "traps.config", + "name": "traps.cnpd", "getval": re.compile( r""" - ^snmp-server\senable\straps\sconfig + ^snmp-server\senable\straps\scnpd """, re.VERBOSE, ), - "setval": "snmp-server enable traps config", + "setval": "snmp-server enable traps cnpd", "result": { "traps": { - "config": True, + "cnpd": True, }, }, }, { - "name": "traps.isis", + "name": "traps.config", "getval": re.compile( r""" - ^snmp-server\senable\straps\sisis$ + ^snmp-server\senable\straps\sconfig\s*$ """, re.VERBOSE, ), - "setval": "snmp-server enable traps isis", + "setval": "snmp-server enable traps config", "result": { "traps": { - "isis": True, + "config": True, }, }, }, @@ -763,7 +853,7 @@ class Snmp_serverTemplate(NetworkTemplate): "name": "traps.config_copy", "getval": re.compile( r""" - ^snmp-server\senable\straps\sconfig-copy + ^snmp-server\senable\straps\s(config-copy|copy-config) """, re.VERBOSE, ), "setval": "snmp-server enable traps config-copy", @@ -788,6 +878,26 @@ class Snmp_serverTemplate(NetworkTemplate): }, }, { + "name": "traps.cpu", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\scpu + ((?P<threshold_old>_threshold))? + (\s(?P<threshold>threshold))? + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps cpu" + "{{ ' threshold' if traps.cpu.threshold|d(False) else '' }}", + "result": { + "traps": { + "cpu": { + "enable": True, + "threshold": "{{ not not threshold or not not threshold_old }}", + }, + }, + }, + }, + { "name": "traps.dhcp", "getval": re.compile( r""" @@ -802,6 +912,28 @@ class Snmp_serverTemplate(NetworkTemplate): }, }, { + "name": "traps.dlsw", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\sdlsw + (\s(?P<circuit>circuit))? + (\s(?P<tconn>tconn))? + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps dlsw" + "{{ ' circuit' if traps.dlsw.circuit|d(False) else '' }}" + "{{ ' tconn' if traps.dlsw.tconn|d(False) else '' }}", + "result": { + "traps": { + "dlsw": { + "enable": True, + "circuit": "{{ not not circuit }}", + "tconn": "{{ not not tconn }}", + }, + }, + }, + }, + { "name": "traps.eigrp", "getval": re.compile( r""" @@ -816,10 +948,24 @@ class Snmp_serverTemplate(NetworkTemplate): }, }, { + "name": "traps.energywise", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\senergywise$ + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps energywise", + "result": { + "traps": { + "energywise": True, + }, + }, + }, + { "name": "traps.entity", "getval": re.compile( r""" - ^snmp-server\senable\straps\sentity + ^snmp-server\senable\straps\sentity\s*$ """, re.VERBOSE, ), "setval": "snmp-server enable traps entity", @@ -830,16 +976,228 @@ class Snmp_serverTemplate(NetworkTemplate): }, }, { - "name": "traps.energywise", + "name": "traps.entity_diag", "getval": re.compile( r""" - ^snmp-server\senable\straps\senergywise$ + ^snmp-server\senable\straps\sentity-diag + (\s(?P<boot_up_fail>boot-up-fail))? + (\s(?P<hm_test_recover>hm-test-recover))? + (\s(?P<hm_thresh_reached>hm-thresh-reached))? + (\s(?P<scheduled_test_fail>scheduled-test-fail))? """, re.VERBOSE, ), - "setval": "snmp-server enable traps energywise", + "setval": "snmp-server enable traps entity-diag" + "{{ ' boot-up-fail' if traps.entity_diag.boot_up_fail|d(False) else '' }}" + "{{ ' hm-test-recover' if traps.entity_diag.hm_test_recover|d(False) else '' }}" + "{{ ' hm-thresh-reached' if traps.entity_diag.hm_thresh_reached|d(False) else '' }}" + "{{ ' scheduled-test-fail' if traps.entity_diag.scheduled_test_fail|d(False) else '' }}", "result": { "traps": { - "energywise": True, + "entity_diag": { + "enable": True, + "boot_up_fail": "{{ not not boot_up_fail }}", + "hm_test_recover": "{{ not not hm_test_recover }}", + "hm_thresh_reached": "{{ not not hm_thresh_reached }}", + "scheduled_test_fail": "{{ not not scheduled_test_fail }}", + }, + }, + }, + }, + { + "name": "traps.entity_perf", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\sentity-perf + (\s(?P<throughput_notif>throughput-notif))? + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps entity-perf" + "{{ ' throughput-notif' if traps.entity_perf.throughput_notif|d(False) else '' }}", + "result": { + "traps": { + "entity_perf": { + "enable": True, + "throughput_notif": "{{ not not throughput_notif }}", + }, + }, + }, + }, + { + "name": "traps.entity_state", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\sentity-state + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps entity-state", + "result": { + "traps": { + "entity_state": True, + }, + }, + }, + { + "name": "traps.envmon", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\senvmon + (\s(?P<fan>fan))? + (\s(?P<shutdown>shutdown))? + (\s(?P<supply>supply))? + (\s(?P<temperature>temperature))? + (\s(?P<status>status))? + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps envmon" + "{{ ' fan' if traps.envmon.fan_enable|d(False) else '' }}" + "{{ ' shutdown' if traps.envmon.shutdown|d(False) else '' }}" + "{{ ' supply' if traps.envmon.supply|d(False) else '' }}" + "{{ ' temperature' if traps.envmon.temperature|d(False) else '' }}" + "{{ ' status' if traps.envmon.status|d(False) else '' }}", + "result": { + "traps": { + "envmon": { + "enable": True, + "fan_enable": "{{ True if fan else False }}", + "shutdown": "{{ True if shutdown else False }}", + "supply": "{{ True if supply else False }}", + "temperature": "{{ True if temperature else False }}", + "status": "{{ True if status else False }}", + }, + }, + }, + }, + { + "name": "traps.errdisable", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\serrdisable + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps errdisable", + "result": { + "traps": { + "errdisable": True, + }, + }, + }, + { + "name": "traps.ether_oam", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\sether-oam + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps ether-oam", + "result": { + "traps": { + "ether_oam": True, + }, + }, + }, + { + "name": "traps.ethernet.cfm.alarm", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\sethernet\scfm\salarm + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps ethernet cfm alarm", + "result": { + "traps": { + "ethernet": { + "cfm": { + "alarm": True, + }, + }, + }, + }, + }, + { + "name": "traps.ethernet.cfm.cc", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\sethernet\scfm\scc + (\s(?P<mep_up>mep-up))? + (\s(?P<mep_down>mep-down))? + (\s(?P<cross_connect>cross-connect))? + (\s(?P<loop>loop))? + (\s(?P<config>config))? + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps ethernet cfm cc" + "{{ ' mep-up' if traps.ethernet.cfm.cc.mep_up|d(False) else ''}}" + "{{ ' mep-down' if traps.ethernet.cfm.cc.mep_down|d(False) else ''}}" + "{{ ' cross-connect' if traps.ethernet.cfm.cc.cross_connect|d(False) else ''}}" + "{{ ' loop' if traps.ethernet.cfm.cc.loop|d(False) else ''}}" + "{{ ' config' if traps.ethernet.cfm.cc.config|d(False) else ''}}", + "result": { + "traps": { + "ethernet": { + "cfm": { + "cc": { + "mep_up": "{{ not not mep_up }}", + "mep_down": "{{ not not mep_down }}", + "cross_connect": "{{ not not cross_connect }}", + "loop": "{{ not not loop }}", + "config": "{{ not not config }}", + }, + }, + }, + }, + }, + }, + { + "name": "traps.ethernet.cfm.crosscheck", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\sethernet\scfm\scrosscheck + (\s(?P<mep_missing>mep-missing))? + (\s(?P<mep_unknown>mep-unknown))? + (\s(?P<service_up>service-up))? + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps ethernet cfm crosscheck" + "{{ ' mep-missing' if traps.ethernet.cfm.crosscheck.mep_missing|d(False) else ''}}" + "{{ ' mep-unknown' if traps.ethernet.cfm.crosscheck.mep_unknown|d(False) else ''}}" + "{{ ' service-up' if traps.ethernet.cfm.crosscheck.service_up|d(False) else ''}}", + "result": { + "traps": { + "ethernet": { + "cfm": { + "crosscheck": { + "mep_missing": "{{ not not mep_missing }}", + "mep_unknown": "{{ not not mep_unknown }}", + "service_up": "{{ not not service_up }}", + }, + }, + }, + }, + }, + }, + { + "name": "traps.ethernet.evc", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\sethernet\sevc + (\s(?P<status>status))? + (\s(?P<create>create))? + (\s(?P<delete>delete))? + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps ethernet evc" + "{{ ' status' if traps.ethernet.evc.status|d(False) else ''}}" + "{{ ' create' if traps.ethernet.evc.create|d(False) else ''}}" + "{{ ' delete' if traps.ethernet.evc.delete|d(False) else ''}}", + "result": { + "traps": { + "ethernet": { + "evc": { + "create": "{{ not not create }}", + "delete": "{{ not not delete }}", + "status": "{{ not not status }}", + }, + }, }, }, }, @@ -858,6 +1216,69 @@ class Snmp_serverTemplate(NetworkTemplate): }, }, { + "name": "traps.flash", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\sflash + (\s(?P<insertion>insertion))? + (\s(?P<removal>removal))? + (\s(?P<lowspace>lowspace))? + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps flash" + "{{ ' insertion' if traps.flash.insertion|d(False) else '' }}" + "{{ ' removal' if traps.flash.removal|d(False) else '' }}" + "{{ ' lowspace' if traps.flash.lowspace|d(False) else '' }}", + "result": { + "traps": { + "flash": { + "enable": True, + "insertion": "{{ not not insertion }}", + "removal": "{{ not not removal }}", + "lowspace": "{{ not not lowspace }}", + }, + }, + }, + }, + { + "name": "traps.flex_links", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\sflex-links + (\s(?P<status>status))? + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps flex-links" + "{{ ' status' if traps.flex_links.status|d(False) else '' }}", + "result": { + "traps": { + "flex_links": { + "enable": True, + "status": "{{ not not status }}", + }, + }, + }, + }, + { + "name": "traps.firewall", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\sfirewall + (\s(?P<serverstatus>serverstatus))? + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps firewall" + "{{ ' serverstatus' if traps.firewall.serverstatus|d(False) else '' }}", + "result": { + "traps": { + "firewall": { + "enable": True, + "serverstatus": "{{ not not serverstatus }}", + }, + }, + }, + }, + { "name": "traps.flowmon", "getval": re.compile( r""" @@ -872,6 +1293,46 @@ class Snmp_serverTemplate(NetworkTemplate): }, }, { + "name": "traps.frame_relay", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\s(framerelay|frame-relay)$ + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps frame-relay", + "result": { + "traps": { + "frame_relay": { + "enable": True, + }, + }, + }, + }, + { + "name": "traps.frame_relay.subif", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\sframe-relay\ssubif + (\sinterval(?P<interval>\d+))? + (\scount(?P<count>\d+))? + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps frame-relay subif" + "{{ ' interval ' + interval|string if traps.frame_relay.subif.interval|d(False) else '' }}" + "{{ ' count ' + count|string if traps.frame_relay.subif.count|d(False) else '' }}", + "result": { + "traps": { + "frame_relay": { + "subif": { + "enable": "{{ not not subif }}", + "interval": "{{ interval }}", + "count": "{{ count }}", + }, + }, + }, + }, + }, + { "name": "traps.fru_ctrl", "getval": re.compile( r""" @@ -900,519 +1361,720 @@ class Snmp_serverTemplate(NetworkTemplate): }, }, { - "name": "traps.ipsla", + "name": "traps.ike.policy.add", "getval": re.compile( r""" - ^snmp-server\senable\straps\sipsla + ^snmp-server\senable\straps\sike\spolicy\sadd """, re.VERBOSE, ), - "setval": "snmp-server enable traps ipsla", + "setval": "snmp-server enable traps ike policy add", "result": { "traps": { - "ipsla": True, + "ike": { + "policy": { + "add": True, + }, + }, }, }, }, { - "name": "traps.msdp", + "name": "traps.ike.policy.delete", "getval": re.compile( r""" - ^snmp-server\senable\straps\smsdp$ + ^snmp-server\senable\straps\sike\spolicy\sdelete """, re.VERBOSE, ), - "setval": "snmp-server enable traps msdp", + "setval": "snmp-server enable traps ike policy delete", "result": { "traps": { - "msdp": True, + "ike": { + "policy": { + "delete": True, + }, + }, }, }, }, { - "name": "traps.pw_vc", + "name": "traps.ike.tunnel.start", "getval": re.compile( r""" - ^snmp-server\senable\straps\spw\svc$ + ^snmp-server\senable\straps\sike\stunnel\sstart """, re.VERBOSE, ), - "setval": "snmp-server enable traps pw vc", + "setval": "snmp-server enable traps ike tunnel start", "result": { "traps": { - "pw_vc": True, + "ike": { + "tunnel": { + "start": True, + }, + }, }, }, }, { - "name": "traps.mvpn", + "name": "traps.ike.tunnel.stop", "getval": re.compile( r""" - ^snmp-server\senable\straps\smvpn + ^snmp-server\senable\straps\sike\stunnel\sstop """, re.VERBOSE, ), - "setval": "snmp-server enable traps mvpn", + "setval": "snmp-server enable traps ike tunnel stop", "result": { "traps": { - "mvpn": True, + "ike": { + "tunnel": { + "stop": True, + }, + }, }, }, }, { - "name": "traps.mpls_vpn", + "name": "traps.ipmulticast", "getval": re.compile( r""" - ^snmp-server\senable\straps\smpls\svpn + ^snmp-server\senable\straps\sipmulticast """, re.VERBOSE, ), - "setval": "snmp-server enable traps mpls vpn", + "setval": "snmp-server enable traps ipmulticast", "result": { "traps": { - "mpls_vpn": True, + "ipmulticast": True, }, }, }, { - "name": "traps.pki", + "name": "traps.ipsec.cryptomap.add", "getval": re.compile( r""" - ^snmp-server\senable\straps\spki + ^snmp-server\senable\straps\sipsec\scryptomap\sadd """, re.VERBOSE, ), - "setval": "snmp-server enable traps pki", + "setval": "snmp-server enable traps ipsec cryptomap add", "result": { "traps": { - "pki": True, + "ipsec": { + "cryptomap": { + "add": True, + }, + }, }, }, }, { - "name": "traps.rsvp", + "name": "traps.ipsec.cryptomap.attach", "getval": re.compile( r""" - ^snmp-server\senable\straps\srsvp + ^snmp-server\senable\straps\sipsec\scryptomap\sattach """, re.VERBOSE, ), - "setval": "snmp-server enable traps rsvp", + "setval": "snmp-server enable traps ipsec cryptomap attach", "result": { "traps": { - "rsvp": True, + "ipsec": { + "cryptomap": { + "attach": True, + }, + }, }, }, }, { - "name": "traps.syslog", + "name": "traps.ipsec.cryptomap.delete", "getval": re.compile( r""" - ^snmp-server\senable\straps\ssyslog + ^snmp-server\senable\straps\sipsec\scryptomap\sdelete """, re.VERBOSE, ), - "setval": "snmp-server enable traps syslog", + "setval": "snmp-server enable traps ipsec cryptomap delete", "result": { "traps": { - "syslog": True, + "ipsec": { + "cryptomap": { + "delete": True, + }, + }, }, }, }, { - "name": "traps.transceiver_all", + "name": "traps.ipsec.cryptomap.detach", "getval": re.compile( r""" - ^snmp-server\senable\straps\stransceiver\sall + ^snmp-server\senable\straps\sipsec\scryptomap\sdetach """, re.VERBOSE, ), - "setval": "snmp-server enable traps transceiver all", + "setval": "snmp-server enable traps ipsec cryptomap detach", "result": { "traps": { - "transceiver_all": True, + "ipsec": { + "cryptomap": { + "detach": True, + }, + }, }, }, }, { - "name": "traps.tty", + "name": "traps.ipsec.too_many_sas", "getval": re.compile( r""" - ^snmp-server\senable\straps\stty + ^snmp-server\senable\straps\sipsec\stoo-many-sas """, re.VERBOSE, ), - "setval": "snmp-server enable traps tty", + "setval": "snmp-server enable traps ipsec too-many-sas", "result": { "traps": { - "tty": True, + "ipsec": { + "too_many_sas": True, + }, }, }, }, { - "name": "traps.envmon.shutdown", + "name": "traps.ipsec.tunnel.start", "getval": re.compile( r""" - ^snmp-server\senable\straps\senvmon\sshutdown$ + ^snmp-server\senable\straps\sipsec\stunnel\sstart """, re.VERBOSE, ), - "setval": "snmp-server enable traps envmon shutdown", + "setval": "snmp-server enable traps ipsec tunnel start", "result": { "traps": { - "envmon": { - "shutdown": True, + "ipsec": { + "tunnel": { + "start": True, + }, }, }, }, }, { - "name": "traps.envmon.status", + "name": "traps.ipsec.tunnel.stop", "getval": re.compile( r""" - ^snmp-server\senable\straps\senvmon\sstatus$ + ^snmp-server\senable\straps\sipsec\stunnel\sstop """, re.VERBOSE, ), - "setval": "snmp-server enable traps envmon status", + "setval": "snmp-server enable traps ipsec tunnel stop", "result": { "traps": { - "envmon": { - "status": True, + "ipsec": { + "tunnel": { + "stop": True, + }, }, }, }, }, { - "name": "traps.envmon.supply", + "name": "traps.ipsla", "getval": re.compile( r""" - ^snmp-server\senable\straps\senvmon\ssupply$ + ^snmp-server\senable\straps\sipsla """, re.VERBOSE, ), - "setval": "snmp-server enable traps envmon supply", + "setval": "snmp-server enable traps ipsla", "result": { "traps": { - "envmon": { - "supply": True, - }, + "ipsla": True, }, }, }, { - "name": "traps.envmon.temperature", + "name": "traps.isis", "getval": re.compile( r""" - ^snmp-server\senable\straps\senvmon\stemperature$ + ^snmp-server\senable\straps\sisis$ """, re.VERBOSE, ), - "setval": "snmp-server enable traps envmon temperature", + "setval": "snmp-server enable traps isis", "result": { "traps": { - "envmon": { - "temperature": True, - }, + "isis": True, }, }, }, { - "name": "traps.envmon.fan.enable", + "name": "traps.l2tc", "getval": re.compile( r""" - ^snmp-server\senable\straps\senvmon\sfan$ + ^snmp-server\senable\straps\sl2tc + (\s(?P<threshold>threshold))? + (\s(?P<sys_threshold>sys-threshold))? """, re.VERBOSE, ), - "setval": "snmp-server enable traps envmon fan", + "setval": "snmp-server enable traps l2tc" + "{{ ' threshold' if traps.l2tc.threshold|d(False) else '' }}" + "{{ ' sys-threshold' if traps.l2tc.sys_threshold|d(False) else '' }}", "result": { "traps": { - "envmon": { - "fan": { - "enable": True, - }, + "l2tc": { + "enable": True, + "sys_threshold": "{{ not not sys_threshold }}", + "threshold": "{{ not not threshold }}", }, }, }, }, { - "name": "traps.envmon.fan.shutdown", + "name": "traps.l2tun.pseudowire_status", "getval": re.compile( r""" - ^snmp-server\senable\straps\senvmon\sfan\sshutdown$ + ^snmp-server\senable\straps\sl2tun\spseudowire\sstatus + (\s(?P<pseudowire_status>))? """, re.VERBOSE, ), - "setval": "snmp-server enable traps envmon fan shutdown", + "setval": "snmp-server enable traps l2tun pseudowire status", "result": { "traps": { - "envmon": { - "fan": { - "shutdown": True, - }, + "l2tun": { + "pseudowire_status": True, }, }, }, }, { - "name": "traps.envmon.fan.status", + "name": "traps.l2tun.session", "getval": re.compile( r""" - ^snmp-server\senable\straps\senvmon\sfan\sstatus$ + ^snmp-server\senable\straps\sl2tun\ssession """, re.VERBOSE, ), - "setval": "snmp-server enable traps envmon fan status", + "setval": "snmp-server enable traps l2tun session", "result": { "traps": { - "envmon": { - "fan": { - "status": True, - }, + "l2tun": { + "session": True, }, }, }, }, { - "name": "traps.envmon.fan.supply", + "name": "traps.license", "getval": re.compile( r""" - ^snmp-server\senable\straps\senvmon\sfan\ssupply$ + ^snmp-server\senable\straps\slicense """, re.VERBOSE, ), - "setval": "snmp-server enable traps envmon fan supply", + "setval": "snmp-server enable traps license", "result": { "traps": { - "envmon": { - "fan": { - "supply": True, - }, - }, + "license": True, }, }, }, { - "name": "traps.envmon.fan.temperature", + "name": "traps.lisp", "getval": re.compile( r""" - ^snmp-server\senable\straps\senvmon\sfan\stemperature$ + ^snmp-server\senable\straps\slisp """, re.VERBOSE, ), - "setval": "snmp-server enable traps envmon fan temperature", + "setval": "snmp-server enable traps lisp", "result": { "traps": { - "envmon": { - "fan": { - "temperature": True, - }, - }, + "lisp": True, }, }, }, { - "name": "traps.vrrp", + "name": "traps.local_auth", "getval": re.compile( r""" - ^snmp-server\senable\straps\svrrp + ^snmp-server\senable\straps\slocal-auth """, re.VERBOSE, ), - "setval": "snmp-server enable traps vrrp", + "setval": "snmp-server enable traps local-auth", "result": { "traps": { - "vrrp": True, + "local_auth": True, }, }, }, { - "name": "traps.ipmulticast", + "name": "traps.mac_notification", "getval": re.compile( r""" - ^snmp-server\senable\straps\sipmulticast + ^snmp-server\senable\straps\smac-notification + (\s(?P<change>change))? + (\s(?P<move>move))? + (\s(?P<threshold>threshold))? """, re.VERBOSE, ), - "setval": "snmp-server enable traps ipmulticast", + "setval": "snmp-server enable traps mac-notification" + "{{ ' change' if traps.mac_notification.change|d(False) else '' }}" + "{{ ' move' if traps.mac_notification.move|d(False) else '' }}" + "{{ ' threshold' if traps.mac_notification.threshold|d(False) else '' }}", "result": { "traps": { - "ipmulticast": True, + "mac_notification": { + "enable": True, + "change": "{{ not not change }}", + "move": "{{ not not move }}", + "threshold": "{{ not not threshold }}", + }, }, }, }, { - "name": "traps.ike.policy.add", + "name": "traps.memory", "getval": re.compile( r""" - ^snmp-server\senable\straps\sike\spolicy\sadd + ^snmp-server\senable\straps\smemory + (\s(?P<bufferpeak>bufferpeak))? """, re.VERBOSE, ), - "setval": "snmp-server enable traps ike policy add", + "setval": "snmp-server enable traps memory" + "{{ ' bufferpeak' if traps.memory.bufferpeak|d(False) else '' }}", "result": { "traps": { - "ike": { - "policy": { - "add": True, - }, + "memory": { + "enable": True, + "bufferpeak": "{{ not not bufferpeak }}", }, }, }, }, { - "name": "traps.ike.policy.delete", + "name": "traps.mpls.fast_reroute", "getval": re.compile( r""" - ^snmp-server\senable\straps\sike\spolicy\sdelete + ^snmp-server\senable\straps\smpls\sfast-reroute + (\s(?P<protected>protected))? """, re.VERBOSE, ), - "setval": "snmp-server enable traps ike policy delete", + "setval": "snmp-server enable traps mpls fast-reroute" + "{{ ' protected' if traps.mpls.fast_reroute.protected|d(False) else '' }}", "result": { "traps": { - "ike": { - "policy": { - "delete": True, + "mpls": { + "fast_reroute": { + "enable": True, + "protected": "{{ not not protected }}", }, }, }, }, }, { - "name": "traps.ike.tunnel.start", + "name": "traps.mpls.ldp", "getval": re.compile( r""" - ^snmp-server\senable\straps\sike\stunnel\sstart + ^snmp-server\senable\straps\smpls\sldp + (\s(?P<pv_limit>pv-limit))? + (\s(?P<session_down>session-down))? + (\s(?P<session_up>session-up))? + (\s(?P<threshold>threshold))? """, re.VERBOSE, ), - "setval": "snmp-server enable traps ike tunnel start", + "setval": "snmp-server enable traps mpls ldp" + "{{ ' pv-limit' if traps.mpls.ldp.pv_limit|d(False) else '' }}" + "{{ ' session-down' if traps.mpls.ldp.session_down|d(False) else '' }}" + "{{ ' session-up' if traps.mpls.ldp.session_up|d(False) else '' }}" + "{{ ' threshold' if traps.mpls.ldp.threshold|d(False) else '' }}", "result": { "traps": { - "ike": { - "tunnel": { - "start": True, + "mpls": { + "ldp": { + "enable": True, + "pv_limit": "{{ not not pv_limit }}", + "session_down": "{{ not not session_down }}", + "session_up": "{{ not not session_up }}", + "threshold": "{{ not not threshold }}", }, }, }, }, }, { - "name": "traps.ike.tunnel.stop", + "name": "traps.mpls.rfc.ldp", "getval": re.compile( r""" - ^snmp-server\senable\straps\sike\stunnel\sstop + ^snmp-server\senable\straps\smpls\srfc\sldp + (\s(?P<pv_limit>pv-limit))? + (\s(?P<session_down>session-down))? + (\s(?P<session_up>session-up))? + (\s(?P<threshold>threshold))? """, re.VERBOSE, ), - "setval": "snmp-server enable traps ike tunnel stop", + "setval": "snmp-server enable traps mpls rfc ldp" + "{{ ' pv-limit' if traps.mpls.rfc.ldp.pv_limit|d(False) else '' }}" + "{{ ' session-down' if traps.mpls.rfc.ldp.session_down|d(False) else '' }}" + "{{ ' session-up' if traps.mpls.rfc.ldp.session_up|d(False) else '' }}" + "{{ ' threshold' if traps.mpls.rfc.ldp.threshold|d(False) else '' }}", "result": { "traps": { - "ike": { - "tunnel": { - "stop": True, + "mpls": { + "rfc": { + "ldp": { + "enable": True, + "pv_limit": "{{ not not pv_limit }}", + "session_down": "{{ not not session_down }}", + "session_up": "{{ not not session_up }}", + "threshold": "{{ not not threshold }}", + }, }, }, }, }, }, { - "name": "traps.ipsec.cryptomap.add", + "name": "traps.mpls.rfc.traffic_eng", "getval": re.compile( r""" - ^snmp-server\senable\straps\sipsec\scryptomap\sadd + ^snmp-server\senable\straps\smpls\srfc\straffic-eng + (\s(?P<down>down))? + (\s(?P<reoptimized>reoptimized))? + (\s(?P<reroute>reroute))? + (\s(?P<up>up))? """, re.VERBOSE, ), - "setval": "snmp-server enable traps ipsec cryptomap add", + "setval": "snmp-server enable traps mpls rfc traffic-eng" + "{{ ' down' if traps.mpls.rfc.traffic_eng.down|d(False) else '' }}" + "{{ ' reoptimized' if traps.mpls.rfc.traffic_eng.reoptimized|d(False) else '' }}" + "{{ ' reroute' if traps.mpls.rfc.traffic_eng.reroute|d(False) else '' }}" + "{{ ' up' if traps.mpls.rfc.traffic_eng.up|d(False) else '' }}", "result": { "traps": { - "ipsec": { - "cryptomap": { - "add": True, + "mpls": { + "rfc": { + "traffic_eng": { + "enable": True, + "down": "{{ not not down }}", + "reoptimized": "{{ not not reoptimized }}", + "reroute": "{{ not not reroute }}", + "up": "{{ not not up }}", + }, }, }, }, }, }, { - "name": "traps.ipsec.cryptomap.delete", + "name": "traps.mpls.rfc.vpn", "getval": re.compile( r""" - ^snmp-server\senable\straps\sipsec\scryptomap\sdelete + ^snmp-server\senable\straps\smpls\srfc\svpn + (\s(?P<illegal_label>illegal-label))? + (\s(?P<max_thresh_cleared>max-thresh-cleared))? + (\s(?P<max_threshold>max-threshold))? + (\s(?P<mid_threshold>mid-threshold))? + (\s(?P<vrf_down>vrf-down))? + (\s(?P<vrf_up>vrf-up))? """, re.VERBOSE, ), - "setval": "snmp-server enable traps ipsec cryptomap delete", + "setval": "snmp-server enable traps mpls rfc vpn" + "{{ ' illegal-label' if traps.mpls.rfc.vpn.illegal_label|d(False) else '' }}" + "{{ ' max-thresh-cleared' if traps.mpls.rfc.vpn.max_thresh_cleared|d(False) else '' }}" + "{{ ' max-threshold' if traps.mpls.rfc.vpn.max_threshold|d(False) else '' }}" + "{{ ' mid-threshold' if traps.mpls.rfc.vpn.mid_threshold|d(False) else '' }}" + "{{ ' vrf-down' if traps.mpls.rfc.vpn.vrf_down|d(False) else '' }}" + "{{ ' vrf-up' if traps.mpls.rfc.vpn.vrf_up|d(False) else '' }}", + "result": { + "traps": { + "mpls": { + "rfc": { + "vpn": { + "enable": True, + "illegal_label": "{{ not not illegal_label }}", + "max_thresh_cleared": "{{ not not max_thresh_cleared }}", + "max_threshold": "{{ not not max_threshold }}", + "mid_threshold": "{{ not not mid_threshold }}", + "vrf_down": "{{ not not vrf_down }}", + "vrf_up": "{{ not not vrf_up }}", + }, + }, + }, + }, + }, + }, + { + "name": "traps.mpls.traffic_eng", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\smpls\straffic-eng + (\s(?P<down>down))? + (\s(?P<reroute>reroute))? + (\s(?P<up>up))? + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps mpls traffic-eng" + "{{ ' down' if traps.mpls.traffic_eng.down|d(False) else '' }}" + "{{ ' reroute' if traps.mpls.traffic_eng.reroute|d(False) else '' }}" + "{{ ' up' if traps.mpls.traffic_eng.up|d(False) else '' }}", "result": { "traps": { - "ipsec": { - "cryptomap": { - "delete": True, + "mpls": { + "traffic_eng": { + "enable": True, + "down": "{{ not not down }}", + "reroute": "{{ not not reroute }}", + "up": "{{ not not up }}", }, }, }, }, }, { - "name": "traps.ipsec.cryptomap.attach", + "name": "traps.mpls.vpn", "getval": re.compile( r""" - ^snmp-server\senable\straps\sipsec\scryptomap\sattach + ^snmp-server\senable\straps\smpls(-|\s)vpn + (\s(?P<illegal_label>illegal-label))? + (\s(?P<max_thresh_cleared>max-thresh-cleared))? + (\s(?P<max_threshold>max-threshold))? + (\s(?P<mid_threshold>mid-threshold))? + (\s(?P<vrf_down>vrf-down))? + (\s(?P<vrf_up>vrf-up))? """, re.VERBOSE, ), - "setval": "snmp-server enable traps ipsec cryptomap attach", + "setval": "{% if 'vpn' in traps.mpls and traps.mpls.vpn.enable %}" + "snmp-server enable traps mpls vpn" + "{{ ' illegal-label' if traps.mpls.vpn.illegal_label|d(False) else '' }}" + "{{ ' max-thresh-cleared' if traps.mpls.vpn.max_thresh_cleared|d(False) else '' }}" + "{{ ' max-threshold' if traps.mpls.vpn.max_threshold|d(False) else '' }}" + "{{ ' mid-threshold' if traps.mpls.vpn.mid_threshold|d(False) else '' }}" + "{{ ' vrf-down' if traps.mpls.vpn.vrf_down|d(False) else '' }}" + "{{ ' vrf-up' if traps.mpls.vpn.vrf_up|d(False) else '' }}" + "{% endif %}", "result": { "traps": { - "ipsec": { - "cryptomap": { - "attach": True, + "mpls": { + "vpn": { + "enable": True, + "illegal_label": "{{ not not illegal_label }}", + "max_thresh_cleared": "{{ not not max_thresh_cleared }}", + "max_threshold": "{{ not not max_threshold }}", + "mid_threshold": "{{ not not mid_threshold }}", + "vrf_down": "{{ not not vrf_down }}", + "vrf_up": "{{ not not vrf_up }}", }, }, }, }, }, { - "name": "traps.ipsec.cryptomap.detach", + "name": "traps.msdp", "getval": re.compile( r""" - ^snmp-server\senable\straps\sipsec\scryptomap\sdetach + ^snmp-server\senable\straps\smsdp$ """, re.VERBOSE, ), - "setval": "snmp-server enable traps ipsec cryptomap detach", + "setval": "snmp-server enable traps msdp", "result": { "traps": { - "ipsec": { - "cryptomap": { - "detach": True, + "msdp": True, + }, + }, + }, + { + "name": "traps.mvpn", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\smvpn + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps mvpn", + "result": { + "traps": { + "mvpn": True, + }, + }, + }, + { + "name": "traps.nhrp.nhc", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\snhrp\snhc + (\s(?P<down>down))? + (\s(?P<up>up))? + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps nhrp nhc" + "{{ ' down' if traps.nhrp.nhc.down|d(False) else '' }}" + "{{ ' up' if traps.nhrp.nhc.up|d(False) else '' }}", + "result": { + "traps": { + "nhrp": { + "enable": True, + "nhc": { + "enable": True, + "down": "{{ not not down }}", + "up": "{{ not not up }}", }, }, }, }, }, { - "name": "traps.ipsec.tunnel.start", + "name": "traps.nhrp.nhp", "getval": re.compile( r""" - ^snmp-server\senable\straps\sipsec\stunnel\sstart + ^snmp-server\senable\straps\snhrp\snhp + (\s(?P<down>down))? + (\s(?P<up>up))? """, re.VERBOSE, ), - "setval": "snmp-server enable traps ipsec tunnel start", + "setval": "snmp-server enable traps nhrp nhp" + "{{ ' down' if traps.nhrp.nhc.down|d(False) else '' }}" + "{{ ' up' if traps.nhrp.nhc.up|d(False) else '' }}", "result": { "traps": { - "ipsec": { - "tunnel": { - "start": True, + "nhrp": { + "enable": True, + "nhp": { + "enable": True, + "down": "{{ not not down }}", + "up": "{{ not not up }}", }, }, }, }, }, { - "name": "traps.ipsec.tunnel.stop", + "name": "traps.nhrp.nhs", "getval": re.compile( r""" - ^snmp-server\senable\straps\sipsec\stunnel\sstop + ^snmp-server\senable\straps\snhrp\snhs + (\s(?P<down>down))? + (\s(?P<up>up))? """, re.VERBOSE, ), - "setval": "snmp-server enable traps ipsec tunnel stop", + "setval": "snmp-server enable traps nhrp nhs" + "{{ ' down' if traps.nhrp.nhc.down|d(False) else '' }}" + "{{ ' up' if traps.nhrp.nhc.up|d(False) else '' }}", "result": { "traps": { - "ipsec": { - "tunnel": { - "stop": True, + "nhrp": { + "enable": True, + "nhs": { + "enable": True, + "down": "{{ not not down }}", + "up": "{{ not not up }}", }, }, }, }, }, { - "name": "traps.ipsec.too_many_sas", + "name": "traps.nhrp.quota_exceeded", "getval": re.compile( r""" - ^snmp-server\senable\straps\sipsec\stoo-many-sas + ^snmp-server\senable\straps\snhrp + (\s(?P<quota_exceeded>quota-exceeded))?$ """, re.VERBOSE, ), - "setval": "snmp-server enable traps ipsec too-many-sas", + "setval": "snmp-server enable traps nhrp" + "{{ ' quota-exceeded' if traps.nhrp.quota_exceeded|d(False) else '' }}", "result": { "traps": { - "ipsec": { - "too_many_sas": True, + "nhrp": { + "enable": True, + "quota_exceeded": "{{ not not quota_exceeded }}", }, }, }, @@ -1436,36 +2098,36 @@ class Snmp_serverTemplate(NetworkTemplate): }, }, { - "name": "traps.ospf.cisco_specific.retransmit", + "name": "traps.ospf.cisco_specific.lsa", "getval": re.compile( r""" - ^snmp-server\senable\straps\sospf\scisco-specific\sretransmit + ^snmp-server\senable\straps\sospf\scisco-specific\slsa """, re.VERBOSE, ), - "setval": "snmp-server enable traps ospf cisco-specific retransmit", + "setval": "snmp-server enable traps ospf cisco-specific lsa", "result": { "traps": { "ospf": { "cisco_specific": { - "retransmit": True, + "lsa": True, }, }, }, }, }, { - "name": "traps.ospf.cisco_specific.lsa", + "name": "traps.ospf.cisco_specific.retransmit", "getval": re.compile( r""" - ^snmp-server\senable\straps\sospf\scisco-specific\slsa + ^snmp-server\senable\straps\sospf\scisco-specific\sretransmit """, re.VERBOSE, ), - "setval": "snmp-server enable traps ospf cisco-specific lsa", + "setval": "snmp-server enable traps ospf cisco-specific retransmit", "result": { "traps": { "ospf": { "cisco_specific": { - "lsa": True, + "retransmit": True, }, }, }, @@ -1552,33 +2214,33 @@ class Snmp_serverTemplate(NetworkTemplate): }, }, { - "name": "traps.ospf.retransmit", + "name": "traps.ospf.lsa", "getval": re.compile( r""" - ^snmp-server\senable\straps\sospf\sretransmit + ^snmp-server\senable\straps\sospf\slsa """, re.VERBOSE, ), - "setval": "snmp-server enable traps ospf retransmit", + "setval": "snmp-server enable traps ospf lsa", "result": { "traps": { "ospf": { - "retransmit": True, + "lsa": True, }, }, }, }, { - "name": "traps.ospf.lsa", + "name": "traps.ospf.retransmit", "getval": re.compile( r""" - ^snmp-server\senable\straps\sospf\slsa + ^snmp-server\senable\straps\sospf\sretransmit """, re.VERBOSE, ), - "setval": "snmp-server enable traps ospf lsa", + "setval": "snmp-server enable traps ospf retransmit", "result": { "traps": { "ospf": { - "lsa": True, + "retransmit": True, }, }, }, @@ -1600,72 +2262,91 @@ class Snmp_serverTemplate(NetworkTemplate): }, }, { - "name": "traps.l2tun.pseudowire_status", - "getval": re.compile( - r""" - ^snmp-server\senable\straps\sl2tun\spseudowire\sstatus - (\s(?P<pseudowire_status>))? - """, re.VERBOSE, - ), - "setval": "snmp-server enable traps l2tun pseudowire status", - "result": { - "traps": { - "l2tun": { - "pseudowire_status": True, - }, - }, - }, - }, - { - "name": "traps.l2tun.session", + "name": "traps.ospfv3.errors", "getval": re.compile( r""" - ^snmp-server\senable\straps\sl2tun\ssession + ^snmp-server\senable\straps\sospfv3\serrors + (\s(?P<bad_packet>bad-packet))? + (\s(?P<config_error>config-error))? + (\s(?P<virt_bad_packet>virt-bad-packet))? + (\s(?P<virt_config_error>virt-config-error))? """, re.VERBOSE, ), - "setval": "snmp-server enable traps l2tun session", + "setval": "snmp-server enable traps ospfv3 errors" + "{{ ' bad-packet' if traps.ospfv3.errors.bad_packet|d(False) else '' }}" + "{{ ' config-error' if traps.ospfv3.errors.config_error|d(False) else '' }}" + "{{ ' virt-bad-packet' if traps.ospfv3.errors.virt_bad_packet|d(False) else '' }}" + "{{ ' virt-config-error' if traps.ospfv3.errors.virt_config_error|d(False) else '' }}", "result": { "traps": { - "l2tun": { - "session": True, + "ospfv3": { + "errors": { + "enable": True, + "bad_packet": "{{ not not bad_packet }}", + "config_error": "{{ not not config_error }}", + "virt_bad_packet": "{{ not not virt_bad_packet }}", + "virt_config_error": "{{ not not virt_config_error }}", + }, }, }, }, }, { - "name": "traps.cpu", + "name": "traps.ospfv3.rate_limit", "getval": re.compile( r""" - ^snmp-server\senable\straps\scpu - (\s(?P<threshold>threshold))? + ^snmp-server\senable\straps\sospfv3\srate-limit + (\s(?P<rate_limit>[0-9]+))? """, re.VERBOSE, ), - "setval": "{{ 'snmp-server enable traps cpu' if traps.cpu.enable is defined else '' }}" - "{{ ' threshold' if traps.cpu.threshold is defined else '' }}", + "setval": "snmp-server enable traps ospfv3 rate_limit" + "{{ traps.ospfv3.rate_limit|int if traps.ospfv3.rate_limit|int > 0 else '' }}", "result": { "traps": { - "cpu": { - "enable": True, - "threshold": "{{ not not threshold }}", + "ospfv3": { + "rate_limit": "{{ rate_limit if rate_limit|int >=2 or rate_limit|int <= 60 }}", }, }, }, }, { - "name": "traps.firewall", + "name": "traps.ospfv3.state_change", "getval": re.compile( r""" - ^snmp-server\senable\straps\sfirewall - (\s(?P<serverstatus>serverstatus))? + ^snmp-server\senable\straps\sospfv3\sstate-change + (\s(?P<if_state_change>if-state-change))? + (\s(?P<neighbor_restart_helper_status_change>neighbor-restart-helper-status-change))? + (\s(?P<neighbor_state_change>neighbor-state-change))? + (\s(?P<nssa_translator_status_change>nssa-translator-status-change))? + (\s(?P<restart_status_change>restart-status-change))? + (\s(?P<virtif_state_change>virtif-state-change))? + (\s(?P<virtneighbor_restart_helper_status_change>virtneighbor-restart-helper-status-change))? + (\s(?P<virtneighbor_state_change>virtneighbor-state-change))? """, re.VERBOSE, ), - "setval": "{{ 'snmp-server enable traps firewall' if traps.firewall.enable is defined else '' }}" - "{{ ' serverstatus' if traps.firewall.serverstatus|d(False) else ''}}", + "setval": "snmp-server enable traps ospfv3 state-change" + "{{ ' if-state-change' if traps.ospfv3.state_change.if_state_change|d(False) else '' }}" + "{{ ' neighbor-restart-helper-status-change' if traps.ospfv3.state_change.neighbor_restart_helper_status_change|d(False) else '' }}" + "{{ ' neighbor-state-change' if traps.ospfv3.state_change.neighbor_state_change|d(False) else '' }}" + "{{ ' nssa-translator-status-change' if traps.ospfv3.state_change.nssa_translator_status_change|d(False) else '' }}" + "{{ ' restart-status-change' if traps.ospfv3.state_change.restart_status_change|d(False) else '' }}" + "{{ ' virtif-state-change' if traps.ospfv3.state_change.virtif_state_change|d(False) else '' }}" + "{{ ' virtneighbor-restart-helper-status-change' if traps.ospfv3.state_change.vn_restart_helper_status_change|d(False) else '' }}" + "{{ ' virtneighbor-state-change' if traps.ospfv3.state_change.vn_state_change|d(False) else '' }}", "result": { "traps": { - "firewall": { - "enable": True, - "serverstatus": "{{ not not serverstatus }}", + "ospfv3": { + "state_change": { + "enable": True, + "if_state_change": "{{ not not if_state_change }}", + "neighbor_restart_helper_status_change": "{{ not not neighbor_restart_helper_status_change }}", + "neighbor_state_change": "{{ not not neighbor_state_change }}", + "nssa_translator_status_change": "{{ not not nssa_translator_status_change }}", + "restart_status_change": "{{ not not restart_status_change }}", + "virtif_state_change": "{{ not not virtif_state_change }}", + "vn_restart_helper_status_change": "{{ not not virtneighbor_restart_helper_status_change }}", + "vn_state_change": "{{ not not virtneighbor_state_change }}", + }, }, }, }, @@ -1696,28 +2377,126 @@ class Snmp_serverTemplate(NetworkTemplate): }, }, { - "name": "traps.vrfmib", + "name": "traps.pki", "getval": re.compile( r""" - ^snmp-server\senable\straps\svrfmib - (\s(?P<vrf_up>vrf-up))? - (\s(?P<vrf_down>vrf-down))? - (\s(?P<vnet_trunk_up>vnet-trunk-up))? - (\s(?P<vnet_trunk_down>vnet-trunk-down))? + ^snmp-server\senable\straps\spki """, re.VERBOSE, ), - "setval": "snmp-server enable traps vrfmib" - "{{ ' vrf-up' if traps.vrfmib.vrf_up|d(False) else ''}}" - "{{ ' vrf-down' if traps.vrfmib.vrf_down|d(False) else ''}}" - "{{ ' vnet-trunk-up' if traps.vrfmib.vnet_trunk_up|d(False) else ''}}" - "{{ ' vnet-trunk-down' if traps.vrfmib.vnet_trunk_down|d(False) else ''}}", + "setval": "snmp-server enable traps pki", "result": { "traps": { - "vrfmib": { - "vrf_up": "{{ not not vrf_up }}", - "vrf_down": "{{ not not vrf_down }}", - "vnet_trunk_up": "{{ not not vnet_trunk_up }}", - "vnet_trunk_down": "{{ not not vnet_trunk_down }}", + "pki": True, + }, + }, + }, + { + "name": "traps.port_security", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\sport-security + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps port-security", + "result": { + "traps": { + "port_security": True, + }, + }, + }, + { + "name": "traps.power_ethernet", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\spower-ethernet + (\s(?P<police>police))?$ + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps power-ethernet" + "{{ ' police' if traps.power_ethernet.police|d(False) else '' }}", + "result": { + "traps": { + "power_ethernet": { + "enable": True, + "police": "{{ not not police }}", + }, + }, + }, + }, + { + "name": "traps.pw_vc", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\spw\svc$ + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps pw vc", + "result": { + "traps": { + "pw_vc": True, + }, + }, + }, + { + "name": "traps.rep", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\srep + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps rep", + "result": { + "traps": { + "rep": True, + }, + }, + }, + { + "name": "traps.rsvp", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\srsvp + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps rsvp", + "result": { + "traps": { + "rsvp": True, + }, + }, + }, + { + "name": "traps.rf", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\srf + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps rf", + "result": { + "traps": { + "rf": True, + }, + }, + }, + { + "name": "traps.smart_license", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\ssmart-license + (\s(?P<entitlement>entitlement))? + (\s(?P<global>global))? + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps smart-license" + "{{ ' entitlement' if traps.smart_license.entitlement|d(False) else '' }}" + "{{ ' global' if traps.smart_license.global|d(False) else '' }}", + "result": { + "traps": { + "smart_license": { + "enable": True, + "entitlement": "{{ not not entitlement }}", + "global": "{{ not not global }}", }, }, }, @@ -1738,8 +2517,8 @@ class Snmp_serverTemplate(NetworkTemplate): "{{ ' authentication' if traps.snmp.authentication is defined else '' }}" "{{ ' linkdown' if traps.snmp.linkdown|d(False) else ''}}" "{{ ' linkup' if traps.snmp.linkup|d(False) else ''}}" - "{{ ' warmstart' if traps.snmp.warmstart|d(False) else ''}}" - "{{ ' coldstart' if traps.snmp.coldstart|d(False) else ''}}", + "{{ ' coldstart' if traps.snmp.coldstart|d(False) else ''}}" + "{{ ' warmstart' if traps.snmp.warmstart|d(False) else ''}}", "result": { "traps": { "snmp": { @@ -1753,202 +2532,381 @@ class Snmp_serverTemplate(NetworkTemplate): }, }, { - "name": "traps.frame_relay", + "name": "traps.stackwise", "getval": re.compile( r""" - ^snmp-server\senable\straps\sframe-relay$ + ^snmp-server\senable\straps\sstackwise """, re.VERBOSE, ), - "setval": "snmp-server enable traps frame-relay", + "setval": "snmp-server enable traps stackwise", "result": { "traps": { - "frame_relay": { + "stackwise": True, + }, + }, + }, + { + "name": "traps.stpx", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\sstpx + (\s(?P<inconsistency>inconsistency))? + (\s(?P<root_inconsistency>root-inconsistency))? + (\s(?P<loop_inconsistency>loop-inconsistency))? + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps stpx" + "{{ ' inconsistency' if traps.stpx.inconsistency|d(False) else '' }}" + "{{ ' root-inconsistency' if traps.stpx.root_inconsistency|d(False) else '' }}" + "{{ ' loop-inconsistency' if traps.stpx.loop_inconsistency|d(False) else '' }}", + "result": { + "traps": { + "stpx": { "enable": True, + "inconsistency": "{{ not not inconsistency }}", + "loop_inconsistency": "{{ not not loop_inconsistency }}", + "root_inconsistency": "{{ not not root_inconsistency }}", }, }, }, }, { - "name": "traps.frame_relay.subif", + "name": "traps.syslog", "getval": re.compile( r""" - ^snmp-server\senable\straps\sframe-relay\ssubif - (\scount(?P<count>\d+))? - (\sinterval(?P<interval>\d+))? + ^snmp-server\senable\straps\ssyslog """, re.VERBOSE, ), - "setval": "snmp-server enable traps frame-relay subif" - "{{ (' count ' + count|string) if traps.frame_relay.count else '' }}" - "{{ (' interval ' + interval|string) if traps.frame_relay.interval else '' }}", + "setval": "snmp-server enable traps syslog", "result": { "traps": { - "frame_relay": { - "subif": { - "enable": "{{ not not subif }}", - "interval": "{{ interval }}", - "count": "{{ count }}", - }, + "syslog": True, + }, + }, + }, + { + "name": "traps.transceiver_all", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\stransceiver\sall + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps transceiver all", + "result": { + "traps": { + "transceiver_all": True, + }, + }, + }, + { + "name": "traps.trustsec", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\strustsec + (?!\S) + (\s(?P<authz_file_error>authz-file-error))? + (\s(?P<cache_file_error>cache-file-error))? + (\s(?P<keystore_file_error>keystore-file-error))? + (\s(?P<keystore_sync_fail>keystore-sync-fail))? + (\s(?P<random_number_fail>random-number-fail))? + (\s(?P<src_entropy_fail>src-entropy-fail))? + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps trustsec" + "{{ ' authz-file-error' if traps.trustsec.authz_file_error|d(False) else '' }}" + "{{ ' cache-file-error' if traps.trustsec.cache_file_error|d(False) else '' }}" + "{{ ' keystore-file-error' if traps.trustsec.keystore_file_error|d(False) else '' }}" + "{{ ' keystore-sync-fail' if traps.trustsec.keystore_sync_fail|d(False) else '' }}" + "{{ ' random-number-fail' if traps.trustsec.random_number_fail|d(False) else '' }}" + "{{ ' src-entropy-fail' if traps.trustsec.src_entropy_fail|d(False) else '' }}", + "result": { + "traps": { + "trustsec": { + "enable": True, + "authz_file_error": "{{ not not authz_file_error }}", + "cache_file_error": "{{ not not cache_file_error }}", + "keystore_file_error": "{{ not not keystore_file_error }}", + "keystore_sync_fail": "{{ not not keystore_sync_fail }}", + "random_number_fail": "{{ not not random_number_fail }}", + "src_entropy_fail": "{{ not not src_entropy_fail }}", }, }, }, }, { - "name": "traps.cef", + "name": "traps.trustsec_interface", "getval": re.compile( r""" - ^snmp-server\senable\straps\scef - (\s(?P<resource_failure>resource-failure))? - (\s(?P<peer_state_change>peer-state-change))? - (\s(?P<peer_fib_state_change>peer-fib-state-change))? - (\s(?P<inconsistency>inconsistency))? + ^snmp-server\senable\straps\strustsec-interface + (\s(?P<unauthorized>unauthorized))? + (\s(?P<sap_fail>sap-fail))? + (\s(?P<authc_fail>authc-fail))? + (\s(?P<supplicant_fail>supplicant-fail))? + (\s(?P<authz_fail>authz-fail))? """, re.VERBOSE, ), - "setval": "{{ 'snmp-server enable traps cef' if traps.cef.enable is defined else '' }}" - "{{ ' resource-failure' if traps.cef.resource_failure|d(False) else ''}}" - "{{ ' peer-state-change' if traps.cef.peer_state_change|d(False) else ''}}" - "{{ ' peer-fib-state-change' if traps.cef.peer_fib_state_change|d(False) else ''}}" - "{{ ' inconsistency' if traps.cef.inconsistency|d(False) else ''}}", + "setval": "snmp-server enable traps trustsec-interface" + "{{ ' unauthorized' if traps.trustsec_interface.unauthorized|d(False) else '' }}" + "{{ ' sap-fail' if traps.trustsec_interface.sap_fail|d(False) else '' }}" + "{{ ' authc-fail' if traps.trustsec_interface.authc_fail|d(False) else '' }}" + "{{ ' supplicant-fail' if traps.trustsec_interface.supplicant_fail|d(False) else '' }}" + "{{ ' authz-fail' if traps.trustsec_interface.authz_fail|d(False) else '' }}", "result": { "traps": { - "cef": { + "trustsec_interface": { "enable": True, - "inconsistency": "{{ not not inconsistency }}", - "peer_fib_state_change": "{{ not not peer_fib_state_change }}", - "peer_state_change": "{{ not not peer_state_change }}", - "resource_failure": "{{ not not resource_failure }}", + "unauthorized": "{{ not not unauthorized }}", + "sap_fail": "{{ not not sap_fail }}", + "authc_fail": "{{ not not authc_fail }}", + "supplicant_fail": "{{ not not supplicant_fail }}", + "authz_fail": "{{ not not authz_fail }}", }, }, }, }, { - "name": "traps.dlsw", + "name": "traps.trustsec_policy", "getval": re.compile( r""" - ^snmp-server\senable\straps\sdlsw - (\s(?P<circuit>circuit))? - (\s(?P<tconn>tconn))? + ^snmp-server\senable\straps\strustsec-policy + (\s(?P<peer_policy_updated>peer-policy-updated))? + (\s(?P<authz_sgacl_fail>authz-sgacl-fail))? """, re.VERBOSE, ), - "setval": "{{ 'snmp-server enable traps dlsw' if traps.dlsw.enable is defined else '' }}" - "{{ ' circuit' if traps.dlsw.circuit|d(False) else ''}}" - "{{ ' tconn' if traps.dlsw.tconn|d(False) else ''}}", + "setval": "snmp-server enable traps trustsec-policy" + "{{ ' peer-policy-updated' if traps.trustsec_policy.peer_policy_updated|d(False) else '' }}" + "{{ ' authz-sgacl-fail' if traps.trustsec_policy.authz_sgacl_fail|d(False) else '' }}", "result": { "traps": { - "dlsw": { + "trustsec_policy": { "enable": True, - "circuit": "{{ not not circuit }}", - "tconn": "{{ not not tconn }}", + "peer_policy_updated": "{{ not not peer_policy_updated }}", + "authz_sgacl_fail": "{{ not not authz_sgacl_fail }}", }, }, }, }, { - "name": "traps.ethernet.evc", + "name": "traps.trustsec_server", "getval": re.compile( r""" - ^snmp-server\senable\straps\sethernet\sevc - (\s(?P<status>status))? - (\s(?P<create>create))? - (\s(?P<delete>delete))? + ^snmp-server\senable\straps\strustsec-server + (\s(?P<radius_server>radius-server))? + (\s(?P<provision_secret>provision-secret))? """, re.VERBOSE, ), - "setval": "snmp-server enable traps ethernet evc" - "{{ ' create' if traps.ethernet.evc.create|d(False) else ''}}" - "{{ ' delete' if traps.ethernet.evc.delete|d(False) else ''}}" - "{{ ' status' if traps.ethernet.evc.status|d(False) else ''}}", + "setval": "snmp-server enable traps trustsec-server" + "{{ ' radius-server' if traps.trustsec_server.radius_server|d(False) else '' }}" + "{{ ' provision-secret' if traps.trustsec_server.provision_secret|d(False) else '' }}", "result": { "traps": { - "ethernet": { - "evc": { - "create": "{{ not not create }}", - "delete": "{{ not not delete }}", - "status": "{{ not not status }}", - }, + "trustsec_server": { + "enable": True, + "radius_server": "{{ not not radius_server }}", + "provision_secret": "{{ not not provision_secret }}", }, }, }, }, { - "name": "traps.ethernet.cfm.cc", + "name": "traps.trustsec_sxp", "getval": re.compile( r""" - ^snmp-server\senable\straps\sethernet\scfm\scc - (\s(?P<mep_up>mep-up))? - (\s(?P<mep_down>mep-down))? - (\s(?P<cross_connect>cross-connect))? - (\s(?P<loop>loop))? - (\s(?P<config>config))? + ^snmp-server\senable\straps\strustsec-sxp + (\s(?P<conn_srcaddr_err>conn-srcaddr-err))? + (\s(?P<msg_parse_err>msg-parse-err))? + (\s(?P<conn_config_err>conn-config-err))? + (\s(?P<binding_err>binding-err))? + (\s(?P<conn_up>conn-up))? + (\s(?P<conn_down>conn-down))? + (\s(?P<binding_expn_fail>binding-expn-fail))? + (\s(?P<oper_nodeid_change>oper-nodeid-change))? + (\s(?P<binding_conflict>binding-conflict))? """, re.VERBOSE, ), - "setval": "snmp-server enable traps ethernet cfm cc" - "{{ ' mep-up' if traps.ethernet.cfm.cc.mep_up|d(False) else ''}}" - "{{ ' mep-down' if traps.ethernet.cfm.cc.mep_down|d(False) else ''}}" - "{{ ' cross-connect' if traps.ethernet.cfm.cc.cross_connect|d(False) else ''}}" - "{{ ' loop' if traps.ethernet.cfm.cc.loop|d(False) else ''}}" - "{{ ' config' if traps.ethernet.cfm.cc.config|d(False) else ''}}", + "setval": "snmp-server enable traps trustsec-sxp" + "{{ ' conn-srcaddr-err' if traps.trustsec_sxp.conn_srcaddr_err|d(False) else '' }}" + "{{ ' msg-parse-err' if traps.trustsec_sxp.msg_parse_err|d(False) else '' }}" + "{{ ' conn-config-err' if traps.trustsec_sxp.conn_config_err|d(False) else '' }}" + "{{ ' binding-err' if traps.trustsec_sxp.binding_err|d(False) else '' }}" + "{{ ' conn-up' if traps.trustsec_sxp.conn_up|d(False) else '' }}" + "{{ ' conn-down' if traps.trustsec_sxp.conn_down|d(False) else '' }}" + "{{ ' binding-expn-fail' if traps.trustsec_sxp.binding_expn_fail|d(False) else '' }}" + "{{ ' oper-nodeid-change' if traps.trustsec_sxp.oper_nodeid_change|d(False) else '' }}" + "{{ ' binding-conflict' if traps.trustsec_sxp.binding_conflict|d(False) else '' }}", "result": { "traps": { - "ethernet": { - "cfm": { - "cc": { - "mep_up": "{{ not not mep_up }}", - "mep_down": "{{ not not mep_down }}", - "cross_connect": "{{ not not cross_connect }}", - "loop": "{{ not not loop }}", - "config": "{{ not not config }}", - }, - }, + "trustsec_sxp": { + "enable": True, + "conn_srcaddr_err": "{{ not not conn_srcaddr_err }}", + "msg_parse_err": "{{ not not msg_parse_err }}", + "conn_config_err": "{{ not not conn_config_err }}", + "binding_err": "{{ not not binding_err }}", + "conn_up": "{{ not not conn_up }}", + "conn_down": "{{ not not conn_down }}", + "binding_expn_fail": "{{ not not binding_expn_fail }}", + "oper_nodeid_change": "{{ not not oper_nodeid_change }}", + "binding_conflict": "{{ not not binding_conflict }}", }, }, }, }, { - "name": "traps.ethernet.cfm.crosscheck", + "name": "traps.tty", "getval": re.compile( r""" - ^snmp-server\senable\straps\sethernet\scfm\scrosscheck - (\s(?P<mep_missing>mep-missing))? - (\s(?P<mep_unknown>mep-unknown))? - (\s(?P<service_up>service-up))? + ^snmp-server\senable\straps\stty """, re.VERBOSE, ), - "setval": "snmp-server enable traps ethernet cfm crosscheck" - "{{ ' mep-missing' if traps.ethernet.cfm.crosscheck.mep_missing|d(False) else ''}}" - "{{ ' mep-unknown' if traps.ethernet.cfm.crosscheck.mep_unknown|d(False) else ''}}" - "{{ ' service-up' if traps.ethernet.cfm.crosscheck.service_up|d(False) else ''}}", + "setval": "snmp-server enable traps tty", "result": { "traps": { - "ethernet": { - "cfm": { - "crosscheck": { - "mep_missing": "{{ not not mep_missing }}", - "mep_unknown": "{{ not not mep_unknown }}", - "service_up": "{{ not not service_up }}", - }, - }, + "tty": True, + }, + }, + }, + { + "name": "traps.udld", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\sudld + (\s(?P<link_fail_rpt>link-fail-rpt))? + (\s(?P<status_change>status-change))? + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps udld" + "{{ ' link-fail-rpt' if traps.udld.link_fail_rpt|d(False) else '' }}" + "{{ ' status-change' if traps.udld.status_change|d(False) else '' }}", + "result": { + "traps": { + "udld": { + "enable": True, + "link_fail_rpt": "{{ not not link_fail_rpt }}", + "status_change": "{{ not not status_change }}", }, }, }, }, { - "name": "traps.ethernet.cfm.alarm", + "name": "traps.vlan_membership", "getval": re.compile( r""" - ^snmp-server\senable\straps\sethernet\scfm\salarm + ^snmp-server\senable\straps\svlan-membership """, re.VERBOSE, ), - "setval": "snmp-server enable traps ethernet cfm alarm", + "setval": "snmp-server enable traps vlan-membership", "result": { "traps": { - "ethernet": { - "cfm": { - "alarm": True, - }, + "vlan_membership": True, + }, + }, + }, + { + "name": "traps.vlancreate", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\svlancreate + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps vlancreate", + "result": { + "traps": { + "vlancreate": True, + }, + }, + }, + { + "name": "traps.vlandelete", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\svlandelete + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps vlandelete", + "result": { + "traps": { + "vlandelete": True, + }, + }, + }, + { + "name": "traps.vrfmib", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\svrfmib + (\s(?P<vrf_up>vrf-up))? + (\s(?P<vrf_down>vrf-down))? + (\s(?P<vnet_trunk_up>vnet-trunk-up))? + (\s(?P<vnet_trunk_down>vnet-trunk-down))? + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps vrfmib" + "{{ ' vrf-up' if traps.vrfmib.vrf_up|d(False) else ''}}" + "{{ ' vrf-down' if traps.vrfmib.vrf_down|d(False) else ''}}" + "{{ ' vnet-trunk-up' if traps.vrfmib.vnet_trunk_up|d(False) else ''}}" + "{{ ' vnet-trunk-down' if traps.vrfmib.vnet_trunk_down|d(False) else ''}}", + "result": { + "traps": { + "vrfmib": { + "vrf_up": "{{ not not vrf_up }}", + "vrf_down": "{{ not not vrf_down }}", + "vnet_trunk_up": "{{ not not vnet_trunk_up }}", + "vnet_trunk_down": "{{ not not vnet_trunk_down }}", }, }, }, }, { + "name": "traps.vrrp", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\svrrp + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps vrrp", + "result": { + "traps": { + "vrrp": True, + }, + }, + }, + { + "name": "traps.vswitch", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\svswitch + (\s(?P<dual_active>dual-active))? + (\s(?P<vsl>vsl))? + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps vswitch" + "{{ ' dual-active' if traps.vswitch.dual_active|d(False) else '' }}" + "{{ ' vsl' if traps.vswitch.vsl|d(False) else '' }}", + "result": { + "traps": { + "vswitch": { + "enable": True, + "dual_active": "{{ not not dual_active }}", + "vsl": "{{ not not vsl }}", + }, + }, + }, + }, + { + "name": "traps.vtp", + "getval": re.compile( + r""" + ^snmp-server\senable\straps\svtp + """, re.VERBOSE, + ), + "setval": "snmp-server enable traps vtp", + "result": { + "traps": { + "vtp": True, + }, + }, + }, + { "name": "system_shutdown", "getval": re.compile( r""" diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/static_routes.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/static_routes.py index 790f0c8df..a43d59cf7 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/static_routes.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/static_routes.py @@ -37,7 +37,7 @@ class Static_routesTemplate(NetworkTemplate): (\svrf\s(?P<vrf>\S+))? (\s(?P<dest>\S+)) (\s(?P<netmask>\S+)) - (\s(?P<interface>(ACR|ATM-ACR|Analysis-Module|AppNav-Compress|AppNav-UnCompress|Async|Auto-Template|BD-VIF|BDI|BVI|Bluetooth|CDMA-Ix|CEM-ACR|CEM-PG|CTunnel|Container|Dialer|EsconPhy|Ethernet-Internal|Fcpa|Filter|Filtergroup|GigabitEthernet|IMA-ACR|LongReachEthernet|Loopback|Lspvif|MFR|Multilink|NVI|Null|PROTECTION_GROUP|Port-channel|Portgroup|Pos-channel|SBC|SDH_ACR|SERIAL-ACR|SONET_ACR|SSLVPN-VIF|SYSCLOCK|Serial-PG|Service-Engine|TLS-VIF|Tunnel|VPN|Vif|Vir-cem-ACR|Virtual-PPP|Virtual-TokenRing)\d+))? + (\s(?P<interface>(ACR|ATM-ACR|Analysis-Module|AppNav-Compress|AppNav-UnCompress|Async|Auto-Template|BD-VIF|BDI|BVI|Bluetooth|CDMA-Ix|CEM-ACR|CEM-PG|CTunnel|Container|Dialer|EsconPhy|Ethernet-Internal|Fcpa|Filter|Filtergroup|GigabitEthernet|IMA-ACR|LongReachEthernet|Loopback|Lspvif|MFR|Multilink|NVI|Null|PROTECTION_GROUP|Port-channel|Portgroup|Pos-channel|SBC|SDH_ACR|SERIAL-ACR|SONET_ACR|SSLVPN-VIF|SYSCLOCK|Serial-PG|Service-Engine|TLS-VIF|Tunnel|VPN|Vif|Vir-cem-ACR|Virtual-PPP|Virtual-TokenRing)\S+))? (\s(?P<forward_router_address>(?!multicast|dhcp|global|tag|track|permanent|name)\S+))? (\s(?P<distance_metric>\d+))? (\stag\s(?P<tag>\d+))? @@ -93,7 +93,7 @@ class Static_routesTemplate(NetworkTemplate): (\stopology\s(?P<topology>\S+))? (\svrf\s(?P<vrf>\S+))? (\s(?P<dest>\S+)) - (\s(?P<interface>(ACR|ATM-ACR|Analysis-Module|AppNav-Compress|AppNav-UnCompress|Async|Auto-Template|BD-VIF|BDI|BVI|Bluetooth|CDMA-Ix|CEM-ACR|CEM-PG|CTunnel|Container|Dialer|EsconPhy|Ethernet-Internal|Fcpa|Filter|Filtergroup|GigabitEthernet|IMA-ACR|LongReachEthernet|Loopback|Lspvif|MFR|Multilink|NVI|Null|PROTECTION_GROUP|Port-channel|Portgroup|Pos-channel|SBC|SDH_ACR|SERIAL-ACR|SONET_ACR|SSLVPN-VIF|SYSCLOCK|Serial-PG|Service-Engine|TLS-VIF|Tunnel|VPN|Vif|Vir-cem-ACR|Virtual-PPP|Virtual-TokenRing)\d+))? + (\s(?P<interface>(ACR|ATM-ACR|Analysis-Module|AppNav-Compress|AppNav-UnCompress|Async|Auto-Template|BD-VIF|BDI|BVI|Bluetooth|CDMA-Ix|CEM-ACR|CEM-PG|CTunnel|Container|Dialer|EsconPhy|Ethernet-Internal|Fcpa|Filter|Filtergroup|GigabitEthernet|IMA-ACR|LongReachEthernet|Loopback|Lspvif|MFR|Multilink|NVI|Null|PROTECTION_GROUP|Port-channel|Portgroup|Pos-channel|SBC|SDH_ACR|SERIAL-ACR|SONET_ACR|SSLVPN-VIF|SYSCLOCK|Serial-PG|Service-Engine|TLS-VIF|Tunnel|VPN|Vif|Vir-cem-ACR|Virtual-PPP|Virtual-TokenRing)\S+))? (\s(?P<forward_router_address>(?!multicast|unicast|tag|track|permanent|name)\S+))? (\s(?P<distance_metric>\d+))? (\s(?P<multicast>multicast))? diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/vxlan_vtep.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/vxlan_vtep.py new file mode 100644 index 000000000..ed9517b17 --- /dev/null +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/vxlan_vtep.py @@ -0,0 +1,131 @@ +# -*- coding: utf-8 -*- +# Copyright 2023 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +""" +The Vxlan_vtep parser templates file. This contains +a list of parser definitions and associated functions that +facilitates both facts gathering and native command generation for +the given network resource. +""" + +import re + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( + NetworkTemplate, +) + + +class Vxlan_vtepTemplate(NetworkTemplate): + def __init__(self, lines=None, module=None): + super(Vxlan_vtepTemplate, self).__init__(lines=lines, tmplt=self, module=module) + + # fmt: off + PARSERS = [ + { + "name": "interface", + "getval": re.compile( + r"""^interface\s(?P<interface>\S+)$""", + re.VERBOSE, + ), + "setval": "interface {{ interface }}", + "result": {"{{ interface }}": {"interface": "{{ interface }}"}}, + "shared": True, + }, + { + "name": "source_interface", + "getval": re.compile( + r"""\s+source-interface + \s(?P<source_interface>\S+) + $""", + re.VERBOSE, + ), + "setval": "source-interface {{ source_interface }}", + "result": {"{{ interface }}": {"source_interface": "{{ source_interface }}"}}, + }, + { + "name": "host_reachability_bgp", + "getval": re.compile( + r"""\s+host-reachability\sprotocol\sbgp$""", + re.VERBOSE, + ), + "setval": "host-reachability protocol bgp", + "result": { + "{{ interface }}": { + "host_reachability_bgp": True, + }, + }, + }, + # member vni starts + { + "name": "replication", + "getval": re.compile( + r""" + \s+member\svni\s(?P<vni>\d+)\s(?P<type>mcast-group|ingress-replication) + (\s(?P<ipv4_mcast_group>[\d.]+))? + (\s(?P<ipv6_mcast_group>[\da-fA-F:]+))? + $""", + re.VERBOSE, + ), + "setval": "member vni {{ vni }}" + "{{ (' ' + 'ingress-replication') if replication.type == 'ingress' else (' ' + 'mcast-group') }}" + "{{ (' ' + replication.mcast_group.ipv4) if replication.mcast_group is defined and " + "replication.mcast_group.ipv4 is defined and replication.type == 'static' else '' }}" + "{{ (' ' + replication.mcast_group.ipv6) if replication.mcast_group is defined and " + "replication.mcast_group.ipv6 is defined and replication.type == 'static' else '' }}", + "result": { + "{{ interface }}": { + "member": { + "vni": { + "l2vni": [ + { + "vni": "{{ vni }}", + "replication": { + "type": "{{ 'ingress' if type == 'ingress-replication' else 'static' }}", + "mcast_group": { + "ipv4": "{{ ipv4_mcast_group }}", + "ipv6": "{{ ipv6_mcast_group }}", + }, + }, + }, + ], + }, + }, + }, + }, + }, + { + "name": "vrf", + "getval": re.compile( + r""" + \s+member\svni + \s(?P<vni>\d+) + \svrf\s(?P<vrf>\S+) + $""", + re.VERBOSE, + ), + "setval": "member vni {{ vni }} vrf {{ vrf }}", + "result": { + "{{ interface }}": { + "member": { + "vni": { + "l3vni": [ + { + "vni": "{{ vni }}", + "vrf": "{{ vrf }}", + }, + ], + }, + }, + }, + }, + }, + # member vni ends + ] + # fmt: on diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/utils/utils.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/utils/utils.py index 80b4b084d..f3038f7f2 100644 --- a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/utils/utils.py +++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/utils/utils.py @@ -77,7 +77,7 @@ def new_dict_to_set(input_dict, temp_list, test_set, count=0): temp_list.append(k) for each in v: if isinstance(each, dict): - if [True for i in each.values() if type(i) == list]: + if [True for i in each.values() if isinstance(i, list)]: new_dict_to_set(each, temp_list, test_set, count) else: new_dict_to_set(each, temp_list, test_set, 0) @@ -105,9 +105,12 @@ def new_dict_to_set(input_dict, temp_list, test_set, count=0): expand_dict(new_dict) if tuple(iteritems(temp_dict)) not in test_set: test_set.add(tuple(iteritems(temp_dict))) + return test_dict -def dict_to_set(sample_dict): +def dict_to_set(sample_dict, sort_dictionary=False): + if sort_dictionary: + sample_dict = sort_dict(sample_dict) # Generate a set with passed dictionary for comparison test_dict = dict() if isinstance(sample_dict, dict): @@ -421,3 +424,13 @@ def vlan_range_to_list(vlans): result.append(a) return numerical_sort(result) return result + + +def sort_dict(dictionary): + sorted_dict = dict() + for key, value in sorted(dictionary.items()): + if isinstance(value, dict): + sorted_dict[key] = sort_dict(value) + else: + sorted_dict[key] = value + return sorted_dict |