summaryrefslogtreecommitdiffstats
path: root/ansible_collections/cisco/ios/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'ansible_collections/cisco/ios/plugins')
-rw-r--r--ansible_collections/cisco/ios/plugins/action/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/action/acl_interfaces.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/acls.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/banner.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/bgp.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/bgp_address_family.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/bgp_global.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/command.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/config.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/facts.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/hostname.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/interfaces.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/ios.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/l2_interfaces.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/l3_interfaces.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/lacp.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/lacp_interfaces.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/lag_interfaces.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/linkagg.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/lldp.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/lldp_global.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/lldp_interfaces.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/logging.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/logging_global.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/ntp.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/ntp_global.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/ospf_interfaces.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/ospfv2.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/ospfv3.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/ping.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/prefix_lists.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/route_maps.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/service.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/snmp_server.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/static_routes.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/system.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/user.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/vlans.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/action/vrf.py56
-rw-r--r--ansible_collections/cisco/ios/plugins/cache/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/cliconf/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/cliconf/ios.py601
-rw-r--r--ansible_collections/cisco/ios/plugins/doc_fragments/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/doc_fragments/ios.py19
-rw-r--r--ansible_collections/cisco/ios/plugins/filter/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/inventory/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/lookup/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acl_interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acl_interfaces/acl_interfaces.py75
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acls/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acls/acls.py300
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_address_family/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_address_family/bgp_address_family.py835
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_global/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_global/bgp_global.py952
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/facts/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/facts/facts.py26
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/hostname/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/hostname/hostname.py50
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/interfaces/interfaces.py64
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l2_interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l2_interfaces/l2_interfaces.py91
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l3_interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l3_interfaces/l3_interfaces.py105
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp/lacp.py57
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp_interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp_interfaces/lacp_interfaces.py66
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lag_interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lag_interfaces/lag_interfaces.py68
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_global/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_global/lldp_global.py68
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_interfaces/lldp_interfaces.py70
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/logging_global/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/logging_global/logging_global.py374
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ntp_global/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ntp_global/ntp_global.py177
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospf_interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospf_interfaces/ospf_interfaces.py195
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv2/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv2/ospfv2.py524
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv3/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv3/ospfv3.py725
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ping/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ping/ping.py45
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/prefix_lists/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/prefix_lists/prefix_lists.py76
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/route_maps/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/route_maps/route_maps.py567
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/service/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/service/service.py121
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/snmp_server/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/snmp_server/snmp_server.py484
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/static_routes/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/static_routes/static_routes.py93
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vlans/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vlans/vlans.py75
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acl_interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acl_interfaces/acl_interfaces.py124
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acls/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acls/acls.py315
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_address_family/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_address_family/bgp_address_family.py428
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_global/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_global/bgp_global.py473
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/hostname/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/hostname/hostname.py75
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/interfaces/interfaces.py134
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l2_interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l2_interfaces/l2_interfaces.py155
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l3_interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l3_interfaces/l3_interfaces.py215
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp/lacp.py215
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp_interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp_interfaces/lacp_interfaces.py297
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lag_interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lag_interfaces/lag_interfaces.py125
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_global/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_global/lldp_global.py269
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_interfaces/lldp_interfaces.py315
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/logging_global/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/logging_global/logging_global.py170
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ntp_global/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ntp_global/ntp_global.py171
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospf_interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospf_interfaces/ospf_interfaces.py150
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv2/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv2/ospfv2.py284
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv3/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv3/ospfv3.py298
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ping/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ping/ping.py96
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/prefix_lists/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/prefix_lists/prefix_lists.py250
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/route_maps/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/route_maps/route_maps.py369
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/service/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/service/service.py152
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/snmp_server/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/snmp_server/snmp_server.py253
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/static_routes/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/static_routes/static_routes.py188
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vlans/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vlans/vlans.py371
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acl_interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acl_interfaces/acl_interfaces.py69
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acls/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acls/acls.py168
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_address_family/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_address_family/bgp_address_family.py91
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_global/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_global/bgp_global.py73
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/facts.py151
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/hostname/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/hostname/hostname.py67
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/interfaces/interfaces.py65
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l2_interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l2_interfaces/l2_interfaces.py103
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l3_interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l3_interfaces/l3_interfaces.py83
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp/lacp.py89
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp_interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp_interfaces/lacp_interfaces.py112
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lag_interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lag_interfaces/lag_interfaces.py102
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/legacy/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/legacy/base.py426
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_global/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_global/lldp_global.py101
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_interfaces/lldp_interfaces.py116
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/logging_global/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/logging_global/logging_global.py86
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ntp_global/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ntp_global/ntp_global.py89
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospf_interfaces/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospf_interfaces/ospf_interfaces.py88
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv2/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv2/ospfv2.py86
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv3/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv3/ospfv3.py170
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/prefix_lists/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/prefix_lists/prefix_lists.py116
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/route_maps/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/route_maps/route_maps.py105
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/service/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/service/service.py68
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/snmp_server/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/snmp_server/snmp_server.py151
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/static_routes/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/static_routes/static_routes.py151
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vlans/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vlans/vlans.py239
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/ios.py174
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/base.py82
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/address_family.py147
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/neighbors.py203
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/process.py163
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/module.py66
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/providers.py125
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/acl_interfaces.py76
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/acls.py372
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/bgp_address_family.py2673
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/bgp_global.py3056
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/hostname.py44
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/interfaces.py147
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/l2_interfaces.py250
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/l3_interfaces.py231
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/lag_interfaces.py70
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/logging_global.py782
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ntp_global.py509
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospf_interfaces.py643
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospfv2.py1830
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospfv3.py2935
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ping.py68
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/prefix_lists.py87
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/route_maps.py1273
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/service.py457
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/snmp_server.py1964
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/static_routes.py141
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/utils/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/module_utils/network/ios/utils/utils.py423
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_acl_interfaces.py629
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_acls.py1508
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_banner.py205
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_bgp.py504
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_bgp_address_family.py3010
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_bgp_global.py3063
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_command.py431
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_config.py584
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_facts.py246
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_hostname.py332
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_interfaces.py1009
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_l2_interfaces.py754
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_l3_interfaces.py914
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_lacp.py275
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_lacp_interfaces.py514
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_lag_interfaces.py647
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_linkagg.py354
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_lldp.py114
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_lldp_global.py356
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_lldp_interfaces.py671
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_logging.py498
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_logging_global.py1084
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_ntp.py356
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_ntp_global.py1097
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_ospf_interfaces.py1107
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_ospfv2.py1728
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_ospfv3.py1978
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_ping.py171
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_prefix_lists.py922
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_route_maps.py2358
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_service.py690
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_snmp_server.py2026
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_static_routes.py1014
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_system.py351
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_user.py600
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_vlans.py822
-rw-r--r--ansible_collections/cisco/ios/plugins/modules/ios_vrf.py741
-rw-r--r--ansible_collections/cisco/ios/plugins/plugin_utils/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/terminal/__init__.py0
-rw-r--r--ansible_collections/cisco/ios/plugins/terminal/ios.py144
281 files changed, 70886 insertions, 0 deletions
diff --git a/ansible_collections/cisco/ios/plugins/action/__init__.py b/ansible_collections/cisco/ios/plugins/action/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/action/acl_interfaces.py b/ansible_collections/cisco/ios/plugins/action/acl_interfaces.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/acl_interfaces.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/acls.py b/ansible_collections/cisco/ios/plugins/action/acls.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/acls.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/banner.py b/ansible_collections/cisco/ios/plugins/action/banner.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/banner.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/bgp.py b/ansible_collections/cisco/ios/plugins/action/bgp.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/bgp.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/bgp_address_family.py b/ansible_collections/cisco/ios/plugins/action/bgp_address_family.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/bgp_address_family.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/bgp_global.py b/ansible_collections/cisco/ios/plugins/action/bgp_global.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/bgp_global.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/command.py b/ansible_collections/cisco/ios/plugins/action/command.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/command.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/config.py b/ansible_collections/cisco/ios/plugins/action/config.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/config.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/facts.py b/ansible_collections/cisco/ios/plugins/action/facts.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/facts.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/hostname.py b/ansible_collections/cisco/ios/plugins/action/hostname.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/hostname.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/interfaces.py b/ansible_collections/cisco/ios/plugins/action/interfaces.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/interfaces.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/ios.py b/ansible_collections/cisco/ios/plugins/action/ios.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/ios.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/l2_interfaces.py b/ansible_collections/cisco/ios/plugins/action/l2_interfaces.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/l2_interfaces.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/l3_interfaces.py b/ansible_collections/cisco/ios/plugins/action/l3_interfaces.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/l3_interfaces.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/lacp.py b/ansible_collections/cisco/ios/plugins/action/lacp.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/lacp.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/lacp_interfaces.py b/ansible_collections/cisco/ios/plugins/action/lacp_interfaces.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/lacp_interfaces.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/lag_interfaces.py b/ansible_collections/cisco/ios/plugins/action/lag_interfaces.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/lag_interfaces.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/linkagg.py b/ansible_collections/cisco/ios/plugins/action/linkagg.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/linkagg.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/lldp.py b/ansible_collections/cisco/ios/plugins/action/lldp.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/lldp.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/lldp_global.py b/ansible_collections/cisco/ios/plugins/action/lldp_global.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/lldp_global.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/lldp_interfaces.py b/ansible_collections/cisco/ios/plugins/action/lldp_interfaces.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/lldp_interfaces.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/logging.py b/ansible_collections/cisco/ios/plugins/action/logging.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/logging.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/logging_global.py b/ansible_collections/cisco/ios/plugins/action/logging_global.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/logging_global.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/ntp.py b/ansible_collections/cisco/ios/plugins/action/ntp.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/ntp.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/ntp_global.py b/ansible_collections/cisco/ios/plugins/action/ntp_global.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/ntp_global.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/ospf_interfaces.py b/ansible_collections/cisco/ios/plugins/action/ospf_interfaces.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/ospf_interfaces.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/ospfv2.py b/ansible_collections/cisco/ios/plugins/action/ospfv2.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/ospfv2.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/ospfv3.py b/ansible_collections/cisco/ios/plugins/action/ospfv3.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/ospfv3.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/ping.py b/ansible_collections/cisco/ios/plugins/action/ping.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/ping.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/prefix_lists.py b/ansible_collections/cisco/ios/plugins/action/prefix_lists.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/prefix_lists.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/route_maps.py b/ansible_collections/cisco/ios/plugins/action/route_maps.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/route_maps.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/service.py b/ansible_collections/cisco/ios/plugins/action/service.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/service.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/snmp_server.py b/ansible_collections/cisco/ios/plugins/action/snmp_server.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/snmp_server.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/static_routes.py b/ansible_collections/cisco/ios/plugins/action/static_routes.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/static_routes.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/system.py b/ansible_collections/cisco/ios/plugins/action/system.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/system.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/user.py b/ansible_collections/cisco/ios/plugins/action/user.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/user.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/vlans.py b/ansible_collections/cisco/ios/plugins/action/vlans.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/vlans.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/action/vrf.py b/ansible_collections/cisco/ios/plugins/action/vrf.py
new file mode 100644
index 000000000..38c0ed229
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/action/vrf.py
@@ -0,0 +1,56 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.action.network import (
+ ActionModule as ActionNetworkModule,
+)
+
+
+display = Display()
+
+
+class ActionModule(ActionNetworkModule):
+ def run(self, tmp=None, task_vars=None):
+ del tmp # tmp no longer has any effect
+
+ module_name = self._task.action.split(".")[-1]
+ self._config_module = True if module_name in ["ios_config", "config"] else False
+ persistent_connection = self._play_context.connection.split(".")[-1]
+ warnings = []
+
+ if persistent_connection != "network_cli":
+ return {
+ "failed": True,
+ "msg": "Connection type %s is not valid for this module"
+ % self._play_context.connection,
+ }
+
+ result = super(ActionModule, self).run(task_vars=task_vars)
+ if warnings:
+ if "warnings" in result:
+ result["warnings"].extend(warnings)
+ else:
+ result["warnings"] = warnings
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/cache/__init__.py b/ansible_collections/cisco/ios/plugins/cache/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/cache/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/cliconf/__init__.py b/ansible_collections/cisco/ios/plugins/cliconf/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/cliconf/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/cliconf/ios.py b/ansible_collections/cisco/ios/plugins/cliconf/ios.py
new file mode 100644
index 000000000..be62c3724
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/cliconf/ios.py
@@ -0,0 +1,601 @@
+#
+# (c) 2017 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+author:
+- Ansible Networking Team (@ansible-network)
+name: ios
+short_description: Use ios cliconf to run command on Cisco IOS platform
+description:
+- This ios plugin provides low level abstraction apis for sending and receiving CLI
+ commands from Cisco IOS network devices.
+version_added: 1.0.0
+options:
+ commit_confirm_immediate:
+ type: boolean
+ default: false
+ description:
+ - Enable or disable commit confirm mode.
+ - Confirms the configuration pushed after a custom/ default timeout.(default 1 minute).
+ - For custom timeout configuration set commit_confirm_timeout value.
+ - On commit_confirm_immediate default value for commit_confirm_timeout is considered 1 minute
+ when variable in not explicitly declared.
+ env:
+ - name: ANSIBLE_IOS_COMMIT_CONFIRM_IMMEDIATE
+ vars:
+ - name: ansible_ios_commit_confirm_immediate
+ commit_confirm_timeout:
+ type: int
+ description:
+ - Commits the configuration on a trial basis for the time
+ specified in minutes.
+ - Using commit_confirm_timeout without specifying commit_confirm_immediate would
+ need an explicit C(configure confirm) using the ios_command module
+ to confirm/commit the changes made.
+ - Refer to example for a use case demonstration.
+ env:
+ - name: ANSIBLE_IOS_COMMIT_CONFIRM_TIMEOUT
+ vars:
+ - name: ansible_ios_commit_confirm_timeout
+ config_commands:
+ description:
+ - Specifies a list of commands that can make configuration changes
+ to the target device.
+ - When `ansible_network_single_user_mode` is enabled, if a command sent
+ to the device is present in this list, the existing cache is invalidated.
+ version_added: 2.0.0
+ type: list
+ elements: str
+ default: []
+ vars:
+ - name: ansible_ios_config_commands
+"""
+
+EXAMPLES = """
+# NOTE - IOS waits for a `configure confirm` when the configure terminal
+# command executed is `configure terminal revert timer <timeout>` within the timeout
+# period for the configuration to commit successfully, else a rollback
+# happens.
+
+# Use commit confirm with timeout and confirm the commit explicitly
+
+- name: Example commit confirmed
+ vars:
+ ansible_ios_commit_confirm_timeout: 1
+ tasks:
+ - name: "Commit confirmed with timeout"
+ cisco.ios.ios_hostname:
+ state: merged
+ config:
+ hostname: R1
+
+ - name: "Confirm the Commit"
+ cisco.ios.ios_command:
+ commands:
+ - configure confirm
+
+# Commands fired
+# - configure terminal revert timer 1 (cliconf specific)
+# - hostname R1 (from hostname resource module)
+# - configure confirm (from ios_command module)
+
+# Use commit confirm with timeout and confirm the commit via cliconf
+
+- name: Example commit confirmed
+ vars:
+ ansible_ios_commit_confirm_immediate: True
+ ansible_ios_commit_confirm_timeout: 3
+ tasks:
+ - name: "Commit confirmed with timeout"
+ cisco.ios.ios_hostname:
+ state: merged
+ config:
+ hostname: R1
+
+# Commands fired
+# - configure terminal revert timer 3 (cliconf specific)
+# - hostname R1 (from hostname resource module)
+# - configure confirm (cliconf specific)
+
+# Use commit confirm via cliconf using default timeout
+
+- name: Example commit confirmed
+ vars:
+ ansible_ios_commit_confirm_immediate: True
+ tasks:
+ - name: "Commit confirmed with timeout"
+ cisco.ios.ios_hostname:
+ state: merged
+ config:
+ hostname: R1
+
+# Commands fired
+# - configure terminal revert timer 1 (cliconf specific with default timeout)
+# - hostname R1 (from hostname resource module)
+# - configure confirm (cliconf specific)
+
+"""
+
+import json
+import re
+import time
+
+from ansible.errors import AnsibleConnectionFailure
+from ansible.module_utils._text import to_text
+from ansible.module_utils.common._collections_compat import Mapping
+from ansible.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import (
+ NetworkConfig,
+ dumps,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+from ansible_collections.ansible.netcommon.plugins.plugin_utils.cliconf_base import (
+ CliconfBase,
+ enable_mode,
+)
+
+
+class Cliconf(CliconfBase):
+ def __init__(self, *args, **kwargs):
+ self._device_info = {}
+ super(Cliconf, self).__init__(*args, **kwargs)
+
+ @enable_mode
+ def get_config(self, source="running", flags=None, format=None):
+ if source not in ("running", "startup"):
+ raise ValueError("fetching configuration from %s is not supported" % source)
+
+ if format:
+ raise ValueError("'format' value %s is not supported for get_config" % format)
+
+ if not flags:
+ flags = []
+ if source == "running":
+ cmd = "show running-config "
+ else:
+ cmd = "show startup-config "
+
+ cmd += " ".join(to_list(flags))
+ cmd = cmd.strip()
+
+ return self.send_command(cmd)
+
+ def get_diff(
+ self,
+ candidate=None,
+ running=None,
+ diff_match="line",
+ diff_ignore_lines=None,
+ path=None,
+ diff_replace="line",
+ ):
+ """
+ Generate diff between candidate and running configuration. If the
+ remote host supports onbox diff capabilities ie. supports_onbox_diff in that case
+ candidate and running configurations are not required to be passed as argument.
+ In case if onbox diff capability is not supported candidate argument is mandatory
+ and running argument is optional.
+ :param candidate: The configuration which is expected to be present on remote host.
+ :param running: The base configuration which is used to generate diff.
+ :param diff_match: Instructs how to match the candidate configuration with current device configuration
+ Valid values are 'line', 'strict', 'exact', 'none'.
+ 'line' - commands are matched line by line
+ 'strict' - command lines are matched with respect to position
+ 'exact' - command lines must be an equal match
+ 'none' - will not compare the candidate configuration with the running configuration
+ :param diff_ignore_lines: Use this argument to specify one or more lines that should be
+ ignored during the diff. This is used for lines in the configuration
+ that are automatically updated by the system. This argument takes
+ a list of regular expressions or exact line matches.
+ :param path: The ordered set of parents that uniquely identify the section or hierarchy
+ the commands should be checked against. If the parents argument
+ is omitted, the commands are checked against the set of top
+ level or global commands.
+ :param diff_replace: Instructs on the way to perform the configuration on the device.
+ If the replace argument is set to I(line) then the modified lines are
+ pushed to the device in configuration mode. If the replace argument is
+ set to I(block) then the entire command block is pushed to the device in
+ configuration mode if any line is not correct.
+ :return: Configuration diff in json format.
+ {
+ 'config_diff': '',
+ 'banner_diff': {}
+ }
+ """
+ diff = {}
+ device_operations = self.get_device_operations()
+ option_values = self.get_option_values()
+
+ if candidate is None and device_operations["supports_generate_diff"]:
+ raise ValueError("candidate configuration is required to generate diff")
+
+ if diff_match not in option_values["diff_match"]:
+ raise ValueError(
+ "'match' value %s in invalid, valid values are %s"
+ % (diff_match, ", ".join(option_values["diff_match"])),
+ )
+
+ if diff_replace not in option_values["diff_replace"]:
+ raise ValueError(
+ "'replace' value %s in invalid, valid values are %s"
+ % (diff_replace, ", ".join(option_values["diff_replace"])),
+ )
+
+ # prepare candidate configuration
+ candidate_obj = NetworkConfig(indent=1)
+ want_src, want_banners = self._extract_banners(candidate)
+ candidate_obj.load(want_src)
+
+ if running and diff_match != "none":
+ # running configuration
+ have_src, have_banners = self._extract_banners(running)
+ running_obj = NetworkConfig(indent=1, contents=have_src, ignore_lines=diff_ignore_lines)
+ configdiffobjs = candidate_obj.difference(
+ running_obj,
+ path=path,
+ match=diff_match,
+ replace=diff_replace,
+ )
+
+ else:
+ configdiffobjs = candidate_obj.items
+ have_banners = {}
+
+ diff["config_diff"] = dumps(configdiffobjs, "commands") if configdiffobjs else ""
+ banners = self._diff_banners(want_banners, have_banners)
+ diff["banner_diff"] = banners if banners else {}
+ return diff
+
+ @enable_mode
+ def configure(self):
+ """
+ Enter global configuration mode based on the
+ status of commit_confirm
+ :return: None
+ """
+ if self.get_option("commit_confirm_timeout") or self.get_option("commit_confirm_immediate"):
+ commit_timeout = (
+ self.get_option("commit_confirm_timeout")
+ if self.get_option("commit_confirm_timeout")
+ else 1
+ ) # add default timeout not default: 1 to support above or operation
+
+ persistent_command_timeout = self._connection.get_option("persistent_command_timeout")
+ # check archive state
+ archive_state = self.send_command("show archive")
+ rollback_state = self.send_command("show archive config rollback timer")
+
+ if persistent_command_timeout > commit_timeout * 60:
+ raise ValueError(
+ "ansible_command_timeout can't be greater than commit_confirm_timeout "
+ "Please adjust and try again",
+ )
+
+ if re.search(r"Archive.*not.enabled", archive_state):
+ raise ValueError(
+ "commit_confirm_immediate option set, but archiving "
+ "not enabled on device. "
+ "Please set up archiving and try again",
+ )
+
+ if not re.search(r"%No Rollback Confirmed Change pending", rollback_state):
+ raise ValueError(
+ "Existing rollback change already pending. "
+ "Please resolve by issuing 'configure confirm' "
+ "or 'configure revert now'",
+ )
+
+ self.send_command(f"configure terminal revert timer {commit_timeout}")
+ else:
+ self.send_command("configure terminal")
+
+ @enable_mode
+ def edit_config(self, candidate=None, commit=True, replace=None, comment=None):
+ resp = {}
+ operations = self.get_device_operations()
+ self.check_edit_config_capability(operations, candidate, commit, replace, comment)
+
+ results = []
+ requests = []
+ # commit confirm specific attributes
+ commit_confirm = self.get_option("commit_confirm_immediate")
+ if commit:
+ self.configure()
+ for line in to_list(candidate):
+ if not isinstance(line, Mapping):
+ line = {"command": line}
+
+ cmd = line["command"]
+ if cmd != "end" and cmd[0] != "!":
+ results.append(self.send_command(**line))
+ requests.append(cmd)
+
+ self.send_command("end")
+ if commit_confirm:
+ self.send_command("configure confirm")
+
+ else:
+ raise ValueError("check mode is not supported")
+
+ resp["request"] = requests
+ resp["response"] = results
+ return resp
+
+ def edit_macro(self, candidate=None, commit=True, replace=None, comment=None):
+ """
+ ios_config:
+ lines: "{{ macro_lines }}"
+ parents: "macro name {{ macro_name }}"
+ after: '@'
+ match: line
+ replace: block
+ """
+ resp = {}
+ operations = self.get_device_operations()
+ self.check_edit_config_capability(operations, candidate, commit, replace, comment)
+
+ results = []
+ requests = []
+ if commit:
+ commands = ""
+ self.send_command("config terminal")
+ time.sleep(0.1)
+ # first item: macro command
+ commands += candidate.pop(0) + "\n"
+ multiline_delimiter = candidate.pop(-1)
+ for line in candidate:
+ commands += " " + line + "\n"
+ commands += multiline_delimiter + "\n"
+ obj = {"command": commands, "sendonly": True}
+ results.append(self.send_command(**obj))
+ requests.append(commands)
+
+ time.sleep(0.1)
+ self.send_command("end", sendonly=True)
+ time.sleep(0.1)
+ results.append(self.send_command("\n"))
+ requests.append("\n")
+
+ resp["request"] = requests
+ resp["response"] = results
+ return resp
+
+ def get(
+ self,
+ command=None,
+ prompt=None,
+ answer=None,
+ sendonly=False,
+ newline=True,
+ output=None,
+ check_all=False,
+ ):
+ if not command:
+ raise ValueError("must provide value of command to execute")
+ if output:
+ raise ValueError("'output' value %s is not supported for get" % output)
+
+ return self.send_command(
+ command=command,
+ prompt=prompt,
+ answer=answer,
+ sendonly=sendonly,
+ newline=newline,
+ check_all=check_all,
+ )
+
+ def check_device_type(self):
+ device_type = "L2"
+ try:
+ self.get(command="show vlan")
+ except Exception:
+ device_type = "L3"
+ return device_type
+
+ def get_device_info(self):
+ if not self._device_info:
+ device_info = {}
+
+ device_info["network_os"] = "ios"
+ # Ensure we are not in config mode
+ self._update_cli_prompt_context(config_context=")#", exit_command="end")
+ reply = self.get(command="show version")
+ data = to_text(reply, errors="surrogate_or_strict").strip()
+ match = re.search(r"Version (\S+)", data)
+ if match:
+ device_info["network_os_version"] = match.group(1).strip(",")
+
+ model_search_strs = [
+ r"^[Cc]isco (.+) \(revision",
+ r"^[Cc]isco (\S+).+bytes of .*memory",
+ ]
+ for item in model_search_strs:
+ match = re.search(item, data, re.M)
+ if match:
+ version = match.group(1).split(" ")
+ device_info["network_os_model"] = version[0]
+ break
+
+ match = re.search(r"^(.+) uptime", data, re.M)
+ if match:
+ device_info["network_os_hostname"] = match.group(1)
+
+ match = re.search(r'image file is "(.+)"', data)
+ if match:
+ device_info["network_os_image"] = match.group(1)
+ device_info["network_os_type"] = self.check_device_type()
+ self._device_info = device_info
+
+ return self._device_info
+
+ def get_device_operations(self):
+ return {
+ "supports_diff_replace": True,
+ "supports_commit": False,
+ "supports_rollback": False,
+ "supports_defaults": True,
+ "supports_onbox_diff": False,
+ "supports_commit_comment": False,
+ "supports_multiline_delimiter": True,
+ "supports_diff_match": True,
+ "supports_diff_ignore_lines": True,
+ "supports_generate_diff": True,
+ "supports_replace": False,
+ }
+
+ def get_option_values(self):
+ return {
+ "format": ["text"],
+ "diff_match": ["line", "strict", "exact", "none"],
+ "diff_replace": ["line", "block"],
+ "output": [],
+ }
+
+ def get_capabilities(self):
+ result = super(Cliconf, self).get_capabilities()
+ result["rpc"] += ["edit_banner", "get_diff", "run_commands", "get_defaults_flag"]
+ result["device_operations"] = self.get_device_operations()
+ result.update(self.get_option_values())
+ return json.dumps(result)
+
+ def edit_banner(self, candidate=None, multiline_delimiter="@", commit=True):
+ """
+ Edit banner on remote device
+ :param banners: Banners to be loaded in json format
+ :param multiline_delimiter: Line delimiter for banner
+ :param commit: Boolean value that indicates if the device candidate
+ configuration should be pushed in the running configuration or discarded.
+ :param diff: Boolean flag to indicate if configuration that is applied on remote host should
+ generated and returned in response or not
+ :return: Returns response of executing the configuration command received
+ from remote host
+ """
+ resp = {}
+ banners_obj = json.loads(candidate)
+ results = []
+ requests = []
+ if commit:
+ for key, value in iteritems(banners_obj):
+ key += " %s" % multiline_delimiter
+ self.send_command("config terminal", sendonly=True)
+ for cmd in [key, value, multiline_delimiter]:
+ obj = {"command": cmd, "sendonly": True}
+ results.append(self.send_command(**obj))
+ requests.append(cmd)
+
+ self.send_command("end", sendonly=True)
+ time.sleep(0.1)
+ results.append(self.send_command("\n"))
+ requests.append("\n")
+
+ resp["request"] = requests
+ resp["response"] = results
+
+ return resp
+
+ def run_commands(self, commands=None, check_rc=True):
+ if commands is None:
+ raise ValueError("'commands' value is required")
+
+ responses = list()
+ for cmd in to_list(commands):
+ if not isinstance(cmd, Mapping):
+ cmd = {"command": cmd}
+
+ output = cmd.pop("output", None)
+ if output:
+ raise ValueError("'output' value %s is not supported for run_commands" % output)
+
+ try:
+ out = self.send_command(**cmd)
+ except AnsibleConnectionFailure as e:
+ if check_rc:
+ raise
+ out = getattr(e, "err", to_text(e))
+
+ responses.append(out)
+
+ return responses
+
+ def get_defaults_flag(self):
+ """
+ The method identifies the filter that should be used to fetch running-configuration
+ with defaults.
+ :return: valid default filter
+ """
+ out = self.get("show running-config ?")
+ out = to_text(out, errors="surrogate_then_replace")
+
+ commands = set()
+ for line in out.splitlines():
+ if line.strip():
+ commands.add(line.strip().split()[0])
+
+ if "all" in commands:
+ return "all"
+ else:
+ return "full"
+
+ def set_cli_prompt_context(self):
+ """
+ Make sure we are in the operational cli mode
+ :return: None
+ """
+ if self._connection.connected:
+ out = self._connection.get_prompt()
+
+ if out is None:
+ raise AnsibleConnectionFailure(
+ message="cli prompt is not identified from the last received"
+ " response window: %s" % self._connection._last_recv_window,
+ )
+
+ if re.search(r"config.*\)#", to_text(out, errors="surrogate_then_replace").strip()):
+ self._connection.queue_message("vvvv", "wrong context, sending end to device")
+ self._connection.send_command("end")
+
+ def _extract_banners(self, config):
+ banners = {}
+ banner_cmds = re.findall(r"^banner (\w+)", config, re.M)
+ for cmd in banner_cmds:
+ regex = r"banner %s \^C(.+?)(?=\^C)" % cmd
+ match = re.search(regex, config, re.S)
+ if match:
+ key = "banner %s" % cmd
+ banners[key] = match.group(1).strip()
+
+ for cmd in banner_cmds:
+ regex = r"banner %s \^C(.+?)(?=\^C)" % cmd
+ match = re.search(regex, config, re.S)
+ if match:
+ config = config.replace(str(match.group(1)), "")
+
+ config = re.sub(r"banner \w+ \^C\^C", "!! banner removed", config)
+ return config, banners
+
+ def _diff_banners(self, want, have):
+ candidate = {}
+ for key, value in iteritems(want):
+ if value != have.get(key):
+ candidate[key] = value
+ return candidate
diff --git a/ansible_collections/cisco/ios/plugins/doc_fragments/__init__.py b/ansible_collections/cisco/ios/plugins/doc_fragments/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/doc_fragments/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/doc_fragments/ios.py b/ansible_collections/cisco/ios/plugins/doc_fragments/ios.py
new file mode 100644
index 000000000..ab9a5b155
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/doc_fragments/ios.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+# Copyright: (c) 2015, Peter Sprygada <psprygada@ansible.com>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+
+class ModuleDocFragment(object):
+ # Standard files documentation fragment
+ DOCUMENTATION = r"""options: {}
+notes:
+- For more information on using Ansible to manage network devices see the :ref:`Ansible
+ Network Guide <network_guide>`
+- For more information on using Ansible to manage Cisco devices see the `Cisco integration
+ page <https://www.ansible.com/integrations/networks/cisco>`_.
+"""
diff --git a/ansible_collections/cisco/ios/plugins/filter/__init__.py b/ansible_collections/cisco/ios/plugins/filter/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/filter/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/inventory/__init__.py b/ansible_collections/cisco/ios/plugins/inventory/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/inventory/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/lookup/__init__.py b/ansible_collections/cisco/ios/plugins/lookup/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/lookup/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acl_interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acl_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acl_interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acl_interfaces/acl_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acl_interfaces/acl_interfaces.py
new file mode 100644
index 000000000..d3037ed9b
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acl_interfaces/acl_interfaces.py
@@ -0,0 +1,75 @@
+# -*- coding: utf-8 -*-
+# Copyright 2022 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
+# cli_rm_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.
+#
+#############################################
+
+"""
+The arg spec for the ios_acl_interfaces module
+"""
+
+
+class Acl_interfacesArgs(object): # pylint: disable=R0903
+ """The arg spec for the ios_acl_interfaces module"""
+
+ argument_spec = {
+ "config": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str", "required": True},
+ "access_groups": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "afi": {"type": "str", "required": True, "choices": ["ipv4", "ipv6"]},
+ "acls": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str", "required": True},
+ "direction": {
+ "type": "str",
+ "required": True,
+ "choices": ["in", "out"],
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "type": "str",
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "parsed",
+ "rendered",
+ ],
+ "default": "merged",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acls/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acls/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acls/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acls/acls.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acls/acls.py
new file mode 100644
index 000000000..a3ca057c5
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/acls/acls.py
@@ -0,0 +1,300 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 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
+# cli_rm_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.
+#
+#############################################
+
+"""
+The arg spec for the ios_acls module
+"""
+
+
+class AclsArgs(object): # pylint: disable=R0903
+ """The arg spec for the ios_acls module"""
+
+ argument_spec = {
+ "config": {
+ "elements": "dict",
+ "options": {
+ "acls": {
+ "elements": "dict",
+ "options": {
+ "aces": {
+ "elements": "dict",
+ "options": {
+ "destination": {
+ "options": {
+ "address": {"type": "str"},
+ "any": {"type": "bool"},
+ "host": {"type": "str"},
+ "object_group": {"type": "str"},
+ "port_protocol": {
+ "options": {
+ "eq": {"type": "str"},
+ "gt": {"type": "str"},
+ "lt": {"type": "str"},
+ "neq": {"type": "str"},
+ "range": {
+ "options": {
+ "end": {"type": "int"},
+ "start": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "wildcard_bits": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "dscp": {"type": "str"},
+ "evaluate": {"type": "str"},
+ "fragments": {"type": "str"},
+ "enable_fragments": {"type": "bool"},
+ "grant": {"choices": ["permit", "deny"], "type": "str"},
+ "log": {
+ "options": {
+ "set": {"type": "bool"},
+ "user_cookie": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "log_input": {
+ "options": {
+ "set": {"type": "bool"},
+ "user_cookie": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "option": {
+ "options": {
+ "add_ext": {"type": "bool"},
+ "any_options": {"type": "bool"},
+ "com_security": {"type": "bool"},
+ "dps": {"type": "bool"},
+ "encode": {"type": "bool"},
+ "eool": {"type": "bool"},
+ "ext_ip": {"type": "bool"},
+ "ext_security": {"type": "bool"},
+ "finn": {"type": "bool"},
+ "imitd": {"type": "bool"},
+ "lsr": {"type": "bool"},
+ "mtup": {"type": "bool"},
+ "mtur": {"type": "bool"},
+ "no_op": {"type": "bool"},
+ "nsapa": {"type": "bool"},
+ "record_route": {"type": "bool"},
+ "router_alert": {"type": "bool"},
+ "sdb": {"type": "bool"},
+ "security": {"type": "bool"},
+ "ssr": {"type": "bool"},
+ "stream_id": {"type": "bool"},
+ "timestamp": {"type": "bool"},
+ "traceroute": {"type": "bool"},
+ "ump": {"type": "bool"},
+ "visa": {"type": "bool"},
+ "zsu": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "precedence": {"type": "str"},
+ "protocol": {"type": "str"},
+ "protocol_options": {
+ "options": {
+ "ahp": {"type": "bool"},
+ "eigrp": {"type": "bool"},
+ "esp": {"type": "bool"},
+ "gre": {"type": "bool"},
+ "hbh": {"type": "bool"},
+ "icmp": {
+ "options": {
+ "administratively_prohibited": {"type": "bool"},
+ "alternate_address": {"type": "bool"},
+ "conversion_error": {"type": "bool"},
+ "dod_host_prohibited": {"type": "bool"},
+ "dod_net_prohibited": {"type": "bool"},
+ "echo": {"type": "bool"},
+ "echo_reply": {"type": "bool"},
+ "general_parameter_problem": {"type": "bool"},
+ "host_isolated": {"type": "bool"},
+ "host_precedence_unreachable": {"type": "bool"},
+ "host_redirect": {"type": "bool"},
+ "host_tos_redirect": {"type": "bool"},
+ "host_tos_unreachable": {"type": "bool"},
+ "host_unknown": {"type": "bool"},
+ "host_unreachable": {"type": "bool"},
+ "information_reply": {"type": "bool"},
+ "information_request": {"type": "bool"},
+ "mask_reply": {"type": "bool"},
+ "mask_request": {"type": "bool"},
+ "mobile_redirect": {"type": "bool"},
+ "net_redirect": {"type": "bool"},
+ "net_tos_redirect": {"type": "bool"},
+ "net_tos_unreachable": {"type": "bool"},
+ "net_unreachable": {"type": "bool"},
+ "network_unknown": {"type": "bool"},
+ "no_room_for_option": {"type": "bool"},
+ "option_missing": {"type": "bool"},
+ "packet_too_big": {"type": "bool"},
+ "parameter_problem": {"type": "bool"},
+ "port_unreachable": {"type": "bool"},
+ "precedence_unreachable": {"type": "bool"},
+ "protocol_unreachable": {"type": "bool"},
+ "reassembly_timeout": {"type": "bool"},
+ "redirect": {"type": "bool"},
+ "router_advertisement": {"type": "bool"},
+ "router_solicitation": {"type": "bool"},
+ "source_quench": {"type": "bool"},
+ "source_route_failed": {"type": "bool"},
+ "time_exceeded": {"type": "bool"},
+ "timestamp_reply": {"type": "bool"},
+ "timestamp_request": {"type": "bool"},
+ "traceroute": {"type": "bool"},
+ "ttl_exceeded": {"type": "bool"},
+ "unreachable": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "igmp": {
+ "options": {
+ "dvmrp": {"type": "bool"},
+ "host_query": {"type": "bool"},
+ "mtrace_resp": {"type": "bool"},
+ "mtrace_route": {"type": "bool"},
+ "pim": {"type": "bool"},
+ "trace": {"type": "bool"},
+ "v1host_report": {"type": "bool"},
+ "v2host_report": {"type": "bool"},
+ "v2leave_group": {"type": "bool"},
+ "v3host_report": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "ip": {"type": "bool"},
+ "ipinip": {"type": "bool"},
+ "ipv6": {"type": "bool"},
+ "nos": {"type": "bool"},
+ "ospf": {"type": "bool"},
+ "pcp": {"type": "bool"},
+ "pim": {"type": "bool"},
+ "protocol_number": {"type": "int"},
+ "sctp": {"type": "bool"},
+ "tcp": {
+ "options": {
+ "ack": {"type": "bool"},
+ "established": {"type": "bool"},
+ "fin": {"type": "bool"},
+ "psh": {"type": "bool"},
+ "rst": {"type": "bool"},
+ "syn": {"type": "bool"},
+ "urg": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "udp": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "remarks": {"elements": "str", "type": "list"},
+ "sequence": {"type": "int"},
+ "source": {
+ "options": {
+ "address": {"type": "str"},
+ "any": {"type": "bool"},
+ "host": {"type": "str"},
+ "object_group": {"type": "str"},
+ "port_protocol": {
+ "options": {
+ "eq": {"type": "str"},
+ "gt": {"type": "str"},
+ "lt": {"type": "str"},
+ "neq": {"type": "str"},
+ "range": {
+ "options": {
+ "end": {"type": "int"},
+ "start": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "wildcard_bits": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "time_range": {"type": "str"},
+ "tos": {
+ "options": {
+ "max_reliability": {"type": "bool"},
+ "max_throughput": {"type": "bool"},
+ "min_delay": {"type": "bool"},
+ "min_monetary_cost": {"type": "bool"},
+ "normal": {"type": "bool"},
+ "service_value": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "ttl": {
+ "options": {
+ "eq": {"type": "int"},
+ "gt": {"type": "int"},
+ "lt": {"type": "int"},
+ "neq": {"type": "int"},
+ "range": {
+ "options": {
+ "end": {"type": "int"},
+ "start": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "list",
+ },
+ "acl_type": {"choices": ["extended", "standard"], "type": "str"},
+ "name": {"required": True, "type": "str"},
+ },
+ "type": "list",
+ },
+ "afi": {"choices": ["ipv4", "ipv6"], "required": True, "type": "str"},
+ },
+ "type": "list",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "rendered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_address_family/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_address_family/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_address_family/__init__.py
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
new file mode 100644
index 000000000..a52e3787c
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_address_family/bgp_address_family.py
@@ -0,0 +1,835 @@
+# -*- coding: utf-8 -*-
+# Copyright 2022 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
+# cli_rm_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.
+#
+#############################################
+
+"""
+The arg spec for the ios_bgp_address_family module
+"""
+
+
+class Bgp_address_familyArgs(object): # pylint: disable=R0903
+ """The arg spec for the ios_bgp_address_family module"""
+
+ argument_spec = {
+ "config": {
+ "type": "dict",
+ "options": {
+ "as_number": {"type": "str"},
+ "address_family": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "afi": {
+ "type": "str",
+ "choices": [
+ "ipv4",
+ "ipv6",
+ "l2vpn",
+ "nsap",
+ "rtfilter",
+ "vpnv4",
+ "vpnv6",
+ ],
+ },
+ "safi": {
+ "type": "str",
+ "choices": ["flowspec", "mdt", "multicast", "mvpn", "evpn", "unicast"],
+ },
+ "vrf": {"type": "str"},
+ "aggregate_addresses": {
+ "type": "list",
+ "elements": "dict",
+ "aliases": ["aggregate_address"],
+ "options": {
+ "address": {"type": "str"},
+ "netmask": {"type": "str"},
+ "advertise_map": {"type": "str"},
+ "as_confed_set": {"type": "bool"},
+ "as_set": {"type": "bool"},
+ "attribute_map": {"type": "str"},
+ "summary_only": {"type": "bool"},
+ "suppress_map": {"type": "str"},
+ },
+ },
+ "auto_summary": {"type": "bool"},
+ "bgp": {
+ "type": "dict",
+ "options": {
+ "additional_paths": {
+ "type": "dict",
+ "options": {
+ "receive": {"type": "bool"},
+ "select": {
+ "type": "dict",
+ "options": {
+ "all": {"type": "bool"},
+ "backup": {"type": "bool"},
+ "best": {"type": "int"},
+ "best_external": {"type": "bool"},
+ "group_best": {"type": "bool"},
+ },
+ },
+ "send": {"type": "bool"},
+ "install": {"type": "bool"},
+ },
+ },
+ "aggregate_timer": {"type": "int"},
+ "dampening": {
+ "type": "dict",
+ "options": {
+ "penalty_half_time": {"type": "int"},
+ "reuse_route_val": {"type": "int"},
+ "suppress_route_val": {"type": "int"},
+ "max_suppress": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "dmzlink_bw": {"type": "bool"},
+ "nexthop": {
+ "type": "dict",
+ "options": {
+ "route_map": {"type": "str"},
+ "trigger": {
+ "type": "dict",
+ "options": {
+ "delay": {"type": "int"},
+ "enable": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "redistribute_internal": {"type": "bool"},
+ "route_map": {"type": "bool"},
+ "scan_time": {"type": "int"},
+ "slow_peer": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "detection": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "threshold": {"type": "int"},
+ },
+ },
+ "split_update_group": {
+ "type": "dict",
+ "options": {
+ "dynamic": {"type": "bool"},
+ "permanent": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "slow_peer_options": {
+ "type": "dict",
+ "options": {
+ "detection": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "threshold": {"type": "int"},
+ },
+ },
+ "split_update_group": {
+ "type": "dict",
+ "options": {
+ "dynamic": {"type": "bool"},
+ "permanent": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "soft_reconfig_backup": {"type": "bool"},
+ "update_group": {"type": "bool"},
+ },
+ },
+ "default": {"type": "bool"},
+ "default_information": {"type": "bool"},
+ "default_metric": {"type": "int"},
+ "distance": {
+ "type": "dict",
+ "options": {
+ "external": {"type": "int"},
+ "internal": {"type": "int"},
+ "local": {"type": "int"},
+ },
+ },
+ "neighbors": {
+ "type": "list",
+ "elements": "dict",
+ "aliases": ["neighbor"],
+ "options": {
+ "neighbor_address": {"type": "str"},
+ "address": {"type": "str"},
+ "tag": {"type": "str"},
+ "ipv6_address": {"type": "str", "aliases": ["ipv6_adddress"]},
+ "activate": {"type": "bool"},
+ "additional_paths": {
+ "type": "dict",
+ "options": {
+ "disable": {"type": "bool"},
+ "receive": {"type": "bool"},
+ "send": {"type": "bool"},
+ },
+ },
+ "advertise": {
+ "type": "dict",
+ "options": {
+ "all": {"type": "bool"},
+ "best": {"type": "int"},
+ "group_best": {"type": "bool"},
+ },
+ },
+ "advertises": {
+ "type": "dict",
+ "options": {
+ "additional_paths": {
+ "type": "dict",
+ "options": {
+ "all": {"type": "bool"},
+ "best": {"type": "int"},
+ "group_best": {"type": "bool"},
+ },
+ },
+ "best_external": {"type": "bool"},
+ "diverse_path": {
+ "type": "dict",
+ "options": {
+ "backup": {"type": "bool"},
+ "mpath": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "advertise_map": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "exist_map": {"type": "str"},
+ "non_exist_map": {"type": "str"},
+ },
+ },
+ "advertisement_interval": {"type": "int"},
+ "aigp": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "str"},
+ "send": {
+ "type": "dict",
+ "options": {
+ "cost_community": {
+ "type": "dict",
+ "options": {
+ "id": {"type": "int"},
+ "poi": {
+ "type": "dict",
+ "options": {
+ "igp_cost": {"type": "bool"},
+ "pre_bestpath": {"type": "bool"},
+ "transitive": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "med": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "allow_policy": {"type": "bool"},
+ "allowas_in": {"type": "int"},
+ "as_override": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "split_horizon": {"type": "bool"},
+ },
+ },
+ "bmp_activate": {
+ "type": "dict",
+ "options": {"all": {"type": "bool"}, "server": {"type": "int"}},
+ },
+ "capability": {
+ "type": "dict",
+ "options": {
+ "both": {"type": "bool"},
+ "receive": {"type": "bool"},
+ "send": {"type": "bool"},
+ },
+ },
+ "cluster_id": {"type": "str"},
+ "default_originate": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "description": {"type": "str"},
+ "disable_connected_check": {"type": "bool"},
+ "distribute_list": {
+ "type": "dict",
+ "options": {
+ "acl": {"type": "str"},
+ "in": {"type": "bool"},
+ "out": {"type": "bool"},
+ },
+ },
+ "dmzlink_bw": {"type": "bool"},
+ "ebgp_multihop": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "hop_count": {"type": "int"},
+ },
+ },
+ "fall_over": {
+ "type": "dict",
+ "options": {
+ "bfd": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "multi_hop": {"type": "bool"},
+ "single_hop": {"type": "bool"},
+ },
+ },
+ "route_map": {"type": "str"},
+ },
+ },
+ "filter_list": {
+ "type": "dict",
+ "options": {
+ "as_path_acl": {"type": "int"},
+ "in": {"type": "bool"},
+ "out": {"type": "bool"},
+ },
+ },
+ "ha_mode": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "disable": {"type": "bool"},
+ },
+ },
+ "inherit": {"type": "str"},
+ "internal_vpn_client": {"type": "bool"},
+ "local_as": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "number": {"type": "int"},
+ "dual_as": {"type": "bool"},
+ "no_prepend": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "replace_as": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "log_neighbor_changes": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "disable": {"type": "bool"},
+ },
+ },
+ "maximum_prefix": {
+ "type": "dict",
+ "options": {
+ "number": {"type": "int"},
+ "threshold_value": {"type": "int"},
+ "restart": {"type": "int"},
+ "warning_only": {"type": "bool"},
+ },
+ },
+ "next_hop_self": {"type": "bool"},
+ "nexthop_self": {
+ "type": "dict",
+ "options": {"set": {"type": "bool"}, "all": {"type": "bool"}},
+ },
+ "next_hop_unchanged": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "allpaths": {"type": "bool"},
+ },
+ },
+ "password": {"type": "str", "no_log": True},
+ "password_options": {
+ "type": "dict",
+ "no_log": False,
+ "options": {
+ "encryption": {"type": "int"},
+ "pass_key": {"type": "str", "no_log": True},
+ },
+ },
+ "path_attribute": {
+ "type": "dict",
+ "options": {
+ "discard": {
+ "type": "dict",
+ "options": {
+ "type": {"type": "int"},
+ "range": {
+ "type": "dict",
+ "options": {
+ "start": {"type": "int"},
+ "end": {"type": "int"},
+ },
+ },
+ "in": {"type": "bool"},
+ },
+ },
+ "treat_as_withdraw": {
+ "type": "dict",
+ "options": {
+ "type": {"type": "int"},
+ "range": {
+ "type": "dict",
+ "options": {
+ "start": {"type": "int"},
+ "end": {"type": "int"},
+ },
+ },
+ "in": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "peer_group": {"type": "bool"},
+ "peer_group_name": {"type": "str"},
+ "prefix_list": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "in": {"type": "bool"},
+ "out": {"type": "bool"},
+ },
+ },
+ "prefix_lists": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "in": {"type": "bool"},
+ "out": {"type": "bool"},
+ },
+ },
+ "remote_as": {"type": "int"},
+ "remove_private_as": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "all": {"type": "bool"},
+ "replace_as": {"type": "bool"},
+ },
+ },
+ "route_map": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "in": {"type": "bool"},
+ "out": {"type": "bool"},
+ },
+ },
+ "route_maps": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "in": {"type": "bool"},
+ "out": {"type": "bool"},
+ },
+ },
+ "route_reflector_client": {"type": "bool"},
+ "route_server_client": {"type": "bool"},
+ "send_community": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "both": {"type": "bool"},
+ "extended": {"type": "bool"},
+ "standard": {"type": "bool"},
+ },
+ },
+ "shutdown": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "graceful": {"type": "int"},
+ },
+ },
+ "slow_peer": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "detection": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "disable": {"type": "bool"},
+ "threshold": {"type": "int"},
+ },
+ },
+ "split_update_group": {
+ "type": "dict",
+ "options": {
+ "dynamic": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "disable": {"type": "bool"},
+ "permanent": {"type": "bool"},
+ },
+ },
+ "static": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "slow_peer_options": {
+ "type": "dict",
+ "options": {
+ "detection": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "disable": {"type": "bool"},
+ "threshold": {"type": "int"},
+ },
+ },
+ "split_update_group": {
+ "type": "dict",
+ "options": {
+ "dynamic": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "disable": {"type": "bool"},
+ "permanent": {"type": "bool"},
+ },
+ },
+ "static": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "soft_reconfiguration": {"type": "bool"},
+ "soo": {"type": "str"},
+ "timers": {
+ "type": "dict",
+ "options": {
+ "interval": {"type": "int"},
+ "holdtime": {"type": "int"},
+ "min_holdtime": {"type": "int"},
+ },
+ },
+ "transport": {
+ "type": "dict",
+ "options": {
+ "connection_mode": {
+ "type": "dict",
+ "options": {
+ "active": {"type": "bool"},
+ "passive": {"type": "bool"},
+ },
+ },
+ "multi_session": {"type": "bool"},
+ "path_mtu_discovery": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "disable": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "ttl_security": {"type": "int"},
+ "unsuppress_map": {"type": "str"},
+ "version": {"type": "int"},
+ "weight": {"type": "int"},
+ },
+ },
+ "networks": {
+ "type": "list",
+ "elements": "dict",
+ "aliases": ["network"],
+ "options": {
+ "address": {"type": "str"},
+ "mask": {"type": "str"},
+ "backdoor": {"type": "bool"},
+ "evpn": {"type": "bool"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "redistribute": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "application": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "bgp": {
+ "type": "dict",
+ "options": {
+ "as_number": {"type": "str"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "connected": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "eigrp": {
+ "type": "dict",
+ "options": {
+ "as_number": {"type": "str"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "isis": {
+ "type": "dict",
+ "options": {
+ "area_tag": {"type": "str"},
+ "clns": {"type": "bool"},
+ "ip": {"type": "bool"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "iso_igrp": {
+ "type": "dict",
+ "options": {
+ "area_tag": {"type": "str"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "lisp": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "mobile": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "odr": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "ospf": {
+ "type": "dict",
+ "options": {
+ "process_id": {"type": "int"},
+ "include_connected": {"type": "bool"},
+ "match": {
+ "type": "dict",
+ "options": {
+ "external": {"type": "bool"},
+ "internal": {"type": "bool"},
+ "externals": {
+ "type": "dict",
+ "options": {
+ "type_1": {"type": "bool"},
+ "type_2": {"type": "bool"},
+ },
+ },
+ "nssa_external": {"type": "bool"},
+ "nssa_externals": {
+ "type": "dict",
+ "options": {
+ "type_1": {"type": "bool"},
+ "type_2": {"type": "bool"},
+ },
+ },
+ "type_1": {"type": "bool"},
+ "type_2": {"type": "bool"},
+ },
+ },
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ "vrf": {"type": "str"},
+ },
+ },
+ "ospfv3": {
+ "type": "dict",
+ "options": {
+ "process_id": {"type": "int"},
+ "match": {
+ "type": "dict",
+ "options": {
+ "external": {"type": "bool"},
+ "internal": {"type": "bool"},
+ "externals": {
+ "type": "dict",
+ "options": {
+ "type_1": {"type": "bool"},
+ "type_2": {"type": "bool"},
+ },
+ },
+ "nssa_external": {"type": "bool"},
+ "nssa_externals": {
+ "type": "dict",
+ "options": {
+ "type_1": {"type": "bool"},
+ "type_2": {"type": "bool"},
+ },
+ },
+ "type_1": {"type": "bool"},
+ "type_2": {"type": "bool"},
+ },
+ },
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "rip": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "static": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "clns": {"type": "bool"},
+ "ip": {"type": "bool"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "vrf": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "global": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "snmp": {
+ "type": "dict",
+ "options": {
+ "context": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "community": {
+ "type": "dict",
+ "options": {
+ "snmp_community": {"type": "str"},
+ "acl": {"type": "str"},
+ "ipv6": {"type": "str"},
+ "ro": {"type": "bool"},
+ "rw": {"type": "bool"},
+ },
+ },
+ "user": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "access": {
+ "type": "dict",
+ "options": {
+ "acl": {"type": "str"},
+ "ipv6": {"type": "str"},
+ },
+ },
+ "auth": {
+ "type": "dict",
+ "options": {
+ "md5": {"type": "str"},
+ "sha": {"type": "str"},
+ },
+ },
+ "priv": {
+ "type": "dict",
+ "options": {
+ "des": {"type": "str"},
+ "des56": {"type": "str"},
+ "aes128": {"type": "str"},
+ "aes192": {"type": "str"},
+ "aes256": {"type": "str"},
+ },
+ },
+ "credential": {"type": "bool"},
+ "encrypted": {"type": "bool"},
+ },
+ },
+ },
+ },
+ },
+ },
+ "table_map": {
+ "type": "dict",
+ "options": {"name": {"type": "str"}, "filter": {"type": "bool"}},
+ },
+ },
+ },
+ },
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "rendered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_global/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_global/__init__.py
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
new file mode 100644
index 000000000..38c4e1ab3
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/bgp_global/bgp_global.py
@@ -0,0 +1,952 @@
+# -*- coding: utf-8 -*-
+# Copyright 2022 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
+# cli_rm_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.
+#
+#############################################
+
+"""
+The arg spec for the ios_bgp_global module
+"""
+
+
+class Bgp_globalArgs(object): # pylint: disable=R0903
+ """The arg spec for the ios_bgp_global module"""
+
+ argument_spec = {
+ "config": {
+ "type": "dict",
+ "options": {
+ "as_number": {"type": "str"},
+ "aggregate_address": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "netmask": {"type": "str"},
+ "advertise_map": {"type": "str"},
+ "as_confed_set": {"type": "bool"},
+ "as_set": {"type": "bool"},
+ "attribute_map": {"type": "str"},
+ "summary_only": {"type": "bool"},
+ "suppress_map": {"type": "str"},
+ },
+ },
+ "aggregate_addresses": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "netmask": {"type": "str"},
+ "advertise_map": {"type": "str"},
+ "as_confed_set": {"type": "bool"},
+ "as_set": {"type": "bool"},
+ "attribute_map": {"type": "str"},
+ "summary_only": {"type": "bool"},
+ "suppress_map": {"type": "str"},
+ },
+ },
+ "auto_summary": {"type": "bool"},
+ "bgp": {
+ "type": "dict",
+ "options": {
+ "additional_paths": {
+ "type": "dict",
+ "options": {
+ "install": {"type": "bool"},
+ "receive": {"type": "bool"},
+ "select": {
+ "type": "dict",
+ "options": {
+ "all": {"type": "bool"},
+ "best": {"type": "int"},
+ "best_external": {"type": "bool"},
+ "group_best": {"type": "bool"},
+ },
+ },
+ "send": {"type": "bool"},
+ },
+ },
+ "advertise_best_external": {"type": "bool"},
+ "aggregate_timer": {"type": "int"},
+ "always_compare_med": {"type": "bool"},
+ "asnotation": {"type": "bool"},
+ "bestpath": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "aigp": {"type": "bool"},
+ "compare_routerid": {"type": "bool"},
+ "cost_community": {"type": "bool"},
+ "igp_metric": {"type": "bool"},
+ "med": {
+ "type": "dict",
+ "options": {
+ "confed": {"type": "bool"},
+ "missing_as_worst": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "bestpath_options": {
+ "type": "dict",
+ "options": {
+ "aigp": {"type": "bool"},
+ "compare_routerid": {"type": "bool"},
+ "cost_community": {"type": "bool"},
+ "igp_metric": {"type": "bool"},
+ "med": {
+ "type": "dict",
+ "options": {
+ "confed": {"type": "bool"},
+ "missing_as_worst": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "client_to_client": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "all": {"type": "bool"},
+ "intra_cluster": {"type": "str"},
+ },
+ },
+ "cluster_id": {"type": "str"},
+ "confederation": {
+ "type": "dict",
+ "options": {"identifier": {"type": "str"}, "peers": {"type": "str"}},
+ },
+ "consistency_checker": {
+ "type": "dict",
+ "options": {
+ "auto_repair": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "interval": {"type": "int"},
+ },
+ },
+ "error_message": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "interval": {"type": "int"},
+ },
+ },
+ },
+ },
+ "dampening": {
+ "type": "dict",
+ "options": {
+ "penalty_half_time": {"type": "int"},
+ "reuse_route_val": {"type": "int"},
+ "suppress_route_val": {"type": "int"},
+ "max_suppress": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "deterministic_med": {"type": "bool"},
+ "dmzlink_bw": {"type": "bool"},
+ "enforce_first_as": {"type": "bool"},
+ "enhanced_error": {"type": "bool"},
+ "fast_external_fallover": {"type": "bool"},
+ "graceful_restart": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "extended": {"type": "bool"},
+ "restart_time": {"type": "int"},
+ "stalepath_time": {"type": "int"},
+ },
+ },
+ "graceful_shutdown": {
+ "type": "dict",
+ "options": {
+ "neighbors": {
+ "type": "dict",
+ "options": {
+ "time": {"type": "int"},
+ "activate": {"type": "bool"},
+ },
+ },
+ "vrfs": {
+ "type": "dict",
+ "options": {
+ "time": {"type": "int"},
+ "activate": {"type": "bool"},
+ },
+ },
+ "community": {"type": "str"},
+ "local_preference": {"type": "int"},
+ },
+ },
+ "inject_map": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "exist_map_name": {"type": "str"},
+ "copy_attributes": {"type": "bool"},
+ },
+ },
+ "inject_maps": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "exist_map_name": {"type": "str"},
+ "copy_attributes": {"type": "bool"},
+ },
+ },
+ "listen": {
+ "type": "dict",
+ "options": {
+ "limit": {"type": "int"},
+ "range": {
+ "type": "dict",
+ "options": {
+ "ipv4_with_subnet": {"type": "str"},
+ "ipv6_with_subnet": {"type": "str"},
+ "host_with_subnet": {"type": "str"},
+ "peer_group": {"type": "str"},
+ },
+ },
+ },
+ },
+ "log_neighbor_changes": {"type": "bool"},
+ "maxas_limit": {"type": "int"},
+ "maxcommunity_limit": {"type": "int"},
+ "maxextcommunity_limit": {"type": "int"},
+ "nexthop": {
+ "type": "dict",
+ "options": {
+ "route_map": {"type": "str"},
+ "trigger": {
+ "type": "dict",
+ "options": {
+ "delay": {"type": "int"},
+ "enable": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "nopeerup_delay": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "cold_boot": {"type": "int"},
+ "nsf_switchover": {"type": "int"},
+ "post_boot": {"type": "int"},
+ "user_initiated": {"type": "int"},
+ },
+ },
+ "nopeerup_delay_options": {
+ "type": "dict",
+ "options": {
+ "cold_boot": {"type": "int"},
+ "nsf_switchover": {"type": "int"},
+ "post_boot": {"type": "int"},
+ "user_initiated": {"type": "int"},
+ },
+ },
+ "recursion": {"type": "bool"},
+ "redistribute_internal": {"type": "bool"},
+ "refresh": {
+ "type": "dict",
+ "options": {
+ "max_eor_time": {"type": "int"},
+ "stalepath_time": {"type": "int"},
+ },
+ },
+ "regexp": {"type": "bool"},
+ "route_map": {"type": "bool"},
+ "router_id": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "interface": {"type": "str"},
+ "vrf": {"type": "bool"},
+ },
+ },
+ "scan_time": {"type": "int"},
+ "slow_peer": {
+ "type": "dict",
+ "options": {
+ "detection": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "threshold": {"type": "int"},
+ },
+ },
+ "split_update_group": {
+ "type": "dict",
+ "options": {
+ "dynamic": {"type": "bool"},
+ "permanent": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "snmp": {"type": "bool"},
+ "sso": {"type": "bool"},
+ "soft_reconfig_backup": {"type": "bool"},
+ "suppress_inactive": {"type": "bool"},
+ "transport": {"type": "bool"},
+ "update_delay": {"type": "int"},
+ "update_group": {"type": "bool"},
+ "upgrade_cli": {
+ "type": "dict",
+ "options": {"set": {"type": "bool"}, "af_mode": {"type": "bool"}},
+ },
+ },
+ },
+ "bmp": {
+ "type": "dict",
+ "options": {
+ "buffer_size": {"type": "int"},
+ "initial_refresh": {
+ "type": "dict",
+ "options": {"delay": {"type": "int"}, "skip": {"type": "bool"}},
+ },
+ "server": {"type": "int"},
+ "server_options": {
+ "type": "dict",
+ "options": {
+ "activate": {"type": "bool"},
+ "address": {
+ "type": "dict",
+ "options": {"host": {"type": "str"}, "port": {"type": "int"}},
+ },
+ },
+ },
+ },
+ },
+ "default_information": {"type": "bool"},
+ "default_metric": {"type": "int"},
+ "distance": {
+ "type": "dict",
+ "options": {
+ "admin": {
+ "type": "dict",
+ "options": {
+ "distance": {"type": "int"},
+ "address": {"type": "str"},
+ "wildcard_bit": {"type": "str"},
+ "acl": {"type": "str"},
+ },
+ },
+ "bgp": {
+ "type": "dict",
+ "options": {
+ "routes_external": {"type": "int"},
+ "routes_internal": {"type": "int"},
+ "routes_local": {"type": "int"},
+ },
+ },
+ "mbgp": {
+ "type": "dict",
+ "options": {
+ "routes_external": {"type": "int"},
+ "routes_internal": {"type": "int"},
+ "routes_local": {"type": "int"},
+ },
+ },
+ },
+ },
+ "distributes": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "prefix": {"type": "str"},
+ "gateway": {"type": "str"},
+ "acl": {"type": "str"},
+ "in": {"type": "bool"},
+ "out": {"type": "bool"},
+ "interface": {"type": "str"},
+ },
+ },
+ "distribute_list": {
+ "type": "dict",
+ "options": {
+ "acl": {"type": "str"},
+ "in": {"type": "bool"},
+ "out": {"type": "bool"},
+ "interface": {"type": "str"},
+ },
+ },
+ "maximum_paths": {
+ "type": "dict",
+ "options": {
+ "paths": {"type": "int"},
+ "eibgp": {"type": "int"},
+ "ibgp": {"type": "int"},
+ },
+ },
+ "maximum_secondary_paths": {
+ "type": "dict",
+ "options": {
+ "paths": {"type": "int"},
+ "eibgp": {"type": "int"},
+ "ibgp": {"type": "int"},
+ },
+ },
+ "neighbors": {
+ "type": "list",
+ "elements": "dict",
+ "aliases": ["neighbor"],
+ "options": {
+ "neighbor_address": {"type": "str"},
+ "address": {"type": "str"},
+ "tag": {"type": "str"},
+ "ipv6_adddress": {"type": "str"},
+ "activate": {"type": "bool"},
+ "additional_paths": {
+ "type": "dict",
+ "options": {
+ "disable": {"type": "bool"},
+ "receive": {"type": "bool"},
+ "send": {"type": "bool"},
+ },
+ },
+ "advertise": {
+ "type": "dict",
+ "options": {
+ "additional_paths": {
+ "type": "dict",
+ "options": {
+ "all": {"type": "bool"},
+ "best": {"type": "int"},
+ "group_best": {"type": "bool"},
+ },
+ },
+ "best_external": {"type": "bool"},
+ "diverse_path": {
+ "type": "dict",
+ "options": {
+ "backup": {"type": "bool"},
+ "mpath": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "advertise_map": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "exist_map": {"type": "str"},
+ "non_exist_map": {"type": "str"},
+ },
+ },
+ "advertisement_interval": {"type": "int"},
+ "aigp": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "send": {
+ "type": "dict",
+ "options": {
+ "cost_community": {
+ "type": "dict",
+ "options": {
+ "id": {"type": "int"},
+ "poi": {
+ "type": "dict",
+ "options": {
+ "igp_cost": {"type": "bool"},
+ "pre_bestpath": {"type": "bool"},
+ "transitive": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "med": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "allow_policy": {"type": "bool"},
+ "allowas_in": {"type": "int"},
+ "as_override": {"type": "bool"},
+ "bmp_activate": {
+ "type": "dict",
+ "options": {"all": {"type": "bool"}, "server": {"type": "int"}},
+ },
+ "capability": {
+ "type": "dict",
+ "options": {
+ "both": {"type": "bool"},
+ "receive": {"type": "bool"},
+ "send": {"type": "bool"},
+ },
+ },
+ "cluster_id": {"type": "str"},
+ "default_originate": {
+ "type": "dict",
+ "options": {"set": {"type": "bool"}, "route_map": {"type": "str"}},
+ },
+ "description": {"type": "str"},
+ "disable_connected_check": {"type": "bool"},
+ "distribute_list": {
+ "type": "dict",
+ "options": {
+ "acl": {"type": "str"},
+ "in": {"type": "bool"},
+ "out": {"type": "bool"},
+ },
+ },
+ "dmzlink_bw": {"type": "bool"},
+ "ebgp_multihop": {
+ "type": "dict",
+ "options": {"enable": {"type": "bool"}, "hop_count": {"type": "int"}},
+ },
+ "fall_over": {
+ "type": "dict",
+ "options": {
+ "bfd": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "multi_hop": {"type": "bool"},
+ "single_hop": {"type": "bool"},
+ },
+ },
+ "route_map": {"type": "str"},
+ },
+ },
+ "filter_list": {
+ "type": "dict",
+ "options": {
+ "path_acl": {"type": "str"},
+ "in": {"type": "bool"},
+ "out": {"type": "bool"},
+ },
+ },
+ "ha_mode": {
+ "type": "dict",
+ "options": {"set": {"type": "bool"}, "disable": {"type": "bool"}},
+ },
+ "inherit": {"type": "str"},
+ "local_as": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "number": {"type": "int"},
+ "dual_as": {"type": "bool"},
+ "no_prepend": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "replace_as": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "log_neighbor_changes": {
+ "type": "dict",
+ "options": {"set": {"type": "bool"}, "disable": {"type": "bool"}},
+ },
+ "maximum_prefix": {
+ "type": "dict",
+ "options": {
+ "max_no": {"type": "int"},
+ "threshold_val": {"type": "int"},
+ "restart": {"type": "int"},
+ "warning_only": {"type": "bool"},
+ },
+ },
+ "next_hop_self": {
+ "type": "dict",
+ "options": {"set": {"type": "bool"}, "all": {"type": "bool"}},
+ },
+ "next_hop_unchanged": {
+ "type": "dict",
+ "options": {"set": {"type": "bool"}, "allpaths": {"type": "bool"}},
+ },
+ "password": {"type": "str", "no_log": True},
+ "password_options": {
+ "type": "dict",
+ "no_log": False,
+ "options": {
+ "encryption": {"type": "int"},
+ "pass_key": {"type": "str", "no_log": True},
+ },
+ },
+ "path_attribute": {
+ "type": "dict",
+ "options": {
+ "discard": {
+ "type": "dict",
+ "options": {
+ "type": {"type": "int"},
+ "range": {
+ "type": "dict",
+ "options": {
+ "start": {"type": "int"},
+ "end": {"type": "int"},
+ },
+ },
+ "in": {"type": "bool"},
+ },
+ },
+ "treat_as_withdraw": {
+ "type": "dict",
+ "options": {
+ "type": {"type": "int"},
+ "range": {
+ "type": "dict",
+ "options": {
+ "start": {"type": "int"},
+ "end": {"type": "int"},
+ },
+ },
+ "in": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "peer_group": {"type": "str"},
+ "remote_as": {"type": "str"},
+ "remove_private_as": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "all": {"type": "bool"},
+ "replace_as": {"type": "bool"},
+ },
+ },
+ "route_map": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "in": {"type": "bool"},
+ "out": {"type": "bool"},
+ },
+ },
+ "route_maps": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "in": {"type": "bool"},
+ "out": {"type": "bool"},
+ },
+ },
+ "route_reflector_client": {"type": "bool"},
+ "route_server_client": {
+ "type": "dict",
+ "options": {"set": {"type": "bool"}, "context": {"type": "str"}},
+ },
+ "send_community": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "both": {"type": "bool"},
+ "extended": {"type": "bool"},
+ "standard": {"type": "bool"},
+ },
+ },
+ "send_label": {
+ "type": "dict",
+ "options": {"set": {"type": "bool"}, "explicit_null": {"type": "bool"}},
+ },
+ "shutdown": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "graceful": {"type": "int"},
+ "community": {"type": "int"},
+ "local_preference": {"type": "bool"},
+ },
+ },
+ "slow_peer": {
+ "type": "dict",
+ "options": {
+ "detection": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "disable": {"type": "bool"},
+ "threshold": {"type": "int"},
+ },
+ },
+ "split_update_group": {
+ "type": "dict",
+ "options": {
+ "dynamic": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "disable": {"type": "bool"},
+ "permanent": {"type": "bool"},
+ },
+ },
+ "static": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "soft_reconfiguration": {"type": "bool"},
+ "timers": {
+ "type": "dict",
+ "options": {
+ "interval": {"type": "int"},
+ "holdtime": {"type": "int"},
+ "min_holdtime": {"type": "int"},
+ },
+ },
+ "translate_update": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "nlri": {
+ "type": "dict",
+ "options": {
+ "multicast": {"type": "bool"},
+ "unicast": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "transport": {
+ "type": "dict",
+ "options": {
+ "connection_mode": {
+ "type": "dict",
+ "options": {
+ "active": {"type": "bool"},
+ "passive": {"type": "bool"},
+ },
+ },
+ "multi_session": {"type": "bool"},
+ "path_mtu_discovery": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "disable": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "ttl_security": {"type": "int"},
+ "unsuppress_map": {"type": "str"},
+ "update_source": {"type": "str"},
+ "version": {"type": "int"},
+ "weight": {"type": "int"},
+ },
+ },
+ "networks": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "netmask": {"type": "str"},
+ "route_map": {"type": "str"},
+ "backdoor": {"type": "bool"},
+ },
+ },
+ "redistribute": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "application": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "bgp": {
+ "type": "dict",
+ "options": {
+ "as_number": {"type": "str"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "connected": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "eigrp": {
+ "type": "dict",
+ "options": {
+ "as_number": {"type": "str"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "isis": {
+ "type": "dict",
+ "options": {
+ "area_tag": {"type": "str"},
+ "clns": {"type": "bool"},
+ "ip": {"type": "bool"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "iso_igrp": {
+ "type": "dict",
+ "options": {"area_tag": {"type": "str"}, "route_map": {"type": "str"}},
+ },
+ "lisp": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "mobile": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "odr": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "ospf": {
+ "type": "dict",
+ "options": {
+ "process_id": {"type": "int"},
+ "match": {
+ "type": "dict",
+ "options": {
+ "external": {"type": "bool"},
+ "internal": {"type": "bool"},
+ "nssa_external": {"type": "bool"},
+ "type_1": {"type": "bool"},
+ "type_2": {"type": "bool"},
+ },
+ },
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ "vrf": {"type": "str"},
+ },
+ },
+ "ospfv3": {
+ "type": "dict",
+ "options": {
+ "process_id": {"type": "int"},
+ "match": {
+ "type": "dict",
+ "options": {
+ "external": {"type": "bool"},
+ "internal": {"type": "bool"},
+ "nssa_external": {"type": "bool"},
+ "type_1": {"type": "bool"},
+ "type_2": {"type": "bool"},
+ },
+ },
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "rip": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "static": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "clns": {"type": "bool"},
+ "ip": {"type": "bool"},
+ "metric": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "vrf": {
+ "type": "dict",
+ "options": {"name": {"type": "str"}, "global": {"type": "bool"}},
+ },
+ },
+ },
+ "route_server_context": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "address_family": {
+ "type": "dict",
+ "options": {
+ "afi": {"type": "str", "choices": ["ipv4", "ipv6"]},
+ "modifier": {"type": "str", "choices": ["multicast", "unicast"]},
+ "import_map": {"type": "str"},
+ },
+ },
+ "description": {"type": "str"},
+ },
+ },
+ "scope": {
+ "type": "dict",
+ "options": {"global": {"type": "bool"}, "vrf": {"type": "str"}},
+ },
+ "synchronization": {"type": "bool"},
+ "table_map": {
+ "type": "dict",
+ "options": {"name": {"type": "str"}, "filter": {"type": "bool"}},
+ },
+ "template": {
+ "type": "dict",
+ "options": {"peer_policy": {"type": "str"}, "peer_session": {"type": "str"}},
+ },
+ "timers": {
+ "type": "dict",
+ "options": {
+ "keepalive": {"type": "int"},
+ "holdtime": {"type": "int"},
+ "min_holdtime": {"type": "int"},
+ },
+ },
+ },
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "deleted",
+ "purged",
+ "gathered",
+ "rendered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/facts/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/facts/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/facts/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/facts/facts.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/facts/facts.py
new file mode 100644
index 000000000..18c33971b
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/facts/facts.py
@@ -0,0 +1,26 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The arg spec for the ios facts module.
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class FactsArgs(object):
+ """The arg spec for the ios facts module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "gather_subset": dict(default=["min"], type="list", elements="str"),
+ "gather_network_resources": dict(type="list", elements="str"),
+ "available_network_resources": {"type": "bool", "default": False},
+ }
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/hostname/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/hostname/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/hostname/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/hostname/hostname.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/hostname/hostname.py
new file mode 100644
index 000000000..f3cdca182
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/hostname/hostname.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+# Copyright 2022 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
+# cli_rm_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.
+#
+#############################################
+
+"""
+The arg spec for the ios_hostname module
+"""
+
+
+class HostnameArgs(object): # pylint: disable=R0903
+ """The arg spec for the ios_hostname module"""
+
+ argument_spec = {
+ "config": {"type": "dict", "options": {"hostname": {"type": "str"}}},
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "rendered",
+ "gathered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/interfaces/interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/interfaces/interfaces.py
new file mode 100644
index 000000000..ce5cbb65f
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/interfaces/interfaces.py
@@ -0,0 +1,64 @@
+# -*- coding: utf-8 -*-
+# Copyright 2022 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
+# cli_rm_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.
+#
+#############################################
+
+"""
+The arg spec for the ios_interfaces module
+"""
+
+
+class InterfacesArgs(object): # pylint: disable=R0903
+ """The arg spec for the ios_interfaces module"""
+
+ argument_spec = {
+ "config": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str", "required": True},
+ "description": {"type": "str"},
+ "enabled": {"type": "bool", "default": True},
+ "speed": {"type": "str"},
+ "mtu": {"type": "int"},
+ "mode": {"choices": ["layer2", "layer3"], "type": "str"},
+ "duplex": {"type": "str", "choices": ["full", "half", "auto"]},
+ "template": {"type": "str"},
+ },
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "rendered",
+ "gathered",
+ "purged",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l2_interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l2_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l2_interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l2_interfaces/l2_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l2_interfaces/l2_interfaces.py
new file mode 100644
index 000000000..e7a65dd1c
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l2_interfaces/l2_interfaces.py
@@ -0,0 +1,91 @@
+# -*- coding: utf-8 -*-
+# Copyright 2022 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
+# cli_rm_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.
+#
+#############################################
+
+"""
+The arg spec for the ios_l2_interfaces module
+"""
+
+
+class L2_interfacesArgs(object): # pylint: disable=R0903
+ """The arg spec for the ios_l2_interfaces module"""
+
+ argument_spec = {
+ "config": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str", "required": True},
+ "access": {
+ "type": "dict",
+ "options": {"vlan": {"type": "int"}, "vlan_name": {"type": "str"}},
+ },
+ "voice": {
+ "type": "dict",
+ "options": {
+ "vlan": {"type": "int"},
+ "vlan_tag": {"choices": ["dot1p", "none", "untagged"], "type": "str"},
+ "vlan_name": {"type": "str"},
+ },
+ },
+ "trunk": {
+ "type": "dict",
+ "options": {
+ "allowed_vlans": {"type": "list", "elements": "str"},
+ "native_vlan": {"type": "int"},
+ "encapsulation": {"choices": ["dot1q", "isl", "negotiate"], "type": "str"},
+ "pruning_vlans": {"type": "list", "elements": "str"},
+ },
+ },
+ "mode": {
+ "type": "str",
+ "choices": [
+ "access",
+ "trunk",
+ "dot1q_tunnel",
+ "dynamic",
+ "dynamic_auto",
+ "dynamic_desirable",
+ "private_vlan_host",
+ "private_vlan_promiscuous",
+ "private_vlan_trunk",
+ ],
+ },
+ },
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "rendered",
+ "gathered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l3_interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l3_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l3_interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l3_interfaces/l3_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l3_interfaces/l3_interfaces.py
new file mode 100644
index 000000000..455261409
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/l3_interfaces/l3_interfaces.py
@@ -0,0 +1,105 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 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
+# cli_rm_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.
+#
+#############################################
+
+"""
+The arg spec for the ios_l3_interfaces module
+"""
+
+
+class L3_interfacesArgs(object): # pylint: disable=R0903
+ """The arg spec for the ios_l3_interfaces module"""
+
+ argument_spec = {
+ "config": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str", "required": True},
+ "ipv4": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "secondary": {"type": "bool"},
+ "dhcp_client": {"type": "str"},
+ "dhcp_hostname": {"type": "str"},
+ "dhcp": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "client_id": {"type": "str"},
+ "hostname": {"type": "str"},
+ },
+ },
+ "pool": {"type": "str"},
+ },
+ },
+ "ipv6": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "autoconfig": {
+ "type": "dict",
+ "options": {"enable": {"type": "bool"}, "default": {"type": "bool"}},
+ },
+ "dhcp": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "rapid_commit": {"type": "bool"},
+ },
+ },
+ "anycast": {"type": "bool"},
+ "cga": {"type": "bool"},
+ "eui": {"type": "bool"},
+ "link_local": {"type": "bool"},
+ "segment_routing": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "default": {"type": "bool"},
+ "ipv6_sr": {"type": "bool"},
+ },
+ },
+ },
+ },
+ },
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "rendered",
+ "gathered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp/__init__.py
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
new file mode 100644
index 000000000..3e346db12
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp/lacp.py
@@ -0,0 +1,57 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#############################################
+# WARNING #
+#############################################
+#
+# This file is auto generated by the resource
+# module builder playbook.
+#
+# Do not edit this file manually.
+#
+# Changes to this file will be over written
+# by the resource module builder.
+#
+# Changes should be made in the model used to
+# generate this file or in the resource module
+# builder template.
+#
+#############################################
+
+"""
+The arg spec for the ios_lacp module
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class LacpArgs(object):
+ """The arg spec for the ios_lacp module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "options": {
+ "system": {
+ "options": {"priority": {"required": True, "type": "int"}},
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": ["merged", "replaced", "deleted", "rendered", "parsed", "gathered"],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp_interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp_interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp_interfaces/lacp_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp_interfaces/lacp_interfaces.py
new file mode 100644
index 000000000..594cfa122
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lacp_interfaces/lacp_interfaces.py
@@ -0,0 +1,66 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#############################################
+# WARNING #
+#############################################
+#
+# This file is auto generated by the resource
+# module builder playbook.
+#
+# Do not edit this file manually.
+#
+# Changes to this file will be over written
+# by the resource module builder.
+#
+# Changes should be made in the model used to
+# generate this file or in the resource module
+# builder template.
+#
+#############################################
+
+"""
+The arg spec for the ios_lacp_interfaces module
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class Lacp_InterfacesArgs(object):
+ """The arg spec for the ios_lacp_interfaces module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "elements": "dict",
+ "options": {
+ "name": {"required": True, "type": "str"},
+ "port_priority": {"type": "int"},
+ "fast_switchover": {"type": "bool"},
+ "max_bundle": {"type": "int"},
+ },
+ "type": "list",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "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/lag_interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lag_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lag_interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lag_interfaces/lag_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lag_interfaces/lag_interfaces.py
new file mode 100644
index 000000000..29332f73e
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lag_interfaces/lag_interfaces.py
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+# Copyright 2022 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
+# cli_rm_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.
+#
+#############################################
+
+"""
+The arg spec for the ios_lag_interfaces module
+"""
+
+
+class Lag_InterfacesArgs(object): # pylint: disable=R0903
+ """The arg spec for the ios_lag_interfaces module"""
+
+ argument_spec = {
+ "config": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str", "required": True},
+ "members": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "member": {"type": "str"},
+ "mode": {
+ "type": "str",
+ "choices": ["auto", "desirable", "on", "active", "passive"],
+ },
+ "link": {"type": "int"},
+ },
+ },
+ },
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "type": "str",
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "rendered",
+ "parsed",
+ "gathered",
+ ],
+ "default": "merged",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_global/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_global/__init__.py
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
new file mode 100644
index 000000000..841e34bed
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_global/lldp_global.py
@@ -0,0 +1,68 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#############################################
+# WARNING #
+#############################################
+#
+# This file is auto generated by the resource
+# module builder playbook.
+#
+# Do not edit this file manually.
+#
+# Changes to this file will be over written
+# by the resource module builder.
+#
+# Changes should be made in the model used to
+# generate this file or in the resource module
+# builder template.
+#
+#############################################
+"""
+The arg spec for the ios_lldp_global module
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class Lldp_globalArgs(object):
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "options": {
+ "holdtime": {"type": "int"},
+ "reinit": {"type": "int"},
+ "enabled": {"type": "bool"},
+ "timer": {"type": "int"},
+ "tlv_select": {
+ "options": {
+ "four_wire_power_management": {"type": "bool"},
+ "mac_phy_cfg": {"type": "bool"},
+ "management_address": {"type": "bool"},
+ "port_description": {"type": "bool"},
+ "port_vlan": {"type": "bool"},
+ "power_management": {"type": "bool"},
+ "system_capabilities": {"type": "bool"},
+ "system_description": {"type": "bool"},
+ "system_name": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": ["merged", "replaced", "deleted", "rendered", "parsed", "gathered"],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_interfaces/lldp_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_interfaces/lldp_interfaces.py
new file mode 100644
index 000000000..080d3fe97
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/lldp_interfaces/lldp_interfaces.py
@@ -0,0 +1,70 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#############################################
+# WARNING #
+#############################################
+#
+# This file is auto generated by the resource
+# module builder playbook.
+#
+# Do not edit this file manually.
+#
+# Changes to this file will be over written
+# by the resource module builder.
+#
+# Changes should be made in the model used to
+# generate this file or in the resource module
+# builder template.
+#
+#############################################
+
+"""
+The arg spec for the ios_lldp_interfaces module
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class Lldp_InterfacesArgs(object):
+ """The arg spec for the ios_lldp_interfaces module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "elements": "dict",
+ "options": {
+ "name": {"required": True, "type": "str"},
+ "transmit": {"type": "bool"},
+ "receive": {"type": "bool"},
+ "med_tlv_select": {
+ "options": {"inventory_management": {"type": "bool"}},
+ "type": "dict",
+ },
+ "tlv_select": {"options": {"power_management": {"type": "bool"}}, "type": "dict"},
+ },
+ "type": "list",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "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/logging_global/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/logging_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/logging_global/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/logging_global/logging_global.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/logging_global/logging_global.py
new file mode 100644
index 000000000..44dd19352
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/logging_global/logging_global.py
@@ -0,0 +1,374 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 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
+# cli_rm_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.
+#
+#############################################
+
+"""
+The arg spec for the ios_logging_global module
+"""
+
+
+class Logging_globalArgs(object): # pylint: disable=R0903
+ """The arg spec for the ios_logging_global module"""
+
+ argument_spec = {
+ "config": {
+ "type": "dict",
+ "options": {
+ "buffered": {
+ "type": "dict",
+ "options": {
+ "size": {"type": "int"},
+ "severity": {
+ "type": "str",
+ "choices": [
+ "alerts",
+ "critical",
+ "debugging",
+ "emergencies",
+ "errors",
+ "informational",
+ "notifications",
+ "warnings",
+ ],
+ },
+ "discriminator": {"type": "str"},
+ "filtered": {"type": "bool"},
+ "xml": {"type": "bool"},
+ },
+ },
+ "buginf": {"type": "bool"},
+ "cns_events": {
+ "type": "str",
+ "choices": [
+ "alerts",
+ "critical",
+ "debugging",
+ "emergencies",
+ "errors",
+ "informational",
+ "notifications",
+ "warnings",
+ ],
+ },
+ "console": {
+ "type": "dict",
+ "options": {
+ "severity": {
+ "type": "str",
+ "choices": [
+ "alerts",
+ "critical",
+ "debugging",
+ "emergencies",
+ "errors",
+ "informational",
+ "notifications",
+ "warnings",
+ "guaranteed",
+ ],
+ },
+ "discriminator": {"type": "str"},
+ "filtered": {"type": "bool"},
+ "xml": {"type": "bool"},
+ },
+ },
+ "count": {"type": "bool"},
+ "delimiter": {"type": "dict", "options": {"tcp": {"type": "bool"}}},
+ "discriminator": {"type": "list", "elements": "str"},
+ "dmvpn": {"type": "dict", "options": {"rate_limit": {"type": "int"}}},
+ "esm": {"type": "dict", "options": {"config": {"type": "bool"}}},
+ "exception": {"type": "int"},
+ "facility": {
+ "type": "str",
+ "choices": [
+ "auth",
+ "cron",
+ "daemon",
+ "kern",
+ "local0",
+ "local1",
+ "local2",
+ "local3",
+ "local4",
+ "local5",
+ "local6",
+ "local7",
+ "lpr",
+ "mail",
+ "news",
+ "sys10",
+ "sys11",
+ "sys12",
+ "sys13",
+ "sys14",
+ "sys9",
+ "syslog",
+ "user",
+ "uucp",
+ ],
+ },
+ "filter": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "url": {"type": "str"},
+ "order": {"type": "int"},
+ "args": {"type": "str"},
+ },
+ },
+ "history": {
+ "type": "dict",
+ "options": {
+ "size": {"type": "int"},
+ "severity": {
+ "type": "str",
+ "choices": [
+ "alerts",
+ "critical",
+ "debugging",
+ "emergencies",
+ "errors",
+ "informational",
+ "notifications",
+ "warnings",
+ ],
+ },
+ },
+ },
+ "hosts": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "discriminator": {"type": "str"},
+ "filtered": {"type": "bool"},
+ "sequence_num_session": {"type": "bool"},
+ "session_id": {
+ "type": "dict",
+ "options": {
+ "tag": {"type": "str", "choices": ["hostname", "ipv4", "ipv6"]},
+ "text": {"type": "str"},
+ },
+ },
+ "stream": {"type": "int"},
+ "transport": {
+ "type": "dict",
+ "options": {
+ "tcp": {
+ "type": "dict",
+ "options": {
+ "audit": {"type": "bool"},
+ "discriminator": {"type": "str"},
+ "stream": {"type": "int"},
+ "filtered": {"type": "bool"},
+ "port": {"type": "int"},
+ "sequence_num_session": {"type": "bool"},
+ "session_id": {
+ "type": "dict",
+ "options": {
+ "tag": {
+ "type": "str",
+ "choices": ["hostname", "ipv4", "ipv6"],
+ },
+ "text": {"type": "str"},
+ },
+ },
+ "xml": {"type": "bool"},
+ },
+ },
+ "udp": {
+ "type": "dict",
+ "options": {
+ "discriminator": {"type": "str"},
+ "stream": {"type": "int"},
+ "filtered": {"type": "bool"},
+ "port": {"type": "int"},
+ "sequence_num_session": {"type": "bool"},
+ "session_id": {
+ "type": "dict",
+ "options": {
+ "tag": {
+ "type": "str",
+ "choices": ["hostname", "ipv4", "ipv6"],
+ },
+ "text": {"type": "str"},
+ },
+ },
+ "xml": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "vrf": {"type": "str"},
+ "xml": {"type": "bool"},
+ "ipv6": {"type": "str"},
+ "host": {"type": "str", "aliases": ["hostname"]},
+ },
+ },
+ "message_counter": {
+ "type": "list",
+ "elements": "str",
+ "choices": ["log", "debug", "syslog"],
+ },
+ "monitor": {
+ "type": "dict",
+ "options": {
+ "severity": {
+ "type": "str",
+ "choices": [
+ "alerts",
+ "critical",
+ "debugging",
+ "emergencies",
+ "errors",
+ "informational",
+ "notifications",
+ "warnings",
+ ],
+ },
+ "discriminator": {"type": "str"},
+ "filtered": {"type": "bool"},
+ "xml": {"type": "bool"},
+ },
+ },
+ "logging_on": {"type": "str", "choices": ["enable", "disable"]},
+ "origin_id": {
+ "type": "dict",
+ "options": {
+ "tag": {"type": "str", "choices": ["hostname", "ip", "ipv6"]},
+ "text": {"type": "str"},
+ },
+ },
+ "persistent": {
+ "type": "dict",
+ "options": {
+ "batch": {"type": "int"},
+ "filesize": {"type": "int"},
+ "immediate": {"type": "bool"},
+ "notify": {"type": "bool"},
+ "protected": {"type": "bool"},
+ "size": {"type": "int"},
+ "threshold": {"type": "int"},
+ "url": {"type": "str"},
+ },
+ },
+ "policy_firewall": {"type": "dict", "options": {"rate_limit": {"type": "int"}}},
+ "queue_limit": {
+ "type": "dict",
+ "options": {
+ "size": {"type": "int"},
+ "esm": {"type": "int"},
+ "trap": {"type": "int"},
+ },
+ },
+ "rate_limit": {
+ "type": "dict",
+ "options": {
+ "size": {"type": "int", "required": True},
+ "all": {"type": "bool"},
+ "console": {"type": "bool"},
+ "except_severity": {
+ "type": "str",
+ "choices": [
+ "alerts",
+ "critical",
+ "debugging",
+ "emergencies",
+ "errors",
+ "informational",
+ "notifications",
+ "warnings",
+ ],
+ },
+ },
+ },
+ "reload": {
+ "type": "dict",
+ "options": {
+ "severity": {
+ "type": "str",
+ "choices": [
+ "alerts",
+ "critical",
+ "debugging",
+ "emergencies",
+ "errors",
+ "informational",
+ "notifications",
+ "warnings",
+ ],
+ },
+ "message_limit": {"type": "int"},
+ },
+ },
+ "server_arp": {"type": "bool"},
+ "snmp_trap": {
+ "type": "list",
+ "elements": "str",
+ "choices": [
+ "alerts",
+ "critical",
+ "debugging",
+ "emergencies",
+ "errors",
+ "informational",
+ "notifications",
+ "warnings",
+ ],
+ },
+ "source_interface": {
+ "type": "list",
+ "elements": "dict",
+ "options": {"interface": {"type": "str"}, "vrf": {"type": "str"}},
+ },
+ "trap": {
+ "type": "str",
+ "choices": [
+ "alerts",
+ "critical",
+ "debugging",
+ "emergencies",
+ "errors",
+ "informational",
+ "notifications",
+ "warnings",
+ ],
+ },
+ "userinfo": {"type": "bool"},
+ },
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "parsed",
+ "rendered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ntp_global/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ntp_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ntp_global/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ntp_global/ntp_global.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ntp_global/ntp_global.py
new file mode 100644
index 000000000..dd36984c1
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ntp_global/ntp_global.py
@@ -0,0 +1,177 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 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
+# cli_rm_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.
+#
+#############################################
+
+"""
+The arg spec for the ios_ntp_global module
+"""
+
+
+class Ntp_globalArgs(object): # pylint: disable=R0903
+ """The arg spec for the ios_ntp_global module"""
+
+ argument_spec = {
+ "config": {
+ "type": "dict",
+ "options": {
+ "access_group": {
+ "type": "dict",
+ "options": {
+ "peer": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "access_list": {"type": "str"},
+ "kod": {"type": "bool"},
+ "ipv4": {"type": "bool"},
+ "ipv6": {"type": "bool"},
+ },
+ },
+ "query_only": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "access_list": {"type": "str"},
+ "kod": {"type": "bool"},
+ "ipv4": {"type": "bool"},
+ "ipv6": {"type": "bool"},
+ },
+ },
+ "serve": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "access_list": {"type": "str"},
+ "kod": {"type": "bool"},
+ "ipv4": {"type": "bool"},
+ "ipv6": {"type": "bool"},
+ },
+ },
+ "serve_only": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "access_list": {"type": "str"},
+ "kod": {"type": "bool"},
+ "ipv4": {"type": "bool"},
+ "ipv6": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "allow": {
+ "type": "dict",
+ "options": {
+ "control": {"type": "dict", "options": {"rate_limit": {"type": "int"}}},
+ "private": {"type": "bool"},
+ },
+ },
+ "authenticate": {"type": "bool"},
+ "authentication_keys": {
+ "type": "list",
+ "elements": "dict",
+ "no_log": False,
+ "options": {
+ "id": {"type": "int"},
+ "algorithm": {"type": "str"},
+ "key": {"type": "str", "no_log": True},
+ "encryption": {"type": "int"},
+ },
+ },
+ "broadcast_delay": {"type": "int"},
+ "clock_period": {"type": "int"},
+ "logging": {"type": "bool"},
+ "master": {
+ "type": "dict",
+ "options": {"enabled": {"type": "bool"}, "stratum": {"type": "int"}},
+ },
+ "max_associations": {"type": "int"},
+ "max_distance": {"type": "int"},
+ "min_distance": {"type": "int"},
+ "orphan": {"type": "int"},
+ "panic_update": {"type": "bool"},
+ "passive": {"type": "bool"},
+ "peers": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "peer": {"type": "str"},
+ "use_ipv4": {"type": "bool"},
+ "use_ipv6": {"type": "bool"},
+ "vrf": {"type": "str"},
+ "burst": {"type": "bool"},
+ "iburst": {"type": "bool"},
+ "key_id": {"type": "int", "aliases": ["key"]},
+ "maxpoll": {"type": "int"},
+ "minpoll": {"type": "int"},
+ "normal_sync": {"type": "bool"},
+ "prefer": {"type": "bool"},
+ "source": {"type": "str"},
+ "version": {"type": "int"},
+ },
+ },
+ "servers": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "server": {"type": "str"},
+ "use_ipv4": {"type": "bool"},
+ "use_ipv6": {"type": "bool"},
+ "vrf": {"type": "str"},
+ "burst": {"type": "bool"},
+ "iburst": {"type": "bool"},
+ "key_id": {"type": "int", "aliases": ["key"]},
+ "maxpoll": {"type": "int"},
+ "minpoll": {"type": "int"},
+ "normal_sync": {"type": "bool"},
+ "prefer": {"type": "bool"},
+ "source": {"type": "str"},
+ "version": {"type": "int"},
+ },
+ },
+ "source": {"type": "str"},
+ "trusted_keys": {
+ "type": "list",
+ "elements": "dict",
+ "no_log": False,
+ "options": {"range_start": {"type": "int"}, "range_end": {"type": "int"}},
+ },
+ "update_calendar": {"type": "bool"},
+ },
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "rendered",
+ "gathered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospf_interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospf_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospf_interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospf_interfaces/ospf_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospf_interfaces/ospf_interfaces.py
new file mode 100644
index 000000000..fafaeb97f
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospf_interfaces/ospf_interfaces.py
@@ -0,0 +1,195 @@
+# -*- 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_ospf_interfaces module
+"""
+
+
+class Ospf_interfacesArgs(object): # pylint: disable=R0903
+ """The arg spec for the ios_ospf_interfaces module"""
+
+ argument_spec = {
+ "config": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str", "required": True},
+ "address_family": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "afi": {
+ "type": "str",
+ "choices": ["ipv4", "ipv6"],
+ "required": True,
+ },
+ "process": {
+ "type": "dict",
+ "options": {
+ "id": {"type": "int"},
+ "area_id": {"type": "str"},
+ "secondaries": {"type": "bool"},
+ "instance_id": {"type": "int"},
+ },
+ },
+ "adjacency": {"type": "bool"},
+ "authentication": {
+ "type": "dict",
+ "options": {
+ "key_chain": {"type": "str", "no_log": True},
+ "message_digest": {"type": "bool"},
+ "null": {"type": "bool"},
+ },
+ },
+ "bfd": {"type": "bool"},
+ "cost": {
+ "type": "dict",
+ "options": {
+ "interface_cost": {"type": "int"},
+ "dynamic_cost": {
+ "type": "dict",
+ "options": {
+ "default": {"type": "int"},
+ "hysteresis": {
+ "type": "dict",
+ "options": {
+ "percent": {"type": "int"},
+ "threshold": {"type": "int"},
+ },
+ },
+ "weight": {
+ "type": "dict",
+ "options": {
+ "l2_factor": {"type": "int"},
+ "latency": {"type": "int"},
+ "oc": {"type": "bool"},
+ "resources": {"type": "int"},
+ "throughput": {"type": "int"},
+ },
+ },
+ },
+ },
+ },
+ },
+ "database_filter": {"type": "bool"},
+ "dead_interval": {
+ "type": "dict",
+ "options": {
+ "time": {"type": "int"},
+ "minimal": {"type": "int"},
+ },
+ },
+ "demand_circuit": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "ignore": {"type": "bool"},
+ "disable": {"type": "bool"},
+ },
+ },
+ "flood_reduction": {"type": "bool"},
+ "hello_interval": {"type": "int"},
+ "lls": {"type": "bool"},
+ "manet": {
+ "type": "dict",
+ "options": {
+ "cost": {
+ "type": "dict",
+ "options": {
+ "percent": {"type": "int"},
+ "threshold": {"type": "int"},
+ },
+ },
+ "link_metrics": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "cost_threshold": {"type": "int"},
+ },
+ },
+ },
+ },
+ "mtu_ignore": {"type": "bool"},
+ "multi_area": {
+ "type": "dict",
+ "options": {
+ "id": {"type": "int"},
+ "cost": {"type": "int"},
+ },
+ },
+ "neighbor": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "cost": {"type": "int"},
+ "database_filter": {"type": "bool"},
+ "poll_interval": {"type": "int"},
+ "priority": {"type": "int"},
+ },
+ },
+ "network": {
+ "type": "dict",
+ "options": {
+ "broadcast": {"type": "bool"},
+ "manet": {"type": "bool"},
+ "non_broadcast": {"type": "bool"},
+ "point_to_multipoint": {"type": "bool"},
+ "point_to_point": {"type": "bool"},
+ },
+ },
+ "prefix_suppression": {"type": "bool"},
+ "priority": {"type": "int"},
+ "resync_timeout": {"type": "int"},
+ "retransmit_interval": {"type": "int"},
+ "shutdown": {"type": "bool"},
+ "transmit_delay": {"type": "int"},
+ "ttl_security": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "hops": {"type": "int"},
+ },
+ },
+ },
+ },
+ },
+ },
+ "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/ospfv2/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv2/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv2/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv2/ospfv2.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv2/ospfv2.py
new file mode 100644
index 000000000..e9e890c6d
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv2/ospfv2.py
@@ -0,0 +1,524 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#############################################
+# WARNING #
+#############################################
+#
+# This file is auto generated by the resource
+# module builder playbook.
+#
+# Do not edit this file manually.
+#
+# Changes to this file will be over written
+# by the resource module builder.
+#
+# Changes should be made in the model used to
+# generate this file or in the resource module
+# builder template.
+#
+#############################################
+
+"""
+The arg spec for the ios_ospfv2 module
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class Ospfv2Args(object):
+ """The arg spec for the ios_ospfv2 module"""
+
+ argument_spec = {
+ "config": {
+ "options": {
+ "processes": {
+ "mutually_exclusive": [("passive_interface", "passive_interfaces")],
+ "elements": "dict",
+ "options": {
+ "address_family": {
+ "options": {
+ "default": {"type": "bool"},
+ "snmp_context": {"type": "str"},
+ "topology": {
+ "options": {
+ "base": {"type": "bool"},
+ "name": {"type": "str"},
+ "tid": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "adjacency": {
+ "options": {
+ "max_adjacency": {"type": "int"},
+ "min_adjacency": {"type": "int"},
+ "none": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "areas": {
+ "elements": "dict",
+ "options": {
+ "area_id": {"type": "str"},
+ "authentication": {
+ "options": {
+ "enable": {"type": "bool"},
+ "message_digest": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "capability": {"type": "bool"},
+ "default_cost": {"type": "int"},
+ "filter_list": {
+ "elements": "dict",
+ "options": {
+ "direction": {
+ "choices": ["in", "out"],
+ "required": True,
+ "type": "str",
+ },
+ "name": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "nssa": {
+ "options": {
+ "default_information_originate": {
+ "options": {
+ "metric": {"type": "int"},
+ "metric_type": {"choices": [1, 2], "type": "int"},
+ "nssa_only": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "no_ext_capability": {"type": "bool"},
+ "no_redistribution": {"type": "bool"},
+ "no_summary": {"type": "bool"},
+ "set": {"type": "bool"},
+ "translate": {
+ "choices": ["always", "suppress-fa"],
+ "type": "str",
+ },
+ },
+ "type": "dict",
+ },
+ "ranges": {
+ "options": {
+ "address": {"type": "str"},
+ "advertise": {"type": "bool"},
+ "cost": {"type": "int"},
+ "netmask": {"type": "str"},
+ "not_advertise": {"type": "bool"},
+ },
+ "type": "list",
+ "elements": "dict",
+ },
+ "sham_link": {
+ "options": {
+ "cost": {"type": "int"},
+ "destination": {"type": "str"},
+ "source": {"type": "str"},
+ "ttl_security": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "stub": {
+ "options": {
+ "no_ext_capability": {"type": "bool"},
+ "no_summary": {"type": "bool"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "list",
+ },
+ "auto_cost": {
+ "options": {
+ "reference_bandwidth": {"type": "int"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "bfd": {"type": "bool"},
+ "capability": {
+ "options": {
+ "lls": {"type": "bool"},
+ "opaque": {"type": "bool"},
+ "transit": {"type": "bool"},
+ "vrf_lite": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "compatible": {
+ "options": {
+ "rfc1583": {"type": "bool"},
+ "rfc1587": {"type": "bool"},
+ "rfc5243": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "default_information": {
+ "options": {
+ "always": {"type": "bool"},
+ "metric": {"type": "int"},
+ "metric_type": {"type": "int"},
+ "originate": {"type": "bool"},
+ "route_map": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "default_metric": {"type": "int"},
+ "discard_route": {
+ "options": {
+ "external": {"type": "int"},
+ "internal": {"type": "int"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "distance": {
+ "options": {
+ "admin_distance": {
+ "options": {
+ "acl": {"type": "str"},
+ "address": {"type": "str"},
+ "distance": {"type": "int"},
+ "wildcard_bits": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "ospf": {
+ "options": {
+ "external": {"type": "int"},
+ "inter_area": {"type": "int"},
+ "intra_area": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "distribute_list": {
+ "options": {
+ "acls": {
+ "elements": "dict",
+ "options": {
+ "direction": {
+ "choices": ["in", "out"],
+ "required": True,
+ "type": "str",
+ },
+ "interface": {"type": "str"},
+ "name": {"required": True, "type": "str"},
+ "protocol": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "prefix": {
+ "options": {
+ "direction": {
+ "choices": ["in", "out"],
+ "required": True,
+ "type": "str",
+ },
+ "gateway_name": {"type": "str"},
+ "interface": {"type": "str"},
+ "name": {"required": True, "type": "str"},
+ "protocol": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "route_map": {
+ "options": {"name": {"required": True, "type": "str"}},
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "domain_id": {
+ "options": {
+ "ip_address": {
+ "options": {
+ "address": {"type": "str"},
+ "secondary": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "null": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "domain_tag": {"type": "int"},
+ "event_log": {
+ "options": {
+ "enable": {"type": "bool"},
+ "one_shot": {"type": "bool"},
+ "pause": {"type": "bool"},
+ "size": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "help": {"type": "bool"},
+ "ignore": {"type": "bool"},
+ "interface_id": {"type": "bool"},
+ "ispf": {"type": "bool"},
+ "limit": {
+ "options": {
+ "dc": {
+ "options": {
+ "disable": {"type": "bool"},
+ "number": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "non_dc": {
+ "options": {
+ "disable": {"type": "bool"},
+ "number": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "local_rib_criteria": {
+ "options": {
+ "enable": {"type": "bool"},
+ "forwarding_address": {"type": "bool"},
+ "inter_area_summary": {"type": "bool"},
+ "nssa_translation": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "log_adjacency_changes": {
+ "options": {"detail": {"type": "bool"}, "set": {"type": "bool"}},
+ "type": "dict",
+ },
+ "max_lsa": {
+ "options": {
+ "ignore_count": {"type": "int"},
+ "ignore_time": {"type": "int"},
+ "number": {"type": "int"},
+ "reset_time": {"type": "int"},
+ "threshold_value": {"type": "int"},
+ "warning_only": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "max_metric": {
+ "options": {
+ "external_lsa": {"type": "int"},
+ "include_stub": {"type": "bool"},
+ "on_startup": {
+ "options": {
+ "time": {"type": "int"},
+ "wait_for_bgp": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "router_lsa": {"required": True, "type": "bool"},
+ "summary_lsa": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "maximum_paths": {"type": "int"},
+ "mpls": {
+ "options": {
+ "ldp": {
+ "options": {
+ "autoconfig": {
+ "options": {
+ "area": {"type": "str"},
+ "set": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "sync": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "traffic_eng": {
+ "options": {
+ "area": {"type": "str"},
+ "autoroute_exclude": {"type": "str"},
+ "interface": {
+ "options": {
+ "area": {"type": "int"},
+ "interface_type": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "mesh_group": {
+ "options": {
+ "area": {"type": "str"},
+ "id": {"type": "int"},
+ "interface": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "multicast_intact": {"type": "bool"},
+ "router_id_interface": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "neighbor": {
+ "options": {
+ "address": {"type": "str"},
+ "cost": {"type": "int"},
+ "database_filter": {"type": "bool"},
+ "poll_interval": {"type": "int"},
+ "priority": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "network": {
+ "options": {
+ "address": {"type": "str"},
+ "area": {"type": "str"},
+ "wildcard_bits": {"type": "str"},
+ },
+ "type": "list",
+ "elements": "dict",
+ },
+ "nsf": {
+ "options": {
+ "cisco": {
+ "options": {
+ "disable": {"type": "bool"},
+ "helper": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "ietf": {
+ "options": {
+ "disable": {"type": "bool"},
+ "helper": {"type": "bool"},
+ "strict_lsa_checking": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "passive_interface": {"type": "str"},
+ "passive_interfaces": {
+ "options": {
+ "default": {"type": "bool"},
+ "interface": {
+ "options": {
+ "set_interface": {"type": "bool"},
+ "name": {"type": "list", "elements": "str"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "prefix_suppression": {"type": "bool"},
+ "priority": {"type": "int"},
+ "process_id": {"required": True, "type": "int"},
+ "queue_depth": {
+ "options": {
+ "hello": {
+ "options": {
+ "max_packets": {"type": "int"},
+ "unlimited": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "update": {
+ "options": {
+ "max_packets": {"type": "int"},
+ "unlimited": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "router_id": {"type": "str"},
+ "shutdown": {"type": "bool"},
+ "summary_address": {
+ "options": {
+ "address": {"type": "str"},
+ "mask": {"type": "str"},
+ "not_advertise": {"type": "bool"},
+ "nssa_only": {"type": "bool"},
+ "tag": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "timers": {
+ "options": {
+ "lsa": {"type": "int"},
+ "pacing": {
+ "options": {
+ "flood": {"type": "int"},
+ "lsa_group": {"type": "int"},
+ "retransmission": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "throttle": {
+ "options": {
+ "lsa": {
+ "options": {
+ "first_delay": {"type": "int"},
+ "max_delay": {"type": "int"},
+ "min_delay": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "spf": {
+ "options": {
+ "between_delay": {"type": "int"},
+ "max_delay": {"type": "int"},
+ "receive_delay": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "traffic_share": {"type": "bool"},
+ "ttl_security": {
+ "options": {"hops": {"type": "int"}, "set": {"type": "bool"}},
+ "type": "dict",
+ },
+ "vrf": {"type": "str"},
+ },
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "rendered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv3/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv3/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv3/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv3/ospfv3.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv3/ospfv3.py
new file mode 100644
index 000000000..3a22e9a15
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ospfv3/ospfv3.py
@@ -0,0 +1,725 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 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 resource
+# module builder playbook.
+#
+# Do not edit this file manually.
+#
+# Changes to this file will be over written
+# by the resource module builder.
+#
+# Changes should be made in the model used to
+# generate this file or in the resource module
+# builder template.
+#
+#############################################
+
+"""
+The arg spec for the cisco.ios_ospfv3 module
+"""
+
+
+class Ospfv3Args(object): # pylint: disable=R0903
+ """The arg spec for the cisco.ios_ospfv3 module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "type": "dict",
+ "options": {
+ "processes": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "process_id": {"required": True, "type": "int"},
+ "address_family": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "afi": {"type": "str", "choices": ["ipv4", "ipv6"]},
+ "unicast": {"type": "bool"},
+ "vrf": {"type": "str"},
+ "adjacency": {
+ "type": "dict",
+ "options": {
+ "min_adjacency": {"type": "int"},
+ "none": {"type": "bool"},
+ "max_adjacency": {"type": "int"},
+ "disable": {"type": "bool"},
+ },
+ },
+ "areas": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "area_id": {"type": "str"},
+ "authentication": {
+ "type": "dict",
+ "options": {
+ "key_chain": {"type": "str", "no_log": True},
+ "null": {"type": "bool"},
+ },
+ },
+ "default_cost": {"type": "int"},
+ "filter_list": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "direction": {
+ "type": "str",
+ "choices": ["in", "out"],
+ "required": True,
+ },
+ },
+ },
+ "normal": {"type": "bool"},
+ "nssa": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "default_information_originate": {
+ "type": "dict",
+ "options": {
+ "metric": {"type": "int"},
+ "metric_type": {
+ "type": "int",
+ "choices": [1, 2],
+ },
+ "nssa_only": {"type": "bool"},
+ },
+ },
+ "no_redistribution": {"type": "bool"},
+ "no_summary": {"type": "bool"},
+ "translate": {
+ "type": "str",
+ "choices": ["always", "suppress-fa"],
+ },
+ },
+ },
+ "ranges": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "netmask": {"type": "str"},
+ "advertise": {"type": "bool"},
+ "cost": {"type": "int"},
+ "not_advertise": {"type": "bool"},
+ },
+ },
+ "sham_link": {
+ "type": "dict",
+ "options": {
+ "source": {"type": "str"},
+ "destination": {"type": "str"},
+ "authentication": {
+ "type": "dict",
+ "options": {
+ "key_chain": {
+ "type": "str",
+ "no_log": True,
+ },
+ "null": {"type": "bool"},
+ },
+ },
+ "cost": {"type": "int"},
+ "ttl_security": {"type": "int"},
+ },
+ },
+ "stub": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "no_summary": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "authentication": {
+ "type": "dict",
+ "options": {
+ "deployment": {"type": "bool"},
+ "normal": {"type": "bool"},
+ },
+ },
+ "auto_cost": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "reference_bandwidth": {"type": "int"},
+ },
+ },
+ "bfd": {
+ "type": "dict",
+ "options": {
+ "all_interfaces": {"type": "bool"},
+ "disable": {"type": "bool"},
+ },
+ },
+ "capability": {"type": "bool"},
+ "compatible": {
+ "type": "dict",
+ "options": {
+ "rfc1583": {"type": "bool"},
+ "rfc1587": {"type": "bool"},
+ "rfc5243": {"type": "bool"},
+ },
+ },
+ "default_information": {
+ "type": "dict",
+ "options": {
+ "originate": {"type": "bool"},
+ "always": {"type": "bool"},
+ "metric": {"type": "int"},
+ "metric_type": {"type": "int"},
+ "route_map": {"type": "str"},
+ },
+ },
+ "default_metric": {"type": "int"},
+ "discard_route": {
+ "type": "dict",
+ "options": {
+ "sham_link": {"type": "bool"},
+ "external": {"type": "bool"},
+ "internal": {"type": "bool"},
+ },
+ },
+ "distance": {"type": "int"},
+ "distribute_list": {
+ "type": "dict",
+ "options": {
+ "acls": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str", "required": True},
+ "direction": {
+ "type": "str",
+ "required": True,
+ "choices": ["in", "out"],
+ },
+ "interface": {"type": "str"},
+ "protocol": {"type": "str"},
+ },
+ },
+ "prefix": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "str", "required": True},
+ "gateway_name": {"type": "str"},
+ "direction": {
+ "type": "str",
+ "required": True,
+ "choices": ["in", "out"],
+ },
+ "interface": {"type": "str"},
+ "protocol": {"type": "str"},
+ },
+ },
+ "route_map": {
+ "type": "dict",
+ "options": {"name": {"type": "str", "required": True}},
+ },
+ },
+ },
+ "event_log": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "one_shot": {"type": "bool"},
+ "pause": {"type": "bool"},
+ "size": {"type": "int"},
+ },
+ },
+ "graceful_restart": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "disable": {"type": "bool"},
+ "strict_lsa_checking": {"type": "bool"},
+ },
+ },
+ "interface_id": {
+ "type": "dict",
+ "options": {
+ "ios_if_index": {"type": "bool"},
+ "snmp_if_index": {"type": "bool"},
+ },
+ },
+ "limit": {
+ "type": "dict",
+ "options": {
+ "dc": {
+ "type": "dict",
+ "options": {
+ "number": {"type": "int"},
+ "disable": {"type": "bool"},
+ },
+ },
+ "non_dc": {
+ "type": "dict",
+ "options": {
+ "number": {"type": "int"},
+ "disable": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "local_rib_criteria": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "forwarding_address": {"type": "bool"},
+ "inter_area_summary": {"type": "bool"},
+ "nssa_translation": {"type": "bool"},
+ },
+ },
+ "log_adjacency_changes": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "detail": {"type": "bool"},
+ },
+ },
+ "manet": {
+ "type": "dict",
+ "options": {
+ "cache": {
+ "type": "dict",
+ "options": {
+ "acknowledgement": {"type": "int"},
+ "update": {"type": "int"},
+ },
+ },
+ "hello": {
+ "type": "dict",
+ "options": {
+ "multicast": {"type": "bool"},
+ "unicast": {"type": "bool"},
+ },
+ },
+ "peering": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "disable": {"type": "bool"},
+ "per_interface": {"type": "bool"},
+ "redundancy": {"type": "int"},
+ },
+ },
+ "willingness": {"type": "int"},
+ },
+ },
+ "max_lsa": {
+ "type": "dict",
+ "options": {
+ "number": {"type": "int"},
+ "threshold_value": {"type": "int"},
+ "ignore_count": {"type": "int"},
+ "ignore_time": {"type": "int"},
+ "reset_time": {"type": "int"},
+ "warning_only": {"type": "bool"},
+ },
+ },
+ "max_metric": {
+ "type": "dict",
+ "options": {
+ "disable": {"type": "bool"},
+ "external_lsa": {"type": "int"},
+ "inter_area_lsas": {"type": "int"},
+ "on_startup": {
+ "type": "dict",
+ "options": {
+ "time": {"type": "int"},
+ "wait_for_bgp": {"type": "bool"},
+ },
+ },
+ "stub_prefix_lsa": {"type": "bool"},
+ },
+ },
+ "maximum_paths": {"type": "int"},
+ "passive_interface": {"type": "str"},
+ "prefix_suppression": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "disable": {"type": "bool"},
+ },
+ },
+ "queue_depth": {
+ "type": "dict",
+ "options": {
+ "hello": {
+ "type": "dict",
+ "options": {
+ "max_packets": {"type": "int"},
+ "unlimited": {"type": "bool"},
+ },
+ },
+ "update": {
+ "type": "dict",
+ "options": {
+ "max_packets": {"type": "int"},
+ "unlimited": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "router_id": {"type": "str"},
+ "shutdown": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "disable": {"type": "bool"},
+ },
+ },
+ "summary_prefix": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "mask": {"type": "str"},
+ "not_advertise": {"type": "bool"},
+ "nssa_only": {"type": "bool"},
+ "tag": {"type": "int"},
+ },
+ },
+ "timers": {
+ "type": "dict",
+ "options": {
+ "lsa": {"type": "int"},
+ "manet": {
+ "type": "dict",
+ "options": {
+ "cache": {
+ "type": "dict",
+ "options": {
+ "acknowledgement": {"type": "int"},
+ "redundancy": {"type": "int"},
+ },
+ },
+ "hello": {"type": "bool"},
+ "peering": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "per_interface": {"type": "bool"},
+ "redundancy": {"type": "int"},
+ },
+ },
+ "willingness": {"type": "int"},
+ },
+ },
+ "pacing": {
+ "type": "dict",
+ "options": {
+ "flood": {"type": "int"},
+ "lsa_group": {"type": "int"},
+ "retransmission": {"type": "int"},
+ },
+ },
+ "throttle": {
+ "type": "dict",
+ "options": {
+ "lsa": {
+ "type": "dict",
+ "options": {
+ "first_delay": {"type": "int"},
+ "min_delay": {"type": "int"},
+ "max_delay": {"type": "int"},
+ },
+ },
+ "spf": {
+ "type": "dict",
+ "options": {
+ "receive_delay": {"type": "int"},
+ "between_delay": {"type": "int"},
+ "max_delay": {"type": "int"},
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ "adjacency": {
+ "type": "dict",
+ "options": {
+ "min_adjacency": {"type": "int"},
+ "max_adjacency": {"type": "int"},
+ "none": {"type": "bool"},
+ },
+ },
+ "areas": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "area_id": {"type": "str"},
+ "authentication": {
+ "type": "dict",
+ "options": {
+ "key_chain": {"type": "str", "no_log": True},
+ "ipsec": {
+ "type": "dict",
+ "options": {
+ "spi": {"type": "int"},
+ "md5": {"type": "int"},
+ "sha1": {"type": "int"},
+ "hex_string": {"type": "str"},
+ },
+ },
+ },
+ },
+ "default_cost": {"type": "int"},
+ "nssa": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "default_information_originate": {
+ "type": "dict",
+ "options": {
+ "metric": {"type": "int"},
+ "metric_type": {"type": "int", "choices": [1, 2]},
+ "nssa_only": {"type": "bool"},
+ },
+ },
+ "no_redistribution": {"type": "bool"},
+ "no_summary": {"type": "bool"},
+ "translate": {
+ "type": "str",
+ "choices": ["always", "suppress-fa"],
+ },
+ },
+ },
+ "stub": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "no_summary": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "authentication": {"type": "bool"},
+ "auto_cost": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "reference_bandwidth": {"type": "int"},
+ },
+ },
+ "bfd": {"type": "bool"},
+ "compatible": {
+ "type": "dict",
+ "options": {
+ "rfc1583": {"type": "bool"},
+ "rfc1587": {"type": "bool"},
+ "rfc5243": {"type": "bool"},
+ },
+ },
+ "event_log": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "one_shot": {"type": "bool"},
+ "pause": {"type": "bool"},
+ "size": {"type": "int"},
+ },
+ },
+ "graceful_restart": {
+ "type": "dict",
+ "options": {
+ "disable": {"type": "bool"},
+ "strict_lsa_checking": {"type": "bool"},
+ },
+ },
+ "help": {"type": "bool"},
+ "interface_id": {"type": "bool"},
+ "limit": {
+ "type": "dict",
+ "options": {
+ "dc": {
+ "type": "dict",
+ "options": {
+ "number": {"type": "int"},
+ "disable": {"type": "bool"},
+ },
+ },
+ "non_dc": {
+ "type": "dict",
+ "options": {
+ "number": {"type": "int"},
+ "disable": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "local_rib_criteria": {
+ "type": "dict",
+ "options": {
+ "enable": {"type": "bool"},
+ "forwarding_address": {"type": "bool"},
+ "inter_area_summary": {"type": "bool"},
+ "nssa_translation": {"type": "bool"},
+ },
+ },
+ "log_adjacency_changes": {
+ "type": "dict",
+ "options": {"set": {"type": "bool"}, "detail": {"type": "bool"}},
+ },
+ "manet": {
+ "type": "dict",
+ "options": {
+ "cache": {
+ "type": "dict",
+ "options": {
+ "acknowledgement": {"type": "int"},
+ "redundancy": {"type": "int"},
+ },
+ },
+ "hello": {"type": "bool"},
+ "peering": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "per_interface": {"type": "bool"},
+ "redundancy": {"type": "int"},
+ },
+ },
+ "willingness": {"type": "int"},
+ },
+ },
+ "max_lsa": {
+ "type": "dict",
+ "options": {
+ "number": {"type": "int"},
+ "threshold_value": {"type": "int"},
+ "ignore_count": {"type": "int"},
+ "ignore_time": {"type": "int"},
+ "reset_time": {"type": "int"},
+ "warning_only": {"type": "bool"},
+ },
+ },
+ "max_metric": {
+ "type": "dict",
+ "options": {
+ "router_lsa": {"type": "bool", "required": True},
+ "external_lsa": {"type": "int"},
+ "include_stub": {"type": "bool"},
+ "on_startup": {
+ "type": "dict",
+ "options": {
+ "time": {"type": "int"},
+ "wait_for_bgp": {"type": "bool"},
+ },
+ },
+ "summary_lsa": {"type": "int"},
+ },
+ },
+ "passive_interface": {"type": "str"},
+ "prefix_suppression": {"type": "bool"},
+ "queue_depth": {
+ "type": "dict",
+ "options": {
+ "hello": {
+ "type": "dict",
+ "options": {
+ "max_packets": {"type": "int"},
+ "unlimited": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "router_id": {"type": "str"},
+ "shutdown": {"type": "bool"},
+ "timers": {
+ "type": "dict",
+ "options": {
+ "lsa": {"type": "int"},
+ "manet": {
+ "type": "dict",
+ "options": {
+ "cache": {
+ "type": "dict",
+ "options": {
+ "acknowledgement": {"type": "int"},
+ "redundancy": {"type": "int"},
+ },
+ },
+ "hello": {"type": "bool"},
+ "peering": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "per_interface": {"type": "bool"},
+ "redundancy": {"type": "int"},
+ },
+ },
+ "willingness": {"type": "int"},
+ },
+ },
+ "pacing": {
+ "type": "dict",
+ "options": {
+ "flood": {"type": "int"},
+ "lsa_group": {"type": "int"},
+ "retransmission": {"type": "int"},
+ },
+ },
+ "throttle": {
+ "type": "dict",
+ "options": {
+ "lsa": {
+ "type": "dict",
+ "options": {
+ "first_delay": {"type": "int"},
+ "min_delay": {"type": "int"},
+ "max_delay": {"type": "int"},
+ },
+ },
+ "spf": {
+ "type": "dict",
+ "options": {
+ "receive_delay": {"type": "int"},
+ "between_delay": {"type": "int"},
+ "max_delay": {"type": "int"},
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "type": "str",
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "parsed",
+ "rendered",
+ ],
+ "default": "merged",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ping/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ping/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ping/__init__.py
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
new file mode 100644
index 000000000..f89779d06
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/ping/ping.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+# Copyright 2022 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
+# cli_rm_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.
+#
+#############################################
+
+"""
+The arg spec for the ios_ping module
+"""
+
+
+class PingArgs(object): # pylint: disable=R0903
+ """The arg spec for the ios_ping module"""
+
+ argument_spec = {
+ "count": {"type": "int"},
+ "afi": {"choices": ["ip", "ipv6"], "default": "ip", "type": "str"},
+ "dest": {"required": True, "type": "str"},
+ "df_bit": {"default": False, "type": "bool"},
+ "source": {"type": "str"},
+ "ingress": {"type": "str"},
+ "egress": {"type": "str"},
+ "timeout": {"type": "int"},
+ "state": {"choices": ["absent", "present"], "default": "present", "type": "str"},
+ "vrf": {"type": "str"},
+ } # pylint: disable=C0301
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/prefix_lists/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/prefix_lists/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/prefix_lists/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/prefix_lists/prefix_lists.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/prefix_lists/prefix_lists.py
new file mode 100644
index 000000000..8a3f8ed7f
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/prefix_lists/prefix_lists.py
@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 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
+# cli_rm_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.
+#
+#############################################
+
+"""
+The arg spec for the cisco.ios_prefix_lists module
+"""
+
+
+class Prefix_listsArgs(object):
+ """The arg spec for the cisco.ios_prefix_lists module"""
+
+ argument_spec = {
+ "config": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "afi": {"type": "str", "choices": ["ipv4", "ipv6"]},
+ "prefix_lists": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "description": {"type": "str"},
+ "entries": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "action": {"type": "str", "choices": ["deny", "permit"]},
+ "sequence": {"type": "int"},
+ "description": {"type": "str"},
+ "prefix": {"type": "str"},
+ "ge": {"type": "int"},
+ "le": {"type": "int"},
+ },
+ },
+ },
+ },
+ },
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "type": "str",
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "parsed",
+ "rendered",
+ ],
+ "default": "merged",
+ },
+ }
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/route_maps/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/route_maps/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/route_maps/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/route_maps/route_maps.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/route_maps/route_maps.py
new file mode 100644
index 000000000..fdc127e0e
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/route_maps/route_maps.py
@@ -0,0 +1,567 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 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
+# cli_rm_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.
+#
+#############################################
+
+"""
+The arg spec for the cisco.ios_route_maps module
+"""
+
+
+class Route_mapsArgs(object): # pylint: disable=R0903
+ """The arg spec for the cisco.ios_route_maps module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "route_map": {"type": "str"},
+ "entries": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "sequence": {"type": "int"},
+ "action": {"type": "str", "choices": ["deny", "permit"]},
+ "continue_entry": {
+ "type": "dict",
+ "options": {"set": {"type": "bool"}, "entry_sequence": {"type": "int"}},
+ },
+ "description": {"type": "str"},
+ "match": {
+ "type": "dict",
+ "options": {
+ "additional_paths": {
+ "type": "dict",
+ "options": {
+ "all": {"type": "bool"},
+ "best": {"type": "int"},
+ "best_range": {
+ "type": "dict",
+ "options": {
+ "lower_limit": {"type": "int"},
+ "upper_limit": {"type": "int"},
+ },
+ },
+ "group_best": {"type": "bool"},
+ },
+ },
+ "as_path": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "acls": {"type": "list", "elements": "int"},
+ },
+ },
+ "clns": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "next_hop": {"type": "str"},
+ "route_source": {"type": "str"},
+ },
+ },
+ "community": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "list", "elements": "str"},
+ "exact_match": {"type": "bool"},
+ },
+ },
+ "extcommunity": {"type": "list", "elements": "str"},
+ "interfaces": {"type": "list", "elements": "str"},
+ "ip": {
+ "type": "dict",
+ "options": {
+ "address": {
+ "type": "dict",
+ "options": {
+ "acls": {"type": "list", "elements": "str"},
+ "prefix_lists": {"type": "list", "elements": "str"},
+ },
+ },
+ "flowspec": {
+ "type": "dict",
+ "options": {
+ "dest_pfx": {"type": "bool"},
+ "src_pfx": {"type": "bool"},
+ "acls": {"type": "list", "elements": "str"},
+ "prefix_lists": {"type": "list", "elements": "str"},
+ },
+ },
+ "next_hop": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "acls": {"type": "list", "elements": "str"},
+ "prefix_lists": {"type": "list", "elements": "str"},
+ },
+ },
+ "redistribution_source": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "acls": {"type": "list", "elements": "str"},
+ "prefix_lists": {"type": "list", "elements": "str"},
+ },
+ },
+ "route_source": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "redistribution_source": {"type": "bool"},
+ "acls": {"type": "list", "elements": "str"},
+ "prefix_lists": {"type": "list", "elements": "str"},
+ },
+ },
+ },
+ },
+ "ipv6": {
+ "type": "dict",
+ "options": {
+ "address": {
+ "type": "dict",
+ "options": {
+ "acl": {"type": "str"},
+ "prefix_list": {"type": "str"},
+ },
+ },
+ "flowspec": {
+ "type": "dict",
+ "options": {
+ "dest_pfx": {"type": "bool"},
+ "src_pfx": {"type": "bool"},
+ "acl": {"type": "str"},
+ "prefix_list": {"type": "str"},
+ },
+ },
+ "next_hop": {
+ "type": "dict",
+ "options": {
+ "acl": {"type": "str"},
+ "prefix_list": {"type": "str"},
+ },
+ },
+ "route_source": {
+ "type": "dict",
+ "options": {
+ "acl": {"type": "str"},
+ "prefix_list": {"type": "str"},
+ },
+ },
+ },
+ },
+ "length": {
+ "type": "dict",
+ "options": {
+ "minimum": {"type": "int"},
+ "maximum": {"type": "int"},
+ },
+ },
+ "local_preference": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "value": {"type": "list", "elements": "str"},
+ },
+ },
+ "mdt_group": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "acls": {"type": "list", "elements": "str"},
+ },
+ },
+ "metric": {
+ "type": "dict",
+ "options": {
+ "value": {"type": "int"},
+ "external": {"type": "bool"},
+ "deviation": {"type": "bool"},
+ "deviation_value": {"type": "int"},
+ },
+ },
+ "mpls_label": {"type": "bool"},
+ "policy_lists": {"type": "list", "elements": "str"},
+ "route_type": {
+ "type": "dict",
+ "options": {
+ "external": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "type_1": {"type": "bool"},
+ "type_2": {"type": "bool"},
+ },
+ },
+ "internal": {"type": "bool"},
+ "level_1": {"type": "bool"},
+ "level_2": {"type": "bool"},
+ "local": {"type": "bool"},
+ "nssa_external": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "type_1": {"type": "bool"},
+ "type_2": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "rpki": {
+ "type": "dict",
+ "options": {
+ "invalid": {"type": "bool"},
+ "not_found": {"type": "bool"},
+ "valid": {"type": "bool"},
+ },
+ },
+ "security_group": {
+ "type": "dict",
+ "options": {
+ "source": {"type": "list", "elements": "int"},
+ "destination": {"type": "list", "elements": "int"},
+ },
+ },
+ "source_protocol": {
+ "type": "dict",
+ "options": {
+ "bgp": {"type": "str"},
+ "connected": {"type": "bool"},
+ "eigrp": {"type": "int"},
+ "isis": {"type": "bool"},
+ "lisp": {"type": "bool"},
+ "mobile": {"type": "bool"},
+ "ospf": {"type": "int"},
+ "ospfv3": {"type": "int"},
+ "rip": {"type": "bool"},
+ "static": {"type": "bool"},
+ },
+ },
+ "tag": {
+ "type": "dict",
+ "options": {
+ "value": {"type": "list", "elements": "str"},
+ "tag_list": {"type": "list", "elements": "str"},
+ },
+ },
+ "track": {"type": "int"},
+ },
+ },
+ "set": {
+ "type": "dict",
+ "options": {
+ "aigp_metric": {
+ "type": "dict",
+ "options": {
+ "value": {"type": "int"},
+ "igp_metric": {"type": "bool"},
+ },
+ },
+ "as_path": {
+ "type": "dict",
+ "options": {
+ "prepend": {
+ "type": "dict",
+ "options": {
+ "as_number": {"type": "list", "elements": "str"},
+ "last_as": {"type": "int"},
+ },
+ },
+ "tag": {"type": "bool"},
+ },
+ },
+ "automatic_tag": {"type": "bool"},
+ "clns": {"type": "str"},
+ "comm_list": {"type": "str"},
+ "community": {
+ "type": "dict",
+ "options": {
+ "number": {"type": "str"},
+ "additive": {"type": "bool"},
+ "gshut": {"type": "bool"},
+ "internet": {"type": "bool"},
+ "local_as": {"type": "bool"},
+ "no_advertise": {"type": "bool"},
+ "no_export": {"type": "bool"},
+ "none": {"type": "bool"},
+ },
+ },
+ "dampening": {
+ "type": "dict",
+ "options": {
+ "penalty_half_time": {"type": "int"},
+ "reuse_route_val": {"type": "int"},
+ "suppress_route_val": {"type": "int"},
+ "max_suppress": {"type": "int"},
+ },
+ },
+ "default": {"type": "str"},
+ "extcomm_list": {"type": "str"},
+ "extcommunity": {
+ "type": "dict",
+ "options": {
+ "cost": {
+ "type": "dict",
+ "options": {
+ "id": {"type": "str"},
+ "cost_value": {"type": "int"},
+ "igp": {"type": "bool"},
+ "pre_bestpath": {"type": "bool"},
+ },
+ },
+ "rt": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "range": {
+ "type": "dict",
+ "options": {
+ "lower_limit": {"type": "str"},
+ "upper_limit": {"type": "str"},
+ },
+ },
+ "additive": {"type": "bool"},
+ },
+ },
+ "soo": {"type": "str"},
+ "vpn_distinguisher": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "range": {
+ "type": "dict",
+ "options": {
+ "lower_limit": {"type": "str"},
+ "upper_limit": {"type": "str"},
+ },
+ },
+ "additive": {"type": "bool"},
+ },
+ },
+ },
+ },
+ "global_route": {"type": "bool"},
+ "interfaces": {"type": "list", "elements": "str"},
+ "ip": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "df": {"choices": [0, 1], "type": "int"},
+ "global_route": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "verify_availability": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "sequence": {"type": "int"},
+ "track": {"type": "int"},
+ },
+ },
+ },
+ },
+ "next_hop": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "dynamic": {"type": "bool"},
+ "encapsulate": {"type": "str"},
+ "peer_address": {"type": "bool"},
+ "recursive": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "global_route": {"type": "bool"},
+ "vrf": {"type": "str"},
+ },
+ },
+ "self": {"type": "bool"},
+ "verify_availability": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "address": {},
+ "sequence": {"type": "int"},
+ "track": {"type": "int"},
+ },
+ },
+ },
+ },
+ "precedence": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "critical": {"type": "bool"},
+ "flash": {"type": "bool"},
+ "flash_override": {"type": "bool"},
+ "immediate": {"type": "bool"},
+ "internet": {"type": "bool"},
+ "network": {"type": "bool"},
+ "priority": {"type": "bool"},
+ "routine": {"type": "bool"},
+ },
+ },
+ "qos_group": {"type": "int"},
+ "tos": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "max_reliability": {"type": "bool"},
+ "max_throughput": {"type": "bool"},
+ "min_delay": {"type": "bool"},
+ "min_monetary_cost": {"type": "bool"},
+ "normal": {"type": "bool"},
+ },
+ },
+ "vrf": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "address": {"type": "str"},
+ "verify_availability": {
+ "type": "dict",
+ "options": {
+ "set": {"type": "bool"},
+ "address": {},
+ "sequence": {"type": "int"},
+ "track": {"type": "int"},
+ },
+ },
+ },
+ },
+ },
+ },
+ "ipv6": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "default": {"type": "bool"},
+ "global_route": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "verify_availability": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "sequence": {"type": "int"},
+ "track": {"type": "int"},
+ },
+ },
+ },
+ },
+ "next_hop": {
+ "type": "dict",
+ "options": {
+ "address": {"type": "str"},
+ "encapsulate": {"type": "str"},
+ "peer_address": {"type": "bool"},
+ "recursive": {"type": "str"},
+ },
+ },
+ "precedence": {"type": "int"},
+ "vrf": {
+ "type": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "verify_availability": {
+ "type": "dict",
+ "options": {
+ "address": {},
+ "sequence": {"type": "int"},
+ "track": {"type": "int"},
+ },
+ },
+ },
+ },
+ },
+ },
+ "level": {
+ "type": "dict",
+ "options": {
+ "level_1": {"type": "bool"},
+ "level_1_2": {"type": "bool"},
+ "level_2": {"type": "bool"},
+ "nssa_only": {"type": "bool"},
+ },
+ },
+ "lisp": {"type": "str"},
+ "local_preference": {"type": "int"},
+ "metric": {
+ "type": "dict",
+ "options": {
+ "deviation": {"choices": ["plus", "minus"], "type": "str"},
+ "metric_value": {"type": "int"},
+ "eigrp_delay": {"type": "int"},
+ "metric_reliability": {"type": "int"},
+ "metric_bandwidth": {"type": "int"},
+ "mtu": {"type": "int"},
+ },
+ },
+ "metric_type": {
+ "type": "dict",
+ "options": {
+ "external": {"type": "bool"},
+ "internal": {"type": "bool"},
+ "type_1": {"type": "bool"},
+ "type_2": {"type": "bool"},
+ },
+ },
+ "mpls_label": {"type": "bool"},
+ "origin": {
+ "type": "dict",
+ "options": {
+ "igp": {"type": "bool"},
+ "incomplete": {"type": "bool"},
+ },
+ },
+ "tag": {"type": "str"},
+ "traffic_index": {"type": "int"},
+ "vrf": {"type": "str"},
+ "weight": {"type": "int"},
+ },
+ },
+ },
+ },
+ },
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "type": "str",
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "gathered",
+ "parsed",
+ "rendered",
+ ],
+ "default": "merged",
+ },
+ }
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/service/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/service/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/service/__init__.py
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
new file mode 100644
index 000000000..76d2a3e34
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/service/service.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
+
+#############################################
+# 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_service module
+"""
+
+
+class ServiceArgs(object): # pylint: disable=R0903
+ """The arg spec for the ios_service module"""
+
+ argument_spec = {
+ "config": {
+ "options": {
+ "call_home": {"type": "bool"},
+ "compress_config": {"type": "bool"},
+ "config": {"type": "bool"},
+ "counters": {"type": "int", "default": 0},
+ "dhcp": {"type": "bool", "default": True},
+ "disable_ip_fast_frag": {"type": "bool"},
+ "exec_callback": {"type": "bool"},
+ "exec_wait": {"type": "bool"},
+ "hide_telnet_addresses": {"type": "bool"},
+ "internal": {"type": "bool"},
+ "linenumber": {"type": "bool"},
+ "log": {"type": "bool"},
+ "log_hidden": {"type": "bool"},
+ "nagle": {"type": "bool"},
+ "old_slip_prompts": {"type": "bool"},
+ "pad": {"type": "bool"},
+ "pad_cmns": {"type": "bool"},
+ "pad_from_xot": {"type": "bool"},
+ "pad_to_xot": {"type": "bool"},
+ "password_encryption": {"type": "bool"},
+ "password_recovery": {"type": "bool", "default": True},
+ "prompt": {"type": "bool", "default": True},
+ "private_config_encryption": {"type": "bool"},
+ "pt_vty_logging": {"type": "bool"},
+ "scripting": {"type": "bool"},
+ "sequence_numbers": {"type": "bool"},
+ "slave_coredump": {"type": "bool"},
+ "slave_log": {"type": "bool", "default": True},
+ "tcp_keepalives_in": {"type": "bool"},
+ "tcp_keepalives_out": {"type": "bool"},
+ "tcp_small_servers": {
+ "options": {
+ "enable": {"type": "bool"},
+ "max_servers": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "telnet_zeroidle": {"type": "bool"},
+ "timestamps": {
+ "elements": "dict",
+ "options": {
+ "msg": {"choices": ["debug", "log"], "type": "str"},
+ "enable": {"type": "bool"},
+ "timestamp": {
+ "choices": ["datetime", "uptime"],
+ "type": "str",
+ },
+ "datetime_options": {
+ "options": {
+ "localtime": {"type": "bool"},
+ "msec": {"type": "bool"},
+ "show_timezone": {"type": "bool"},
+ "year": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "list",
+ },
+ "udp_small_servers": {
+ "options": {
+ "enable": {"type": "bool"},
+ "max_servers": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ "unsupported_transceiver": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "deleted",
+ "gathered",
+ "rendered",
+ "parsed",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/snmp_server/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/snmp_server/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/snmp_server/__init__.py
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
new file mode 100644
index 000000000..d0473cc97
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/snmp_server/snmp_server.py
@@ -0,0 +1,484 @@
+# -*- coding: utf-8 -*-
+# Copyright 2022 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
+# cli_rm_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.
+#
+#############################################
+
+"""
+The arg spec for the ios_snmp_server module
+"""
+
+
+class Snmp_serverArgs(object): # pylint: disable=R0903
+ """The arg spec for the ios_snmp_server module"""
+
+ argument_spec = {
+ "config": {
+ "options": {
+ "accounting": {"options": {"command": {"type": "str"}}, "type": "dict"},
+ "cache": {"type": "int"},
+ "chassis_id": {"type": "str"},
+ "communities": {
+ "elements": "dict",
+ "options": {
+ "acl_v4": {"type": "str"},
+ "acl_v6": {"type": "str"},
+ "name": {"type": "str"},
+ "ro": {"type": "bool"},
+ "rw": {"type": "bool"},
+ "view": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "contact": {"type": "str"},
+ "context": {"elements": "str", "type": "list"},
+ "drop": {
+ "options": {"unknown_user": {"type": "bool"}, "vrf_traffic": {"type": "bool"}},
+ "type": "dict",
+ },
+ "engine_id": {
+ "elements": "dict",
+ "options": {
+ "id": {"type": "str"},
+ "local": {"type": "bool"},
+ "remote": {
+ "options": {
+ "host": {"type": "str"},
+ "udp_port": {"type": "int"},
+ "vrf": {"type": "str"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "list",
+ },
+ "file_transfer": {
+ "options": {
+ "access_group": {"type": "str"},
+ "protocol": {"type": "list", "elements": "str"},
+ },
+ "type": "dict",
+ },
+ "groups": {
+ "elements": "dict",
+ "options": {
+ "context": {"type": "str"},
+ "version_option": {"choices": ["auth", "noauth", "priv"], "type": "str"},
+ "group": {"type": "str"},
+ "notify": {"type": "str"},
+ "read": {"type": "str"},
+ "version": {"choices": ["v1", "v3", "v2c"], "type": "str"},
+ "write": {"type": "str"},
+ "acl_v4": {"type": "str"},
+ "acl_v6": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "hosts": {
+ "elements": "dict",
+ "options": {
+ "host": {"type": "str"},
+ "informs": {"type": "bool"},
+ "community_string": {"type": "str"},
+ "traps": {"type": "list", "elements": "str"},
+ "version": {"choices": ["1", "2c", "3"], "type": "str"},
+ "version_option": {"choices": ["auth", "noauth", "priv"], "type": "str"},
+ "vrf": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "if_index": {"type": "bool"},
+ "inform": {
+ "options": {
+ "pending": {"type": "int"},
+ "retries": {"type": "int"},
+ "timeout": {"type": "int"},
+ },
+ "type": "dict",
+ },
+ "ip": {
+ "options": {"dscp": {"type": "int"}, "precedence": {"type": "int"}},
+ "type": "dict",
+ },
+ "location": {"type": "str"},
+ "manager": {"type": "int"},
+ "packet_size": {"type": "int"},
+ "password_policy": {
+ "elements": "dict",
+ "no_log": False,
+ "options": {
+ "change": {"type": "int"},
+ "digits": {"type": "int"},
+ "lower_case": {"type": "int"},
+ "max_len": {"type": "int"},
+ "min_len": {"type": "int"},
+ "policy_name": {"type": "str"},
+ "special_char": {"type": "int"},
+ "upper_case": {"type": "int"},
+ "username": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "queue_length": {"type": "int"},
+ "source_interface": {"type": "str"},
+ "system_shutdown": {"type": "bool"},
+ "trap_source": {"type": "str"},
+ "trap_timeout": {"type": "int"},
+ "traps": {
+ "options": {
+ "auth_framework": {
+ "options": {
+ "sec_violation": {"type": "bool"},
+ "enable": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "bfd": {
+ "options": {
+ "enable": {"type": "bool"},
+ "session_down": {"type": "bool"},
+ "session_up": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "bgp": {
+ "options": {
+ "cbgp2": {"type": "bool"},
+ "enable": {"type": "bool"},
+ "state_changes": {
+ "options": {
+ "all": {"type": "bool"},
+ "backward_trans": {"type": "bool"},
+ "limited": {"type": "bool"},
+ "enable": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "threshold": {
+ "options": {"prefix": {"type": "bool"}},
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "bridge": {
+ "options": {
+ "newroot": {"type": "bool"},
+ "enable": {"type": "bool"},
+ "topologychange": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "casa": {"type": "bool"},
+ "cef": {
+ "options": {
+ "inconsistency": {"type": "bool"},
+ "peer_fib_state_change": {"type": "bool"},
+ "peer_state_change": {"type": "bool"},
+ "resource_failure": {"type": "bool"},
+ "enable": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "cnpd": {"type": "bool"},
+ "config": {"type": "bool"},
+ "config_copy": {"type": "bool"},
+ "config_ctid": {"type": "bool"},
+ "cpu": {
+ "options": {"enable": {"type": "bool"}, "threshold": {"type": "bool"}},
+ "type": "dict",
+ },
+ "dhcp": {"type": "bool"},
+ "dlsw": {
+ "options": {
+ "circuit": {"type": "bool"},
+ "enable": {"type": "bool"},
+ "tconn": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "eigrp": {"type": "bool"},
+ "entity": {"type": "bool"},
+ "energywise": {"type": "bool"},
+ "envmon": {
+ "options": {
+ "fan": {
+ "options": {
+ "shutdown": {"type": "bool"},
+ "enable": {"type": "bool"},
+ "status": {"type": "bool"},
+ "supply": {"type": "bool"},
+ "temperature": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "shutdown": {"type": "bool"},
+ "status": {"type": "bool"},
+ "supply": {"type": "bool"},
+ "temperature": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "ethernet": {
+ "options": {
+ "cfm": {
+ "options": {
+ "alarm": {"type": "bool"},
+ "cc": {
+ "type": "dict",
+ "options": {
+ "config": {"type": "bool"},
+ "cross_connect": {"type": "bool"},
+ "loop": {"type": "bool"},
+ "mep_down": {"type": "bool"},
+ "mep_up": {"type": "bool"},
+ },
+ },
+ "crosscheck": {
+ "type": "dict",
+ "options": {
+ "mep_missing": {"type": "bool"},
+ "mep_unknown": {"type": "bool"},
+ "service_up": {"type": "bool"},
+ },
+ },
+ },
+ "type": "dict",
+ },
+ "evc": {
+ "options": {
+ "create": {"type": "bool"},
+ "delete": {"type": "bool"},
+ "status": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "event_manager": {"type": "bool"},
+ "flowmon": {"type": "bool"},
+ "firewall": {
+ "options": {
+ "enable": {"type": "bool"},
+ "serverstatus": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "frame_relay": {
+ "options": {
+ "enable": {"type": "bool"},
+ "subif": {
+ "options": {
+ "count": {"type": "int"},
+ "interval": {"type": "int"},
+ "enable": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "fru_ctrl": {"type": "bool"},
+ "hsrp": {"type": "bool"},
+ "ike": {
+ "options": {
+ "policy": {
+ "options": {
+ "add": {"type": "bool"},
+ "delete": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "tunnel": {
+ "options": {
+ "start": {"type": "bool"},
+ "stop": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "ipmulticast": {"type": "bool"},
+ "ipsec": {
+ "options": {
+ "cryptomap": {
+ "options": {
+ "add": {"type": "bool"},
+ "attach": {"type": "bool"},
+ "delete": {"type": "bool"},
+ "detach": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "too_many_sas": {"type": "bool"},
+ "tunnel": {
+ "options": {
+ "start": {"type": "bool"},
+ "stop": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "ipsla": {"type": "bool"},
+ "l2tun": {
+ "options": {
+ "pseudowire_status": {"type": "bool"},
+ "session": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "msdp": {"type": "bool"},
+ "mvpn": {"type": "bool"},
+ "mpls_vpn": {"type": "bool"},
+ "ospf": {
+ "options": {
+ "cisco_specific": {
+ "options": {
+ "error": {"type": "bool"},
+ "lsa": {"type": "bool"},
+ "retransmit": {"type": "bool"},
+ "state_change": {
+ "options": {
+ "nssa_trans_change": {"type": "bool"},
+ "shamlink": {
+ "options": {
+ "interface": {"type": "bool"},
+ "neighbor": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ },
+ "type": "dict",
+ },
+ "error": {"type": "bool"},
+ "retransmit": {"type": "bool"},
+ "lsa": {"type": "bool"},
+ "state_change": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "pim": {
+ "options": {
+ "invalid_pim_message": {"type": "bool"},
+ "neighbor_change": {"type": "bool"},
+ "rp_mapping_change": {"type": "bool"},
+ "enable": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "vrfmib": {
+ "options": {
+ "vrf_up": {"type": "bool"},
+ "vrf_down": {"type": "bool"},
+ "vnet_trunk_up": {"type": "bool"},
+ "vnet_trunk_down": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "pki": {"type": "bool"},
+ "rsvp": {"type": "bool"},
+ "isis": {"type": "bool"},
+ "pw_vc": {"type": "bool"},
+ "snmp": {
+ "options": {
+ "authentication": {"type": "bool"},
+ "coldstart": {"type": "bool"},
+ "linkdown": {"type": "bool"},
+ "linkup": {"type": "bool"},
+ "warmstart": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "syslog": {"type": "bool"},
+ "transceiver_all": {"type": "bool"},
+ "tty": {"type": "bool"},
+ "vrrp": {"type": "bool"},
+ },
+ "type": "dict",
+ },
+ "users": {
+ "elements": "dict",
+ "options": {
+ "acl_v6": {"type": "str"},
+ "acl_v4": {"type": "str"},
+ "authentication": {
+ "no_log": False,
+ "type": "dict",
+ "options": {
+ "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_option": {"type": "str"},
+ "password": {"type": "str", "no_log": True},
+ },
+ },
+ "group": {"type": "str"},
+ "remote": {"type": "str"},
+ "udp_port": {"type": "int"},
+ "username": {"type": "str"},
+ "version": {"choices": ["v1", "v2c", "v3"], "type": "str"},
+ "version_option": {"choices": ["encrypted"], "type": "str"},
+ "vrf": {"type": "str"},
+ },
+ "type": "list",
+ },
+ "views": {
+ "elements": "dict",
+ "options": {
+ "excluded": {"type": "bool"},
+ "family_name": {"type": "str"},
+ "included": {"type": "bool"},
+ "name": {"type": "str"},
+ },
+ "type": "list",
+ },
+ },
+ "type": "dict",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "parsed",
+ "gathered",
+ "rendered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ } # pylint: disable=C0301
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/static_routes/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/static_routes/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/static_routes/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/static_routes/static_routes.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/static_routes/static_routes.py
new file mode 100644
index 000000000..3d08590fb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/static_routes/static_routes.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_static_routes module
+"""
+
+
+class Static_routesArgs(object): # pylint: disable=R0903
+ """The arg spec for the ios_static_routes module"""
+
+ argument_spec = {
+ "config": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "vrf": {"type": "str"},
+ "address_families": {
+ "elements": "dict",
+ "type": "list",
+ "options": {
+ "afi": {
+ "required": True,
+ "type": "str",
+ "choices": ["ipv4", "ipv6"],
+ },
+ "routes": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "dest": {"type": "str", "required": True},
+ "topology": {"type": "str"},
+ "next_hops": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "forward_router_address": {"type": "str"},
+ "interface": {"type": "str"},
+ "dhcp": {"type": "bool"},
+ "distance_metric": {"type": "int"},
+ "global": {"type": "bool"},
+ "name": {"type": "str"},
+ "multicast": {"type": "bool"},
+ "unicast": {"type": "bool"},
+ "permanent": {"type": "bool"},
+ "tag": {"type": "int"},
+ "track": {"type": "int"},
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ "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/vlans/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vlans/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vlans/__init__.py
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
new file mode 100644
index 000000000..a3b0b6acd
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/argspec/vlans/vlans.py
@@ -0,0 +1,75 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#############################################
+# WARNING #
+#############################################
+#
+# This file is auto generated by the resource
+# module builder playbook.
+#
+# Do not edit this file manually.
+#
+# Changes to this file will be over written
+# by the resource module builder.
+#
+# Changes should be made in the model used to
+# generate this file or in the resource module
+# builder template.
+#
+#############################################
+
+"""
+The arg spec for the ios_vlans module
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+class VlansArgs(object):
+ """The arg spec for the ios_vlans module"""
+
+ def __init__(self, **kwargs):
+ pass
+
+ argument_spec = {
+ "config": {
+ "elements": "dict",
+ "options": {
+ "name": {"type": "str"},
+ "vlan_id": {"required": True, "type": "int"},
+ "mtu": {"type": "int"},
+ "remote_span": {"type": "bool"},
+ "state": {"type": "str", "choices": ["active", "suspend"]},
+ "shutdown": {"type": "str", "choices": ["enabled", "disabled"]},
+ "private_vlan": {
+ "type": "dict",
+ "options": {
+ "type": {"type": "str", "choices": ["primary", "community", "isolated"]},
+ "associated": {"type": "list", "elements": "int"},
+ },
+ },
+ },
+ "type": "list",
+ },
+ "running_config": {"type": "str"},
+ "state": {
+ "choices": [
+ "merged",
+ "replaced",
+ "overridden",
+ "deleted",
+ "rendered",
+ "parsed",
+ "gathered",
+ ],
+ "default": "merged",
+ "type": "str",
+ },
+ }
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acl_interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acl_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acl_interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acl_interfaces/acl_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acl_interfaces/acl_interfaces.py
new file mode 100644
index 000000000..e8d64f18c
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acl_interfaces/acl_interfaces.py
@@ -0,0 +1,124 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2022 Red Hat Inc.
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios_acl_interfaces class
+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 it's desired end-state is
+created
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+from ansible.module_utils._text import to_text
+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.acl_interfaces import (
+ Acl_interfacesTemplate,
+)
+
+
+class Acl_interfaces(ResourceModule):
+ """
+ The ios_acl_interfaces class
+ """
+
+ def __init__(self, module):
+ super(Acl_interfaces, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="acl_interfaces",
+ tmplt=Acl_interfacesTemplate(),
+ )
+
+ 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):
+ """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
+ """
+ # convert list of dicts to dicts of dicts
+ wantd = {entry["name"]: entry for entry in self.want}
+ haved = {entry["name"]: entry for entry in self.have}
+
+ # turn all lists of dicts into dicts prior to merge
+ for entry in wantd, haved:
+ self._list_to_dict(entry)
+
+ # 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 haved.items() if k in wantd or not wantd}
+ wantd = {}
+
+ # remove superfluous config
+ if self.state in ["overridden", "deleted"]:
+ for k, have in haved.items():
+ if k not in wantd:
+ self._compare(want={}, have=have)
+
+ for k, want in wantd.items():
+ self._compare(want=want, have=haved.pop(k, {}))
+
+ def _compare(self, want, have):
+ begin = len(self.commands)
+ self._compare_lists(want=want, have=have)
+ if len(self.commands) != begin:
+ self.commands.insert(begin, self._tmplt.render(want or have, "interface", False))
+
+ def _compare_lists(self, want, have):
+ wdict = want.get("access_groups", {})
+ hdict = have.get("access_groups", {})
+
+ for afi in ("ipv4", "ipv6"):
+ wacls = wdict.pop(afi, {}).pop("acls", {})
+ hacls = hdict.pop(afi, {}).pop("acls", {})
+
+ for key, entry in wacls.items():
+ if entry != hacls.pop(key, {}):
+ entry["afi"] = afi
+ self.addcmd(entry, "access_groups", False)
+ # remove remaining items in have for replaced
+ for entry in hacls.values():
+ entry["afi"] = afi
+ self.addcmd(entry, "access_groups", True)
+
+ def _list_to_dict(self, entry):
+ for item in entry.values():
+ for ag in item.get("access_groups", []):
+ ag["acls"] = {
+ subentry["direction"]: {
+ "name": to_text(subentry["name"]),
+ "direction": subentry["direction"],
+ }
+ for subentry in ag.get("acls", [])
+ }
+ item["access_groups"] = {
+ subentry["afi"]: subentry for subentry in item.get("access_groups", [])
+ }
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acls/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acls/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acls/__init__.py
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
new file mode 100644
index 000000000..9d29555cc
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/acls/acls.py
@@ -0,0 +1,315 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat Inc.
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios_acls class
+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 it's desired end-state is
+created
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+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.acls import (
+ AclsTemplate,
+)
+
+
+class Acls(ResourceModule):
+ """
+ The ios_acls config class
+ """
+
+ def __init__(self, module):
+ super(Acls, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="acls",
+ tmplt=AclsTemplate(),
+ )
+
+ 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.
+ """
+ haved, wantd = dict(), dict()
+
+ if self.have:
+ haved = self.list_to_dict(self.have)
+ if self.want:
+ wantd = self.list_to_dict(self.want)
+
+ # 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 want
+ if self.state == "deleted":
+ haved = {k: v for k, v in iteritems(haved) if k in wantd or not wantd}
+ if wantd.get("ipv4") and not haved.get("ipv4"):
+ haved["ipv4"] = {}
+ if wantd.get("ipv6") and not haved.get("ipv6"):
+ haved["ipv6"] = {}
+ for key, hvalue in iteritems(haved):
+ wvalue = wantd.pop(key, {})
+ if wvalue:
+ wplists = wvalue.get("acls", {})
+ hplists = hvalue.get("acls", {})
+ hvalue["acls"] = {
+ 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):
+ if k not in wantd:
+ self._compare(want={}, have=have, afi=k)
+
+ for k, want in iteritems(wantd):
+ self._compare(want=want, have=haved.pop(k, {}), afi=k)
+
+ def _compare(self, want, have, afi):
+ """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 acls network resource.
+ """
+
+ def rearrange_cmds(aces):
+ non_negates = []
+ negates = []
+ for ace in aces:
+ if ace.startswith("no"):
+ negates.append(ace)
+ else:
+ non_negates.append(ace)
+ if non_negates or negates:
+ negates.extend(non_negates)
+ return negates
+
+ wplists = want.get("acls", {})
+ hplists = have.get("acls", {})
+ for wname, wentry in iteritems(wplists):
+ hentry = hplists.pop(wname, {})
+ acl_type = wentry["acl_type"] if wentry.get("acl_type") else hentry.get("acl_type")
+ begin = len(self.commands) # to determine the index for acl command
+ self._compare_aces(
+ wentry.pop("aces", {}),
+ hentry.pop("aces", {}),
+ afi,
+ wname,
+ ) # handle aces
+
+ end = len(self.commands)
+ self.commands[begin:end] = rearrange_cmds(self.commands[begin:])
+
+ if len(self.commands) != begin or (not have and want):
+ _cmd = self.acl_name_cmd(wname, afi, acl_type)
+ self.commands.insert(begin, _cmd)
+
+ if self.state in ["overridden", "deleted"]:
+ # remove remaining acls lists
+ for hname, hval in iteritems(hplists):
+ _cmd = self.acl_name_cmd(hname, afi, hval.get("acl_type", ""))
+ self.commands.append("no " + _cmd)
+
+ def _compare_aces(self, want, have, afi, name):
+ """compares all aces"""
+
+ def add_afi(entry, afi):
+ """adds afi needed for
+ setval processing"""
+ if entry:
+ entry["afi"] = afi
+ return entry
+
+ for wseq, wentry in iteritems(want):
+ hentry = have.pop(wseq, {})
+ if hentry:
+ hentry = self.sanitize_protocol_options(wentry, hentry)
+ if hentry != wentry:
+ if hentry:
+ if self.state == "merged":
+ self._module.fail_json(
+ msg="Cannot update existing sequence {0} of ACLs {1} with state merged."
+ " Please use state replaced or overridden.".format(
+ hentry.get("sequence", ""),
+ name,
+ ),
+ )
+ 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
+ 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
+ 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)
+ else: # remove extra aces
+ self.addcmd(add_afi(hseq, afi), "aces", negate=True)
+
+ def sanitize_protocol_options(self, wace, hace):
+ """handles protocol and protocol options as optional attribute"""
+ if wace.get("protocol_options"):
+ if not wace.get("protocol") and (
+ list(wace.get("protocol_options"))[0] == hace.get("protocol")
+ ):
+ hace.pop("protocol")
+ return hace
+
+ def acl_name_cmd(self, name, afi, acl_type):
+ """generate parent acl command"""
+
+ if afi == "ipv4":
+ if not acl_type:
+ try:
+ acl_id = int(name)
+ if not acl_type:
+ if acl_id >= 1 and acl_id <= 99:
+ acl_type = "standard"
+ if acl_id >= 100 and acl_id <= 199:
+ acl_type = "extended"
+ except ValueError:
+ acl_type = "extended"
+ command = "ip access-list {0} {1}".format(acl_type, name)
+ elif afi == "ipv6":
+ command = "ipv6 access-list {0}".format(name)
+ return command
+
+ def list_to_dict(self, param):
+ """converts list attributes to dict"""
+
+ temp, count = dict(), 0
+ if param:
+ for each in param: # ipv4 and ipv6 acl
+ temp_acls = {}
+ if each.get("acls"):
+ 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
+ for ace in acl.get("aces"): # each ace turned to dict
+ if ace.get("destination") and ace.get("destination", {}).get(
+ "port_protocol",
+ {},
+ ):
+ for k, v in (
+ ace.get("destination", {}).get("port_protocol", {}).items()
+ ):
+ ace["destination"]["port_protocol"][
+ k
+ ] = self.port_protocl_no_to_protocol(v)
+ if acl.get("acl_type") == "standard":
+ for ks in list(ace.keys()):
+ if ks not in [
+ "sequence",
+ "grant",
+ "source",
+ "remarks",
+ "log",
+ ]: # failing for mutually exclusive standard acl key
+ self._module.fail_json(
+ "Unsupported attribute for standard ACL - {0}.".format(
+ ks,
+ ),
+ )
+
+ if ace.get("remarks"):
+ en_name = str(acl.get("name")) + "remark"
+ temp_rem.extend(ace.pop("remarks"))
+
+ if ace.get("sequence"):
+ temp_aces.update({ace.get("sequence"): ace})
+ elif ace:
+ count += 1
+ temp_aces.update({"_" + str(count): ace})
+
+ 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(
+ {acl.get("name"): {"aces": temp_aces, "acl_type": acl["acl_type"]}},
+ )
+ else: # if no acl type then here eg: ipv6
+ temp_acls.update({acl.get("name"): {"aces": temp_aces}})
+ each["acls"] = temp_acls
+ temp.update({each["afi"]: {"acls": temp_acls}})
+ return temp
+
+ def port_protocl_no_to_protocol(self, num):
+ map_protocol = {
+ "179": "bgp",
+ "19": "chargen",
+ "514": "cmd",
+ "13": "daytime",
+ "9": "discard",
+ "53": "domain",
+ "7": "echo",
+ "512": "exec",
+ "79": "finger",
+ "21": "ftp",
+ "20": "ftp-data",
+ "70": "gopher",
+ "101": "hostname",
+ "113": "ident",
+ "194": "irc",
+ "543": "klogin",
+ "544": "kshell",
+ "513": "login",
+ "515": "lpd",
+ "135": "msrpc",
+ "119": "nntp",
+ "5001": "onep-plain",
+ "5002": "onep-tls",
+ "496": "pim-auto-rp",
+ "109": "pop2",
+ "110": "pop3",
+ "25": "smtp",
+ "111": "sunrpc",
+ "49": "tacacs",
+ "517": "talk",
+ "23": "telnet",
+ "37": "time",
+ "540": "uucp",
+ "43": "whois",
+ "80": "www",
+ } # NOTE - "514": "syslog" duplicate value device renders "cmd"
+ return map_protocol.get(num, num)
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_address_family/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_address_family/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_address_family/__init__.py
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
new file mode 100644
index 000000000..36ea3e963
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_address_family/bgp_address_family.py
@@ -0,0 +1,428 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2020 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 cisco.ios_bgp_address_family 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 copy import deepcopy
+
+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.bgp_address_family import (
+ Bgp_address_familyTemplate,
+)
+
+
+class Bgp_address_family(ResourceModule):
+ """
+ The cisco.ios_bgp_address_family config class
+ """
+
+ parsers = [
+ "as_number", # generic
+ "aggregate_addresses",
+ "auto_summary",
+ "default",
+ "default_information",
+ "default_metric",
+ "distance",
+ "table_map",
+ "bgp.additional_paths.select", # bgp
+ "bgp.additional_paths.install",
+ "bgp.additional_paths.receive",
+ "bgp.additional_paths.send",
+ "bgp.aggregate_timer",
+ "bgp.dmzlink_bw",
+ "bgp.nexthop.route_map",
+ "bgp.nexthop.trigger.delay",
+ "bgp.nexthop.trigger.enable",
+ "bgp.redistribute_internal",
+ "bgp.route_map",
+ "bgp.scan_time",
+ "bgp.soft_reconfig_backup",
+ "bgp.update_group",
+ "bgp.dampening",
+ "bgp.slow_peer_options.detection.enable",
+ "bgp.slow_peer_options.detection.threshold",
+ "bgp.slow_peer_options.split_update_group.dynamic",
+ "bgp.slow_peer.split_update_group.permanent",
+ "snmp.context.user", # snmp
+ "snmp.context.community",
+ "redistribute.application", # redistribute
+ "redistribute.bgp",
+ "redistribute.connected",
+ "redistribute.eigrp",
+ "redistribute.isis",
+ "redistribute.iso_igrp",
+ "redistribute.lisp",
+ "redistribute.mobile",
+ "redistribute.odr",
+ "redistribute.ospf",
+ "redistribute.ospfv3",
+ "redistribute.rip",
+ "redistribute.static",
+ "redistribute.vrf", # redistribute
+ ]
+
+ def __init__(self, module):
+ super(Bgp_address_family, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="bgp_address_family",
+ tmplt=Bgp_address_familyTemplate(),
+ )
+
+ 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.
+ """
+ if self.state in ["merged", "replaced", "overridden"]:
+ if self.have.get("as_number") and self.want.get("as_number") != self.have.get(
+ "as_number",
+ ):
+ self._module.fail_json(
+ msg="BGP is already running. Only one BGP instance is allowed per device.",
+ )
+
+ for each in self.want, self.have:
+ each["address_family"] = self._bgp_add_fam_list_to_dict(each.get("address_family", []))
+
+ wantd = self.want
+ haved = self.have
+
+ if self.state == "merged":
+ wantd = dict_merge(haved, wantd)
+
+ if self.state == "deleted":
+ for k, have in haved.get("address_family", {}).items():
+ if wantd.get("address_family"):
+ if wantd["address_family"].get(k):
+ self.commands.append(
+ self._tmplt.render(wantd["address_family"].get(k, {}), "afi", True),
+ )
+ else: # to clear off all afs
+ self.commands.append(self._tmplt.render(have, "afi", True))
+
+ # remove superfluous config
+ if self.state in ["overridden"]:
+ for k, have in haved.get("address_family").items():
+ if k not in wantd.get("address_family", {}):
+ self._compare(want={}, have=have)
+
+ if self.state != "deleted": # not deleted state
+ for k, want in wantd.get("address_family", {}).items():
+ self._compare(want=want, have=haved["address_family"].pop(k, {}))
+
+ # adds router bgp AS_NUMB command
+ if len(self.commands) > 0:
+ if self.want.get("as_number"):
+ as_number = self.want
+ else:
+ as_number = self.have
+ self.commands.insert(0, self._tmplt.render(as_number, "as_number", False))
+
+ def _compare(self, want, have):
+ begin = len(self.commands)
+ # for everything else
+ self.compare(parsers=self.parsers, want=want, have=have)
+ # for neighbors
+ self._compare_neighbor_lists(want.get("neighbors", {}), have.get("neighbors", {}))
+ # for networks
+ self._compare_network_lists(want.get("networks", {}), have.get("networks", {}))
+ # for aggregate_addresses
+ self._compare_agg_add_lists(
+ want.get("aggregate_addresses", {}),
+ have.get("aggregate_addresses", {}),
+ )
+ # for distribution of ospfv2 and ospfv3 routes
+ for ospf_version in ["ospf", "ospfv3"]:
+ self._compare_redist_ospf(
+ ospf_version,
+ want.get("redistribute", {}).get(ospf_version, {}),
+ have.get("redistribute", {}).get(ospf_version, {}),
+ )
+ # add af command
+ if len(self.commands) != begin:
+ self.commands.insert(begin, self._tmplt.render(want or have, "afi", False))
+
+ def _compare_redist_ospf(self, _parser, w_attr, h_attr):
+ """
+ Adds and/or removes commands related to
+ ospf and ospv3 redistribution
+ :param _parser: ospf or ospfv3
+ :param w_attr: content of want['redistribute']['ospf']
+ :param h_attr:content of have['redistribute']['ospf']
+ :return: None
+ """
+ for wkey, wentry in w_attr.items():
+ if wentry != h_attr.pop(wkey, {}):
+ # always negate the command in the
+ # appropriate states before applying
+ if self.state in ["overridden", "replaced"]:
+ self.addcmd(wentry, f"redistribute.{_parser}", True)
+ self.addcmd(wentry, f"redistribute.{_parser}", False)
+
+ # remove remaining items in have for replaced state
+ for hkey, hentry in h_attr.items():
+ self.addcmd(hentry, "redistribute.ospf", True)
+
+ def _compare_neighbor_lists(self, want, have):
+ """Compare neighbor list of dict"""
+ neig_parses = [
+ "peer_group",
+ "peer_group_name",
+ "local_as",
+ "remote_as",
+ "activate",
+ "additional_paths",
+ "advertises.additional_paths",
+ "advertises.best_external",
+ "advertises.diverse_path",
+ "advertise_map",
+ "advertisement_interval",
+ "aigp",
+ "aigp.send.cost_community",
+ "aigp.send.med",
+ "allow_policy",
+ "allowas_in",
+ "as_override",
+ "bmp_activate",
+ "capability",
+ "cluster_id",
+ "default_originate",
+ "default_originate.route_map",
+ "description",
+ "disable_connected_check",
+ "ebgp_multihop",
+ "distribute_list",
+ "dmzlink_bw",
+ "filter_list",
+ "fall_over.bfd",
+ "fall_over.route_map",
+ "ha_mode",
+ "inherit",
+ "internal_vpn_client",
+ "log_neighbor_changes",
+ "maximum_prefix",
+ "nexthop_self.set",
+ "nexthop_self.all",
+ "next_hop_unchanged.set",
+ "next_hop_unchanged.allpaths",
+ "password_options",
+ "path_attribute.discard",
+ "path_attribute.treat_as_withdraw",
+ "route_maps",
+ "remove_private_as.set",
+ "remove_private_as.all",
+ "remove_private_as.replace_as",
+ "route_reflector_client",
+ "route_server_client",
+ "send_community.set",
+ "send_community.both",
+ "send_community.extended",
+ "send_community.standard",
+ "shutdown",
+ "slow_peer_options.detection",
+ "slow_peer_options.split_update_group",
+ "soft_reconfiguration",
+ "soo",
+ "timers",
+ "transport.connection_mode",
+ "transport.multi_session",
+ "transport.path_mtu_discovery",
+ "ttl_security",
+ "unsuppress_map",
+ "version",
+ "weight",
+ ]
+
+ for name, w_neighbor in want.items():
+ have_nbr = have.pop(name, {})
+ self.compare(parsers=neig_parses, want=w_neighbor, have=have_nbr)
+ for i in ["route_maps", "prefix_lists"]: # handles route_maps, prefix_lists
+ want_route_or_prefix = w_neighbor.pop(i, {})
+ have_route_or_prefix = have_nbr.pop(i, {})
+ if want_route_or_prefix:
+ for k_rmps, w_rmps in want_route_or_prefix.items():
+ have_rmps = have_route_or_prefix.pop(k_rmps, {})
+ w_rmps["neighbor_address"] = w_neighbor.get("neighbor_address")
+ if have_rmps:
+ have_rmps["neighbor_address"] = have_nbr.get("neighbor_address")
+ have_rmps = {i: have_rmps}
+ self.compare(parsers=[i], want={i: w_rmps}, have=have_rmps)
+ for name, h_neighbor in have.items():
+ self.compare(parsers="neighbor_address", want={}, have=h_neighbor)
+
+ def _compare_network_lists(self, w_attr, h_attr):
+ """Handling of network list options."""
+ for wkey, wentry in w_attr.items():
+ if wentry != h_attr.pop(wkey, {}):
+ self.addcmd(wentry, "networks", False)
+
+ # remove remaining items in have for replaced state
+ for hkey, hentry in h_attr.items():
+ self.addcmd(hentry, "networks", True)
+
+ def _compare_agg_add_lists(self, w_attr, h_attr):
+ """Handling of agg_add list options."""
+ for wkey, wentry in w_attr.items():
+ if wentry != h_attr.pop(wkey, {}):
+ self.addcmd(wentry, "aggregate_addresses", False)
+ # remove remaining items in have for replaced state
+ for hkey, hentry in h_attr.items():
+ self.addcmd(hentry, "aggregate_addresses", True)
+
+ def _bgp_add_fam_list_to_dict(self, tmp_data):
+ """Convert all list of dicts to dicts of dicts, also deals with deprecated attributes"""
+ p_key = {
+ "aggregate_address": "address",
+ "aggregate_addresses": "address",
+ "neighbor": "neighbor_address",
+ "neighbors": "neighbor_address",
+ "route_maps": "name",
+ "prefix_lists": "name",
+ "networks": "address",
+ "network": "address",
+ "ospf": "process_id",
+ "ospfv3": "process_id",
+ }
+
+ af_data = {}
+ for af in tmp_data:
+ _af = {}
+ for k, tval in af.items():
+ val = deepcopy(tval)
+ if k == "neighbor" or k == "neighbors":
+ tmp = {}
+ for neib in val:
+ # address/ tag/ ipv6_address to neighbor_address
+ if neib.get("address"):
+ neib["neighbor_address"] = neib.pop("address")
+ if neib.get("tag"):
+ neib["neighbor_address"] = neib.pop("tag")
+ if neib.get("ipv6_address"):
+ 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")]
+ if neib.get("prefix_lists"):
+ neib["prefix_lists"] = {
+ str(i[p_key["prefix_lists"]]): i for i in neib.get("prefix_lists")
+ }
+ # route_map and route_maps
+ if neib.get("route_map"): # deprecated made list
+ neib["route_maps"] = [neib.pop("route_map")]
+ if neib.get("route_maps"):
+ neib["route_maps"] = {
+ str(i[p_key["route_maps"]]): i for i in neib.get("route_maps")
+ }
+ # 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]
+ # make dict neighbors dict
+ tmp[neib[p_key[k]]] = neib
+ _af["neighbors"] = tmp
+ # make dict networks dict
+ elif k == "network" or k == "networks":
+ _af["networks"] = {str(i[p_key[k]]): i for i in tval}
+ # make dict aggregate_addresses dict
+ elif k == "aggregate_address" or k == "aggregate_addresses":
+ _af["aggregate_addresses"] = {str(i[p_key[k]]): i for i in tval}
+ # slow_peer to slow_peer_options
+ elif k == "bgp":
+ _af["bgp"] = val
+ if val.get("slow_peer"): # only one slow_peer is allowed
+ _af["bgp"]["slow_peer_options"] = _af["bgp"].pop("slow_peer")[0]
+ # keep single dict to compare redistribute
+ elif k == "redistribute":
+ _redist = {}
+ for i in tval:
+ # establish elif sections for future protocols
+ # if necessary
+ if any(x in ["ospf", "ospfv3"] for x in i):
+ for ospf_version in ["ospf", "ospfv3"]:
+ if i.get(ospf_version):
+ _i = i[ospf_version]
+
+ # Start handle deprecates
+ if _i.get("match"):
+ for depr in [
+ "external",
+ "nssa_external",
+ "type_1",
+ "type_2",
+ ]:
+ if depr in _i["match"].keys():
+ val = _i["match"].pop(depr, False)
+ if depr.startswith("type"):
+ # map deprecated nssa_external type to new option
+ if "nssa_externals" in _i["match"].keys():
+ _i["match"]["nssa_externals"][depr] = val
+ else:
+ _i["match"]["nssa_externals"] = {
+ depr: val,
+ }
+ elif depr in ["external", "nssa_external"]:
+ # deprecated external and nssa_external are boolean
+ # so both types mapped to true
+ _i["match"][depr + "s"] = {
+ "type_1": True,
+ "type_2": True,
+ }
+ # End handle deprecates
+
+ if ospf_version not in _redist:
+ _redist[ospf_version] = {}
+
+ _redist[ospf_version].update(
+ {
+ str(_i[p_key[ospf_version]]): dict(_i.items()),
+ },
+ )
+ break
+ else:
+ _redist.update(i)
+ _af["redistribute"] = _redist
+ else:
+ _af[k] = tval
+ # make distinct address family entires
+ af_data[af.get("afi", "") + "_" + af.get("safi", "") + "_" + af.get("vrf", "")] = _af
+
+ return af_data
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_global/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_global/__init__.py
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
new file mode 100644
index 000000000..59881d622
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/bgp_global/bgp_global.py
@@ -0,0 +1,473 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2020 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 cisco.ios_bgp_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.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.bgp_global import (
+ Bgp_globalTemplate,
+)
+
+
+class Bgp_global(ResourceModule):
+ """
+ The cisco.ios_bgp_global config class
+ """
+
+ parsers = [
+ "auto_summary",
+ "bmp.buffer_size",
+ "bmp.initial_refresh.delay",
+ "bmp.initial_refresh.skip",
+ "bmp.server",
+ "bmp.server_options.activate",
+ "bmp.server_options.address",
+ "default_information",
+ "default_metric",
+ "distance.admin",
+ "distance.bgp",
+ "distance.mbgp",
+ "maximum_paths.paths",
+ "maximum_paths.eibgp",
+ "maximum_paths.ibgp",
+ "maximum_secondary_paths.paths",
+ "maximum_secondary_paths.eibgp",
+ "maximum_secondary_paths.ibgp",
+ "route_server_context.name",
+ "route_server_context.address_family",
+ "route_server_context.description",
+ "synchronization",
+ "table_map",
+ "timers",
+ "bgp.additional_paths",
+ "bgp.advertise_best_external",
+ "bgp.aggregate_timer",
+ "bgp.always_compare_med",
+ "bgp.asnotation",
+ "bgp.bestpath_options.aigp",
+ "bgp.bestpath_options.compare_routerid",
+ "bgp.bestpath_options.cost_community",
+ "bgp.bestpath_options.igp_metric",
+ "bgp.bestpath_options.med",
+ "bgp.client_to_client",
+ "bgp.cluster_id",
+ "bgp.confederation.peer",
+ "bgp.confederation.identifier",
+ "bgp.consistency_checker.auto_repair",
+ "bgp.consistency_checker.error_message",
+ "bgp.dampening",
+ "bgp.deterministic_med",
+ "bgp.dmzlink_bw",
+ "bgp.enforce_first_as",
+ "bgp.enhanced_error",
+ "bgp.fast_external_fallover",
+ "bgp.graceful_restart.set",
+ "bgp.graceful_restart.extended",
+ "bgp.graceful_restart.restart_time",
+ "bgp.graceful_restart.stalepath_time",
+ "bgp.graceful_shutdown.neighbors",
+ "bgp.graceful_shutdown.vrfs",
+ "bgp.listen.limit",
+ "bgp.listen.range",
+ "bgp.log_neighbor_changes",
+ "bgp.maxas_limit",
+ "bgp.maxcommunity_limit",
+ "bgp.maxextcommunity_limit",
+ "bgp.nexthop.route_map",
+ "bgp.nexthop.trigger.delay",
+ "bgp.nexthop.trigger.enable",
+ "bgp.nopeerup_delay_options.cold_boot",
+ "bgp.nopeerup_delay_options.post_boot",
+ "bgp.nopeerup_delay_options.nsf_switchover",
+ "bgp.nopeerup_delay_options.user_initiated",
+ "bgp.recursion",
+ "bgp.redistribute_internal",
+ "bgp.refresh.max_eor_time",
+ "bgp.refresh.stalepath_time",
+ "bgp.regexp",
+ "bgp.router_id",
+ "bgp.scan_time",
+ "bgp.slow_peer.detection.set",
+ "bgp.slow_peer.detection.threshold",
+ "bgp.slow_peer.split_update_group",
+ "bgp.snmp",
+ "bgp.sso",
+ "bgp.soft_reconfig_backup",
+ "bgp.suppress_inactive",
+ "bgp.transport",
+ "bgp.update_delay",
+ "bgp.update_group",
+ "bgp.upgrade_cli.set",
+ "bgp.upgrade_cli.af_mode",
+ ]
+
+ def __init__(self, module):
+ super(Bgp_global, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="bgp_global",
+ tmplt=Bgp_globalTemplate(),
+ )
+
+ 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.
+ """
+ if self.state in ["merged", "replaced"]:
+ w_asn = self.want.get("as_number")
+ h_asn = self.have.get("as_number")
+
+ if h_asn and w_asn != h_asn:
+ self._module.fail_json(
+ msg="BGP is already configured with ASN {0}. "
+ "Please remove it with state: purged before "
+ "configuring new ASN".format(h_asn),
+ )
+
+ if self.want:
+ self.handle_deprecates(self.want)
+
+ for each in self.want, self.have:
+ self._bgp_global_list_to_dict(each)
+
+ if self.state == "deleted":
+ # deleted, clean up global params
+ if not self.want or (self.have.get("as_number") == self.want.get("as_number")):
+ self._compare(want={}, have=self.have)
+
+ elif self.state == "purged":
+ # delete as_number takes down whole bgp config
+ if not self.want or (self.have.get("as_number") == self.want.get("as_number")):
+ self.addcmd(self.have or {}, "as_number", True)
+
+ else:
+ wantd = self.want
+ # if state is merged, merge want with have and then compare
+ if self.state == "merged":
+ wantd = dict_merge(self.have, self.want)
+
+ self._compare(want=wantd, have=self.have)
+
+ 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 Bgp_global network resource.
+ """
+ self.generic_list_parsers = ["distributes", "aggregate_addresses", "networks"]
+ if self._has_bgp_inject_maps(want):
+ self.generic_list_parsers.insert(0, "inject_maps")
+
+ cmd_len = len(self.commands) # holds command length to add as_number
+ # for dict type attributes
+ self.compare(parsers=self.parsers, want=want, have=have)
+
+ # for list type attributes
+ for _parse in self.generic_list_parsers:
+ if _parse == "inject_maps":
+ self._compare_generic_lists(
+ want.get("bgp", {}).get(_parse, {}),
+ have.get("bgp", {}).get(_parse, {}),
+ _parse,
+ )
+ else:
+ self._compare_generic_lists(want.get(_parse, {}), have.get(_parse, {}), _parse)
+
+ # for neighbors
+ self._compare_neighbor_lists(want.get("neighbors", {}), have.get("neighbors", {}))
+
+ # for redistribute
+ self._compare_redistribute_lists(want.get("redistribute", {}), have.get("redistribute", {}))
+
+ # add as_number in the begining fo command set if commands generated
+ if len(self.commands) != cmd_len or (not have and want):
+ self.commands.insert(0, self._tmplt.render(want or have, "as_number", False))
+
+ def _has_bgp_inject_maps(self, want):
+ if want.get("bgp", {}).get("inject_maps", {}):
+ return True
+ else:
+ return False
+
+ def _compare_redistribute_lists(self, want, have):
+ """Compare redistribute list of dict"""
+ redist_parses = [
+ "application",
+ "bgp",
+ "connected",
+ "eigrp",
+ "isis",
+ "iso_igrp",
+ "lisp",
+ "mobile",
+ "odr",
+ "ospf",
+ "ospfv3",
+ "rip",
+ "static",
+ "vrf",
+ ]
+ for name, w_redist in want.items():
+ have_nbr = have.pop(name, {})
+ self.compare(parsers=redist_parses, want=w_redist, have=have_nbr)
+
+ # remove remaining items in have for replaced state
+ for name, h_redist in have.items():
+ self.compare(parsers=redist_parses, want={}, have=h_redist)
+
+ def _compare_neighbor_lists(self, want, have):
+ """Compare neighbor list of dict"""
+ neig_parses = [
+ "remote_as",
+ "peer_group",
+ "bmp_activate",
+ "cluster_id",
+ "description",
+ "disable_connected_check",
+ "ebgp_multihop",
+ "fall_over.bfd",
+ "fall_over.route_map",
+ "ha_mode",
+ "inherit",
+ "local_as",
+ "log_neighbor_changes",
+ "password_options",
+ "path_attribute.discard",
+ "path_attribute.treat_as_withdraw",
+ "shutdown",
+ "soft_reconfiguration",
+ "ntimers",
+ "transport.connection_mode",
+ "transport.multi_session",
+ "transport.path_mtu_discovery",
+ "ttl_security",
+ "unsuppress_map",
+ "update_source",
+ "version",
+ "weight",
+ "activate",
+ "additional_paths",
+ "advertise.additional_paths",
+ "advertise.best_external",
+ "advertise.diverse_path",
+ "advertise_map",
+ "advertisement_interval",
+ "aigp",
+ "aigp.send.cost_community",
+ "aigp.send.med",
+ "allow_policy",
+ "allowas_in",
+ "as_override",
+ "bmp_activate",
+ "capability",
+ "default_originate",
+ "default_originate.route_map",
+ "distribute_list",
+ "dmzlink_bw",
+ "filter_list",
+ "maximum_prefix",
+ "next_hop_self.set",
+ "next_hop_self.all",
+ "next_hop_unchanged.set",
+ "next_hop_unchanged.allpaths",
+ "remove_private_as.set",
+ "remove_private_as.all",
+ "remove_private_as.replace_as",
+ "route_reflector_client",
+ "route_server_client.set",
+ "route_server_client.context",
+ "send_community.set",
+ "send_community.both",
+ "send_community.extended",
+ "send_community.standard",
+ "send_label.set",
+ "send_label.explicit_null",
+ "slow_peer.detection",
+ "slow_peer.split_update_group",
+ "translate_update.set",
+ "translate_update.nlri",
+ ]
+
+ for name, w_neighbor in want.items():
+ have_nbr = have.pop(name, {})
+ want_route = w_neighbor.pop("route_maps", {})
+ have_route = have_nbr.pop("route_maps", {})
+ self.compare(parsers=neig_parses, want=w_neighbor, have=have_nbr)
+ if want_route:
+ for k_rmps, w_rmps in want_route.items():
+ have_rmps = have_route.pop(k_rmps, {})
+ w_rmps["neighbor_address"] = w_neighbor.get("neighbor_address")
+ if have_rmps:
+ have_rmps["neighbor_address"] = have_nbr.get("neighbor_address")
+ have_rmps = {"route_maps": have_rmps}
+ self.compare(
+ parsers=["route_maps"],
+ want={"route_maps": w_rmps},
+ have=have_rmps,
+ )
+ for name, h_neighbor in have.items():
+ self.compare(parsers="neighbor_address", want={}, have=h_neighbor)
+
+ def _compare_generic_lists(self, w_attr, h_attr, parser):
+ """Handling of gereric list options."""
+ for wkey, wentry in iteritems(w_attr):
+ if wentry != h_attr.pop(wkey, {}):
+ self.addcmd(wentry, parser, False)
+
+ # remove remaining items in have for replaced state
+ for hkey, hentry in iteritems(h_attr):
+ self.addcmd(hentry, parser, True)
+
+ def _bgp_global_list_to_dict(self, tmp_data):
+ """Convert all list of dicts to dicts of dicts"""
+ p_key = {
+ "aggregate_addresses": "address",
+ "inject_maps": "name",
+ "distributes": ["acl", "gateway", "prefix"],
+ "neighbors": "neighbor_address",
+ "route_maps": "name",
+ "networks": "address",
+ "bgp": None,
+ "redistribute": [
+ "application",
+ "bgp",
+ "eigrp",
+ "isis",
+ "iso_igrp",
+ "ospf",
+ "ospfv3",
+ "vrf",
+ ],
+ }
+ for k, _v in p_key.items():
+ if tmp_data.get(k) and k not in ["distributes", "redistribute", "bgp"]:
+ if k == "neighbors":
+ for neb in tmp_data.get("neighbors"):
+ neb = self._bgp_global_list_to_dict(neb)
+ _ntimer = neb.pop("timers", {})
+ if _ntimer:
+ neb["ntimers"] = _ntimer
+ tmp_data[k] = {str(i[p_key[k]]): i for i in tmp_data[k]}
+ elif tmp_data.get("distributes") and k == "distributes":
+ tmp_data[k] = {str("".join([i.get(j, "") for j in _v])): i for i in tmp_data[k]}
+ elif tmp_data.get("redistribute") and k == "redistribute":
+ tmp_data[k] = {
+ str(
+ [
+ ky + vl.get("name", "") + vl.get("process_id", "") if ky in _v else ky
+ for ky, vl in i.items()
+ ][0],
+ ): i
+ for i in tmp_data[k]
+ }
+ elif tmp_data.get("bgp") and k == "bgp":
+ tmp_data[k] = self._bgp_global_list_to_dict(tmp_data.get(k))
+ return tmp_data
+
+ def handle_deprecates(self, want, is_nbr=False):
+ """
+ Handles deprecated values post rewrite
+ aggregate_address [dict] - aggregate_addresses [list:dict]
+ bgp.bestpath [list:dict] - bgp.bestpath_options [dict]
+ bgp.inject_map [dict] - bgp.inject_map [list:dict]
+ bgp.listen.(ipv4/v6_with_subnet) [multiple] - bgp.listen.host_with_subnet
+ bgp.nopeerup_delay [list:dict] - bgp.nopeerup_delay_option [dict]
+ distributed_list [dict] - distributes [list:dict]
+ neighbor.address.(tag/ipv4/v6_address) [multiple] - neighbor.address.neighbor_address
+ neighbor.password [str] - neighbor.password [dict]
+ neighbor.route_map [dict] - neighbor.route_maps [list:dict]
+
+ Args:
+ want (_type_): Handle want attributes for deprecated values
+ is_nbr (bool, optional): activates neighbor part on recursion. Defaults to False.
+ """
+ if not is_nbr:
+ if want.get("aggregate_address"):
+ if want.get("aggregate_addresses"):
+ want["aggregate_addresses"].append(want.pop("aggregate_address"))
+ else:
+ want["aggregate_addresses"] = [want.pop("aggregate_address")]
+ if want.get("bgp"):
+ _want_bgp = want.get("bgp", {})
+ if _want_bgp.get("bestpath"):
+ bpath = {}
+ for i in _want_bgp.pop("bestpath"):
+ bpath = dict_merge(bpath, i)
+ _want_bgp["bestpath_options"] = bpath
+ if _want_bgp.get("nopeerup_delay"):
+ npdelay = {}
+ for i in _want_bgp.pop("nopeerup_delay"):
+ npdelay = dict_merge(npdelay, i)
+ _want_bgp["nopeerup_delay_options"] = npdelay
+ if _want_bgp.get("inject_map"):
+ if _want_bgp.get("inject_maps"):
+ _want_bgp["inject_maps"].append(_want_bgp.pop("inject_map"))
+ else:
+ _want_bgp["inject_maps"] = [_want_bgp.pop("inject_map")]
+ if _want_bgp.get("listen", {}).get("range"):
+ if _want_bgp.get("listen").get("range").get("ipv4_with_subnet"):
+ _want_bgp["listen"]["range"]["host_with_subnet"] = _want_bgp["listen"][
+ "range"
+ ].pop("ipv4_with_subnet")
+ elif _want_bgp.get("listen").get("range").get("ipv6_with_subnet"):
+ _want_bgp["listen"]["range"]["host_with_subnet"] = _want_bgp["listen"][
+ "range"
+ ].pop("ipv6_with_subnet")
+ if want.get("distribute_list"):
+ if want.get("distributes"):
+ want["distributes"].append(want.pop("distribute_list"))
+ else:
+ want["distributes"] = [want.pop("distribute_list")]
+ if want.get("neighbors"):
+ _want_nbrs = want.get("neighbors", {})
+ for nbr in _want_nbrs:
+ nbr = self.handle_deprecates(nbr, is_nbr=True)
+ else:
+ if want.get("address"):
+ want["neighbor_address"] = want.pop("address")
+ if want.get("tag"):
+ want["neighbor_address"] = want.pop("tag")
+ if want.get("ipv6_adddress"):
+ want["neighbor_address"] = want.pop("ipv6_adddress")
+ if want.get("route_map"):
+ if want.get("route_maps"):
+ want["route_maps"].append(want.pop("route_map"))
+ else:
+ want["route_maps"] = [want.pop("route_map")]
+ if want.get("password"):
+ want["password_options"] = {"pass_key": want.pop("password")}
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/hostname/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/hostname/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/hostname/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/hostname/hostname.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/hostname/hostname.py
new file mode 100644
index 000000000..88d83fe94
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/hostname/hostname.py
@@ -0,0 +1,75 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2022 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_hostname 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.cisco.ios.plugins.module_utils.network.ios.facts.facts import Facts
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.hostname import (
+ HostnameTemplate,
+)
+
+
+class Hostname(ResourceModule):
+ """
+ The ios_hostname config class
+ """
+
+ def __init__(self, module):
+ super(Hostname, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="hostname",
+ tmplt=HostnameTemplate(),
+ )
+ self.parsers = ["hostname"]
+
+ 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 self.state == "deleted":
+ wantd = {}
+
+ 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 Hostname network resource.
+ """
+ self.compare(parsers=self.parsers, want=want, have=have)
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/interfaces/interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/interfaces/interfaces.py
new file mode 100644
index 000000000..2f9e34221
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/interfaces/interfaces.py
@@ -0,0 +1,134 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2022 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_interfaces 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.interfaces import (
+ InterfacesTemplate,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ normalize_interface,
+)
+
+
+class Interfaces(ResourceModule):
+ """
+ The ios_interfaces config class
+ """
+
+ def __init__(self, module):
+ super(Interfaces, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="interfaces",
+ tmplt=InterfacesTemplate(),
+ )
+ self.parsers = ["description", "speed", "mtu", "duplex", "template"]
+
+ 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["name"]: entry for entry in self.want}
+ haved = {entry["name"]: entry for entry in self.have}
+
+ for each in wantd, haved:
+ self.normalize_interface_names(each)
+
+ # 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 in ["deleted", "purged"]:
+ 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._compare(want={}, have=have)
+
+ if self.state == "purged":
+ for k, have in iteritems(haved):
+ self.purge(have)
+ else:
+ 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 Interfaces network resource.
+ """
+ begin = len(self.commands)
+ self.compare(parsers=self.parsers, want=want, have=have)
+ if want.get("enabled") != have.get("enabled"):
+ if want.get("enabled"):
+ self.addcmd(want, "enabled", True)
+ else:
+ if want:
+ self.addcmd(want, "enabled", False)
+ elif have.get("enabled"):
+ # handles deleted as want be blank and only
+ # negates if no shutdown
+ self.addcmd(have, "enabled", False)
+ if want.get("mode") != have.get("mode"):
+ if want.get("mode") == "layer3":
+ self.addcmd(want, "mode", True)
+ else:
+ if want:
+ self.addcmd(want, "mode", False)
+ elif have.get("mode"): # can oly have layer2 as switchport no show cli
+ # handles deleted as want be blank and only
+ self.addcmd(have, "mode", False)
+ if len(self.commands) != begin:
+ self.commands.insert(begin, self._tmplt.render(want or have, "interface", False))
+
+ def purge(self, have):
+ """Handle operation for purged state"""
+ self.commands.append(self._tmplt.render(have, "interface", True))
+
+ def normalize_interface_names(self, param):
+ if param:
+ for _k, val in iteritems(param):
+ val["name"] = normalize_interface(val["name"])
+ return param
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l2_interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l2_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l2_interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l2_interfaces/l2_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l2_interfaces/l2_interfaces.py
new file mode 100644
index 000000000..653b837eb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l2_interfaces/l2_interfaces.py
@@ -0,0 +1,155 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2022 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_l2_interfaces 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.l2_interfaces import (
+ L2_interfacesTemplate,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ normalize_interface,
+ vlan_list_to_range,
+ vlan_range_to_list,
+)
+
+
+class L2_interfaces(ResourceModule):
+ """
+ The ios_l2_interfaces config class
+ """
+
+ def __init__(self, module):
+ super(L2_interfaces, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="l2_interfaces",
+ tmplt=L2_interfacesTemplate(),
+ )
+ self.parsers = [
+ "access.vlan",
+ "access.vlan_name",
+ "voice.vlan",
+ "voice.vlan_tag",
+ "voice.vlan_name",
+ "mode",
+ "trunk.encapsulation",
+ "trunk.native_vlan",
+ ]
+
+ 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["name"]: entry for entry in self.want}
+ haved = {entry["name"]: entry for entry in self.have}
+
+ for each in wantd, haved:
+ self.process_list_attrs(each)
+
+ # 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._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 L2_interfaces network resource.
+ """
+ begin = len(self.commands)
+ self.compare(parsers=self.parsers, want=want, have=have)
+ self.compare_list(want, have)
+ if len(self.commands) != begin:
+ self.commands.insert(begin, self._tmplt.render(want or have, "name", False))
+
+ def compare_list(self, want, have):
+ for vlan in ["allowed_vlans", "pruning_vlans"]:
+ cmd_always = list(
+ set(want.get("trunk", {}).get(vlan, [])) - set(have.get("trunk", {}).get(vlan, [])),
+ ) # find vlans to create wrt have
+ if self.state != "merged":
+ rem_vlan = []
+ for vl_no in have.get("trunk", {}).get(vlan, []):
+ if vl_no not in cmd_always and vl_no not in want.get("trunk", {}).get(vlan, []):
+ rem_vlan.append(vl_no)
+ if (
+ not want.get("trunk", {}).get(vlan, []) and rem_vlan
+ ): # remove vlan all as want blank
+ self.commands.append(
+ "no switchport trunk {0} vlan".format(vlan.split("_", maxsplit=1)[0]),
+ )
+ elif rem_vlan: # remove excess vlans for replaced overridden with vlan entries
+ self.commands.append(
+ "switchport trunk {0} vlan remove {1}".format(
+ vlan.split("_", maxsplit=1)[0],
+ vlan_list_to_range(sorted(rem_vlan)),
+ ),
+ )
+ if self.state != "deleted" and cmd_always: # add configuration needed
+ add = "add " if have.get("trunk", {}).get(vlan, []) else ""
+ self.commands.append(
+ "switchport trunk {0} vlan {1}{2}".format(
+ vlan.split("_", maxsplit=1)[0],
+ add,
+ vlan_list_to_range(sorted(cmd_always)),
+ ),
+ )
+
+ def process_list_attrs(self, param):
+ if param:
+ for _k, val in iteritems(param):
+ val["name"] = normalize_interface(val["name"])
+ if val.get("trunk"):
+ for vlan in ["allowed_vlans", "pruning_vlans"]:
+ if val.get("trunk").get(vlan):
+ val["trunk"][vlan] = vlan_range_to_list(val.get("trunk").get(vlan))
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l3_interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l3_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l3_interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l3_interfaces/l3_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l3_interfaces/l3_interfaces.py
new file mode 100644
index 000000000..b4b874d6e
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/l3_interfaces/l3_interfaces.py
@@ -0,0 +1,215 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat Inc.
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios_l3_interfaces class
+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 it's desired end-state is
+created
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+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.l3_interfaces import (
+ L3_interfacesTemplate,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ normalize_interface,
+ validate_ipv6,
+ validate_n_expand_ipv4,
+)
+
+
+class L3_interfaces(ResourceModule):
+ """
+ The ios_l3_interfaces class
+ """
+
+ def __init__(self, module):
+ super(L3_interfaces, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="l3_interfaces",
+ tmplt=L3_interfacesTemplate(),
+ )
+ self.parsers = [
+ "ipv4.address",
+ "ipv4.pool",
+ "ipv4.dhcp",
+ "ipv6.address",
+ "ipv6.autoconfig",
+ "ipv6.dhcp",
+ ]
+
+ 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.
+ """
+ if self.want:
+ wantd = {}
+ for each in self.want:
+ wantd.update({each["name"]: each})
+ else:
+ wantd = {}
+ if self.have:
+ haved = {}
+ for each in self.have:
+ haved.update({each["name"]: each})
+ else:
+ haved = {}
+
+ for each in wantd, haved:
+ self.list_to_dict(each)
+
+ if self.state == "merged":
+ wantd = dict_merge(haved, wantd)
+
+ if self.state == "deleted":
+ haved = {k: v for k, v in haved.items() if k in wantd or not wantd}
+ wantd = {}
+
+ # remove superfluous config
+ if self.state in ["overridden", "deleted"]:
+ for k, have in haved.items():
+ if k not in wantd:
+ self._compare(want={}, have=have)
+
+ for k, want in wantd.items():
+ self._compare(want=want, have=haved.pop(k, {}))
+
+ def _compare(self, want, have):
+ begin = len(self.commands)
+ self._compare_lists(want=want, have=have)
+ if len(self.commands) != begin:
+ self.commands.insert(begin, self._tmplt.render(want or have, "name", False))
+
+ def _compare_lists(self, want, have):
+ for afi in ("ipv4", "ipv6"):
+ wacls = want.pop(afi, {})
+ hacls = have.pop(afi, {})
+
+ for key, entry in wacls.items():
+ if entry.get("secondary", False) is True:
+ continue
+ # entry is set as primary
+ hacl = hacls.get(key, {})
+ if hacl.get("secondary", False) is True:
+ hacl = {}
+ self.validate_ips(afi, want=entry, have=hacl)
+
+ if hacl:
+ hacls.pop(key, {})
+
+ self.compare(
+ parsers=self.parsers,
+ want={afi: entry},
+ have={afi: hacl},
+ )
+
+ for key, entry in wacls.items():
+ if entry.get("secondary", False) is False:
+ continue
+ # entry is set as secondary
+ hacl = hacls.get(key, {})
+ if hacl.get("secondary", False) is False:
+ # hacl is set as primary, if wacls has no other primary entry we must keep
+ # this entry as primary (so we'll compare entry to hacl and not
+ # generate commands)
+ if list(filter(lambda w: w.get("secondary", False) is False, wacls.values())):
+ # another primary is in wacls
+ hacl = {}
+ self.validate_ips(afi, want=entry, have=hacl)
+
+ if hacl:
+ hacls.pop(key, {})
+
+ self.compare(
+ parsers=self.parsers,
+ want={afi: entry},
+ have={afi: hacl},
+ )
+
+ # remove remaining items in have for replaced
+ # these can be subnets that are no longer used
+ # or secondaries that have moved to primary
+ # or primary that has moved to secondary
+ for key, entry in hacls.items():
+ self.validate_ips(afi, have=entry)
+ self.compare(parsers=self.parsers, want={}, have={afi: entry})
+
+ def validate_ips(self, afi, want=None, have=None):
+ if afi == "ipv4" and want:
+ v4_addr = validate_n_expand_ipv4(self._module, want) if want.get("address") else {}
+ if v4_addr:
+ want["address"] = v4_addr
+ elif afi == "ipv6" and want:
+ if want.get("address"):
+ validate_ipv6(want["address"], self._module)
+
+ if afi == "ipv4" and have:
+ v4_addr_h = validate_n_expand_ipv4(self._module, have) if have.get("address") else {}
+ if v4_addr_h:
+ have["address"] = v4_addr_h
+ elif afi == "ipv6" and have:
+ if have.get("address"):
+ validate_ipv6(have["address"], self._module)
+
+ def list_to_dict(self, param):
+ if param:
+ for _k, val in iteritems(param):
+ val["name"] = normalize_interface(val["name"])
+ if "ipv4" in val:
+ temp = {}
+ for each in val["ipv4"]:
+ if each.get("address") and each.get("address") != "dhcp":
+ temp.update({each["address"]: each})
+ elif each.get("address") == "dhcp":
+ # deprecated attribute
+ temp.update(
+ {
+ "dhcp": {
+ "dhcp": {
+ "client_id": each.get("dhcp_client"),
+ "hostname": each.get("dhcp_hostname"),
+ },
+ },
+ },
+ )
+ if not each.get("address"):
+ temp.update({list(each.keys())[0]: each})
+ val["ipv4"] = temp
+ if "ipv6" in val:
+ temp = {}
+ for each in val["ipv6"]:
+ if each.get("address"):
+ each["address"] = each["address"].lower()
+ temp.update({each["address"]: each})
+ if not each.get("address"):
+ temp.update({list(each.keys())[0]: each})
+ val["ipv6"] = temp
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp/__init__.py
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
new file mode 100644
index 000000000..0420c347b
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp/lacp.py
@@ -0,0 +1,215 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios_lacp class
+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 it's desired end-state is
+created
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__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.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
+
+
+class Lacp(ConfigBase):
+ """
+ The ios_lacp class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["lacp"]
+
+ def __init__(self, module):
+ super(Lacp, self).__init__(module)
+
+ def get_lacp_facts(self, data=None):
+ """Get the 'facts' (the current configuration)
+
+ :rtype: A dictionary
+ :returns: The current configuration as a dictionary
+ """
+ facts, _warnings = Facts(self._module).get_facts(
+ self.gather_subset,
+ self.gather_network_resources,
+ data=data,
+ )
+ lacp_facts = facts["ansible_network_resources"].get("lacp")
+ if not lacp_facts:
+ return dict()
+
+ return lacp_facts
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {"changed": False}
+ commands = list()
+ warnings = list()
+
+ if self.state in self.ACTION_STATES:
+ existing_lacp_facts = self.get_lacp_facts()
+ else:
+ existing_lacp_facts = dict()
+
+ if self.state in self.ACTION_STATES or self.state == "rendered":
+ commands.extend(self.set_config(existing_lacp_facts))
+ if commands and self.state in self.ACTION_STATES:
+ if not self._module.check_mode:
+ self._connection.edit_config(commands)
+ result["changed"] = True
+ if self.state in self.ACTION_STATES:
+ result["commands"] = commands
+
+ if self.state in self.ACTION_STATES or self.state == "gathered":
+ changed_lacp_facts = self.get_lacp_facts()
+ elif self.state == "rendered":
+ result["rendered"] = commands
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_lacp_facts(data=running_config)
+ else:
+ changed_lacp_facts = dict()
+
+ if self.state in self.ACTION_STATES:
+ result["before"] = existing_lacp_facts
+ if result["changed"]:
+ result["after"] = changed_lacp_facts
+ elif self.state == "gathered":
+ result["gathered"] = changed_lacp_facts
+ result["warnings"] = warnings
+
+ return result
+
+ def set_config(self, existing_lacp_facts):
+ """Collect the configuration from the args passed to the module,
+ collect the current configuration (as a dict from facts)
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ want = self._module.params["config"]
+ have = existing_lacp_facts
+ resp = self.set_state(want, have)
+
+ return to_list(resp)
+
+ def set_state(self, want, have):
+ """Select the appropriate function based on the state provided
+
+ :param want: the desired configuration as a dictionary
+ :param have: the current configuration as a dictionary
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ if self.state in ("merged", "replaced", "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 == "deleted":
+ commands = self._state_deleted(want, have)
+ elif self.state in ("merged", "rendered"):
+ commands = self._state_merged(want, have)
+ elif self.state == "replaced":
+ commands = self._state_replaced(want, have)
+
+ return commands
+
+ def _state_replaced(self, want, have):
+ """The command generator when state is replaced
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ commands = []
+
+ commands.extend(self._set_config(want, have))
+
+ return commands
+
+ def _state_merged(self, want, have):
+ """The command generator when state is merged
+
+ :rtype: A list
+ :returns: the commands necessary to merge the provided into
+ the current configuration
+ """
+ commands = []
+
+ commands.extend(self._set_config(want, have))
+
+ return commands
+
+ def _state_deleted(self, want, have):
+ """The command generator when state is deleted
+
+ :rtype: A list
+ :returns: the commands necessary to remove the current configuration
+ of the provided objects
+ """
+ commands = []
+
+ if want:
+ commands.extend(self._clear_config(have))
+ else:
+ commands.extend(self._clear_config(have))
+
+ return commands
+
+ def _remove_command_from_config_list(self, cmd, commands):
+ commands.append("no %s" % cmd)
+ return commands
+
+ def _add_command_to_config_list(self, cmd, commands):
+ if cmd not in commands:
+ commands.append(cmd)
+
+ def _set_config(self, want, have):
+ # Set the interface config based on the want and have config
+ commands = []
+
+ want_dict = dict_to_set(want)
+ have_dict = dict_to_set(have)
+ diff = want_dict - have_dict
+
+ if diff:
+ cmd = "lacp system-priority {0}".format(want.get("system").get("priority"))
+ self._add_command_to_config_list(cmd, commands)
+
+ return commands
+
+ def _clear_config(self, have):
+ # Delete the interface config based on the want and have config
+ commands = []
+
+ if have.get("system").get("priority") and have.get("system").get("priority") != 32768:
+ cmd = "lacp system-priority"
+ self._remove_command_from_config_list(cmd, commands)
+
+ return commands
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp_interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp_interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp_interfaces/lacp_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp_interfaces/lacp_interfaces.py
new file mode 100644
index 000000000..09427b3d6
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lacp_interfaces/lacp_interfaces.py
@@ -0,0 +1,297 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios_lacp_interfaces class
+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 it's desired end-state is
+created
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__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.cisco.ios.plugins.module_utils.network.ios.facts.facts import Facts
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ add_command_to_config_list,
+ dict_to_set,
+ filter_dict_having_none_value,
+ normalize_interface,
+ remove_command_from_config_list,
+ remove_duplicate_interface,
+)
+
+
+class Lacp_Interfaces(ConfigBase):
+ """
+ The ios_lacp_interfaces class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["lacp_interfaces"]
+
+ def __init__(self, module):
+ super(Lacp_Interfaces, self).__init__(module)
+
+ def get_lacp_interfaces_facts(self, data=None):
+ """Get the 'facts' (the current configuration)
+
+ :rtype: A dictionary
+ :returns: The current configuration as a dictionary
+ """
+ facts, _warnings = Facts(self._module).get_facts(
+ self.gather_subset,
+ self.gather_network_resources,
+ data=data,
+ )
+ lacp_interfaces_facts = facts["ansible_network_resources"].get("lacp_interfaces")
+
+ if not lacp_interfaces_facts:
+ return []
+ return lacp_interfaces_facts
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {"changed": False}
+ commands = list()
+ warnings = list()
+
+ if self.state in self.ACTION_STATES:
+ existing_lacp_interfaces_facts = self.get_lacp_interfaces_facts()
+ else:
+ existing_lacp_interfaces_facts = []
+ if self.state in self.ACTION_STATES or self.state == "rendered":
+ commands.extend(self.set_config(existing_lacp_interfaces_facts))
+ if commands and self.state in self.ACTION_STATES:
+ if not self._module.check_mode:
+ self._connection.edit_config(commands)
+ result["changed"] = True
+
+ if self.state in self.ACTION_STATES:
+ result["commands"] = commands
+
+ if self.state in self.ACTION_STATES or self.state == "gathered":
+ changed_lacp_interfaces_facts = self.get_lacp_interfaces_facts()
+ elif self.state == "rendered":
+ result["rendered"] = commands
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_lacp_interfaces_facts(data=running_config)
+ else:
+ changed_lacp_interfaces_facts = []
+
+ if self.state in self.ACTION_STATES:
+ result["before"] = existing_lacp_interfaces_facts
+ if result["changed"]:
+ result["after"] = changed_lacp_interfaces_facts
+ elif self.state == "gathered":
+ result["gathered"] = changed_lacp_interfaces_facts
+
+ result["warnings"] = warnings
+
+ return result
+
+ def set_config(self, existing_lacp_interfaces_facts):
+ """Collect the configuration from the args passed to the module,
+ collect the current configuration (as a dict from facts)
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ config = self._module.params.get("config")
+ want = []
+ if config:
+ for each in config:
+ each.update({"name": normalize_interface(each["name"])})
+ want.append(each)
+ have = existing_lacp_interfaces_facts
+ resp = self.set_state(want, have)
+
+ return to_list(resp)
+
+ def set_state(self, want, have):
+ """Select the appropriate function based on the state provided
+
+ :param want: the desired configuration as a dictionary
+ :param have: the current configuration as a dictionary
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ commands = []
+
+ if self.state in ("overridden", "merged", "replaced", "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":
+ commands = self._state_replaced(want, have)
+
+ return commands
+
+ def _state_replaced(self, want, have):
+ """The command generator when state is replaced
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ commands = []
+
+ for interface in want:
+ for each in have:
+ if each["name"] == interface["name"]:
+ break
+ else:
+ continue
+ have_dict = filter_dict_having_none_value(interface, each)
+ commands.extend(self._clear_config(dict(), have_dict))
+ commands.extend(self._set_config(interface, each))
+ # Remove the duplicate interface call
+ commands = remove_duplicate_interface(commands)
+
+ return commands
+
+ def _state_overridden(self, want, have):
+ """The command generator when state is overridden
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ commands = []
+
+ for each in have:
+ for interface in want:
+ if each["name"] == interface["name"]:
+ break
+ else:
+ # We didn't find a matching desired state, which means we can
+ # pretend we received an empty desired state.
+ interface = dict(name=each["name"])
+ commands.extend(self._clear_config(interface, each))
+ continue
+ have_dict = filter_dict_having_none_value(interface, each)
+ commands.extend(self._clear_config(dict(), have_dict))
+ commands.extend(self._set_config(interface, each))
+ # Remove the duplicate interface call
+ commands = remove_duplicate_interface(commands)
+
+ return commands
+
+ def _state_merged(self, want, have):
+ """The command generator when state is merged
+
+ :rtype: A list
+ :returns: the commands necessary to merge the provided into
+ the current configuration
+ """
+ commands = []
+
+ for interface in want:
+ for each in have:
+ if interface["name"] == each["name"]:
+ break
+ else:
+ commands.extend(self._set_config(interface, dict()))
+ continue
+ commands.extend(self._set_config(interface, each))
+
+ return commands
+
+ def _state_deleted(self, want, have):
+ """The command generator when state is deleted
+
+ :rtype: A list
+ :returns: the commands necessary to remove the current configuration
+ of the provided objects
+ """
+ commands = []
+
+ if want:
+ for interface in want:
+ for each in have:
+ if each["name"] == interface["name"]:
+ break
+ else:
+ continue
+ interface = dict(name=interface["name"])
+ commands.extend(self._clear_config(interface, each))
+ else:
+ for each in have:
+ commands.extend(self._clear_config(dict(), each))
+
+ return commands
+
+ def _set_config(self, want, have):
+ # Set the interface config based on the want and have config
+ commands = []
+ interface = "interface " + want["name"]
+
+ want_dict = dict_to_set(want)
+ have_dict = dict_to_set(have)
+ diff = want_dict - have_dict
+
+ if diff:
+ port_priotity = dict(diff).get("port_priority")
+ max_bundle = dict(diff).get("max_bundle")
+ fast_switchover = dict(diff).get("fast_switchover")
+ if port_priotity:
+ cmd = "lacp port-priority {0}".format(port_priotity)
+ add_command_to_config_list(interface, cmd, commands)
+ if max_bundle:
+ cmd = "lacp max-bundle {0}".format(max_bundle)
+ add_command_to_config_list(interface, cmd, commands)
+ if fast_switchover:
+ cmd = "lacp fast-switchover"
+ add_command_to_config_list(interface, cmd, commands)
+
+ return commands
+
+ def _clear_config(self, want, have):
+ # Delete the interface config based on the want and have config
+ commands = []
+ if want.get("name"):
+ interface = "interface " + want["name"]
+ else:
+ interface = "interface " + have["name"]
+
+ if have.get("port_priority") and have.get("port_priority") != want.get("port_priority"):
+ cmd = "lacp port-priority"
+ remove_command_from_config_list(interface, cmd, commands)
+ if have.get("max_bundle") and have.get("max_bundle") != want.get("max_bundle"):
+ cmd = "lacp max-bundle"
+ remove_command_from_config_list(interface, cmd, commands)
+ if have.get("fast_switchover"):
+ cmd = "lacp fast-switchover"
+ remove_command_from_config_list(interface, cmd, commands)
+
+ return commands
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lag_interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lag_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lag_interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lag_interfaces/lag_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lag_interfaces/lag_interfaces.py
new file mode 100644
index 000000000..10c7cbf96
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lag_interfaces/lag_interfaces.py
@@ -0,0 +1,125 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2022 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_lag_interfaces 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.lag_interfaces import (
+ Lag_interfacesTemplate,
+)
+
+
+class Lag_interfaces(ResourceModule):
+ """
+ The ios_lag_interfaces config class
+ """
+
+ def __init__(self, module):
+ super(Lag_interfaces, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="lag_interfaces",
+ tmplt=Lag_interfacesTemplate(),
+ )
+
+ 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.list_to_dict(self.want)
+ haved = self.list_to_dict(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._compare(wants={}, haveing=have)
+
+ for k, want in iteritems(wantd):
+ self._compare(wants=want, haveing=haved.pop(k, {}))
+
+ def _compare(self, wants, haveing):
+ """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 Lag_interfaces network resource.
+ """
+
+ for key, entry in wants.items():
+ begin = len(self.commands)
+ if entry != haveing.pop(key, {}):
+ self.addcmd(entry, "channel", False)
+ if len(self.commands) != begin:
+ self.commands.insert(begin, self._tmplt.render(entry, "member", False))
+
+ # remove remaining items in have for replaced
+ for key, entry in haveing.items():
+ if key:
+ begin = len(self.commands)
+ self.addcmd(entry, "channel", True)
+ if len(self.commands) != begin:
+ self.commands.insert(begin, self._tmplt.render(entry, "member", False))
+
+ def extract_channel_num(self, channel):
+ try:
+ return channel.lower().split("port-channel")[1], False
+ except IndexError:
+ return channel.lower().split("port-channel")[0], True
+
+ def list_to_dict(self, params):
+ channels = {}
+ for ethChannels in params:
+ tmp = {}
+ for member in ethChannels.get("members", {}):
+ member["channel"] = self.extract_channel_num(ethChannels.get("name"))[0]
+ tmp[member.get("member")] = member
+ update = self.extract_channel_num(ethChannels.get("name"))[1]
+ if update:
+ ethChannels["name"] = "Port-channel" + ethChannels.get("name")
+ channels[ethChannels.get("name")] = tmp
+ return channels
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_global/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_global/__init__.py
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
new file mode 100644
index 000000000..c575bc7b0
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_global/lldp_global.py
@@ -0,0 +1,269 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat Inc.
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios_lldp_global class
+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 __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+from ansible.module_utils.six import iteritems
+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.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,
+ filter_dict_having_none_value,
+)
+
+
+class Lldp_global(ConfigBase):
+ """
+ The ios_lldp_global class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["lldp_global"]
+
+ tlv_select_params = {
+ "four_wire_power_management": "4-wire-power-management",
+ "mac_phy_cfg": "mac-phy-cfg",
+ "management_address": "management-address",
+ "port_description": "port-description",
+ "port_vlan": "port-vlan",
+ "power_management": "power-management",
+ "system_capabilities": "system-capabilities",
+ "system_description": "system-description",
+ "system_name": "system-name",
+ }
+
+ def __init__(self, module):
+ super(Lldp_global, self).__init__(module)
+
+ def get_lldp_global_facts(self, data=None):
+ """Get the 'facts' (the current configuration)
+
+ :rtype: A dictionary
+ :returns: The current configuration as a dictionary
+ """
+ facts, _warnings = Facts(self._module).get_facts(
+ self.gather_subset,
+ self.gather_network_resources,
+ data=data,
+ )
+ lldp_global_facts = facts["ansible_network_resources"].get("lldp_global")
+ if not lldp_global_facts:
+ return {}
+
+ return lldp_global_facts
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {"changed": False}
+ commands = list()
+ warnings = list()
+
+ if self.state in self.ACTION_STATES:
+ existing_lldp_global_facts = self.get_lldp_global_facts()
+ else:
+ existing_lldp_global_facts = dict()
+
+ if self.state in self.ACTION_STATES or self.state == "rendered":
+ commands.extend(self.set_config(existing_lldp_global_facts))
+ if commands and self.state in self.ACTION_STATES:
+ if not self._module.check_mode:
+ self._connection.edit_config(commands)
+ result["changed"] = True
+ if self.state in self.ACTION_STATES:
+ result["commands"] = commands
+
+ if self.state in self.ACTION_STATES or self.state == "gathered":
+ changed_lldp_global_facts = self.get_lldp_global_facts()
+ elif self.state == "rendered":
+ result["rendered"] = commands
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_lldp_global_facts(data=running_config)
+ else:
+ changed_lldp_global_facts = dict()
+
+ if self.state in self.ACTION_STATES:
+ result["before"] = existing_lldp_global_facts
+ if result["changed"]:
+ result["after"] = changed_lldp_global_facts
+ elif self.state == "gathered":
+ result["gathered"] = changed_lldp_global_facts
+ result["warnings"] = warnings
+
+ return result
+
+ def set_config(self, existing_lldp_global_facts):
+ """Collect the configuration from the args passed to the module,
+ collect the current configuration (as a dict from facts)
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ want = self._module.params["config"]
+ have = existing_lldp_global_facts
+ resp = self.set_state(want, have)
+ return to_list(resp)
+
+ def set_state(self, want, have):
+ """Select the appropriate function based on the state provided
+
+ :param want: the desired configuration as a dictionary
+ :param have: the current configuration as a dictionary
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ commands = []
+ if self.state in ("merged", "replaced", "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":
+ commands = self._state_replaced(want, have)
+
+ return commands
+
+ def _state_replaced(self, want, have):
+ """The command generator when state is replaced
+
+ :param want: the desired configuration as a dictionary
+ :param have: the current configuration as a dictionary
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ commands = []
+
+ have_dict = filter_dict_having_none_value(want, have)
+ commands.extend(self._clear_config(have_dict))
+ commands.extend(self._set_config(want, have))
+
+ return commands
+
+ def _state_merged(self, want, have):
+ """The command generator when state is merged
+
+ :param want: the additive configuration as a dictionary
+ :param obj_in_have: the current configuration as a dictionary
+ :rtype: A list
+ :returns: the commands necessary to merge the provided into
+ the current configuration
+ """
+ commands = []
+
+ commands.extend(self._set_config(want, have))
+
+ return commands
+
+ def _state_deleted(self, want, have):
+ """The command generator when state is deleted
+
+ :param want: the objects from which the configuration should be removed
+ :param obj_in_have: the current configuration as a dictionary
+ :rtype: A list
+ :returns: the commands necessary to remove the current configuration
+ of the provided objects
+ """
+ commands = []
+
+ commands.extend(self._clear_config(have))
+
+ return commands
+
+ def _remove_command_from_config_list(self, cmd, commands):
+ if cmd not in commands:
+ commands.append("no %s" % cmd)
+
+ def add_command_to_config_list(self, cmd, commands):
+ if cmd not in commands:
+ commands.append(cmd)
+
+ def _set_config(self, want, have):
+ # Set the lldp global config based on the want and have config
+ commands = []
+
+ # Get the diff b/w want and have
+ want_dict = dict_to_set(want)
+ have_dict = dict_to_set(have)
+ diff = want_dict - have_dict
+
+ if diff:
+ diff = dict(diff)
+ holdtime = diff.get("holdtime")
+ enabled = diff.get("enabled")
+ timer = diff.get("timer")
+ reinit = diff.get("reinit")
+ tlv_select = diff.get("tlv_select")
+
+ if holdtime:
+ cmd = "lldp holdtime {0}".format(holdtime)
+ self.add_command_to_config_list(cmd, commands)
+ if enabled:
+ cmd = "lldp run"
+ self.add_command_to_config_list(cmd, commands)
+ if timer:
+ cmd = "lldp timer {0}".format(timer)
+ self.add_command_to_config_list(cmd, commands)
+ if reinit:
+ cmd = "lldp reinit {0}".format(reinit)
+ self.add_command_to_config_list(cmd, commands)
+ if tlv_select:
+ tlv_selec_dict = dict(tlv_select)
+ for k, v in iteritems(self.tlv_select_params):
+ if k in tlv_selec_dict and tlv_selec_dict[k]:
+ cmd = "lldp tlv-select {0}".format(v)
+ self.add_command_to_config_list(cmd, commands)
+
+ return commands
+
+ def _clear_config(self, have):
+ # Delete the lldp global config based on the want and have config
+ commands = []
+
+ if have.get("holdtime"):
+ cmd = "lldp holdtime"
+ self._remove_command_from_config_list(cmd, commands)
+ if have.get("enabled"):
+ cmd = "lldp run"
+ self._remove_command_from_config_list(cmd, commands)
+ if have.get("timer"):
+ cmd = "lldp timer"
+ self._remove_command_from_config_list(cmd, commands)
+ if have.get("reinit"):
+ cmd = "lldp reinit"
+ self._remove_command_from_config_list(cmd, commands)
+
+ return commands
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_interfaces/lldp_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_interfaces/lldp_interfaces.py
new file mode 100644
index 000000000..20d1f01b8
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/lldp_interfaces/lldp_interfaces.py
@@ -0,0 +1,315 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios_lldp_interfaces class
+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 __future__ import absolute_import, division, print_function
+
+
+__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.cisco.ios.plugins.module_utils.network.ios.facts.facts import Facts
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ add_command_to_config_list,
+ dict_to_set,
+ filter_dict_having_none_value,
+ normalize_interface,
+ remove_command_from_config_list,
+ remove_duplicate_interface,
+)
+
+
+class Lldp_Interfaces(ConfigBase):
+ """
+ The ios_lldp_interfaces class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["lldp_interfaces"]
+
+ def __init__(self, module):
+ super(Lldp_Interfaces, self).__init__(module)
+
+ def get_lldp_interfaces_facts(self, data=None):
+ """Get the 'facts' (the current configuration)
+
+ :rtype: A dictionary
+ :returns: The current configuration as a dictionary
+ """
+ facts, _warnings = Facts(self._module).get_facts(
+ self.gather_subset,
+ self.gather_network_resources,
+ data=data,
+ )
+ lldp_interfaces_facts = facts["ansible_network_resources"].get("lldp_interfaces")
+ if not lldp_interfaces_facts:
+ return []
+ return lldp_interfaces_facts
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {"changed": False}
+ commands = list()
+ warnings = list()
+
+ if self.state in self.ACTION_STATES:
+ existing_lldp_interfaces_facts = self.get_lldp_interfaces_facts()
+ else:
+ existing_lldp_interfaces_facts = []
+ if self.state in self.ACTION_STATES or self.state == "rendered":
+ commands.extend(self.set_config(existing_lldp_interfaces_facts))
+ if commands and self.state in self.ACTION_STATES:
+ if not self._module.check_mode:
+ self._connection.edit_config(commands)
+ result["changed"] = True
+ if self.state in self.ACTION_STATES:
+ result["commands"] = commands
+
+ if self.state in self.ACTION_STATES or self.state == "gathered":
+ changed_lldp_interfaces_facts = self.get_lldp_interfaces_facts()
+ elif self.state == "rendered":
+ result["rendered"] = commands
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_lldp_interfaces_facts(data=running_config)
+ else:
+ changed_lldp_interfaces_facts = []
+
+ if self.state in self.ACTION_STATES:
+ result["before"] = existing_lldp_interfaces_facts
+ if result["changed"]:
+ result["after"] = changed_lldp_interfaces_facts
+ elif self.state == "gathered":
+ result["gathered"] = changed_lldp_interfaces_facts
+
+ result["warnings"] = warnings
+
+ return result
+
+ def set_config(self, existing_lldp_interfaces_facts):
+ """Collect the configuration from the args passed to the module,
+ collect the current configuration (as a dict from facts)
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ config = self._module.params.get("config")
+ want = []
+ if config:
+ for each in config:
+ each.update({"name": normalize_interface(each["name"])})
+ want.append(each)
+ have = existing_lldp_interfaces_facts
+ resp = self.set_state(want, have)
+
+ return to_list(resp)
+
+ def set_state(self, want, have):
+ """Select the appropriate function based on the state provided
+
+ :param want: the desired configuration as a dictionary
+ :param have: the current configuration as a dictionary
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+
+ if self.state in ("overridden", "merged", "replaced", "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":
+ commands = self._state_replaced(want, have)
+
+ return commands
+
+ def _state_replaced(self, want, have):
+ """The command generator when state is replaced
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ commands = []
+
+ for interface in want:
+ for each in have:
+ if each["name"] == interface["name"]:
+ break
+ else:
+ continue
+ have_dict = filter_dict_having_none_value(interface, each)
+ commands.extend(self._clear_config(dict(), have_dict))
+ commands.extend(self._set_config(interface, each))
+ # Remove the duplicate interface call
+ commands = remove_duplicate_interface(commands)
+
+ return commands
+
+ def _state_overridden(self, want, have):
+ """The command generator when state is overridden
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ commands = []
+
+ for each in have:
+ for interface in want:
+ if each["name"] == interface["name"]:
+ break
+ else:
+ # We didn't find a matching desired state, which means we can
+ # pretend we received an empty desired state.
+ interface = dict(name=each["name"])
+ commands.extend(self._clear_config(interface, each))
+ continue
+ have_dict = filter_dict_having_none_value(interface, each)
+ commands.extend(self._clear_config(dict(), have_dict))
+ commands.extend(self._set_config(interface, each))
+ # Remove the duplicate interface call
+ commands = remove_duplicate_interface(commands)
+
+ return commands
+
+ def _state_merged(self, want, have):
+ """The command generator when state is merged
+
+ :rtype: A list
+ :returns: the commands necessary to merge the provided into
+ the current configuration
+ """
+ commands = []
+
+ for interface in want:
+ for each in have:
+ if interface["name"] == each["name"]:
+ break
+ else:
+ if self.state == "rendered":
+ commands.extend(self._set_config(interface, dict()))
+ continue
+ commands.extend(self._set_config(interface, each))
+
+ return commands
+
+ def _state_deleted(self, want, have):
+ """The command generator when state is deleted
+
+ :rtype: A list
+ :returns: the commands necessary to remove the current configuration
+ of the provided objects
+ """
+ commands = []
+
+ if want:
+ for interface in want:
+ for each in have:
+ if each["name"] == interface["name"]:
+ break
+ else:
+ continue
+ interface = dict(name=interface["name"])
+ commands.extend(self._clear_config(interface, each))
+ else:
+ for each in have:
+ commands.extend(self._clear_config(dict(), each))
+
+ return commands
+
+ def _set_config(self, want, have):
+ # Set the interface config based on the want and have config
+ commands = []
+
+ interface = "interface " + want["name"]
+ # Get the diff b/w want and have
+ want_dict = dict_to_set(want)
+ have_dict = dict_to_set(have)
+ diff = want_dict - have_dict
+
+ if diff:
+ diff = dict(diff)
+ receive = diff.get("receive")
+ transmit = diff.get("transmit")
+ med_tlv_select = diff.get("med_tlv_select")
+ tlv_select = diff.get("tlv_select")
+ if receive:
+ cmd = "lldp receive"
+ add_command_to_config_list(interface, cmd, commands)
+ elif receive is False:
+ cmd = "no lldp receive"
+ add_command_to_config_list(interface, cmd, commands)
+ if transmit:
+ cmd = "lldp transmit"
+ add_command_to_config_list(interface, cmd, commands)
+ elif transmit is False:
+ cmd = "no lldp transmit"
+ add_command_to_config_list(interface, cmd, commands)
+
+ if med_tlv_select:
+ med_tlv_select = dict(med_tlv_select)
+ if med_tlv_select.get("inventory_management"):
+ add_command_to_config_list(
+ interface,
+ "lldp med-tlv-select inventory-management",
+ commands,
+ )
+ if tlv_select:
+ tlv_select = dict(tlv_select)
+ if tlv_select.get("power_management"):
+ add_command_to_config_list(
+ interface,
+ "lldp tlv-select power-management",
+ commands,
+ )
+
+ return commands
+
+ def _clear_config(self, want, have):
+ # Delete the interface config based on the want and have config
+ commands = []
+ if want.get("name"):
+ interface = "interface " + want["name"]
+ else:
+ interface = "interface " + have["name"]
+
+ if have.get("receive") and have.get("receive") != want.get("receive"):
+ cmd = "lldp receive"
+ remove_command_from_config_list(interface, cmd, commands)
+ if have.get("transmit") and have.get("transmit") != want.get("transmit"):
+ cmd = "lldp transmit"
+ remove_command_from_config_list(interface, cmd, commands)
+
+ return commands
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/logging_global/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/logging_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/logging_global/__init__.py
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
new file mode 100644
index 000000000..4eb442a0c
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/logging_global/logging_global.py
@@ -0,0 +1,170 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2021 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_logging_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 copy import deepcopy
+
+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,
+)
+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.logging_global import (
+ Logging_globalTemplate,
+)
+
+
+class Logging_global(ResourceModule):
+ """
+ The ios_logging_global config class
+ """
+
+ def __init__(self, module):
+ super(Logging_global, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="logging_global",
+ tmplt=Logging_globalTemplate(),
+ )
+ self.parsers = [
+ "buffered",
+ "buginf",
+ "cns_events",
+ "console",
+ "count",
+ "delimiter",
+ "dmvpn",
+ "esm",
+ "exception",
+ "facility",
+ "history.size",
+ "history.severity",
+ "monitor",
+ "logging_on",
+ "origin_id",
+ "persistent",
+ "policy_firewall",
+ "queue_limit",
+ "rate_limit",
+ "reload",
+ "server_arp",
+ "trap",
+ "userinfo",
+ ]
+ self.list_parsers = ["hosts", "filter", "source_interface"]
+ self.complex_parsers = ["message_counter", "discriminator", "snmp_trap"]
+
+ 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.list_to_dict(self.want)
+ haved = self.list_to_dict(self.have)
+
+ if self.state == "merged":
+ wantd = dict_merge(haved, wantd)
+
+ if self.state == "deleted":
+ wantd = {}
+
+ 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 Logging_global network resource.
+ """
+ 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"""
+ for _par in self.list_parsers:
+ i_want = want.get(_par, {})
+ i_have = have.get(_par, {})
+ for key, wanting in iteritems(i_want):
+ _parser = _par
+ if wanting.get("transport") and _parser == "hosts":
+ _parser = "hosts.transport"
+ 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):
+ _parser = _par
+ if haveing.get("transport") and _parser == "hosts":
+ _parser = "hosts.transport"
+ self.addcmd(haveing, _parser, negate=True)
+
+ def _compare_complex_attrs(self, want, have):
+ """Compare dict of list"""
+ for _par in self.complex_parsers:
+ i_want = want.get(_par, {})
+ i_have = have.get(_par, {})
+ 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, _par, negate=True)
+ self.addcmd(wanting, _par)
+ for key, haveing in iteritems(i_have):
+ self.addcmd(haveing, _par, negate=True)
+
+ def list_to_dict(self, data):
+ """Convert all list of dicts to dicts of dicts"""
+ p_key = {"filter": "url", "hosts": "host", "source_interface": "interface"}
+ if data.get("hosts"): # handle aliased hostname as host
+ for v in data.get("hosts"):
+ if v.get("hostname"):
+ v["host"] = v.pop("hostname")
+ list_el = ["message_counter", "discriminator", "snmp_trap"]
+ tmp_data = deepcopy(data)
+ for k, _v in p_key.items():
+ if tmp_data.get(k):
+ tmp_data[k] = {
+ str(i[p_key[k]]) if i.get(p_key[k]) else str(i.get("ipv6")): i
+ for i in tmp_data[k]
+ }
+ for el in list_el:
+ if tmp_data.get(el):
+ tmp_data[el] = {self.trim_whitespace(el + i): {el: i} for i in tmp_data[el]}
+ return tmp_data
+
+ def trim_whitespace(self, word):
+ return to_text(word).strip()
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ntp_global/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ntp_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ntp_global/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ntp_global/ntp_global.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ntp_global/ntp_global.py
new file mode 100644
index 000000000..ace378e08
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ntp_global/ntp_global.py
@@ -0,0 +1,171 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2021 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_ntp_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 copy import deepcopy
+
+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.ntp_global import (
+ Ntp_globalTemplate,
+)
+
+
+class Ntp_global(ResourceModule):
+ """
+ The ios_ntp_global config class
+ """
+
+ def __init__(self, module):
+ super(Ntp_global, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="ntp_global",
+ tmplt=Ntp_globalTemplate(),
+ )
+ self.parsers = [
+ "allow.control.rate_limit",
+ "allow.private",
+ "authenticate",
+ "broadcast_delay",
+ "clock_period",
+ "logging",
+ "master.enabled",
+ "master.stratum",
+ "max_associations",
+ "max_distance",
+ "min_distance",
+ "orphan",
+ "panic_update",
+ "passive",
+ "source",
+ "update_calendar",
+ ]
+ self.complex_parser = [
+ "peer",
+ "query_only",
+ "serve",
+ "serve_only",
+ "authentication_keys",
+ "peers",
+ "servers",
+ "trusted_keys",
+ ]
+
+ 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._ntp_list_to_dict(self.want)
+ haved = self._ntp_list_to_dict(self.have)
+
+ if self.state == "merged":
+ wantd = dict_merge(haved, wantd)
+
+ if self.state == "deleted":
+ wantd = {}
+
+ 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 Ntp_global network resource.
+ """
+ self.compare(parsers=self.parsers, want=want, have=have)
+ self._compare_access_groups(want, have)
+ self._compare_lists_attrs(want, have)
+
+ def _compare_lists_attrs(self, want, have):
+ """Compare list of dict"""
+ for _parser in self.complex_parser[4:8]: # other list attrs
+ 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 (
+ _parser != "authentication_keys"
+ and 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 _compare_access_groups(self, want, have):
+ w = want.get("access_group", {})
+ h = have.get("access_group", {})
+ for _parser in self.complex_parser[0:4]: # access_group
+ i_want = w.get(_parser, {})
+ i_have = h.get(_parser, {})
+
+ for key, wanting in iteritems(i_want):
+ haveing = i_have.pop(key, {})
+ if wanting != haveing:
+ self.addcmd(wanting, _parser)
+
+ for key, haveing in iteritems(i_have):
+ self.addcmd(haveing, _parser, negate=True)
+
+ def _ntp_list_to_dict(self, data):
+ """Convert all list of dicts to dicts of dicts"""
+ p_key = {
+ "servers": "server",
+ "peers": "peer",
+ "authentication_keys": "id",
+ "peer": "access_list",
+ "query_only": "access_list",
+ "serve": "access_list",
+ "serve_only": "access_list",
+ "trusted_keys": "range_start",
+ "access_group": True,
+ }
+ tmp_data = deepcopy(data)
+ for k, _v in p_key.items():
+ if k in tmp_data and k != "access_group":
+ if k in ["servers", "peers"]:
+ for i in tmp_data[k]:
+ if i.get("key"):
+ del i["key"]
+ tmp_data[k] = {str(i[p_key[k]]): i for i in tmp_data[k]}
+ elif tmp_data.get("access_group") and k == "access_group":
+ tmp_data[k] = self._ntp_list_to_dict(tmp_data.get("access_group"))
+ return tmp_data
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospf_interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospf_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospf_interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospf_interfaces/ospf_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospf_interfaces/ospf_interfaces.py
new file mode 100644
index 000000000..f10c6d871
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospf_interfaces/ospf_interfaces.py
@@ -0,0 +1,150 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2020 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 cisco.ios_ospf_interfaces 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.ospf_interfaces import (
+ Ospf_interfacesTemplate,
+)
+
+
+class Ospf_interfaces(ResourceModule):
+ """
+ The cisco.ios_ospf_interfaces config class
+ """
+
+ def __init__(self, module):
+ super(Ospf_interfaces, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="ospf_interfaces",
+ tmplt=Ospf_interfacesTemplate(),
+ )
+ self.parsers = []
+
+ 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.
+ """
+
+ # turn all lists of dicts into dicts prior to merge
+ wantd = self._list_to_dict(self.want, "want")
+ haved = self._list_to_dict(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 haved.items() 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 haved.items():
+ if k not in wantd:
+ self._compare(want={}, have=have, interface=k)
+
+ for k, want in wantd.items():
+ self._compare(want=want, have=haved.pop(k, {}), interface=k)
+
+ def _compare(self, want, have, interface):
+ begin = len(self.commands)
+ self._compare_afis(want=want, have=have)
+ if len(self.commands) != begin:
+ self.commands.insert(begin, self._tmplt.render({"name": interface}, "name", False))
+
+ def _compare_afis(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 Ospf_interfaces network resource.
+ """
+
+ parsers = [
+ "name",
+ "process",
+ "adjacency",
+ "authentication",
+ "bfd",
+ "cost",
+ "database_filter",
+ "dead_interval",
+ "demand_circuit",
+ "flood_reduction",
+ "hello_interval",
+ "lls",
+ "manet",
+ "mtu_ignore",
+ "multi_area",
+ "neighbor",
+ "network",
+ "prefix_suppression",
+ "priority",
+ "resync_timeout",
+ "retransmit_interval",
+ "shutdown",
+ "transmit_delay",
+ "ttl_security",
+ ]
+
+ for afi in ("ipv4", "ipv6"):
+ wacls = want.pop(afi, {})
+ hacls = have.pop(afi, {})
+
+ self.compare(parsers=parsers, want=wacls, have=hacls)
+
+ def _list_to_dict(self, entry, attr_type=None):
+ if self.state == "deleted" and attr_type == "want":
+ del_list = {}
+ for intf in entry:
+ del_list[intf.get("name")] = {}
+ return del_list
+
+ list_to_dict = {}
+ for intf in entry:
+ if intf.get("address_family"):
+ list_to_dict[intf.get("name")] = self.process_list_attr(intf)
+ return list_to_dict
+
+ def process_list_attr(self, add_fam):
+ item = {}
+ for ag in add_fam.get("address_family", []):
+ item[ag.get("afi")] = ag
+ return item
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv2/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv2/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv2/__init__.py
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
new file mode 100644
index 000000000..2cbc53e17
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv2/ospfv2.py
@@ -0,0 +1,284 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios_ospfv2 class
+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 it's desired end-state is
+created
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+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.ospfv2 import (
+ Ospfv2Template,
+)
+
+
+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={},
+ facts_module=Facts(module),
+ module=module,
+ resource="ospfv2",
+ tmplt=Ospfv2Template(),
+ )
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ self.gen_config()
+ self.run_commands()
+ return self.result
+
+ def gen_config(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
+ """
+ if self.want:
+ wantd = {}
+ for entry in self.want.get("processes", []):
+ wantd.update({(entry["process_id"], entry.get("vrf")): entry})
+ else:
+ wantd = {}
+ if self.have:
+ haved = {}
+ for entry in self.have.get("processes", []):
+ 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 state is merged, merge want onto have
+ if self.state == "merged":
+ wantd = dict_merge(haved, wantd)
+
+ # if state is deleted, limit the have to anything in want
+ # set want to nothing
+ if self.state == "deleted":
+ temp = {}
+ for k, v in iteritems(haved):
+ if k in wantd or not wantd:
+ temp.update({k: v})
+ haved = temp
+ wantd = {}
+
+ # delete processes first so we do run into "more than one" errors
+ if self.state in ["overridden", "deleted"]:
+ for k, have in iteritems(haved):
+ if k not in wantd:
+ self.addcmd(have, "pid", True)
+
+ for k, want in iteritems(wantd):
+ 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._areas_compare(want, have)
+ if want.get("passive_interfaces"):
+ self._passive_interfaces_compare(want, have)
+
+ def _areas_compare(self, want, have):
+ wareas = want.get("areas", {})
+ hareas = have.get("areas", {})
+ for name, entry in iteritems(wareas):
+ self._area_compare(want=entry, have=hareas.pop(name, {}))
+ for name, entry in iteritems(hareas):
+ self._area_compare(want={}, have=entry)
+
+ 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",
+ ]
+ self.compare(parsers=parsers, want=want, have=have)
+ self._area_compare_filters(want, have)
+
+ 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 _passive_interfaces_compare(self, want, have):
+ parsers = ["passive_interfaces"]
+ 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:
+ for each in v["name"]:
+ h_interface_name = h_pi[k].get("name", [])
+ if each not in h_interface_name:
+ temp = {"interface": {each: each}, "set_interface": v["set_interface"]}
+ self.compare(
+ parsers=parsers,
+ want={"passive_interfaces": temp},
+ have=dict(),
+ )
+ else:
+ h_interface_name.pop(each)
+ elif not h_pi:
+ if k == "interface":
+ for each in v["name"]:
+ temp = {"interface": {each: each}, "set_interface": v["set_interface"]}
+ self.compare(
+ parsers=parsers,
+ want={"passive_interfaces": temp},
+ have=dict(),
+ )
+ elif k == "default":
+ self.compare(
+ parsers=parsers,
+ want={"passive_interfaces": {"default": True}},
+ have=dict(),
+ )
+ else:
+ h_pi.pop(k)
+ if (self.state == "replaced" or self.state == "overridden") and h_pi:
+ if h_pi.get("default") or h_pi.get("interface"):
+ for k, v in iteritems(h_pi):
+ if k == "interface":
+ for each in v["name"]:
+ temp = {
+ "interface": {each: each},
+ "set_interface": not (v["set_interface"]),
+ }
+ self.compare(
+ parsers=parsers,
+ want={"passive_interface": temp},
+ have=dict(),
+ )
+ elif k == "default":
+ self.compare(
+ parsers=parsers,
+ want=dict(),
+ have={"passive_interface": {"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
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv3/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv3/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv3/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv3/ospfv3.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv3/ospfv3.py
new file mode 100644
index 000000000..7b2464260
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ospfv3/ospfv3.py
@@ -0,0 +1,298 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios_ospfv3 class
+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 it's desired end-state is
+created
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+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.ospfv3 import (
+ Ospfv3Template,
+)
+
+
+class Ospfv3(ResourceModule):
+ """
+ The ios_ospfv3 class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["ospfv3"]
+
+ def __init__(self, module):
+ super(Ospfv3, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="ospfv3",
+ tmplt=Ospfv3Template(),
+ )
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ self.gen_config()
+ self.run_commands()
+ return self.result
+
+ def gen_config(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
+ """
+ if self.want:
+ wantd = {}
+ for entry in self.want.get("processes", []):
+ wantd.update({(entry["process_id"], entry.get("vrf")): entry})
+ else:
+ wantd = {}
+ if self.have:
+ haved = {}
+ for entry in self.have.get("processes", []):
+ haved.update({(entry["process_id"], entry.get("vrf")): entry})
+ else:
+ haved = {}
+
+ # turn all lists of dicts into dicts prior to merge
+ for thing in wantd, haved:
+ for _pid, proc in iteritems(thing):
+ 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 state is merged, merge want onto have
+ if self.state == "merged":
+ wantd = dict_merge(haved, wantd)
+
+ # if state is deleted, limit the have to anything in want
+ # set want to nothing
+ if self.state == "deleted":
+ temp = {}
+ for k, v in iteritems(haved):
+ if k in wantd or not wantd:
+ temp.update({k: v})
+ haved = temp
+ wantd = {}
+
+ # delete processes first so we do run into "more than one" errors
+ if self.state in ["overridden", "deleted"]:
+ for k, have in iteritems(haved):
+ if k not in wantd:
+ self.addcmd(have, "pid", True)
+
+ for k, want in iteritems(wantd):
+ self._compare(want=want, have=haved.pop(k, {}))
+
+ def _compare(self, want, have):
+ parsers = [
+ "adjacency",
+ "auto_cost",
+ "bfd",
+ "compatible",
+ "event_log",
+ "help",
+ "interface_id",
+ "limit",
+ "local_rib_criteria",
+ "log_adjacency_changes",
+ "manet",
+ "max_lsa",
+ "max_metric",
+ "passive_interface",
+ "prefix_suppression",
+ "queue_depth.hello",
+ "queue_depth.update",
+ "router_id",
+ "shutdown",
+ "timers.throttle.lsa",
+ "timers.throttle.spf",
+ ]
+
+ if want != have:
+ self.addcmd(want or have, "pid", False)
+ self.compare(parsers, want, have)
+ self._areas_compare(want, have)
+ self._address_family_compare(want, have)
+
+ if len(self.commands) == 1 and "router" in self.commands[0]:
+ del self.commands[0]
+
+ def _areas_compare(self, want, have):
+ wareas = want.get("areas", {})
+ hareas = have.get("areas", {})
+ for name, entry in iteritems(wareas):
+ self._area_compare(want=entry, have=hareas.pop(name, {}))
+ for name, entry in iteritems(hareas):
+ self._area_compare(want={}, have=entry)
+
+ 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",
+ ]
+ self.compare(parsers=parsers, want=want, have=have)
+ self._area_compare_filters(want, have)
+
+ 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 _address_family_compare(self, want, have):
+ if want["process_id"] == have.get("process_id") or want["process_id"]:
+ af_parsers = [
+ "address_family.adjacency",
+ "address_family.auto_cost",
+ "address_family.bfd",
+ "address_family.capability",
+ "address_family.compatible",
+ "address_family.default_information",
+ "address_family.default_metric",
+ "address_family.distance.admin_distance",
+ "address_family.distance.ospf",
+ "address_family.distribute_list.acls",
+ "address_family.distribute_list.prefix",
+ "address_family.distribute_list.route_map",
+ "address_family.event_log",
+ "address_family.graceful_restart",
+ "address_family.interface_id",
+ "address_family.limit",
+ "address_family.local_rib_criteria",
+ "address_family.log_adjacency_changes",
+ "address_family.manet",
+ "address_family.max_lsa",
+ "address_family.max_metric",
+ "address_family.maximum_paths",
+ "address_family.passive_interface",
+ "address_family.prefix_suppression",
+ "address_family.queue_depth.hello",
+ "address_family.queue_depth.update",
+ "address_family.router_id",
+ "address_family.shutdown",
+ "address_family.summary_prefix",
+ "address_family.timers.throttle.lsa",
+ "address_family.timers.throttle.spf",
+ ]
+ delete_exit_family = False
+ for each_want_af in want["address_family"]:
+ if have.get("address_family"):
+ for each_have_af in have["address_family"]:
+ if each_have_af.get("vrf") == each_want_af.get("vrf") and each_have_af.get(
+ "afi",
+ ) == each_want_af.get("afi"):
+ self.compare(
+ parsers=["address_family"],
+ want={"address_family": each_want_af},
+ have={"address_family": each_have_af},
+ )
+ self.compare(parsers=af_parsers, want=each_want_af, have=each_have_af)
+ elif each_have_af.get("afi") == each_want_af.get("afi"):
+ self.compare(
+ parsers=["address_family"],
+ want={"address_family": each_want_af},
+ have={"address_family": each_have_af},
+ )
+ self.compare(
+ parsers=af_parsers,
+ want={"address_family": each_want_af},
+ have={"address_family": each_have_af},
+ )
+ if each_want_af.get("areas"):
+ af_want_areas = {}
+ af_have_areas = {}
+ for each_area in each_want_af["areas"]:
+ af_want_areas.update({each_area["area_id"]: each_area})
+ if each_have_af.get("areas"):
+ for each_area in each_have_af["areas"]:
+ af_have_areas.update({each_area["area_id"]: each_area})
+
+ if "exit-address-family" in self.commands:
+ del self.commands[self.commands.index("exit-address-family")]
+ delete_exit_family = True
+
+ if af_have_areas:
+ self._areas_compare(
+ {"areas": af_want_areas},
+ {"areas": af_have_areas},
+ )
+ else:
+ self._areas_compare({"areas": af_want_areas}, dict())
+ if delete_exit_family:
+ self.commands.append("exit-address-family")
+ else:
+ temp_cmd_before = self.commands
+ self.commands = []
+ self.compare(
+ parsers=["address_family"],
+ want={"address_family": each_want_af},
+ have=dict(),
+ )
+ self.compare(parsers=af_parsers, want=each_want_af, have=dict())
+ if each_want_af.get("areas"):
+ af_areas = {}
+ for each_area in each_want_af["areas"]:
+ af_areas.update({each_area["area_id"]: each_area})
+ self._areas_compare({"areas": af_areas}, dict())
+ del self.commands[self.commands.index("exit-address-family")]
+ self.commands.append("exit-address-family")
+ self.commands[0:0] = temp_cmd_before
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ping/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ping/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ping/__init__.py
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
new file mode 100644
index 000000000..f2417f596
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/ping/ping.py
@@ -0,0 +1,96 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2022 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_ping 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 import utils
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import run_commands
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.ping import (
+ PingTemplate,
+)
+
+
+class Ping:
+ """
+ The ios_ping config class
+ """
+
+ def __init__(self, module):
+ self.module = module
+ self.result = {}
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ self.generate_command()
+ res = self.run_command()
+ return self.process_result(res)
+
+ def build_ping(self, params):
+ tmplt = PingTemplate()
+ params = utils.remove_empties(params)
+ cmd = tmplt.render(params, "rate", False)
+ return cmd
+
+ def validate_results(self, module, loss, results):
+ """
+ This function is used to validate whether the ping results were unexpected per "state" param.
+ """
+ state = module.params["state"]
+ if state == "present" and loss == 100:
+ module.fail_json(msg="Ping failed unexpectedly", **results)
+ elif state == "absent" and loss < 100:
+ module.fail_json(msg="Ping succeeded unexpectedly", **results)
+
+ def generate_command(self):
+ """Generate configuration commands to send based on
+ want, have and desired state.
+ """
+ warnings = list()
+ if warnings:
+ self.result["warnings"] = warnings
+ self.result["commands"] = self.build_ping(self.module.params)
+
+ def run_command(self):
+ ping_results = run_commands(self.module, commands=self.result["commands"])
+ return ping_results
+
+ def process_result(self, ping_results):
+ """
+ Function used to parse the statistical information from the ping response.
+ Example: "Success rate is 100 percent (5/5), round-trip min/avg/max = 1/2/8 ms"
+ Returns the percent of packet loss, received packets, transmitted packets, and RTT data.
+ """
+
+ if type(ping_results) == list:
+ ping_results = ping_results[0]
+
+ ping_data = PingTemplate(lines=ping_results.splitlines())
+ obj = list(ping_data.parse().values())
+
+ self.result["packet_loss"] = obj[0].get("loss_percentage")
+ self.result["packets_rx"] = obj[0].get("rx")
+ self.result["packets_tx"] = obj[0].get("tx")
+ self.result["rtt"] = obj[0].get("rtt")
+ loss = obj[0].get("loss")
+ self.validate_results(self.module, loss, self.result)
+ return self.result
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/prefix_lists/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/prefix_lists/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/prefix_lists/__init__.py
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
new file mode 100644
index 000000000..7c4ebe5ec
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/prefix_lists/prefix_lists.py
@@ -0,0 +1,250 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2021 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 cisco.ios_prefix_lists 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.prefix_lists import (
+ Prefix_listsTemplate,
+)
+
+
+class Prefix_lists(ResourceModule):
+ """
+ The cisco.ios_prefix_lists config class
+ """
+
+ def __init__(self, module):
+ super(Prefix_lists, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="prefix_lists",
+ tmplt=Prefix_listsTemplate(),
+ )
+ self.parsers = ["prefix_list"]
+
+ 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["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)
+
+ # 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":
+ 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))
+
+ # 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))
+
+ 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
+ populates the list of commands to be run by comparing
+ 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(),
+ )
+
+ 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,
+ },
+ },
+ )
+ val["prefix_lists"] = temp_prefix_list
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/route_maps/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/route_maps/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/route_maps/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/route_maps/route_maps.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/route_maps/route_maps.py
new file mode 100644
index 000000000..d8a1bec9f
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/route_maps/route_maps.py
@@ -0,0 +1,369 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2021 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 cisco.ios_route_maps 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.route_maps import (
+ Route_mapsTemplate,
+)
+
+
+class Route_maps(ResourceModule):
+ """
+ The cisco.ios_route_maps config class
+ """
+
+ parsers = ["continue_entry", "description"]
+
+ def __init__(self, module):
+ super(Route_maps, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="route_maps",
+ tmplt=Route_mapsTemplate(),
+ )
+
+ 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.
+ """
+
+ if self.want:
+ wantd = {(entry["route_map"]): entry for entry in self.want}
+ else:
+ wantd = {}
+
+ if self.have:
+ haved = {(entry["route_map"]): entry for entry in self.have}
+ else:
+ haved = {}
+
+ # Convert each of config list to dict
+ for each in wantd, haved:
+ self.list_to_dict(each)
+
+ # 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:
+ route_map_cmd = "no route-map {route_map}".format(**have)
+ self.commands.append(route_map_cmd)
+
+ 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 Route_maps network resource.
+ """
+ if want != have and self.state != "deleted":
+ self.entries_compare(want, have)
+
+ def entries_compare(self, want, have):
+ if want.get("entries"):
+ cmd_len = len(self.commands)
+ if have.get("entries"):
+ for k, v in iteritems(want["entries"]):
+ have_entry = have["entries"].pop(k, {})
+ if want["entries"][k] != have_entry:
+ # description gets merged with existing description, so explicit delete is required
+ # replaced and overridden state
+ if (
+ (self.state == "replaced" or self.state == "overridden")
+ and have_entry.get("description")
+ and have_entry.get("description")
+ != want["entries"][k].get("description")
+ ):
+ self.compare(parsers=["description"], want=dict(), have=have_entry)
+ self.compare(parsers=self.parsers, want=want["entries"][k], have=have_entry)
+ have_match = have_entry.get("match")
+ want_match = v.get("match")
+ if have_match and want_match:
+ self.list_type_compare("match", want=want_match, have=have_match)
+ elif not have_match and want_match:
+ self.list_type_compare("match", want=want_match, have=dict())
+ have_set = have_entry.get("set")
+ want_set = v.get("set")
+
+ if have_set and want_set:
+ self.list_type_compare("set", want=want_set, have=have_set)
+ elif not have_set and want_set:
+ self.list_type_compare("set", want=want_set, have=dict())
+
+ if cmd_len != len(self.commands):
+ route_map_cmd = "route-map {route_map}".format(**want)
+ if want["entries"][k].get("action"):
+ route_map_cmd += " {action}".format(**want["entries"][k])
+ if want["entries"][k].get("sequence"):
+ route_map_cmd += " {sequence}".format(**want["entries"][k])
+ self.commands.insert(cmd_len, route_map_cmd)
+ cmd_len = len(self.commands)
+ else:
+ for k, v in iteritems(want["entries"]):
+ self.compare(parsers=self.parsers, want=want["entries"][k], have=dict())
+ want_match = v.get("match")
+ if want_match:
+ self.list_type_compare("match", want=want_match, have=dict())
+ want_set = v.get("set")
+ if want_set:
+ self.list_type_compare("set", want=want_set, have=dict())
+ if cmd_len != len(self.commands):
+ route_map_cmd = "route-map {route_map}".format(**want)
+ if want["entries"][k].get("action"):
+ route_map_cmd += " {action}".format(**want["entries"][k])
+ if want["entries"][k].get("sequence"):
+ route_map_cmd += " {sequence}".format(**want["entries"][k])
+ self.commands.insert(cmd_len, route_map_cmd)
+ cmd_len = len(self.commands)
+
+ if (self.state == "replaced" or self.state == "overridden") and have.get("entries"):
+ cmd_len = len(self.commands)
+ for k, v in iteritems(have["entries"]):
+ route_map_cmd = "no route-map {route_map}".format(**have)
+ if have["entries"][k].get("action"):
+ route_map_cmd += " {action}".format(**have["entries"][k])
+ if have["entries"][k].get("sequence"):
+ route_map_cmd += " {sequence}".format(**have["entries"][k])
+ self.commands.insert(cmd_len, route_map_cmd)
+
+ def list_type_compare(self, compare_type, want, have):
+ parsers = [
+ "{0}".format(compare_type),
+ "{0}.ip".format(compare_type),
+ "{0}.ipv6".format(compare_type),
+ ]
+ for k, v in iteritems(want):
+ have_v = have.pop(k, {})
+ if v != have_v and k not in ["ip", "ipv6", "action", "sequence", "community"]:
+ if have_v:
+ self.compare(
+ parsers=parsers,
+ want={compare_type: {k: v}},
+ have={compare_type: {k: have_v}},
+ )
+ else:
+ self.compare(parsers=parsers, want={compare_type: {k: v}}, have=dict())
+
+ if k in ["community"]:
+ if have_v:
+ if have_v != v:
+ if self.state == "overridden" or self.state == "replaced":
+ self.compare(parsers=parsers, want={}, have={compare_type: {k: have_v}})
+ elif self.state == "merged":
+ for _key, _val in have_v.items():
+ if isinstance(_val, list):
+ v[_key].extend(_val)
+ v[_key] = list(set(v[_key]))
+ v[_key].sort()
+
+ self.compare(
+ parsers=parsers,
+ want={compare_type: {k: v}},
+ have={compare_type: {k: have_v}},
+ )
+ else:
+ self.compare(parsers=parsers, want={compare_type: {k: v}}, have=dict())
+
+ if k in ["ip", "ipv6"]:
+ for key, val in iteritems(v):
+ have_val = have_v.pop(key, {})
+ if val != have_val:
+ if have_val:
+ if self.state == "overridden" or self.state == "replaced":
+ self.compare(
+ parsers=parsers,
+ want=dict(),
+ have={compare_type: {k: {key: have_val}}},
+ )
+ self.compare(
+ parsers=parsers,
+ want={compare_type: {k: {key: val}}},
+ have={compare_type: {k: {key: have_val}}},
+ )
+ else:
+ self.compare(
+ parsers=parsers,
+ want={compare_type: {k: {key: val}}},
+ have=dict(),
+ )
+ if (self.state == "overridden" or self.state == "replaced") and have_v:
+ for key, val in iteritems(have_v):
+ self.compare(
+ parsers=parsers,
+ want=dict(),
+ have={compare_type: {k: {key: val}}},
+ )
+
+ if have and (self.state == "replaced" or self.state == "overridden"):
+ for k, v in iteritems(have):
+ if k in ["ip", "ipv6"]:
+ for key, val in iteritems(v):
+ if key and val:
+ self.compare(
+ parsers=parsers,
+ want=dict(),
+ have={compare_type: {k: {key: val}}},
+ )
+ else:
+ self.compare(parsers=parsers, want=dict(), have={compare_type: {k: v}})
+
+ def list_to_dict(self, param):
+ if param:
+
+ def convert_to_dict(inner_match, key):
+ temp = dict()
+ for each in inner_match:
+ temp.update({key + "_" + str(each): each})
+ return dict(sorted(temp.items(), key=lambda x: x[1]))
+
+ for key, val in iteritems(param):
+ temp_entries = dict()
+ if val.get("entries"):
+ for every in val["entries"]:
+ match = every.get("match")
+ if match:
+ if match.get("as_path") and match.get("as_path").get("acls"):
+ match["as_path"]["acls"] = convert_to_dict(
+ match["as_path"]["acls"],
+ "acl",
+ )
+ if match.get("community") and match.get("community").get("name"):
+ match["community"]["name"] = convert_to_dict(
+ match["community"]["name"],
+ "name",
+ )
+ if match.get("extcommunity"):
+ match["extcommunity"] = convert_to_dict(
+ match["extcommunity"],
+ "num",
+ )
+ if match.get("interfaces"):
+ match["interfaces"] = convert_to_dict(
+ match["interfaces"],
+ "interface",
+ )
+ if match.get("ip"):
+ for each_ip_param in [
+ "address",
+ "flowspec",
+ "next_hop",
+ "redistribution_source",
+ "route_source",
+ ]:
+ if match["ip"].get(each_ip_param):
+ if match["ip"][each_ip_param].get("acls"):
+ match["ip"][each_ip_param]["acls"] = convert_to_dict(
+ match["ip"][each_ip_param]["acls"],
+ "acl",
+ )
+ elif match["ip"][each_ip_param].get("prefix_lists"):
+ match["ip"][each_ip_param][
+ "prefix_lists"
+ ] = convert_to_dict(
+ match["ip"][each_ip_param]["prefix_lists"],
+ "prefix_list",
+ )
+ if match.get("local_preference") and match.get("local_preference").get(
+ "value",
+ ):
+ match["local_preference"]["value"] = convert_to_dict(
+ match["local_preference"]["value"],
+ "value",
+ )
+ if match.get("mdt_group") and match.get("mdt_group").get("acls"):
+ match["mdt_group"]["acls"] = convert_to_dict(
+ match["mdt_group"]["acls"],
+ "acl",
+ )
+ if match.get("policy_lists"):
+ match["policy_lists"] = convert_to_dict(
+ match["policy_lists"],
+ "policy",
+ )
+ if match.get("security_group"):
+ for each_sg_param in ["source", "destination"]:
+ if match.get("security_group").get(each_sg_param):
+ match["security_group"][each_sg_param] = convert_to_dict(
+ match["security_group"][each_sg_param],
+ each_sg_param,
+ )
+ set = every.get("set")
+ if set:
+ if set.get("interfaces"):
+ set["interfaces"] = convert_to_dict(set["interfaces"], "interface")
+ if set.get("as_path"):
+ _k = set.get("as_path").get("prepend")
+ if _k:
+ if _k.get("as_number"):
+ _k["as_number"] = " ".join(_k["as_number"])
+
+ if set.get("community"):
+ _k = set.get("community")
+ if _k and _k.get("number"):
+ # asplain helper func
+ def to_asplain(new_format):
+ _int, _remainder = (int(i) for i in new_format.split(":"))
+ return str(_int * 65536 + _remainder)
+
+ # convert to asplain for correct sorting
+ if ":" in _k["number"]:
+ _k["number"] = list(
+ map(to_asplain, _k["number"].split(" ")),
+ )
+ else:
+ _k["number"] = _k["number"].split(" ")
+
+ # sort the list to ensure idempotency
+ _k["number"].sort()
+
+ action = every.get("action")
+ sequence = every.get("sequence")
+ temp_entries.update({action + "_" + str(sequence): every})
+ val["entries"] = temp_entries
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/service/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/service/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/service/__init__.py
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
new file mode 100644
index 000000000..23e3329be
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/service/service.py
@@ -0,0 +1,152 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat Inc.
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios_service class
+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 __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+from copy import deepcopy
+
+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.service import (
+ ServiceTemplate,
+)
+
+
+class Service(ResourceModule):
+ """
+ The ios_service class
+ """
+
+ def __init__(self, module):
+ super(Service, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="service",
+ tmplt=ServiceTemplate(),
+ )
+ self.parsers = [
+ "call_home",
+ "compress_config",
+ "config",
+ "counters",
+ "dhcp",
+ "disable_ip_fast_frag",
+ "exec_callback",
+ "exec_wait",
+ "hide_telnet_addresses",
+ "internal",
+ "linenumber",
+ "log",
+ "log_hidden",
+ "nagle",
+ "old_slip_prompts",
+ "pad",
+ "pad_cmns",
+ "pad_from_xot",
+ "pad_to_xot",
+ "password_encryption",
+ "password_recovery",
+ "private_config_encryption",
+ "prompt",
+ "pt_vty_logging",
+ "scripting",
+ "sequence_numbers",
+ "slave_coredump",
+ "slave_log",
+ "tcp_keepalives_in",
+ "tcp_keepalives_out",
+ "telnet_zeroidle",
+ "unsupported_transceiver",
+ ]
+
+ 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._service_list_to_dict(self.want)
+ haved = self._service_list_to_dict(self.have)
+
+ service_default = {
+ "counters": 0,
+ "dhcp": True,
+ "prompt": True,
+ "slave_log": True,
+ "password_recovery": True,
+ "private_config_encryption": True,
+ }
+
+ # 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
+ elif self.state == "deleted":
+ wantd = self._service_list_to_dict(service_default)
+
+ # if state is replaced
+ elif self.state == "replaced":
+ wantd = dict_merge(self._service_list_to_dict(service_default), wantd)
+
+ 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 Service network resource.
+ """
+ self.compare(parsers=self.parsers, want=want, have=have)
+ self._compare_lists_attrs(want, have)
+
+ def _compare_lists_attrs(self, want, have):
+ """Compare list of dict"""
+ i_want = want.get("timestamps", {})
+ i_have = have.get("timestamps", {})
+ for key, wanting in iteritems(i_want):
+ haveing = i_have.pop(key, {})
+ if wanting != haveing:
+ self.addcmd(wanting, "timestamps")
+ for key, haveing in iteritems(i_have):
+ self.addcmd(haveing, "timestamps", negate=True)
+
+ def _service_list_to_dict(self, data):
+ """Convert all list of dicts to dicts of dicts"""
+ p_key = {
+ "timestamps": "msg",
+ }
+ tmp_data = deepcopy(data)
+ for k, _v in p_key.items():
+ if k in tmp_data:
+ tmp_data[k] = {str(i[p_key.get(k)]): i for i in tmp_data[k]}
+ return tmp_data
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/snmp_server/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/snmp_server/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/snmp_server/__init__.py
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
new file mode 100644
index 000000000..ff45f7b5f
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/snmp_server/snmp_server.py
@@ -0,0 +1,253 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2021 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_snmp_server 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 copy import deepcopy
+
+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.snmp_server import (
+ Snmp_serverTemplate,
+)
+
+
+class Snmp_server(ResourceModule):
+ """
+ The ios_snmp_server config class
+ """
+
+ def __init__(self, module):
+ super(Snmp_server, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="snmp_server",
+ tmplt=Snmp_serverTemplate(),
+ )
+ self.parsers = [
+ "accounting",
+ "cache",
+ "chassis_id",
+ "contact",
+ "drop",
+ "file_transfer",
+ "if_index",
+ "inform",
+ "ip",
+ "location",
+ "manager",
+ "packet_size",
+ "queue_length",
+ "trap_timeout",
+ "source_interface",
+ "trap_source",
+ "system_shutdown",
+ ]
+ self.list_parsers = [
+ "hosts",
+ "groups",
+ "engine_id",
+ "communities",
+ "context",
+ "password_policy",
+ "users",
+ "views",
+ ]
+ self.complex_parsers = [
+ "traps.auth_framework",
+ "traps.bfd",
+ "traps.bgp",
+ "traps.bridge",
+ "traps.casa",
+ "traps.cnpd",
+ "traps.config",
+ "traps.config_copy",
+ "traps.config_ctid",
+ "traps.dhcp",
+ "traps.eigrp",
+ "traps.entity",
+ "traps.energywise",
+ "traps.event_manager",
+ "traps.flowmon",
+ "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.ipsec.cryptomap.add",
+ "traps.ipsec.cryptomap.delete",
+ "traps.ipsec.cryptomap.attach",
+ "traps.ipsec.cryptomap.detach",
+ "traps.ipsec.tunnel.start",
+ "traps.ipsec.tunnel.stop",
+ "traps.ipsec.too_many_sas",
+ "traps.ospf.cisco_specific.error",
+ "traps.ospf.cisco_specific.retransmit",
+ "traps.ospf.cisco_specific.lsa",
+ "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.state_change",
+ "traps.l2tun.pseudowire_status",
+ "traps.l2tun.session",
+ "traps.cpu",
+ "traps.firewall",
+ "traps.pim",
+ "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",
+ ]
+
+ 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._snmp_list_to_dict(self.want)
+ haved = self._snmp_list_to_dict(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":
+ wantd = {}
+
+ 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 Snmp_server network resource.
+ """
+ self.compare(parsers=self.parsers, want=want, have=have)
+ self.compare(parsers=self.complex_parsers, want=want, have=have)
+ self._compare_lists_attrs(want, have)
+
+ 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)
+
+ def _snmp_list_to_dict(self, data):
+ """Convert all list of dicts to dicts of dicts"""
+ p_key = {
+ "hosts": "host",
+ "groups": "group",
+ "engine_id": "id",
+ "communities": "name",
+ "context": True,
+ "password_policy": "policy_name",
+ "file_transfer": True,
+ "users": "username",
+ "views": "name",
+ }
+ tmp_data = deepcopy(data)
+ for k, _v in p_key.items():
+ if k in tmp_data:
+ if k == "hosts":
+ tmp_host = dict()
+ for i in tmp_data[k]:
+ tmp = dict()
+ if i.get("traps"):
+ for t in i.get("traps"):
+ tmp.update({t: t})
+ i["traps"] = tmp
+ tmp_host.update(
+ {
+ str(
+ i[p_key.get(k)]
+ + i.get("version", "")
+ + i.get("community_string", ""),
+ ): i,
+ },
+ )
+ tmp_data[k] = tmp_host
+ elif k == "context":
+ tmp_data[k] = {i: {"context": i} for i in tmp_data[k]}
+ elif k == "file_transfer":
+ if tmp_data.get(k):
+ if tmp_data[k].get("protocol"):
+ tmp = dict()
+ for t in tmp_data[k].get("protocol"):
+ tmp.update({t: t})
+ 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]
+ }
+ elif k == "views":
+ tmp_data[k] = {
+ str(i[p_key.get(k)] + i.get("family_name", "")): i for i in tmp_data[k]
+ }
+ else:
+ tmp_data[k] = {str(i[p_key.get(k)]): i for i in tmp_data[k]}
+ return tmp_data
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/static_routes/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/static_routes/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/static_routes/__init__.py
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
new file mode 100644
index 000000000..79b63c8fe
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/static_routes/static_routes.py
@@ -0,0 +1,188 @@
+#
+# -*- 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_static_routes 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.static_routes import (
+ Static_routesTemplate,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ validate_n_expand_ipv4,
+)
+
+
+class Static_routes(ResourceModule):
+ """
+ The ios_static_routes config class
+ """
+
+ def __init__(self, module):
+ super(Static_routes, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="static_routes",
+ tmplt=Static_routesTemplate(),
+ )
+ self.parsers = []
+
+ 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, delete_spcl = self.list_to_dict(self.want, "want")
+ haved, n_req = self.list_to_dict(self.have, "have")
+
+ 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_")
+ for k, v in _afis.get(pk, {}).items():
+ for each_dest in to_rem:
+ if k.split("_")[0] == each_dest:
+ self.addcmd({pk: v}, pk, True)
+ else:
+ _vrfs = haved.get(pk)
+ for ak, v in _vrfs.items():
+ for k, srts in v.items():
+ for each_dest in to_rem.get(ak):
+ if k.split("_")[0] == each_dest:
+ self.addcmd({ak: srts}, ak, True)
+
+ else:
+ # if state is merged, merge want onto have and then compare
+ if self.state == "merged":
+ wantd = dict_merge(haved, wantd)
+
+ for k, want in iteritems(wantd):
+ self._compare_top_level_keys(want=want, have=haved.pop(k, {}))
+
+ # if self.state in ["overridden", "deleted"]:
+ if (self.state == "deleted" and not wantd) or self.state == "overridden":
+ for k, have in iteritems(haved):
+ self._compare_top_level_keys(want={}, have=have)
+
+ def _compare_top_level_keys(self, want, have):
+ # if state is deleted, empty out wantd and set haved to wantd
+ if self.state == "deleted" and have:
+ _have = {}
+ for addf in ["ipv4", "ipv6"]:
+ _temp_sr = {}
+ for k, ha in iteritems(have.get(addf, {})):
+ if k in want.get(addf, {}): # or not want.get(addf)
+ _temp_sr[k] = ha
+ if _temp_sr:
+ _have[addf] = _temp_sr
+ if _have:
+ have = _have
+ want = {}
+
+ if self.state != "deleted":
+ for _afi, routes in want.items():
+ self._compare(s_want=routes, s_have=have.pop(_afi, {}), afi=_afi)
+
+ if self.state in ["overridden", "deleted"]:
+ for _afi, routes in have.items():
+ self._compare(s_want={}, s_have=routes, afi=_afi)
+
+ def _compare(self, s_want, s_have, afi):
+ for name, w_srs in s_want.items():
+ have_srs = s_have.pop(name, {})
+ self.compare(parsers=afi, want={afi: w_srs}, have={afi: have_srs})
+
+ # remove remaining items in have for replaced state
+ for name, h_srs in s_have.items():
+ self.compare(parsers=afi, want={}, have={afi: h_srs})
+
+ def list_to_dict(self, param, operation):
+ _static_rts = {}
+ _delete_spc = {}
+ if param:
+ for srs in param:
+ _vrf = srs.get("vrf")
+ _srts = {}
+ for adfs in srs.get("address_families", []):
+ _afi = adfs.get("afi")
+ _routes = {}
+ for rts in adfs.get("routes", []):
+ _dest = rts.get("dest", "")
+ _sdest = rts.get("dest", "")
+ _topo = rts.get("topology", "")
+ # below if specific to special deletes
+ if (
+ self.state == "deleted"
+ and operation == "want"
+ and not rts.get("next_hops")
+ ):
+ if _vrf:
+ if not _delete_spc.get(_vrf):
+ _delete_spc[_vrf] = {}
+ if not _delete_spc[_vrf].get(_afi):
+ _delete_spc[_vrf][_afi] = []
+ _delete_spc[_vrf][_afi].append(_dest)
+ else:
+ if not _delete_spc.get(_afi):
+ _delete_spc[_afi] = []
+ _delete_spc[_afi].append(_dest)
+
+ for nxh in rts.get("next_hops", []):
+ _forw_rtr_add = nxh.get("forward_router_address", "").upper()
+ _intf = nxh.get("interface", "")
+ _key = _sdest + "_" + _topo + _forw_rtr_add + _intf
+
+ if _afi == "ipv4":
+ _dest = validate_n_expand_ipv4(self._module, {"address": _dest})
+ dummy_sr = {
+ "afi": _afi,
+ "dest": _dest,
+ }
+
+ if _vrf:
+ dummy_sr["vrf"] = _vrf
+ if _topo:
+ dummy_sr["topology"] = _topo
+ if _intf:
+ dummy_sr["interface"] = _intf
+ if _forw_rtr_add:
+ dummy_sr["forward_router_address"] = _forw_rtr_add
+ dummy_sr.update(nxh)
+
+ _routes[_key] = dummy_sr
+ _srts[_afi] = _routes
+ _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/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vlans/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vlans/__init__.py
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
new file mode 100644
index 000000000..9d206f509
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/config/vlans/vlans.py
@@ -0,0 +1,371 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios_vlans class
+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 it's desired end-state is
+created
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__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.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
+
+
+class Vlans(ConfigBase):
+ """
+ The ios_vlans class
+ """
+
+ gather_subset = ["!all", "!min"]
+
+ gather_network_resources = ["vlans"]
+
+ def __init__(self, module):
+ super(Vlans, self).__init__(module)
+
+ def get_vlans_facts(self, data=None):
+ """Get the 'facts' (the current configuration)
+
+ :rtype: A dictionary
+ :returns: The current configuration as a dictionary
+ """
+ facts, _warnings = Facts(self._module).get_facts(
+ self.gather_subset,
+ self.gather_network_resources,
+ data=data,
+ )
+ vlans_facts = facts["ansible_network_resources"].get("vlans")
+ if not vlans_facts:
+ return []
+ return vlans_facts
+
+ def execute_module(self):
+ """Execute the module
+
+ :rtype: A dictionary
+ :returns: The result from module execution
+ """
+ result = {"changed": False}
+ commands = list()
+ warnings = list()
+
+ if self.state in self.ACTION_STATES:
+ existing_vlans_facts = self.get_vlans_facts()
+ else:
+ existing_vlans_facts = []
+
+ if self.state in self.ACTION_STATES or self.state == "rendered":
+ commands.extend(self.set_config(existing_vlans_facts))
+ if commands and self.state in self.ACTION_STATES:
+ if not self._module.check_mode:
+ self._connection.edit_config(commands)
+ result["changed"] = True
+ if self.state in self.ACTION_STATES:
+ result["commands"] = commands
+
+ if self.state in self.ACTION_STATES or self.state == "gathered":
+ changed_vlans_facts = self.get_vlans_facts()
+ elif self.state == "rendered":
+ result["rendered"] = commands
+ elif self.state == "parsed":
+ running_config = self._module.params["running_config"]
+ if not running_config:
+ self._module.fail_json(
+ msg="value of running_config parameter must not be empty for state parsed",
+ )
+ result["parsed"] = self.get_vlans_facts(data=running_config)
+ else:
+ changed_vlans_facts = []
+
+ if self.state in self.ACTION_STATES:
+ result["before"] = existing_vlans_facts
+ if result["changed"]:
+ result["after"] = changed_vlans_facts
+ elif self.state == "gathered":
+ result["gathered"] = changed_vlans_facts
+
+ result["warnings"] = warnings
+ return result
+
+ def set_config(self, existing_vlans_facts):
+ """Collect the configuration from the args passed to the module,
+ collect the current configuration (as a dict from facts)
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ want = self._module.params["config"]
+ have = existing_vlans_facts
+ resp = self.set_state(want, have)
+ return to_list(resp)
+
+ def set_state(self, want, have):
+ """Select the appropriate function based on the state provided
+
+ :param want: the desired configuration as a dictionary
+ :param have: the current configuration as a dictionary
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+
+ if self.state in ("overridden", "merged", "replaced", "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":
+ commands = self._state_replaced(want, have)
+ return commands
+
+ def _state_replaced(self, want, have):
+ """The command generator when state is replaced
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ commands = []
+
+ check = False
+ for each in want:
+ for every in have:
+ if every["vlan_id"] == each["vlan_id"]:
+ check = True
+ break
+ continue
+ if check:
+ commands.extend(self._set_config(each, every))
+ else:
+ commands.extend(self._set_config(each, dict()))
+
+ return commands
+
+ def _state_overridden(self, want, have):
+ """The command generator when state is overridden
+
+ :rtype: A list
+ :returns: the commands necessary to migrate the current configuration
+ to the desired configuration
+ """
+ commands = []
+
+ want_local = want
+ for each in have:
+ count = 0
+ for every in want_local:
+ if each["vlan_id"] == every["vlan_id"]:
+ break
+ count += 1
+ else:
+ # We didn't find a matching desired state, which means we can
+ # pretend we received an empty desired state.
+ commands.extend(self._clear_config(every, each))
+ continue
+ commands.extend(self._set_config(every, each))
+ # as the pre-existing VLAN are now configured by
+ # above set_config call, deleting the respective
+ # VLAN entry from the want_local list
+ del want_local[count]
+
+ # Iterating through want_local list which now only have new VLANs to be
+ # configured
+ for each in want_local:
+ commands.extend(self._set_config(each, dict()))
+
+ return commands
+
+ def _state_merged(self, want, have):
+ """The command generator when state is merged
+
+ :rtype: A list
+ :returns: the commands necessary to merge the provided into
+ the current configuration
+ """
+ commands = []
+
+ check = False
+ for each in want:
+ for every in have:
+ if each.get("vlan_id") == every.get("vlan_id"):
+ check = True
+ break
+ continue
+ if check:
+ commands.extend(self._set_config(each, every))
+ else:
+ commands.extend(self._set_config(each, dict()))
+
+ return commands
+
+ def _state_deleted(self, want, have):
+ """The command generator when state is deleted
+
+ :rtype: A list
+ :returns: the commands necessary to remove the current configuration
+ of the provided objects
+ """
+ commands = []
+
+ if want:
+ check = False
+ for each in want:
+ for every in have:
+ if each.get("vlan_id") == every.get("vlan_id"):
+ check = True
+ break
+ check = False
+ continue
+ if check:
+ commands.extend(self._clear_config(each, every))
+ else:
+ for each in have:
+ commands.extend(self._clear_config(dict(), each))
+
+ return commands
+
+ def remove_command_from_config_list(self, vlan_id, cmd, commands):
+ if vlan_id not in commands and cmd != "vlan":
+ commands.insert(0, vlan_id)
+ elif cmd == "vlan":
+ commands.append("no %s" % vlan_id)
+ return commands
+ commands.append("no %s" % cmd)
+ return commands
+
+ def add_command_to_config_list(self, vlan_id, cmd, commands):
+ if vlan_id not in commands:
+ commands.insert(0, vlan_id)
+ if cmd not in commands:
+ commands.append(cmd)
+
+ 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"))
+
+ def negate_have_config(want_diff, have_diff, vlan, commands):
+ name = dict(have_diff).get("name")
+ if name and not dict(want_diff).get("name"):
+ self.remove_command_from_config_list(vlan, "name {0}".format(name), commands)
+ state = dict(have_diff).get("state")
+ if state and not dict(want_diff).get("state"):
+ self.remove_command_from_config_list(vlan, "state {0}".format(state), commands)
+ shutdown = dict(have_diff).get("shutdown")
+ if shutdown and not dict(want_diff).get("shutdown"):
+ self.remove_command_from_config_list(vlan, "shutdown", commands)
+ mtu = dict(have_diff).get("mtu")
+ if mtu and not dict(want_diff).get("mtu"):
+ self.remove_command_from_config_list(vlan, "mtu {0}".format(mtu), commands)
+ remote_span = dict(have_diff).get("remote_span")
+ if remote_span and not dict(want_diff).get("remote_span"):
+ self.remove_command_from_config_list(vlan, "remote-span", commands)
+ private_vlan = dict(have_diff).get("private_vlan")
+ if private_vlan and not dict(want_diff).get("private_vlan"):
+ private_vlan_type = dict(private_vlan).get("type")
+ self.remove_command_from_config_list(
+ vlan,
+ "private-vlan {0}".format(private_vlan_type),
+ commands,
+ )
+ if private_vlan_type == "primary" and dict(private_vlan).get("associated"):
+ 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)
+ diff = want_dict - have_dict
+ have_diff = have_dict - want_dict
+
+ if diff:
+ 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 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)
+ 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"))
+
+ if (
+ have.get("vlan_id")
+ 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)
+
+ return commands
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acl_interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acl_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acl_interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acl_interfaces/acl_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acl_interfaces/acl_interfaces.py
new file mode 100644
index 000000000..a3bf09957
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acl_interfaces/acl_interfaces.py
@@ -0,0 +1,69 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios_acl_interfaces 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 __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.acl_interfaces.acl_interfaces import (
+ Acl_interfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.acl_interfaces import (
+ Acl_interfacesTemplate,
+)
+
+
+class Acl_interfacesFacts(object):
+ """The ios_acl_interfaces fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Acl_interfacesArgs.argument_spec
+
+ def get_acl_interfaces_data(self, connection):
+ return connection.get(
+ "show running-config | include ^interface|ip access-group|ipv6 traffic-filter",
+ )
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for interfaces
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+ :rtype: dictionary
+ :returns: facts
+ """
+ if not data:
+ data = self.get_acl_interfaces_data(connection)
+
+ config_parser = Acl_interfacesTemplate(lines=data.splitlines())
+ entry = sorted(list(config_parser.parse().values()), key=lambda k, sk="name": k[sk])
+ if entry:
+ for item in entry:
+ item["access_groups"] = sorted(
+ list(item["access_groups"].values()),
+ key=lambda k, sk="afi": k[sk],
+ )
+
+ ansible_facts["ansible_network_resources"].pop("acl_interfaces", None)
+ facts = {"acl_interfaces": []}
+ for cfg in entry:
+ utils.remove_empties(cfg)
+ if cfg.get("access_groups"):
+ facts["acl_interfaces"].append(cfg)
+ utils.validate_config(self.argument_spec, {"config": facts.get("acl_interfaces")})
+
+ ansible_facts["ansible_network_resources"].update(facts)
+ return ansible_facts
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acls/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acls/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acls/__init__.py
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
new file mode 100644
index 000000000..6037d99e1
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/acls/acls.py
@@ -0,0 +1,168 @@
+# pylint: skip-file
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios_acls 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 __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+import re
+
+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 (
+ NetworkTemplate,
+)
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.acls.acls import (
+ AclsArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.acls import (
+ AclsTemplate,
+)
+
+
+class AclsFacts(object):
+ """The ios_acls fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ 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
+
+ def sanitize_data(self, data):
+ """removes matches or extra config info that is added on acl match"""
+ re_data = ""
+ for da in data.split("\n"):
+ if "match" in da:
+ mod_da = re.sub(r"\([^()]*\)", "", da)
+ re_data += mod_da[:-1] + "\n"
+ else:
+ re_data += da + "\n"
+ return re_data
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for acls
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+ :rtype: dictionary
+ :returns: facts
+ """
+
+ if not data:
+ data = self.get_acl_data(connection)
+
+ if data:
+ data = self.sanitize_data(data)
+
+ rmmod = NetworkTemplate(lines=data.splitlines(), tmplt=AclsTemplate())
+ current = rmmod.parse()
+
+ temp_v4 = []
+ temp_v6 = []
+
+ if current.get("acls"):
+ for k, v in iteritems(current.get("acls")):
+ if v.get("afi") == "ipv4" and v.get("acl_type") in ["standard", "extended"]:
+ del v["afi"]
+ temp_v4.append(v)
+ elif v.get("afi") == "ipv6":
+ del v["afi"]
+ temp_v6.append(v)
+
+ temp_v4 = sorted(temp_v4, key=lambda i: str(i["name"]))
+ temp_v6 = sorted(temp_v6, key=lambda i: str(i["name"]))
+
+ def factor_source_dest(ace, typ):
+ temp = ace.get(typ, {})
+ if temp.get("address"):
+ _temp_addr = temp.get("address", "")
+ ace[typ]["address"] = _temp_addr.split(" ")[0]
+ ace[typ]["wildcard_bits"] = _temp_addr.split(" ")[1]
+
+ def process_protocol_options(each):
+ for each_ace in each.get("aces"):
+ if each.get("acl_type") == "standard":
+ if len(each_ace.get("source", {})) == 1 and each_ace.get("source", {}).get(
+ "address",
+ ):
+ each_ace["source"]["host"] = each_ace["source"].pop("address")
+ if each_ace.get("source", {}).get("address"):
+ addr = each_ace.get("source", {}).get("address")
+ if addr[-1] == ",":
+ each_ace["source"]["address"] = addr[:-1]
+ else: # for extended acl
+ if each_ace.get("source", {}):
+ factor_source_dest(each_ace, "source")
+ if each_ace.get("destination", {}):
+ factor_source_dest(each_ace, "destination")
+
+ if each_ace.get("icmp_igmp_tcp_protocol"):
+ each_ace["protocol_options"] = {
+ each_ace["protocol"]: {
+ each_ace.pop("icmp_igmp_tcp_protocol").replace("-", "_"): True,
+ },
+ }
+ if each_ace.get("protocol_number"):
+ each_ace["protocol_options"] = {
+ "protocol_number": each_ace.pop("protocol_number"),
+ }
+
+ def collect_remarks(aces):
+ """makes remarks list per ace"""
+ ace_entry = []
+ rem = []
+ for i in aces:
+ if i.get("remarks"):
+ rem.append(i.pop("remarks"))
+ else:
+ ace_entry.append(i)
+ if rem:
+ ace_entry.append({"remarks": rem})
+ return ace_entry
+
+ for each in temp_v4:
+ if each.get("aces"):
+ each["aces"] = collect_remarks(each.get("aces"))
+ process_protocol_options(each)
+
+ for each in temp_v6:
+ if each.get("aces"):
+ each["aces"] = collect_remarks(each.get("aces"))
+ process_protocol_options(each)
+
+ objs = []
+ if temp_v4:
+ objs.append({"afi": "ipv4", "acls": temp_v4})
+ if temp_v6:
+ objs.append({"afi": "ipv6", "acls": temp_v6})
+
+ facts = {}
+ if objs:
+ facts["acls"] = []
+ params = utils.validate_config(self.argument_spec, {"config": objs})
+ for cfg in params["config"]:
+ facts["acls"].append(utils.remove_empties(cfg))
+ ansible_facts["ansible_network_resources"].update(facts)
+
+ return ansible_facts
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_address_family/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_address_family/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_address_family/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_address_family/bgp_address_family.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_address_family/bgp_address_family.py
new file mode 100644
index 000000000..29631eec1
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_address_family/bgp_address_family.py
@@ -0,0 +1,91 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 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 cisco.ios bgp_address_family 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.bgp_address_family.bgp_address_family import (
+ Bgp_address_familyArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.bgp_address_family import (
+ Bgp_address_familyTemplate,
+)
+
+
+class Bgp_address_familyFacts(object):
+ """The cisco.ios_bgp_address_family facts class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Bgp_address_familyArgs.argument_spec
+
+ def get_bgp_address_family_data(self, connection):
+ return connection.get("show running-config | section ^router bgp")
+
+ def _process_facts(self, objs):
+ """makes data as per the facts after data obtained from parsers"""
+ addr_fam_facts = {}
+ temp_af = []
+
+ addr_fam_facts["as_number"] = objs["as_number"]
+ if objs.get("address_family"):
+ for kaf, afs in (objs["address_family"]).items(): # remove unique value from add_fam
+ af = {}
+ for af_key, afs_val in afs.items():
+ if af_key == "neighbors":
+ temp_neighbor = []
+ for tag, neighbor in afs_val.items(): # remove unique value from neighbor
+ if not neighbor.get("neighbor_address"):
+ neighbor["neighbor_address"] = tag
+ temp_neighbor.append(neighbor)
+ af[af_key] = temp_neighbor
+ else:
+ af[af_key] = afs_val
+ temp_af.append(af)
+
+ if temp_af:
+ addr_fam_facts["address_family"] = temp_af
+ return addr_fam_facts
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for Bgp_address_family 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_bgp_address_family_data(connection)
+
+ # parse native config using the Bgp_address_family template
+ bgp_af_parser = Bgp_address_familyTemplate(lines=data.splitlines(), module=self._module)
+ objs = bgp_af_parser.parse()
+ if objs:
+ objs = self._process_facts(utils.remove_empties(objs))
+ ansible_facts["ansible_network_resources"].pop("bgp_address_family", None)
+ params = utils.remove_empties(
+ bgp_af_parser.validate_config(self.argument_spec, {"config": objs}, redact=True),
+ )
+ facts["bgp_address_family"] = 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/bgp_global/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_global/__init__.py
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
new file mode 100644
index 000000000..68ff93636
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/bgp_global/bgp_global.py
@@ -0,0 +1,73 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 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 cisco.ios bgp_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.bgp_global.bgp_global import (
+ Bgp_globalArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.bgp_global import (
+ Bgp_globalTemplate,
+)
+
+
+class Bgp_globalFacts(object):
+ """The cisco.ios bgp_global facts class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Bgp_globalArgs.argument_spec
+
+ def get_bgp_global_data(self, connection):
+ return connection.get("show running-config | section ^router bgp")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for Bgp_global network resource
+
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+
+ :rtype: dictionary
+ :returns: facts
+ """
+ facts = {}
+
+ if not data:
+ 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)
+ objs = bgp_global_parser.parse()
+ neighbor_list = objs.get("neighbors", {})
+ if neighbor_list:
+ objs["neighbors"] = sorted(
+ list(neighbor_list.values()),
+ key=lambda k, pk="neighbor_address": k[pk],
+ )
+
+ obj = utils.remove_empties(objs)
+
+ 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),
+ )
+
+ facts["bgp_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
new file mode 100644
index 000000000..6a28043bf
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/facts.py
@@ -0,0 +1,151 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The facts class for ios
+this file validates each subset of facts and selectively
+calls the appropriate facts gathering function
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts import (
+ FactsBase,
+)
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.acl_interfaces.acl_interfaces import (
+ Acl_interfacesFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.acls.acls import AclsFacts
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.bgp_address_family.bgp_address_family import (
+ Bgp_address_familyFacts,
+)
+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.hostname.hostname import (
+ HostnameFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.interfaces.interfaces import (
+ InterfacesFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.l2_interfaces.l2_interfaces import (
+ L2_interfacesFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.l3_interfaces.l3_interfaces import (
+ L3_InterfacesFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.lacp.lacp import LacpFacts
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.lacp_interfaces.lacp_interfaces import (
+ Lacp_InterfacesFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.lag_interfaces.lag_interfaces import (
+ Lag_interfacesFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.legacy.base import (
+ Config,
+ Default,
+ Hardware,
+ Interfaces,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.lldp_global.lldp_global import (
+ Lldp_globalFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.lldp_interfaces.lldp_interfaces import (
+ Lldp_InterfacesFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.logging_global.logging_global import (
+ Logging_globalFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.ntp_global.ntp_global import (
+ Ntp_globalFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.ospf_interfaces.ospf_interfaces import (
+ Ospf_interfacesFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.ospfv2.ospfv2 import (
+ Ospfv2Facts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.ospfv3.ospfv3 import (
+ Ospfv3Facts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.prefix_lists.prefix_lists import (
+ Prefix_listsFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.route_maps.route_maps import (
+ Route_mapsFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.service.service import (
+ ServiceFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.snmp_server.snmp_server import (
+ Snmp_serverFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.static_routes.static_routes import (
+ Static_routesFacts,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.vlans.vlans import (
+ VlansFacts,
+)
+
+
+FACT_LEGACY_SUBSETS = dict(default=Default, hardware=Hardware, interfaces=Interfaces, config=Config)
+
+FACT_RESOURCE_SUBSETS = dict(
+ interfaces=InterfacesFacts,
+ l2_interfaces=L2_interfacesFacts,
+ vlans=VlansFacts,
+ lag_interfaces=Lag_interfacesFacts,
+ lacp=LacpFacts,
+ lacp_interfaces=Lacp_InterfacesFacts,
+ lldp_global=Lldp_globalFacts,
+ lldp_interfaces=Lldp_InterfacesFacts,
+ l3_interfaces=L3_InterfacesFacts,
+ acl_interfaces=Acl_interfacesFacts,
+ static_routes=Static_routesFacts,
+ acls=AclsFacts,
+ ospfv2=Ospfv2Facts,
+ ospfv3=Ospfv3Facts,
+ ospf_interfaces=Ospf_interfacesFacts,
+ bgp_global=Bgp_globalFacts,
+ bgp_address_family=Bgp_address_familyFacts,
+ logging_global=Logging_globalFacts,
+ route_maps=Route_mapsFacts,
+ prefix_lists=Prefix_listsFacts,
+ ntp_global=Ntp_globalFacts,
+ service=ServiceFacts,
+ snmp_server=Snmp_serverFacts,
+ hostname=HostnameFacts,
+)
+
+
+class Facts(FactsBase):
+ """The fact class for ios"""
+
+ VALID_LEGACY_GATHER_SUBSETS = frozenset(FACT_LEGACY_SUBSETS.keys())
+ VALID_RESOURCE_SUBSETS = frozenset(FACT_RESOURCE_SUBSETS.keys())
+
+ def __init__(self, module):
+ super(Facts, self).__init__(module)
+
+ def get_facts(self, legacy_facts_type=None, resource_facts_type=None, data=None):
+ """Collect the facts for ios
+ :param legacy_facts_type: List of legacy facts types
+ :param resource_facts_type: List of resource fact types
+ :param data: previously collected conf
+ :rtype: dict
+ :return: the facts gathered
+ """
+ if self.VALID_RESOURCE_SUBSETS:
+ self.get_network_resources_facts(FACT_RESOURCE_SUBSETS, resource_facts_type, data)
+
+ if self.VALID_LEGACY_GATHER_SUBSETS:
+ self.get_network_legacy_facts(FACT_LEGACY_SUBSETS, legacy_facts_type)
+
+ return self.ansible_facts, self._warnings
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/hostname/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/hostname/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/hostname/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/hostname/hostname.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/hostname/hostname.py
new file mode 100644
index 000000000..20fa1e20f
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/hostname/hostname.py
@@ -0,0 +1,67 @@
+# -*- coding: utf-8 -*-
+# Copyright 2022 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 hostname 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.hostname.hostname import (
+ HostnameArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.hostname import (
+ HostnameTemplate,
+)
+
+
+class HostnameFacts(object):
+ """The ios hostname facts class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = HostnameArgs.argument_spec
+
+ def get_hostname_data(self, connection):
+ return connection.get("show running-config | section ^hostname")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for Hostname 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_hostname_data(connection)
+
+ # parse native config using the Hostname template
+ hostname_parser = HostnameTemplate(lines=data.splitlines(), module=self._module)
+ objs = hostname_parser.parse()
+
+ ansible_facts["ansible_network_resources"].pop("hostname", None)
+
+ params = utils.remove_empties(
+ hostname_parser.validate_config(self.argument_spec, {"config": objs}, redact=True),
+ )
+
+ facts["hostname"] = 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/interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/interfaces/interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/interfaces/interfaces.py
new file mode 100644
index 000000000..8c7e562b7
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/interfaces/interfaces.py
@@ -0,0 +1,65 @@
+# -*- coding: utf-8 -*-
+# Copyright 2022 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 interfaces 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.interfaces.interfaces import (
+ InterfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.interfaces import (
+ InterfacesTemplate,
+)
+
+
+class InterfacesFacts(object):
+ """The ios interfaces facts class"""
+
+ def __init__(self, module):
+ self._module = module
+ self.argument_spec = InterfacesArgs.argument_spec
+
+ def get_interfaces_data(self, connection):
+ return connection.get("show running-config | section ^interface")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for Interfaces network resource
+
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+
+ :rtype: dictionary
+ :returns: facts
+ """
+ if not data:
+ data = self.get_interfaces_data(connection)
+
+ # parse native config using the Interfaces template
+ interfaces_parser = InterfacesTemplate(lines=data.splitlines(), module=self._module)
+ objs = sorted(list(interfaces_parser.parse().values()), key=lambda k, sk="name": k[sk])
+
+ ansible_facts["ansible_network_resources"].pop("interfaces", None)
+ facts = {"interfaces": []}
+ params = utils.remove_empties(
+ interfaces_parser.validate_config(self.argument_spec, {"config": objs}, redact=True),
+ )
+
+ facts["interfaces"] = 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/l2_interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l2_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l2_interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l2_interfaces/l2_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l2_interfaces/l2_interfaces.py
new file mode 100644
index 000000000..b1e6e0659
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l2_interfaces/l2_interfaces.py
@@ -0,0 +1,103 @@
+# -*- coding: utf-8 -*-
+# Copyright 2022 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 l2_interfaces 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.l2_interfaces.l2_interfaces import (
+ L2_interfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.l2_interfaces import (
+ L2_interfacesTemplate,
+)
+
+
+class L2_interfacesFacts(object):
+ """The ios l2_interfaces facts class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = L2_interfacesArgs.argument_spec
+
+ def get_l2_interfaces_data(self, connection):
+ return connection.get("show running-config | section ^interface")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for L2_interfaces 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_l2_interfaces_data(connection)
+
+ # parse native config using the L2_interfaces template
+ l2_interfaces_parser = L2_interfacesTemplate(lines=data.splitlines(), module=self._module)
+ objs = list(l2_interfaces_parser.parse().values())
+
+ def process_mode(obj):
+ mode = ""
+ if obj == "dot1q-tunnel":
+ mode = "dot1q_tunnel"
+ elif obj == "dynamic auto":
+ mode = "dynamic_auto"
+ elif obj == "dynamic desirable":
+ mode = "dynamic_desirable"
+ elif obj == "private-vlan host":
+ mode = "private_vlan_host"
+ elif obj == "private-vlan promiscuous":
+ mode = "private_vlan_promiscuous"
+ elif obj == "private-vlan trunk secondary":
+ mode = "private_vlan_trunk"
+ return mode
+
+ def process_vlans(obj, vlan_type):
+ vlans = []
+ _vlans = obj.get("trunk")
+ if _vlans.get(vlan_type):
+ vlans.extend(_vlans.get(vlan_type))
+ if _vlans.get(vlan_type + "_add"):
+ for vlan_grp in _vlans.get(vlan_type + "_add"):
+ vlans.extend(vlan_grp)
+ del _vlans[vlan_type + "_add"]
+ return vlans
+
+ if objs:
+ for obj in objs:
+ if obj.get("mode") and obj.get("mode") not in ["trunk", "access", "dynamic"]:
+ obj["mode"] = process_mode(obj.get("mode"))
+ if obj.get("trunk"):
+ for _vlan in ["allowed_vlans", "pruning_vlans"]:
+ if obj.get("trunk", {}).get(_vlan):
+ obj["trunk"][_vlan] = process_vlans(obj, _vlan)
+
+ ansible_facts["ansible_network_resources"].pop("l2_interfaces", None)
+
+ params = utils.remove_empties(
+ l2_interfaces_parser.validate_config(self.argument_spec, {"config": objs}, redact=True),
+ )
+
+ facts["l2_interfaces"] = 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/l3_interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l3_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l3_interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l3_interfaces/l3_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l3_interfaces/l3_interfaces.py
new file mode 100644
index 000000000..bea49159b
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/l3_interfaces/l3_interfaces.py
@@ -0,0 +1,83 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios_l3_interfaces 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 __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+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.l3_interfaces.l3_interfaces import (
+ L3_interfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.l3_interfaces import (
+ L3_interfacesTemplate,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ netmask_to_cidr,
+)
+
+
+class L3_InterfacesFacts(object):
+ """The ios l3 interfaces fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = L3_interfacesArgs.argument_spec
+
+ def get_l3_interfaces_data(self, connection):
+ return connection.get("show running-config | section ^interface")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for l3 interfaces
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+ :rtype: dictionary
+ :returns: facts
+ """
+ objs = []
+
+ if not data:
+ data = self.get_l3_interfaces_data(connection)
+
+ # parse native config using the l3_interfaces template
+ l3_interfaces_parser = L3_interfacesTemplate(lines=data.splitlines())
+ objs = l3_interfaces_parser.parse()
+
+ objs = utils.remove_empties(objs)
+ temp = []
+ for k, v in iteritems(objs):
+ if v.get("ipv4"):
+ for each in v["ipv4"]:
+ if each.get("netmask"):
+ cidr_val = netmask_to_cidr(each["netmask"])
+ each["address"] = each["address"].strip(" ") + "/" + cidr_val
+ del each["netmask"]
+ temp.append(v)
+ # sorting the dict by interface name
+ temp = sorted(temp, key=lambda k, sk="name": k[sk])
+
+ objs = temp
+ facts = {}
+ if objs:
+ facts["l3_interfaces"] = []
+ params = utils.validate_config(self.argument_spec, {"config": objs})
+ for cfg in params["config"]:
+ facts["l3_interfaces"].append(utils.remove_empties(cfg))
+ facts["l3_interfaces"] = sorted(facts["l3_interfaces"], key=lambda k, sk="name": k[sk])
+ ansible_facts["ansible_network_resources"].update(facts)
+
+ return ansible_facts
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp/lacp.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp/lacp.py
new file mode 100644
index 000000000..ec664c2e6
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp/lacp.py
@@ -0,0 +1,89 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios lacp 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 __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from copy import deepcopy
+
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.lacp.lacp import (
+ LacpArgs,
+)
+
+
+class LacpFacts(object):
+ """The ios lacp fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = LacpArgs.argument_spec
+ spec = deepcopy(self.argument_spec)
+ if subspec:
+ if options:
+ facts_argument_spec = spec[subspec][options]
+ else:
+ facts_argument_spec = spec[subspec]
+ else:
+ facts_argument_spec = spec
+
+ self.generated_spec = utils.generate_dict(facts_argument_spec)
+
+ def get_lacp_data(self, connection):
+ return connection.get("show lacp sys-id")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for lacp
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+ :rtype: dictionary
+ :returns: facts
+ """
+
+ if not data:
+ data = self.get_lacp_data(connection)
+
+ obj = {}
+ if data:
+ lacp_obj = self.render_config(self.generated_spec, data)
+ if lacp_obj:
+ obj = lacp_obj
+
+ ansible_facts["ansible_network_resources"].pop("lacp", None)
+ facts = {}
+
+ params = utils.validate_config(self.argument_spec, {"config": obj})
+ facts["lacp"] = utils.remove_empties(params["config"])
+ ansible_facts["ansible_network_resources"].update(facts)
+
+ return ansible_facts
+
+ def render_config(self, spec, conf):
+ """
+ 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)
+
+ config["system"]["priority"] = int(conf.split(",")[0])
+
+ return utils.remove_empties(config)
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp_interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp_interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp_interfaces/lacp_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp_interfaces/lacp_interfaces.py
new file mode 100644
index 000000000..08ae028ae
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lacp_interfaces/lacp_interfaces.py
@@ -0,0 +1,112 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios_lacp_interfaces 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 __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
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.lacp_interfaces.lacp_interfaces import (
+ Lacp_InterfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ get_interface_type,
+ normalize_interface,
+)
+
+
+class Lacp_InterfacesFacts(object):
+ """The ios_lacp_interfaces fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Lacp_InterfacesArgs.argument_spec
+ spec = deepcopy(self.argument_spec)
+ if subspec:
+ if options:
+ facts_argument_spec = spec[subspec][options]
+ else:
+ facts_argument_spec = spec[subspec]
+ else:
+ facts_argument_spec = spec
+
+ self.generated_spec = utils.generate_dict(facts_argument_spec)
+
+ def get_lacp_interface_data(self, connection):
+ return connection.get("show running-config | section ^interface")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for lacp_interfaces
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+ :rtype: dictionary
+ :returns: facts
+ """
+
+ objs = []
+ if not data:
+ data = self.get_lacp_interface_data(connection)
+
+ # operate on a collection of resource x
+ config = ("\n" + data).split("\ninterface ")
+
+ for conf in config:
+ if conf:
+ obj = self.render_config(self.generated_spec, conf)
+ if obj:
+ objs.append(obj)
+ facts = {}
+
+ if objs:
+ facts["lacp_interfaces"] = []
+ params = utils.validate_config(self.argument_spec, {"config": objs})
+ for cfg in params["config"]:
+ facts["lacp_interfaces"].append(utils.remove_empties(cfg))
+ ansible_facts["ansible_network_resources"].update(facts)
+
+ return ansible_facts
+
+ def render_config(self, spec, conf):
+ """
+ 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)
+ match = re.search(r"^(\S+)", conf)
+ intf = match.group(1)
+ if get_interface_type(intf) == "unknown":
+ return {}
+
+ config["name"] = normalize_interface(intf)
+ port_priority = utils.parse_conf_arg(conf, "lacp port-priority")
+ max_bundle = utils.parse_conf_arg(conf, "lacp max-bundle")
+ if port_priority:
+ config["port_priority"] = int(port_priority)
+ if "lacp fast-switchover" in conf:
+ config["fast_switchover"] = True
+ if max_bundle:
+ config["max_bundle"] = int(max_bundle)
+
+ return utils.remove_empties(config)
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lag_interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lag_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lag_interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lag_interfaces/lag_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lag_interfaces/lag_interfaces.py
new file mode 100644
index 000000000..a8e54bd9f
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lag_interfaces/lag_interfaces.py
@@ -0,0 +1,102 @@
+# -*- coding: utf-8 -*-
+# Copyright 2022 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 lag_interfaces 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 itertools import groupby
+
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.lag_interfaces.lag_interfaces import (
+ Lag_InterfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.lag_interfaces import (
+ Lag_interfacesTemplate,
+)
+
+
+class Lag_interfacesFacts(object):
+ """The ios lag_interfaces facts class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Lag_InterfacesArgs.argument_spec
+
+ def get_lag_interfaces_data(self, connection):
+ return connection.get("show running-config | section ^interface")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for Lag_interfaces 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_lag_interfaces_data(connection)
+
+ # parse native config using the Lag_interfaces template
+ lag_interfaces_parser = Lag_interfacesTemplate(lines=data.splitlines(), module=self._module)
+ objs = self.process_facts(list(lag_interfaces_parser.parse().values()))
+ ansible_facts["ansible_network_resources"].pop("lag_interfaces", None)
+
+ params = utils.remove_empties(
+ lag_interfaces_parser.validate_config(
+ self.argument_spec,
+ {"config": objs},
+ redact=True,
+ ),
+ )
+
+ facts["lag_interfaces"] = params.get("config", [])
+ ansible_facts["ansible_network_resources"].update(facts)
+
+ return ansible_facts
+
+ def process_facts(self, all_objs):
+ lag_facts = []
+ objs = []
+ temp_channels = []
+
+ def key_channel(k):
+ return k.get("channel")
+
+ for intrf in all_objs:
+ if intrf.get("channel"):
+ if intrf.get("channel") in temp_channels:
+ temp_channels.remove(intrf.get("channel"))
+ objs.append(intrf)
+ if "Port-channel" in intrf.get("member"):
+ temp_channels.append(intrf.get("member"))
+
+ objs = sorted(objs, key=key_channel)
+
+ for empty_channel in temp_channels:
+ objs.append({"channel": empty_channel})
+
+ for key, value in groupby(objs, key_channel):
+ if key:
+ _v = list(value)
+ for v in _v:
+ v.pop("channel")
+ lag_facts.append({"name": key, "members": _v})
+
+ return lag_facts
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/legacy/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/legacy/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/legacy/__init__.py
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
new file mode 100644
index 000000000..de92f1ed5
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/legacy/base.py
@@ -0,0 +1,426 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+"""
+The ios legacy 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 __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+import platform
+import re
+
+from ansible.module_utils.six import iteritems
+from ansible.module_utils.six.moves import zip
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ get_capabilities,
+ normalize_interface,
+ run_commands,
+)
+
+
+class FactsBase(object):
+ COMMANDS = list()
+
+ def __init__(self, module):
+ self.module = module
+ self.facts = dict()
+ self.warnings = list()
+ self.responses = None
+
+ def populate(self):
+ self.responses = run_commands(self.module, commands=self.COMMANDS, check_rc=False)
+
+ def run(self, cmd):
+ return run_commands(self.module, commands=cmd, check_rc=False)
+
+
+class Default(FactsBase):
+ COMMANDS = ["show version", "show switch virtual", "show inventory"]
+
+ def populate(self):
+ super(Default, self).populate()
+ self.facts.update(self.platform_facts())
+ data = self.responses[0]
+ if data:
+ self.facts["iostype"] = self.parse_iostype(data)
+ self.facts["operatingmode"] = self.parse_operatingmode(data, self.facts["iostype"])
+ self.facts["serialnum"] = self.parse_serialnum(data)
+ self.parse_stacks(data)
+ data = self.responses[1] + self.responses[2]
+ vss_errs = ["Invalid input", "Switch Mode : Standalone"]
+ if data and not any(err in data for err in vss_errs):
+ self.parse_virtual_switch(data)
+
+ def parse_iostype(self, data):
+ match = re.search(r"\sIOS-XE\s", data)
+ if match:
+ return "IOS-XE"
+ else:
+ return "IOS"
+
+ def parse_operatingmode(self, data, iostype):
+ # for older ios versions default being autonomous where operating mode classification not present
+ match = re.search(r"Router\soperating\smode: (\S+)", data)
+ if (match and "autonomous" in match.group(1).lower()) or iostype == "IOS":
+ return "autonomous"
+ else:
+ return "controller"
+
+ def parse_serialnum(self, data):
+ match = re.search(r"board ID (\S+)", data)
+ if match:
+ return match.group(1)
+
+ def parse_stacks(self, data):
+ match = re.findall(r"^Model [Nn]umber\s+: (\S+)", data, re.M)
+ if match:
+ self.facts["stacked_models"] = match
+
+ match = re.findall(r"^System [Ss]erial [Nn]umber\s+: (\S+)", data, re.M)
+ if match:
+ self.facts["stacked_serialnums"] = match
+
+ if "stacked_models" in self.facts:
+ self.facts["virtual_switch"] = "STACK"
+
+ def parse_virtual_switch(self, data):
+ match = re.search(r"^Virtual switch domain number : ([0-9]+)", data, re.M)
+ if match:
+ self.facts["virtual_switch"] = "VSS"
+ self.facts["virtual_switch_domain"] = match.group(1)
+
+ match = re.findall(r"System\".*?SN:\s*([^\s]+)", data, re.S)
+ if match:
+ self.facts["virtual_switch_serialnums"] = match
+
+ def platform_facts(self):
+ platform_facts = {}
+
+ resp = get_capabilities(self.module)
+ device_info = resp["device_info"]
+
+ platform_facts["system"] = device_info["network_os"]
+
+ for item in ("model", "image", "version", "platform", "hostname"):
+ val = device_info.get("network_os_%s" % item)
+ if val:
+ platform_facts[item] = val
+
+ platform_facts["api"] = resp["network_api"]
+ platform_facts["python_version"] = platform.python_version()
+
+ return platform_facts
+
+
+class Hardware(FactsBase):
+ COMMANDS = ["dir", "show memory statistics"]
+
+ 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)
+
+ 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
+
+ def parse_filesystems(self, data):
+ return re.findall(r"^Directory of (\S+)/", data, re.M)
+
+ def parse_filesystems_info(self, data):
+ facts = dict()
+ fs = ""
+ for line in data.split("\n"):
+ match = re.match(r"^Directory of (\S+)/", line)
+ if match:
+ fs = match.group(1)
+ facts[fs] = dict()
+ continue
+ match = re.match(r"^(\d+) bytes total \((\d+) bytes free\)", line)
+ if match:
+ facts[fs]["spacetotal_kb"] = int(match.group(1)) / 1024
+ facts[fs]["spacefree_kb"] = int(match.group(2)) / 1024
+ return facts
+
+
+class Config(FactsBase):
+ COMMANDS = ["show running-config"]
+
+ def populate(self):
+ super(Config, self).populate()
+ data = self.responses[0]
+ if data:
+ data = re.sub(
+ r"""^Building configuration
+ ...\s+Current configuration : \d+ bytes\n""",
+ "",
+ data,
+ flags=re.MULTILINE,
+ )
+ self.facts["config"] = data
+
+
+class Interfaces(FactsBase):
+ COMMANDS = [
+ "show interfaces",
+ "show ip interface",
+ "show ipv6 interface",
+ "show lldp",
+ "show cdp",
+ ]
+
+ def populate(self):
+ super(Interfaces, self).populate()
+
+ self.facts["all_ipv4_addresses"] = list()
+ self.facts["all_ipv6_addresses"] = list()
+ self.facts["neighbors"] = {}
+
+ data = self.responses[0]
+ if data:
+ interfaces = self.parse_interfaces(data)
+ self.facts["interfaces"] = self.populate_interfaces(interfaces)
+
+ data = self.responses[1]
+ if data:
+ data = self.parse_interfaces(data)
+ self.populate_ipv4_interfaces(data)
+
+ data = self.responses[2]
+ if data:
+ data = self.parse_interfaces(data)
+ self.populate_ipv6_interfaces(data)
+
+ data = self.responses[3]
+ lldp_errs = ["Invalid input", "LLDP is not enabled"]
+
+ if data and not any(err in data for err in lldp_errs):
+ neighbors = self.run(["show lldp neighbors detail"])
+ if neighbors:
+ self.facts["neighbors"].update(self.parse_neighbors(neighbors[0]))
+
+ data = self.responses[4]
+ cdp_errs = ["CDP is not enabled"]
+
+ if data and not any(err in data for err in cdp_errs):
+ cdp_neighbors = self.run(["show cdp neighbors detail"])
+ if cdp_neighbors:
+ self.facts["neighbors"].update(self.parse_cdp_neighbors(cdp_neighbors[0]))
+
+ def populate_interfaces(self, interfaces):
+ facts = dict()
+ for key, value in iteritems(interfaces):
+ intf = dict()
+ intf["description"] = self.parse_description(value)
+ intf["macaddress"] = self.parse_macaddress(value)
+
+ intf["mtu"] = self.parse_mtu(value)
+ intf["bandwidth"] = self.parse_bandwidth(value)
+ intf["mediatype"] = self.parse_mediatype(value)
+ intf["duplex"] = self.parse_duplex(value)
+ intf["lineprotocol"] = self.parse_lineprotocol(value)
+ intf["operstatus"] = self.parse_operstatus(value)
+ intf["type"] = self.parse_type(value)
+
+ facts[key] = intf
+ return facts
+
+ def populate_ipv4_interfaces(self, data):
+ for key, value in data.items():
+ self.facts["interfaces"][key]["ipv4"] = list()
+ primary_address = addresses = []
+ primary_address = re.findall(r"Internet address is (.+)$", value, re.M)
+ addresses = re.findall(r"Secondary address (.+)$", value, re.M)
+ if len(primary_address) == 0:
+ continue
+ addresses.append(primary_address[0])
+ for address in addresses:
+ addr, subnet = address.split("/")
+ ipv4 = dict(address=addr.strip(), subnet=subnet.strip())
+ self.add_ip_address(addr.strip(), "ipv4")
+ self.facts["interfaces"][key]["ipv4"].append(ipv4)
+
+ def populate_ipv6_interfaces(self, data):
+ for key, value in iteritems(data):
+ try:
+ self.facts["interfaces"][key]["ipv6"] = list()
+ except KeyError:
+ self.facts["interfaces"][key] = dict()
+ self.facts["interfaces"][key]["ipv6"] = list()
+ addresses = re.findall(r"\s+(.+), subnet", value, re.M)
+ subnets = re.findall(r", subnet is (.+)$", value, re.M)
+ for addr, subnet in zip(addresses, subnets):
+ ipv6 = dict(address=addr.strip(), subnet=subnet.strip())
+ self.add_ip_address(addr.strip(), "ipv6")
+ self.facts["interfaces"][key]["ipv6"].append(ipv6)
+
+ def add_ip_address(self, address, family):
+ if family == "ipv4":
+ self.facts["all_ipv4_addresses"].append(address)
+ else:
+ self.facts["all_ipv6_addresses"].append(address)
+
+ def parse_neighbors(self, neighbors):
+ facts = dict()
+ for entry in neighbors.split("------------------------------------------------"):
+ if entry == "":
+ continue
+ intf = self.parse_lldp_intf(entry)
+ if intf is None:
+ return facts
+ intf = normalize_interface(intf)
+ if intf not in facts:
+ facts[intf] = list()
+ fact = dict()
+ fact["host"] = self.parse_lldp_host(entry)
+ fact["port"] = self.parse_lldp_port(entry)
+ fact["ip"] = self.parse_lldp_ip(entry)
+ facts[intf].append(fact)
+ return facts
+
+ def parse_cdp_neighbors(self, neighbors):
+ facts = dict()
+ for entry in neighbors.split("-------------------------"):
+ if entry == "":
+ continue
+ intf_port = self.parse_cdp_intf_port(entry)
+ if intf_port is None:
+ return facts
+ intf, port = intf_port
+ if intf not in facts:
+ facts[intf] = list()
+ fact = dict()
+ fact["host"] = self.parse_cdp_host(entry)
+ fact["platform"] = self.parse_cdp_platform(entry)
+ fact["port"] = port
+ fact["ip"] = self.parse_cdp_ip(entry)
+ facts[intf].append(fact)
+ return facts
+
+ def parse_interfaces(self, data):
+ parsed = dict()
+ key = ""
+ for line in data.split("\n"):
+ if len(line) == 0:
+ continue
+ if line[0] == " ":
+ parsed[key] += "\n%s" % line
+ else:
+ match = re.match(r"^(\S+)", line)
+ if match:
+ key = match.group(1)
+ parsed[key] = line
+ return parsed
+
+ def parse_description(self, data):
+ match = re.search(r"Description: (.+)$", data, re.M)
+ if match:
+ return match.group(1)
+
+ def parse_macaddress(self, data):
+ match = re.search(r"Hardware is (?:.*), address is (\S+)", data)
+ if match:
+ return match.group(1)
+
+ def parse_ipv4(self, data):
+ match = re.search(r"Internet address is (\S+)", data)
+ if match:
+ addr, masklen = match.group(1).split("/")
+ return dict(address=addr, masklen=int(masklen))
+
+ def parse_mtu(self, data):
+ match = re.search(r"MTU (\d+)", data)
+ if match:
+ return int(match.group(1))
+
+ def parse_bandwidth(self, data):
+ match = re.search(r"BW (\d+)", data)
+ if match:
+ return int(match.group(1))
+
+ def parse_duplex(self, data):
+ match = re.search(r"(\w+) Duplex", data, re.M)
+ if match:
+ return match.group(1)
+
+ def parse_mediatype(self, data):
+ match = re.search(r"media type is (.+)$", data, re.M)
+ if match:
+ return match.group(1)
+
+ def parse_type(self, data):
+ match = re.search(r"Hardware is (.+),", data, re.M)
+ if match:
+ return match.group(1)
+
+ def parse_lineprotocol(self, data):
+ match = re.search(r"line protocol is (up|down)(.+)?$", data, re.M)
+ if match:
+ return match.group(1)
+
+ def parse_operstatus(self, data):
+ match = re.search(r"^(?:.+) is (.+),", data, re.M)
+ if match:
+ return (match.group(1)).lstrip()
+
+ def parse_lldp_intf(self, data):
+ match = re.search(r"^Local Intf: (.+)$", data, re.M)
+ if match:
+ return match.group(1)
+
+ def parse_lldp_host(self, data):
+ match = re.search(r"System Name: (.+)$", data, re.M)
+ if match:
+ return match.group(1)
+
+ def parse_lldp_port(self, data):
+ match = re.search(r"Port id: (.+)$", data, re.M)
+ if match:
+ return match.group(1)
+
+ def parse_lldp_ip(self, data):
+ match = re.search(r"^ IP: (.+)$", data, re.M)
+ if match:
+ return match.group(1)
+
+ def parse_cdp_intf_port(self, data):
+ match = re.search(r"^Interface: (.+), Port ID \(outgoing port\): (.+)$", data, re.M)
+ if match:
+ return match.group(1), match.group(2)
+
+ def parse_cdp_host(self, data):
+ match = re.search(r"^Device ID: (.+)$", data, re.M)
+ if match:
+ return match.group(1)
+
+ def parse_cdp_platform(self, data):
+ match = re.search(r"^Platform: (.+),", data, re.M)
+ if match:
+ return match.group(1)
+
+ def parse_cdp_ip(self, data):
+ match = re.search(r"^ IP address: (.+)$", data, re.M)
+ if match:
+ return match.group(1)
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_global/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_global/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_global/lldp_global.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_global/lldp_global.py
new file mode 100644
index 000000000..2b8e4fe04
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_global/lldp_global.py
@@ -0,0 +1,101 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios lldp_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 __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from copy import deepcopy
+
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.lldp_global.lldp_global import (
+ Lldp_globalArgs,
+)
+
+
+class Lldp_globalFacts(object):
+ """The ios lldp_global fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Lldp_globalArgs.argument_spec
+ spec = deepcopy(self.argument_spec)
+ if subspec:
+ if options:
+ facts_argument_spec = spec[subspec][options]
+ else:
+ facts_argument_spec = spec[subspec]
+ else:
+ facts_argument_spec = spec
+
+ self.generated_spec = utils.generate_dict(facts_argument_spec)
+
+ def get_lldp_global_data(self, connection):
+ return connection.get("show running-config | section ^lldp")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for lldp_global
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+ :rtype: dictionary
+ :returns: facts
+ """
+ objs = dict()
+ if not data:
+ data = self.get_lldp_global_data(connection)
+ # operate on a collection of resource x
+ config = data.split("\n")
+ for conf in config:
+ if conf:
+ obj = self.render_config(self.generated_spec, conf)
+ if obj:
+ objs.update(obj)
+ facts = {}
+
+ if objs:
+ params = utils.validate_config(
+ self.argument_spec,
+ {"config": utils.remove_empties(objs)},
+ )
+ facts["lldp_global"] = utils.remove_empties(params["config"])
+ ansible_facts["ansible_network_resources"].update(facts)
+
+ return ansible_facts
+
+ def render_config(self, spec, conf):
+ """
+ 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)
+
+ holdtime = utils.parse_conf_arg(conf, "lldp holdtime")
+ timer = utils.parse_conf_arg(conf, "lldp timer")
+ reinit = utils.parse_conf_arg(conf, "lldp reinit")
+ if holdtime:
+ config["holdtime"] = int(holdtime)
+ if "lldp run" in conf:
+ config["enabled"] = True
+ if timer:
+ config["timer"] = int(timer)
+ if reinit:
+ config["reinit"] = int(reinit)
+
+ return utils.remove_empties(config)
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_interfaces/lldp_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_interfaces/lldp_interfaces.py
new file mode 100644
index 000000000..906be1874
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/lldp_interfaces/lldp_interfaces.py
@@ -0,0 +1,116 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios_lldp_interfaces 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 __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
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.lldp_interfaces.lldp_interfaces import (
+ Lldp_InterfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ get_interface_type,
+ normalize_interface,
+)
+
+
+class Lldp_InterfacesFacts(object):
+ """The ios_lldp_interfaces fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Lldp_InterfacesArgs.argument_spec
+ spec = deepcopy(self.argument_spec)
+ if subspec:
+ if options:
+ facts_argument_spec = spec[subspec][options]
+ else:
+ facts_argument_spec = spec[subspec]
+ else:
+ facts_argument_spec = spec
+
+ self.generated_spec = utils.generate_dict(facts_argument_spec)
+
+ def get_lldp_interfaces_data(self, connection):
+ return connection.get("show lldp interface")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for lldp_interfaces
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+ :rtype: dictionary
+ :returns: facts
+ """
+
+ objs = []
+ if not data:
+ data = self.get_lldp_interfaces_data(connection)
+ # operate on a collection of resource x
+ config = data.split("\n\n")
+ for conf in config:
+ if conf:
+ obj = self.render_config(self.generated_spec, conf)
+ if obj:
+ objs.append(obj)
+ facts = {}
+
+ if objs:
+ facts["lldp_interfaces"] = []
+ params = utils.validate_config(self.argument_spec, {"config": objs})
+ for cfg in params["config"]:
+ facts["lldp_interfaces"].append(utils.remove_empties(cfg))
+ ansible_facts["ansible_network_resources"].update(facts)
+
+ return ansible_facts
+
+ def render_config(self, spec, conf):
+ """
+ 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)
+ match = re.search(r"^(\S+)(:)", conf)
+ intf = ""
+ if match:
+ intf = match.group(1)
+
+ if get_interface_type(intf) == "unknown":
+ return {}
+ if intf.lower().startswith("gi"):
+ config["name"] = normalize_interface(intf)
+ receive = utils.parse_conf_arg(conf, "Rx:")
+ transmit = utils.parse_conf_arg(conf, "Tx:")
+
+ if receive == "enabled":
+ config["receive"] = True
+ elif receive == "disabled":
+ config["receive"] = False
+ if transmit == "enabled":
+ config["transmit"] = True
+ elif transmit == "disabled":
+ config["transmit"] = False
+
+ return utils.remove_empties(config)
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/logging_global/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/logging_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/logging_global/__init__.py
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
new file mode 100644
index 000000000..639d43dba
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/logging_global/logging_global.py
@@ -0,0 +1,86 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 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 logging_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.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.logging_global.logging_global import (
+ Logging_globalArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.logging_global import (
+ Logging_globalTemplate,
+)
+
+
+class Logging_globalFacts(object):
+ """The ios logging_global facts class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Logging_globalArgs.argument_spec
+
+ def get_logging_data(self, connection):
+ return connection.get("show running-config | include logging")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for Logging_global network resource
+
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+
+ :rtype: dictionary
+ :returns: facts
+ """
+ facts = {}
+ objFinal = []
+
+ if not data:
+ data = self.get_logging_data(connection)
+
+ # parse native config using the Logging_global template
+ logging_global_parser = Logging_globalTemplate(lines=data.splitlines(), module=self._module)
+ objFinal = logging_global_parser.parse()
+
+ if objFinal:
+ for k, v in iteritems(objFinal):
+ if type(v) == list and k not in ["hosts", "source_interface", "filter"]:
+ v.sort()
+ objFinal[k] = v
+ elif type(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":
+ objFinal[k] = sorted(objFinal[k], key=lambda item: item["interface"])
+ elif type(v) == list and k == "filter":
+ objFinal[k] = sorted(objFinal[k], key=lambda item: item["url"])
+ ansible_facts["ansible_network_resources"].pop("logging_global", None)
+
+ params = utils.remove_empties(
+ logging_global_parser.validate_config(
+ self.argument_spec,
+ {"config": objFinal},
+ redact=True,
+ ),
+ )
+
+ facts["logging_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/ntp_global/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ntp_global/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ntp_global/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ntp_global/ntp_global.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ntp_global/ntp_global.py
new file mode 100644
index 000000000..f762ec0f1
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ntp_global/ntp_global.py
@@ -0,0 +1,89 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 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 ntp_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.ntp_global.ntp_global import (
+ Ntp_globalArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.ntp_global import (
+ Ntp_globalTemplate,
+)
+
+
+class Ntp_globalFacts(object):
+ """The ios ntp_global facts class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Ntp_globalArgs.argument_spec
+
+ def sort_dicts(self, objs):
+ p_key = {
+ "servers": "server",
+ "peers": "peer",
+ "authentication_keys": "id",
+ "peer": "access_list",
+ "query_only": "access_list",
+ "serve": "access_list",
+ "serve_only": "access_list",
+ "trusted_keys": "range_start",
+ "access_group": True,
+ }
+ for k, _v in p_key.items():
+ if k in objs and k != "access_group":
+ objs[k] = sorted(objs[k], key=lambda _k: str(_k[p_key[k]]))
+ elif objs.get("access_group") and k == "access_group":
+ objs[k] = self.sort_dicts(objs.get("access_group"))
+ return objs
+
+ def get_ntp_data(self, connection):
+ return connection.get("show running-config | section ^ntp")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for Ntp_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_ntp_data(connection)
+
+ # parse native config using the Ntp_global template
+ ntp_global_parser = Ntp_globalTemplate(lines=data.splitlines(), module=self._module)
+ objs = ntp_global_parser.parse()
+
+ if objs:
+ objs = self.sort_dicts(objs)
+
+ ansible_facts["ansible_network_resources"].pop("ntp_global", None)
+
+ params = utils.remove_empties(
+ ntp_global_parser.validate_config(self.argument_spec, {"config": objs}, redact=True),
+ )
+
+ facts["ntp_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/ospf_interfaces/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospf_interfaces/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospf_interfaces/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospf_interfaces/ospf_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospf_interfaces/ospf_interfaces.py
new file mode 100644
index 000000000..eab4d8263
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospf_interfaces/ospf_interfaces.py
@@ -0,0 +1,88 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 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 cisco.ios ospf_interfaces 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.ospf_interfaces.ospf_interfaces import (
+ Ospf_interfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.ospf_interfaces import (
+ Ospf_interfacesTemplate,
+)
+
+
+class Ospf_interfacesFacts(object):
+ """The cisco.ios ospf_interfaces facts class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Ospf_interfacesArgs.argument_spec
+
+ def get_ospf_interfaces_data(self, connection):
+ return connection.get("show running-config | section ^interface")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for Ospf_interfaces 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_ospf_interfaces_data(connection)
+
+ # parse native config using the Ospf_interfaces template
+ ospf_interfaces_parser = Ospf_interfacesTemplate(
+ lines=data.splitlines(),
+ module=self._module,
+ )
+
+ objs = ospf_interfaces_parser.parse()
+ final_objs = []
+
+ for key, value in objs.items():
+ temp_af = []
+ if value["address_family"].get("ip"):
+ temp_af.append(value["address_family"].get("ip"))
+ if value["address_family"].get("ipv6"):
+ temp_af.append(value["address_family"].get("ipv6"))
+ if temp_af:
+ value["address_family"] = temp_af
+ if value:
+ value = utils.remove_empties(value)
+ final_objs.append(value)
+
+ ansible_facts["ansible_network_resources"].pop("ospf_interfaces", None)
+
+ params = utils.remove_empties(
+ ospf_interfaces_parser.validate_config(
+ self.argument_spec,
+ {"config": final_objs},
+ redact=True,
+ ),
+ )
+
+ facts["ospf_interfaces"] = 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/ospfv2/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv2/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv2/__init__.py
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
new file mode 100644
index 000000000..48a77de99
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv2/ospfv2.py
@@ -0,0 +1,86 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios ospfv2 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 __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+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 (
+ NetworkTemplate,
+)
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.ospfv2.ospfv2 import (
+ Ospfv2Args,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.ospfv2 import (
+ Ospfv2Template,
+)
+
+
+class Ospfv2Facts(object):
+ """The ios ospfv2 fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Ospfv2Args.argument_spec
+
+ def get_ospfv2_data(self, connection):
+ return connection.get("show running-config | section ^router ospf")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for ospfv2
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+ :rtype: dictionary
+ :returns: facts
+ """
+ if not data:
+ data = self.get_ospfv2_data(connection)
+
+ ipv4 = {"processes": []}
+ rmmod = NetworkTemplate(lines=data.splitlines(), tmplt=Ospfv2Template())
+ current = rmmod.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])
+
+ 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)
+
+ 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)
+
+ 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/ospfv3/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv3/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv3/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv3/ospfv3.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv3/ospfv3.py
new file mode 100644
index 000000000..d67a02bc6
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/ospfv3/ospfv3.py
@@ -0,0 +1,170 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios ospfv3 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 __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+import re
+
+from copy import deepcopy
+
+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 (
+ NetworkTemplate,
+)
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.ospfv3.ospfv3 import (
+ Ospfv3Args,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.ospfv3 import (
+ Ospfv3Template,
+)
+
+
+class Ospfv3Facts(object):
+ """The ios ospfv3 fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Ospfv3Args.argument_spec
+
+ def get_ospfv3_data(self, connection):
+ return connection.get("show running-config | section ^router ospfv3")
+
+ def parse(self, net_template_obj):
+ """Overrided network template parse"""
+ result = {}
+ shared = {}
+ temp_pid = None
+ for line in net_template_obj._lines:
+ for parser in net_template_obj._tmplt.PARSERS:
+ cap = re.match(parser["getval"], line)
+ if cap:
+ capdict = cap.groupdict()
+ temp = {}
+ for k, v in iteritems(capdict):
+ if v is not None:
+ temp.update({k: v})
+ capdict = temp
+ if "address-family" in line:
+ capdict.update({"id": temp_pid})
+ if "manet" in line and "pid" not in shared and shared.get("unicast"):
+ del shared["unicast"]
+
+ if "router ospfv3" in line:
+ temp_pid = None
+ if parser.get("shared"):
+ shared = capdict
+ if not temp_pid and (shared.get("pid") or shared.get("id")):
+ temp_pid = shared.get("pid") or shared.get("id")
+ vals = utils.dict_merge(capdict, shared)
+ try:
+ res = net_template_obj._deepformat(deepcopy(parser["result"]), vals)
+ except Exception:
+ continue
+ result = utils.dict_merge(result, res)
+ break
+ return result
+
+ def parse_for_address_family(self, current):
+ """Parsing and Fishing out address family contents"""
+ pid_addr_family_dict = {}
+ temp_dict = {}
+ temp_pid = None
+ temp = []
+ if current.get("address_family"):
+ for each in current.pop("address_family"):
+ each = utils.remove_empties(each)
+ if each.get("exit"):
+ if temp_pid == each.get("exit")["pid"]:
+ temp.append(temp_dict)
+ pid_addr_family_dict[temp_pid] = temp
+ temp_dict = dict()
+ else:
+ temp_pid = each.get("exit")["pid"]
+ pid_addr_family_dict[temp_pid] = [temp_dict]
+ temp = []
+ temp.append(temp_dict)
+ temp_dict = dict()
+ elif each.get("manet") and temp_dict.get("manet"):
+ for k, v in iteritems(each.get("manet")):
+ if k in temp_dict.get("manet"):
+ temp_dict.get("manet")[k].update(v)
+ else:
+ temp_dict["manet"].update(each.get("manet"))
+ elif each.get("manet") and not temp_dict.get("manet"):
+ temp_dict["manet"] = each.get("manet")
+ else:
+ temp_dict.update(each)
+ return pid_addr_family_dict
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for ospfv3
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+ :rtype: dictionary
+ :returns: facts
+ """
+ if not data:
+ data = self.get_ospfv3_data(connection)
+
+ ipv4 = {"processes": []}
+ ospfv3_parser = NetworkTemplate(
+ lines=data.splitlines(),
+ tmplt=Ospfv3Template(),
+ module=self._module,
+ )
+ current = self.parse(ospfv3_parser)
+ address_family = self.parse_for_address_family(current)
+ if address_family:
+ for k, v in iteritems(current["processes"]):
+ temp = address_family.pop(k)
+ v.update({"address_family": temp})
+ # 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])
+
+ for process in current.get("processes", []):
+ 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()
+ if "address_family" in process:
+ for each in process["address_family"]:
+ if "areas" in each:
+ each["areas"] = list(each["areas"].values())
+ each["areas"] = sorted(each["areas"], key=lambda k, sk="area_id": k[sk])
+ for area in each["areas"]:
+ if "filters" in area:
+ area["filters"].sort()
+ ipv4["processes"].append(process)
+
+ ansible_facts["ansible_network_resources"].pop("ospfv3", None)
+ facts = {}
+ if current:
+ params = ospfv3_parser.validate_config(
+ self.argument_spec,
+ {"config": ipv4},
+ redact=True,
+ )
+ params = utils.remove_empties(params)
+
+ facts["ospfv3"] = 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/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/prefix_lists/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/prefix_lists/__init__.py
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
new file mode 100644
index 000000000..167f68c73
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/prefix_lists/prefix_lists.py
@@ -0,0 +1,116 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 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 cisco.ios prefix_lists 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 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 (
+ Prefix_listsArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.prefix_lists import (
+ Prefix_listsTemplate,
+)
+
+
+class Prefix_listsFacts(object):
+ """The cisco.ios prefix_lists facts class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Prefix_listsArgs.argument_spec
+
+ def get_prefix_list_data(self, connection):
+ return connection.get("show running-config | section ^ip prefix-list|^ipv6 prefix-list")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for Prefix_lists 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_prefix_list_data(connection)
+
+ # parse native config using the Prefix_lists template
+ prefix_lists_parser = Prefix_listsTemplate(lines=data.splitlines())
+ objs = prefix_lists_parser.parse()
+
+ final_objs = []
+ temp = {}
+ temp["afi"] = None
+ temp["prefix_lists"] = []
+ 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]),
+ )
+ # 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])
+
+ ansible_facts["ansible_network_resources"].pop("prefix_lists", None)
+
+ params = utils.remove_empties(
+ utils.validate_config(self.argument_spec, {"config": final_objs}),
+ )
+
+ facts["prefix_lists"] = 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/route_maps/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/route_maps/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/route_maps/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/route_maps/route_maps.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/route_maps/route_maps.py
new file mode 100644
index 000000000..030076279
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/route_maps/route_maps.py
@@ -0,0 +1,105 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 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 cisco.ios route_maps 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 copy import deepcopy
+
+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.route_maps.route_maps import (
+ Route_mapsArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.route_maps import (
+ Route_mapsTemplate,
+)
+
+
+class Route_mapsFacts(object):
+ """The cisco.ios route_maps facts class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Route_mapsArgs.argument_spec
+ spec = deepcopy(self.argument_spec)
+ if subspec:
+ if options:
+ facts_argument_spec = spec[subspec][options]
+ else:
+ facts_argument_spec = spec[subspec]
+ else:
+ facts_argument_spec = spec
+
+ self.generated_spec = utils.generate_dict(facts_argument_spec)
+
+ def get_route_maps_data(self, connection):
+ return connection.get("show running-config | section ^route-map")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for Route_maps 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_route_maps_data(connection)
+ # parse native config using the Route_maps template
+ route_maps_parser = Route_mapsTemplate(lines=data.splitlines())
+ objs = route_maps_parser.parse()
+
+ final_objs = []
+ if objs:
+ for k, v in iteritems(objs):
+ temp_dict = {}
+ temp_dict["entries"] = []
+ for key, val in iteritems(v):
+ if key == "route_map":
+ temp_dict.update({"route_map": val})
+ continue
+ if val.get("entries"):
+ if val["entries"].get("match"):
+ if val["entries"]["match"].get("ip"):
+ for k_ip, v_ip in iteritems(val["entries"]["match"]["ip"]):
+ if v_ip.get("acls"):
+ if "src-pfx" in v_ip["acls"]:
+ v_ip["acls"].pop(v_ip["acls"].index("src-pfx"))
+ elif "dest-pfx" in v_ip["acls"]:
+ v_ip["acls"].pop(v_ip["acls"].index("dest-pfx"))
+ temp_dict["entries"].append(val["entries"])
+ temp_dict["entries"] = sorted(
+ temp_dict["entries"],
+ key=lambda k, sk="sequence": k[sk],
+ )
+ final_objs.append(temp_dict)
+ final_objs = sorted(final_objs, key=lambda k, sk="route_map": k[sk])
+
+ ansible_facts["ansible_network_resources"].pop("route_maps", None)
+
+ params = utils.remove_empties(
+ utils.validate_config(self.argument_spec, {"config": final_objs}),
+ )
+
+ facts["route_maps"] = 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/service/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/service/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/service/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/service/service.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/service/service.py
new file mode 100644
index 000000000..df2dcf993
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/service/service.py
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 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_service 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.service.service import (
+ ServiceArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.service import (
+ ServiceTemplate,
+)
+
+
+class ServiceFacts(object):
+ """The ios service facts class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = ServiceArgs.argument_spec
+
+ def get_service_data(self, connection):
+ return connection.get("show running-config all | section ^service ")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for Service network resource
+
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+
+ :rtype: dictionary
+ :returns: facts
+ """
+ facts = {}
+ objs = []
+ params = {}
+
+ if not data:
+ data = self.get_service_data(connection)
+
+ # parse native config using the ServiceTemplate
+ service_parser = ServiceTemplate(lines=data.splitlines(), module=self._module)
+ objs = service_parser.parse()
+
+ ansible_facts["ansible_network_resources"].pop("service", None)
+
+ params = utils.remove_empties(
+ service_parser.validate_config(self.argument_spec, {"config": objs}, redact=True),
+ )
+
+ facts["service"] = 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/snmp_server/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/snmp_server/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/snmp_server/__init__.py
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
new file mode 100644
index 000000000..2fc1042e7
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/snmp_server/snmp_server.py
@@ -0,0 +1,151 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 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 snmp_server 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.snmp_server.snmp_server import (
+ Snmp_serverArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.snmp_server import (
+ Snmp_serverTemplate,
+)
+
+
+class Snmp_serverFacts(object):
+ """The ios snmp_server facts class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = Snmp_serverArgs.argument_spec
+
+ def get_snmp_data(self, connection):
+ _get_snmp_data = connection.get("show running-config | section ^snmp-server")
+ return _get_snmp_data
+
+ def get_snmpv3_user_data(self, connection):
+ """get snmpv3 user data from the device
+
+ :param connection: the device connection
+
+ :rtype: string
+ :returns: snmpv3 user data
+
+ 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")
+ return _get_snmpv3_user
+
+ def sort_list_dicts(self, objs):
+ p_key = {
+ "hosts": "host",
+ "groups": "group",
+ "engine_id": "id",
+ "communities": "name",
+ "password_policy": "policy_name",
+ "users": "username",
+ "views": "name",
+ }
+ for k, _v in p_key.items():
+ if k in objs:
+ objs[k] = sorted(objs[k], key=lambda _k: str(_k[p_key[k]]))
+ return objs
+
+ def host_traps_string_to_list(self, hosts):
+ if hosts:
+ for element in hosts:
+ if element.get("traps", {}):
+ element["traps"] = list(element.get("traps").split())
+ return hosts
+
+ def get_snmpv3_user_facts(self, snmpv3_user):
+ """Parse the snmpv3_user data and return a list of users
+ example data-
+ User name: TESTU25
+ Engine ID: 000000090200000000000A0B
+ storage-type: nonvolatile active access-list: 22
+ Authentication Protocol: MD5
+ Privacy Protocol: None
+ Group-name: TESTG
+ :param snmpv3_user: the snmpv3_user data which is a string
+
+ :rtype: list
+ :returns: list of users
+ """
+ user_sets = snmpv3_user.split("User ")
+ user_list = []
+ 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]
+ 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]
+ one_set["version"] = "v3" # defaults to version 3 data
+ if len(one_set):
+ user_list.append(one_set)
+ return user_list
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for Snmp_server network resource
+
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+
+ :rtype: dictionary
+ :returns: facts
+ """
+ facts = {}
+ objs = []
+ params = {}
+ snmpv3_user = ""
+
+ if not data:
+ data = self.get_snmp_data(connection)
+ snmpv3_user = self.get_snmpv3_user_data(connection) # gathers v3 user data
+
+ # parse native config using the Snmp_server template
+ snmp_server_parser = Snmp_serverTemplate(lines=data.splitlines(), module=self._module)
+ # parse snmpv3_user data using the get_snmpv3_user_facts method
+ snmp_user_data = self.get_snmpv3_user_facts(snmpv3_user)
+ objs = snmp_server_parser.parse()
+
+ # add snmpv3_user data to the objs dictionary
+ if snmp_user_data:
+ if objs.get("users") is None:
+ objs["users"] = snmp_user_data
+ else:
+ objs["users"] = objs["users"] + snmp_user_data
+ if objs:
+ self.host_traps_string_to_list(objs.get("hosts"))
+ self.sort_list_dicts(objs)
+
+ ansible_facts["ansible_network_resources"].pop("snmp_server", None)
+
+ params = utils.remove_empties(
+ snmp_server_parser.validate_config(self.argument_spec, {"config": objs}, redact=True),
+ )
+
+ facts["snmp_server"] = 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/static_routes/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/static_routes/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/static_routes/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/static_routes/static_routes.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/static_routes/static_routes.py
new file mode 100644
index 000000000..cdd6aaf45
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/static_routes/static_routes.py
@@ -0,0 +1,151 @@
+# -*- 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 static_routes 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.static_routes.static_routes import (
+ Static_routesArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.static_routes import (
+ Static_routesTemplate,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import (
+ netmask_to_cidr,
+)
+
+
+class Static_routesFacts(object):
+ """The ios static_routes facts class"""
+
+ def __init__(self, module):
+ self._module = module
+ self.argument_spec = Static_routesArgs.argument_spec
+
+ def get_static_routes_data(self, connection):
+ return connection.get("show running-config | include ^ip route .+ |^ipv6 route .+")
+
+ def process_static_routes(self, objs):
+ def update_netmask_to_cidr(address, netmask):
+ dest = address + "/" + netmask_to_cidr(netmask)
+ return dest
+
+ strout = {}
+ for k, obj in objs.items():
+ _routes = {"next_hops": []}
+ _nx_hop = []
+ is_vrf = False
+
+ for routes in obj:
+ _vrf = routes.pop("_vrf", None)
+ if _vrf:
+ is_vrf = True
+ _afi = routes.pop("_afi")
+ _dest = routes.pop("_dest")
+ _topology = routes.pop("_topology", None)
+ _netmask = routes.pop("_netmask", None)
+ _routes["dest"] = (
+ update_netmask_to_cidr(_dest, _netmask) if _afi == "ipv4" else _dest
+ )
+ if _topology:
+ _routes["topology"] = _topology
+ _nx_hop.append(routes)
+
+ _routes["next_hops"].extend(_nx_hop)
+
+ if is_vrf:
+ if strout.get(_vrf) and strout[_vrf].get(_afi):
+ strout[_vrf][_afi].append(_routes)
+ else:
+ if strout.get(_vrf):
+ _tma = {_afi: [_routes]}
+ strout[_vrf].update(_tma)
+ else:
+ _tm = {_vrf: {_afi: [_routes]}}
+ strout.update(_tm)
+ else:
+ if strout.get(_afi):
+ strout[_afi].append(_routes)
+ else:
+ _tma = {_afi: [_routes]}
+ strout.update(_tma)
+ return strout
+
+ def structure_static_routes(self, strout):
+ _static_route_facts = []
+ afi_v4 = strout.pop("ipv4", None)
+ afi_v6 = strout.pop("ipv6", None)
+
+ if afi_v4 or afi_v6:
+ _triv_static_route = {"address_families": []}
+
+ if afi_v4:
+ _triv_static_route["address_families"].append({"afi": "ipv4", "routes": afi_v4})
+ if afi_v6:
+ _triv_static_route["address_families"].append({"afi": "ipv6", "routes": afi_v6})
+
+ _static_route_facts.append(_triv_static_route)
+
+ for k, v in strout.items():
+ afi_v4 = v.pop("ipv4", None)
+ afi_v6 = v.pop("ipv6", None)
+
+ _vrf_static_route = {
+ "vrf": k,
+ "address_families": [],
+ }
+
+ if afi_v4:
+ _vrf_static_route["address_families"].append({"afi": "ipv4", "routes": afi_v4})
+ if afi_v6:
+ _vrf_static_route["address_families"].append({"afi": "ipv6", "routes": afi_v6})
+
+ _static_route_facts.append(_vrf_static_route)
+ return _static_route_facts
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for Static_routes 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_static_routes_data(connection)
+
+ # parse native config using the Static_routes template
+ static_routes_parser = Static_routesTemplate(lines=data.splitlines(), module=self._module)
+ objs = static_routes_parser.parse()
+
+ strout = self.process_static_routes(objs)
+ objs = self.structure_static_routes(strout)
+
+ ansible_facts["ansible_network_resources"].pop("static_routes", None)
+
+ params = utils.remove_empties(
+ static_routes_parser.validate_config(self.argument_spec, {"config": objs}, redact=True),
+ )
+
+ facts["static_routes"] = 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/vlans/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vlans/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vlans/__init__.py
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
new file mode 100644
index 000000000..73f73a5a2
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/facts/vlans/vlans.py
@@ -0,0 +1,239 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+"""
+The ios vlans 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 __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+from copy import deepcopy
+
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.vlans.vlans import (
+ VlansArgs,
+)
+
+
+class VlansFacts(object):
+ """The ios vlans fact class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = VlansArgs.argument_spec
+ spec = deepcopy(self.argument_spec)
+ if subspec:
+ if options:
+ facts_argument_spec = spec[subspec][options]
+ else:
+ facts_argument_spec = spec[subspec]
+ else:
+ facts_argument_spec = spec
+
+ self.generated_spec = utils.generate_dict(facts_argument_spec)
+
+ def get_vlans_data(self, connection):
+ """Checks device is L2/L3 and returns
+ facts gracefully. Does not fail module.
+ """
+ check_os_type = connection.get_device_info()
+ if check_os_type.get("network_os_type") == "L3":
+ return ""
+ return connection.get("show vlan")
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for vlans
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+ :rtype: dictionary
+ :returns: facts
+ """
+
+ 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
+ vlan_info = ""
+ temp = ""
+ vlan_name = True
+ for conf in config:
+ if len(list(filter(None, conf.split(" ")))) <= 2 and vlan_name:
+ temp = temp + conf
+ if len(list(filter(None, temp.split(" ")))) <= 2:
+ continue
+ if "VLAN Name" in conf:
+ vlan_info = "Name"
+ elif "VLAN Type" in conf:
+ vlan_info = "Type"
+ vlan_name = False
+ elif "Remote SPAN" in conf:
+ vlan_info = "Remote"
+ vlan_name = False
+ elif "VLAN AREHops" in conf or "STEHops" in conf:
+ vlan_info = "Hops"
+ vlan_name = False
+ elif "Primary Secondary" in conf:
+ vlan_info = "Private"
+ vlan_name = False
+ if temp:
+ conf = temp
+ temp = ""
+ if conf and " " not in filter(None, conf.split("-")) and not conf.split(" ")[0] == "":
+ obj = self.render_config(self.generated_spec, conf, vlan_info)
+ if "mtu" in obj:
+ mtu_objs.append(obj)
+ elif "remote_span" in obj:
+ remote_objs = obj
+ elif "tmp_pvlans" in obj:
+ pvlan_objs.append(obj)
+ elif obj:
+ objs.append(obj)
+ # Appending MTU value to the retrieved dictionary
+ for o, m in zip(objs, mtu_objs):
+ o.update(m)
+ final_objs.append(o)
+
+ # Appending Remote Span value to related VLAN
+ if remote_objs:
+ if remote_objs.get("remote_span"):
+ for each in remote_objs.get("remote_span"):
+ for every in final_objs:
+ if each == every.get("vlan_id"):
+ every.update({"remote_span": True})
+ break
+
+ # Appending private vlan information to related VLAN
+ if pvlan_objs:
+ 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")
+ secvlan = pvdata.get("secondary")
+ sectype = pvdata.get("sec_type")
+
+ # Define the secondary VLAN's type
+ if secvlan and (isinstance(secvlan, int) or secvlan.isnumeric()):
+ secvlan = int(secvlan)
+ pvlan_final[secvlan] = {"private_vlan": {"type": sectype}}
+
+ # Assemble and merge data for primary private VLANs
+ if privlan and (isinstance(privlan, int) or privlan.isnumeric()):
+ privlan = int(privlan)
+ if privlan not in pvlan_final.keys():
+ pvlan_final[privlan] = {
+ "private_vlan": {"type": "primary", "associated": []},
+ }
+ if secvlan and (isinstance(secvlan, int) or secvlan.isnumeric()):
+ pvlan_final[privlan]["private_vlan"]["associated"].append(int(secvlan))
+
+ # Associate with the proper VLAN in final_objs
+ for vlan_id, data in pvlan_final.items():
+ for every in final_objs:
+ 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)
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/ios.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/ios.py
new file mode 100644
index 000000000..9ed7a1f27
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/ios.py
@@ -0,0 +1,174 @@
+# This code is part of Ansible, but is an independent component.
+# This particular file snippet, and this file snippet only, is BSD licensed.
+# Modules you write using this snippet, which is embedded dynamically by Ansible
+# still belong to the author of the module, and may assign their own license
+# to the complete work.
+#
+# (c) 2016 Red Hat Inc.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+import json
+
+from ansible.module_utils._text import to_text
+from ansible.module_utils.connection import Connection, ConnectionError
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+
+
+_DEVICE_CONFIGS = {}
+
+
+def get_connection(module):
+ if hasattr(module, "_ios_connection"):
+ return module._ios_connection
+
+ capabilities = get_capabilities(module)
+ network_api = capabilities.get("network_api")
+ if network_api == "cliconf":
+ module._ios_connection = Connection(module._socket_path)
+ else:
+ module.fail_json(msg="Invalid connection type %s" % network_api)
+
+ return module._ios_connection
+
+
+def get_capabilities(module):
+ if hasattr(module, "_ios_capabilities"):
+ return module._ios_capabilities
+ try:
+ capabilities = Connection(module._socket_path).get_capabilities()
+ except ConnectionError as exc:
+ module.fail_json(msg=to_text(exc, errors="surrogate_then_replace"))
+ module._ios_capabilities = json.loads(capabilities)
+ return module._ios_capabilities
+
+
+def get_defaults_flag(module):
+ connection = get_connection(module)
+ try:
+ out = connection.get_defaults_flag()
+ except ConnectionError as exc:
+ module.fail_json(msg=to_text(exc, errors="surrogate_then_replace"))
+ return to_text(out, errors="surrogate_then_replace").strip()
+
+
+def get_config(module, flags=None):
+ flags = to_list(flags)
+
+ section_filter = False
+ if flags and "section" in flags[-1]:
+ section_filter = True
+
+ flag_str = " ".join(flags)
+
+ try:
+ return _DEVICE_CONFIGS[flag_str]
+ except KeyError:
+ connection = get_connection(module)
+ try:
+ out = connection.get_config(flags=flags)
+ except ConnectionError as exc:
+ if section_filter:
+ # Some ios devices don't understand `| section foo`
+ out = get_config(module, flags=flags[:-1])
+ else:
+ module.fail_json(msg=to_text(exc, errors="surrogate_then_replace"))
+ cfg = to_text(out, errors="surrogate_then_replace").strip()
+ _DEVICE_CONFIGS[flag_str] = cfg
+ return cfg
+
+
+def run_commands(module, commands, check_rc=True):
+ connection = get_connection(module)
+ try:
+ return connection.run_commands(commands=commands, check_rc=check_rc)
+ except ConnectionError as exc:
+ module.fail_json(msg=to_text(exc))
+
+
+def load_config(module, commands):
+ connection = get_connection(module)
+
+ try:
+ resp = connection.edit_config(commands)
+ return resp.get("response")
+ except ConnectionError as exc:
+ module.fail_json(msg=to_text(exc))
+
+
+def normalize_interface(name):
+ """Return the normalized interface name"""
+ if not name:
+ return
+
+ def _get_number(name):
+ digits = ""
+ for char in name:
+ if char.isdigit() or char in "/.":
+ digits += char
+ return digits
+
+ if name.lower().startswith("gi"):
+ if_type = "GigabitEthernet"
+ elif name.lower().startswith("twe"):
+ if_type = "TwentyFiveGigE"
+ elif name.lower().startswith("tw"):
+ if_type = "TwoGigabitEthernet"
+ elif name.lower().startswith("te"):
+ if_type = "TenGigabitEthernet"
+ elif name.lower().startswith("fa"):
+ if_type = "FastEthernet"
+ elif name.lower().startswith("fo"):
+ if_type = "FortyGigabitEthernet"
+ elif name.lower().startswith("fi"):
+ if_type = "FiveGigabitEthernet"
+ elif name.lower().startswith("et"):
+ if_type = "Ethernet"
+ elif name.lower().startswith("vl"):
+ if_type = "Vlan"
+ elif name.lower().startswith("lo"):
+ if_type = "loopback"
+ elif name.lower().startswith("po"):
+ if_type = "port-channel"
+ elif name.lower().startswith("nv"):
+ if_type = "nve"
+ elif name.lower().startswith("hu"):
+ if_type = "HundredGigE"
+ elif name.lower().startswith("se"):
+ if_type = "Serial"
+ else:
+ if_type = None
+
+ number_list = name.split(" ")
+ if len(number_list) == 2:
+ if_number = number_list[-1].strip()
+ else:
+ if_number = _get_number(name)
+
+ if if_type:
+ proper_interface = if_type + if_number
+ else:
+ proper_interface = name
+
+ return proper_interface
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/base.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/base.py
new file mode 100644
index 000000000..f1b9cdb90
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/base.py
@@ -0,0 +1,82 @@
+#
+# (c) 2019, Ansible by Red Hat, inc
+# 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
+from ansible.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import (
+ NetworkConfig,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+
+
+class ConfigBase(object):
+ argument_spec = {}
+
+ mutually_exclusive = []
+
+ identifier = ()
+
+ def __init__(self, **kwargs):
+ self.values = {}
+ self._rendered_configuration = {}
+ self.active_configuration = None
+
+ for item in self.identifier:
+ self.values[item] = kwargs.pop(item)
+
+ for key, value in iteritems(kwargs):
+ if key in self.argument_spec:
+ setattr(self, key, value)
+
+ for key, value in iteritems(self.argument_spec):
+ if value.get("default"):
+ if not getattr(self, key, None):
+ setattr(self, key, value.get("default"))
+
+ def __getattr__(self, key):
+ if key in self.argument_spec:
+ return self.values.get(key)
+
+ def __setattr__(self, key, value):
+ if key in self.argument_spec:
+ if key in self.identifier:
+ raise TypeError("cannot set value")
+ elif value is not None:
+ self.values[key] = value
+ else:
+ super(ConfigBase, self).__setattr__(key, value)
+
+ def context_config(self, cmd):
+ if "context" not in self._rendered_configuration:
+ self._rendered_configuration["context"] = list()
+ self._rendered_configuration["context"].extend(to_list(cmd))
+
+ def global_config(self, cmd):
+ if "global" not in self._rendered_configuration:
+ self._rendered_configuration["global"] = list()
+ self._rendered_configuration["global"].extend(to_list(cmd))
+
+ def get_rendered_configuration(self):
+ config = list()
+ for section in ("context", "global"):
+ config.extend(self._rendered_configuration.get(section, []))
+ return config
+
+ def set_active_configuration(self, config):
+ self.active_configuration = config
+
+ def render(self, config=None):
+ raise NotImplementedError
+
+ def get_section(self, config, section):
+ if config is not None:
+ netcfg = NetworkConfig(indent=1, contents=config)
+ try:
+ config = netcfg.get_block_config(to_list(section))
+ except ValueError:
+ config = None
+ return config
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/address_family.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/address_family.py
new file mode 100644
index 000000000..e4c2bd803
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/address_family.py
@@ -0,0 +1,147 @@
+#
+# (c) 2019, Ansible by Red Hat, inc
+# 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
+import re
+
+from ansible.module_utils.common.network import to_netmask
+from ansible.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.providers.cli.config.bgp.neighbors import (
+ AFNeighbors,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.providers.providers import (
+ CliProvider,
+)
+
+
+class AddressFamily(CliProvider):
+ def render(self, config=None):
+ commands = list()
+ safe_list = list()
+
+ router_context = "router bgp %s" % self.get_value("config.bgp_as")
+ context_config = None
+
+ for item in self.get_value("config.address_family"):
+ context = "address-family %s" % item["afi"]
+ if item["safi"] != "unicast":
+ context += " %s" % item["safi"]
+ context_commands = list()
+
+ if config:
+ context_path = [router_context, context]
+ context_config = self.get_config_context(config, context_path, indent=1)
+
+ for key, value in iteritems(item):
+ if value is not None:
+ meth = getattr(self, "_render_%s" % key, None)
+ if meth:
+ resp = meth(item, context_config)
+ if resp:
+ context_commands.extend(to_list(resp))
+
+ if context_commands:
+ commands.append(context)
+ commands.extend(context_commands)
+ commands.append("exit-address-family")
+
+ safe_list.append(context)
+
+ if self.params["operation"] == "replace":
+ if config:
+ resp = self._negate_config(config, safe_list)
+ commands.extend(resp)
+
+ return commands
+
+ def _negate_config(self, config, safe_list=None):
+ commands = list()
+ matches = re.findall(r"(address-family .+)$", config, re.M)
+ for item in set(matches).difference(safe_list):
+ commands.append("no %s" % item)
+ return commands
+
+ def _render_auto_summary(self, item, config=None):
+ cmd = "auto-summary"
+ if item["auto_summary"] is False:
+ cmd = "no %s" % cmd
+ if not config or cmd not in config:
+ return cmd
+
+ def _render_synchronization(self, item, config=None):
+ cmd = "synchronization"
+ if item["synchronization"] is False:
+ cmd = "no %s" % cmd
+ if not config or cmd not in config:
+ return cmd
+
+ def _render_networks(self, item, config=None):
+ commands = list()
+ safe_list = list()
+
+ for entry in item["networks"]:
+ network = entry["prefix"]
+ cmd = "network %s" % network
+ if entry["masklen"]:
+ cmd += " mask %s" % to_netmask(entry["masklen"])
+ network += " mask %s" % to_netmask(entry["masklen"])
+ if entry["route_map"]:
+ cmd += " route-map %s" % entry["route_map"]
+ network += " route-map %s" % entry["route_map"]
+
+ safe_list.append(network)
+
+ if not config or cmd not in config:
+ commands.append(cmd)
+
+ if self.params["operation"] == "replace":
+ if config:
+ matches = re.findall(r"network (.*)", config, re.M)
+ for entry in set(matches).difference(safe_list):
+ commands.append("no network %s" % entry)
+
+ return commands
+
+ def _render_redistribute(self, item, config=None):
+ commands = list()
+ safe_list = list()
+
+ for entry in item["redistribute"]:
+ option = entry["protocol"]
+
+ cmd = "redistribute %s" % entry["protocol"]
+
+ if entry["id"] and entry["protocol"] in ("ospf", "ospfv3", "eigrp"):
+ cmd += " %s" % entry["id"]
+ option += " %s" % entry["id"]
+
+ if entry["metric"]:
+ cmd += " metric %s" % entry["metric"]
+
+ if entry["route_map"]:
+ cmd += " route-map %s" % entry["route_map"]
+
+ if not config or cmd not in config:
+ commands.append(cmd)
+
+ safe_list.append(option)
+
+ if self.params["operation"] == "replace":
+ if config:
+ matches = re.findall(r"redistribute (\S+)(?:\s*)(\d*)", config, re.M)
+ for i in range(0, len(matches)):
+ matches[i] = " ".join(matches[i]).strip()
+ for entry in set(matches).difference(safe_list):
+ commands.append("no redistribute %s" % entry)
+
+ return commands
+
+ def _render_neighbors(self, item, config):
+ """generate bgp neighbor configuration"""
+ return AFNeighbors(self.params).render(config, nbr_list=item["neighbors"])
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/neighbors.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/neighbors.py
new file mode 100644
index 000000000..4ee337b00
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/neighbors.py
@@ -0,0 +1,203 @@
+#
+# (c) 2019, Ansible by Red Hat, inc
+# 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
+import re
+
+from ansible.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.providers.providers import (
+ CliProvider,
+)
+
+
+class Neighbors(CliProvider):
+ def render(self, config=None, nbr_list=None):
+ commands = list()
+ safe_list = list()
+ if not nbr_list:
+ nbr_list = self.get_value("config.neighbors")
+
+ for item in nbr_list:
+ neighbor_commands = list()
+ context = "neighbor %s" % item["neighbor"]
+ cmd = "%s remote-as %s" % (context, item["remote_as"])
+
+ if not config or cmd not in config:
+ neighbor_commands.append(cmd)
+
+ for key, value in iteritems(item):
+ if value is not None:
+ meth = getattr(self, "_render_%s" % key, None)
+ if meth:
+ resp = meth(item, config)
+ if resp:
+ neighbor_commands.extend(to_list(resp))
+
+ commands.extend(neighbor_commands)
+ safe_list.append(context)
+
+ if self.params["operation"] == "replace":
+ if config and safe_list:
+ commands.extend(self._negate_config(config, safe_list))
+
+ return commands
+
+ def _negate_config(self, config, safe_list=None):
+ commands = list()
+ matches = re.findall(r"(neighbor \S+)", config, re.M)
+ for item in set(matches).difference(safe_list):
+ commands.append("no %s" % item)
+ return commands
+
+ def _render_local_as(self, item, config=None):
+ cmd = "neighbor %s local-as %s" % (item["neighbor"], item["local_as"])
+ if not config or cmd not in config:
+ return cmd
+
+ def _render_port(self, item, config=None):
+ cmd = "neighbor %s port %s" % (item["neighbor"], item["port"])
+ if not config or cmd not in config:
+ return cmd
+
+ def _render_description(self, item, config=None):
+ cmd = "neighbor %s description %s" % (item["neighbor"], item["description"])
+ if not config or cmd not in config:
+ return cmd
+
+ def _render_enabled(self, item, config=None):
+ cmd = "neighbor %s shutdown" % item["neighbor"]
+ if item["enabled"] is True:
+ if not config or cmd in config:
+ cmd = "no %s" % cmd
+ return cmd
+ elif not config or cmd not in config:
+ return cmd
+
+ def _render_update_source(self, item, config=None):
+ cmd = "neighbor %s update-source %s" % (item["neighbor"], item["update_source"])
+ if not config or cmd not in config:
+ return cmd
+
+ def _render_password(self, item, config=None):
+ cmd = "neighbor %s password %s" % (item["neighbor"], item["password"])
+ if not config or cmd not in config:
+ return cmd
+
+ def _render_ebgp_multihop(self, item, config=None):
+ cmd = "neighbor %s ebgp-multihop %s" % (item["neighbor"], item["ebgp_multihop"])
+ if not config or cmd not in config:
+ return cmd
+
+ def _render_peer_group(self, item, config=None):
+ cmd = "neighbor %s peer-group %s" % (item["neighbor"], item["peer_group"])
+ if not config or cmd not in config:
+ return cmd
+
+ def _render_timers(self, item, config):
+ """generate bgp timer related configuration"""
+ keepalive = item["timers"]["keepalive"]
+ holdtime = item["timers"]["holdtime"]
+ min_neighbor_holdtime = item["timers"]["min_neighbor_holdtime"]
+ neighbor = item["neighbor"]
+
+ if keepalive and holdtime:
+ cmd = "neighbor %s timers %s %s" % (neighbor, keepalive, holdtime)
+ if min_neighbor_holdtime:
+ cmd += " %s" % min_neighbor_holdtime
+ if not config or cmd not in config:
+ return cmd
+
+
+class AFNeighbors(CliProvider):
+ def render(self, config=None, nbr_list=None):
+ commands = list()
+ if not nbr_list:
+ return
+
+ for item in nbr_list:
+ neighbor_commands = list()
+ for key, value in iteritems(item):
+ if value is not None:
+ meth = getattr(self, "_render_%s" % key, None)
+ if meth:
+ resp = meth(item, config)
+ if resp:
+ neighbor_commands.extend(to_list(resp))
+
+ commands.extend(neighbor_commands)
+
+ return commands
+
+ def _render_advertisement_interval(self, item, config=None):
+ cmd = "neighbor %s advertisement-interval %s" % (
+ item["neighbor"],
+ item["advertisement_interval"],
+ )
+ if not config or cmd not in config:
+ return cmd
+
+ def _render_route_reflector_client(self, item, config=None):
+ cmd = "neighbor %s route-reflector-client" % item["neighbor"]
+ if item["route_reflector_client"] is False:
+ if not config or cmd in config:
+ cmd = "no %s" % cmd
+ return cmd
+ elif not config or cmd not in config:
+ return cmd
+
+ def _render_route_server_client(self, item, config=None):
+ cmd = "neighbor %s route-server-client" % item["neighbor"]
+ if item["route_server_client"] is False:
+ if not config or cmd in config:
+ cmd = "no %s" % cmd
+ return cmd
+ elif not config or cmd not in config:
+ return cmd
+
+ def _render_remove_private_as(self, item, config=None):
+ cmd = "neighbor %s remove-private-as" % item["neighbor"]
+ if item["remove_private_as"] is False:
+ if not config or cmd in config:
+ cmd = "no %s" % cmd
+ return cmd
+ elif not config or cmd not in config:
+ return cmd
+
+ def _render_next_hop_self(self, item, config=None):
+ cmd = "neighbor %s next-hop-self" % item["neighbor"]
+ if item["next_hop_self"] is False:
+ if not config or cmd in config:
+ cmd = "no %s" % cmd
+ return cmd
+ elif not config or cmd not in config:
+ return cmd
+
+ def _render_activate(self, item, config=None):
+ cmd = "neighbor %s activate" % item["neighbor"]
+ if item["activate"] is False:
+ if not config or cmd in config:
+ cmd = "no %s" % cmd
+ return cmd
+ elif not config or cmd not in config:
+ return cmd
+
+ def _render_maximum_prefix(self, item, config=None):
+ cmd = "neighbor %s maximum-prefix %s" % (item["neighbor"], item["maximum_prefix"])
+ if not config or cmd not in config:
+ return cmd
+
+ def _render_prefix_list_in(self, item, config=None):
+ cmd = "neighbor %s prefix-list %s in" % (item["neighbor"], item["prefix_list_in"])
+ if not config or cmd not in config:
+ return cmd
+
+ def _render_prefix_list_out(self, item, config=None):
+ cmd = "neighbor %s prefix-list %s out" % (item["neighbor"], item["prefix_list_out"])
+ if not config or cmd not in config:
+ return cmd
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/process.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/process.py
new file mode 100644
index 000000000..2b54daa35
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/cli/config/bgp/process.py
@@ -0,0 +1,163 @@
+#
+# (c) 2019, Ansible by Red Hat, inc
+# 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
+import re
+
+from ansible.module_utils.common.network import to_netmask
+from ansible.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.providers.cli.config.bgp.address_family import (
+ AddressFamily,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.providers.cli.config.bgp.neighbors import (
+ Neighbors,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.providers.providers import (
+ CliProvider,
+ register_provider,
+)
+
+
+REDISTRIBUTE_PROTOCOLS = [
+ "ospf",
+ "ospfv3",
+ "eigrp",
+ "isis",
+ "static",
+ "connected",
+ "odr",
+ "lisp",
+ "mobile",
+ "rip",
+]
+
+
+@register_provider("ios", "ios_bgp")
+class Provider(CliProvider):
+ def render(self, config=None):
+ commands = list()
+
+ existing_as = None
+ if config:
+ match = re.search(r"router bgp (\d+)", config, re.M)
+ if match:
+ existing_as = match.group(1)
+
+ operation = self.params["operation"]
+
+ context = None
+ if self.params["config"]:
+ context = "router bgp %s" % self.get_value("config.bgp_as")
+
+ if operation == "delete":
+ if existing_as:
+ commands.append("no router bgp %s" % existing_as)
+ elif context:
+ commands.append("no %s" % context)
+
+ else:
+ self._validate_input(config)
+ if operation == "replace":
+ if existing_as and int(existing_as) != self.get_value("config.bgp_as"):
+ commands.append("no router bgp %s" % existing_as)
+ config = None
+
+ elif operation == "override":
+ if existing_as:
+ commands.append("no router bgp %s" % existing_as)
+ config = None
+
+ context_commands = list()
+
+ for key, value in iteritems(self.get_value("config")):
+ if value is not None:
+ meth = getattr(self, "_render_%s" % key, None)
+ if meth:
+ resp = meth(config)
+ if resp:
+ context_commands.extend(to_list(resp))
+
+ if context and context_commands:
+ commands.append(context)
+ commands.extend(context_commands)
+ commands.append("exit")
+ return commands
+
+ def _render_router_id(self, config=None):
+ cmd = "bgp router-id %s" % self.get_value("config.router_id")
+ if not config or cmd not in config:
+ return cmd
+
+ def _render_log_neighbor_changes(self, config=None):
+ cmd = "bgp log-neighbor-changes"
+ log_neighbor_changes = self.get_value("config.log_neighbor_changes")
+ if log_neighbor_changes is True:
+ if not config or cmd not in config:
+ return cmd
+ elif log_neighbor_changes is False:
+ if config and cmd in config:
+ return "no %s" % cmd
+
+ def _render_networks(self, config=None):
+ commands = list()
+ safe_list = list()
+
+ for entry in self.get_value("config.networks"):
+ network = entry["prefix"]
+ cmd = "network %s" % network
+ if entry["masklen"] and entry["masklen"] not in (24, 16, 8):
+ cmd += " mask %s" % to_netmask(entry["masklen"])
+ network += " mask %s" % to_netmask(entry["masklen"])
+
+ if entry["route_map"]:
+ cmd += " route-map %s" % entry["route_map"]
+ network += " route-map %s" % entry["route_map"]
+
+ safe_list.append(network)
+
+ if not config or cmd not in config:
+ commands.append(cmd)
+
+ if self.params["operation"] == "replace":
+ if config:
+ matches = re.findall(r"network (.*)", config, re.M)
+ for entry in set(matches).difference(safe_list):
+ commands.append("no network %s" % entry)
+
+ return commands
+
+ def _render_neighbors(self, config):
+ """generate bgp neighbor configuration"""
+ return Neighbors(self.params).render(config)
+
+ def _render_address_family(self, config):
+ """generate address-family configuration"""
+ return AddressFamily(self.params).render(config)
+
+ def _validate_input(self, config=None):
+ def device_has_AF(config):
+ return re.search(r"address-family (?:.*)", config)
+
+ address_family = self.get_value("config.address_family")
+ root_networks = self.get_value("config.networks")
+ operation = self.params["operation"]
+
+ if operation == "replace":
+ if address_family and root_networks:
+ for item in address_family:
+ if item["networks"]:
+ raise ValueError(
+ "operation is replace but provided both root level network(s) and network(s) under %s %s address family"
+ % (item["afi"], item["safi"]),
+ )
+
+ if root_networks and config and device_has_AF(config):
+ raise ValueError(
+ "operation is replace and device has one or more address family activated but root level network(s) provided",
+ )
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/module.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/module.py
new file mode 100644
index 000000000..4de464795
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/module.py
@@ -0,0 +1,66 @@
+#
+# (c) 2019, Ansible by Red Hat, inc
+# 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
+from ansible.module_utils._text import to_text
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.connection import Connection
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.providers import providers
+
+
+class NetworkModule(AnsibleModule):
+ fail_on_missing_provider = True
+
+ def __init__(self, connection=None, *args, **kwargs):
+ super(NetworkModule, self).__init__(*args, **kwargs)
+
+ if connection is None:
+ connection = Connection(self._socket_path)
+
+ self.connection = connection
+
+ @property
+ def provider(self):
+ if not hasattr(self, "_provider"):
+ capabilities = self.from_json(self.connection.get_capabilities())
+
+ network_os = capabilities["device_info"]["network_os"]
+ network_api = capabilities["network_api"]
+
+ if network_api == "cliconf":
+ connection_type = "network_cli"
+
+ cls = providers.get(network_os, self._name.split(".")[-1], connection_type)
+
+ if not cls:
+ msg = "unable to find suitable provider for network os %s" % network_os
+ if self.fail_on_missing_provider:
+ self.fail_json(msg=msg)
+ else:
+ self.warn(msg)
+
+ obj = cls(self.params, self.connection, self.check_mode)
+
+ setattr(self, "_provider", obj)
+
+ return getattr(self, "_provider")
+
+ def get_facts(self, subset=None):
+ try:
+ self.provider.get_facts(subset)
+ except Exception as exc:
+ self.fail_json(msg=to_text(exc))
+
+ def edit_config(self, config_filter=None):
+ current_config = self.connection.get_config(flags=config_filter)
+ try:
+ commands = self.provider.edit_config(current_config)
+ changed = bool(commands)
+ return {"commands": commands, "changed": changed}
+ except Exception as exc:
+ self.fail_json(msg=to_text(exc))
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/providers.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/providers.py
new file mode 100644
index 000000000..b422f745f
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/providers/providers.py
@@ -0,0 +1,125 @@
+#
+# (c) 2019, Ansible by Red Hat, inc
+# 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
+import json
+
+from threading import RLock
+
+from ansible.module_utils.six import itervalues
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import (
+ NetworkConfig,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
+
+
+_registered_providers = {}
+_provider_lock = RLock()
+
+
+def register_provider(network_os, module_name):
+ def wrapper(cls):
+ _provider_lock.acquire()
+ try:
+ if network_os not in _registered_providers:
+ _registered_providers[network_os] = {}
+ for ct in cls.supported_connections:
+ if ct not in _registered_providers[network_os]:
+ _registered_providers[network_os][ct] = {}
+ for item in to_list(module_name):
+ for entry in itervalues(_registered_providers[network_os]):
+ entry[item] = cls
+ finally:
+ _provider_lock.release()
+ return cls
+
+ return wrapper
+
+
+def get(network_os, module_name, connection_type):
+ network_os_providers = _registered_providers.get(network_os)
+ if network_os_providers is None:
+ raise ValueError("unable to find a suitable provider for this module")
+ if connection_type not in network_os_providers:
+ raise ValueError("provider does not support this connection type")
+ elif module_name not in network_os_providers[connection_type]:
+ raise ValueError("could not find a suitable provider for this module")
+ return network_os_providers[connection_type][module_name]
+
+
+class ProviderBase(object):
+ supported_connections = ()
+
+ def __init__(self, params, connection=None, check_mode=False):
+ self.params = params
+ self.connection = connection
+ self.check_mode = check_mode
+
+ @property
+ def capabilities(self):
+ if not hasattr(self, "_capabilities"):
+ resp = self.from_json(self.connection.get_capabilities())
+ setattr(self, "_capabilities", resp)
+ return getattr(self, "_capabilities")
+
+ def get_value(self, path):
+ params = self.params.copy()
+ for key in path.split("."):
+ params = params[key]
+ return params
+
+ def get_facts(self, subset=None):
+ raise NotImplementedError(self.__class__.__name__)
+
+ def edit_config(self):
+ raise NotImplementedError(self.__class__.__name__)
+
+
+class CliProvider(ProviderBase):
+ supported_connections = ("network_cli",)
+
+ @property
+ def capabilities(self):
+ if not hasattr(self, "_capabilities"):
+ resp = self.from_json(self.connection.get_capabilities())
+ setattr(self, "_capabilities", resp)
+ return getattr(self, "_capabilities")
+
+ def get_config_context(self, config, path, indent=1):
+ if config is not None:
+ netcfg = NetworkConfig(indent=indent, contents=config)
+ try:
+ config = netcfg.get_block_config(to_list(path))
+ except ValueError:
+ config = None
+ return config
+
+ def render(self, config=None):
+ raise NotImplementedError(self.__class__.__name__)
+
+ def cli(self, command):
+ try:
+ if not hasattr(self, "_command_output"):
+ setattr(self, "_command_output", {})
+ return self._command_output[command]
+ except KeyError:
+ out = self.connection.get(command)
+ try:
+ out = json.loads(out)
+ except ValueError:
+ pass
+ self._command_output[command] = out
+ return out
+
+ def get_facts(self, subset=None):
+ return self.populate()
+
+ def edit_config(self, config=None):
+ commands = self.render(config)
+ if commands and self.check_mode is False:
+ self.connection.edit_config(commands)
+ return commands
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/acl_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/acl_interfaces.py
new file mode 100644
index 000000000..9ae0dbe50
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/acl_interfaces.py
@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+# Copyright 2022 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 Acl_interfaces 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 Acl_interfacesTemplate(NetworkTemplate):
+ def __init__(self, lines=None, module=None):
+ super(Acl_interfacesTemplate, self).__init__(lines=lines, tmplt=self, module=module)
+
+ # fmt: off
+ PARSERS = [
+ {
+ 'name': 'interface',
+ 'getval': re.compile(
+ r'''
+ ^interface\s
+ (?P<name>\S+)$''', re.VERBOSE,
+ ),
+ 'setval': 'interface {{ name }}',
+ 'result': {
+ '{{ name }}': {
+ 'name': '{{ name }}',
+ 'access_groups': {},
+ },
+ },
+ 'shared': True,
+ },
+ {
+ "name": "access_groups",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)
+ (\saccess-group\s(?P<acl_name>\S+))?
+ (\straffic-filter\s(?P<acl_name_traffic>\S+))?
+ \s(?P<direction>\S+)$
+ """,
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip access-group' if afi == 'ipv4' else 'ipv6 traffic-filter' }} {{ name|string }} {{ direction }}",
+ "result": {
+ "{{ name }}": {
+ "access_groups": {
+ "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "acls": [
+ {
+ "name": "{{ acl_name|string if acl_name is defined else acl_name_traffic }}",
+ "direction": "{{ direction }}",
+ },
+ ],
+ },
+ },
+ },
+ },
+ },
+ ]
+ # fmt: on
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
new file mode 100644
index 000000000..164c93caf
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/acls.py
@@ -0,0 +1,372 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 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 acls 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,
+)
+
+
+def _tmplt_access_list_entries(aces):
+ def source_destination_common_config(config_data, command, attr):
+ if config_data[attr].get("address"):
+ command += " {address}".format(**config_data[attr])
+ if config_data[attr].get("wildcard_bits"):
+ command += " {wildcard_bits}".format(**config_data[attr])
+ elif config_data[attr].get("any"):
+ command += " any".format(**config_data[attr])
+ elif config_data[attr].get("host"):
+ command += " host {host}".format(**config_data[attr])
+ elif config_data[attr].get("object_group"):
+ command += " object-group {object_group}".format(**config_data[attr])
+ if config_data[attr].get("port_protocol"):
+ if config_data[attr].get("port_protocol").get("range"):
+ command += " range {0} {1}".format(
+ config_data[attr]["port_protocol"]["range"].get("start"),
+ config_data[attr]["port_protocol"]["range"].get("end"),
+ )
+ else:
+ port_proto_type = list(config_data[attr]["port_protocol"].keys())[0]
+ command += " {0} {1}".format(
+ port_proto_type,
+ config_data[attr]["port_protocol"][port_proto_type],
+ )
+ return command
+
+ command = ""
+ proto_option = None
+ if aces:
+ if aces.get("sequence") and aces.get("afi") == "ipv4":
+ command += "{sequence}".format(**aces)
+ if aces.get("grant") and aces.get("sequence") and aces.get("afi") == "ipv4":
+ command += " {grant}".format(**aces)
+ elif aces.get("grant") and aces.get("sequence") and aces.get("afi") == "ipv6":
+ command += "{grant}".format(**aces)
+ elif aces.get("grant"):
+ command += "{grant}".format(**aces)
+ if aces.get("protocol_options"):
+ if "protocol_number" in aces["protocol_options"]:
+ 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])
+ elif aces.get("protocol"):
+ command += " {protocol}".format(**aces)
+ if aces.get("source"):
+ command = source_destination_common_config(aces, command, "source")
+ if aces.get("destination"):
+ command = source_destination_common_config(aces, command, "destination")
+ if isinstance(proto_option, dict):
+ command += " {0}".format(list(proto_option.keys())[0].replace("_", "-"))
+ if aces.get("dscp"):
+ command += " dscp {dscp}".format(**aces)
+ if aces.get("sequence") and aces.get("afi") == "ipv6":
+ command += " sequence {sequence}".format(**aces)
+ if aces.get("enable_fragments") or aces.get("fragments"):
+ command += " fragments"
+ if aces.get("log"):
+ command += " log"
+ if aces["log"].get("user_cookie"):
+ command += " {user_cookie}".format(**aces["log"])
+ if aces.get("log_input"):
+ command += " log-input"
+ if aces["log_input"].get("user_cookie"):
+ command += " {user_cookie}".format(**aces["log_input"])
+ if aces.get("option"):
+ option_val = list(aces.get("option").keys())[0]
+ command += " option {0}".format(option_val)
+ if aces.get("precedence"):
+ command += " precedence {precedence}".format(**aces)
+ if aces.get("time_range"):
+ command += " time-range {time_range}".format(**aces)
+ if aces.get("tos"):
+ command += " tos"
+ if aces["tos"].get("service_value"):
+ command += " {service_value}".format(**aces["tos"])
+ elif aces["tos"].get("max_reliability"):
+ command += " max-reliability"
+ elif aces["tos"].get("max_throughput"):
+ command += " max-throughput"
+ elif aces["tos"].get("min_delay"):
+ command += " min-delay"
+ elif aces["tos"].get("min_monetary_cost"):
+ command += " min-monetary-cost"
+ elif aces["tos"].get("normal"):
+ command += " normal"
+ if aces.get("ttl"):
+ command += " ttl {0}".format(list(aces["ttl"])[0])
+ proto_option = aces["ttl"].get(list(aces["ttl"])[0])
+ command += " {0}".format(proto_option)
+ return command
+
+
+class AclsTemplate(NetworkTemplate):
+ def __init__(self, lines=None):
+ super(AclsTemplate, self).__init__(lines=lines, tmplt=self)
+
+ PARSERS = [
+ {
+ "name": "acls_name",
+ "getval": re.compile(
+ r"""^(?P<acl_type>Standard|Extended|Reflexive)*
+ \s*(?P<afi>IP|IPv6)*
+ \s*access*
+ \s*list*
+ \s*(?P<acl_name>.+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "compval": "name",
+ "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": "_acls_name",
+ "getval": re.compile(
+ r"""^(ip|ipv6)
+ (\s(access-list))
+ (\s(standard|extended))
+ (\s(?P<acl_name_r>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "compval": "name",
+ "setval": "ip access-list",
+ "result": {},
+ "shared": True,
+ },
+ {
+ "name": "_mac_acls_name", #
+ "getval": re.compile(
+ r"""^(?P<acl_type>Standard|Extended|Reflexive)*
+ \s*(?P<afi>MAC)*
+ \s*access
+ \s*list*
+ \s*(?P<acl_name>.+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "compval": "name",
+ "setval": "",
+ "result": {
+ "acls": {
+ "{{ acl_name|d() }}": {
+ "name": "{{ acl_name }}",
+ "acl_type": "{{ acl_type.lower() if acl_type is defined }}",
+ "afi": "{{ afi }}",
+ },
+ },
+ },
+ "shared": True,
+ },
+ {
+ "name": "remarks",
+ "getval": re.compile(
+ r"""\s+remark
+ (\s(?P<remarks>.+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "remark {{ remarks }}",
+ "result": {
+ "acls": {
+ "{{ acl_name_r|d() }}": {
+ "name": "{{ acl_name_r }}",
+ "aces": [{"remarks": "{{ remarks }}"}],
+ },
+ },
+ },
+ },
+ {
+ "name": "remarks_type_linear",
+ "getval": re.compile(
+ r"""^(access-list)
+ (\s(?P<acl_name_linear>\S+))?
+ (\sremark\s(?P<remarks>.+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "remark {{ remarks }}",
+ "result": {
+ "acls": {
+ "{{ acl_name_linear|d() }}": {
+ "name": "{{ acl_name_linear }}",
+ "aces": [{"remarks": "{{ remarks }}"}],
+ },
+ },
+ },
+ },
+ {
+ "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+,))?
+ (\s*(?P<any>any))?
+ (\swildcard\sbits\s(?P<wildcard>\S+))?
+ (\shost\s(?P<host>\S+))?
+ (\s(?P<log>log))?
+ $""",
+ re.VERBOSE,
+ ),
+ "compval": "aces",
+ "result": {
+ "acls": {
+ "{{ acl_name|d() }}": {
+ "name": "{{ acl_name }}",
+ "aces": [
+ {
+ "sequence": "{{ sequence }}",
+ "grant": "{{ grant }}",
+ "source": {
+ "address": "{{ address }}",
+ "wildcard_bits": "{{ wildcard }}",
+ "any": "{{ not not any }}",
+ "host": "{{ host }}",
+ },
+ "log": {"set": "{{ not not log }}"},
+ },
+ ],
+ },
+ },
+ },
+ },
+ {
+ "name": "aces",
+ "getval": re.compile(
+ r"""\s*((?P<sequence>\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<source_any>any))|
+ (\sobject-group\s(?P<source_obj_grp>\S+))|
+ (\shost\s(?P<source_host>\S+))|
+ (\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+)))?
+ (\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<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+)))?
+ (\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))?
+ (\soption\s(?P<option>\S+|\d+))?
+ (\sprecedence\s(?P<precedence>\S+))?
+ (\stime-range\s(?P<time_range>\S+))?
+ (\stos\s(?P<tos>\S+|\d+))?
+ (\sttl\seq\s(?P<ttl_eq>\d+))?
+ (\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,
+ ),
+ "setval": _tmplt_access_list_entries,
+ "compval": "aces",
+ "result": {
+ "acls": {
+ "{{ acl_name|d() }}": {
+ "name": "{{ acl_name }}",
+ "aces": [
+ {
+ "sequence": "{% if sequence is defined %}{{ sequence \
+ }}{% elif sequence_ipv6 is defined %}{{ sequence_ipv6 }}{% endif %}",
+ "grant": "{{ grant }}",
+ "evaluate": "{{ evaluate }}",
+ "protocol": "{{ protocol }}",
+ "protocol_number": "{{ protocol_num }}",
+ "icmp_igmp_tcp_protocol": "{{ icmp_igmp_tcp_protocol }}",
+ "source": {
+ "address": "{{ 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 }}",
+ "range": {
+ "start": "{{ srange_start if srange_start is defined else None }}",
+ "end": "{{ srange_end if srange_end is defined else None }}",
+ },
+ },
+ },
+ "destination": {
+ "address": "{{ 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 }}",
+ "range": {
+ "start": "{{ drange_start if drange_start is defined else None }}",
+ "end": "{{ drange_end if drange_end is defined else None }}",
+ },
+ },
+ },
+ "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 '' }}",
+ },
+ "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 }}",
+ },
+ "option": {
+ "{{ option if option is defined else None }}": "{{ True if option is defined else None }}",
+ },
+ "precedence": "{{ precedence }}",
+ "time_range": "{{ time_range }}",
+ "tos": {
+ "max_reliability": "{{ True if tos is defined and 'max-reliability' in tos else '' }}",
+ "max_throughput": "{{ True if tos is defined and 'max-throughput' in tos else '' }}",
+ "min_delay": "{{ True if tos is defined and 'min-delay' in tos else '' }}",
+ "min_monetary_cost": "{{ True if tos is defined and 'min-monetary-cost' in tos else '' }}",
+ "normal": "{{ True if tos is defined and 'normal' in tos else '' }}",
+ "service_value": "{{ tos if tos is defined else None }}",
+ },
+ "ttl": {
+ "eq": "{{ ttl_eq }}",
+ "gt": "{{ ttl_gt }}",
+ "lt": "{{ ttl_lt }}",
+ "neq": "{{ ttl_neq }}",
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+ ]
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
new file mode 100644
index 000000000..b9654956c
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/bgp_address_family.py
@@ -0,0 +1,2673 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 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 Bgp_address_family 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,
+)
+
+
+UNIQUE_AFI = "{{ afi|d() + '_' + safi|d() + '_' + vrf|d() }}"
+UNIQUE_NEIB_ADD = "{{ neighbor_address }}"
+
+
+class Bgp_address_familyTemplate(NetworkTemplate):
+ def __init__(self, lines=None, module=None):
+ super(Bgp_address_familyTemplate, self).__init__(lines=lines, tmplt=self, module=module)
+
+ PARSERS = [
+ {
+ "name": "as_number",
+ "getval": re.compile(
+ r"""
+ ^router\sbgp
+ (\s(?P<as_number>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "router bgp {{ as_number }}",
+ "result": {"as_number": "{{ as_number }}"},
+ "shared": True,
+ },
+ {
+ "name": "afi",
+ "getval": re.compile(
+ r"""
+ \saddress-family
+ (\s(?P<afi>ipv4|ipv6|l2vpn|nsap|rtfilter|vpnv4|vpnv6))?
+ (\s(?P<safi>flowspec|mdt|multicast|mvpn|unicast|evpn|vpls))?
+ (\svrf\s(?P<vrf>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "address-family"
+ "{{ (' ' + afi) if afi is defined else '' }}"
+ "{{ (' ' + safi) if safi is defined else '' }}"
+ "{{ (' vrf ' + vrf) if vrf is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {"afi": "{{ afi }}", "safi": "{{ safi }}", "vrf": "{{ vrf }}"},
+ },
+ },
+ "shared": True,
+ },
+ {
+ "name": "aggregate_addresses",
+ "getval": re.compile(
+ r"""
+ \s\saggregate-address
+ (\s(?P<address>\S+))?
+ (\s(?P<netmask>\S+))?
+ (\s(?P<as_set>as-set))?
+ (\s(?P<summary_only>summary-only))?
+ (\s(?P<as_confed_set>as-confed-set))?
+ (\sadvertise-map\s(?P<advertise_map>\S+))?
+ (\sattribute-map\s(?P<attribute_map>\S+))?
+ (\ssuppress-map\s(?P<suppress_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "aggregate-address "
+ "{{ address }} {{ netmask }}"
+ "{{ ' as-set' if as_set|d(False) else ''}}"
+ "{{ ' summary-only' if summary_only|d(False) else ''}}"
+ "{{ ' as-confed-set' if as_confed_set|d(False) else ''}}"
+ "{{ (' advertise-map ' + advertise_map) if advertise_map is defined else '' }}"
+ "{{ (' attribute-map ' + attribute_map) if attribute_map is defined else '' }}"
+ "{{ (' suppress-map ' + suppress_map) if suppress_map is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "aggregate_addresses": [
+ {
+ "address": "{{ address }}",
+ "netmask": "{{ netmask }}",
+ "advertise_map": "{{ advertise_map }}",
+ "as_confed_set": "{{ not not as_confed_set }}",
+ "as_set": "{{ not not as_set }}",
+ "attribute_map": "{{ attribute_map }}",
+ "suppress_map": "{{ suppress_map }}",
+ "summary_only": "{{ not not summary_only }}",
+ },
+ ],
+ },
+ },
+ },
+ },
+ {
+ "name": "auto_summary",
+ "getval": re.compile(
+ r"""
+ ((\s\sauto-summary))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "auto-summary",
+ "result": {"address_family": {UNIQUE_AFI: {"auto_summary": True}}},
+ },
+ {
+ "name": "table_map",
+ "getval": re.compile(
+ r"""
+ \s\stable-map
+ (\s(?P<name>\S+))?
+ (\s(?P<filter>filter))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "table-map"
+ "{{ (' ' + table_map.name) if table_map.name is defined else '' }}"
+ "{{ (' filter' ) if table_map.filter|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "table_map": {"name": "{{ name }}", "filter": "{{ not not filter }}"},
+ },
+ },
+ },
+ },
+ {
+ "name": "default",
+ "getval": re.compile(r"""\s\sdefault$""", re.VERBOSE),
+ "setval": "default",
+ "result": {"address_family": {UNIQUE_AFI: {"default": True}}},
+ },
+ {
+ "name": "default_information",
+ "getval": re.compile(r"""\s\sdefault-information\soriginate$""", re.VERBOSE),
+ "setval": "default-information originate",
+ "result": {"address_family": {UNIQUE_AFI: {"default_information": True}}},
+ },
+ {
+ "name": "default_metric",
+ "getval": re.compile(
+ r"""\s\sdefault-metric
+ (\s(?P<default_metric>\d+))
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "default-metric {{ default_metric|string }}",
+ "result": {"address_family": {UNIQUE_AFI: {"default_metric": "{{ default_metric }}"}}},
+ },
+ {
+ "name": "distance",
+ "getval": re.compile(
+ r"""\s\sdistance\sbgp
+ (\s(?P<external>\d+))
+ (\s(?P<internal>\d+))
+ (\s(?P<local>\d+))
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "distance bgp {{ distance.external|string }} {{ distance.internal|string }} {{ distance.local|string }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "distance": {
+ "external": "{{ external }}",
+ "internal": "{{ internal }}",
+ "local": "{{ local }}",
+ },
+ },
+ },
+ },
+ },
+ # bgp starts
+ {
+ "name": "bgp.additional_paths.select",
+ "getval": re.compile(
+ r"""
+ \s\sbgp\sadditional-paths\sselect
+ (\s(?P<select_all>all))?
+ (\s(?P<select_backup>backup))?
+ (\s(?P<select_best_ext>best-external))?
+ (\s(?P<select_group_best>group-best))?
+ (\sbest\s(?P<select_best>\d))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp additional-paths select"
+ "{{ (' all' ) if bgp.additional_paths.select.all|d(False) else '' }}"
+ "{{ (' backup' ) if bgp.additional_paths.select.backup|d(False) else '' }}"
+ "{{ (' best-external' ) if bgp.additional_paths.select.best_external|d(False) else '' }}"
+ "{{ (' group-best' ) if bgp.additional_paths.select.group_best|d(False) else '' }}"
+ "{{ (' best ' + bgp.additional_paths.select.best|string ) if bgp.additional_paths.select.best is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "bgp": {
+ "additional_paths": {
+ "select": {
+ "all": "{{ not not select_all }}",
+ "backup": "{{ not not select_backup }}",
+ "best": "{{ select_best }}",
+ "group_best": "{{ not not select_group_best }}",
+ "best_external": "{{ not not select_best_ext }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "bgp.additional_paths.install",
+ "getval": re.compile(
+ r"""
+ \s\sbgp\sadditional-paths\sinstall$""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp additional-paths select install",
+ "result": {
+ "address_family": {UNIQUE_AFI: {"bgp": {"additional_paths": {"install": True}}}},
+ },
+ },
+ {
+ "name": "bgp.additional_paths.receive",
+ "getval": re.compile(
+ r"""
+ \s\sbgp\sadditional-paths\sreceive$""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp additional-paths select receive",
+ "result": {
+ "address_family": {UNIQUE_AFI: {"bgp": {"additional_paths": {"receive": True}}}},
+ },
+ },
+ {
+ "name": "bgp.additional_paths.send",
+ "getval": re.compile(
+ r"""
+ \s\sbgp\sadditional-paths\ssend$""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp additional-paths select send",
+ "result": {
+ "address_family": {UNIQUE_AFI: {"bgp": {"additional_paths": {"send": True}}}},
+ },
+ },
+ {
+ "name": "bgp.aggregate_timer",
+ "getval": re.compile(
+ r"""
+ \s\sbgp\saggregate-timer
+ (\s(?P<aggregate_timer>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp aggregate-timer {{ bgp.aggregate_timer }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {"bgp": {"aggregate_timer": "{{ aggregate_timer }}"}},
+ },
+ },
+ },
+ {
+ "name": "bgp.dmzlink_bw",
+ "getval": re.compile(
+ r"""
+ \s\sbgp\sdmzlink-bw
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp dmzlink-bw",
+ "result": {"address_family": {UNIQUE_AFI: {"bgp": {"dmzlink_bw": True}}}},
+ },
+ {
+ "name": "bgp.nexthop.route_map",
+ "getval": re.compile(
+ r"""
+ \s\sbgp\snexthop\sroute-map
+ (\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp nexthop route-map {{ bgp.nexthop.route_map }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {"bgp": {"nexthop": {"route_map": "{{ route_map }}"}}},
+ },
+ },
+ },
+ {
+ "name": "bgp.nexthop.trigger.delay",
+ "getval": re.compile(
+ r"""
+ \s\sbgp\snexthop\strigger\sdelay
+ (\s(?P<delay>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp nexthop trigger delay {{ bgp.nexthop.trigger.delay|string }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {"bgp": {"nexthop": {"trigger": {"delay": "{{ delay }}"}}}},
+ },
+ },
+ },
+ {
+ "name": "bgp.nexthop.trigger.enable",
+ "getval": re.compile(
+ r"""
+ \s\sbgp\snexthop\strigger\sdelay\senable
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp nexthop trigger delay enable",
+ "result": {
+ "address_family": {UNIQUE_AFI: {"bgp": {"nexthop": {"trigger": {"enable": True}}}}},
+ },
+ },
+ {
+ "name": "bgp.redistribute_internal",
+ "getval": re.compile(
+ r"""
+ \s\sbgp\sredistribute-internal
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp redistribute-internal",
+ "result": {"address_family": {UNIQUE_AFI: {"bgp": {"redistribute_internal": True}}}},
+ },
+ {
+ "name": "bgp.route_map",
+ "getval": re.compile(
+ r"""
+ \s\sbgp\sroute-map\spriority
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp route-map priority",
+ "result": {"address_family": {UNIQUE_AFI: {"bgp": {"route_map": True}}}},
+ },
+ {
+ "name": "bgp.scan_time",
+ "getval": re.compile(
+ r"""
+ \s\sbgp\sscan-time
+ (\s(?P<scan_time>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp scan-time {{ bgp.scan_time }}",
+ "result": {"address_family": {UNIQUE_AFI: {"bgp": {"scan_time": "{{ scan_time }}"}}}},
+ },
+ {
+ "name": "bgp.soft_reconfig_backup",
+ "getval": re.compile(
+ r"""
+ \s\sbgp\ssoft-reconfig-backup
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp soft-reconfig-backup",
+ "result": {"address_family": {UNIQUE_AFI: {"bgp": {"soft_reconfig_backup": True}}}},
+ },
+ {
+ "name": "bgp.update_group",
+ "getval": re.compile(
+ r"""
+ \s\sbgp\supdate-group\ssplit\sas-override
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp update-group split as-override",
+ "result": {"address_family": {UNIQUE_AFI: {"bgp": {"update_group": True}}}},
+ },
+ {
+ "name": "bgp.dampening",
+ "getval": re.compile(
+ r"""\s\sbgp\sdampening
+ (\s(?P<penalty_half_time>\d+))?
+ (\s(?P<reuse_route_val>\d+))?
+ (\s(?P<suppress_route_val>\d+))?
+ (\s(?P<max_suppress>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp dampening"
+ "{{ (' ' + bgp.dampening.penalty_half_time|string ) if bgp.dampening.penalty_half_time is defined else '' }}"
+ "{{ (' ' + bgp.dampening.reuse_route_val|string ) if bgp.dampening.reuse_route_val is defined else '' }}"
+ "{{ (' ' + bgp.dampening.suppress_route_val|string ) if bgp.dampening.suppress_route_val is defined else '' }}"
+ "{{ (' ' + bgp.dampening.max_suppress|string ) if bgp.dampening.max_suppress is defined else '' }}"
+ "{{ (' route-map ' + bgp.dampening.route_map ) if bgp.dampening.route_map is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "bgp": {
+ "dampening": {
+ "penalty_half_time": "{{ penalty_half_time }}",
+ "reuse_route_val": "{{ reuse_route_val }}",
+ "suppress_route_val": "{{ suppress_route_val }}",
+ "max_suppress": "{{ max_suppress }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "bgp.slow_peer_options.detection.enable",
+ "getval": re.compile(r"""\s\sbgp\sslow-peer\sdetection$""", re.VERBOSE),
+ "setval": "bgp slow-peer detection",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {"bgp": {"slow_peer_options": {"detection": {"enable": True}}}},
+ },
+ },
+ },
+ {
+ "name": "bgp.slow_peer_options.detection.threshold",
+ "getval": re.compile(
+ r"""
+ \s\sbgp\sslow-peer\sdetection\sthreshold
+ (\s(?P<threshold>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp slow-peer detection threshold {{ bgp.slow_peer_options.detection.threshold }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "bgp": {
+ "slow_peer_options": {"detection": {"threshold": "{{ threshold }}"}},
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "bgp.slow_peer_options.split_update_group.dynamic",
+ "getval": re.compile(
+ r"""
+ \s\sbgp\sslow-peer\ssplit-update-group\sdynamic$""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp slow-peer split-update-group dynamic",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "bgp": {"slow_peer_options": {"split_update_group": {"dynamic": True}}},
+ },
+ },
+ },
+ },
+ {
+ "name": "bgp.slow_peer.split_update_group.permanent",
+ "getval": re.compile(
+ r"""
+ \s\sbgp\sslow-peer\ssplit-update-group\sdynamic\spermanent$""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp slow-peer split-update-group dynamic permanent",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "bgp": {"slow_peer_options": {"split_update_group": {"permanent": True}}},
+ },
+ },
+ },
+ },
+ # bgp ends
+ # neighbor starts
+ {
+ "name": "peer_group_name",
+ "getval": re.compile(
+ r"""\s\sneighbor\s(?P<neighbor_address>\S+)
+ \speer-group\s(?P<peer_group_name>\S+)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }}"
+ "{{ (' peer-group ' + peer_group_name) if peer_group_name|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "peer_group_name": "{{ peer_group_name }}",
+ "neighbor_address": UNIQUE_NEIB_ADD,
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "peer_group",
+ "getval": re.compile(
+ r"""\s\sneighbor\s(?P<neighbor_address>\S+)\speer-group$""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} peer-group",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "peer_group": True,
+ "neighbor_address": UNIQUE_NEIB_ADD,
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "remote_as",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\s(?P<remote_as>remote-as)
+ (\s(?P<number>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} remote-as"
+ "{{ (' ' + remote_as|string) if remote_as is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {"neighbors": {UNIQUE_NEIB_ADD: {"remote_as": "{{ number }}"}}},
+ },
+ },
+ },
+ {
+ "name": "local_as",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\s(?P<local_as>local-as)
+ (\s(?P<number>\S+))?
+ (\s(?P<dual_as>dual-as))?
+ (\s(?P<no_prepend>no-prepend))?
+ (\s(?P<replace_as>replace-as))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} local-as"
+ "{{ (' ' + local_as.number|string) if local_as.number is defined else '' }}"
+ "{{ (' dual-as') if local_as.dual_as is defined else '' }}"
+ "{{ (' no-prepend') if local_as.no_prepend.set is defined else '' }}"
+ "{{ (' replace-as') if local_as.no_prepend.replace_as is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "local_as": {
+ "set": "{{ not not local_as }}",
+ "number": "{{ number }}",
+ "dual_as": "{{ not not dual_as }}",
+ "no_prepend": {
+ "set": "{{ not not no_prepend }}",
+ "replace_as": "{{ not not replace_as }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "neighbor_address",
+ "getval": re.compile(
+ r"""
+ \sneighbordelDummy(?P<neighbor_address>\S+)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }}",
+ "result": {"dummy_neighbor": True},
+ },
+ {
+ "name": "activate",
+ "getval": re.compile(
+ r"""\s\sneighbor\s(?P<neighbor_address>\S+)\sactivate$""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} activate",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "neighbor_address": UNIQUE_NEIB_ADD,
+ "activate": True,
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "additional_paths",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sadditional-paths
+ (\s(?P<disable>disable))?
+ (\s(?P<receive>receive))?
+ (\s(?P<send>send))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} additional-paths"
+ "{{ (' disable') if additional_paths.disable|d(False) else '' }}"
+ "{{ (' receive') if additional_paths.receive|d(False) else '' }}"
+ "{{ (' send') if additional_paths.send|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "additional_paths": {
+ "disable": "{{ not not disable }}",
+ "receive": "{{ not not receive }}",
+ "send": "{{ not not send }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "advertises.additional_paths",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sadvertise\sadditional-paths
+ (\s(?P<all>all))?
+ (\sbest\s(?P<receive>\d+))?
+ (\s(?P<group_best>group-best))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} advertise additional-paths"
+ "{{ (' all') if advertise.additional_paths.all|d(False) else '' }}"
+ "{{ (' best '+ best|string) if advertise.additional_paths.best|d(False) else '' }}"
+ "{{ (' group-best') if advertise.additional_paths.group_best|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "advertises": {
+ "additional_paths": {
+ "all": "{{ not not all }}",
+ "best": "{{ receive }}",
+ "group_best": "{{ not not group_best }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "advertises.best_external",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sadvertise\sbest-external
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }}"
+ "{{ (' advertise best-external') if advertise.best_external|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {UNIQUE_NEIB_ADD: {"advertises": {"best-external": True}}},
+ },
+ },
+ },
+ },
+ {
+ "name": "advertises.diverse_path",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sadvertise\sdiverse-path
+ (\s(?P<backup>backup))?
+ (\s(?P<mpath>mpath))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} advertise diverse-path"
+ "{{ (' backup') if advertise.diverse_path.backup|d(False) else '' }}"
+ "{{ (' mpath') if advertise.diverse_path.mpath|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "advertises": {
+ "diverse_path": {
+ "backup": "{{ not not backup }}",
+ "mpath": "{{ not not mpath }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "advertise_map",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sadvertise-map
+ (\s(?P<name>\S+))?
+ (\sexist-map\s(?P<exist_map>\S+))?
+ (\snon-exist-map\s(?P<non_exist_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} advertise-map"
+ "{{ (' ' + name) if advertise_map.name is defined else '' }}"
+ "{{ (' exist-map ' + exist_map) if advertise_map.exist_map is defined else '' }}"
+ "{{ (' non-exist-map ' + non_exist_map) if advertise_map.non_exist_map is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "advertise_map": {
+ "name": "{{ name }}",
+ "exist_map": "{{ exist_map }}",
+ "non_exist_map": "{{ non_exist_map }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "advertisement_interval",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sadvertisement-interval
+ (\s(?P<advertisement_interval>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} advertisement-interval"
+ "{{ (' ' + advertisement_interval|string) if advertisement_interval is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "advertisement_interval": "{{ advertisement_interval }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "aigp",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\saigp
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' aigp') if aigp.enable|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {"neighbors": {UNIQUE_NEIB_ADD: {"aigp": {"enable": True}}}},
+ },
+ },
+ },
+ {
+ "name": "aigp.send.cost_community",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\saigp\ssend\scost-community
+ (\s(?P<id>\d+))\spoi
+ (\s(?P<igp_cost>igp-cost))?
+ (\s(?P<pre_bestpath>pre-bestpath))?
+ (\s(?P<transitive>transitive))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} aigp send cost-community"
+ "{{ (' ' + aigp.send.cost_community.id|string + ' poi') if aigp.send.cost_community.id is defined else '' }}"
+ "{{ (' igp-cost') if aigp.send.cost_community.poi.igp_cost|d(False) else '' }}"
+ "{{ (' pre-bestpath') if aigp.send.cost_community.poi.pre_bestpath|d(False) else '' }}"
+ "{{ (' transitive') if aigp.send.cost_community.poi.transitive|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "aigp": {
+ "send": {
+ "cost_community": {
+ "id": "{{ id }}",
+ "poi": {
+ "igp_cost": "{{ not not igp_cost }}",
+ "pre_bestpath": "{{ not not pre_bestpath }}",
+ "transitive": "{{ not not transitive }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "aigp.send.med",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\saigp\ssend\smed
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }}"
+ "{{ (' aigp send med') if aigp.send.med|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {"neighbors": {UNIQUE_NEIB_ADD: {"aigp": {"send": {"med": True}}}}},
+ },
+ },
+ },
+ {
+ "name": "allow_policy",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sallow-policy
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' allow-policy') if allow_policy|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {"neighbors": {UNIQUE_NEIB_ADD: {"allow_policy": True}}},
+ },
+ },
+ },
+ {
+ "name": "allowas_in",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sallowas-in
+ (\s(?P<allowas_in>\d+))
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }}"
+ "{{ (' allowas-in ' + allowas_in|string) if allowas_in is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {UNIQUE_NEIB_ADD: {"allowas_in": "{{ allowas_in }}"}},
+ },
+ },
+ },
+ },
+ {
+ "name": "as_override",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sas-override
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }}"
+ "{{ (' as-override') if as_override|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {"neighbors": {UNIQUE_NEIB_ADD: {"as_override": True}}},
+ },
+ },
+ },
+ {
+ "name": "bmp_activate",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sbmp-activate
+ (\sserver\s(?P<server>\d+))?
+ (\s(?P<all>all))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} bmp-activate"
+ "{{ (' server '+ bmp_activate.server|string) if bmp_activate.server is defined else '' }}"
+ "{{ (' all') if bmp_activate.all|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "neighbor_address": UNIQUE_NEIB_ADD,
+ "bmp_activate": {
+ "server": "{{ server }}",
+ "all": "{{ not not all }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "capability",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\scapability\sorf\sprefix-list
+ (\s(?P<both>both))?
+ (\s(?P<receive>receive))?
+ (\s(?P<send>send))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} capability orf prefix-list"
+ "{{ (' both') if capability.both|d(False) else '' }}"
+ "{{ (' receive') if capability.receive|d(False) else '' }}"
+ "{{ (' send') if capability.send|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "capability": {
+ "both": "{{ not not both }}",
+ "receive": "{{ not not receive }}",
+ "send": "{{ not not send }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "cluster_id",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\scluster-id(\s(?P<cluster_id>\s\d+))$""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} cluster-id {{ cluster_id }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {UNIQUE_NEIB_ADD: {"cluster_id": "{{ cluster_id }}"}},
+ },
+ },
+ },
+ },
+ {
+ "name": "default_originate",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sdefault-originate$""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' default-originate') if default_originate.set|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {UNIQUE_NEIB_ADD: {"default_originate": {"set": True}}},
+ },
+ },
+ },
+ },
+ {
+ "name": "default_originate.route_map",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sdefault-originate
+ (\sroute-map\s(?P<route_map>\S+))
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} default-originate"
+ "{{ (' route-map' + default_originate.route_map) if default_originate.route_map is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "default_originate": {"route_map": "{{ route_map }}"},
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "description",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sdescription\s(?P<description>\S.+)$""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} description {{ description }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "neighbor_address": UNIQUE_NEIB_ADD,
+ "description": "{{ description }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "disable_connected_check",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)
+ \s(?P<disable_connected_check>disable-connected-check)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} disable-connected-check",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "disable_connected_check": "{{ not not disable_connected_check }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "ebgp_multihop",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)
+ \s(?P<enable>ebgp_multihop)
+ (\s(?P<hop_count>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} ebgp-multihop"
+ "{{ (' ' + hop_count|string) if hop_count is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "ebgp_multihop": {
+ "enable": "{{ not not enable }}",
+ "hop_count": "{{ hop_count }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "distribute_list",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sdistribute-list
+ (\s(?P<acl>\S+))
+ (\s(?P<in>in))?
+ (\s(?P<out>out))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} distribute-list"
+ "{{ (' ' + distribute_list.acl) if distribute_list.acl is defined else '' }}"
+ "{{ (' in') if distribute_list.in|d(False) else '' }}"
+ "{{ (' out') if distribute_list.out|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "distribute_list": {
+ "acl": "{{ acl }}",
+ "in": "{{ not not in }}",
+ "out": "{{ not not out }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "dmzlink_bw",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sdmzlink-bw
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' dmzlink-bw') if dmzlink_bw|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {"neighbors": {UNIQUE_NEIB_ADD: {"dmzlink_bw": True}}},
+ },
+ },
+ },
+ {
+ "name": "filter_list",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sfilter-list
+ (\s(?P<acl>\S+))
+ (\s(?P<in>in))?
+ (\s(?P<out>out))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} filter-list"
+ "{{ (' ' + filter_list.as_path_acl) 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": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "filter_list": {
+ "as_path_acl": "{{ acl }}",
+ "in": "{{ not not in }}",
+ "out": "{{ not not out }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "fall_over.bfd",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sfall-over
+ \s(?P<set>bfd)
+ (\s(?P<multi_hop>multi-hop))?
+ (\s(?P<single_hop>single-hop))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} fall-over"
+ "{{ (' bfd') if fall_over.bfd.set is defined else '' }}"
+ "{{ (' multi-hop') if fall_over.bfd.multi_hop is defined else '' }}"
+ "{{ (' single-hop') if fall_over.bfd.single_hop is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "fall_over": {
+ "bfd": {
+ "set": "{{ not not set }}",
+ "multi_hop": "{{ not not multi_hop }}",
+ "single_hop": "{{ not not single_hop }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "fall_over.route_map",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sroute-map
+ \s(?P<route_map>\S+)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} route-map {{ fall_over.route_map }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "fall_over": {"route_map": "{{ not not route_map }}"},
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "ha_mode",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sha-mode
+ \s(?P<set>graceful-restart)
+ (\s(?P<disable>disable))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} ha-mode"
+ "{{ (' graceful-restart') if ha_mode.set is defined else '' }}"
+ "{{ (' disable') if ha_mode.disable is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "ha_mode": {
+ "set": "{{ not not set }}",
+ "disable": "{{ not not disable }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "inherit",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sinherit\speer-session
+ \s(?P<inherit>\S+)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} inherit peer-session"
+ "{{ (' ' + inherit) if inherit is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {"neighbors": {UNIQUE_NEIB_ADD: {"inherit": "{{ inherit }}"}}},
+ },
+ },
+ },
+ {
+ "name": "internal_vpn_client",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sinternal-vpn-client
+ \s(?P<inherit>\S+)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} internal-vpn-client",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {"neighbors": {UNIQUE_NEIB_ADD: {"internal_vpn_client": True}}},
+ },
+ },
+ },
+ {
+ "name": "log_neighbor_changes",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)
+ \s(?P<set>log-neighbor-changes)
+ (\s(?P<disable>disable))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }}"
+ "{{ (' log-neighbor-changes') if log_neighbor_changes.set is defined else '' }}"
+ "{{ (' disable') if log_neighbor_changes.disable is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "neighbor_address": UNIQUE_NEIB_ADD,
+ "log_neighbor_changes": {
+ "set": "{{ not not set }}",
+ "disable": "{{ not not disable }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "maximum_prefix",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\smaximum-prefix
+ (\s(?P<max_no>\d+))
+ (\s(?P<threshold_val>\d+))?
+ (\srestart\s(?P<restart>\d+))?
+ (\s(?P<warning_only>warning-only))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} maximum-prefix"
+ "{{ (' ' + maximum_prefix.number|string) if maximum_prefix.number is defined else '' }}"
+ "{{ (' ' + maximum_prefix.threshold_value|string) if maximum_prefix.threshold_value is defined else '' }}"
+ "{{ (' restart ' + maximum_prefix.restart|string) if maximum_prefix.restart is defined else '' }}"
+ "{{ (' warning-only') if maximum_prefix.warning_only|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "maximum_prefix": {
+ "number": "{{ max_no }}",
+ "threshold_value": "{{ threshold_val }}",
+ "restart": "{{ restart }}",
+ "warning_only": "{{ not not warning_only }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "nexthop_self.set",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\snext-hop-self
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' next-hop-self') if nexthop_self.set|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {"neighbors": {UNIQUE_NEIB_ADD: {"nexthop_self": {"set": True}}}},
+ },
+ },
+ },
+ {
+ "name": "nexthop_self.all",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\snext-hop-self\sall
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' next-hop-self all') if nexthop_self.all|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {"neighbors": {UNIQUE_NEIB_ADD: {"nexthop_self": {"all": True}}}},
+ },
+ },
+ },
+ {
+ "name": "next_hop_unchanged.set",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\snext-hop-unchanged
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' next-hop-unchanged') if next_hop_unchanged.set|d(False) else ''}}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {UNIQUE_NEIB_ADD: {"next_hop_unchanged": {"set": True}}},
+ },
+ },
+ },
+ },
+ {
+ "name": "next_hop_unchanged.allpaths",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\snext-hop-unchanged\sallpaths
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' next-hop-unchanged allpaths') if next_hop_unchanged.allpaths|d(False) else ''}}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {UNIQUE_NEIB_ADD: {"next_hop_unchanged": {"allpaths": True}}},
+ },
+ },
+ },
+ },
+ {
+ "name": "password_options",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\spassword
+ \s(?P<encryption>\d+)
+ (\s(?P<pass_key>.$))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} password"
+ "{{ (' '+ password_options.encryption|string) if password_options.encryption is defined else '' }}"
+ "{{ (' '+ password_options.pass_key) if password_options.pass_key is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "neighbor_address": UNIQUE_NEIB_ADD,
+ "password_options": {
+ "encryption": "{{ encryption }}",
+ "pass_key": "{{ pass_key }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "path_attribute.discard",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\spath-attribute\sdiscard
+ (\s(?P<type>\d+))?
+ (\srange\s(?P<start>\d+)\s(?P<end>\d+))?
+ (\s(?P<in>in))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} path-attribute discard"
+ "{{ (' ' + type) if path_attribute.discard.type is defined else '' }}"
+ "{{ (' range '+ path_attribute.discard.range.start|string) if spath_attribute.discard.range.start is defined else '' }}"
+ "{{ (' '+ path_attribute.discard.range.end|string) if spath_attribute.discard.range.end is defined else '' }}"
+ "{{ (' in') if path_attribute.discard.in|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "path_attribute": {
+ "discard": {
+ "type": "{{ type }}",
+ "range": {"start": "{{ start }}", "end": "{{ end }}"},
+ "in": "{{ not not in }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "path_attribute.treat_as_withdraw",
+ "getval": re.compile(
+ r"""\s\sneighbor\s(?P<neighbor_address>\S+)\spath-attribute\streat-as-withdraw
+ (\s(?P<type>\d+))?
+ (\srange\s(?P<start>\d+)\s(?P<end>\d+))?
+ (\s(?P<in>in))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} path-attribute treat-as-withdraw"
+ "{{ (' ' + type) if path_attribute.treat_as_withdraw.type is defined else '' }}"
+ "{{ (' range '+ path_attribute.treat_as_withdraw.range.start|string) if spath_attribute.treat_as_withdraw.range.start is defined else '' }}"
+ "{{ (' '+ path_attribute.treat_as_withdraw.range.end|string) if spath_attribute.treat_as_withdraw.range.end is defined else '' }}"
+ "{{ (' in') if path_attribute.treat_as_withdraw.in|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "path_attribute": {
+ "treat_as_withdraw": {
+ "type": "{{ type }}",
+ "range": {"start": "{{ start }}", "end": "{{ end }}"},
+ "in": "{{ not not in }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "route_maps",
+ "getval": re.compile(
+ r"""\s\sneighbor\s(?P<neighbor_address>\S+)\sroute-map
+ (\s(?P<route_map>\S+))
+ (\s(?P<in>in))?
+ (\s(?P<out>out))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ route_maps.neighbor_address }} route-map"
+ "{{ (' ' + route_maps.name) if route_maps.name is defined else '' }}"
+ "{{ (' in') if route_maps.in|d(False) else '' }}"
+ "{{ (' out') if route_maps.out|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "neighbor_address": UNIQUE_NEIB_ADD,
+ "route_maps": [
+ {
+ "name": "{{ route_map }}",
+ "in": "{{ not not in }}",
+ "out": "{{ not not out }}",
+ },
+ ],
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "prefix_lists",
+ "getval": re.compile(
+ r"""\s\sneighbor\s(?P<neighbor_address>\S+)\sprefix-list
+ (\s(?P<prefix_list>\S+))
+ (\s(?P<in>in))?
+ (\s(?P<out>out))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ prefix_lists.neighbor_address }} prefix-list"
+ "{{ (' ' + prefix_lists.name) if prefix_lists.name is defined else '' }}"
+ "{{ (' in') if prefix_lists.in|d(False) else '' }}"
+ "{{ (' out') if prefix_lists.out|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "neighbor_address": UNIQUE_NEIB_ADD,
+ "prefix_lists": [
+ {
+ "name": "{{ prefix_list }}",
+ "in": "{{ not not in }}",
+ "out": "{{ not not out }}",
+ },
+ ],
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "remove_private_as.set",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sremove-private-as
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' remove-private-as') if remove_private_as.set|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {UNIQUE_NEIB_ADD: {"remove_private_as": {"set": True}}},
+ },
+ },
+ },
+ },
+ {
+ "name": "remove_private_as.all",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sremove-private-as\sall
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' remove-private-as all') if remove_private_as.all|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {UNIQUE_NEIB_ADD: {"remove_private_as": {"all": True}}},
+ },
+ },
+ },
+ },
+ {
+ "name": "remove_private_as.replace_as",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sremove-private-as\sreplace-as
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' remove-private-as replace-as') if remove_private_as.replace_as|d(False) else ''}}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {UNIQUE_NEIB_ADD: {"remove_private_as": {"replace_as": True}}},
+ },
+ },
+ },
+ },
+ {
+ "name": "route_reflector_client",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sroute-reflector-client
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' route-reflector-client') if route_reflector_client|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "neighbor_address": UNIQUE_NEIB_ADD,
+ "route_reflector_client": True,
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "route_server_client",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sroute-server-client
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' route-server-client') if route_server_client|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "neighbor_address": UNIQUE_NEIB_ADD,
+ "route_server_client": True,
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "send_community.set",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\ssend-community
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' send-community') if send_community.set|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {"neighbors": {UNIQUE_NEIB_ADD: {"send_community": {"set": True}}}},
+ },
+ },
+ },
+ {
+ "name": "send_community.both",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\ssend-community\sboth
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} send-community"
+ "{{ (' both') if send_community.both|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {UNIQUE_NEIB_ADD: {"send_community": {"both": True}}},
+ },
+ },
+ },
+ },
+ {
+ "name": "send_community.extended",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\ssend-community\sextended
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} send-community"
+ "{{ (' extended') if send_community.extended|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {UNIQUE_NEIB_ADD: {"send_community": {"extended": True}}},
+ },
+ },
+ },
+ },
+ {
+ "name": "send_community.standard",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\ssend-community\sstandard
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} send-community"
+ "{{ (' standard') if send_community.standard|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {UNIQUE_NEIB_ADD: {"send_community": {"standard": True}}},
+ },
+ },
+ },
+ },
+ {
+ "name": "shutdown",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sshutdown
+ (\sgraceful(?P<graceful>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }}"
+ "{{ (' shutdown') if shutdown.set is defined else '' }}"
+ "{{ (' graceful '+ shutdown.graceful|string) if shutdown.graceful is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "shutdown": {"set": True, "graceful": "{{ graceful }}"},
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "slow_peer_options.detection",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sslow-peer\sdetection
+ (\s(?P<enable>enable))?
+ (\s(?P<disable>disable))?
+ (\sthreshold\s(?P<threshold>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} slow-peer detection"
+ "{{ (' enable') if slow_peer_options.detection.enable|d(False) else '' }}"
+ "{{ (' disable') if slow_peer_options.detection.disable|d(False) else '' }}"
+ "{{ (' threshold ' + slow_peer_options.detection.threshold|string) if slow_peer_options.detection.threshold is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "slow_peer_options": {
+ "detection": {
+ "enable": "{{ not not enable }}",
+ "disable": "{{ not not disable }}",
+ "threshold": "{{ threshold }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "slow_peer_options.split_update_group",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sslow-peer\ssplit-update-group
+ (\s(?P<static>static))?
+ (\s(?P<dynamic>dynamic))?
+ (\s(?P<disable>disable))?
+ (\s(?P<permanent>permanent))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} slow-peer split-update-group"
+ "{{ (' static') if slow_peer_options.split_update_group.static|d(False) else '' }}"
+ "{{ (' dynamic') if slow_peer_options.split_update_group.dynamic.enable|d(False) else '' }}"
+ "{{ (' disable') if slow_peer_options.split_update_group.dynamic.disable|d(False) else '' }}"
+ "{{ (' permanent') if slow_peer_options.split_update_group.dynamic.permanent|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "slow_peer_options": {
+ "split_update_group": {
+ "static": "{{ not not static }}",
+ "dynamic": {
+ "enable": "{{ not not dynamic }}",
+ "disable": "{{ not not disable }}",
+ "permanent": "{{ not not permanent }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "soft_reconfiguration",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\ssoft-reconfiguration\sinbound
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }}"
+ "{{ (' soft-reconfiguration inbound') if soft_reconfiguration|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {"neighbors": {UNIQUE_NEIB_ADD: {"soft_reconfiguration": True}}},
+ },
+ },
+ },
+ {
+ "name": "soo",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\ssoo
+ (\s(?P<soo>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} soo {{ soo }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {"neighbors": {UNIQUE_NEIB_ADD: {"soo": "{{ soo }}"}}},
+ },
+ },
+ },
+ {
+ "name": "timers",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\stimers
+ (\s(?P<keepalive>\d+))?
+ (\s(?P<holdtime>\d+))?
+ (\s(?P<min_holdtime>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} timers"
+ "{{ (' ' + timers.interval|string) if timers.interval is defined else '' }}"
+ "{{ (' ' + timers.holdtime|string) if timers.holdtime is defined else '' }}"
+ "{{ (' ' + timers.min_holdtime|string) if timers.min_holdtime is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "timers": {
+ "interval": "{{ keepalive }}",
+ "holdtime": "{{ holdtime }}",
+ "min_holdtime": "{{ min_holdtime }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "transport.connection_mode",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\stransport\sconnection-mode
+ (\s(?P<active>active))?
+ (\s(?P<passive>passive))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} transport connection-mode"
+ "{{ (' active') if transport.connection_mode.active|d(False) else '' }}"
+ "{{ (' passive') if transport.connection_mode.passive|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "transport": {
+ "connection_mode": {
+ "active": "{{ not not active }}",
+ "passive": "{{ not not passive }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "transport.multi_session",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\stransport\smulti-session
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} transport multi-session",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "neighbor_address": UNIQUE_NEIB_ADD,
+ "transport": {"multi_session": True},
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "transport.path_mtu_discovery",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\stransport\spath-mtu-discovery
+ (\s(?P<disable>disable))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} transport"
+ "{{ (' path-mtu-discovery') if transport.path_mtu_discovery.set|d(False) else '' }}"
+ "{{ (' disable') if transport.path_mtu_discovery.disable|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "transport": {
+ "path_mtu_discovery": {
+ "set": True,
+ "disable": "{{ not not disable }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "ttl_security",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sttl-security
+ (\shops(?P<ttl_security>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} ttl-security"
+ "{{ (' hops '+ ttl_security|string) if ttl_security is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {UNIQUE_NEIB_ADD: {"ttl_security": "{{ ttl_security }}"}},
+ },
+ },
+ },
+ },
+ {
+ "name": "unsuppress_map",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sunsuppress-map
+ (\s(?P<unsuppress_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} unsuppress-map"
+ "{{ (' ' + unsuppress_map) if unsuppress_map is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {UNIQUE_NEIB_ADD: {"unsuppress_map": "{{ unsuppress_map }}"}},
+ },
+ },
+ },
+ },
+ {
+ "name": "version",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sversion
+ (\s(?P<version>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} version"
+ "{{ (' ' + version|string) if version is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "neighbors": {
+ UNIQUE_NEIB_ADD: {
+ "neighbor_address": UNIQUE_NEIB_ADD,
+ "version": "{{ version }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "weight",
+ "getval": re.compile(
+ r"""
+ \s\sneighbor\s(?P<neighbor_address>\S+)\sweight
+ (\s(?P<weight>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} weight"
+ "{{ (' ' + weight|string) if weight is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {"neighbors": {UNIQUE_NEIB_ADD: {"weight": "{{ weight }}"}}},
+ },
+ },
+ },
+ # neighbors end
+ {
+ "name": "networks",
+ "getval": re.compile(
+ r"""
+ \s\snetwork
+ (\s(?P<address>\S+))?
+ (\smask\s(?P<netmask>\S+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ (\s(?P<backdoor>backdoor))?
+ (\s(?P<evpn>evpn))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "network"
+ "{{ (' ' + address) if address is defined else '' }}"
+ "{{ (' mask ' + mask) if mask is defined else '' }}"
+ "{{ (' route-map ' + route_map) if route_map is defined else '' }}"
+ "{{ (' backdoor' ) if backdoor|d(False) else '' }}"
+ "{{ (' evpn' ) if evpn|d(False) else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "networks": [
+ {
+ "address": "{{ address }}",
+ "mask": "{{ netmask }}",
+ "route_map": "{{ route_map }}",
+ "evpn": "{{ not not evpn }}",
+ "backdoor": "{{ not not backdoor }}",
+ },
+ ],
+ },
+ },
+ },
+ },
+ {
+ "name": "snmp.context.user",
+ "getval": re.compile(
+ r"""\s\ssnmp
+ (\scontext\s(?P<context>\S+))
+ (\suser\s(?P<user>\S+))
+ (\s(?P<credential>credential))?
+ (\s(?P<encrypted>encrypted))?
+ (\sauth\smd5\s(?P<md5>\S+))?
+ (\sauth\ssha\s(?P<sha>\S+))?
+ (\spriv\saes\s128\s(?P<a>\S+))?
+ (\spriv\saes\s192\s(?P<b>\S+))?
+ (\spriv\saes\s256\s(?P<c>\S+))?
+ (\spriv\sdes\s(?P<des>\S+))?
+ (\spriv\sdes56\s(?P<des56>\S+))?
+ (\saccess\sipv6\s(?P<aclv6>\S+))?
+ (\saccess\s(?P<acl>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "snmp context {{ snmp.context.name }} user"
+ "{{ (' ' + snmp.context.user.name) if snmp.context.user.name is defined else '' }}"
+ "{{ (' credential' ) if snmp.context.user.credential|d(False) else '' }}"
+ "{{ (' encrypted' ) if snmp.context.user.encrypted|d(False) else '' }}"
+ "{{ (' auth md5 ' + snmp.context.user.auth.md5 ) if snmp.context.user.auth is defined and snmp.context.user.auth.acl is defined else '' }}"
+ "{{ (' auth sha ' + snmp.context.user.auth.sha ) if snmp.context.user.auth is defined and snmp.context.user.auth.sha is defined else '' }}"
+ "{{ (' priv md5 ' + snmp.context.user.priv.aes128 ) if snmp.context.user.priv is defined and snmp.context.user.priv.aes128 is defined else '' }}"
+ "{{ (' priv sha ' + snmp.context.user.priv.aes192 ) if snmp.context.user.priv is defined and snmp.context.user.priv.aes192 is defined else '' }}"
+ "{{ (' priv sha ' + snmp.context.user.priv.aes256 ) if snmp.context.user.priv is defined and snmp.context.user.priv.aes256 is defined else '' }}"
+ "{{ (' priv sha ' + snmp.context.user.priv.des56 ) if snmp.context.user.priv is defined and snmp.context.user.priv.des56 is defined else '' }}"
+ "{{ (' priv sha ' + snmp.context.user.priv.des ) if snmp.context.user.priv is defined and snmp.context.user.priv.des is defined else '' }}"
+ "{{ (' access ' + snmp.context.user.access.acl|string ) if snmp.context.user.access is defined"
+ " and snmp.context.user.access.acl is defined else '' }}"
+ "{{ (' access ipv6 ' + snmp.context.user.access.ipv6|string ) if snmp.context.user.access is defined"
+ " and snmp.context.user.access.ipv6 is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "snmp": {
+ "context": {
+ "name": "{{ context }}",
+ "user": {
+ "name": "{{ user }}",
+ "access": {"acl": "{{ acl }}", "ipv6": "{{ aclv6 }}"},
+ "auth": {"md5": "{{ md5 }}", "sha": "{{ sha }}"},
+ "priv": {
+ "des56": "{{ des56 }}",
+ "aes128": "{{ a }}",
+ "aes192": "{{ b }}",
+ "aes256": "{{ c }}",
+ "des": "{{ des }}",
+ },
+ "credential": "{{ not not credential }}",
+ "encrypted": "{{ not not encrypted }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "snmp.context.community",
+ "getval": re.compile(
+ r"""\s\ssnmp
+ (\scontext\s(?P<context>\S+))
+ (\scommunity\s(?P<community>\S+))
+ (\s(?P<ro>RO))?
+ (\s(?P<rw>RW))?
+ (\sipv6\s(?P<ip6acl>\S+))?
+ (\s(?P<acl>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "snmp context {{ snmp.context.name }} community"
+ "{{ (' ' + snmp.context.community.snmp_community) if snmp.context.community.snmp_community is defined else '' }}"
+ "{{ (' ro' ) if snmp.context.community.ro|d(False) else '' }}"
+ "{{ (' rw' ) if snmp.context.community.rw|d(False) else '' }}"
+ "{{ (' ' + snmp.context.community.acl) if snmp.context.community.acl is defined else '' }}"
+ "{{ (' ipv6 ' + snmp.context.community.ipv6) if snmp.context.community.ipv6 is defined else '' }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "snmp": {
+ "context": {
+ "name": "{{ context }}",
+ "community": {
+ "snmp_community": "{{ community }}",
+ "acl": "{{ acl }}",
+ "ro": "{{ not not ro }}",
+ "rw": "{{ not not rw }}",
+ "ipv6": "{{ ip6acl }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ # redistribute starts
+ {
+ "name": "redistribute.application",
+ "getval": re.compile(
+ r"""
+ \s\sredistribute\sapplication\s(?P<name>\S+)
+ (\smetric\s(?P<metric>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute application {{ redistribute.application.name }}"
+ "{{ (' metric ' + redistribute.application.metric|string) if redistribute.application.metric is defined else '' }}"
+ "{{ (' route-map ' + redistribute.application.route_map) if redistribute.application.route_map is defined else '' }}",
+ "remval": "redistribute application {{ redistribute.application.name }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "redistribute": [
+ {
+ "application": {
+ "name": "{{ name }}",
+ "metric": "{{ metric }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+ {
+ "name": "redistribute.bgp",
+ "getval": re.compile(
+ r"""
+ \s\sredistribute\sbgp\s(?P<name>\S+)
+ (\smetric\s(?P<metric>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute bgp {{ redistribute.bgp.as_number }}"
+ "{{ (' metric ' + redistribute.bgp.metric|string) if redistribute.bgp.metric is defined else '' }}"
+ "{{ (' route-map ' + redistribute.bgp.route_map) if redistribute.bgp.route_map is defined else '' }}",
+ "remval": "redistribute bgp {{ redistribute.bgp.as_number }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "redistribute": [
+ {
+ "bgp": {
+ "as_number": "{{ name }}",
+ "metric": "{{ metric }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+ {
+ "name": "redistribute.connected",
+ "getval": re.compile(
+ r"""
+ \s\sredistribute\sconnected
+ (\smetric\s(?P<metric>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute connected"
+ "{{ (' metric ' + redistribute.connected.metric|string) if redistribute.connected.metric is defined else '' }}"
+ "{{ (' route-map ' + redistribute.connected.route_map) if redistribute.connected.route_map is defined else '' }}",
+ "remval": "redistribute connected",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "redistribute": [
+ {
+ "connected": {
+ "set": True,
+ "metric": "{{ metric }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+ {
+ "name": "redistribute.eigrp",
+ "getval": re.compile(
+ r"""
+ \s\sredistribute\seigrp\s(?P<name>\S+)
+ (\smetric\s(?P<metric>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute eigrp {{ redistribute.eigrp.name|string }}"
+ "{{ (' metric ' + redistribute.eigrp.metric|string) if redistribute.eigrp.metric is defined else '' }}"
+ "{{ (' route-map ' + redistribute.eigrp.route_map) if redistribute.eigrp.route_map is defined else '' }}",
+ "remval": "redistribute eigrp {{ redistribute.eigrp.name|string }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "redistribute": [
+ {
+ "eigrp": {
+ "as_number": "{{ name }}",
+ "metric": "{{ metric }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+ {
+ "name": "redistribute.isis",
+ "getval": re.compile(
+ r"""
+ \s\sredistribute\sisis\s(?P<name>\S+)
+ (\s(?P<clns>clns))?
+ (\s(?P<ip>ip))?
+ (\smetric\s(?P<metric>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute isis {{ redistribute.isis.area_tag }}"
+ "{{ (' clns') if redistribute.isis.clns|d(False) else '' }}"
+ "{{ (' ip') if redistribute.isis.ip|d(False) else '' }}"
+ "{{ (' metric ' + redistribute.isis.metric|string) if redistribute.isis.metric is defined else '' }}"
+ "{{ (' route-map ' + redistribute.isis.route_map) if redistribute.isis.route_map is defined else '' }}",
+ "remval": "redistribute isis {{ redistribute.isis.area_tag }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "redistribute": [
+ {
+ "isis": {
+ "area_tag": "{{ name }}",
+ "clns": "{{ not not clns }}",
+ "ip": "{{ not not ip }}",
+ "metric": "{{ metric }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+ {
+ "name": "redistribute.iso_igrp",
+ "getval": re.compile(
+ r"""
+ \s\sredistribute\siso-igrp\s(?P<name>\S+)
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute iso-igrp {{ redistribute.iso_igrp.area_tag }}"
+ "{{ (' route-map ' + redistribute.iso_igrp.route_map) if redistribute.iso_igrp.route_map is defined else '' }}",
+ "remval": "redistribute iso-igrp {{ redistribute.iso_igrp.area_tag }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "redistribute": [
+ {
+ "iso_igrp": {
+ "area_tag": "{{ name }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+ {
+ "name": "redistribute.lisp",
+ "getval": re.compile(
+ r"""
+ \s\sredistribute\slisp
+ (\smetric\s(?P<metric>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute lisp"
+ "{{ (' metric ' + redistribute.lisp.metric|string) if redistribute.lisp.metric is defined else '' }}"
+ "{{ (' route-map ' + redistribute.lisp.route_map) if redistribute.lisp.route_map is defined else '' }}",
+ "remval": "redistribute lisp",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "redistribute": [
+ {
+ "lisp": {
+ "set": True,
+ "metric": "{{ metric }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+ {
+ "name": "redistribute.mobile",
+ "getval": re.compile(
+ r"""
+ \s\sredistribute\smobile
+ (\smetric\s(?P<metric>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute mobile"
+ "{{ (' metric ' + redistribute.mobile.metric|string) if redistribute.mobile.metric is defined else '' }}"
+ "{{ (' route-map ' + redistribute.mobile.route_map) if redistribute.mobile.route_map is defined else '' }}",
+ "remval": "redistribute mobile",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "redistribute": [
+ {
+ "mobile": {
+ "set": True,
+ "metric": "{{ metric }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+ {
+ "name": "redistribute.odr",
+ "getval": re.compile(
+ r"""
+ \s\sredistribute\sodr
+ (\smetric\s(?P<metric>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute odr"
+ "{{ (' metric ' + redistribute.odr.metric|string) if redistribute.odr.metric is defined else '' }}"
+ "{{ (' route-map ' + redistribute.odr.route_map) if redistribute.odr.route_map is defined else '' }}",
+ "remval": "redistribute odr",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "redistribute": [
+ {
+ "odr": {
+ "set": True,
+ "metric": "{{ metric }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+ {
+ "name": "redistribute.ospf",
+ "getval": re.compile(
+ r"""
+ \s+redistribute\sospf\s(?P<process_id>\S+)
+ (\svrf(?P<vrf>\s\S+))?
+ (\smetric\s(?P<metric>\d+))?
+ (\smatch)?
+ (\s(?P<internal>internal))?
+ (\s(?P<ext_type_1>external\s1))?
+ (\s(?P<ext_type_2>external\s2))?
+ (\s(?P<nssa_type_1>nssa-external\s1))?
+ (\s(?P<nssa_type_2>nssa-external\s2))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ (\s(?P<include_connected>include-connected))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute ospf {{ process_id }}"
+ "{{ (' metric ' + metric|string) if metric is defined }}"
+ "{{ (' vrf ' + vrf) if vrf is defined }}"
+ "{{ (' match') if match is defined }}"
+ "{{ (' internal') if match is defined and match.internal is defined and match.internal }}"
+ "{{ (' external 1') if match is defined and match.externals is defined and "
+ "match.externals.type_1 is defined and match.externals.type_1 }}"
+ "{{ (' external 2') if match is defined and match.externals is defined and "
+ "match.externals.type_2 is defined and match.externals.type_2 }}"
+ "{{ (' nssa-external 1') if match is defined and match.nssa_externals is defined and "
+ "match.nssa_externals.type_1 is defined and match.nssa_externals.type_1 }}"
+ "{{ (' nssa-external 2') if match is defined and match.nssa_externals is defined and "
+ "match.nssa_externals.type_2 is defined and match.nssa_externals.type_2}}"
+ "{{ (' route-map ' + route_map) if route_map is defined }}"
+ "{{ (' include-connected') if include_connected is defined and include_connected }}",
+ "remval": "redistribute ospf {{ process_id }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "redistribute": [
+ {
+ "ospf": {
+ "process_id": "{{ process_id }}",
+ "vrf": "{{ vrf }}",
+ "metric": "{{ metric }}",
+ "match": {
+ "internal": "{{ not not internal }}",
+ "externals": {
+ "type_1": "{{ not not ext_type_1 }}",
+ "type_2": "{{ not not ext_type_2 }}",
+ },
+ "nssa_externals": {
+ "type_1": "{{ not not nssa_type_1 }}",
+ "type_2": "{{ not not nssa_type_2 }}",
+ },
+ },
+ "route_map": "{{ route_map }}",
+ "include_connected": "{{ not not include_connected }}",
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+ {
+ "name": "redistribute.ospfv3",
+ "getval": re.compile(
+ r"""
+ \s+redistribute\sospfv3\s(?P<process_id>\S+)
+ (\smetric\s(?P<metric>\d+))?
+ (\smatch)?
+ (\s(?P<internal>internal))?
+ (\s(?P<ext_type_1>external\s1))?
+ (\s(?P<ext_type_2>external\s2))?
+ (\s(?P<nssa_type_1>nssa-external\s1))?
+ (\s(?P<nssa_type_2>nssa-external\s2))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute ospfv3 {{ process_id }}"
+ "{{ (' metric ' + metric|string) if metric is defined }}"
+ "{{ (' match') if match is defined }}"
+ "{{ (' internal') if match is defined and match.internal is defined and match.internal }}"
+ "{{ (' external 1') if match is defined and match.externals is defined and "
+ "match.externals.type_1 is defined and match.externals.type_1 }}"
+ "{{ (' external 2') if match is defined and match.externals is defined and "
+ "match.externals.type_2 is defined and match.externals.type_2 }}"
+ "{{ (' nssa-external 1') if match is defined and match.nssa_externals is defined and "
+ "match.nssa_externals.type_1 is defined and match.nssa_externals.type_1 }}"
+ "{{ (' nssa-external 2') if match is defined and match.nssa_externals is defined and "
+ "match.nssa_externals.type_2 is defined and match.nssa_externals.type_2}}"
+ "{{ (' route-map ' + route_map) if route_map is defined }}",
+ "remval": "redistribute ospfv3 {{ process_id }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "redistribute": [
+ {
+ "ospfv3": {
+ "process_id": "{{ process_id }}",
+ "metric": "{{ metric }}",
+ "match": {
+ "internal": "{{ not not internal }}",
+ "externals": {
+ "type_1": "{{ not not ext_type_1 }}",
+ "type_2": "{{ not not ext_type_2 }}",
+ },
+ "nssa_externals": {
+ "type_1": "{{ not not nssa_type_1 }}",
+ "type_2": "{{ not not nssa_type_2 }}",
+ },
+ },
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+ {
+ "name": "redistribute.rip",
+ "getval": re.compile(
+ r"""
+ \s\sredistribute\srip
+ (\smetric\s(?P<metric>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute rip"
+ "{{ (' metric ' + redistribute.rip.metric|string) if redistribute.rip.metric is defined else '' }}"
+ "{{ (' route-map ' + redistribute.rip.route_map) if redistribute.rip.route_map is defined else '' }}",
+ "remval": "redistribute rip",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "redistribute": [
+ {
+ "rip": {
+ "set": True,
+ "metric": "{{ metric }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+ {
+ "name": "redistribute.static",
+ "getval": re.compile(
+ r"""
+ \s\sredistribute\sstatic
+ (\s(?P<clns>clns))?
+ (\s(?P<ip>ip))?
+ (\smetric\s(?P<metric>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute static"
+ "{{ (' clns') if redistribute.static.clns|d(False) else '' }}"
+ "{{ (' ip') if redistribute.static.ip|d(False) else '' }}"
+ "{{ (' metric ' + redistribute.static.metric|string) if redistribute.static.metric is defined else '' }}"
+ "{{ (' route-map ' + redistribute.static.route_map) if redistribute.static.route_map is defined else '' }}",
+ "remval": "redistribute static",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "redistribute": [
+ {
+ "static": {
+ "set": True,
+ "clns": "{{ not not clns }}",
+ "ip": "{{ not not ip }}",
+ "metric": "{{ metric }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+ {
+ "name": "redistribute.vrf",
+ "getval": re.compile(
+ r"""
+ \s\sredistribute\svrf
+ (\s(?P<name>\S+))?
+ (\s(?P<global>global))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute vrf {{ redistribute.vrf.name }}"
+ "{{ (' global') if redistribute.vrf.global|d(False) else '' }}",
+ "remval": "redistribute vrf {{ redistribute.vrf.name }}",
+ "result": {
+ "address_family": {
+ UNIQUE_AFI: {
+ "redistribute": [
+ {"vrf": {"name": "{{ name }}", "global": "{{ not not global }}"}},
+ ],
+ },
+ },
+ },
+ },
+ # redistribute ends
+ ]
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
new file mode 100644
index 000000000..477cbc679
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/bgp_global.py
@@ -0,0 +1,3056 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 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 Bgp_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 Bgp_globalTemplate(NetworkTemplate):
+ def __init__(self, lines=None, module=None):
+ super(Bgp_globalTemplate, self).__init__(lines=lines, tmplt=self, module=module)
+
+ PARSERS = [
+ {
+ "name": "as_number",
+ "getval": re.compile(
+ r"""
+ ^router\sbgp
+ (\s(?P<as_number>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "router bgp {{ as_number|string }}",
+ "result": {"as_number": "{{ as_number }}"},
+ },
+ {
+ "name": "aggregate_addresses",
+ "getval": re.compile(
+ r"""
+ \saggregate-address
+ (\s(?P<address>\S+))?
+ (\s(?P<netmask>\S+))?
+ (\s(?P<as_set>as-set))?
+ (\s(?P<summary_only>summary-only))?
+ (\s(?P<as_confed_set>as-confed-set))?
+ (\sadvertise-map\s(?P<advertise_map>\S+))?
+ (\sattribute-map\s(?P<attribute_map>\S+))?
+ (\ssuppress-map\s(?P<suppress_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "aggregate-address "
+ "{{ address }} {{ netmask }}"
+ "{{ ' as-set' if as_set|d(False) else ''}}"
+ "{{ ' summary-only' if summary_only|d(False) else ''}}"
+ "{{ ' as-confed-set' if as_confed_set|d(False) else ''}}"
+ "{{ (' advertise-map ' + advertise_map) if advertise_map is defined else '' }}"
+ "{{ (' attribute-map ' + attribute_map) if attribute_map is defined else '' }}"
+ "{{ (' suppress-map ' + suppress_map) if suppress_map is defined else '' }}",
+ "result": {
+ "aggregate_addresses": [
+ {
+ "address": "{{ address }}",
+ "netmask": "{{ netmask }}",
+ "advertise_map": "{{ advertise_map }}",
+ "as_confed_set": "{{ not not as_confed_set }}",
+ "as_set": "{{ not not as_set }}",
+ "attribute_map": "{{ attribute_map }}",
+ "suppress_map": "{{ suppress_map }}",
+ "summary_only": "{{ not not summary_only }}",
+ },
+ ],
+ },
+ },
+ {
+ "name": "auto_summary",
+ "getval": re.compile(
+ r"""
+ ((\sauto-summary))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "auto-summary",
+ "result": {"auto_summary": True},
+ },
+ {
+ "name": "bmp.buffer_size",
+ "getval": re.compile(
+ r"""
+ \sbmp\sbuffer-size
+ (\s(?P<buffer_size>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bmp buffer-size {{ bmp.buffer_size|string }}",
+ "result": {"bmp": {"buffer_size": "{{ buffer_size }}"}},
+ },
+ {
+ "name": "bmp.initial_refresh.delay",
+ "getval": re.compile(
+ r"""
+ \sbmp\sinitial-refresh\sdelay
+ (\s(?P<delay>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bmp initial-refresh delay {{ bmp.initial_refresh.delay|string }}",
+ "result": {"bmp": {"initial_refresh": {"delay": "{{ delay }}"}}},
+ },
+ {
+ "name": "bmp.initial_refresh.skip",
+ "getval": re.compile(
+ r"""
+ \sbmp\sinitial-refresh\sskip
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bmp initial-refresh skip",
+ "result": {"bmp": {"initial_refresh": {"skip": True}}},
+ },
+ {
+ "name": "bmp.server",
+ "getval": re.compile(
+ r"""
+ \sbmp\sserver
+ (\s(?P<server>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bmp server {{ bmp.server }}",
+ "result": {"bmp": {"server": "{{ server|string }}"}},
+ },
+ {
+ "name": "bmp.server_options.activate",
+ "getval": re.compile(
+ r"""
+ \sactivate
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "activate",
+ "result": {"bmp": {"server_options": {"activate": True}}},
+ },
+ {
+ "name": "bmp.server_options.address",
+ "getval": re.compile(
+ r"""
+ \saddress\s(?P<host>\S+)\s
+ (\sport-number(?P<port>\d+))
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "address "
+ "{{ 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 }}"}},
+ },
+ },
+ },
+ {
+ "name": "default_information",
+ "getval": re.compile(
+ r"""
+ (\sdefault-information originate)?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "default-information originate",
+ "result": {"default_information": True},
+ },
+ {
+ "name": "default_metric",
+ "getval": re.compile(
+ r"""
+ ^default-metric\s(?P<default_metric>\d+)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "default-metric {{ default_metric|string }}",
+ "result": {"default_metric": "{{ default_metric }}"},
+ },
+ {
+ "name": "distance.admin",
+ "getval": re.compile(
+ r"""
+ \sdistance
+ (\s(?P<distance>\d+))?
+ (\s(?P<address>\S+))?
+ (\s(?P<wildcard_bit>\S+))?
+ (\s(?P<acl>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "distance"
+ "{{ (' ' + distance.admin.distance|string) if distance.admin.distance is defined else '' }}"
+ "{{ (' ' + distance.admin.address) if distance.admin.address is defined else '' }}"
+ "{{ (' ' + distance.admin.wildcard_bit) if distance.admin.wildcard_bit is defined else '' }}"
+ "{{ (' ' + distance.admin.acl) if distance.admin.acl is defined else '' }}",
+ "result": {
+ "distance": {
+ "admin": {
+ "distance": "{{ distance }}",
+ "address": "{{ address }}",
+ "wildcard_bit": "{{ wildcard_bit }}",
+ "acl": "{{ acl }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "distance.bgp",
+ "getval": re.compile(
+ r"""
+ \sdistance\sbgp
+ (\s(?P<routes_external>\d+))?
+ (\s(?P<routes_internal>\d+))?
+ (\s(?P<routes_local>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "distance bgp"
+ "{{ (' ' + distance.bgp.routes_external|string) if distance.bgp.routes_external is defined else '' }}"
+ "{{ (' ' + distance.bgp.routes_internal|string) if distance.bgp.routes_internal is defined else '' }}"
+ "{{ (' ' + distance.bgp.routes_local|string) if distance.bgp.routes_local is defined else '' }}",
+ "result": {
+ "distance": {
+ "bgp": {
+ "routes_external": "{{ routes_external }}",
+ "routes_internal": "{{ routes_internal }}",
+ "routes_local": "{{ routes_local }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "distance.mbgp",
+ "getval": re.compile(
+ r"""
+ \sdistance\smbgp
+ (\s(?P<routes_external>\d+))?
+ (\s(?P<routes_internal>\d+))?
+ (\s(?P<routes_local>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "distance mbgp"
+ "{{ (' ' + distance.mbgp.routes_external|string) if distance.mbgp.routes_external is defined else '' }}"
+ "{{ (' ' + distance.mbgp.routes_internal|string) if distance.mbgp.routes_internal is defined else '' }}"
+ "{{ (' ' + distance.mbgp.routes_local|string) if distance.mbgp.routes_local is defined else '' }}",
+ "result": {
+ "distance": {
+ "mbgp": {
+ "routes_external": "{{ routes_external }}",
+ "routes_internal": "{{ routes_internal }}",
+ "routes_local": "{{ routes_local }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "distributes",
+ "getval": re.compile(
+ r"""
+ \sdistribute-list
+ (\s(?P<acl>\S+))?
+ (\sprefix\s(?P<prefix>\S+))?
+ (\sgateway\s(?P<gateway>\S+))?
+ (\s(?P<in>in))?
+ (\s(?P<out>out))?
+ (\s(?P<interface>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "distribute-list"
+ "{{ (' prefix ' + prefix) if prefix is defined else '' }}"
+ "{{ (' gateway ' + gateway) if gateway is defined else '' }}"
+ "{{ (' ' + acl) if acl is defined else '' }}"
+ "{{ (' in' ) if in|d(False) else '' }}"
+ "{{ (' out' ) if out|d(False) else '' }}"
+ "{{ (' ' + interface) if interface is defined else '' }}",
+ "result": {
+ "distributes": [
+ {
+ "prefix": "{{ prefix }}",
+ "gateway": "{{ gateway }}",
+ "acl": "{{ acl }}",
+ "in": "{{ not not in }}",
+ "out": "{{ not not out }}",
+ "interface": "{{ interface }}",
+ },
+ ],
+ },
+ },
+ {
+ "name": "maximum_paths.paths",
+ "getval": re.compile(
+ r"""
+ \smaximum-paths
+ (\s(?P<paths>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "maximum-paths {{ maximum_paths.paths|string }}",
+ "result": {"maximum_paths": {"paths": "{{ paths }}"}},
+ },
+ {
+ "name": "maximum_paths.eibgp",
+ "getval": re.compile(
+ r"""
+ \smaximum-paths\seibgp
+ (\s(?P<eibgp>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "maximum-paths eibgp {{ maximum_paths.eibgp|string }}",
+ "result": {"maximum_paths": {"eibgp": "{{ eibgp }}"}},
+ },
+ {
+ "name": "maximum_paths.ibgp",
+ "getval": re.compile(
+ r"""
+ \smaximum-paths\sibgp
+ (\s(?P<ibgp>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "maximum-paths ibgp {{ maximum_paths.ibgp|string }}",
+ "result": {"maximum_paths": {"ibgp": "{{ ibgp }}"}},
+ },
+ {
+ "name": "maximum_secondary_paths.paths",
+ "getval": re.compile(
+ r"""
+ \smaximum-secondary-paths
+ (\s(?P<paths>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "maximum-secondary-paths {{ maximum_secondary_paths.paths|string }}",
+ "result": {"maximum_secondary_paths": {"paths": "{{ paths }}"}},
+ },
+ {
+ "name": "maximum_secondary_paths.eibgp",
+ "getval": re.compile(
+ r"""
+ \smaximum-secondary-paths\seibgp
+ (\s(?P<eibgp>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "maximum-secondary-paths eibgp {{ maximum_secondary_paths.eibgp|string }}",
+ "result": {"maximum_secondary_paths": {"eibgp": "{{ eibgp }}"}},
+ },
+ {
+ "name": "maximum_secondary_paths.ibgp",
+ "getval": re.compile(
+ r"""
+ \smaximum-secondary-paths\sibgp
+ (\s(?P<ibgp>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "maximum-secondary-paths ibgp {{ maximum_secondary_paths.ibgp|string }}",
+ "result": {"maximum_secondary_paths": {"ibgp": "{{ ibgp }}"}},
+ },
+ {
+ "name": "networks",
+ "getval": re.compile(
+ r"""
+ \snetwork
+ (\s(?P<address>\S+))?
+ (\smask\s(?P<netmask>\S+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ (\s(?P<backdoor>backdoor))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "network"
+ "{{ (' ' + address) if address is defined else '' }}"
+ "{{ (' mask ' + netmask) if netmask is defined else '' }}"
+ "{{ (' route-map ' + route_map) if route_map is defined else '' }}"
+ "{{ (' backdoor' ) if backdoor|d(False) else '' }}",
+ "result": {
+ "networks": [
+ {
+ "address": "{{ address }}",
+ "netmask": "{{ netmask }}",
+ "route_map": "{{ route_map }}",
+ "backdoor": "{{ not not backdoor }}",
+ },
+ ],
+ },
+ },
+ {
+ "name": "route_server_context.name",
+ "getval": re.compile(
+ r"""
+ \sroute-server_context
+ (\s(?P<name>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "route-server-context {{ route_server_context.name }}",
+ "result": {"route_server_context": {"name": "{{ name }}"}},
+ },
+ {
+ "name": "route_server_context.address_family",
+ "getval": re.compile(
+ r"""
+ \sroute-server_context\saddress-family
+ (\s(?P<afi>ipv4|ipv6))?
+ (\s(?P<modifier>multicast|unicast))?
+ (\simport-map\s(?P<import_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "address-family"
+ "{{ (' ' + route_server_context.address_family.afi) if route_server_context.address_family.afi is defined else '' }}"
+ "{{ (' ' + route_server_context.address_family.modifier) if route_server_context.address_family.modifier is defined else '' }}"
+ "{{ (' import-map ' + route_server_context.address_family.import_map) if route_server_context.address_family.import_map is defined else '' }}",
+ "result": {
+ "route_server_context": {
+ "address_family": {
+ "afi": "{{ afi }}",
+ "modifier": "{{ modifier }}",
+ "import_map": "{{ import_map }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "route_server_context.description",
+ "getval": re.compile(
+ r"""
+ \sroute-server_context\sdescription
+ (\s(?P<description>.+$))?
+ """,
+ re.VERBOSE,
+ ),
+ "setval": "description {{ route_server_context.description }}",
+ "result": {"route_server_context": {"description": "{{ description }}"}},
+ },
+ {
+ "name": "synchronization",
+ "getval": re.compile(r"""\s(?P<synchronization>synchronization)""", re.VERBOSE),
+ "setval": "synchronization",
+ "result": {"synchronization": "{{ not not synchronization }}"},
+ },
+ {
+ "name": "table_map",
+ "getval": re.compile(
+ r"""
+ \stable-map
+ (\s(?P<name>\S+))?
+ (\s(?P<filter>filter))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "table-map"
+ "{{ (' ' + name) if name is defined else '' }}"
+ "{{ (' filter' ) if filter|d(False) else '' }}",
+ "result": {"table_map": {"name": "{{ name }}", "filter": "{{ not not filter }}"}},
+ },
+ {
+ "name": "timers",
+ "getval": re.compile(
+ r"""
+ \stimers\sbgp
+ (\s(?P<keepalive>\d+))?
+ (\s(?P<holdtime>\d+))?
+ (\s(?P<min_holdtime>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "timers bgp"
+ "{{ (' ' + timers.keepalive|string) if timers.keepalive is defined else '' }}"
+ "{{ (' ' + timers.holdtime|string) if timers.holdtime is defined else '' }}"
+ "{{ (' ' + timers.min_holdtime|string) if timers.min_holdtime is defined else '' }}",
+ "result": {
+ "timers": {
+ "keepalive": "{{ keepalive }}",
+ "holdtime": "{{ holdtime }}",
+ "min_holdtime": "{{ min_holdtime }}",
+ },
+ },
+ },
+ # bgp starts
+ {
+ "name": "bgp.additional_paths",
+ "getval": re.compile(
+ r"""
+ \sbgp\sadditional-paths
+ (\s(?P<install>install))?
+ (\s(?P<receive>receive))?
+ (\s(?P<select>select))?
+ (\s(?P<send>send))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp additional-paths"
+ "{{ (' install' ) if bgp.additional_paths.install|d(False) else '' }}"
+ "{{ (' receive' ) if bgp.additional_paths.receive|d(False) else '' }}"
+ "{{ (' select' ) if bgp.additional_paths.select|d(False) else '' }}"
+ "{{ (' send' ) if bgp.additional_paths.send|d(False) else '' }}",
+ "result": {
+ "bgp": {
+ "additional_paths": {
+ "install": "{{ not not install }}",
+ "receive": "{{ not not receive }}",
+ "select": "{{ not not select }}",
+ "send": "{{ not not send }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "bgp.advertise_best_external",
+ "getval": re.compile(r"""\s(bgp\sadvertise-best-external)""", re.VERBOSE),
+ "setval": "{{ ('bgp advertise-best-external' ) if bgp.advertise_best_external|d(False) else '' }}",
+ "result": {"bgp": {"advertise_best_external": True}},
+ },
+ {
+ "name": "bgp.aggregate_timer",
+ "getval": re.compile(
+ r"""
+ \sbgp\saggregate-timer
+ (\s(?P<aggregate_timer>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp aggregate-timer {{ bgp.aggregate_timer|string }}",
+ "result": {"bgp": {"aggregate_timer": "{{ aggregate_timer }}"}},
+ },
+ {
+ "name": "bgp.always_compare_med",
+ "getval": re.compile(r"""\s(bgp\salways-compare-med)""", re.VERBOSE),
+ "setval": "{{ ('bgp always-compare-med' ) if bgp.always_compare_med|d(False) else '' }}",
+ "result": {"bgp": {"always_compare_med": True}},
+ },
+ {
+ "name": "bgp.asnotation",
+ "getval": re.compile(r"""\s(bgp\sasnotation\sdot)""", re.VERBOSE),
+ "setval": "{{ ('bgp asnotation dot' ) if bgp.asnotation|d(False) else '' }}",
+ "result": {"bgp": {"asnotation": True}},
+ },
+ {
+ "name": "bgp.bestpath_options.aigp",
+ "getval": re.compile(r"""\s(bgp\sbestpath\saigp\signore)""", re.VERBOSE),
+ "setval": "{{ ('bgp bestpath aigp ignore' ) if bgp.bestpath_options.aigp|d(False) else '' }}",
+ "result": {"bgp": {"bestpath_options": {"aigp": True}}},
+ },
+ {
+ "name": "bgp.bestpath_options.compare_routerid",
+ "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),
+ "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),
+ "setval": "bgp bestpath igp-metric ignore",
+ "result": {"bgp": {"bestpath_options": {"igp_metric": True}}},
+ },
+ {
+ "name": "bgp.bestpath_options.med",
+ "getval": re.compile(
+ r"""
+ \sbgp\sbestpath\smed
+ (\s(?P<confed>confed))?
+ (\s(?P<missing_as_worst>missing-as-worst))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp bestpath med"
+ "{{ (' confed') if bgp.bestpath_options.med.confed|d(False) else '' }}"
+ "{{ (' missing-as-worst') if bgp.bestpath_options.med.missing_as_worst|d(False) else '' }}",
+ "result": {
+ "bgp": {
+ "bestpath_options": {
+ "med": {
+ "confed": "{{ not not confed }}",
+ "missing_as_worst": "{{ not not missing_as_worst }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "bgp.client_to_client",
+ "getval": re.compile(
+ r"""
+ \sbgp\sclient-to-client
+ (\s(?P<set>reflection))?
+ (\s(?P<all>all))?
+ (\sintra-cluster\scluster-id\s(?P<intra_cluster>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp client-to-client"
+ "{{ (' reflection') if bgp.client_to_client.set|d(False) else '' }}"
+ "{{ (' all') if bgp.client_to_client.all|d(False) else '' }}"
+ "{{ (' intra-cluster cluster-id '+ bgp.client_to_client.intra_cluster ) if bgp.client_to_client.intra_cluster is defined else '' }}",
+ "result": {
+ "bgp": {
+ "client_to_client": {
+ "set": "{{ not not set }}",
+ "all": "{{ not not all }}",
+ "intra_cluster": "{{ intra_cluster }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "bgp.cluster_id",
+ "getval": re.compile(
+ r"""
+ \sbgp\scluster-id
+ (\s(?P<cluster_id>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp cluster-id {{ bgp.cluster_id }}",
+ "result": {"bgp": {"cluster_id": "{{ not not cluster_id }}"}},
+ },
+ {
+ "name": "bgp.confederation.peer",
+ "getval": re.compile(
+ r"""
+ \sbgp\sconfederation\speer
+ (\s(?P<peer>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp confederation peers {{ bgp.confederation.peer }}",
+ "result": {"bgp": {"confederation": {"peers": "{{ peer }}"}}},
+ },
+ {
+ "name": "bgp.confederation.identifier",
+ "getval": re.compile(
+ r"""
+ \sbgp\sconfederation\sidentifier
+ (\s(?P<identifier>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp confederation identifier {{ bgp.confederation.identifier }}",
+ "result": {"bgp": {"confederation": {"identifier": "{{ identifier }}"}}},
+ },
+ {
+ "name": "bgp.consistency_checker.auto_repair",
+ "getval": re.compile(
+ r"""
+ \sbgp\sconsistency-checker\sauto-repair
+ (\sinterval\s(?P<interval>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp consistency-checker auto-repair"
+ "{{ (' interval '+ bgp.consistency_checker.auto_repair.interval|string) if bgp.consistency_checker.auto_repair.interval is defined else '' }}",
+ "result": {
+ "bgp": {
+ "consistency_checker": {
+ "auto_repair": {"set": True, "interval": "{{ interval }}"},
+ },
+ },
+ },
+ },
+ {
+ "name": "bgp.consistency_checker.error_message",
+ "getval": re.compile(
+ r"""
+ \sbgp\sconsistency-checker\serror-message
+ (\sinterval\s(?P<interval>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp consistency-checker error-message"
+ "{{ (' interval '+ bgp.consistency_checker.error_message.interval|string) if bgp.consistency_checker.error_message.interval is defined else '' }}",
+ "result": {
+ "bgp": {
+ "consistency_checker": {
+ "error_message": {"set": True, "interval": "{{ interval }}"},
+ },
+ },
+ },
+ },
+ {
+ "name": "bgp.dampening",
+ "getval": re.compile(
+ r"""
+ \sbgp\sdampening
+ (\s(?P<penalty_half_time>\d+))?
+ (\s(?P<reuse_route_val>\d+))?
+ (\s(?P<suppress_route_val>\d+))?
+ (\s(?P<max_suppress>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp dampening"
+ "{{ (' '+ bgp.dampening.penalty_half_time|string) if bgp.dampening.penalty_half_time is defined else '' }}"
+ "{{ (' '+ bgp.dampening.reuse_route_val|string) if bgp.dampening.reuse_route_val is defined else '' }}"
+ "{{ (' '+ bgp.dampening.suppress_route_val|string) if bgp.dampening.suppress_route_val is defined else '' }}"
+ "{{ (' '+ bgp.dampening.max_suppress|string) if bgp.dampening.max_suppress is defined else '' }}"
+ "{{ (' route-map '+ bgp.dampening.route_map|string) if bgp.dampening.route_map is defined else '' }}",
+ "result": {
+ "bgp": {
+ "dampening": {
+ "penalty_half_time": "{{ penalty_half_time }}",
+ "reuse_route_val": "{{ reuse_route_val }}",
+ "suppress_route_val": "{{ suppress_route_val }}",
+ "max_suppress": "{{ max_suppress }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "bgp.deterministic_med",
+ "getval": re.compile(r"""\s(bgp\sdeterministic-med)""", re.VERBOSE),
+ "setval": "bgp deterministic-med",
+ "result": {"bgp": {"deterministic_med": True}},
+ },
+ {
+ "name": "bgp.dmzlink_bw",
+ "getval": re.compile(r"""\s(bgp\sdmzlink-bw)""", re.VERBOSE),
+ "setval": "bgp dmzlink-bw",
+ "result": {"bgp": {"dmzlink_bw": True}},
+ },
+ {
+ "name": "bgp.enforce_first_as",
+ "getval": re.compile(r"""\s(bgp\senforce-first-as)""", re.VERBOSE),
+ "setval": "bgp enforce-first-as",
+ "result": {"bgp": {"enforce_first_as": True}},
+ },
+ {
+ "name": "bgp.enhanced_error",
+ "getval": re.compile(r"""\s(bgp\senhanced-error)""", re.VERBOSE),
+ "setval": "bgp enhanced-error",
+ "result": {"bgp": {"enhanced_error": True}},
+ },
+ {
+ "name": "bgp.fast_external_fallover",
+ "getval": re.compile(r"""\s(bgp\sfast-external-fallover)""", re.VERBOSE),
+ "setval": "bgp fast-external-fallover",
+ "result": {"bgp": {"fast_external_fallover": True}},
+ },
+ {
+ "name": "bgp.graceful_restart.set",
+ "getval": re.compile(
+ r"""
+ \sbgp\sgraceful-restart
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp graceful-restart",
+ "result": {"bgp": {"graceful_restart": {"set": True}}},
+ },
+ {
+ "name": "bgp.graceful_restart.extended",
+ "getval": re.compile(
+ r"""
+ \sbgp\sgraceful-restart\sextended
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp graceful-restart extended",
+ "result": {"bgp": {"graceful_restart": {"extended": True}}},
+ },
+ {
+ "name": "bgp.graceful_restart.restart_time",
+ "getval": re.compile(
+ r"""
+ \sbgp\sgraceful-restart\srestart-time
+ (\s(?P<restart_time>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp graceful-restart restart-time {{ bgp.graceful_restart.restart_time|string }}",
+ "result": {"bgp": {"graceful_restart": {"restart_time": "{{ restart_time }}"}}},
+ },
+ {
+ "name": "bgp.graceful_restart.stalepath_time",
+ "getval": re.compile(
+ r"""
+ \sbgp\sgraceful-restart\sstalepath-time
+ (\s(?P<stalepath_time>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp graceful-restart stalepath-time {{ bgp.graceful_restart.stalepath_time|string }}",
+ "result": {"bgp": {"graceful_restart": {"stalepath_time": "{{ stalepath_time }}"}}},
+ },
+ {
+ "name": "bgp.graceful_shutdown.neighbors",
+ "getval": re.compile(
+ r"""
+ \sbgp\sgraceful-shutdown\sall\sneighbors
+ (\s(?P<time>\d+))?
+ (\s(?P<activate>activate))?
+ (\slocal-preference\s(?P<local_preference>\d+))?
+ (\scommunity\s(?P<community>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp graceful-shutdown all neighbors"
+ "{{ (' ' + bgp.graceful_shutdown.neighbors.time|string) if bgp.graceful_shutdown.neighbors.time is defined else '' }}"
+ "{{ (' activate') if bgp.graceful_shutdown.neighbors.activate|d(False) else '' }}"
+ "{{ (' local-preference ' + bgp.graceful_shutdown.local_preference|string) if bgp.graceful_shutdown.local_preference is defined else '' }}"
+ "{{ (' community ' + bgp.graceful_shutdown.community|string) if bgp.graceful_shutdown.community is defined else '' }}",
+ "result": {
+ "bgp": {
+ "graceful_shutdown": {
+ "neighbors": {"time": "{{ time }}", "activate": "{{ not not activate }}"},
+ "community": "{{ community }}",
+ "local_preference": "{{ local_preference }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "bgp.graceful_shutdown.vrfs",
+ "getval": re.compile(
+ r"""
+ \sbgp\sgraceful-shutdown\sall\svrfs
+ (\s(?P<time>\d+))?
+ (\s(?P<activate>activate))?
+ (\slocal-preference\s(?P<local_preference>\d+))?
+ (\scommunity\s(?P<community>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp graceful-shutdown all vrfs"
+ "{{ (' ' + bgp.graceful_shutdown.vrfs.time|string) if bgp.graceful_shutdown.vrfs.time is defined else '' }}"
+ "{{ (' activate') if bgp.graceful_shutdown.vrfs.activate|d(False) else '' }}"
+ "{{ (' local-preference ' + bgp.graceful_shutdown.local_preference|string) if bgp.graceful_shutdown.local_preference is defined else '' }}"
+ "{{ (' community ' + bgp.graceful_shutdown.community|string) if bgp.graceful_shutdown.community is defined else '' }}",
+ "result": {
+ "bgp": {
+ "graceful_shutdown": {
+ "vrfs": {"time": "{{ time }}", "activate": "{{ not not activate }}"},
+ "community": "{{ community }}",
+ "local_preference": "{{ local_preference }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "inject_maps",
+ "getval": re.compile(
+ r"""
+ \sbgp\sinject-map
+ (\s(?P<name>\S+))?
+ (\sexist-map\s(?P<exist_map_name>\S+))?
+ (\s(?P<copy_attributes>copy-attributes))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp inject-map"
+ "{{ (' '+ name) if name is defined else '' }}"
+ "{{ (' exist-map '+ exist_map_name) if exist_map_name is defined else '' }}"
+ "{{ (' copy-attributes') if copy_attributes|d(False) else '' }}",
+ "result": {
+ "bgp": {
+ "inject_maps": [
+ {
+ "name": "{{ name }}",
+ "exist_map_name": "{{ exist_map_name }}",
+ "copy_attributes": "{{ not not copy_attributes }}",
+ },
+ ],
+ },
+ },
+ },
+ {
+ "name": "bgp.listen.limit",
+ "getval": re.compile(
+ r"""
+ \sbgp\slisten\slimit
+ (\s(?P<limit>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp listen limit {{ bgp.listen.limit|string }}",
+ "result": {"bgp": {"listen": {"limit": "{{ limit }}"}}},
+ },
+ {
+ "name": "bgp.listen.range",
+ "getval": re.compile(
+ r"""
+ \sbgp\slisten\srange
+ (\s(?P<host_with_subnet>\S+))?
+ (\speer-group\s(?P<peer_group>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp listen range"
+ "{{ (' '+ bgp.listen.range.host_with_subnet) if bgp.listen.range.host_with_subnet is defined else '' }}"
+ "{{ (' peer-group '+ bgp.listen.range.peer_group) if bgp.listen.range.peer_group is defined else '' }}",
+ "result": {
+ "bgp": {
+ "listen": {
+ "range": {
+ "host_with_subnet": "{{ host_with_subnet }}",
+ "peer_group": "{{ peer_group }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "bgp.log_neighbor_changes",
+ "getval": re.compile(r"""\s(bgp\slog-neighbor-changes)""", re.VERBOSE),
+ "setval": "bgp log-neighbor-changes",
+ "result": {"bgp": {"log_neighbor_changes": True}},
+ },
+ {
+ "name": "bgp.maxas_limit",
+ "getval": re.compile(
+ r"""
+ \sbgp\smaxas-limit
+ (\s(?P<maxas_limit>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp maxas-limit {{ bgp.maxas_limit|string }}",
+ "result": {"bgp": {"maxas_limit": "{{ maxas_limit }}"}},
+ },
+ {
+ "name": "bgp.maxcommunity_limit",
+ "getval": re.compile(
+ r"""
+ \sbgp\smaxcommunity-limit
+ (\s(?P<maxcommunity_limit>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp maxcommunity-limit {{ bgp.maxcommunity_limit|string }}",
+ "result": {"bgp": {"maxcommunity_limit": "{{ maxcommunity_limit }}"}},
+ },
+ {
+ "name": "bgp.maxextcommunity_limit",
+ "getval": re.compile(
+ r"""
+ \sbgp\smaxextcommunity-limit
+ (\s(?P<maxextcommunity_limit>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp maxextcommunity-limit {{ bgp.maxextcommunity_limit|string }}",
+ "result": {"bgp": {"maxextcommunity_limit": "{{ maxextcommunity_limit }}"}},
+ },
+ {
+ "name": "bgp.nexthop.route_map",
+ "getval": re.compile(
+ r"""
+ \sbgp\snexthop\sroute-map
+ (\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp nexthop route-map {{ bgp.nexthop.route_map }}",
+ "result": {"bgp": {"nexthop": {"route_map": "{{ route_map }}"}}},
+ },
+ {
+ "name": "bgp.nexthop.trigger.delay",
+ "getval": re.compile(
+ r"""
+ \sbgp\snexthop\strigger\sdelay
+ (\s(?P<delay>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp nexthop trigger delay {{ bgp.nexthop.trigger.delay|string }}",
+ "result": {"bgp": {"nexthop": {"trigger": {"delay": "{{ delay }}"}}}},
+ },
+ {
+ "name": "bgp.nexthop.trigger.enable",
+ "getval": re.compile(
+ r"""
+ \sbgp\snexthop\strigger\senable
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp nexthop trigger enable",
+ "result": {"bgp": {"nexthop": {"trigger": {"enable": True}}}},
+ },
+ {
+ "name": "bgp.nopeerup_delay_options.cold_boot",
+ "getval": re.compile(
+ r"""
+ \sbgp\snopeerup-delay\scold-boot
+ (\s(?P<cold_boot>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp nopeerup-delay cold-boot {{ bgp.nopeerup_delay_options.cold_boot|string }}",
+ "result": {"bgp": {"nopeerup_delay_options": {"cold_boot": "{{ cold_boot }}"}}},
+ },
+ {
+ "name": "bgp.nopeerup_delay_options.post_boot",
+ "getval": re.compile(
+ r"""
+ \sbgp\snopeerup-delay\spost-boot
+ (\s(?P<post_boot>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp nopeerup-delay post-boot {{ bgp.nopeerup_delay_options.post_boot|string }}",
+ "result": {"bgp": {"nopeerup_delay_options": {"post_boot": "{{ post_boot }}"}}},
+ },
+ {
+ "name": "bgp.nopeerup_delay_options.nsf_switchover",
+ "getval": re.compile(
+ r"""
+ \sbgp\snopeerup-delay\snsf-switchover
+ (\s(?P<nsf_switchover>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp nopeerup-delay nsf-switchover {{ bgp.nopeerup_delay_options.nsf_switchover|string }}",
+ "result": {
+ "bgp": {"nopeerup_delay_options": {"nsf_switchover": "{{ nsf_switchover }}"}},
+ },
+ },
+ {
+ "name": "bgp.nopeerup_delay_options.user_initiated",
+ "getval": re.compile(
+ r"""
+ \sbgp\snopeerup-delay\suser-initiated
+ (\s(?P<user_initiated>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp nopeerup-delay user-initiated {{ bgp.nopeerup_delay_options.user_initiated|string }}",
+ "result": {
+ "bgp": {"nopeerup_delay_options": {"user_initiated": "{{ user_initiated }}"}},
+ },
+ },
+ {
+ "name": "bgp.recursion",
+ "getval": re.compile(
+ r"""
+ \sbgp\srecursion\shost
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp recursion host",
+ "result": {"bgp": {"recursion": True}},
+ },
+ {
+ "name": "bgp.redistribute_internal",
+ "getval": re.compile(
+ r"""
+ \sbgp\sredistribute-internal
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp redistribute-internal",
+ "result": {"bgp": {"redistribute_internal": True}},
+ },
+ {
+ "name": "bgp.refresh.max_eor_time",
+ "getval": re.compile(
+ r"""
+ \sbgp\srefresh\smax-eor-time
+ (\s(?P<max_eor_time>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp refresh max-eor-time {{ bgp.refresh.max_eor_time|string }}",
+ "result": {"bgp": {"refresh": {"max_eor_time": "{{ max_eor_time }}"}}},
+ },
+ {
+ "name": "bgp.refresh.stalepath_time",
+ "getval": re.compile(
+ r"""
+ \sbgp\srefresh\sstalepath-time
+ (\s(?P<stalepath_time>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp refresh stalepath-time {{ bgp.refresh.stalepath_time|string }}",
+ "result": {"bgp": {"refresh": {"stalepath_time": "{{ stalepath_time }}"}}},
+ },
+ {
+ "name": "bgp.regexp",
+ "getval": re.compile(
+ r"""
+ \sbgp\sregexp\sdeterministic
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp regexp deterministic",
+ "result": {"bgp": {"regexp": True}},
+ },
+ {
+ "name": "bgp.router_id",
+ "getval": re.compile(
+ r"""
+ \sbgp\srouter-id
+ (\s(?P<address>\S+))?
+ (\sinterface\s(?P<interface>\S+))?
+ (\svrf\s(?P<vrf>auto-assign))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp router-id"
+ "{{ (' ' + bgp.router_id.address) if bgp.router_id.address is defined else '' }}"
+ "{{ (' interface ' + bgp.router_id.interface) if bgp.router_id.interface is defined else '' }}"
+ "{{ (' vrf auto-assign') if bgp.router_id.vrf|d(False) else '' }}",
+ "result": {
+ "bgp": {
+ "router_id": {
+ "address": "{{ address }}",
+ "interface": "{{ interface }}",
+ "vrf": "{{ not not vrf }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "bgp.scan_time",
+ "getval": re.compile(
+ r"""
+ \sbgp\sscan-time
+ (\s(?P<scan_time>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp scan-time {{ bgp.scan_time|string }}",
+ "result": {"bgp": {"scan_time": "{{ scan_time }}"}},
+ },
+ {
+ "name": "bgp.slow_peer.detection.set",
+ "getval": re.compile(
+ r"""
+ \sbgp\sslow-peer\sdetection
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp slow-peer detection",
+ "result": {"bgp": {"slow_peer": {"detection": {"set": True}}}},
+ },
+ {
+ "name": "bgp.slow_peer.detection.threshold",
+ "getval": re.compile(
+ r"""
+ \sbgp\sslow-peer\sdetection\sthreshold
+ (\s(?P<threshold>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp slow-peer detection threshold {{ bgp.slow_peer.detection.threshold|string }}",
+ "result": {"bgp": {"slow_peer": {"detection": {"threshold": "{{ threshold }}"}}}},
+ },
+ {
+ "name": "bgp.slow_peer.split_update_group",
+ "getval": re.compile(
+ r"""
+ \sbgp\sslow-peer\ssplit-update-group
+ (\s(?P<dynamic>dynamic))?
+ (\s(?P<permanent>permanent))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp slow-peer split-update-group"
+ "{{ (' dynamic') if bgp.slow_peer.split_update_group.dynamic|d(False) else '' }}"
+ "{{ (' permanent') if bgp.slow_peer.split_update_group.permanent|d(False) else '' }}",
+ "result": {
+ "bgp": {
+ "slow_peer": {
+ "split_update_group": {
+ "dynamic": "{{ not not dynamic }}",
+ "permanent": "{{ not not permanent }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "bgp.snmp",
+ "getval": re.compile(
+ r"""
+ \sbgp\ssnmp\straps\sadd-type
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp snmp traps add-type",
+ "result": {"bgp": {"snmp": True}},
+ },
+ {
+ "name": "bgp.sso",
+ "getval": re.compile(
+ r"""
+ \sbgp\ssso\sroute-refresh-enable
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp sso route-refresh-enable",
+ "result": {"bgp": {"sso": True}},
+ },
+ {
+ "name": "bgp.soft_reconfig_backup",
+ "getval": re.compile(
+ r"""
+ \sbgp\ssoft-reconfig-backup
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp soft-reconfig-backup ",
+ "result": {"bgp": {"soft_reconfig_backup": True}},
+ },
+ {
+ "name": "bgp.suppress_inactive",
+ "getval": re.compile(
+ r"""
+ \sbgp\ssuppress-inactive
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp suppress-inactive",
+ "result": {"bgp": {"suppress_inactive": True}},
+ },
+ {
+ "name": "bgp.transport",
+ "getval": re.compile(
+ r"""
+ \sbgp\stransport\spath-mtu-discovery
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp transport path-mtu-discovery",
+ "result": {"bgp": {"transport": True}},
+ },
+ {
+ "name": "bgp.update_delay",
+ "getval": re.compile(
+ r"""
+ \sbgp\supdate-delay
+ (\s(?P<update_delay>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp update-delay {{ bgp.update_delay|string }}",
+ "result": {"bgp": {"update_delay": "{{ update_delay }}"}},
+ },
+ {
+ "name": "bgp.update_group",
+ "getval": re.compile(
+ r"""
+ \sbgp\supdate-group\ssplit\sas-override
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp update-group split as-override",
+ "result": {"bgp": {"update_group": True}},
+ },
+ {
+ "name": "bgp.upgrade_cli.set",
+ "getval": re.compile(
+ r"""
+ \sbgp\supgrade-cli
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp upgrade-cli",
+ "result": {"bgp": {"update_group": {"set": True}}},
+ },
+ {
+ "name": "bgp.upgrade_cli.af_mode",
+ "getval": re.compile(
+ r"""
+ \sbgp\supgrade-cli\saf-mode
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "bgp upgrade-cli af-mode",
+ "result": {"bgp": {"update_group": {"af_mode": True}}},
+ },
+ # bgp ends
+ # neighbor remote-as starts
+ {
+ "name": "neighbor_address",
+ "getval": re.compile(
+ r"""
+ \sneighbordel(?P<neighbor_address>\S+)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }}",
+ "result": {"del_neighbor": True},
+ },
+ {
+ "name": "remote_as",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)
+ \sremote-as\s(?P<remote_as>\S+)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }}"
+ "{{ (' remote-as ' + remote_as|string) if remote_as is defined else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "remote_as": "{{ remote_as }}",
+ "neighbor_address": "{{ neighbor_address }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "peer_group",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)
+ \speer-group\s(?P<peer_group>\S+)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }}"
+ "{{ (' peer-group ' + peer_group) if peer_group|d(False) else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "peer_group": "{{ peer_group }}",
+ "neighbor_address": "{{ neighbor_address }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "bmp_activate",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)
+ \s(?P<bmp_activate>bmp-activate)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} bmp-activate",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {"bmp_activate": "{{ not not bmp_activate }}"},
+ },
+ },
+ },
+ {
+ "name": "cluster_id",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)
+ \s(?P<cluster_id>cluster-id)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} cluster-id",
+ "result": {
+ "neighbors": {"{{ neighbor_address }}": {"cluster_id": "{{ not not cluster_id }}"}},
+ },
+ },
+ {
+ "name": "description",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)
+ \sdescription\s(?P<description>.+$)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} description"
+ "{{ (' ' + description) if description is defined else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "neighbor_address": "{{ neighbor_address }}",
+ "description": "{{ description }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "disable_connected_check",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)
+ \s(?P<disable_connected_check>disable-connected-check)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} disable-connected-check",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "disable_connected_check": "{{ not not disable_connected_check }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "ebgp_multihop",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)
+ \s(?P<enable>ebgp_multihop)
+ (\s(?P<hop_count>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} ebgp-multihop"
+ "{{ (' ' + hop_count|string) if hop_count is defined else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "ebgp_multihop": {
+ "enable": "{{ not not enable }}",
+ "hop_count": "{{ hop_count }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "fall_over.bfd",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sfall-over
+ \s(?P<set>bfd)
+ (\s(?P<multi_hop>multi-hop))?
+ (\s(?P<single_hop>single-hop))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} fall-over"
+ "{{ (' bfd') if fall_over.bfd.set is defined else '' }}"
+ "{{ (' multi-hop') if fall_over.bfd.multi_hop is defined else '' }}"
+ "{{ (' single-hop') if fall_over.bfd.single_hop is defined else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "fall_over": {
+ "bfd": {
+ "set": "{{ not not set }}",
+ "multi_hop": "{{ not not multi_hop }}",
+ "single_hop": "{{ not not single_hop }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "fall_over.route_map",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sroute-map
+ \s(?P<route_map>\S+)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} route-map {{ fall_over.route_map }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "fall_over": {"route_map": "{{ not not route_map }}"},
+ },
+ },
+ },
+ },
+ {
+ "name": "ha_mode",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sha-mode
+ \s(?P<set>graceful-restart)
+ (\s(?P<disable>disable))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} ha-mode"
+ "{{ (' graceful-restart') if ha_mode.set|d(False) is defined else '' }}"
+ "{{ (' disable') if ha_mode.disable is defined else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "ha_mode": {"set": "{{ not not set }}", "disable": "{{ not not disable }}"},
+ },
+ },
+ },
+ },
+ {
+ "name": "inherit",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sinherit\speer-session
+ \s(?P<inherit>\S+)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} inherit peer-session"
+ "{{ (' ' + inherit) if inherit is defined else '' }}",
+ "result": {"neighbors": {"{{ neighbor_address }}": {"inherit": "{{ inherit }}"}}},
+ },
+ {
+ "name": "local_as",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\s(?P<local_as>local-as)
+ (\s(?P<number>\S+))?
+ (\s(?P<dual_as>dual-as))?
+ (\s(?P<no_prepend>no-prepend))?
+ (\s(?P<replace_as>replace-as))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} local-as"
+ "{{ (' ' + local_as.number|string) if local_as.number is defined else '' }}"
+ "{{ (' dual-as') if local_as.dual_as is defined else '' }}"
+ "{{ (' no-prepend') if local_as.no_prepend.set is defined else '' }}"
+ "{{ (' replace-as') if local_as.no_prepend.replace_as is defined else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "local_as": {
+ "set": "{{ not not local_as }}",
+ "number": "{{ number }}",
+ "dual_as": "{{ not not dual_as }}",
+ "no_prepend": {
+ "set": "{{ not not no_prepend }}",
+ "replace_as": "{{ not not replace_as }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "log_neighbor_changes",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)
+ \s(?P<set>log-neighbor-changes)
+ (\s(?P<disable>disable))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }}"
+ "{{ (' log-neighbor-changes') if log_neighbor_changes.set is defined else '' }}"
+ "{{ (' disable') if log_neighbor_changes.disable is defined else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "neighbor_address": "{{ neighbor_address }}",
+ "log_neighbor_changes": {
+ "set": "{{ not not set }}",
+ "disable": "{{ not not disable }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "password_options",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\spassword
+ \s(?P<encryption>\d+)
+ (\s(?P<pass_key>.$))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} password"
+ "{{ (' '+ password_options.encryption|string) if password_options.encryption is defined else '' }}"
+ "{{ (' '+ password_options.pass_key) if password_options.pass_key is defined else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "neighbor_address": "{{ neighbor_address }}",
+ "password_options": {
+ "encryption": "{{ encryption }}",
+ "pass_key": "{{ pass_key }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "path_attribute.discard",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\spath-attribute\sdiscard
+ (\s(?P<type>\d+))?
+ (\srange\s(?P<start>\d+)\s(?P<end>\d+))?
+ (\s(?P<in>in))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} path-attribute discard"
+ "{{ (' ' + type) if path_attribute.discard.type is defined else '' }}"
+ "{{ (' range '+ path_attribute.discard.range.start|string) if spath_attribute.discard.range.start is defined else '' }}"
+ "{{ (' '+ path_attribute.discard.range.end|string) if spath_attribute.discard.range.end is defined else '' }}"
+ "{{ (' in') if path_attribute.discard.in|d(False) else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "path_attribute": {
+ "discard": {
+ "type": "{{ type }}",
+ "range": {"start": "{{ start }}", "end": "{{ end }}"},
+ "in": "{{ not not in }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "path_attribute.treat_as_withdraw",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\spath-attribute\streat-as-withdraw
+ (\s(?P<type>\d+))?
+ (\srange\s(?P<start>\d+)\s(?P<end>\d+))?
+ (\s(?P<in>in))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} path-attribute treat-as-withdraw"
+ "{{ (' ' + type) if path_attribute.treat_as_withdraw.type is defined else '' }}"
+ "{{ (' range '+ path_attribute.treat_as_withdraw.range.start|string) if spath_attribute.treat_as_withdraw.range.start is defined else '' }}"
+ "{{ (' '+ path_attribute.treat_as_withdraw.range.end|string) if spath_attribute.treat_as_withdraw.range.end is defined else '' }}"
+ "{{ (' in') if path_attribute.treat_as_withdraw.in|d(False) else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "path_attribute": {
+ "treat_as_withdraw": {
+ "type": "{{ type }}",
+ "range": {"start": "{{ start }}", "end": "{{ end }}"},
+ "in": "{{ not not in }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "shutdown",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sshutdown
+ (\sgraceful(?P<graceful>\d+))?
+ (\scommunity(?P<community>\d+))?
+ (\s(?P<local_preference>local-preference))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }}"
+ "{{ (' shutdown') if shutdown.set|d(False) is defined else '' }}"
+ "{{ (' graceful '+ shutdown.graceful|string) if shutdown.graceful is defined else '' }}"
+ "{{ (' community '+ shutdown.community|string) if shutdown.community is defined else '' }}"
+ "{{ (' local-preference') if shutdown.local_preference|d(False) else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "shutdown": {
+ "set": True,
+ "graceful": "{{ graceful }}",
+ "community": "{{ community }}",
+ "local_preference": "{{ not not local_preference }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "soft_reconfiguration",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\ssoft-reconfiguration\sinbound
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }}"
+ "{{ (' soft-reconfiguration inbound') if soft_reconfiguration|d(False) else '' }}",
+ "result": {"neighbors": {"{{ neighbor_address }}": {"soft_reconfiguration": True}}},
+ },
+ {
+ "name": "ntimers",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\stimers
+ (\s(?P<interval>\d+))?
+ (\s(?P<holdtime>\d+))?
+ (\s(?P<min_holdtime>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} timers"
+ "{{ (' ' + ntimers.interval|string) if ntimers.interval is defined else '' }}"
+ "{{ (' ' + ntimers.holdtime|string) if ntimers.holdtime is defined else '' }}"
+ "{{ (' ' + ntimers.min_holdtime|string) if ntimers.min_holdtime is defined else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "timers": {
+ "interval": "{{ interval }}",
+ "holdtime": "{{ holdtime }}",
+ "min_holdtime": "{{ min_holdtime }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "transport.connection_mode",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\stransport\sconnection-mode
+ (\s(?P<active>active))?
+ (\s(?P<passive>passive))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} transport connection-mode"
+ "{{ (' active') if transport.connection_mode.active|d(False) else '' }}"
+ "{{ (' passive') if transport.connection_mode.passive|d(False) else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "transport": {
+ "connection_mode": {
+ "active": "{{ not not active }}",
+ "passive": "{{ not not passive }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "transport.multi_session",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\stransport\smulti-session
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} transport multi-session",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "neighbor_address": "{{ neighbor_address }}",
+ "transport": {"multi_session": True},
+ },
+ },
+ },
+ },
+ {
+ "name": "transport.path_mtu_discovery",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\stransport\spath-mtu-discovery
+ (\s(?P<disable>disable))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} transport"
+ "{{ (' path-mtu-discovery') if transport.path_mtu_discovery.set|d(False) else '' }}"
+ "{{ (' disable') if transport.path_mtu_discovery.disable|d(False) else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "transport": {
+ "path_mtu_discovery": {"set": True, "disable": "{{ not not disable }}"},
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "ttl_security",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sttl-security
+ (\shops(?P<ttl_security>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} ttl-security"
+ "{{ (' hops '+ ttl_security|string) if ttl_security is defined else '' }}",
+ "result": {
+ "neighbors": {"{{ neighbor_address }}": {"ttl_security": "{{ ttl_security }}"}},
+ },
+ },
+ {
+ "name": "unsuppress_map",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sunsuppress-map
+ (\s(?P<unsuppress_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} unsuppress-map"
+ "{{ (' ' + unsuppress_map) if unsuppress_map is defined else '' }}",
+ "result": {
+ "neighbors": {"{{ neighbor_address }}": {"unsuppress_map": "{{ unsuppress_map }}"}},
+ },
+ },
+ {
+ "name": "update_source",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\supdate-source
+ (\s(?P<update_source>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} update-source"
+ "{{ (' ' + update_source) if update_source is defined else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "update_source": "{{ update_source }}",
+ "neighbor_address": "{{ neighbor_address }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "version",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sversion
+ (\s(?P<version>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} version"
+ "{{ (' ' + version|string) if version is defined else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "neighbor_address": "{{ neighbor_address }}",
+ "version": "{{ version }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "weight",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sweight
+ (\s(?P<weight>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} weight"
+ "{{ (' ' + weight|string) if weight is defined else '' }}",
+ "result": {"neighbors": {"{{ neighbor_address }}": {"weight": "{{ weight }}"}}},
+ },
+ # neighbor remote-as ends
+ # neighbor peer-group starts
+ {
+ "name": "activate",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sactivate
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }}"
+ "{{ (' activate') if activate|d(False) else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "activate": True,
+ "neighbor_address": "{{ neighbor_address }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "additional_paths",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sadditional-paths
+ (\s(?P<disable>disable))?
+ (\s(?P<receive>receive))?
+ (\s(?P<send>send))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} additional-paths"
+ "{{ (' disable') if additional_paths.disable|d(False) else '' }}"
+ "{{ (' receive') if additional_paths.receive|d(False) else '' }}"
+ "{{ (' send') if additional_paths.send|d(False) else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "additional_paths": {
+ "disable": "{{ not not disable }}",
+ "receive": "{{ not not receive }}",
+ "send": "{{ not not send }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "advertise.additional_paths",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sadvertise\sadditional-paths
+ (\s(?P<all>all))?
+ (\sbest\s(?P<receive>\d+))?
+ (\s(?P<group_best>group-best))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} advertise additional-paths"
+ "{{ (' all') if advertise.additional_paths.all|d(False) else '' }}"
+ "{{ (' best '+ best|string) if advertise.additional_paths.best|d(False) else '' }}"
+ "{{ (' group-best') if advertise.additional_paths.group_best|d(False) else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "advertise": {
+ "additional_paths": {
+ "all": "{{ not not all }}",
+ "best": "{{ receive }}",
+ "group_best": "{{ not not group_best }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "advertise.best_external",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sadvertise\sbest-external
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }}"
+ "{{ (' advertise best-external') if advertise.best_external|d(False) else '' }}",
+ "result": {
+ "neighbors": {"{{ neighbor_address }}": {"advertise": {"best-external": True}}},
+ },
+ },
+ {
+ "name": "advertise.diverse_path",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sadvertise\sdiverse-path
+ (\s(?P<backup>backup))?
+ (\s(?P<mpath>mpath))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} advertise diverse-path"
+ "{{ (' backup') if advertise.diverse_path.backup|d(False) else '' }}"
+ "{{ (' mpath') if advertise.diverse_path.mpath|d(False) else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "advertise": {
+ "diverse_path": {
+ "backup": "{{ not not backup }}",
+ "mpath": "{{ not not mpath }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "advertise_map",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sadvertise-map
+ (\s(?P<name>\S+))?
+ (\sexist-map\s(?P<exist_map>\S+))?
+ (\snon-exist-map\s(?P<non_exist_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} advertise-map"
+ "{{ (' ' + name) if advertise_map.name is defined else '' }}"
+ "{{ (' exist-map ' + exist_map) if advertise_map.exist_map is defined else '' }}"
+ "{{ (' non-exist-map ' + non_exist_map) if advertise_map.non_exist_map is defined else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "advertise_map": {
+ "name": "{{ name }}",
+ "exist_map": "{{ exist_map }}",
+ "non_exist_map": "{{ non_exist_map }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "advertisement_interval",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sadvertisement-interval
+ (\s(?P<advertisement_interval>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} advertisement-interval"
+ "{{ (' ' + advertisement_interval|string) if advertisement_interval is defined else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "advertisement_interval": "{{ advertisement_interval }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "aigp",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\saigp
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' aigp') if aigp.enable|d(False) else '' }}",
+ "result": {"neighbors": {"{{ neighbor_address }}": {"aigp": {"enable": True}}}},
+ },
+ {
+ "name": "aigp.send.cost_community",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\saigp\ssend\scost-community
+ (\s(?P<id>\d+))\spoi
+ (\s(?P<igp_cost>igp-cost))?
+ (\s(?P<pre_bestpath>pre-bestpath))?
+ (\s(?P<transitive>transitive))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} aigp send cost-community"
+ "{{ (' ' + aigp.send.cost_community.id|string + ' poi') if aigp.send.cost_community.id is defined else '' }}"
+ "{{ (' igp-cost') if aigp.send.cost_community.poi.igp_cost|d(False) else '' }}"
+ "{{ (' pre-bestpath') if aigp.send.cost_community.poi.pre_bestpath|d(False) else '' }}"
+ "{{ (' transitive') if aigp.send.cost_community.poi.transitive|d(False) else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "aigp": {
+ "send": {
+ "cost_community": {
+ "id": "{{ id }}",
+ "poi": {
+ "igp_cost": "{{ not not igp_cost }}",
+ "pre_bestpath": "{{ not not pre_bestpath }}",
+ "transitive": "{{ not not transitive }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "aigp.send.med",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\saigp\ssend\smed
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }}"
+ "{{ (' aigp send med') if aigp.send.med|d(False) else '' }}",
+ "result": {"neighbors": {"{{ neighbor_address }}": {"aigp": {"send": {"med": True}}}}},
+ },
+ {
+ "name": "allow_policy",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sallow-policy
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' allow-policy') if allow_policy|d(False) else '' }}",
+ "result": {"neighbors": {"{{ neighbor_address }}": {"allow_policy": True}}},
+ },
+ {
+ "name": "allowas_in",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sallowas-in
+ (\s(?P<allowas_in>\d+))
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }}"
+ "{{ (' allowas-in ' + allowas_in|string) if allowas_in is defined else '' }}",
+ "result": {"neighbors": {"{{ neighbor_address }}": {"allowas_in": "{{ allowas_in }}"}}},
+ },
+ {
+ "name": "as_override",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sas-override
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }}"
+ "{{ (' as-override') if as_override|d(False) else '' }}",
+ "result": {"neighbors": {"{{ neighbor_address }}": {"as_override": True}}},
+ },
+ {
+ "name": "bmp_activate",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sbmp-activate
+ (\sserver\s(?P<server>\d+))?
+ (\s(?P<all>all))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} bmp-activate"
+ "{{ (' server '+ bmp_activate.server|string) if bmp_activate.server is defined else '' }}"
+ "{{ (' all') if bmp_activate.all|d(False) else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "neighbor_address": "{{ neighbor_address }}",
+ "bmp_activate": {"server": "{{ server }}", "all": "{{ not not all }}"},
+ },
+ },
+ },
+ },
+ {
+ "name": "capability",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\scapability\sorf\sprefix-list
+ (\s(?P<both>both))?
+ (\s(?P<receive>receive))?
+ (\s(?P<send>send))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} capability orf prefix-list"
+ "{{ (' both') if capability.both|d(False) else '' }}"
+ "{{ (' receive') if capability.receive|d(False) else '' }}"
+ "{{ (' send') if capability.send|d(False) else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "capability": {
+ "both": "{{ not not both }}",
+ "receive": "{{ not not receive }}",
+ "send": "{{ not not send }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "default_originate",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sdefault-originate
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' default-originate') if default_originate.set|d(False) else '' }}",
+ "result": {
+ "neighbors": {"{{ neighbor_address }}": {"default_originate": {"set": True}}},
+ },
+ },
+ {
+ "name": "default_originate.route_map",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sdefault-originate
+ (\sroute-map\s(?P<route_map>\S+))
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} default-originate"
+ "{{ (' route-map' + default_originate.route_map) if default_originate.route_map is defined else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "default-originate": {"route_map": "{{ route_map }}"},
+ },
+ },
+ },
+ },
+ {
+ "name": "distribute_list",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sdistribute-list
+ (\s(?P<acl>\S+))
+ (\s(?P<in>in))?
+ (\s(?P<out>out))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} distribute-list"
+ "{{ (' ' + distribute_list.acl) if distribute_list.acl is defined else '' }}"
+ "{{ (' in') if distribute_list.in|d(False) else '' }}"
+ "{{ (' out') if distribute_list.out|d(False) else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "distribute_list": {
+ "acl": "{{ acl }}",
+ "in": "{{ not not in }}",
+ "out": "{{ not not out }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "dmzlink_bw",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sdmzlink-bw
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' dmzlink-bw') if dmzlink_bw|d(False) else '' }}",
+ "result": {"neighbors": {"{{ neighbor_address }}": {"dmzlink_bw": True}}},
+ },
+ {
+ "name": "filter_list",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sfilter-list
+ (\s(?P<acl>\S+))
+ (\s(?P<in>in))?
+ (\s(?P<out>out))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} filter-list"
+ "{{ (' ' + filter_list.path_acl) if filter_list.path_acl is defined else '' }}"
+ "{{ (' in') if filter_list.in|d(False) else '' }}"
+ "{{ (' out') if filter_list.out|d(False) else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "filter_list": {
+ "path_acl": "{{ acl }}",
+ "in": "{{ not not in }}",
+ "out": "{{ not not out }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "maximum_prefix",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\smaximum-prefix
+ (\s(?P<max_no>\d+))
+ (\s(?P<threshold_val>\d+))?
+ (\srestart(?P<restart>\d+))?
+ (\s(?P<warning_only>warning-only))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} maximum-prefix"
+ "{{ (' ' + maximum_prefix.max_no|string) if maximum_prefix.max_no is defined else '' }}"
+ "{{ (' ' + maximum_prefix.threshold_val|string) if maximum_prefix.threshold_val is defined else '' }}"
+ "{{ (' restart ' + maximum_prefix.restart|string) if maximum_prefix.restart is defined else '' }}"
+ "{{ (' warning-only') if maximum_prefix.warning_only|d(False) else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "maximum_prefix": {
+ "max_no": "{{ max_no }}",
+ "threshold_val": "{{ threshold_val }}",
+ "restart": "{{ restart }}",
+ "warning_only": "{{ not not warning_only }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "next_hop_self.set",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\snext-hop-self
+ $""",
+ 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}}}},
+ },
+ {
+ "name": "next_hop_self.all",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\snext-hop-self\sall
+ $""",
+ 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}}}},
+ },
+ {
+ "name": "next_hop_unchanged.set",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\snext-hop-unchanged
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' next-hop-unchanged') if next_hop_unchanged.set|d(False) else ''}}",
+ "result": {
+ "neighbors": {"{{ neighbor_address }}": {"next_hop_unchanged": {"set": True}}},
+ },
+ },
+ {
+ "name": "next_hop_unchanged.allpaths",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\snext-hop-unchanged\sallpaths
+ $""",
+ re.VERBOSE,
+ ),
+ "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}}},
+ },
+ },
+ {
+ "name": "remove_private_as.set",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sremove-private-as
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' remove-private-as') if remove_private_as.set|d(False) else '' }}",
+ "result": {
+ "neighbors": {"{{ neighbor_address }}": {"remove_private_as": {"set": True}}},
+ },
+ },
+ {
+ "name": "remove_private_as.all",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sremove-private-as\sall
+ $""",
+ re.VERBOSE,
+ ),
+ "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}}},
+ },
+ },
+ {
+ "name": "remove_private_as.replace_as",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sremove-private-as\sreplace-as
+ $""",
+ re.VERBOSE,
+ ),
+ "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}},
+ },
+ },
+ },
+ {
+ "name": "route_maps",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sroute-map
+ (\s(?P<route_maps>\S+))
+ (\s(?P<in>in))?
+ (\s(?P<out>out))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ route_maps.neighbor_address }} route-map"
+ "{{ (' ' + route_maps.name) if route_maps.name is defined else '' }}"
+ "{{ (' in') if route_maps.in|d(False) else '' }}"
+ "{{ (' out') if route_maps.out|d(False) else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "route_maps": [
+ {
+ "name": "{{ route_maps }}",
+ "in": "{{ not not in }}",
+ "out": "{{ not not out }}",
+ },
+ ],
+ },
+ },
+ },
+ },
+ {
+ "name": "route_reflector_client",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sroute-reflector-client
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' route-reflector-client') if route_reflector_client|d(False) else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "neighbor_address": "{{ neighbor_address }}",
+ "route_reflector_client": True,
+ },
+ },
+ },
+ },
+ {
+ "name": "route_server_client.set",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sroute-server-client
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' route-server-client') if route_server_client.set|d(False) else '' }}",
+ "result": {
+ "neighbors": {"{{ neighbor_address }}": {"route_server_client": {"set": True}}},
+ },
+ },
+ {
+ "name": "route_server_client.context",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sroute-server-client
+ (\scontext(?P<context>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} route-server-client"
+ "{{ (' context ' + route_server_client.context) if route_server_client.context is defined else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {"route_server_client": {"context": "{{ context }}"}},
+ },
+ },
+ },
+ {
+ "name": "send_community.set",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\ssend-community
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' send-community') if send_community.set|d(False) else '' }}",
+ "result": {"neighbors": {"{{ neighbor_address }}": {"send_community": {"set": True}}}},
+ },
+ {
+ "name": "send_community.both",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\ssend-community\sboth
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} send-community"
+ "{{ (' both') if send_community.both|d(False) else '' }}",
+ "result": {"neighbors": {"{{ neighbor_address }}": {"send_community": {"both": True}}}},
+ },
+ {
+ "name": "send_community.extended",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\ssend-community\sextended
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} send-community"
+ "{{ (' extended') if send_community.extended|d(False) else '' }}",
+ "result": {
+ "neighbors": {"{{ neighbor_address }}": {"send_community": {"extended": True}}},
+ },
+ },
+ {
+ "name": "send_community.standard",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\ssend-community\sstandard
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} send-community"
+ "{{ (' standard') if send_community.standard|d(False) else '' }}",
+ "result": {
+ "neighbors": {"{{ neighbor_address }}": {"send_community": {"standard": True}}},
+ },
+ },
+ {
+ "name": "send_label.set",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\ssend-label
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' send-label') if send_label.set|d(False) else '' }}",
+ "result": {"neighbors": {"{{ neighbor_address }}": {"send_label": {"set": True}}}},
+ },
+ {
+ "name": "send_label.explicit_null",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sexplicit-null
+ $""",
+ re.VERBOSE,
+ ),
+ "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}}},
+ },
+ },
+ {
+ "name": "slow_peer.detection",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sslow-peer\sdetection
+ (\s(?P<enable>enable))?
+ (\s(?P<disable>disable))?
+ (\sthreshold\s(?P<threshold>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} slow-peer detection"
+ "{{ (' enable') if slow_peer.detection.enable|d(False) else '' }}"
+ "{{ (' disable') if slow_peer.detection.disable|d(False) else '' }}"
+ "{{ (' threshold ' + slow_peer.detection.threshold|string) if slow_peer.detection.threshold is defined else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "slow_peer": {
+ "detection": {
+ "enable": "{{ not not enable }}",
+ "disable": "{{ not not disable }}",
+ "threshold": "{{ threshold }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "slow_peer.split_update_group",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\sslow-peer\ssplit-update-group
+ (\s(?P<static>static))?
+ (\s(?P<dynamic>dynamic))?
+ (\s(?P<disable>disable))?
+ (\s(?P<permanent>permanent))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} slow-peer split-update-group"
+ "{{ (' static') if slow_peer.split_update_group.static|d(False) else '' }}"
+ "{{ (' dynamic') if slow_peer.split_update_group.dynamic.enable|d(False) else '' }}"
+ "{{ (' disable') if slow_peer.split_update_group.dynamic.disable|d(False) else '' }}"
+ "{{ (' permanent') if slow_peer.split_update_group.dynamic.permanent|d(False) else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "slow_peer": {
+ "split_update_group": {
+ "static": "{{ not not static }}",
+ "dynamic": {
+ "enable": "{{ not not dynamic }}",
+ "disable": "{{ not not disable }}",
+ "permanent": "{{ not not permanent }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "translate_update.set",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\stranslate-update
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ ('neighbor ' + neighbor_address + ' translate_update') if translate_update.set|d(False) else '' }}",
+ "result": {
+ "neighbors": {"{{ neighbor_address }}": {"translate_update": {"set": True}}},
+ },
+ },
+ {
+ "name": "translate_update.nlri",
+ "getval": re.compile(
+ r"""
+ \sneighbor\s(?P<neighbor_address>\S+)\stranslate-update\snlri
+ (\s(?P<multicast>multicast))?
+ (\s(?P<unicast>unicast))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "neighbor {{ neighbor_address }} translate-update nlri"
+ "{{ (' multicast') if translate_update.nlri.multicast|d(False) else '' }}"
+ "{{ (' unicast') if translate_update.nlri.unicast|d(False) else '' }}",
+ "result": {
+ "neighbors": {
+ "{{ neighbor_address }}": {
+ "translate_update": {
+ "nlri": {
+ "multicast": "{{ not not multicast }}",
+ "unicast": "{{ not not unicast }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ # neighbor peer-group ends
+ # redistribute starts
+ {
+ "name": "application",
+ "getval": re.compile(
+ r"""
+ \sredistribute\sapplication\s(?P<name>\S+)
+ (\smetric\s(?P<metric>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute application {{ application.name }}"
+ "{{ (' metric ' + application.metric|string) if application.metric is defined else '' }}"
+ "{{ (' route-map ' + application.route_map) if application.route_map is defined else '' }}",
+ "remval": "redistribute application {{ application.name }}",
+ "result": {
+ "redistribute": [
+ {
+ "application": {
+ "name": "{{ name }}",
+ "metric": "{{ metric }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "bgp",
+ "getval": re.compile(
+ r"""
+ \sredistribute\sbgp\s(?P<name>\S+)
+ (\smetric\s(?P<metric>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute bgp {{ bgp.name }}"
+ "{{ (' metric ' + bgp.metric|string) if bgp.metric is defined else '' }}"
+ "{{ (' route-map ' + bgp.route_map) if bgp.route_map is defined else '' }}",
+ "remval": "redistribute bgp {{ bgp.name }}",
+ "result": {
+ "redistribute": [
+ {
+ "bgp": {
+ "name": "{{ name }}",
+ "metric": "{{ metric }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "connected",
+ "getval": re.compile(
+ r"""
+ \sredistribute\sconnected
+ (\smetric\s(?P<metric>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute connected"
+ "{{ (' metric ' + connected.metric|string) if connected.metric is defined else '' }}"
+ "{{ (' route-map ' + connected.route_map) if connected.route_map is defined else '' }}",
+ "remval": "redistribute connected",
+ "result": {
+ "redistribute": [
+ {
+ "connected": {
+ "set": True,
+ "metric": "{{ metric }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "eigrp",
+ "getval": re.compile(
+ r"""
+ \sredistribute\seigrp\s(?P<name>\S+)
+ (\smetric\s(?P<metric>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute eigrp {{ eigrp.name|string }}"
+ "{{ (' metric ' + eigrp.metric|string) if eigrp.metric is defined else '' }}"
+ "{{ (' route-map ' + eigrp.route_map) if eigrp.route_map is defined else '' }}",
+ "remval": "redistribute eigrp {{ eigrp.name|string }}",
+ "result": {
+ "redistribute": [
+ {
+ "eigrp": {
+ "as_number": "{{ name }}",
+ "metric": "{{ metric }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "isis",
+ "getval": re.compile(
+ r"""
+ \sredistribute\sisis\s(?P<name>\S+)
+ (\s(?P<clns>clns))?
+ (\s(?P<ip>ip))?
+ (\smetric\s(?P<metric>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute isis {{ isis.area_tag }}"
+ "{{ (' clns') if isis.clns|d(False) else '' }}"
+ "{{ (' ip') if isis.ip|d(False) else '' }}"
+ "{{ (' metric ' + isis.metric|string) if isis.metric is defined else '' }}"
+ "{{ (' route-map ' + isis.route_map) if isis.route_map is defined else '' }}",
+ "remval": "redistribute isis {{ isis.area_tag }}",
+ "result": {
+ "redistribute": [
+ {
+ "isis": {
+ "area_tag": "{{ name }}",
+ "clns": "{{ not not clns }}",
+ "ip": "{{ not not ip }}",
+ "metric": "{{ metric }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "iso_igrp",
+ "getval": re.compile(
+ r"""
+ \sredistribute\siso-igrp\s(?P<name>\S+)
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute iso-igrp {{ iso_igrp.area_tag }}"
+ "{{ (' route-map ' + iso_igrp.route_map) if iso_igrp.route_map is defined else '' }}",
+ "remval": "redistribute iso-igrp {{ iso_igrp.area_tag }}",
+ "result": {
+ "redistribute": [
+ {"iso_igrp": {"area_tag": "{{ name }}", "route_map": "{{ route_map }}"}},
+ ],
+ },
+ },
+ {
+ "name": "lisp",
+ "getval": re.compile(
+ r"""
+ \sredistribute\slisp
+ (\smetric\s(?P<metric>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute lisp"
+ "{{ (' metric ' + lisp.metric|string) if lisp.metric is defined else '' }}"
+ "{{ (' route-map ' + lisp.route_map) if lisp.route_map is defined else '' }}",
+ "remval": "redistribute lisp",
+ "result": {
+ "redistribute": [
+ {
+ "lisp": {
+ "set": True,
+ "metric": "{{ metric }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "mobile",
+ "getval": re.compile(
+ r"""
+ \sredistribute\smobile
+ (\smetric\s(?P<metric>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute mobile"
+ "{{ (' metric ' + mobile.metric|string) if mobile.metric is defined else '' }}"
+ "{{ (' route-map ' + mobile.route_map) if mobile.route_map is defined else '' }}",
+ "remval": "redistribute mobile",
+ "result": {
+ "redistribute": [
+ {
+ "mobile": {
+ "set": True,
+ "metric": "{{ metric }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "odr",
+ "getval": re.compile(
+ r"""
+ \sredistribute\sodr
+ (\smetric\s(?P<metric>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute odr"
+ "{{ (' metric ' + odr.metric|string) if odr.metric is defined else '' }}"
+ "{{ (' route-map ' + odr.route_map) if odr.route_map is defined else '' }}",
+ "remval": "redistribute odr",
+ "result": {
+ "redistribute": [
+ {
+ "odr": {
+ "set": True,
+ "metric": "{{ metric }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "ospf",
+ "getval": re.compile(
+ r"""
+ \sredistribute\sospf\s(?P<process_id>\S+)
+ (\s(?P<type_1>1))?
+ (\s(?P<type_2>2))?
+ (\s(?P<external>external))?
+ (\s(?P<internal>internal))?
+ (\s(?P<nssa_external>nssa-external))?
+ (\smetric\s(?P<metric>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ (\svrf\s(?P<vrf>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute ospf {{ ospf.process_id }}"
+ "{{ (' 1') if ospf.match.type_1|d(False) else '' }}"
+ "{{ (' 2') if ospf.match.type_2|d(False) else '' }}"
+ "{{ (' external') if ospf.match.external|d(False) else '' }}"
+ "{{ (' internal') if ospf.match.internal|d(False) else '' }}"
+ "{{ (' nssa-external') if ospf.match.nssa_external|d(False) else '' }}"
+ "{{ (' metric ' + ospf.metric|string) if ospf.metric is defined else '' }}"
+ "{{ (' route-map ' + ospf.route_map) if ospf.route_map is defined else '' }}"
+ "{{ (' vrf ' + ospf.vrf) if ospf.vrf is defined else '' }}",
+ "remval": "redistribute ospf {{ ospf.process_id }}",
+ "result": {
+ "redistribute": [
+ {
+ "ospf": {
+ "process_id": "{{ process_id }}",
+ "match": {
+ "type_1": "{{ not not type_1 }}",
+ "type_2": "{{ not not type_2 }}",
+ "external": "{{ not not external }}",
+ "internal": "{{ not not internal }}",
+ "nssa_external": "{{ not not nssa_external }}",
+ },
+ "metric": "{{ metric }}",
+ "route_map": "{{ route_map }}",
+ "vrf": "{{ vrf }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "ospfv3",
+ "getval": re.compile(
+ r"""
+ \sredistribute\sospfv3\s(?P<process_id>\S+)
+ (\s(?P<type_1>1))?
+ (\s(?P<type_2>2))?
+ (\s(?P<external>external))?
+ (\s(?P<internal>internal))?
+ (\s(?P<nssa_external>nssa-external))?
+ (\smetric\s(?P<metric>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute ospfv3 {{ ospfv3.process_id }}"
+ "{{ (' 1') if ospfv3.match.type_1|d(False) else '' }}"
+ "{{ (' 2') if ospfv3.match.type_2|d(False) else '' }}"
+ "{{ (' external') if ospfv3.match.external|d(False) else '' }}"
+ "{{ (' internal') if ospfv3.match.internal|d(False) else '' }}"
+ "{{ (' nssa-external') if ospfv3.match.nssa_external|d(False) else '' }}"
+ "{{ (' metric ' + ospfv3.metric|string) if ospfv3.metric is defined else '' }}"
+ "{{ (' route-map ' + ospfv3.route_map) if ospfv3.route_map is defined else '' }}",
+ "remval": "redistribute ospfv3 {{ ospfv3.process_id }}",
+ "result": {
+ "redistribute": [
+ {
+ "ospfv3": {
+ "process_id": "{{ process_id }}",
+ "match": {
+ "type_1": "{{ not not type_2 }}",
+ "type_2": "{{ not not type_2 }}",
+ "external": "{{ not not external }}",
+ "internal": "{{ not not internal }}",
+ "nssa_external": "{{ not not nssa_external }}",
+ },
+ "metric": "{{ metric }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "rip",
+ "getval": re.compile(
+ r"""
+ \sredistribute\srip
+ (\smetric\s(?P<metric>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute rip"
+ "{{ (' metric ' + rip.metric|string) if rip.metric is defined else '' }}"
+ "{{ (' route-map ' + rip.route_map) if rip.route_map is defined else '' }}",
+ "remval": "redistribute rip",
+ "result": {
+ "redistribute": [
+ {
+ "rip": {
+ "set": True,
+ "metric": "{{ metric }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "static",
+ "getval": re.compile(
+ r"""
+ \sredistribute\sstatic
+ (\s(?P<clns>clns))?
+ (\s(?P<ip>ip))?
+ (\smetric\s(?P<metric>\d+))?
+ (\sroute-map\s(?P<route_map>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute static"
+ "{{ (' clns') if static.clns|d(False) else '' }}"
+ "{{ (' ip') if static.ip|d(False) else '' }}"
+ "{{ (' metric ' + static.metric|string) if static.metric is defined else '' }}"
+ "{{ (' route-map ' + static.route_map) if static.route_map is defined else '' }}",
+ "remval": "redistribute static",
+ "result": {
+ "redistribute": [
+ {
+ "static": {
+ "set": True,
+ "clns": "{{ not not clns }}",
+ "ip": "{{ not not ip }}",
+ "metric": "{{ metric }}",
+ "route_map": "{{ route_map }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "vrf",
+ "getval": re.compile(
+ r"""
+ \sredistribute\svrf
+ (\s(?P<name>\S+))?
+ (\s(?P<global>global))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "redistribute vrf {{ vrf.name }}"
+ "{{ (' global') if vrf.global|d(False) else '' }}",
+ "remval": "redistribute vrf {{ vrf.name }}",
+ "result": {
+ "redistribute": [{"vrf": {"name": "{{ name }}", "global": "{{ not not global }}"}}],
+ },
+ },
+ # redistribute ends
+ ]
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/hostname.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/hostname.py
new file mode 100644
index 000000000..bf922fb4c
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/hostname.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+# Copyright 2022 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 Hostname 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 HostnameTemplate(NetworkTemplate):
+ def __init__(self, lines=None, module=None):
+ super(HostnameTemplate, self).__init__(lines=lines, tmplt=self, module=module)
+
+ # fmt: off
+ PARSERS = [
+ {
+ "name": "hostname",
+ "getval": re.compile(
+ r"""
+ ^hostname\s(?P<hostname>\S+)
+ $""", re.VERBOSE,
+ ),
+ "setval": "hostname {{ hostname }}",
+ "result": {
+ "hostname": "{{ hostname }}",
+ },
+ },
+ ]
+ # fmt: on
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/interfaces.py
new file mode 100644
index 000000000..084945143
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/interfaces.py
@@ -0,0 +1,147 @@
+# -*- coding: utf-8 -*-
+# Copyright 2022 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 Interfaces 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 InterfacesTemplate(NetworkTemplate):
+ def __init__(self, lines=None, module=None):
+ super(InterfacesTemplate, self).__init__(lines=lines, tmplt=self, module=module)
+
+ # fmt: off
+ PARSERS = [
+ {
+ 'name': 'interface',
+ 'getval': re.compile(
+ r'''
+ ^interface\s
+ (?P<name>\S+)$''', re.VERBOSE,
+ ),
+ 'setval': 'interface {{ name }}',
+ 'result': {
+ '{{ name }}': {
+ 'name': '{{ name }}',
+ },
+ },
+ 'shared': True,
+ },
+ {
+ "name": "description",
+ "getval": re.compile(
+ r"""
+ \s+description\s(?P<description>.+$)
+ $""", re.VERBOSE,
+ ),
+ "setval": "description {{ description }}",
+ "result": {
+ '{{ name }}': {
+ 'description': '{{ description }}',
+ },
+ },
+ },
+ {
+ "name": "enabled",
+ "getval": re.compile(
+ r"""
+ (?P<negate>\sno)?
+ (?P<shutdown>\sshutdown)
+ $""", re.VERBOSE,
+ ),
+ "setval": "shutdown",
+ "result": {
+ '{{ name }}': {
+ 'enabled': "{{ False if shutdown is defined and negate is not defined else True }}",
+ },
+ },
+ },
+ { # only applicable for switches
+ "name": "mode",
+ "getval": re.compile(
+ r"""
+ (?P<negate>\sno)?
+ (?P<switchport>\sswitchport)
+ $""", re.VERBOSE,
+ ),
+ "setval": "switchport",
+ "result": {
+ '{{ name }}': {
+ 'mode': "{{ 'layer2' if switchport is defined and negate is not defined else 'layer3' }}",
+ },
+ },
+ },
+ {
+ "name": "speed",
+ "getval": re.compile(
+ r"""
+ \s+speed\s(?P<speed>.+$)
+ $""", re.VERBOSE,
+ ),
+ "setval": "speed {{ speed|string }}",
+ "result": {
+ '{{ name }}': {
+ 'speed': '{{ speed }}',
+ },
+ },
+ },
+ {
+ "name": "mtu",
+ "getval": re.compile(
+ r"""
+ \s+mtu\s(?P<mtu>.+$)
+ $""", re.VERBOSE,
+ ),
+ "setval": "mtu {{ mtu|string }}",
+ "result": {
+ '{{ name }}': {
+ 'mtu': '{{ mtu }}',
+ },
+ },
+ },
+ {
+ "name": "duplex",
+ "getval": re.compile(
+ r"""
+ \s+duplex\s(?P<duplex>full|half|auto)
+ $""", re.VERBOSE,
+ ),
+ "setval": "duplex {{ duplex }}",
+ "result": {
+ '{{ name }}': {
+ 'duplex': '{{ duplex }}',
+ },
+ },
+ },
+ {
+ "name": "template",
+ "getval": re.compile(
+ r"""
+ \s+source\stemplate\s(?P<template>.+$)
+ """, re.VERBOSE,
+ ),
+ "setval": "source template {{ template }}",
+ "result": {
+ '{{ name }}': {
+ 'template': '{{ template }}',
+ },
+ },
+ },
+ ]
+ # fmt: on
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/l2_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/l2_interfaces.py
new file mode 100644
index 000000000..30ddb405c
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/l2_interfaces.py
@@ -0,0 +1,250 @@
+# -*- coding: utf-8 -*-
+# Copyright 2022 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 L2_interfaces 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 L2_interfacesTemplate(NetworkTemplate):
+ def __init__(self, lines=None, module=None):
+ super(L2_interfacesTemplate, self).__init__(lines=lines, tmplt=self, module=module)
+
+ # fmt: off
+ PARSERS = [
+ {
+ "name": "name",
+ "getval": re.compile(
+ r"""^interface
+ (\s(?P<name>\S+))
+ $""",
+ re.VERBOSE,
+ ),
+ "compval": "name",
+ "setval": "interface {{ name }}",
+ "result": {"{{ name }}": {"name": "{{ name }}"}},
+ "shared": True,
+ },
+ {
+ "name": "access.vlan",
+ "getval": re.compile(
+ r"""
+ \s+switchport\saccess\svlan\s(?P<vlan>\d+)
+ $""", re.VERBOSE,
+ ),
+ "setval": "switchport access vlan {{ access.vlan }}",
+ "remval": "switchport access vlan",
+ "result": {
+ "{{ name }}": {
+ "access": {
+ "vlan": "{{ vlan }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "access.vlan_name",
+ "getval": re.compile(
+ r"""
+ \s+switchport\saccess\svlan\sname\s(?P<vlan_name>\S+)
+ $""", re.VERBOSE,
+ ),
+ "setval": "switchport access vlan name {{ access.vlan_name }}",
+ "result": {
+ "{{ name }}": {
+ "access": {
+ "vlan_name": "{{ vlan_name }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "voice.vlan",
+ "getval": re.compile(
+ r"""
+ \s+switchport\svoice\svlan\s(?P<vlan>\d+)
+ $""", re.VERBOSE,
+ ),
+ "setval": "switchport voice vlan {{ voice.vlan|string }}",
+ "remval": "switchport voice vlan",
+ "result": {
+ "{{ name }}": {
+ "voice": {
+ "vlan": "{{ vlan }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "voice.vlan_tag",
+ "getval": re.compile(
+ r"""
+ \s+switchport\svoice\svlan\s(?P<vlan_tag>dot1p|none|untagged)
+ $""", re.VERBOSE,
+ ),
+ "setval": "switchport voice vlan {{ voice.vlan_tag }}",
+ "remval": "switchport voice vlan",
+ "result": {
+ "{{ name }}": {
+ "voice": {
+ "vlan_tag": "{{ vlan_tag }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "voice.vlan_name",
+ "getval": re.compile(
+ r"""
+ \s+switchport\svoice\svlan\sname\s(?P<vlan_name>\S+)
+ $""", re.VERBOSE,
+ ),
+ "setval": "switchport voice vlan name {{ voice.vlan_name }}",
+ "result": {
+ "{{ name }}": {
+ "voice": {
+ "vlan_name": "{{ vlan_name }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "mode",
+ "getval": re.compile(
+ r"""
+ \s+switchport\smode\s(?P<mode>access|trunk|dynamic|dynamic\sauto|dynamic\sdesirable|private-vlan\shost|private-vlan\spromiscuous|private-vlan\strunk\ssecondary|dot1q-tunnel)
+ $""", re.VERBOSE,
+ ),
+ "setval": "switchport mode "
+ "{{ 'trunk' if mode == 'trunk' }}"
+ "{{ 'access' if mode == 'access' }}"
+ "{{ 'dynamic' if mode == 'dynamic' }}"
+ "{{ 'dynamic desirable' if mode == 'dynamic_desirable' }}"
+ "{{ 'dynamic auto' if mode == 'dynamic_auto' }}"
+ "{{ 'dot1q-tunnel' if mode == 'dot1q_tunnel' }}"
+ "{{ 'private-vlan host' if mode == 'private_vlan_host' }}"
+ "{{ 'private-vlan promiscuous' if mode == 'private_vlan_promiscuous' }}"
+ "{{ 'private-vlan trunk secondary' if mode == 'private_vlan_trunk' }}",
+ "remval": "switchport mode",
+ "result": {
+ "{{ name }}": {
+ "mode": "{{ mode }}",
+ },
+ },
+ },
+ {
+ "name": "trunk.allowed_vlans",
+ "getval": re.compile(
+ r"""
+ \s+switchport\strunk\sallowed\svlan\s(?P<allowed_vlan>\S+)
+ $""", re.VERBOSE,
+ ),
+ "setval": "",
+ "result": {
+ "{{ name }}": {
+ "trunk": {
+ "allowed_vlans": "{{ allowed_vlan.split(',') }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "trunk.allowed_vlans_add",
+ "getval": re.compile(
+ r"""
+ \s+switchport\strunk\sallowed\svlan\sadd\s(?P<allowed_vlans_add>\S+$)
+ """, re.VERBOSE,
+ ),
+ "setval": "",
+ "result": {
+ "{{ name }}": {
+ "trunk": {
+ "allowed_vlans_add": ["{{ allowed_vlans_add.split(',') }}"],
+ },
+ },
+ },
+ },
+ {
+ "name": "trunk.encapsulation",
+ "getval": re.compile(
+ r"""
+ \s+switchport\strunk\sencapsulation\s(?P<encapsulation>dot1q|isl|negotiate)
+ $""", re.VERBOSE,
+ ),
+ "setval": "switchport trunk encapsulation {{ trunk.encapsulation }}",
+ "remval": "switchport trunk encapsulation",
+ "result": {
+ "{{ name }}": {
+ "trunk": {
+ "encapsulation": "{{ encapsulation }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "trunk.native_vlan",
+ "getval": re.compile(
+ r"""
+ \s+switchport\strunk\snative\svlan\s(?P<native_vlan>\d+)
+ $""", re.VERBOSE,
+ ),
+ "setval": "switchport trunk native vlan {{ trunk.native_vlan }}",
+ "remval": "switchport trunk native vlan",
+ "result": {
+ "{{ name }}": {
+ "trunk": {
+ "native_vlan": "{{ native_vlan }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "trunk.pruning_vlans",
+ "getval": re.compile(
+ r"""
+ \s+switchport\strunk\spruning\svlan\s(?P<pruning_vlans>\S+)
+ $""", re.VERBOSE,
+ ),
+ "setval": "",
+ "result": {
+ "{{ name }}": {
+ "trunk": {
+ "pruning_vlans": "{{ pruning_vlans.split(',') }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "trunk.pruning_vlans_add",
+ "getval": re.compile(
+ r"""
+ \s+switchport\strunk\spruning\svlan\sadd\s(?P<pruning_vlans_add>\S+)
+ $""", re.VERBOSE,
+ ),
+ "setval": "",
+ "result": {
+ "{{ name }}": {
+ "trunk": {
+ "pruning_vlans_add": ["{{ pruning_vlans_add.split(',') }}"],
+ },
+ },
+ },
+ },
+ ]
+ # fmt: on
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/l3_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/l3_interfaces.py
new file mode 100644
index 000000000..d57a8ded8
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/l3_interfaces.py
@@ -0,0 +1,231 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 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 L3_interfaces 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,
+)
+
+
+def ip_tmplt(config_data):
+ cmd = "ipv6 address {ip}"
+ if config_data.get("ipv6"):
+ config = config_data.get("ipv6")
+ cmd = cmd.format(ip=config["address"])
+ if config.get("segment_routing"):
+ # if config.get("segment_routing").get("enable"):
+ cmd += " segment-routing"
+ if config.get("segment_routing").get("default"):
+ cmd += " default"
+ if config.get("segment_routing").get("ipv6_sr"):
+ cmd += " ipv6-sr"
+ if config.get("secondary"):
+ cmd += " secondary"
+ if config.get("link_local"):
+ cmd += " link-local"
+ if config.get("anycast"):
+ cmd += " anycast"
+ if config.get("cga"):
+ cmd += " cga"
+ if config.get("eui"):
+ cmd += " eui"
+ return cmd
+
+
+def ipv4_dhcp(config_data):
+ _data = config_data.get("ipv4", {}).get("dhcp")
+ if not _data.get("enable", True):
+ return ""
+ cmd = "ip address dhcp"
+ if _data.get("client_id"):
+ cmd += " client-id {client_id}".format(**_data)
+ if _data.get("hostname"):
+ cmd += " hostname {hostname}".format(**_data)
+ return cmd
+
+
+class L3_interfacesTemplate(NetworkTemplate):
+ def __init__(self, lines=None, module=None):
+ super(L3_interfacesTemplate, self).__init__(lines=lines, tmplt=self, module=module)
+
+ # fmt: off
+ PARSERS = [
+ {
+ "name": "name",
+ "getval": re.compile(
+ r"""^interface
+ (\s(?P<name>\S+))
+ $""",
+ re.VERBOSE,
+ ),
+ "compval": "name",
+ "setval": "interface {{ name }}",
+ "result": {"{{ name }}": {"name": "{{ name }}"}},
+ "shared": True,
+ },
+ {
+ "name": "ipv4.address",
+ "getval": re.compile(
+ r"""\s+ip\saddress
+ (\s(?P<ipv4>\S+))
+ (\s(?P<netmask>\S+))
+ (\s(?P<secondary>secondary))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "ip address {{ ipv4.address }}"
+ "{{ ' secondary' if ipv4.secondary|d(False) else ''}}",
+ "result": {
+ "{{ name }}": {
+ "ipv4": [
+ {
+ "address": "{{ ipv4 }}",
+ "netmask": "{{ netmask }}",
+ "secondary": "{{ True if secondary is defined }}",
+ },
+ ],
+ },
+ },
+ },
+ {
+ "name": "ipv4.pool",
+ "getval": re.compile(
+ r"""
+ \s+ip\saddress\spool\s(?P<pool>.+$)
+ $""", re.VERBOSE,
+ ),
+ "setval": "ip address pool {{ ipv4.pool }}",
+ "result": {
+ "{{ name }}": {
+ "ipv4": [
+ {
+ "pool": "{{ pool }}",
+ },
+ ],
+ },
+ },
+ },
+ {
+ "name": "ipv4.dhcp",
+ "getval": re.compile(
+ r"""\s+ip\saddress\s
+ ((?P<dhcp>dhcp))
+ (\sclient-id\s(?P<client_id>\S+))?
+ (\shostname\s(?P<hostname>\S+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": ipv4_dhcp,
+ "result": {
+ "{{ name }}": {
+ "ipv4": [
+ {
+ "dhcp": {
+ "enable": "{{ True if dhcp is defined }}",
+ "client_id": "{{ client_id }}",
+ "hostname": "{{ hostname }}",
+ },
+ },
+ ],
+ },
+ },
+ },
+ {
+ "name": "ipv6.address",
+ "getval": re.compile(
+ r"""\s+ipv6\saddress
+ (\s(?P<ipv6>\b(?!autoconfig\b)\S+))
+ (\s(?P<link_local>link-local))?
+ (\s(?P<anycast>anycast))?
+ (\s(?P<cga>cga))?
+ (\s(?P<eui>eui))?
+ (\s(?P<enable>segment-routing))?
+ (\s(?P<default>default))?
+ (\s(?P<ipv6_sr>ipv6-sr))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": ip_tmplt,
+ "result": {
+ "{{ name }}": {
+ "ipv6": [
+ {
+ "address": "{{ ipv6 }}",
+ "link_local": "{{ True if link_local is defined }}",
+ "anycast": "{{ True if anycast is defined }}",
+ "cga": "{{ True if cga is defined }}",
+ "eui": "{{ True if eui is defined }}",
+ "segment_routing": {
+ "enable": "{{ True if enable is defined }}",
+ "default": "{{ True if default is defined }}",
+ "ipv6_sr": "{{ True if ipv6_sr is defined }}",
+ },
+ },
+ ],
+ },
+ },
+ },
+ {
+ "name": "ipv6.autoconfig",
+ "getval": re.compile(
+ r"""\s+ipv6\saddress\s
+ ((?P<enable>autoconfig))
+ (\s(?P<default>default))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ipv6 address autoconfig' if ipv6.autoconfig.enable|d(False) or ipv6.autoconfig.default|d(False) else ''}}"
+ "{{ ' default' if ipv6.autoconfig.default|d(False) else ''}}",
+ "result": {
+ "{{ name }}": {
+ "ipv6": [
+ {
+ "autoconfig": {
+ "enable": "{{ True if enable is defined }}",
+ "default": "{{ True if default is defined }}",
+ },
+ },
+ ],
+ },
+ },
+ },
+ {
+ "name": "ipv6.dhcp",
+ "getval": re.compile(
+ r"""\s+ipv6\saddress\sdhcp
+ (\s(?P<rapid_commit>rapid-commit))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ipv6 address dhcp' if ipv6.dhcp.enable|d(False)|d(False) or ipv6.dhcp.rapid_commit|d(False)|d(False)else ''}}"
+ "{{ ' rapid-commit' if ipv6.dhcp.rapid_commit|d(False) else ''}}",
+ "result": {
+ "{{ name }}": {
+ "ipv6": [
+ {
+ "dhcp": {
+ "enable": True,
+ "rapid_commit": "{{ True if rapid_commit is defined }}",
+ },
+ },
+ ],
+ },
+ },
+ },
+ ]
+ # fmt: on
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/lag_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/lag_interfaces.py
new file mode 100644
index 000000000..8bee47581
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/lag_interfaces.py
@@ -0,0 +1,70 @@
+# -*- coding: utf-8 -*-
+# Copyright 2022 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 Lag_interfaces 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 Lag_interfacesTemplate(NetworkTemplate):
+ def __init__(self, lines=None, module=None):
+ super(Lag_interfacesTemplate, self).__init__(lines=lines, tmplt=self, module=module)
+
+ # fmt: off
+ PARSERS = [
+ {
+ 'name': 'member',
+ 'getval': re.compile(
+ r'''
+ ^interface\s
+ (?P<member>\S+)$''', re.VERBOSE,
+ ),
+ 'setval': 'interface {{ member }}',
+ 'result': {
+ '{{ member }}': {
+ 'member': '{{ member }}',
+ },
+ },
+ 'shared': True,
+ },
+ {
+ "name": "channel",
+ "getval": re.compile(
+ r"""
+ \s+channel-group
+ (\s(?P<channel>\d+))?
+ (\smode\s(?P<mode>active|passive|on|desirable|auto))?
+ (\slink\s(?P<link>\d+))?
+ $""", re.VERBOSE,
+ ),
+ "setval": "channel-group"
+ "{{ (' ' + channel|string) if channel is defined else '' }}"
+ "{{ (' mode ' + mode) if mode is defined else '' }}"
+ "{{ (' link ' + link|string) if link is defined else '' }}",
+ "result": {
+ '{{ member }}': {
+ 'member': '{{ member }}',
+ 'mode': '{{ mode }}',
+ 'channel': 'Port-channel{{ channel }}',
+ 'link': '{{ link }}',
+ },
+ },
+ },
+ ]
+ # fmt: on
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/logging_global.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/logging_global.py
new file mode 100644
index 000000000..f6e43da4e
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/logging_global.py
@@ -0,0 +1,782 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 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 Logging_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,
+)
+
+
+def tmplt_host(verb):
+ cmd = "logging host"
+ changed = True
+ if verb.get("transport"):
+ changed = False
+ if verb:
+ if verb.get("host"):
+ cmd += " {hostname}".format(hostname=verb["host"])
+ if verb.get("ipv6"):
+ cmd += " ipv6 {ipv6}".format(ipv6=verb["ipv6"])
+ if verb.get("vrf"):
+ cmd += " vrf {vrf}".format(vrf=verb["vrf"])
+ if verb.get("filtered"):
+ cmd += " {filtered}".format(filtered="filtered")
+ changed = True
+ if verb.get("xml"):
+ cmd += " {xml}".format(xml="xml")
+ changed = True
+ if verb.get("session_id"):
+ session_id = verb.get("session_id")
+ changed = True
+ if session_id.get("text"):
+ cmd += " session-id string {text}".format(text=session_id["text"])
+ elif session_id.get("tag"):
+ cmd += " session-id {tag}".format(tag=session_id["tag"])
+ if verb.get("stream"):
+ cmd += " stream {stream}".format(stream=verb["stream"])
+ changed = True
+ if verb.get("sequence_num_session"):
+ cmd += " {sequence_num_session}".format(sequence_num_session="sequence-num-session")
+ changed = True
+ if verb.get("discriminator"):
+ cmd += " discriminator {discriminator}".format(discriminator=verb["discriminator"])
+ changed = True
+ if not changed:
+ cmd = None
+ return cmd
+
+
+def tmplt_host_transport(verb):
+ cmd = "logging host"
+
+ if verb.get("host"):
+ cmd += " {hostname}".format(hostname=verb["host"])
+ if verb.get("ipv6"):
+ cmd += " ipv6 {ipv6}".format(ipv6=verb["ipv6"])
+ if verb.get("vrf"):
+ cmd += " vrf {vrf}".format(vrf=verb["vrf"])
+ if verb.get("transport"):
+ transport_type = verb.get("transport")
+ prot = None
+ if transport_type.get("udp"):
+ cmd += " transport {prot}".format(prot="udp")
+ prot = "udp"
+ elif transport_type.get("tcp"):
+ cmd += " transport {prot}".format(prot="tcp")
+ prot = "tcp"
+
+ if prot:
+ verb = transport_type.get(prot)
+
+ if verb.get("port"):
+ cmd += " port {port}".format(port=verb["port"])
+ if verb.get("audit"):
+ cmd += " {audit}".format(audit="audit")
+ if verb.get("xml"):
+ cmd += " {xml}".format(xml="xml")
+ if verb.get("filtered"):
+ cmd += " {filtered}".format(filtered="filtered")
+ if verb.get("discriminator"):
+ cmd += " discriminator {discriminator}".format(discriminator=verb["discriminator"])
+ if verb.get("stream"):
+ cmd += " stream {stream}".format(stream=verb["stream"])
+ if verb.get("session_id"):
+ session_id = verb.get("session_id")
+ if session_id.get("text"):
+ cmd += " session-id string {text}".format(text=session_id["text"])
+ elif session_id.get("tag"):
+ cmd += " session-id {tag}".format(tag=session_id["tag"])
+ if verb.get("sequence_num_session"):
+ cmd += " {sequence_num_session}".format(sequence_num_session="sequence-num-session")
+ return cmd
+
+
+def tmplt_host_del(verb):
+ cmd = "logging host"
+ if verb.get("host"):
+ cmd += " {hostname}".format(hostname=verb["host"])
+ if verb.get("ipv6"):
+ cmd += " ipv6 {ipv6}".format(ipv6=verb["ipv6"])
+ if verb.get("transport"):
+ cmd = None
+ return cmd
+
+
+def tmplt_host_transport_del(verb):
+ cmd = "logging host"
+ if verb.get("host"):
+ cmd += " {hostname}".format(hostname=verb["host"])
+ if verb.get("ipv6"):
+ cmd += " ipv6 {ipv6}".format(ipv6=verb["ipv6"])
+ return cmd
+
+
+def tmplt_buffered(config_data):
+ return tmplt_common(config_data.get("buffered"), "logging buffered")
+
+
+def tmplt_console(config_data):
+ return tmplt_common(config_data.get("console"), "logging console")
+
+
+def tmplt_monitor(config_data):
+ return tmplt_common(config_data.get("monitor"), "logging monitor")
+
+
+def tmplt_origin_id(config_data):
+ return tmplt_common(config_data.get("origin_id"), "logging origin-id")
+
+
+def tmplt_logging_on(config_data):
+ cmd = "logging on"
+ if config_data.get("logging_on") == "disable":
+ cmd = "no " + cmd
+ return cmd
+
+
+def tmplt_queue_limit(config_data):
+ return tmplt_common(config_data.get("queue_limit"), "logging queue-limit")
+
+
+def tmplt_rate_limit(config_data):
+ return tmplt_common(config_data.get("rate_limit"), "logging rate-limit")
+
+
+def tmplt_reload(config_data):
+ return tmplt_common(config_data.get("reload"), "logging reload")
+
+
+def tmplt_message_counter(verb):
+ cmd = "logging message-counter"
+
+ if verb.get("message_counter"):
+ cmd += " {message_counter}".format(message_counter=verb["message_counter"])
+ return cmd
+
+
+def tmplt_filter(verb):
+ cmd = "logging filter"
+
+ if verb.get("url"):
+ cmd += " {url}".format(url=verb["url"])
+ if verb.get("order"):
+ cmd += " {order}".format(order=verb["order"])
+ if verb.get("args"):
+ cmd += " args {args}".format(args=verb["args"])
+ return cmd
+
+
+def tmplt_source_interface(verb):
+ cmd = "logging source-interface"
+
+ if verb.get("interface"):
+ cmd += " {interface}".format(interface=verb["interface"])
+ if verb.get("vrf"):
+ cmd += " vrf {vrf}".format(vrf=verb["vrf"])
+ return cmd
+
+
+def tmplt_common(verb, cmd):
+ if verb:
+ if verb.get("all"):
+ cmd += " {all}".format(all="all")
+ if verb.get("console"):
+ cmd += " {console}".format(console="console")
+ if verb.get("message_limit"):
+ cmd += " message-limit {message_limit}".format(message_limit=verb["message_limit"])
+ if verb.get("discriminator"):
+ cmd += " discriminator {discriminator}".format(discriminator=verb.get("discriminator"))
+ if verb.get("filtered"):
+ cmd += " {filtered}".format(filtered="filtered")
+ if verb.get("xml"):
+ cmd += " {xml}".format(xml="xml")
+ if verb.get("size"):
+ cmd += " {size}".format(size=verb["size"])
+ if verb.get("severity"):
+ cmd += " {severity}".format(severity=verb["severity"])
+ if verb.get("except_severity"):
+ cmd += " except {exceptSev}".format(exceptSev=verb["except_severity"])
+ if verb.get("tag"):
+ cmd += " {tag}".format(tag=verb["tag"])
+ if verb.get("text"):
+ cmd += " string {tag}".format(tag=verb["text"])
+ if verb.get("esm"):
+ cmd += " esm {tag}".format(tag=verb["esm"])
+ if verb.get("trap"):
+ cmd += " trap {tag}".format(tag=verb["trap"])
+ return cmd
+
+
+def tmplt_persistent(config_data):
+ cmd = "logging persistent"
+ verb = config_data.get("persistent")
+
+ if verb.get("url"):
+ cmd += " url {url}".format(url=verb["url"])
+ if verb.get("size"):
+ cmd += " size {size}".format(size=verb["size"])
+ if verb.get("filesize"):
+ cmd += " filesize {filesize}".format(filesize=verb["filesize"])
+ if verb.get("batch"):
+ cmd += " batch {batch}".format(batch=verb["batch"])
+ if verb.get("threshold"):
+ cmd += " threshold {threshold}".format(threshold=verb["threshold"])
+ if verb.get("immediate"):
+ cmd += " {immediate}".format(immediate="immediate")
+ if verb.get("protected"):
+ cmd += " {protected}".format(protected="protected")
+ if verb.get("notify"):
+ cmd += " {notify}".format(notify="notify")
+ return cmd
+
+
+class Logging_globalTemplate(NetworkTemplate):
+ def __init__(self, lines=None, module=None):
+ super(Logging_globalTemplate, self).__init__(lines=lines, tmplt=self, module=module)
+
+ # fmt: off
+ PARSERS = [
+ {
+ "name": "hosts",
+ "getval": re.compile(
+ r"""
+ ^logging\shost
+ (\s(?P<hostname>\S+))?
+ (\sipv6\s(?P<ipv6>\S+))?
+ (\svrf\s(?P<vrf>\S+))?
+ (\s(?P<filtered>filtered))?
+ (\s(?P<xml>xml))?
+ (\sstream\s(?P<stream>\d+))?
+ (\ssession-id\s(?P<tag>hostname|ipv4|ipv6))?
+ (\ssession-id\sstring\s(?P<text>\S+))?
+ (\s(?P<sequence_num_session>sequence-num-session))?
+ (\sdiscriminator\s(?P<discriminator>.+$))?
+ $""", re.VERBOSE,
+ ),
+ "setval": tmplt_host,
+ "remval": tmplt_host_del,
+ "result": {
+ "hosts": [{
+ "host": "{{ hostname }}",
+ "ipv6": "{{ ipv6 }}",
+ "discriminator": "{{ discriminator }}",
+ "vrf": "{{ vrf }}",
+ "xml": "{{ True if xml is defined }}",
+ "filtered": "{{ True if filtered is defined }}",
+ "sequence_num_session": "{{ True if sequence_num_session is defined }}",
+ "stream": "{{ stream }}",
+ "session_id": {
+ "tag": "{{ tag }}",
+ "text": "{{ text }}",
+ },
+ }],
+ },
+ },
+ {
+ "name": "hosts.transport",
+ "getval": re.compile(
+ r"""
+ ^logging\shost
+ (\s(?P<hostname>\S+))?
+ (\sipv6\s(?P<ipv6>\S+))?
+ (\svrf\s(?P<vrf>\S+))?
+ (\stransport\s(?P<transport>tcp|udp))?
+ (\sport\s(?P<port>\d+))?
+ (\s(?P<audit>audit))?
+ (\s(?P<xml>xml))?
+ (\s(?P<filtered>filtered))?
+ (\sdiscriminator\s(?P<discriminator>.+$))?
+ (\sstream\s(?P<stream>\d+))?
+ (\ssession-id\s(?P<tag>hostname|ipv4|ipv6))?
+ (\ssession-id\sstring\s(?P<text>\S+))?
+ (\s(?P<sequence_num_session>sequence-num-session))?
+ $""", re.VERBOSE,
+ ),
+ "setval": tmplt_host_transport,
+ "remval": tmplt_host_transport_del,
+ "result": {
+ "hosts": [{
+ "host": "{{ hostname }}",
+ "ipv6": "{{ ipv6 }}",
+ "vrf": "{{ vrf if transport is defined }}",
+ "transport": {
+ "{{ transport }}": {
+ "audit": "{{ True if audit is defined }}",
+ "sequence_num_session": "{{ True if sequence_num_session is defined }}",
+ "xml": "{{ True if xml is defined }}",
+ "discriminator": "{{ discriminator }}",
+ "port": "{{ port }}",
+ "session_id": {
+ "tag": "{{ tag }}",
+ "text": "{{ text }}",
+ },
+ "filtered": "{{ True if filtered is defined }}",
+ "stream": "{{ stream }}",
+ },
+ },
+ }],
+ },
+ },
+ {
+ "name": "buffered",
+ "getval": re.compile(
+ r"""
+ ^logging\sbuffered
+ (\sdiscriminator\s(?P<discriminator>.+))?
+ (\s(?P<filtered>filtered))?
+ (\s(?P<xml>xml))?
+ (\s(?P<size>[1-9][0-9]*))?
+ (\s(?P<severity>alerts|critical|debugging|emergencies|errors|informational|notifications|warnings))?
+ $""", re.VERBOSE,
+ ),
+ "setval": tmplt_buffered,
+ "result": {
+ "buffered": {
+ "filtered": "{{ True if filtered is defined }}",
+ "xml": "{{ True if xml is defined }}",
+ "severity": "{{ severity }}",
+ "size": "{{ size }}",
+ "discriminator": "{{ discriminator }}",
+ },
+ },
+ },
+ {
+ "name": "buginf",
+ "getval": re.compile(
+ r"""
+ ^logging\s(?P<buginf>buginf)
+ $""", re.VERBOSE,
+ ),
+ "setval": "logging buginf",
+ "result": {
+ "buginf": "{{ True if buginf is defined }}",
+ },
+ },
+ {
+ "name": "cns_events",
+ "getval": re.compile(
+ r"""
+ ^logging\scns-events
+ (\s(?P<severity>alerts|critical|debugging|emergencies|errors|informational|notifications|warnings))?
+ $""", re.VERBOSE,
+ ),
+ "setval": "logging cns-events {{ cns_events }}",
+ "result": {
+ "cns_events": "{{ severity }}",
+ },
+ },
+ {
+ "name": "console",
+ "getval": re.compile(
+ r"""
+ ^logging\sconsole
+ (\s(?P<filtered>filtered))?
+ (\s(?P<xml>xml))?
+ (\s(?P<severity>alerts|critical|debugging|emergencies|errors|informational|notifications|warnings|guaranteed$))?
+ (\sdiscriminator\s(?P<discriminator>.+$))?
+ $""", re.VERBOSE,
+ ),
+ "setval": tmplt_console,
+ "result": {
+ "console": {
+ "severity": "{{ severity }}",
+ "discriminator": "{{ discriminator }}",
+ "filtered": "{{ True if filtered is defined }}",
+ "xml": "{{ True if xml is defined }}",
+ },
+ },
+ },
+ {
+ "name": "count",
+ "getval": re.compile(
+ r"""
+ ^logging\s(?P<count>count)
+ $""", re.VERBOSE,
+ ),
+ "setval": "logging count",
+ "result": {
+ "count": "{{ True if count is defined }}",
+ },
+ },
+ {
+ "name": "delimiter",
+ "getval": re.compile(
+ r"""
+ ^logging\sdelimiter\s(?P<tcp>tcp)
+ $""", re.VERBOSE,
+ ),
+ "setval": "logging delimiter tcp",
+ "result": {
+ "delimiter": {
+ "tcp": "{{ True if tcp is defined }}",
+ },
+ },
+ },
+ {
+ "name": "discriminator",
+ "getval": re.compile(
+ r"""
+ ^logging\sdiscriminator\s(?P<discriminator>.+$)
+ $""", re.VERBOSE,
+ ),
+ "setval": "logging discriminator {{ discriminator }}",
+ "result": {
+ "discriminator": ["{{ discriminator }}"],
+ },
+ },
+ {
+ "name": "dmvpn",
+ "getval": re.compile(
+ r"""
+ ^logging\sdmvpn\srate-limit
+ (\s(?P<rate>\d+))?
+ $""", re.VERBOSE,
+ ),
+ "setval": "logging dmvpn rate-limit {{ dmvpn.rate_limit }}",
+ "result": {
+ "dmvpn": {
+ "rate_limit": "{{ rate }}",
+ },
+ },
+ },
+ {
+ "name": "esm",
+ "getval": re.compile(
+ r"""
+ ^logging\sesm\s(?P<config>config)
+ $""", re.VERBOSE,
+ ),
+ "setval": "logging esm config",
+ "result": {
+ "esm": {
+ "config": "{{ True if config is defined }}",
+ },
+ },
+ },
+ {
+ "name": "exception",
+ "getval": re.compile(
+ r"""
+ ^logging\sexception
+ \s(?P<exception>[1-9][0-9]*)
+ $""", re.VERBOSE,
+ ),
+ "setval": "logging exception {{ exception }}",
+ "result": {
+ "exception": "{{ exception }}",
+ },
+ },
+ {
+ "name": "facility",
+ "getval": re.compile(
+ r"""
+ ^logging\sfacility
+ \s(?P<facility>auth|cron|daemon|kern|local0|local1|local2|local3|local4|local5|local6|local7|lpr|mail|news|sys10|sys11|sys12|sys13|sys14|sys9|syslog|user|uucp)
+ $""", re.VERBOSE,
+ ),
+ "setval": "logging facility {{ facility }}",
+ "result": {
+ "facility": "{{ facility }}",
+ },
+ },
+ {
+ "name": "filter",
+ "getval": re.compile(
+ r"""
+ ^logging\sfilter
+ (\s(?P<url>\S+))?
+ (\s(?P<order>\d+))?
+ (\sargs\s(?P<args>.+$))?
+ $""", re.VERBOSE,
+ ),
+ "setval": tmplt_filter,
+ "result": {
+ "filter": [{
+ "url": "{{ url }}",
+ "order": "{{ order }}",
+ "args": "{{ args }}",
+ }],
+ },
+ },
+ {
+ "name": "history.size",
+ "getval": re.compile(
+ r"""
+ ^logging\shistory\ssize
+ (\s(?P<size>\d+))
+ $""", re.VERBOSE,
+ ),
+ "setval": "logging history size {{ history.size }}",
+ "result": {
+ "history": {
+ "size": "{{ size }}",
+ },
+ },
+ },
+ {
+ "name": "history.severity",
+ "getval": re.compile(
+ r"""
+ ^logging\shistory
+ (\s(?P<severity>alerts|critical|debugging|emergencies|errors|informational|notifications|warnings))
+ $""", re.VERBOSE,
+ ),
+ "setval": "logging history {{ history.severity }}",
+ "result": {
+ "history": {
+ "severity": "{{ severity }}",
+ },
+ },
+ },
+ {
+ "name": "message_counter",
+ "getval": re.compile(
+ r"""
+ ^logging\smessage-counter
+ \s(?P<counter>log|debug|syslog)
+ $""", re.VERBOSE,
+ ),
+ "setval": tmplt_message_counter,
+ "result": {
+ "message_counter": ["{{ counter }}"],
+ },
+ },
+ {
+ "name": "monitor",
+ "getval": re.compile(
+ r"""
+ ^logging\smonitor
+ (\s(?P<filtered>filtered))?
+ (\s(?P<xml>xml))?
+ (\s(?P<severity>alerts|critical|debugging|emergencies|errors|informational|notifications|warnings))?
+ (\sdiscriminator\s(?P<discriminator>.+$))?
+ $""", re.VERBOSE,
+ ),
+ "setval": tmplt_monitor,
+ "result": {
+ "monitor": {
+ "filtered": "{{ True if filtered is defined }}",
+ "xml": "{{ True if xml is defined }}",
+ "severity": "{{ severity }}",
+ "discriminator": "{{ discriminator }}",
+ },
+ },
+ },
+ {
+ "name": "logging_on",
+ "getval": re.compile(
+ r"""
+ ((?P<negate>no))?
+ ((\s|^))?logging
+ (\s(?P<on>on))?
+ $""", re.VERBOSE,
+ ),
+ "setval": tmplt_logging_on,
+ "remval": "logging on",
+ "result": {
+ "logging_on": "{{ 'disable' if negate is defined else 'enable' }}",
+ },
+ },
+ {
+ "name": "origin_id",
+ "getval": re.compile(
+ r"""
+ ^logging\sorigin-id
+ (\s(?P<tag>hostname|ip|ipv6))?
+ (\sstring\s(?P<text>.+$))?
+ $""", re.VERBOSE,
+ ),
+ "setval": tmplt_origin_id,
+ "result": {
+ "origin_id": {
+ "tag": "{{ tag }}",
+ "text": "{{ text }}",
+ },
+ },
+ },
+ {
+ "name": "persistent",
+ "getval": re.compile(
+ r"""
+ ^logging\spersistent
+ (\surl\s(?P<url>\S+))?
+ (\ssize\s(?P<size>[1-9][0-9]*))?
+ (\sfilesize\s(?P<filesize>[1-9][0-9]*))?
+ (\sbatch\s(?P<batch>[1-9][0-9]*))?
+ (\sthreshold\s(?P<threshold>[1-9][0-9]*))?
+ (\s(?P<immediate>immediate))?
+ (\s(?P<protected>protected))?
+ (\s(?P<notify>notify))?
+ $""", re.VERBOSE,
+ ),
+ "setval": tmplt_persistent,
+ "result": {
+ "persistent": {
+ "batch": "{{ batch }}",
+ "filesize": "{{ filesize }}",
+ "immediate": "{{ True if immediate is defined }}",
+ "notify": "{{ True if notify is defined }}",
+ "protected": "{{ True if protected is defined }}",
+ "size": "{{ size }}",
+ "threshold": "{{ threshold }}",
+ "url": "{{ url }}",
+ },
+ },
+ },
+ {
+ "name": "policy_firewall",
+ "getval": re.compile(
+ r"""
+ ^logging\spolicy-firewall
+ (\srate-limit\s(?P<rate>[1-9][0-9]*))?
+ $""", re.VERBOSE,
+ ),
+ "setval": "logging policy-firewall rate-limit {{ policy_firewall.rate_limit }}",
+ "result": {
+ "policy_firewall": {
+ "rate_limit": "{{ rate }}",
+ },
+ },
+ },
+ {
+ "name": "queue_limit",
+ "getval": re.compile(
+ r"""
+ ^logging\squeue-limit
+ (\s(?P<size>[1-9][0-9]*))?
+ (\sesm\s(?P<esm>[1-9][0-9]*))?
+ (\strap\s(?P<trap>[1-9][0-9]*))?
+ $""", re.VERBOSE,
+ ),
+ "setval": tmplt_queue_limit,
+ "result": {
+ "queue_limit": {
+ "size": "{{ size }}",
+ "esm": "{{ esm }}",
+ "trap": "{{ trap }}",
+ },
+ },
+ },
+ {
+ "name": "rate_limit",
+ "getval": re.compile(
+ r"""
+ ^logging\srate-limit
+ (\s(?P<option>all|console))?
+ (\s(?P<size>[1-9][0-9]*))?
+ (\sexcept\s(?P<except_severity>alerts|critical|debugging|emergencies|errors|informational|notifications|warnings))?
+ $""", re.VERBOSE,
+ ),
+ "setval": tmplt_rate_limit,
+ "result": {
+ "rate_limit": {
+ "size": "{{ size }}",
+ "all": "{{ True if option == 'all' }}",
+ "console": "{{ True if option == 'console' }}",
+ "except_severity": "{{ except_severity }}",
+ },
+ },
+ },
+ {
+ "name": "reload",
+ "getval": re.compile(
+ r"""
+ ^logging
+ (\s(?P<reload>reload))?
+ (\smessage-limit\s(?P<message_limit>[1-9][0-9]*))?
+ (\s(?P<severity>alerts|critical|debugging|emergencies|errors|informational|notifications|warnings))?
+ $""", re.VERBOSE,
+ ),
+ "setval": tmplt_reload,
+ "result": {
+ "reload": {
+ "severity": "{{ severity }}",
+ "message_limit": "{{ message_limit }}",
+ },
+ },
+ },
+ {
+ "name": "server_arp",
+ "getval": re.compile(
+ r"""
+ ^logging
+ \s(?P<server_arp>server-arp)
+ $""", re.VERBOSE,
+ ),
+ "setval": "logging server-arp",
+ "result": {
+ "server_arp": "{{ True if server_arp is defined }}",
+ },
+ },
+ {
+ "name": "snmp_trap",
+ "getval": re.compile(
+ r"""
+ ^logging\ssnmp-trap
+ (\s(?P<severity>alerts|critical|debugging|emergencies|errors|informational|notifications|warnings))?
+ $""", re.VERBOSE,
+ ),
+ "setval": "logging snmp-trap {{ snmp_trap }}",
+ "result": {
+ "snmp_trap": ["{{ severity }}"],
+ },
+ },
+ {
+ "name": "source_interface",
+ "getval": re.compile(
+ r"""
+ ^logging\ssource-interface
+ (\s(?P<interface>\S+))?
+ (\svrf\s(?P<vrf>\S+))?
+ $""", re.VERBOSE,
+ ),
+ "setval": tmplt_source_interface,
+ "result": {
+ "source_interface": [{
+ "interface": "{{ interface }}",
+ "vrf": "{{ vrf }}",
+ }],
+ },
+ },
+ {
+ "name": "trap",
+ "getval": re.compile(
+ r"""
+ ^logging\strap
+ \s(?P<severity>alerts|critical|debugging|emergencies|errors|informational|notifications|warnings)
+ $""", re.VERBOSE,
+ ),
+ "setval": "logging trap {{ trap }}",
+ "result": {
+ "trap": "{{ severity }}",
+ },
+ },
+ {
+ "name": "userinfo",
+ "getval": re.compile(
+ r"""
+ ^logging\s(?P<userinfo>userinfo)
+ $""", re.VERBOSE,
+ ),
+ "setval": "logging userinfo",
+ "result": {
+ "userinfo": "{{ True if userinfo is defined }}",
+ },
+ },
+ ]
+ # fmt: on
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ntp_global.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ntp_global.py
new file mode 100644
index 000000000..7a1a68658
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ntp_global.py
@@ -0,0 +1,509 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 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 Ntp_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 Ntp_globalTemplate(NetworkTemplate):
+ def __init__(self, lines=None, module=None):
+ super(Ntp_globalTemplate, self).__init__(lines=lines, tmplt=self, module=module)
+
+ # fmt: off
+ PARSERS = [
+ {
+ "name": "peer",
+ "getval": re.compile(
+ r"""
+ ^ntp\saccess-group
+ (\s(?P<ipv4>ipv4))?
+ (\s(?P<ipv6>ipv6))?
+ \speer
+ \s(?P<access_list>\S+)
+ (\s(?P<kod>kod))?
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp access-group"
+ "{{ ' ipv4' if ipv4 is defined else '' }}"
+ "{{ ' ipv6' if ipv6 is defined else '' }}"
+ " peer "
+ "{{ access_list }}"
+ "{{ ' kod' if kod|d(False) else '' }}",
+ "result": {
+ "access_group": {
+ "peer": [
+ {
+ "access_list": "{{ access_list }}",
+ "kod": "{{ not not kod }}",
+ "ipv4": "{{ not not ipv4 }}",
+ "ipv6": "{{ not not ipv6 }}",
+ },
+ ],
+ },
+ },
+ },
+ {
+ "name": "query_only",
+ "getval": re.compile(
+ r"""
+ ^ntp\saccess-group
+ (\s(?P<ipv4>ipv4))?
+ (\s(?P<ipv6>ipv6))?
+ \squery-only
+ \s(?P<access_list>\S+)
+ (\s(?P<kod>kod))?
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp access-group"
+ "{{ ' ipv4' if ipv4 is defined else '' }}"
+ "{{ ' ipv6' if ipv6 is defined else '' }}"
+ " query-only "
+ "{{ access_list }}"
+ "{{ ' kod' if kod|d(False) else '' }}",
+ "result": {
+ "access_group": {
+ "query_only": [
+ {
+ "access_list": "{{ access_list }}",
+ "kod": "{{ not not kod }}",
+ "ipv4": "{{ not not ipv4 }}",
+ "ipv6": "{{ not not ipv6 }}",
+ },
+ ],
+ },
+ },
+ },
+ {
+ "name": "serve",
+ "getval": re.compile(
+ r"""
+ ^ntp\saccess-group
+ (\s(?P<ipv4>ipv4))?
+ (\s(?P<ipv6>ipv6))?
+ \sserve
+ \s(?P<access_list>\S+)
+ (\s(?P<kod>kod))?
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp access-group"
+ "{{ ' ipv4' if ipv4 is defined else '' }}"
+ "{{ ' ipv6' if ipv6 is defined else '' }}"
+ " serve "
+ "{{ access_list }}"
+ "{{ ' kod' if kod|d(False) else '' }}",
+ "result": {
+ "access_group": {
+ "serve": [
+ {
+ "access_list": "{{ access_list }}",
+ "kod": "{{ not not kod }}",
+ "ipv4": "{{ not not ipv4 }}",
+ "ipv6": "{{ not not ipv6 }}",
+ },
+ ],
+ },
+ },
+ },
+ {
+ "name": "serve_only",
+ "getval": re.compile(
+ r"""
+ ^ntp\saccess-group
+ (\s(?P<ipv4>ipv4))?
+ (\s(?P<ipv6>ipv6))?
+ \sserve-only
+ \s(?P<access_list>\S+)
+ (\s(?P<kod>kod))?
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp access-group"
+ "{{ ' ipv4' if ipv4 is defined else '' }}"
+ "{{ ' ipv6' if ipv6 is defined else '' }}"
+ " serve-only "
+ "{{ access_list }}"
+ "{{ ' kod' if kod|d(False) else '' }}",
+ "result": {
+ "access_group": {
+ "serve_only": [
+ {
+ "access_list": "{{ access_list }}",
+ "kod": "{{ not not kod }}",
+ "ipv4": "{{ not not ipv4 }}",
+ "ipv6": "{{ not not ipv6 }}",
+ },
+ ],
+ },
+ },
+ },
+ {
+ "name": "allow.control.rate_limit",
+ "getval": re.compile(
+ r"""
+ ^ntp\sallow\smode\scontrol\s(?P<rate_limit>\d+)
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp allow mode control {{ allow.control.rate_limit }}",
+ "result": {
+ "allow": {
+ "control": {
+ "rate_limit": "{{ rate_limit }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "allow.private",
+ "getval": re.compile(
+ r"""
+ ^ntp\sallow\smode\s(?P<private>private)
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp allow mode private",
+ "result": {
+ "allow": {
+ "private": "{{ not not private }}",
+ },
+ },
+ },
+ {
+ "name": "authenticate",
+ "getval": re.compile(
+ r"""
+ ^ntp\s(?P<authenticate>authenticate)
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp authenticate",
+ "result": {
+ "authenticate": "{{ not not authenticate }}",
+ },
+ },
+ {
+ "name": "authentication_keys",
+ "getval": re.compile(
+ r"""
+ ^ntp\sauthentication-key\s(?P<id>\d+)
+ \s(?P<algorithm>\S+)
+ \s(?P<key>\S+)
+ \s(?P<encryption>\d+)
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp authentication-key {{ id }} {{ algorithm }} {{ key }} {{ encryption }}",
+ "result": {
+ "authentication_keys": [
+ {
+ "id": "{{ id }}",
+ "algorithm": "{{ algorithm }}",
+ "key": "{{ key }}",
+ "encryption": "{{ encryption }}",
+ },
+ ],
+ },
+ },
+ {
+ "name": "broadcast_delay",
+ "getval": re.compile(
+ r"""
+ ^ntp\sbroadcastdelay\s(?P<broadcast_delay>\d+)
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp broadcastdelay {{ broadcast_delay }}",
+ "result": {
+ "broadcast_delay": "{{ broadcast_delay }}",
+ },
+ },
+ {
+ "name": "clock_period",
+ "getval": re.compile(
+ r"""
+ ^ntp\sclock-period\s(?P<clock_period>\d+)
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp clock-period {{ clock_period }}",
+ "result": {
+ "clock_period": "{{ clock_period }}",
+ },
+ },
+ {
+ "name": "logging",
+ "getval": re.compile(
+ r"""
+ ^ntp\s(?P<logging>logging)
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp logging",
+ "result": {
+ "logging": "{{ not not logging }}",
+ },
+ },
+ {
+ "name": "master.enabled",
+ "getval": re.compile(
+ r"""
+ ^ntp\s(?P<master>master)
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp master",
+ "result": {
+ "master": {
+ "enabled": "{{ not not master }}",
+ },
+ },
+ },
+ {
+ "name": "master.stratum",
+ "getval": re.compile(
+ r"""
+ ^ntp\smaster\s(?P<stratum>\d+)
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp master {{ master.stratum }}",
+ "result": {
+ "master": {
+ "stratum": "{{ stratum }}",
+ },
+ },
+ },
+ {
+ "name": "max_associations",
+ "getval": re.compile(
+ r"""
+ ^ntp\smax-associations\s(?P<max_associations>\d+)
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp max-associations {{ max_associations }}",
+ "result": {
+ "max_associations": "{{ max_associations }}",
+ },
+ },
+ {
+ "name": "max_distance",
+ "getval": re.compile(
+ r"""
+ ^ntp\smaxdistance\s(?P<max_distance>\d+)
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp maxdistance {{ max_distance }}",
+ "result": {
+ "max_distance": "{{ max_distance }}",
+ },
+ },
+ {
+ "name": "min_distance",
+ "getval": re.compile(
+ r"""
+ ^ntp\smindistance\s(?P<min_distance>\d+)
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp mindistance {{ min_distance }}",
+ "result": {
+ "min_distance": "{{ min_distance }}",
+ },
+ },
+ {
+ "name": "orphan",
+ "getval": re.compile(
+ r"""
+ ^ntp\sorphan\s(?P<orphan>\d+)
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp orphan {{ orphan }}",
+ "result": {
+ "orphan": "{{ orphan }}",
+ },
+ },
+ {
+ "name": "panic_update",
+ "getval": re.compile(
+ r"""
+ ^ntp\spanic\s(?P<update>update)
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp panic update",
+ "result": {
+ "panic_update": "{{ not not update }}",
+ },
+ },
+ {
+ "name": "passive",
+ "getval": re.compile(
+ r"""
+ ^ntp\s(?P<passive>passive)
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp passive",
+ "result": {
+ "passive": "{{ not not passive }}",
+ },
+ },
+ {
+ "name": "peers",
+ "getval": re.compile(
+ r"""
+ ^ntp\speer
+ (\svrf\s(?P<vrf>\S+))?
+ (\s(?P<ipv4>ip))?
+ (\s(?P<ipv6>ipv6))?
+ \s(?P<peer>\S+)
+ (\s(?P<burst>burst))?
+ (\s(?P<iburst>iburst))?
+ (\skey\s(?P<key>\d+))?
+ (\sminpoll\s(?P<minpoll>\d+))?
+ (\smaxpoll\s(?P<maxpoll>\d+))?
+ (\s(?P<normal_sync>normal-sync))?
+ (\s(?P<prefer>prefer))?
+ (\ssource\s(?P<source>\S+))?
+ (\sversion\s(?P<version>\d+))?
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp peer"
+ "{{ (' vrf ' + vrf) if vrf is defined else '' }}"
+ "{{ ' ip' if use_ipv4|d(False) else ''}}"
+ "{{ ' ipv6' if use_ipv6|d(False) else ''}}"
+ "{{ ( ' ' + peer ) if peer is defined else '' }}"
+ "{{ ' burst ' if burst|d(False) else ''}}"
+ "{{ ' iburst ' if iburst|d(False) else ''}}"
+ "{{ (' key ' + key_id|string) if key_id is defined else '' }}"
+ "{{ (' minpoll ' + minpoll|string) if minpoll is defined else '' }}"
+ "{{ (' maxpoll ' + maxpoll|string) if maxpoll is defined else '' }}"
+ "{{ ' normal-sync ' if normal_sync is defined else ''}}"
+ "{{ ' prefer' if prefer|d(False) else ''}}"
+ "{{ (' source ' + source) if source is defined else '' }}"
+ "{{ (' version ' + version|string) if version is defined else '' }}",
+ "result": {
+ "peers": [
+ {
+ "peer": "{{ peer }}",
+ "use_ipv4": "{{ not not ipv4 }}",
+ "use_ipv6": "{{ not not ipv6 }}",
+ "vrf": "{{ vrf }}",
+ "burst": "{{ not not burst }}",
+ "iburst": "{{ not not iburst }}",
+ "key_id": "{{ key }}",
+ "minpoll": "{{ minpoll }}",
+ "maxpoll": "{{ maxpoll }}",
+ "normal_sync": "{{ not not normal_sync }}",
+ "prefer": "{{ not not prefer }}",
+ "source": "{{ source }}",
+ "version": "{{ version }}",
+ },
+ ],
+ },
+ },
+ {
+ "name": "servers",
+ "getval": re.compile(
+ r"""
+ ^ntp\sserver
+ (\svrf\s(?P<vrf>\S+))?
+ (\s(?P<ipv4>ip))?
+ (\s(?P<ipv6>ipv6))?
+ \s(?P<server>\S+)
+ (\s(?P<burst>burst))?
+ (\s(?P<iburst>iburst))?
+ (\skey\s(?P<key>\d+))?
+ (\sminpoll\s(?P<minpoll>\d+))?
+ (\smaxpoll\s(?P<maxpoll>\d+))?
+ (\s(?P<normal_sync>normal-sync))?
+ (\s(?P<prefer>prefer))?
+ (\ssource\s(?P<source>\S+))?
+ (\sversion\s(?P<version>\d+))?
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp server"
+ "{{ (' vrf ' + vrf) if vrf is defined else '' }}"
+ "{{ ' ip' if use_ipv4|d(False) else ''}}"
+ "{{ ' ipv6' if use_ipv6|d(False) else ''}}"
+ "{{ ( ' ' + server ) if server is defined else '' }}"
+ "{{ ' burst ' if burst|d(False) else ''}}"
+ "{{ ' iburst ' if iburst|d(False) else ''}}"
+ "{{ (' key ' + key_id|string) if key_id is defined else '' }}"
+ "{{ (' minpoll ' + minpoll|string) if minpoll is defined else '' }}"
+ "{{ (' maxpoll ' + maxpoll|string) if maxpoll is defined else '' }}"
+ "{{ ' normal-sync ' if normal_sync is defined else ''}}"
+ "{{ ' prefer' if prefer|d(False) else ''}}"
+ "{{ (' source ' + source) if source is defined else '' }}"
+ "{{ (' version ' + version|string) if version is defined else '' }}",
+ "result": {
+ "servers": [
+ {
+ "server": "{{ server }}",
+ "use_ipv4": "{{ not not ipv4 }}",
+ "use_ipv6": "{{ not not ipv6 }}",
+ "vrf": "{{ vrf }}",
+ "burst": "{{ not not burst }}",
+ "iburst": "{{ not not iburst }}",
+ "key_id": "{{ key }}",
+ "minpoll": "{{ minpoll }}",
+ "maxpoll": "{{ maxpoll }}",
+ "normal_sync": "{{ not not normal_sync }}",
+ "prefer": "{{ not not prefer }}",
+ "source": "{{ source }}",
+ "version": "{{ version }}",
+ },
+ ],
+ },
+ },
+ {
+ "name": "source",
+ "getval": re.compile(
+ r"""
+ ^ntp\ssource\s(?P<source>\S+)
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp source {{ source }}",
+ "result": {
+ "source": "{{ source }}",
+ },
+ },
+ {
+ "name": "trusted_keys",
+ "getval": re.compile(
+ r"""
+ ^ntp\strusted-key
+ \s((?P<range_start>\d+))
+ (\s\-\s)?
+ ((?P<range_end>\d+))?
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp trusted-key {{ range_start }}"
+ "{{ (' - ' + range_end|string) if range_end is defined else '' }}",
+ "result": {
+ "trusted_keys": [
+ {
+ "range_start": "{{ range_start }}",
+ "range_end": "{{ range_end }}",
+ },
+ ],
+ },
+ },
+ {
+ "name": "update_calendar",
+ "getval": re.compile(
+ r"""
+ ^ntp\s(?P<update_calendar>update-calendar)
+ $""", re.VERBOSE,
+ ),
+ "setval": "ntp update-calendar",
+ "result": {
+ "update_calendar": "{{ not not update_calendar }}",
+ },
+ },
+ ]
+ # fmt: on
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospf_interfaces.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospf_interfaces.py
new file mode 100644
index 000000000..2894240b9
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospf_interfaces.py
@@ -0,0 +1,643 @@
+# -*- coding: utf-8 -*-
+# Copyright 2020 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 Ospf_interfaces 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 Ospf_interfacesTemplate(NetworkTemplate):
+ def __init__(self, lines=None, module=None):
+ super(Ospf_interfacesTemplate, self).__init__(lines=lines, tmplt=self, module=module)
+
+ PARSERS = [
+ {
+ "name": "name",
+ "getval": re.compile(
+ r"""
+ ^interface\s(?P<name>\S+)$""",
+ re.VERBOSE,
+ ),
+ "setval": "interface {{ name }}",
+ "result": {"{{ name }}": {"name": "{{ name }}", "address_family": {}}},
+ "shared": True,
+ },
+ {
+ "name": "process",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)\sospf
+ (\s(?P<id>\d+))
+ (\sarea\s(?P<area>\d+))?
+ (\sarea\s(?P<area_ip>\s+))?
+ (\s(?P<secondaries>secondaries))?
+ (\sinstance\s(?P<instance>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} {{ process.id|string }}"
+ "{{ (' area ' + process.area_id|string ) if process.area_id is defined else '' }}"
+ "{{ (' ' + secondaries) if process.secondaries is defined else '' }}"
+ "{{ (' instance ' + process.instance) if process.instance is defined else '' }}",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "process": {
+ "id": "{{ id }}",
+ "area_id": "{{ area }}",
+ "secondaries": "{{ not not secondaries }}",
+ "instance_id": "{{ instance }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "adjacency",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)\sospf
+ \s(?P<adjacency>adjacency\sstagger\sdisable)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} adjacency stagger disable",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "adjacency": "{{ not not adjacency }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "authentication",
+ "getval": re.compile(
+ r"""
+ \s+ip\sospf\sauthentication
+ (\skey-chain\s(?P<key_chain>\S+))?
+ (\s(?P<message_digest>message-digest))?
+ (\s(?P<isnull>null))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "ip ospf authentication"
+ "{{ (' key-chain ' + authentication.key_chain) if authentication.key_chain is defined else '' }}"
+ "{{ (' ' + message-digest) if authentication.message_digest is defined else '' }}"
+ "{{ (' ' + null) if authentication.null is defined else '' }}",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "ip": {
+ "afi": "ipv4",
+ "authentication": {
+ "key_chain": "{{ key_chain }}",
+ "message_digest": "{{ not not message_digest }}",
+ "null": "{{ not not isnull }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "bfd",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)\sospf\sbfd
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} bfd",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "bfd": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "cost",
+ "getval": re.compile(
+ r"""
+ \s+ip\sospf
+ (\scost\s(?P<cost>\d+))
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} cost"
+ " {{ cost.interface_cost|string }}",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "ip": {
+ "afi": "ipv4",
+ "cost": {"interface_cost": "{{ cost }}"},
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "cost_ipv6_dynamic_cost",
+ "getval": re.compile(
+ r"""
+ \s+ipv6\sospf\scost\s(?P<interface_cost>\d+)
+ (\sdynamic)?
+ (\sdefault\s(?P<default>\d+))?
+ (\shysteresis)?
+ (\spercent\s(?P<h_params_p>\d+))?
+ (\sthreshold\s(?P<h_params_t>\d+))?
+ (\sweight)?
+ (\sL2-factor\s(?P<l2_factor>\d+))?
+ (\slatency\s(?P<latency>\d+))?
+ (\sresources\s(?P<resources>\d+))?
+ (\sthroughput\s(?P<throughput>\d+))?
+ (\s(?P<weight_oc>oc))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} cost"
+ " {{ cost.interface_cost|string }}",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "ipv6": {
+ "afi": "ipv6",
+ "cost": {
+ "interface_cost": "{{ interface_cost }}",
+ "dynamic_cost": {
+ "default": "{{ default }}",
+ "hysteresis": {
+ "percent": "{{ h_params_p }}",
+ "threshold": "{{ h_params_t }}",
+ },
+ "weight": {
+ "l2_factor": "{{ l2_factor }}",
+ "latency": "{{ latency }}",
+ "oc": "{{ not not weight_oc }}",
+ "resources": "{{ resources }}",
+ "throughput": "{{ throughput }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "database_filter",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)\sospf\sdatabase-filter\sall\sout
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} database-filter all out",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "database_filter": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "dead_interval",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)\sospf\sdead-interval
+ (\s(?P<seconds>\d+))?
+ (\sminimal\shello-multiplier\s(?P<minimal>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} dead-interval {{ dead_interval.time|string }}"
+ "{{ (' minimal hello-multiplier ' + dead_interval.minimal|string) if dead_interval.minimal is defined else '' }}",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "dead_interval": {"time": "{{ seconds }}", "minimal": "{{ minimal }}"},
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "demand_circuit",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)\sospf\sdemand-circuit
+ (\s(?P<ignore>ignore))?
+ (\s(?P<disable>disable))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} demand-circuit"
+ "{{ ' ignore' if demand_circuit.ignore is defined else '' }}"
+ "{{ ' disable' if demand_circuit.disable is defined else '' }}",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "demand_circuit": {
+ "enable": True,
+ "ignore": "{{ not not ignore }}",
+ "disable": "{{ not not disable }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "flood_reduction",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)\sospf\sflood-reduction
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} flood-reduction",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "flood_reduction": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "hello_interval",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)\sospf(\shello-interval\s(?P<hello_interval>\d+))
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} hello-interval {{ hello_interval }}",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "hello_interval": "{{ hello_interval }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "lls",
+ "getval": re.compile(
+ r"""\s+ip\sospf\slls$""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} lls",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "ip": {
+ "afi": "ipv4",
+ "lls": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "manet",
+ "getval": re.compile(
+ r"""
+ \s+ipv6\sospf\smanet\speering
+ (\scost\spercent\s(?P<cost_p>\d+))?
+ (\scost\sthreshold\s(?P<cost_t>\d+))?
+ (\slink-metrics\s(?P<link_metrics>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "ipv6 ospf manet peering"
+ "{{ ' cost' if manet.cost is defined else '' }}"
+ "{{ (' percent ' + manet.cost.percent|string ) if manet.cost.percent is defined else '' }}"
+ "{{ (' threshold ' + manet.cost.threshold|string ) if manet.cost.threshold is defined else '' }}"
+ "{{ ' link-metrics' if manet.link_metrics is defined else '' }}"
+ "{{ (' ' + manet.link_metrics.cost_threshold) if manet.link_metrics is defined and manet.link_metrics.cost_threshold is defined else '' }}",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "ipv6": {
+ "afi": "ipv6",
+ "manet": {
+ "cost": {
+ "percent": "{{ cost_p }}",
+ "threshold": "{{ cost_t }}",
+ },
+ "link_metrics": {
+ "set": "{{ True if link_metrics is not defined and link_metrics is defined }}",
+ "cost_threshold": "{{ link_metrics }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "mtu_ignore",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)\sospf\smtu-ignore
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} mtu-ignore",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "mtu_ignore": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "multi_area",
+ "getval": re.compile(
+ r"""
+ \s+ip\sospf\smulti-area\s(?P<multi_area>\d+)
+ (\scost\s(?P<cost>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "ip ospf multi-area {{ multi_area.id|string }}"
+ "{{ (' cost ' + multi_area.cost|string ) if multi_area.cost is defined else '' }}",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "ip": {
+ "afi": "ipv4",
+ "multi_area": {
+ "id": "{{ multi_area }}",
+ "cost": "{{ cost }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "neighbor",
+ "getval": re.compile(
+ r"""
+ \s+ipv6\sospf\sneighbor\s(?P<address>\S+)
+ (\scost\s(?P<cost>\d+))?
+ (\s(?P<database_filter>database-filter\sall\sout))?
+ (\spoll-interval\s(?P<poll_interval>\d+))?
+ (\spriority\s(?P<priority>\d+))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "ipv6 ospf neighbor {{ neighbor.address }}"
+ "{{ (' cost ' + neighbor.cost|string ) if neighbor.cost is defined else '' }}"
+ "{{ ' database-filter all out' if neighbor.database_filter is defined else '' }}"
+ "{{ (' poll-interval ' + neighbor.poll_interval|string ) if neighbor.poll_interval is defined else '' }}"
+ "{{ (' priority ' + neighbor.priority|string ) if neighbor.priority is defined else '' }}",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "ipv6": {
+ "afi": "ipv6",
+ "neighbor": {
+ "address": "{{ address }}",
+ "cost": "{{ cost }}",
+ "database_filter": "{{ not not database_filter }}",
+ "poll_interval": "{{ poll_interval }}",
+ "priority": "{{ priority }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "network",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)\sospf\snetwork
+ (\s(?P<broadcast>broadcast))?
+ (\s(?P<manet>manet))?
+ (\s(?P<non_broadcast>non-broadcast))?
+ (\s(?P<point_to_multipoint>point-to-multipoint))?
+ (\s(?P<point_to_point>point-to-point))?
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} network"
+ "{{ ' broadcast' if network.broadcast is defined else '' }}"
+ "{{ ' manet' if network.manet is defined else '' }}"
+ "{{ ' non-broadcast' if network.non_broadcast is defined else '' }}"
+ "{{ ' point-to-multipoint' if network.point_to_multipoint is defined else '' }}"
+ "{{ ' point-to-point' if network.point_to_point is defined else '' }}",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "network": {
+ "broadcast": "{{ not not broadcast }}",
+ "manet": "{{ not not manet }}",
+ "non_broadcast": "{{ not not non_broadcast }}",
+ "point_to_multipoint": "{{ not not point_to_multipoint }}",
+ "point_to_point": "{{ not not point_to_point }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "prefix_suppression",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)\sospf\sprefix-suppression
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} prefix-suppression",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "prefix_suppression": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "priority",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)\sospf
+ (\spriority\s(?P<priority>\d+))
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} priority {{ priority }}",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "priority": "{{ priority }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "resync_timeout",
+ "getval": re.compile(
+ r"""
+ \s+ip\sospf
+ (\sresync-timeout\s(?P<resync_timeout>\d+))
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "ip ospf resync-timeout {{ resync_timeout|string }}",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "ip": {
+ "afi": "ipv4",
+ "resync_timeout": "{{ resync_timeout }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "retransmit_interval",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)\sospf
+ (\sretransmit-interval\s(?P<retransmit_interval>\d+))
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} retransmit-interval {{ retransmit_interval|string }}",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "retransmit_interval": "{{ retransmit_interval }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "shutdown",
+ "getval": re.compile(
+ r"""
+ \s+(?P<afi>ip|ipv6)\sospf\sshutdown
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "{{ 'ip ospf' if afi == 'ipv4' else 'ipv6 ospf' }} shutdown",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "{{ afi }}": {
+ "afi": "{{ 'ipv4' if afi == 'ip' else 'ipv6' }}",
+ "shutdown": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "transmit_delay",
+ "getval": re.compile(
+ r"""
+ \s+ipv6\sospf\stransmit-delay\s(?P<transmit_delay>\d+)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "ipv6 ospf transmit-delay {{ transmit_delay|string }}",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "ipv6": {
+ "afi": "ipv6",
+ "transmit_delay": "{{ transmit_delay }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "ttl_security",
+ "getval": re.compile(
+ r"""
+ \s+ip\sospf\sttl-security\shops\s(?P<hops>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "ip ospf ttl-security"
+ "{{ (' hops ' + ttl_security.hops|string) if ttl_security.hops is defined else '' }}",
+ "result": {
+ "{{ name }}": {
+ "address_family": {
+ "ip": {
+ "afi": "ipv4",
+ "ttl_security": {
+ "set": True,
+ "hops": "{{ hops }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ ]
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
new file mode 100644
index 000000000..5b746e507
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospfv2.py
@@ -0,0 +1,1830 @@
+from __future__ import absolute_import, division, print_function
+
+
+__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"]
+ if config_data["address_family"].get("topology"):
+ if "base" in config_data["address_family"].get("topology"):
+ command.insert(1, "topology base")
+ elif "name" in config_data["address_family"].get("topology"):
+ cmd = "topology {name}".format(**config_data["address_family"].get("topology"))
+ if "tid" in config_data["address_family"].get("topology"):
+ cmd += " tid {tid}".format(**config_data["address_family"].get("topology"))
+ command.insert(1, cmd)
+ 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:
+ command = "area {area_id} nssa".format(**config_data)
+ if "default_information_originate" in config_data["nssa"]:
+ 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"]:
+ command += " nssa-only"
+ if config_data["nssa"].get("no_ext_capability"):
+ command += " no-ext-capability"
+ if config_data["nssa"].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"]:
+ 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"
+ if "ip_address" in config_data["domain_id"]:
+ 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"])
+ 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"
+ if "router_lsa" in config_data["max_metric"]:
+ command += " router-lsa"
+ if "external_lsa" in config_data["max_metric"]:
+ command += " external-lsa {external_lsa}".format(**config_data["max_metric"])
+ if "include_stub" in config_data["max_metric"]:
+ command += " include-stub"
+ if "on_startup" in config_data["max_metric"]:
+ if "time" in config_data["max_metric"]["on_startup"]:
+ command += " on-startup {time}".format(**config_data["max_metric"]["on_startup"])
+ elif "wait_for_bgp" in config_data["max_metric"]["on_startup"]:
+ command += " on-startup wait-for-bgp"
+ if "summary_lsa" in config_data["max_metric"]:
+ command += " summary-lsa {summary_lsa}".format(**config_data["max_metric"])
+ 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"
+ if "area" in config_data["mpls"]["traffic_eng"]:
+ 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"]
+ )
+ elif "interface" in config_data["mpls"]["traffic_eng"]:
+ command += " interface {int_type}".format(
+ **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"]
+ )
+ if "area" in config_data["mpls"]["traffic_eng"]["mesh_group"]:
+ command += " area {area}".format(**config_data["mpls"]["traffic_eng"]["mesh_group"])
+ elif "multicast_intact" in config_data["mpls"]["traffic_eng"]:
+ 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"]
+ )
+ return command
+
+
+def _tmplt_ospf_neighbor(config_data):
+ if "neighbor" in config_data:
+ command = "neighbor"
+ if "address" in config_data["neighbor"]:
+ command += " {address}".format(**config_data["neighbor"])
+ if "cost" in config_data["neighbor"]:
+ command += " cost {cost}".format(**config_data["neighbor"])
+ if "database_filter" in config_data["neighbor"]:
+ command += " database-filter all out"
+ if "poll_interval" in config_data["neighbor"]:
+ command += " poll-interval {poll_interval}".format(**config_data["neighbor"])
+ if "priority" in config_data["neighbor"]:
+ command += " priority {priority}".format(**config_data["neighbor"])
+ 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"]:
+ cmd = "passive-interface {0}".format(each)
+ elif not config_data["passive_interfaces"].get("set_interface"):
+ for each in config_data["passive_interfaces"]["interface"]:
+ cmd = "no passive-interface {0}".format(each)
+ 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)
+
+ PARSERS = [
+ {
+ "name": "pid",
+ "getval": re.compile(
+ r"""
+ ^router\s
+ ospf*
+ \s(?P<pid>\S+)
+ \svrf
+ \s(?P<vrf>\S+)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_vrf_cmd,
+ "result": {
+ "processes": {"{{ pid }}": {"process_id": "{{ pid|int }}", "vrf": "{{ vrf }}"}},
+ },
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_adjacency_cmd,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "adjacency": {
+ "min_adjacency": "{{ min|int }}",
+ "max_adjacency": "{{ max|int }}",
+ "none": "{{ True if none_adj is defined else None }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "address_family",
+ "getval": re.compile(
+ r"""\s+topology
+ \s(?P<base>base)*
+ \s*(?P<name>\S+)*
+ \s*(?P<tid>tid\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_address_family_cmd,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "address_family": {
+ "topology": {
+ "base": "{{ True if base is defined }}",
+ "name": "{{ name }}",
+ "tid": "{{ tid.split(" ")[1] }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "area.authentication",
+ "getval": re.compile(
+ r"""\s+area
+ \s(?P<area_id>\S+)*
+ \s*(?P<auth>authentication)*
+ \s*(?P<md>message-digest)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_authentication,
+ "compval": "authentication",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "authentication": {
+ "enable": "{{ True if auth is defined and md is undefined }}",
+ "message_digest": "{{ not not md }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "area.capability",
+ "getval": re.compile(
+ r"""\s+area
+ \s(?P<area_id>\S+)*
+ \s*(?P<capability>capability)*
+ \s*(?P<df>default-exclusion)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "area {{ area_id }} capability default-exclusion",
+ "compval": "capability",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "capability": "{{ not not capability }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "area.default_cost",
+ "getval": re.compile(
+ r"""\s+area
+ \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 }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "default_cost": "{{ default_cost|int }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "area.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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_filter,
+ "compval": "filter_list",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "filter_list": [{"name": "{{ name }}", "direction": "{{ dir }}"}],
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "area.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)*$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_nssa_translate,
+ "compval": "nssa",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "nssa": {
+ "set": "{{ True if nssa is defined and 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 }}",
+ "nssa_only": "{{ True if nssa_only is defined }}",
+ },
+ "no_ext_capability": "{{ True if no_ext is defined }}",
+ "no_redistribution": "{{ True if no_redis is defined }}",
+ "no_summary": "{{ True if no_summary is defined }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "area.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)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_nssa,
+ "compval": "nssa.translate",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "nssa": {
+ "translate": "{{ translate_always if translate_always is defined else translate_supress if translate_supress is defined }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "area.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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_ranges,
+ "compval": "ranges",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "ranges": [
+ {
+ "address": "{{ address }}",
+ "netmask": "{{ netmask }}",
+ "advertise": "{{ True if advertise is defined }}",
+ "cost": "{{ cost.split(" ")[1]|int }}",
+ "not_advertise": "{{ True if not_advertise is defined }}",
+ },
+ ],
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "area.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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_sham_link,
+ "compval": "sham_link",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "sham_link": {
+ "source": "{{ source }}",
+ "destination": "{{ destination }}",
+ "cost": "{{ cost.split(" ")[1]|int }}",
+ "ttl_security": '{{ ttl_security.split("hops ")[1] }}',
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "area.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)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_stub_link,
+ "compval": "stub",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "stub": {
+ "set": "{{ True if stub is defined and no_ext is undefined and no_sum is undefined }}",
+ "no_ext_capability": "{{ True if no_ext is defined }}",
+ "no_summary": "{{ True if no_sum is defined }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "auto_cost",
+ "getval": re.compile(
+ r"""\s+(?P<auto_cost>auto-cost)*
+ \s*(?P<ref_band>reference-bandwidth\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_auto_cost,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "auto_cost": {
+ "set": "{{ True if auto_cost is defined and ref_band is undefined }}",
+ "reference_bandwidth": '{{ ref_band.split(" ")[1] }}',
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "bfd",
+ "getval": re.compile(
+ r"""\s+bfd*
+ \s*(?P<bfd>all-interfaces)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "bfd all-interfaces",
+ "result": {"processes": {"{{ pid }}": {"bfd": "{{ True if bfd is defined }}"}}},
+ },
+ {
+ "name": "capability",
+ "getval": re.compile(
+ r"""\s+capability*
+ \s*((?P<lls>lls)|(?P<opaque>opaque)|(?P<transit>transit)|(?P<vrf_lite>vrf-lite))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_capability,
+ "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 }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "compatible",
+ "getval": re.compile(
+ r"""\s+compatible*
+ \s*((?P<rfc1583>rfc1583)|(?P<rfc1587>rfc1587)|(?P<rfc5243>rfc5243))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_compatible,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "compatible": {
+ "rfc1583": "{{ True if rfc1583 is defined }}",
+ "rfc1587": "{{ True if rfc1587 is defined }}",
+ "rfc5243": "{{ True if rfc5243 is defined }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_default_information,
+ "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] }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "default_metric",
+ "getval": re.compile(
+ r"""\s+default-metric(?P<default_metric>\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "default-metric {{ default_metric }}",
+ "result": {"processes": {"{{ pid }}": {"default_metric": "{{ default_metric| int}}"}}},
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_discard_route,
+ "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 }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distance_admin_distance,
+ "compval": "admin_distance",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "distance": {
+ "admin_distance": {
+ "distance": "{{ admin_dist }}",
+ "address": "{{ source }}",
+ "wildcard_bits": "{{ wildcard }}",
+ "acl": "{{ acl }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distance_ospf,
+ "compval": "ospf",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "distance": {
+ "ospf": {
+ "inter_area": "{{ inter.split(" ")[1]|int }}",
+ "intra_area": "{{ intra.split(" ")[1]|int }}",
+ "external": "{{ external.split(" ")[1]|int }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distribute_list_acls,
+ "compval": "distribute_list.acls",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "distribute_list": {
+ "acls": [
+ {
+ "name": "{{ name }}",
+ "direction": "{{ dir }}",
+ "interface": '{{ int_pro if dir == "in" }}',
+ "protocol": '{{ int_pro if dir == "out" }}',
+ },
+ ],
+ },
+ },
+ },
+ },
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distribute_list_prefix,
+ "compval": "distribute_list.prefix",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "distribute_list": {
+ "prefix": {
+ "name": "{{ prefix.split(" ")[1] }}",
+ "gateway_name": "{{ gateway.split(" ")[1] if prefix is defined }}",
+ "direction": "{{ dir if gateway is undefined }}",
+ "interface": '{{ int_pro if dir == "in" }}',
+ "protocol": '{{ int_pro if dir == "out" }}',
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "distribute_list.route_map",
+ "getval": re.compile(
+ r"""\s+distribute-list
+ \s(?P<route_map>route-map\s\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] }}"}},
+ },
+ },
+ },
+ },
+ {
+ "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)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_domain_id,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "domain_id": {
+ "ip_address": {
+ "address": "{{ address }}",
+ "secondary": "{{ True if secondary is defined }}",
+ },
+ "null": "{{ True if null is defined }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "domain_tag",
+ "getval": re.compile(
+ r"""\s+domain-tag
+ \s(?P<tag>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "domain-tag {{ domain_tag }}",
+ "result": {"processes": {"{{ pid }}": {"domain_tag": "{{ tag|int }}"}}},
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_event_log,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "event_log": {
+ "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 }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "help",
+ "getval": re.compile(
+ r"""\s+(?P<help>help)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "help",
+ "result": {"processes": {"{{ pid }}": {"help": "{{ True if help is defined }}"}}},
+ },
+ {
+ "name": "ignore",
+ "getval": re.compile(
+ r"""\s+(?P<ignore>ignore)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "ignore lsa mospf",
+ "result": {"processes": {"{{ pid }}": {"ignore": "{{ True if ignore is defined }}"}}},
+ },
+ {
+ "name": "interface_id",
+ "getval": re.compile(
+ r"""\s+(?P<interface_id>interface-id\ssnmp-if-index)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "interface-id snmp-if-index",
+ "result": {
+ "processes": {
+ "{{ pid }}": {"interface_id": "{{ True if interface_id is defined }}"},
+ },
+ },
+ },
+ {
+ "name": "ispf",
+ "getval": re.compile(
+ r"""\s+(?P<ispf>ispf)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "ispf",
+ "result": {"processes": {"{{ pid }}": {"ispf": "{{ True if ispf is defined }}"}}},
+ },
+ {
+ "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))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_limit,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "limit": {
+ "dc": {
+ "number": "{{ dc_num.split(" ")[1]|int }}",
+ "disable": "{{ True if dc_disable is defined }}",
+ },
+ "non_dc": {
+ "number": "{{ non_dc_num.split(" ")[1]|int }}",
+ "disable": "{{ True if dc_disable is defined }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "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)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_vrf_local_rib_criteria,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "local_rib_criteria": {
+ "enable": "{{ True if local is defined and forward is undefined and inter is undefined and nssa is undefined }}",
+ "forwarding_address": "{{ True if forward is defined }}",
+ "inter_area_summary": "{{ True if inter is defined }}",
+ "nssa_translation": "{{ True if nssa is defined }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "log_adjacency_changes",
+ "getval": re.compile(
+ r"""\s+(?P<log>log-adjacency-changes)*
+ \s*(?P<detail>detail)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_log_adjacency_changes,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "log_adjacency_changes": {
+ "set": "{{ True if log is defined and detail is undefined }}",
+ "detail": "{{ True if detail is defined }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_max_lsa,
+ "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] }}",
+ "warning_only": "{{ True if warning is defined }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_max_metric,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "max_metric": {
+ "router_lsa": "{{ True if router_lsa is defined }}",
+ "external_lsa": "{{ external_lsa.split(" ")[1] }}",
+ "include_stub": "{{ ignore_count.split(" ")[1] }}",
+ "on_startup": {
+ "time": "{{ startup_time.split(" ")[1] }}",
+ "wait_for_bgp": "{{ True if startup_wait is defined }}",
+ },
+ "summary_lsa": "{{ summary_lsa.split(" ")[1] }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "maximum_paths",
+ "getval": re.compile(
+ r"""\s+maximum-paths*
+ \s+(?P<paths>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "maximum-paths {{ maximum_paths }}",
+ "result": {"processes": {"{{ pid }}": {"maximum_paths": "{{ paths }}"}}},
+ },
+ {
+ "name": "mpls.ldp",
+ "getval": re.compile(
+ r"""\s+mpls
+ \sldp*
+ \s*(?P<autoconfig>autoconfig*\s*(?P<area>area\s\S+))*
+ \s*(?P<sync>sync)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_mpls_ldp,
+ "compval": "ldp",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "mpls": {
+ "ldp": {
+ "autoconfig": {
+ "set": "{{ True if autoconfig is defined and area is undefined }}",
+ "area": "{{ area.split(" ")[1] }}",
+ },
+ "sync": "{{ True if sync is defined }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "mpls.traffic_eng",
+ "getval": re.compile(
+ r"""\s+mpls
+ \straffic-eng*
+ \s*(?P<area>area\s\S+)*
+ \s*(?P<autoroute>autoroute-exclude\s\S+\s\S+)*
+ \s*(?P<interface>interface\s(?P<int_type>\S+\s\S+)\s(?P<int_area>area\s\S+))*
+ \s*(?P<mesh>mesh-group\s\d+\s(?P<mesh_int>\S+\s\S+)\s(?P<mesh_area>area\s\d+))*
+ \s*(?P<multicast>multicast-intact)*
+ \s*(?P<router>router-id\s(?P<router_int>\S+\s\S+))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_mpls_traffic_eng,
+ "compval": "traffic_eng",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "mpls": {
+ "traffic_eng": {
+ "area": "{{ area.split(" ")[1] }}",
+ "autoroute_exclude": "{{ autoroute.split(" ")[2] }}",
+ "interface": {
+ "interface_type": "{{ int_type }}",
+ "area": "{{ int_area.split(" ")[1] }}",
+ },
+ "mesh_group": {
+ "id": "{{ mesh.split(" ")[1] }}",
+ "interface": "{{ mest_int }}",
+ "area": "{{ mesh_area.split(" ")[1] }}",
+ },
+ "multicast_intact": "{{ True if multicast is defined }}",
+ "router_id_interface": "{{ router_int }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_neighbor,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "neighbor": {
+ "address": "{{ address }}",
+ "cost": "{{ cost.split(" ")[1] }}",
+ "database_filter": "{{ True if db_filter is defined }}",
+ "poll_interval": "{{ poll.split(" ")[1] }}",
+ "priority": "{{ priority.split(" ")[1] }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_network,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "network": [
+ {
+ "address": "{{ address }}",
+ "wildcard_bits": "{{ wildcard }}",
+ "area": "{{ area.split(" ")[1] }}",
+ },
+ ],
+ },
+ },
+ },
+ },
+ {
+ "name": "nsf.cisco",
+ "getval": re.compile(
+ r"""\s+nsf
+ \s(?P<cisco>cisco)*
+ \s*(?P<helper>helper)*
+ \s*(?P<disable>disable)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_nsf_cisco,
+ "compval": "cisco",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "nsf": {
+ "cisco": {
+ "helper": "{{ True if helper is defined }}",
+ "disable": "{{ True if disable is defined }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "nsf.ietf",
+ "getval": re.compile(
+ r"""\s+nsf
+ \s(?P<ietf>ietf)*
+ \s*(?P<helper>helper)*
+ \s*(?P<disable>disable)*
+ \s*(?P<strict>strict-lsa-checking)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_nsf_ietf,
+ "compval": "ietf",
+ "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 }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "passive_interfaces",
+ "getval": re.compile(
+ r"""\s*(?P<no>no)*
+ \s*passive-interface*
+ \s*(?P<interface>\S+\s\S+|\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_passive_interfaces,
+ "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 }}"],
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "passive_interface",
+ "getval": re.compile(
+ r"""\s+passive-interface
+ \s(?P<interface>\S+\s\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "passive-interface {{ passive_interface }}",
+ "result": {"processes": {"{{ pid }}": {"passive_interface": "{{ interface }}"}}},
+ },
+ {
+ "name": "prefix_suppression",
+ "getval": re.compile(
+ r"""\s+(?P<prefix_sup>prefix-suppression)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "prefix-suppression",
+ "result": {
+ "processes": {
+ "{{ pid }}": {"prefix_suppression": "{{ True if prefix_sup is defined }}"},
+ },
+ },
+ },
+ {
+ "name": "priority",
+ "getval": re.compile(
+ r"""\s+priority
+ \s(?P<priority>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "priority {{ priority }}",
+ "result": {"processes": {"{{ pid }}": {"priority": "{{ priority }}"}}},
+ },
+ {
+ "name": "queue_depth.hello",
+ "getval": re.compile(
+ r"""\s+queue-depth
+ \shello*
+ \s*(?P<max_packets>\d+)*
+ \s*(?P<unlimited>unlimited)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_queue_depth_hello,
+ "compval": "hello",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "queue_depth": {
+ "hello": {
+ "max_packets": "{{ max_packets }}",
+ "unlimited": "{{ True if unlimited is defined }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "queue_depth.update",
+ "getval": re.compile(
+ r"""\s+queue-depth
+ \supdate*
+ \s*(?P<max_packets>\d+)*
+ \s*(?P<unlimited>unlimited)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_queue_depth_update,
+ "compval": "update",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "queue_depth": {
+ "update": {
+ "max_packets": "{{ max_packets }}",
+ "unlimited": "{{ True if unlimited is defined }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "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})
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "router-id {{ router_id }}",
+ "result": {"processes": {"{{ pid }}": {"router_id": "{{ id }}"}}},
+ },
+ {
+ "name": "shutdown",
+ "getval": re.compile(
+ r"""\s+(?P<shutdown>shutdown)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "shutdown",
+ "result": {
+ "processes": {"{{ pid }}": {"shutdown": "{{ True if shutdown is defined }}"}},
+ },
+ },
+ {
+ "name": "summary_address",
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_summary_address,
+ "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] }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "timers.lsa",
+ "getval": re.compile(
+ r"""\s+timers
+ \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",
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_timers_pacing,
+ "compval": "pacing",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "timers": {
+ "pacing": {
+ "flood": "{{ flood.split(" ")[1] }}",
+ "lsa_group": "{{ lsa_group.split(" ")[1] }}",
+ "retransmission": "{{ retransmission.split(" ")[1] }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "timers throttle lsa {{ throttle.lsa.first_delay }} {{ throttle.lsa.min_delay }} {{ throttle.lsa.max_delay }}",
+ "compval": "throttle.lsa",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "timers": {
+ "throttle": {
+ "lsa": {
+ "first_delay": "{{ first_delay }}",
+ "min_delay": "{{ min_delay }}",
+ "max_delay": "{{ max_delay }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "timers throttle spf {{ throttle.spf.receive_delay }} {{ throttle.spf.between_delay }} {{ throttle.spf.max_delay }}",
+ "compval": "throttle.spf",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "timers": {
+ "throttle": {
+ "spf": {
+ "receive_delay": "{{ first_delay }}",
+ "between_delay": "{{ min_delay }}",
+ "max_delay": "{{ max_delay }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traffic_share",
+ "getval": re.compile(
+ r"""\s+(?P<traffic>traffic-share\smin\sacross-interfaces)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "traffic-share min across-interfaces",
+ "result": {
+ "processes": {"{{ pid }}": {"traffic_share": "{{ True if traffic is defined }}"}},
+ },
+ },
+ {
+ "name": "ttl_security",
+ "getval": re.compile(
+ r"""\s+ttl-security
+ \s(?P<interfaces>all-interfaces)*
+ \s*(?P<hops>hops\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_ttl_security,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "ttl_security": {
+ "set": "{{ True if interfaces is defined and hops is undefined }}",
+ "hops": "{{ hops.split(" ")[1] }}",
+ },
+ },
+ },
+ },
+ },
+ ]
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
new file mode 100644
index 000000000..874eed614
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ospfv3.py
@@ -0,0 +1,2935 @@
+from __future__ import absolute_import, division, print_function
+
+
+__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_ospfv3_cmd(process):
+ command = "router ospfv3 {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 = []
+ # for config_data in config_data["address_family"]:
+ cmd = "address-family {afi}".format(**config_data["address_family"])
+ if config_data["address_family"].get("unicast"):
+ cmd += " unicast"
+ if config_data["address_family"].get("vrf"):
+ cmd += " vrf {vrf}".format(**config_data["address_family"])
+ command.append(cmd)
+ if command:
+ command.insert(len(command), "exit-address-family")
+ return command
+
+
+def _tmplt_address_family_graceful_restart(config_data):
+ if "graceful_restart" in config_data:
+ command = "graceful_restart {enable}".format(**config_data["graceful_restart"])
+ if "disable" in config_data["graceful_restart"]:
+ command += " disable"
+ elif "strict_lsa_checking" in config_data["graceful_restart"]:
+ command += " strict-lsa-checking"
+ 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:
+ command = "area {area_id} nssa".format(**config_data)
+ if "default_information_originate" in config_data["nssa"]:
+ 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"]:
+ command += " nssa-only"
+ if config_data["nssa"].get("no_ext_capability"):
+ command += " no-ext-capability"
+ if config_data["nssa"].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 and "translate" in config_data["nssa"]:
+ 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"]:
+ 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"
+ if "ip_address" in config_data["domain_id"]:
+ 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"])
+ 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_manet(config_data):
+ if "manet" in config_data:
+ command = []
+ if "cache" in config_data["manet"]:
+ cmd = "manet cache"
+ if "acknowledgement" in config_data["manet"]["cache"]:
+ cmd += " acknowledgement {acknowledgement}".format(**config_data["manet"]["cache"])
+ elif "redundancy" in config_data["manet"]["cache"]:
+ cmd += " redundancy {redundancy}".format(**config_data["manet"]["cache"])
+ command.append(cmd)
+ if "hello" in config_data["manet"] and config_data["manet"]["hello"]:
+ command.append("manet hello")
+ if "peering" in config_data["manet"]:
+ cmd = "manet peering selective"
+ if "per_interface" in config_data["manet"]["peering"]:
+ cmd += " per-interface"
+ if "redundancy" in config_data["manet"]["peering"]:
+ cmd += " redundancy {redundancy}".format(**config_data["manet"]["peering"])
+ command.append(cmd)
+ if "willingness" in config_data["manet"]:
+ command.append("manet willingness".format(**config_data["manet"]["willingness"]))
+ 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"
+ if "router_lsa" in config_data["max_metric"]:
+ command += " router-lsa"
+ if "external_lsa" in config_data["max_metric"]:
+ command += " external-lsa {external_lsa}".format(**config_data["max_metric"])
+ if "include_stub" in config_data["max_metric"]:
+ command += " include-stub"
+ if "on_startup" in config_data["max_metric"]:
+ if "time" in config_data["max_metric"]["on_startup"]:
+ command += " on-startup {time}".format(**config_data["max_metric"]["on_startup"])
+ elif "wait_for_bgp" in config_data["max_metric"]["on_startup"]:
+ command += " on-startup wait-for-bgp"
+ if "summary_lsa" in config_data["max_metric"]:
+ command += " summary-lsa {summary_lsa}".format(**config_data["max_metric"])
+ 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"
+ if "area" in config_data["mpls"]["traffic_eng"]:
+ 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"]
+ )
+ elif "interface" in config_data["mpls"]["traffic_eng"]:
+ command += " interface {int_type}".format(
+ **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"]
+ )
+ if "area" in config_data["mpls"]["traffic_eng"]["mesh_group"]:
+ command += " area {area}".format(**config_data["mpls"]["traffic_eng"]["mesh_group"])
+ elif "multicast_intact" in config_data["mpls"]["traffic_eng"]:
+ 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"]
+ )
+ return command
+
+
+def _tmplt_ospf_neighbor(config_data):
+ if "neighbor" in config_data:
+ command = "neighbor"
+ if "address" in config_data["neighbor"]:
+ command += " {address}".format(**config_data["neighbor"])
+ if "cost" in config_data["neighbor"]:
+ command += " cost {cost}".format(**config_data["neighbor"])
+ if "database_filter" in config_data["neighbor"]:
+ command += " database-filter all out"
+ if "poll_interval" in config_data["neighbor"]:
+ command += " poll-interval {poll_interval}".format(**config_data["neighbor"])
+ if "priority" in config_data["neighbor"]:
+ command += " priority {priority}".format(**config_data["neighbor"])
+ return command
+
+
+def _tmplt_ospf_network(config_data):
+ if "network" in config_data:
+ command = "network"
+ if "address" in config_data["network"]:
+ command += " {address} {wildcard_bits}".format(**config_data["network"])
+ if "area" in config_data["network"]:
+ command += " area {area}".format(**config_data["network"])
+ 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_summary_prefix(config_data):
+ if "summary_prefix" in config_data:
+ command = "summary-prefix {address} {mask}".format(**config_data["summary_prefix"])
+ if "not_advertise" in config_data["summary_prefix"]:
+ command += " not-advertise"
+ elif "nssa_only" in config_data["summary_prefix"]:
+ command += " nssa-only"
+ if "tag" in config_data["summary_prefix"]:
+ command += " tag {tag}".format(**config_data["summary_prefix"])
+ 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 Ospfv3Template(NetworkTemplate):
+ def __init__(self, lines=None, module=None):
+ super(Ospfv3Template, self).__init__(lines=lines, tmplt=self, module=module)
+
+ PARSERS = [
+ {
+ "name": "pid",
+ "getval": re.compile(
+ r"""
+ ^router\s
+ ospfv3*
+ \s(?P<pid>\S+)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospfv3_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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_adjacency_cmd,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "adjacency": {
+ "min_adjacency": "{{ min|int }}",
+ "max_adjacency": "{{ max|int }}",
+ "none": "{{ True if none_adj is defined else None }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "area.authentication",
+ "getval": re.compile(
+ r"""\s+area
+ \s(?P<area_id>\S+)*
+ \s*(?P<auth>authentication)*
+ \s*(?P<md>message-digest)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_authentication,
+ "compval": "authentication",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "authentication": {
+ "enable": "{{ True if auth is defined and md is undefined }}",
+ "message_digest": "{{ not not md }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "area.capability",
+ "getval": re.compile(
+ r"""\s+area
+ \s(?P<area_id>\S+)*
+ \s*(?P<capability>capability)*
+ \s*(?P<df>default-exclusion)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "area {{ area_id }} capability default-exclusion",
+ "compval": "capability",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "capability": "{{ not not capability }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "area.default_cost",
+ "getval": re.compile(
+ r"""\s+area
+ \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 }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "default_cost": "{{ default_cost|int }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "area.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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_filter,
+ "compval": "filter_list",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "filter_list": [{"name": "{{ name }}", "direction": "{{ dir }}"}],
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "area.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)*$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_nssa,
+ "compval": "nssa",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "nssa": {
+ "set": "{{ True if nssa is defined and 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 }}",
+ "nssa_only": "{{ True if nssa_only is defined }}",
+ },
+ "no_ext_capability": "{{ True if no_ext is defined }}",
+ "no_redistribution": "{{ True if no_redis is defined }}",
+ "no_summary": "{{ True if no_summary is defined }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "area.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)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_nssa_translate,
+ "compval": "nssa.translate",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "nssa": {
+ "translate": "{{ translate_always if translate_always is defined else translate_supress if translate_supress is defined }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "area.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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_ranges,
+ "compval": "ranges",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "ranges": [
+ {
+ "address": "{{ address }}",
+ "netmask": "{{ netmask }}",
+ "advertise": "{{ True if advertise is defined }}",
+ "cost": "{{ cost.split(" ")[1]|int }}",
+ "not_advertise": "{{ True if not_advertise is defined }}",
+ },
+ ],
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "area.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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_sham_link,
+ "compval": "sham_link",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "sham_link": {
+ "source": "{{ source }}",
+ "destination": "{{ destination }}",
+ "cost": "{{ cost.split(" ")[1]|int }}",
+ "ttl_security": '{{ ttl_security.split("hops ")[1] }}',
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "area.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)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_stub_link,
+ "compval": "stub",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "stub": {
+ "set": "{{ True if stub is defined and no_ext is undefined and no_sum is undefined }}",
+ "no_ext_capability": "{{ True if no_ext is defined }}",
+ "no_summary": "{{ True if no_sum is defined }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "auto_cost",
+ "getval": re.compile(
+ r"""\s+(?P<auto_cost>auto-cost)*
+ \s*(?P<ref_band>reference-bandwidth\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_auto_cost,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "auto_cost": {
+ "set": "{{ True if auto_cost is defined and ref_band is undefined }}",
+ "reference_bandwidth": '{{ ref_band.split(" ")[1] }}',
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "bfd",
+ "getval": re.compile(
+ r"""\s+bfd*
+ \s*(?P<bfd>all-interfaces)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "bfd all-interfaces",
+ "result": {"processes": {"{{ pid }}": {"bfd": "{{ True if bfd is defined }}"}}},
+ },
+ {
+ "name": "capability",
+ "getval": re.compile(
+ r"""\s+capability*
+ \s*((?P<lls>lls)|(?P<opaque>opaque)|(?P<transit>transit)|(?P<vrf_lite>vrf-lite))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_capability,
+ "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 }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "compatible",
+ "getval": re.compile(
+ r"""\s+compatible*
+ \s*((?P<rfc1583>rfc1583)|(?P<rfc1587>rfc1587)|(?P<rfc5243>rfc5243))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_compatible,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "compatible": {
+ "rfc1583": "{{ True if rfc1583 is defined }}",
+ "rfc1587": "{{ True if rfc1587 is defined }}",
+ "rfc5243": "{{ True if rfc5243 is defined }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_default_information,
+ "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] }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "default_metric",
+ "getval": re.compile(
+ r"""\s+default-metric(?P<default_metric>\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "default-metric {{ default_metric }}",
+ "result": {"processes": {"{{ pid }}": {"default_metric": "{{ default_metric| int}}"}}},
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_discard_route,
+ "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 }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distance_admin_distance,
+ "compval": "admin_distance",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "distance": {
+ "admin_distance": {
+ "distance": "{{ admin_dist }}",
+ "address": "{{ source }}",
+ "wildcard_bits": "{{ wildcard }}",
+ "acl": "{{ acl }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distance_ospf,
+ "compval": "ospf",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "distance": {
+ "ospf": {
+ "inter_area": "{{ inter.split(" ")[1]|int }}",
+ "intra_area": "{{ intra.split(" ")[1]|int }}",
+ "external": "{{ external.split(" ")[1]|int }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distribute_list_acls,
+ "compval": "distribute_list.acls",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "distribute_list": {
+ "acls": [
+ {
+ "name": "{{ name }}",
+ "direction": "{{ dir }}",
+ "interface": '{{ int_pro if dir == "in" }}',
+ "protocol": '{{ int_pro if dir == "out" }}',
+ },
+ ],
+ },
+ },
+ },
+ },
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distribute_list_prefix,
+ "compval": "distribute_list.prefix",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "distribute_list": {
+ "prefix": {
+ "name": "{{ prefix.split(" ")[1] }}",
+ "gateway_name": "{{ gateway.split(" ")[1] if prefix is defined }}",
+ "direction": "{{ dir if gateway is undefined }}",
+ "interface": '{{ int_pro if dir == "in" }}',
+ "protocol": '{{ int_pro if dir == "out" }}',
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "distribute_list.route_map",
+ "getval": re.compile(
+ r"""\s+distribute-list
+ \s(?P<route_map>route-map\s\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] }}"}},
+ },
+ },
+ },
+ },
+ {
+ "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)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_domain_id,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "domain_id": {
+ "ip_address": {
+ "address": "{{ address }}",
+ "secondary": "{{ True if secondary is defined }}",
+ },
+ "null": "{{ True if null is defined }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "domain_tag",
+ "getval": re.compile(
+ r"""\s+domain-tag
+ \s(?P<tag>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "domain-tag {{ domain_tag }}",
+ "result": {"processes": {"{{ pid }}": {"domain_tag": "{{ tag|int }}"}}},
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_event_log,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "event_log": {
+ "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 }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "help",
+ "getval": re.compile(
+ r"""\s+(?P<help>help)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "help",
+ "result": {"processes": {"{{ pid }}": {"help": "{{ True if help is defined }}"}}},
+ },
+ {
+ "name": "ignore",
+ "getval": re.compile(
+ r"""\s+(?P<ignore>ignore)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "ignore lsa mospf",
+ "result": {"processes": {"{{ pid }}": {"ignore": "{{ True if ignore is defined }}"}}},
+ },
+ {
+ "name": "interface_id",
+ "getval": re.compile(
+ r"""\s+(?P<interface_id>interface-id\ssnmp-if-index)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "interface-id snmp-if-index",
+ "result": {
+ "processes": {
+ "{{ pid }}": {"interface_id": "{{ True if interface_id is defined }}"},
+ },
+ },
+ },
+ {
+ "name": "ispf",
+ "getval": re.compile(
+ r"""\s+(?P<ispf>ispf)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "ispf",
+ "result": {"processes": {"{{ pid }}": {"ispf": "{{ True if ispf is defined }}"}}},
+ },
+ {
+ "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))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_limit,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "limit": {
+ "dc": {
+ "number": "{{ dc_num.split(" ")[1]|int }}",
+ "disable": "{{ True if dc_disable is defined }}",
+ },
+ "non_dc": {
+ "number": "{{ non_dc_num.split(" ")[1]|int }}",
+ "disable": "{{ True if dc_disable is defined }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "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)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_vrf_local_rib_criteria,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "local_rib_criteria": {
+ "enable": "{{ True if local is defined and forward is undefined and inter is undefined and nssa is undefined }}",
+ "forwarding_address": "{{ True if forward is defined }}",
+ "inter_area_summary": "{{ True if inter is defined }}",
+ "nssa_translation": "{{ True if nssa is defined }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "log_adjacency_changes",
+ "getval": re.compile(
+ r"""\s+(?P<log>log-adjacency-changes)*
+ \s*(?P<detail>detail)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_log_adjacency_changes,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "log_adjacency_changes": {
+ "set": "{{ True if log is defined and detail is undefined }}",
+ "detail": "{{ True if detail is defined }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "manet",
+ "getval": re.compile(
+ r"""\s+manet*
+ \s*(?P<cache>cache)*
+ \s*(?P<acknowledgement>acknowledgement\s\d+)*
+ \s*(?P<update>update\s\d+)*
+ \s*(?P<hello>hello)*
+ \s*(?P<unicast>unicast)*
+ \s*(?P<multicast>multicast)*
+ \s*(?P<peering>peering\sselective)*
+ \s*(?P<disable>disable)*
+ \s*(?P<per_interface>per-interface)*
+ \s*(?P<redundancy>redundancy\s\d+)*
+ \s*(?P<willingness>willingness\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_manet,
+ "compval": "manet",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "manet": {
+ "cache": {
+ "acknowledgement": "{{ acknowledgement.split(" ")[1] }}",
+ "update": "{{ update.split(" ")[1] }}",
+ },
+ "hello": {
+ "unicast": "{{ True if unicast is defined }}",
+ "multicast": "{{ True if multicast is defined }}",
+ },
+ "peering": {
+ "set": "{{ True if peering is defined }}",
+ "disable": "{{ True if disable is defined }}",
+ "per_interface": "{{ True if per_interface is defined }}",
+ "redundancy": "{{ redundancy.split(" ")[1] }}",
+ },
+ "willingness": "{{ willingness.split(" ")[1] }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_max_lsa,
+ "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] }}",
+ "warning_only": "{{ True if warning is defined }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_max_metric,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "max_metric": {
+ "router_lsa": "{{ True if router_lsa is defined }}",
+ "external_lsa": "{{ external_lsa.split(" ")[1] }}",
+ "include_stub": "{{ ignore_count.split(" ")[1] }}",
+ "on_startup": {
+ "time": "{{ startup_time.split(" ")[1] }}",
+ "wait_for_bgp": "{{ True if startup_wait is defined }}",
+ },
+ "summary_lsa": "{{ summary_lsa.split(" ")[1] }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "maximum_paths",
+ "getval": re.compile(
+ r"""\s+maximum-paths*
+ \s+(?P<paths>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "maximum-paths {{ maximum_paths }}",
+ "result": {"processes": {"{{ pid }}": {"maximum_paths": "{{ paths }}"}}},
+ },
+ {
+ "name": "mpls.ldp",
+ "getval": re.compile(
+ r"""\s+mpls
+ \sldp*
+ \s*(?P<autoconfig>autoconfig*\s*(?P<area>area\s\S+))*
+ \s*(?P<sync>sync)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_mpls_ldp,
+ "compval": "ldp",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "mpls": {
+ "ldp": {
+ "autoconfig": {
+ "set": "{{ True if autoconfig is defined and area is undefined }}",
+ "area": "{{ area.split(" ")[1] }}",
+ },
+ "sync": "{{ True if sync is defined }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "mpls.traffic_eng",
+ "getval": re.compile(
+ r"""\s+mpls
+ \straffic-eng*
+ \s*(?P<area>area\s\S+)*
+ \s*(?P<autoroute>autoroute-exclude\s\S+\s\S+)*
+ \s*(?P<interface>interface\s(?P<int_type>\S+\s\S+)\s(?P<int_area>area\s\S+))*
+ \s*(?P<mesh>mesh-group\s\d+\s(?P<mesh_int>\S+\s\S+)\s(?P<mesh_area>area\s\d+))*
+ \s*(?P<multicast>multicast-intact)*
+ \s*(?P<router>router-id\s(?P<router_int>\S+\s\S+))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_mpls_traffic_eng,
+ "compval": "traffic_eng",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "mpls": {
+ "traffic_eng": {
+ "area": "{{ area.split(" ")[1] }}",
+ "autoroute_exclude": "{{ autoroute.split(" ")[2] }}",
+ "interface": {
+ "interface_type": "{{ int_type }}",
+ "area": "{{ int_area.split(" ")[1] }}",
+ },
+ "mesh_group": {
+ "id": "{{ mesh.split(" ")[1] }}",
+ "interface": "{{ mest_int }}",
+ "area": "{{ mesh_area.split(" ")[1] }}",
+ },
+ "multicast_intact": "{{ True if multicast is defined }}",
+ "router_id_interface": "{{ router_int }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_neighbor,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "neighbor": {
+ "address": "{{ address }}",
+ "cost": "{{ cost.split(" ")[1] }}",
+ "database_filter": "{{ True if db_filter is defined }}",
+ "poll_interval": "{{ poll.split(" ")[1] }}",
+ "priority": "{{ priority.split(" ")[1] }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_network,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "network": {
+ "address": "{{ address }}",
+ "wildcard_bits": "{{ wildcard }}",
+ "area": "{{ area.split(" ")[1] }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "nsf.cisco",
+ "getval": re.compile(
+ r"""\s+nsf
+ \s(?P<cisco>cisco)*
+ \s*(?P<helper>helper)*
+ \s*(?P<disable>disable)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_nsf_cisco,
+ "compval": "cisco",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "nsf": {
+ "cisco": {
+ "helper": "{{ True if helper is defined }}",
+ "disable": "{{ True if disable is defined }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "nsf.ietf",
+ "getval": re.compile(
+ r"""\s+nsf
+ \s(?P<ietf>ietf)*
+ \s*(?P<helper>helper)*
+ \s*(?P<disable>disable)*
+ \s*(?P<strict>strict-lsa-checking)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_nsf_ietf,
+ "compval": "ietf",
+ "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 }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "passive_interface",
+ "getval": re.compile(
+ r"""\s+passive-interface
+ \s(?P<interface>\S+\s\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "passive-interface {{ passive_interface }}",
+ "result": {"processes": {"{{ pid }}": {"passive_interface": "{{ interface }}"}}},
+ },
+ {
+ "name": "prefix_suppression",
+ "getval": re.compile(
+ r"""\s+(?P<prefix_sup>prefix-suppression)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "prefix-suppression",
+ "result": {
+ "processes": {
+ "{{ pid }}": {"prefix_suppression": "{{ True if prefix_sup is defined }}"},
+ },
+ },
+ },
+ {
+ "name": "priority",
+ "getval": re.compile(
+ r"""\s+priority
+ \s(?P<priority>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "priority {{ priority }}",
+ "result": {"processes": {"{{ pid }}": {"priority": "{{ priority }}"}}},
+ },
+ {
+ "name": "queue_depth.hello",
+ "getval": re.compile(
+ r"""\s+queue-depth
+ \shello*
+ \s*(?P<max_packets>\d+)*
+ \s*(?P<unlimited>unlimited)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_queue_depth_hello,
+ "compval": "hello",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "queue_depth": {
+ "hello": {
+ "max_packets": "{{ max_packets }}",
+ "unlimited": "{{ True if unlimited is defined }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "queue_depth.update",
+ "getval": re.compile(
+ r"""\s+queue-depth
+ \supdate*
+ \s*(?P<max_packets>\d+)*
+ \s*(?P<unlimited>unlimited)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_queue_depth_update,
+ "compval": "update",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "queue_depth": {
+ "update": {
+ "max_packets": "{{ max_packets }}",
+ "unlimited": "{{ True if unlimited is defined }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "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})
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "router-id {{ router_id }}",
+ "result": {"processes": {"{{ pid }}": {"router_id": "{{ id }}"}}},
+ },
+ {
+ "name": "shutdown",
+ "getval": re.compile(
+ r"""\s+(?P<shutdown>shutdown)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "shutdown",
+ "result": {
+ "processes": {"{{ pid }}": {"shutdown": "{{ True if shutdown is defined }}"}},
+ },
+ },
+ {
+ "name": "timers.lsa",
+ "getval": re.compile(
+ r"""\s+timers
+ \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",
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_timers_pacing,
+ "compval": "pacing",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "timers": {
+ "pacing": {
+ "flood": "{{ flood.split(" ")[1] }}",
+ "lsa_group": "{{ lsa_group.split(" ")[1] }}",
+ "retransmission": "{{ retransmission.split(" ")[1] }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "timers throttle lsa {{ throttle.lsa.first_delay }} {{ throttle.lsa.min_delay }} {{ throttle.lsa.max_delay }}",
+ "compval": "throttle.lsa",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "timers": {
+ "throttle": {
+ "lsa": {
+ "first_delay": "{{ first_delay }}",
+ "min_delay": "{{ min_delay }}",
+ "max_delay": "{{ max_delay }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "timers throttle spf {{ throttle.spf.receive_delay }} {{ throttle.spf.between_delay }} {{ throttle.spf.max_delay }}",
+ "compval": "throttle.spf",
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "timers": {
+ "throttle": {
+ "spf": {
+ "receive_delay": "{{ first_delay }}",
+ "between_delay": "{{ min_delay }}",
+ "max_delay": "{{ max_delay }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traffic_share",
+ "getval": re.compile(
+ r"""\s+(?P<traffic>traffic-share\smin\sacross-interfaces)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "traffic-share min across-interfaces",
+ "result": {
+ "processes": {"{{ pid }}": {"traffic_share": "{{ True if traffic is defined }}"}},
+ },
+ },
+ {
+ "name": "ttl_security",
+ "getval": re.compile(
+ r"""\s+ttl-security
+ \s(?P<interfaces>all-interfaces)*
+ \s*(?P<hops>hops\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_ttl_security,
+ "result": {
+ "processes": {
+ "{{ pid }}": {
+ "ttl_security": {
+ "set": "{{ True if interfaces is defined and hops is undefined }}",
+ "hops": "{{ hops.split(" ")[1] }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "address_family",
+ "getval": re.compile(
+ r"""\s+address-family*
+ \s*(?P<afi>\S+)*
+ \s*(?P<unicast>unicast)*
+ \s*(?P<vrf>vrf\s\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_address_family_cmd,
+ # "compval": "afi",
+ "result": {
+ "address_family": [
+ {
+ "afi": "{{ afi }}",
+ "unicast": "{{ True if unicast is defined }}",
+ "vrf": "{{ vrf.split(" ")[1] }}",
+ },
+ ],
+ },
+ "shared": True,
+ },
+ {
+ "name": "address_family.exit",
+ "getval": re.compile(
+ r"""\s+exit-address-family
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_address_family_cmd,
+ "result": {
+ "address_family": [
+ {
+ "exit": {
+ "pid": "{{ id }}",
+ "afi": "{{ afi }}",
+ "unicast": "{{ True if unicast is defined }}",
+ "vrf": "{{ vrf.split(" ")[1] }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.adjacency",
+ "getval": re.compile(
+ r"""\s+adjacency
+ \sstagger*
+ \s*((?P<min>\d+)|(?P<none_adj>none))*
+ \s*(?P<max>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_adjacency_cmd,
+ "compval": "adjacency",
+ "result": {
+ "address_family": [
+ {
+ "adjacency": {
+ "min_adjacency": "{{ min|int }}",
+ "max_adjacency": "{{ max|int }}",
+ "none": "{{ True if none_adj is defined else None }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.area.authentication",
+ "getval": re.compile(
+ r"""\s+area
+ \s(?P<area_id>\S+)*
+ \s*(?P<auth>authentication)*
+ \s*(?P<md>message-digest)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_authentication,
+ "compval": "authentication",
+ "result": {
+ "address_family": [
+ {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "authentication": {
+ "enable": "{{ True if auth is defined and md is undefined }}",
+ "message_digest": "{{ not not md }}",
+ },
+ },
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.area.capability",
+ "getval": re.compile(
+ r"""\s+area
+ \s(?P<area_id>\S+)*
+ \s*(?P<capability>capability)*
+ \s*(?P<df>default-exclusion)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "area {{ area_id }} capability default-exclusion",
+ "compval": "capability",
+ "result": {
+ "address_family": [
+ {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "capability": "{{ not not capability }}",
+ },
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.area.default_cost",
+ "getval": re.compile(
+ r"""\s+area
+ \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": {
+ "address_family": [
+ {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "default_cost": "{{ default_cost|int }}",
+ },
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.area.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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_filter,
+ "compval": "filter_list",
+ "result": {
+ "address_family": [
+ {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "filter_list": [{"name": "{{ name }}", "direction": "{{ dir }}"}],
+ },
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.area.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<nssa_only>nssa-only)*
+ \s*(?P<no_summary>no-summary)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_nssa,
+ "compval": "nssa",
+ "result": {
+ "address_family": [
+ {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "nssa": {
+ "set": "{{ True if nssa is defined and 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 }}",
+ "nssa_only": "{{ True if nssa_only is defined }}",
+ },
+ "no_ext_capability": "{{ True if no_ext is defined }}",
+ "no_redistribution": "{{ True if no_redis is defined }}",
+ "no_summary": "{{ True if no_summary is defined }}",
+ },
+ },
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.area.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)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_nssa_translate,
+ "compval": "nssa.translate",
+ "result": {
+ "address_family": [
+ {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "nssa": {
+ "translate": "{{ translate_always if translate_always is defined else translate_supress if translate_supress is defined }}",
+ },
+ },
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.area.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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_ranges,
+ "compval": "ranges",
+ "result": {
+ "address_family": [
+ {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "ranges": [
+ {
+ "address": "{{ address }}",
+ "netmask": "{{ netmask }}",
+ "advertise": "{{ True if advertise is defined }}",
+ "cost": "{{ cost.split(" ")[1]|int }}",
+ "not_advertise": "{{ True if not_advertise is defined }}",
+ },
+ ],
+ },
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.area.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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_sham_link,
+ "compval": "sham_link",
+ "result": {
+ "address_family": [
+ {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "sham_link": {
+ "source": "{{ source }}",
+ "destination": "{{ destination }}",
+ "cost": "{{ cost.split(" ")[1]|int }}",
+ "ttl_security": '{{ ttl_security.split("hops ")[1] }}',
+ },
+ },
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.area.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)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_area_stub_link,
+ "compval": "stub",
+ "result": {
+ "address_family": [
+ {
+ "areas": {
+ "{{ area_id }}": {
+ "area_id": "{{ area_id }}",
+ "stub": {
+ "set": "{{ True if stub is defined and no_ext is undefined and no_sum is undefined }}",
+ "no_ext_capability": "{{ True if no_ext is defined }}",
+ "no_summary": "{{ True if no_sum is defined }}",
+ },
+ },
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.auto_cost",
+ "getval": re.compile(
+ r"""\s+(?P<auto_cost>auto-cost)*
+ \s*(?P<ref_band>reference-bandwidth\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_auto_cost,
+ "compval": "auto_cost",
+ "result": {
+ "address_family": [
+ {
+ "auto_cost": {
+ "set": "{{ True if auto_cost is defined and ref_band is undefined }}",
+ "reference_bandwidth": '{{ ref_band.split(" ")[1] }}',
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.bfd",
+ "getval": re.compile(
+ r"""\s+bfd*
+ \s*(?P<bfd>all-interfaces)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "bfd all-interfaces",
+ "compval": "bfd",
+ "result": {"address_family": [{"bfd": "{{ True if bfd is defined }}"}]},
+ },
+ {
+ "name": "address_family.capability",
+ "getval": re.compile(
+ r"""\s+capability*
+ \s*((?P<lls>lls)|(?P<opaque>opaque)|(?P<transit>transit)|(?P<vrf_lite>vrf-lite))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_capability,
+ "compval": "capability",
+ "result": {
+ "address_family": [
+ {
+ "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 }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.compatible",
+ "getval": re.compile(
+ r"""\s+compatible*
+ \s*((?P<rfc1583>rfc1583)|(?P<rfc1587>rfc1587)|(?P<rfc5243>rfc5243))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_compatible,
+ "compval": "compatible",
+ "result": {
+ "address_family": [
+ {
+ "compatible": {
+ "rfc1583": "{{ True if rfc1583 is defined }}",
+ "rfc1587": "{{ True if rfc1587 is defined }}",
+ "rfc5243": "{{ True if rfc5243 is defined }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_default_information,
+ "compval": "default_information",
+ "result": {
+ "address_family": [
+ {
+ "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] }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.default_metric",
+ "getval": re.compile(
+ r"""\s+default-metric(?P<default_metric>\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "default-metric {{ default_metric }}",
+ "compval": "default_metric",
+ "result": {"address_family": [{"default_metric": "{{ default_metric| int}}"}]},
+ },
+ {
+ "name": "address_family.discard_route",
+ "getval": re.compile(
+ r"""\s+(?P<discard_route>discard-route)*
+ \s*(?P<external>external\s\d+)*
+ \s*(?P<internal>internal\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_discard_route,
+ "compval": "discard_route",
+ "result": {
+ "address_family": [
+ {
+ "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 }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distance_admin_distance,
+ "compval": "admin_distance",
+ "result": {
+ "address_family": [
+ {
+ "distance": {
+ "admin_distance": {
+ "distance": "{{ admin_dist }}",
+ "address": "{{ source }}",
+ "wildcard_bits": "{{ wildcard }}",
+ "acl": "{{ acl }}",
+ },
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distance_ospf,
+ "compval": "ospf",
+ "result": {
+ "address_family": [
+ {
+ "distance": {
+ "ospf": {
+ "inter_area": "{{ inter.split(" ")[1]|int }}",
+ "intra_area": "{{ intra.split(" ")[1]|int }}",
+ "external": "{{ external.split(" ")[1]|int }}",
+ },
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distribute_list_acls,
+ "compval": "distribute_list.acls",
+ "result": {
+ "address_family": [
+ {
+ "distribute_list": {
+ "acls": [
+ {
+ "name": "{{ name }}",
+ "direction": "{{ dir }}",
+ "interface": '{{ int_pro if dir == "in" }}',
+ "protocol": '{{ int_pro if dir == "out" }}',
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_distribute_list_prefix,
+ "compval": "distribute_list.prefix",
+ "result": {
+ "address_family": [
+ {
+ "distribute_list": {
+ "prefix": {
+ "name": "{{ prefix.split(" ")[1] }}",
+ "gateway_name": "{{ gateway.split(" ")[1] if prefix is defined }}",
+ "direction": "{{ dir if gateway is undefined }}",
+ "interface": '{{ int_pro if dir == "in" }}',
+ "protocol": '{{ int_pro if dir == "out" }}',
+ },
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.distribute_list.route_map",
+ "getval": re.compile(
+ r"""\s+distribute-list
+ \s(?P<route_map>route-map\s\S+)*
+ \s*(?P<dir>\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "distribute-list route-map {{ distribute_list.route_map.name }} in",
+ "compval": "distribute_list.route_map",
+ "result": {
+ "address_family": [
+ {"distribute_list": {"route_map": {"name": "{{ route_map.split(" ")[1] }}"}}},
+ ],
+ },
+ },
+ {
+ "name": "address_family.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)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_domain_id,
+ "compval": "domain_id",
+ "result": {
+ "address_family": [
+ {
+ "domain_id": {
+ "ip_address": {
+ "address": "{{ address }}",
+ "secondary": "{{ True if secondary is defined }}",
+ },
+ "null": "{{ True if null is defined }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.domain_tag",
+ "getval": re.compile(
+ r"""\s+domain-tag
+ \s(?P<tag>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "domain-tag {{ domain_tag }}",
+ "compval": "domain_tag",
+ "result": {"address_family": [{"domain_tag": "{{ tag|int }}"}]},
+ },
+ {
+ "name": "address_family.graceful_restart",
+ "getval": re.compile(
+ r"""\s+graceful-restart*
+ \s*(?P<enable>helper)*
+ \s*(?P<disable>disable)*
+ \s*(?P<lsa>strict-lsa-checking)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_address_family_graceful_restart,
+ "compval": "graceful_restart",
+ "result": {
+ "address_family": [
+ {
+ "event_log": {
+ "enable": "{{ True if is enable defined }}",
+ "disable": "{{ True if disable is defined }}",
+ "strict_lsa_checking": "{{ True if lsa is defined }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_event_log,
+ "compval": "event_log",
+ "result": {
+ "address_family": [
+ {
+ "event_log": {
+ "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 }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.help",
+ "getval": re.compile(
+ r"""\s+(?P<help>help)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "help",
+ "compval": "help",
+ "result": {"address_family": [{"help": "{{ True if help is defined }}"}]},
+ },
+ {
+ "name": "address_family.interface_id",
+ "getval": re.compile(
+ r"""\s+(?P<interface_id>interface-id\ssnmp-if-index)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "interface-id snmp-if-index",
+ "compval": "interface_id",
+ "result": {
+ "address_family": [{"interface_id": "{{ True if interface_id is defined }}"}],
+ },
+ },
+ {
+ "name": "address_family.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))
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_limit,
+ "compval": "limit",
+ "result": {
+ "address_family": [
+ {
+ "limit": {
+ "dc": {
+ "number": "{{ dc_num.split(" ")[1]|int }}",
+ "disable": "{{ True if dc_disable is defined }}",
+ },
+ "non_dc": {
+ "number": "{{ non_dc_num.split(" ")[1]|int }}",
+ "disable": "{{ True if dc_disable is defined }}",
+ },
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.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)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_vrf_local_rib_criteria,
+ "compval": "local_rib_criteria",
+ "result": {
+ "address_family": [
+ {
+ "local_rib_criteria": {
+ "enable": "{{ True if local is defined and forward is undefined and inter is undefined and nssa is undefined }}",
+ "forwarding_address": "{{ True if forward is defined }}",
+ "inter_area_summary": "{{ True if inter is defined }}",
+ "nssa_translation": "{{ True if nssa is defined }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.log_adjacency_changes",
+ "getval": re.compile(
+ r"""\s+(?P<log>log-adjacency-changes)*
+ \s*(?P<detail>detail)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_log_adjacency_changes,
+ "compval": "log_adjacency_changes",
+ "result": {
+ "address_family": [
+ {
+ "log_adjacency_changes": {
+ "set": "{{ True if log is defined and detail is undefined }}",
+ "detail": "{{ True if detail is defined }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.manet",
+ "getval": re.compile(
+ r"""\s+manet*
+ \s*(?P<cache>cache)*
+ \s*(?P<acknowledgement>acknowledgement\s\d+)*
+ \s*(?P<update>update\s\d+)*
+ \s*(?P<hello>hello)*
+ \s*(?P<unicast>unicast)*
+ \s*(?P<multicast>multicast)*
+ \s*(?P<peering>peering\sselective)*
+ \s*(?P<disable>disable)*
+ \s*(?P<per_interface>per-interface)*
+ \s*(?P<redundancy>redundancy\s\d+)*
+ \s*(?P<willingness>willingness\s\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_max_lsa,
+ "compval": "manet",
+ "result": {
+ "address_family": [
+ {
+ "manet": {
+ "cache": {
+ "acknowledgement": "{{ acknowledgement.split(" ")[1] }}",
+ "update": "{{ update.split(" ")[1] }}",
+ },
+ "hello": {
+ "unicast": "{{ True if unicast is defined }}",
+ "multicast": "{{ True if multicast is defined }}",
+ },
+ "peering": {
+ "set": "{{ True if peering is defined }}",
+ "disable": "{{ True if disable is defined }}",
+ "per_interface": "{{ True if per_interface is defined }}",
+ "redundancy": "{{ redundancy.split(" ")[1] }}",
+ },
+ "willingness": "{{ willingness.split(" ")[1] }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_max_lsa,
+ "compval": "max_lsa",
+ "result": {
+ "address_family": [
+ {
+ "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] }}",
+ "warning_only": "{{ True if warning is defined }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_max_metric,
+ "compval": "max_metric",
+ "result": {
+ "address_family": [
+ {
+ "max_metric": {
+ "router_lsa": "{{ True if router_lsa is defined }}",
+ "external_lsa": "{{ external_lsa.split(" ")[1] }}",
+ "include_stub": "{{ ignore_count.split(" ")[1] }}",
+ "on_startup": {
+ "time": "{{ startup_time.split(" ")[1] }}",
+ "wait_for_bgp": "{{ True if startup_wait is defined }}",
+ },
+ "summary_lsa": "{{ summary_lsa.split(" ")[1] }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.maximum_paths",
+ "getval": re.compile(
+ r"""\s+maximum-paths*
+ \s+(?P<paths>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "maximum-paths {{ maximum_paths }}",
+ "compval": "maximum_paths",
+ "result": {"address_family": [{"maximum_paths": "{{ paths }}"}]},
+ },
+ {
+ "name": "address_family.passive_interface",
+ "getval": re.compile(
+ r"""\s+passive-interface
+ \s(?P<interface>\S+\s\S+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "passive-interface {{ passive_interface }}",
+ "compval": "passive_interface",
+ "result": {"address_family": [{"passive_interface": "{{ interface }}"}]},
+ },
+ {
+ "name": "address_family.prefix_suppression",
+ "getval": re.compile(
+ r"""\s+(?P<prefix_sup>prefix-suppression)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "prefix-suppression",
+ "compval": "prefix_suppression",
+ "result": {
+ "address_family": [{"prefix_suppression": "{{ True if prefix_sup is defined }}"}],
+ },
+ },
+ {
+ "name": "address_family.queue_depth.hello",
+ "getval": re.compile(
+ r"""\s+queue-depth
+ \shello*
+ \s*(?P<max_packets>\d+)*
+ \s*(?P<unlimited>unlimited)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_queue_depth_hello,
+ "compval": "hello",
+ "result": {
+ "address_family": [
+ {
+ "queue_depth": {
+ "hello": {
+ "max_packets": "{{ max_packets }}",
+ "unlimited": "{{ True if unlimited is defined }}",
+ },
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.queue_depth.update",
+ "getval": re.compile(
+ r"""\s+queue-depth
+ \supdate*
+ \s*(?P<max_packets>\d+)*
+ \s*(?P<unlimited>unlimited)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_queue_depth_update,
+ "compval": "update",
+ "result": {
+ "address_family": [
+ {
+ "queue_depth": {
+ "update": {
+ "max_packets": "{{ max_packets }}",
+ "unlimited": "{{ True if unlimited is defined }}",
+ },
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.router_id",
+ "getval": re.compile(
+ r"""\s+router-id
+ \s(?P<id>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "router-id {{ router_id }}",
+ "compval": "router_id",
+ "result": {"address_family": [{"router_id": "{{ id }}"}]},
+ },
+ {
+ "name": "address_family.summary_prefix",
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_summary_prefix,
+ "compval": "summary_prefix",
+ "result": {
+ "address_family": [
+ {
+ "summary_prefix": {
+ "address": "{{ address }}",
+ "mask": "{{ mask }}",
+ "not_advertise": "{{ True if not_adv is defined }}",
+ "nssa_only": "{{ True if nssa is defined }}",
+ "tag": "{{ tag.split(" ")[1] }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.shutdown",
+ "getval": re.compile(
+ r"""\s+(?P<shutdown>shutdown)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "shutdown",
+ "compval": "shutdown",
+ "result": {"address_family": [{"shutdown": "{{ True if shutdown is defined }}"}]},
+ },
+ {
+ "name": "address_family.timers.lsa",
+ "getval": re.compile(
+ r"""\s+timers
+ \slsa
+ \sarrival
+ \s(?P<lsa>\d+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "timers lsa arrival {{ timers.lsa }}",
+ "compval": "lsa",
+ "result": {"address_family": [{"timers": {"lsa": "{{ lsa }}"}}]},
+ },
+ {
+ "name": "address_family.timers.pacing",
+ "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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_ospf_timers_pacing,
+ "compval": "pacing",
+ "result": {
+ "address_family": [
+ {
+ "timers": {
+ "pacing": {
+ "flood": "{{ flood.split(" ")[1] }}",
+ "lsa_group": "{{ lsa_group.split(" ")[1] }}",
+ "retransmission": "{{ retransmission.split(" ")[1] }}",
+ },
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "timers throttle lsa {{ throttle.lsa.first_delay }} {{ throttle.lsa.min_delay }} {{ throttle.lsa.max_delay }}",
+ "compval": "throttle.lsa",
+ "result": {
+ "address_family": [
+ {
+ "timers": {
+ "throttle": {
+ "lsa": {
+ "first_delay": "{{ first_delay }}",
+ "min_delay": "{{ min_delay }}",
+ "max_delay": "{{ max_delay }}",
+ },
+ },
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "address_family.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+)
+ *$""",
+ re.VERBOSE,
+ ),
+ "setval": "timers throttle spf {{ throttle.spf.receive_delay }} {{ throttle.spf.between_delay }} {{ throttle.spf.max_delay }}",
+ "compval": "throttle.spf",
+ "result": {
+ "address_family": [
+ {
+ "timers": {
+ "throttle": {
+ "spf": {
+ "receive_delay": "{{ first_delay }}",
+ "between_delay": "{{ min_delay }}",
+ "max_delay": "{{ max_delay }}",
+ },
+ },
+ },
+ },
+ ],
+ },
+ },
+ ]
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
new file mode 100644
index 000000000..d7f375b71
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/ping.py
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+# Copyright 2022 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 Ping 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 PingTemplate(NetworkTemplate):
+ def __init__(self, lines=None):
+ super(PingTemplate, self).__init__(lines=lines, tmplt=self)
+
+ # fmt: off
+ PARSERS = [
+ {
+ 'name': 'rate',
+ 'getval': re.compile(
+ r'''
+ ^Success\srate\sis
+ (\s(?P<pct>\d+))?
+ (\spercent\s\((?P<rx>\d+)/(?P<tx>\d+)\))?
+ (,\s+round-trip\smin/avg/max\s=)?
+ (\s(?P<min>\d+)/(?P<avg>\d+)/(?P<max>\d+))?
+ (\s+\w+\s*$|.*\s*$)?
+ ''', re.VERBOSE,
+ ),
+ "setval": "ping"
+ "{{ (' vrf ' + vrf) if vrf is defined else '' }}"
+ "{{ (' ' + afi|string ) if afi is defined else '' }}"
+ "{{ (' ' + dest ) if dest is defined else '' }}"
+ "{{ (' repeat ' + count|string ) if count is defined else '' }}"
+ "{{ (' df-bit' ) if df_bit|d(False) else '' }}"
+ "{{ (' timeout ' + timeout|string) if timeout is defined else '' }}"
+ "{{ (' ingress ' + ingress) if ingress is defined else '' }}"
+ "{{ (' egress ' + egress) if egress is defined else '' }}"
+ "{{ (' source ' + source) if source is defined else '' }}",
+ 'result': {
+ "ping": {
+ 'loss_percentage': '{{ 100 - pct|int }}%',
+ 'loss': '{{ 100 - pct|int }}',
+ 'rx': '{{ rx|int }}',
+ 'tx': '{{ tx|int }}',
+ 'rtt': {
+ 'min': '{{ min }}',
+ 'avg': '{{ avg }}',
+ 'max': '{{ max }}',
+ },
+ },
+ },
+ },
+ ]
+ # fmt: on
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
new file mode 100644
index 000000000..041d926f5
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/prefix_lists.py
@@ -0,0 +1,87 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 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 Prefix_lists 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,
+)
+
+
+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",
+ "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+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_set_prefix_lists,
+ "result": {
+ "{{ afi + '_' + name }}": {
+ "afi": "{{ 'ipv4' if afi is defined and afi=='ip' else 'ipv6' }}",
+ "prefix_lists": [
+ {
+ "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 }}",
+ },
+ },
+ ],
+ },
+ },
+ "shared": True,
+ },
+ ]
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
new file mode 100644
index 000000000..47b4402b6
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/route_maps.py
@@ -0,0 +1,1273 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 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 Route_maps 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.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import (
+ NetworkTemplate,
+)
+
+
+def _tmplt_route_map_match(config_data):
+ if (
+ config_data.get("match")
+ and not config_data["match"].get("ip")
+ and not config_data["match"].get("ipv6")
+ ):
+ command = []
+ match = config_data["match"]
+ if match and match.get("additional_paths"):
+ cmd = "match additional-paths advertise-set"
+ if config_data["match"]["additional_paths"].get("all"):
+ cmd += " all"
+ if config_data["match"]["additional_paths"].get("best"):
+ cmd += " best {best}".format(**config_data["match"]["additional_paths"])
+ if config_data["match"]["additional_paths"].get("best_range"):
+ 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"]
+ )
+ if config_data["match"]["additional_paths"]["best_range"].get("upper_limit"):
+ cmd += " upper-limit {upper_limit}".format(
+ **config_data["match"]["additional_paths"]["best_range"]
+ )
+ if config_data["match"]["additional_paths"].get("group_best"):
+ cmd += " group-best"
+ command.append(cmd)
+ if match.get("as_path"):
+ cmd = "match as-path "
+ if match["as_path"].get("acls"):
+ temp = []
+ for k, v in iteritems(match["as_path"]["acls"]):
+ temp.append(str(v))
+ cmd += " ".join(sorted(temp))
+ command.append(cmd)
+ if match.get("clns"):
+ cmd = "match clns"
+ if match["clns"].get("address"):
+ cmd += " address {address}".format(**match["clns"])
+ elif match["clns"].get("next_hop"):
+ cmd = " next-hop {next_hop}".format(**match["clns"])
+ elif match["clns"].get("route_source"):
+ cmd = " route-source {route_source}".format(**match["clns"])
+ command.append(cmd)
+ if match.get("community"):
+ cmd = "match community "
+ temp = []
+ for k, v in iteritems(match["community"]["name"]):
+ temp.append(v)
+ cmd += " ".join(sorted(temp))
+ if match["community"].get("exact_match"):
+ cmd += " exact-match"
+ command.append(cmd)
+ if match.get("extcommunity"):
+ cmd = "match extcommunity "
+ temp = []
+ for k, v in iteritems(match["extcommunity"]):
+ temp.append(v)
+ cmd += " ".join(sorted(temp))
+ command.append(cmd)
+ if match.get("interfaces"):
+ cmd = "match interface "
+ temp = []
+ for k, v in iteritems(match["interfaces"]):
+ temp.append(v)
+ cmd += " ".join(sorted(temp))
+ command.append(cmd)
+ if match.get("length"):
+ command.append("match length {minimum} {maximum}".format(**match["length"]))
+ if match.get("local_preference"):
+ cmd = "match local-preference "
+ if match["local_preference"].get("value"):
+ temp = []
+ for k, v in iteritems(match["local_preference"]["value"]):
+ temp.append(v)
+ cmd += " ".join(sorted(temp))
+ command.append(cmd)
+ if match.get("mdt_group"):
+ cmd = "match mdt-group "
+ if match["mdt_group"].get("acls"):
+ temp = []
+ for k, v in iteritems(match["mdt_group"]["acls"]):
+ temp.append(v)
+ cmd += " ".join(sorted(temp))
+ command.append(cmd)
+ if match.get("metric"):
+ cmd = "match metric"
+ if match["metric"].get("external"):
+ cmd += " external"
+ if match["metric"].get("value"):
+ cmd += " {value}".format(**match["metric"])
+ if match["metric"].get("deviation"):
+ cmd += " +-"
+ if match["metric"].get("deviation_value"):
+ cmd += " {deviation_value}".format(**match["metric"])
+ command.append(cmd)
+ if match.get("mpls_label"):
+ command.append("match mpls-label")
+ if match.get("policy_lists"):
+ cmd = "match policy-list "
+ temp = []
+ for k, v in iteritems(match["policy_lists"]):
+ temp.append(v)
+ cmd += " ".join(sorted(temp))
+ command.append(cmd)
+ if match.get("route_type"):
+ cmd = "match route-type"
+ if match["route_type"].get("external"):
+ cmd += " external"
+ if match["route_type"]["external"].get("type_1"):
+ cmd += " type-1"
+ elif match["route_type"]["external"].get("type_2"):
+ cmd += " type-2"
+ elif match["route_type"].get("internal"):
+ cmd += " internal"
+ elif match["route_type"].get("level_1"):
+ cmd += " level-1"
+ elif match["route_type"].get("level_2"):
+ cmd += " level-2"
+ elif match["route_type"].get("local"):
+ cmd += " local"
+ elif match["route_type"].get("nssa_external"):
+ cmd += " nssa-external"
+ if match["route_type"]["nssa_external"].get("type_1"):
+ cmd += " type-1"
+ elif match["route_type"]["nssa_external"].get("type_2"):
+ cmd += " type-2"
+ command.append(cmd)
+ if match.get("rpki"):
+ cmd = "match rpki"
+ if match["rpki"].get("invalid"):
+ cmd += " invalid"
+ if match["rpki"].get("not_found"):
+ cmd += " not-found"
+ if match["rpki"].get("valid"):
+ cmd += " valid"
+ command.append(cmd)
+ if match.get("security_group"):
+ cmd = "match security-group"
+ if match["security_group"].get("source"):
+ cmd += " source tag "
+ temp = []
+ for k, v in iteritems(match["security_group"]["source"]):
+ temp.append(str(v))
+ cmd += " ".join(sorted(temp))
+ elif match["security_group"].get("destination"):
+ cmd += " destination tag"
+ for each in match["destination"]:
+ cmd += " {0}".format(each)
+ command.append(cmd)
+ if match.get("source_protocol"):
+ cmd = "match source-protocol"
+ if match["source_protocol"].get("bgp"):
+ cmd += " bgp {bgp}".format(**match["source_protocol"])
+ if match["source_protocol"].get("connected"):
+ cmd += " connected"
+ if match["source_protocol"].get("eigrp"):
+ cmd += " eigrp {eigrp}".format(**match["source_protocol"])
+ if match["source_protocol"].get("isis"):
+ cmd += " isis"
+ if match["source_protocol"].get("lisp"):
+ cmd += " lisp"
+ if match["source_protocol"].get("mobile"):
+ cmd += " mobile"
+ if match["source_protocol"].get("ospf"):
+ cmd += " ospf {ospf}".format(**match["source_protocol"])
+ if match["source_protocol"].get("ospfv3"):
+ cmd += " ospfv3 {ospfv3}".format(**match["source_protocol"])
+ if match["source_protocol"].get("rip"):
+ cmd += " rip"
+ if match["source_protocol"].get("static"):
+ cmd += " static"
+ command.append(cmd)
+ if match.get("tag"):
+ cmd = "match tag"
+ if match["tag"].get("tag_list"):
+ cmd += " list"
+ for each in match["tag"]["tag_list"]:
+ cmd += " {0}".format(each)
+ elif match["tag"].get("value"):
+ for each in match["tag"]["value"]:
+ cmd += " {0}".format(each)
+ command.append(cmd)
+ if match.get("track"):
+ command.append("match track {track}".format(**match))
+ return command
+
+
+def _tmplt_route_map_match_ip(config_data):
+ if config_data.get("match") and config_data["match"].get("ip"):
+
+ def construct_cmd_from_list(cmd, config):
+ temp = []
+ for k, v in iteritems(config):
+ temp.append(v)
+ cmd += " " + " ".join(sorted(temp))
+ return cmd
+
+ cmd = "match ip"
+ if config_data["match"]["ip"].get("address"):
+ cmd += " address"
+ if config_data["match"]["ip"]["address"].get("prefix_lists"):
+ cmd += " prefix-list"
+ cmd = construct_cmd_from_list(
+ cmd,
+ config_data["match"]["ip"]["address"]["prefix_lists"],
+ )
+ elif config_data["match"]["ip"]["address"].get("acls"):
+ cmd = construct_cmd_from_list(cmd, config_data["match"]["ip"]["address"]["acls"])
+ if config_data["match"]["ip"].get("flowspec"):
+ cmd += " flowspec"
+ if config_data["match"]["ip"]["flowspec"].get("dest_pfx"):
+ cmd += " dest-pfx"
+ elif config_data["match"]["ip"]["flowspec"].get("src_pfx"):
+ cmd += " src-pfx"
+ if config_data["match"]["ip"]["flowspec"].get("prefix_lists"):
+ cmd += " prefix-list"
+ cmd = construct_cmd_from_list(
+ cmd,
+ config_data["match"]["ip"]["flowspec"]["prefix_lists"],
+ )
+ elif config_data["match"]["ip"]["flowspec"].get("acls"):
+ cmd = construct_cmd_from_list(cmd, config_data["match"]["ip"]["flowspec"]["acls"])
+ if config_data["match"]["ip"].get("next_hop"):
+ cmd += " next-hop"
+ if config_data["match"]["ip"]["next_hop"].get("prefix_lists"):
+ cmd += " prefix-list"
+ cmd = construct_cmd_from_list(
+ cmd,
+ config_data["match"]["ip"]["next_hop"]["prefix_lists"],
+ )
+ elif config_data["match"]["ip"]["next_hop"].get("acls"):
+ cmd = construct_cmd_from_list(cmd, config_data["match"]["ip"]["next_hop"]["acls"])
+ if config_data["match"]["ip"].get("redistribution_source"):
+ cmd += " redistribution-source"
+ if config_data["match"]["ip"]["redistribution_source"].get("prefix_lists"):
+ cmd += " prefix-list"
+ cmd = construct_cmd_from_list(
+ cmd,
+ config_data["match"]["ip"]["redistribution_source"]["prefix_lists"],
+ )
+ elif config_data["match"]["ip"]["redistribution_source"].get("acls"):
+ cmd = construct_cmd_from_list(
+ cmd,
+ config_data["match"]["ip"]["redistribution_source"]["acls"],
+ )
+ if config_data["match"]["ip"].get("route_source"):
+ cmd += " route-source"
+ if config_data["match"]["ip"]["route_source"].get("redistribution_source"):
+ cmd += " redistribution-source"
+ if config_data["match"]["ip"]["route_source"].get("prefix_lists"):
+ cmd += " prefix-list"
+ cmd = construct_cmd_from_list(
+ cmd,
+ config_data["match"]["ip"]["route_source"]["prefix_lists"],
+ )
+ elif config_data["match"]["ip"]["route_source"].get("acls"):
+ cmd = construct_cmd_from_list(
+ cmd,
+ config_data["match"]["ip"]["route_source"]["acls"],
+ )
+ return cmd
+
+
+def _tmplt_route_map_match_ipv6(config_data):
+ if config_data.get("match") and config_data["match"].get("ipv6"):
+ cmd = "match ipv6"
+ if config_data["match"]["ipv6"].get("address"):
+ cmd += " address"
+ if config_data["match"]["ipv6"]["address"].get("prefix_list"):
+ cmd += " prefix-list {prefix_list}".format(
+ **config_data["match"]["ipv6"]["address"]
+ )
+ elif config_data["match"]["ipv6"]["address"].get("acl"):
+ cmd += " {acl}".format(**config_data["match"]["ipv6"]["address"])
+ if config_data["match"]["ipv6"].get("flowspec"):
+ cmd += " flowspec"
+ if config_data["match"]["ipv6"]["flowspec"].get("dest_pfx"):
+ cmd += " dest-pfx"
+ elif config_data["match"]["ipv6"]["flowspec"].get("src_pfx"):
+ cmd += " src-pfx"
+ if config_data["match"]["ipv6"]["flowspec"].get("prefix_list"):
+ cmd += " prefix-list {prefix_list}".format(
+ **config_data["match"]["ipv6"]["flowspec"]
+ )
+ elif config_data["match"]["ipv6"]["flowspec"].get("acl"):
+ cmd += " {acl}".format(**config_data["match"]["ipv6"]["flowspec"])
+ if config_data["match"]["ipv6"].get("next_hop"):
+ 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"]
+ )
+ elif config_data["match"]["ipv6"]["next_hop"].get("acl"):
+ cmd += " {acl}".format(**config_data["match"]["ipv6"]["next_hop"])
+ if config_data["match"]["ipv6"].get("route_source"):
+ 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"]
+ )
+ elif config_data["match"]["ipv6"]["route_source"].get("acl"):
+ cmd += " {acl}".format(**config_data["match"]["ipv6"]["route_source"])
+ return cmd
+
+
+def _tmplt_route_map_set(config_data):
+ if config_data.get("set"):
+ command = []
+ set = config_data["set"]
+ if set.get("aigp_metric"):
+ cmd = "set aigp-metric"
+ if set["aigp_metric"].get("value"):
+ cmd += " {value}".format(**set["aigp_metric"])
+ elif set["aigp_metric"].get("igp_metric"):
+ cmd += " igp-metric"
+ command.append(cmd)
+ if set.get("as_path"):
+ cmd = "set as-path"
+ if set["as_path"].get("prepend"):
+ cmd += " prepend"
+ if set["as_path"]["prepend"].get("as_number"):
+ cmd += " {0}".format(set["as_path"]["prepend"].get("as_number"))
+ elif set["as_path"]["prepend"].get("last_as"):
+ cmd += " last-as {last_as}".format(**set["as_path"]["prepend"])
+ if set["as_path"].get("tag"):
+ cmd += " tag"
+ command.append(cmd)
+ if set.get("automatic_tag"):
+ command.append("set automatic-tag")
+ if set.get("clns"):
+ command.append("set clns next-hop {clns}".format(**set))
+ if set.get("comm_list"):
+ command.append("set comm-list {comm_list} delete".format(**set))
+ if set.get("community"):
+ cmd = "set community"
+ if set["community"].get("number"):
+ cmd += " " + " ".join(i for i in set["community"]["number"])
+ if set["community"].get("gshut"):
+ cmd += " gshut"
+ if set["community"].get("internet"):
+ cmd += " internet"
+ if set["community"].get("local_as"):
+ cmd += " local-as"
+ if set["community"].get("no_advertise"):
+ cmd += " no-advertise"
+ if set["community"].get("no_export"):
+ cmd += " no-export"
+ if set["community"].get("none"):
+ cmd += " none"
+ # additive must be set last last
+ if set["community"].get("additive"):
+ cmd += " additive"
+ command.append(cmd)
+ if set.get("dampening"):
+ command.append(
+ "set dampening {penalty_half_time} {reuse_route_val} {suppress_route_val} {max_suppress}".format(
+ **set["dampening"]
+ ),
+ )
+ if set.get("default"):
+ command.append("set default interface {default}".format(**set["default"]))
+ if set.get("extcomm_list"):
+ command.append("set extcomm-list {extcomm_list} delete".format(**set))
+ if set.get("extcommunity"):
+ if set["extcommunity"].get("cost"):
+ cmd = "set extcommunity cost"
+ if set["extcommunity"]["cost"].get("igp"):
+ cmd += " igp"
+ elif set["extcommunity"]["cost"].get("pre_bestpath"):
+ cmd += " pre-bestpath"
+ if set["extcommunity"]["cost"].get("id"):
+ cmd += " {id}".format(**set["extcommunity"]["cost"])
+ if set["extcommunity"]["cost"].get("cost_value"):
+ cmd += " {cost_value}".format(**set["extcommunity"]["cost"])
+ command.append(cmd)
+ if set["extcommunity"].get("rt"):
+ cmd = "set extcommunity rt"
+ if set["extcommunity"]["rt"].get("range"):
+ cmd += " range {lower_limit} {upper_limit}".format(
+ **set["extcommunity"]["rt"]["range"]
+ )
+ elif set["extcommunity"]["rt"].get("address"):
+ cmd += " {address}".format(**set["extcommunity"]["rt"])
+ if set["extcommunity"]["rt"].get("additive"):
+ cmd += " additive"
+ command.append(cmd)
+ if set["extcommunity"].get("soo"):
+ command.append("set extcommunity soo {soo}".format(**set["extcommunity"]))
+ if set["extcommunity"].get("vpn_distinguisher"):
+ cmd = "set extcommunity vpn-distinguisher"
+ if set["extcommunity"]["vpn_distinguisher"].get("range"):
+ cmd += " range {lower_limit} {upper_limit}".format(
+ **set["extcommunity"]["vpn_distinguisher"]["range"]
+ )
+ elif set["extcommunity"]["vpn_distinguisher"].get("address"):
+ cmd += " {address}".format(**set["extcommunity"]["vpn_distinguisher"])
+ if set["extcommunity"]["vpn_distinguisher"].get("additive"):
+ cmd += " additive"
+ command.append(cmd)
+ if set.get("global"):
+ command.append("set global")
+ if set.get("interfaces"):
+ cmd = "set interface "
+ temp = []
+ for k, v in iteritems(set["interfaces"]):
+ temp.append(v)
+ cmd += " ".join(sorted(temp))
+ command.append(cmd)
+ if set.get("level"):
+ cmd = "set level"
+ if set["level"].get("level_1"):
+ cmd += " level-1"
+ elif set["level"].get("level_1_2"):
+ cmd += " level-1-2"
+ elif set["level"].get("level_2"):
+ cmd += " level-2"
+ elif set["level"].get("nssa_only"):
+ cmd += " nssa-only"
+ if set.get("lisp"):
+ command.append("set lisp locator-set {lisp}".format(**set))
+ if set.get("local_preference"):
+ command.append("set local-preference {local_preference}".format(**set))
+ if set.get("metric"):
+ cmd = "set metric"
+ if set["metric"].get("metric_value"):
+ cmd += " {metric_value}".format(**set["metric"])
+ if set["metric"].get("deviation"):
+ if set["metric"]["deviation"] == "plus":
+ cmd += (
+ " +{eigrp_delay} {metric_reliability} {metric_bandwidth} {mtu}".format(
+ **set["metric"]
+ )
+ )
+ elif set["metric"]["deviation"] == "minus":
+ cmd += (
+ " -{eigrp_delay} {metric_reliability} {metric_bandwidth} {mtu}".format(
+ **set["metric"]
+ )
+ )
+ if set["metric"].get("deviation") and not set["metric"].get("eigrp_delay"):
+ if set["metric"]["deviation"] == "plus":
+ cmd = "set metric +{metric_value}".format(**set["metric"])
+ elif set["metric"]["deviation"] == "minus":
+ cmd = "set metric -{metric_value}".format(**set["metric"])
+ command.append(cmd)
+ if set.get("metric_type"):
+ cmd = "set metric-type"
+ if set["metric_type"].get("external"):
+ cmd += " external"
+ elif set["metric_type"].get("internal"):
+ cmd += " internal"
+ elif set["metric_type"].get("type_1"):
+ cmd += " type-1"
+ elif set["metric_type"].get("type_2"):
+ cmd += " type-2"
+ command.append(cmd)
+ if set.get("mpls_label"):
+ command.append("set mpls-label")
+ if set.get("origin"):
+ cmd = "set origin"
+ if set["origin"].get("igp"):
+ cmd += " igp"
+ elif set["origin"].get("incomplete"):
+ cmd += " incomplete"
+ if set.get("tag"):
+ command.append("set tag {tag}".format(**set))
+ if set.get("traffic_index"):
+ command.append("set traffic-index {traffic_index}".format(**set))
+ if set.get("vrf"):
+ command.append("set vrf {vrf}".format(**set))
+ if set.get("weight"):
+ command.append("set weight {weight}".format(**set))
+ return command
+
+
+def _tmplt_route_map_set_ip(config_data):
+ if config_data.get("set") and config_data["set"].get("ip"):
+ command = []
+ set_ip = config_data["set"]["ip"]
+ cmd = "set ip"
+ if set_ip.get("address"):
+ command.append("{0} address prefix-list {address}".format(cmd, **set_ip))
+ if set_ip.get("df"):
+ command.append("{0} df {df}".format(cmd, **set_ip))
+ if set_ip.get("global_route"):
+ 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"]
+ )
+ elif set_ip["global_route"].get("address"):
+ cmd += " {address}".format(**set_ip["global_route"])
+ command.append(cmd)
+ if set_ip.get("next_hop"):
+ cmd += " next-hop"
+ if set_ip["next_hop"].get("address"):
+ command.append("{0} {address}".format(cmd, **set_ip["next_hop"]))
+ if set_ip["next_hop"].get("dynamic"):
+ command.append("{0} dynamic dhcp".format(cmd))
+ if set_ip["next_hop"].get("encapsulate"):
+ command.append(
+ "{0} encapsulate l3vpn {encapsulate}".format(cmd, **set_ip["next_hop"]),
+ )
+ if set_ip["next_hop"].get("peer_address"):
+ command.append("{0} peer-address".format(cmd))
+ if set_ip["next_hop"].get("recursive"):
+ child_cmd = "{0} recursive".format(cmd)
+ if set_ip["next_hop"]["recursive"].get("global_route"):
+ child_cmd += " global"
+ elif set_ip["next_hop"]["recursive"].get("vrf"):
+ child_cmd += " vrf {vrf}".format(**set_ip["next_hop"]["recursive"])
+ if set_ip["next_hop"]["recursive"].get("address"):
+ child_cmd += " {address}".format(**set_ip["next_hop"]["recursive"])
+ command.append(child_cmd)
+ if set_ip["next_hop"].get("self"):
+ command.append("{0} self".format(cmd))
+ 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"]
+ ),
+ )
+ if set_ip.get("precedence"):
+ cmd += " precedence"
+ if set_ip["precedence"].get("critical"):
+ cmd += " critical"
+ elif set_ip["precedence"].get("flash"):
+ cmd += " flash"
+ elif set_ip["precedence"].get("flash_override"):
+ cmd += " flash-override"
+ elif set_ip["precedence"].get("immediate"):
+ cmd += " immediate"
+ elif set_ip["precedence"].get("internet"):
+ cmd += " internet"
+ elif set_ip["precedence"].get("network"):
+ cmd += " network"
+ elif set_ip["precedence"].get("priority"):
+ cmd += " priority"
+ elif set_ip["precedence"].get("routine"):
+ cmd += " routine"
+ command.append(cmd)
+ if set_ip.get("qos_group"):
+ command.append("{0} qos-group {qos_group}".format(cmd, **set_ip))
+ if set_ip.get("tos"):
+ cmd += " tos"
+ if set_ip["tos"].get("max_reliability"):
+ cmd += " max-reliability"
+ elif set_ip["tos"].get("max_throughput"):
+ cmd += " max-throughput"
+ elif set_ip["tos"].get("min_delay"):
+ cmd += " min-delay"
+ elif set_ip["tos"].get("min_monetary_cost"):
+ cmd += " min-monetary-cost"
+ elif set_ip["tos"].get("normal"):
+ cmd += " normal"
+ command.append(cmd)
+ if set_ip.get("vrf"):
+ 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"]
+ )
+ elif set_ip["vrf"].get("address"):
+ cmd += " {address}".format(**set_ip["vrf"])
+ command.append(cmd)
+ return command
+
+
+def _tmplt_route_map_set_ipv6(config_data):
+ if config_data.get("set") and config_data["set"].get("ipv6"):
+ set_ipv6 = config_data["set"]["ipv6"]
+ cmd = "set ipv6"
+ if set_ipv6.get("address"):
+ cmd += " address prefix-list {address}".format(**set_ipv6)
+ if set_ipv6.get("default"):
+ cmd += " default"
+ if set_ipv6.get("global_route"):
+ 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"]
+ )
+ elif set_ipv6["global_route"].get("address"):
+ cmd += " {address}".format(**set_ipv6["global_route"])
+ if set_ipv6.get("next_hop"):
+ cmd += " next-hop"
+ if set_ipv6["next_hop"].get("address"):
+ cmd += " {address}".format(**set_ipv6["next_hop"])
+ if set_ipv6["next_hop"].get("encapsulate"):
+ cmd += " encapsulate l3vpn {encapsulate}".format(**set_ipv6["next_hop"])
+ if set_ipv6["next_hop"].get("peer_address"):
+ cmd += " peer-address"
+ if set_ipv6.get("precedence"):
+ cmd += " precedence {precedence}".format(**set_ipv6)
+ if set_ipv6.get("vrf"):
+ cmd += (
+ " vrf {vrf} next-hop verify-availability {address} {sequence} track {track}".format(
+ **set_ipv6["vrf"]["verify_availability"]
+ )
+ )
+ return cmd
+
+
+class Route_mapsTemplate(NetworkTemplate):
+ def __init__(self, lines=None):
+ super(Route_mapsTemplate, self).__init__(lines=lines, tmplt=self)
+
+ PARSERS = [
+ {
+ "name": "route_map",
+ "getval": re.compile(
+ r"""
+ ^route-map*
+ \s*(?P<route_map>\S+)*
+ \s*(?P<action>deny|permit)*
+ \s*(?P<sequence>\d+)*
+ (\s|$)""",
+ re.VERBOSE,
+ ),
+ "setval": "",
+ "result": {
+ "{{ route_map }}": {
+ "route_map": "{{ route_map }}",
+ "{{ action|d() + '_' + sequence|d() }}": {
+ "entries": {"action": "{{ action }}", "sequence": "{{ sequence }}"},
+ },
+ },
+ },
+ "shared": True,
+ },
+ {
+ "name": "continue_entry",
+ "getval": re.compile(
+ r"""
+ \s+continue*
+ \s*(?P<entry_sequence>\d+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "continue {{ continue_entry.entry_sequence }}",
+ "result": {
+ "{{ route_map }}": {
+ "{{ action|d() + '_' + sequence|d() }}": {
+ "entries": {
+ "continue_entry": {
+ "set": "{{ True if entry_sequence is not defined }}",
+ "entry_sequence": "{{ entry_sequence }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "description",
+ "getval": re.compile(
+ r"""
+ \s+description*
+ \s*(?P<description>\S.*)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "description {{ description }}",
+ "result": {
+ "{{ route_map }}": {
+ "{{ action|d() + '_' + sequence|d() }}": {
+ "entries": {"description": "{{ description }}"},
+ },
+ },
+ },
+ },
+ {
+ "name": "match",
+ "getval": re.compile(
+ r"""
+ \s+match*
+ \s*(?P<additional_paths>additional-paths\sadvertise-set\s\S.*)*
+ \s*(?P<as_path>as-path.*|as-path)*
+ \s*(?P<clns>clns\s(address\s\S+|next-hop\s\S+|route-source\s\S+))*
+ \s*(?P<community>community\s\S.*)*
+ \s*(?P<extcommunity>extcommunity\s\S.*)*
+ \s*(?P<interfaces>interface\s\S.*)*
+ \s*(?P<length>length\s\d+\s\d+)*
+ \s*(?P<local_preference>local-preference\s\d.*|local-preference)*
+ \s*(?P<mdt_group>mdt-group\s\S.*|mdt-group)*
+ \s*(?P<metric>metric\sexternal\s\S.*|metric\s\d+\S.*)*
+ \s*(?P<mpls_label>mpls-label)*
+ \s*(?P<policy_list>policy-list\s\S.*)*
+ \s*(?P<route_type>route-type\s(external\s(type-1|type-2)|internal|level-1|level-2|local|nssa-external\s(type-1|type-2)))*
+ \s*(?P<rpki>rpki\s(invalid|not-found|valid))*
+ \s*(?P<security_group>security-group\s(destination\stag\s\d.*|source\stag\s\d.*))*
+ \s*(?P<source_protocol>source-protocol\s\S.*)*
+ \s*(?P<tag>tag\slist\s\S.*|tag\s\S.*)*
+ \s*(?P<track>track\s*\d+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_route_map_match,
+ "result": {
+ "{{ route_map }}": {
+ "{{ action|d() + '_' + sequence|d() }}": {
+ "entries": {
+ "match": {
+ "additional_paths": {
+ "all": "{{ True if additional_paths is defined and 'all' in additional_paths }}",
+ "best": "{{ additional_paths.split('best ')[1].split(' ')[0]|int if additional_paths is defined and\
+ 'best' in additional_paths and 'best-range' not in additional_paths }}",
+ "best_range": {
+ "lower_limit": "{{ additional_paths.split('best-range ')[1].split(' ')[0]|int if additional_paths is defined and\
+ 'best-range' in additional_paths }}",
+ "upper_limit": "{{ additional_paths.split('best-range ')[1].split(' ')[1]|int if additional_paths is defined and\
+ 'best-range' in additional_paths }}",
+ },
+ "group_best": "{{ True if additional_paths is defined and 'group-best' in additional_paths }}",
+ },
+ "as_path": {
+ "set": "{{ True if as_path is defined and as_path.split(' ')|length == 1 }}",
+ "acls": "{{ as_path.split('as-path ')[1].split(' ') if as_path is defined and as_path.split(' ')|length > 1 }}",
+ },
+ "clns": {
+ "address": "{{ clns.split('clns address ')[1] if clns is defined }}",
+ "next_hop": "{{ clns.split('clns next-hop ')[1] if clns is defined }}",
+ "route_source": "{{ clns.split('clns route-source ')[1] if clns is defined }}",
+ },
+ "community": {
+ "name": "{{ community.split('community ')[1].split(' exact-match')[0].split(' ') if community is defined }}",
+ "exact_match": "{{ True if community is defined and 'exact-match' in community }}",
+ },
+ "extcommunity": "{{ extcommunity.split('extcommunity ')[1].split(' ') if extcommunity is defined }}",
+ "interfaces": "{{ interfaces.split('interface ')[1].split(' ') if interfaces is defined }}",
+ "length": {
+ "minimum": "{{ length.split(' ')[1] if length is defined }}",
+ "maximum": "{{ length.split(' ')[2] if length is defined }}",
+ },
+ "local_preference": {
+ "set": "{{ True if local_preference is defined and local_preference.split(' ')|length == 1 }}",
+ "value": "{{ local_preference.split('local-preference ')[1].split(' ') if local_preference is defined }}",
+ },
+ "mdt_group": {
+ "set": "{{ True if mdt_group is defined and mdt_group.split(' ')|length == 1 }}",
+ "acls": "{{ mdt_group.split('mdt-group ')[1].split(' ') if mdt_group is defined }}",
+ },
+ "metric": {
+ "external": "{{ True if metric is defined and 'external' in metric.split(' ') }}",
+ "value": "{% if metric is defined and 'external' not in metric.split(' ') %}{{ metric.split(' ')[1] }}\
+ {% elif metric is defined and 'external' in metric.split(' ') %}{{ metric.split(' ')[2] }}\
+ {% endif %}",
+ "deviation": "{{ True if metric is defined and '+-' in metric }}",
+ "deviation_value": "{% if metric is defined and 'external' in metric and '+-' in metric %}{{ metric.split(' ')[4] }}\
+ {% elif metric is defined and 'external' not in metric and '+-' in metric %}{{ metric.split(' ')[3] }}{% endif %}",
+ },
+ "mpls_label": "{{ True if mpls_label is defined }}",
+ "policy_lists": "{{ policy_list.split('policy-list ')[1].split(' ') if policy_list is defined }}",
+ "route_type": {
+ "external": {
+ "set": "{{ True if route_type is defined and 'type-1' not in route_type and 'type-2' not in route_type}}",
+ "type_1": "{{ True if route_type is defined and 'type-1' in route_type }}",
+ "type_2": "{{ True if route_type is defined and 'type-2' in route_type }}",
+ },
+ "internal": "{{ True if route_type is defined and 'internal' in route_type }}",
+ "level_1": "{{ True if route_type is defined and 'level-1' in route_type }}",
+ "level_2": "{{ True if route_type is defined and 'level-2' in route_type }}",
+ "local": "{{ True if route_type is defined and 'local' in route_type }}",
+ "nssa_external": {
+ "set": "{{ True if route_type is defined and 'type-1' not in route_type and 'type-2' not in route_type}}",
+ "type_1": "{{ True if route_type is defined and 'type-1' in route_type }}",
+ "type_2": "{{ True if route_type is defined and 'type-2' in route_type }}",
+ },
+ },
+ "rpki": {
+ "invalid": "{{ True if rpki is defined and 'invalid' in rpki and 'valid' not in rpki.split(' ') }}",
+ "not_found": "{{ True if rpki is defined and 'not-found' in rpki }}",
+ "valid": "{{ True if rpki is defined and 'valid' in rpki and 'invalid' not in rpki.split(' ') }}",
+ },
+ "security_group": {
+ "destination": "{{ security_group.split('destination tag ')[1].split(' ') if security_group is defined and\
+ 'destination' in security_group }}",
+ "source": "{{ security_group.split('source tag ')[1].split(' ') if security_group is defined and\
+ 'source' in security_group }}",
+ },
+ "source_protocol": {
+ "bgp": "{{ source_protocol.split('bgp ')[1].split(' ')[0] if source_protocol is defined and 'bgp' in source_protocol }}",
+ "connected": "{{ True if source_protocol is defined and 'connected' in source_protocol }}",
+ "eigrp": "{{ source_protocol.split('eigrp ')[1].split(' ')[0] if source_protocol is defined and\
+ 'eigrp' in source_protocol }}",
+ "isis": "{{ True if source_protocol is defined and 'isis' in source_protocol }}",
+ "lisp": "{{ True if source_protocol is defined and 'lisp' in source_protocol }}",
+ "mobile": "{{ True if source_protocol is defined and 'mobile' in source_protocol }}",
+ "ospf": "{{ source_protocol.split('ospf ')[1].split(' ')[0] if source_protocol is defined and\
+ 'ospf' in source_protocol }}",
+ "ospfv3": "{{ source_protocol.split('ospfv3 ')[1].split(' ')[0] if source_protocol is defined and\
+ 'ospfv3' in source_protocol }}",
+ "rip": "{{ True if source_protocol is defined and 'rip' in source_protocol }}",
+ "static": "{{ True if source_protocol is defined and 'static' in source_protocol }}",
+ },
+ "tag": {
+ "value": "{{ tag.split('tag ')[1].split(' ') if tag is defined and 'list' not in tag }}",
+ "tag_list": "{{ tag.split('tag list ')[1].split(' ') if tag is defined and 'list' in tag }}",
+ },
+ "track": "{{ track.split('track ')[1] if track is defined }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "match.ip",
+ "getval": re.compile(
+ r"""
+ \s+match*
+ \s*(?P<ip>ip)*
+ \s*(?P<address>address\sprefix-list\s\S.*|address\s\S.*)*
+ \s*(?P<flowspec>flowspec\sdest-pfx\s(prefix-list\s\S.*|\S.*)|flowspec\ssrc-pfx\s(prefix-list\s\S.*|\S.*))*
+ \s*(?P<next_hop>next-hop\sprefix-list\s\S.*|next-hop\s\S.*|next-hop)*
+ \s*(?P<redistribution_source>redistribution-source\sprefix-list\s\S.*|redistribution-source\s\S.*|redistribution-source)*
+ \s*(?P<route_source>route-source\sredistribution-source\sprefix-list\s\S.*|route-source\sredistribution-source\s\S.*|route-source\sprefix-list\s\S.*|route-source\s\S.*|route-source\sredistribution-source|route-source)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_route_map_match_ip,
+ "compval": "match",
+ "result": {
+ "{{ route_map }}": {
+ "{{ action|d() + '_' + sequence|d() }}": {
+ "entries": {
+ "match": {
+ "ip": {
+ "address": {
+ "acls": "{{ address.split('address ')[1].split(' ') if address is defined and\
+ 'prefix-list' not in address else none }}",
+ "prefix_lists": "{{ address.split('address prefix-list ')[1].split(' ') if address is defined and\
+ 'prefix-list' in address else None }}",
+ },
+ "flowspec": {
+ "dest_pfx": "{{ True if flowspec is defined and 'dest-pfx' in flowspec }}",
+ "src_pfx": "{{ True if flowspec is defined and 'src-pfx' in flowspec }}",
+ "acls": "{{ flowspec.split('flowspec ')[1].split(' ')|d() if flowspec is defined and\
+ 'prefix-list' not in flowspec else '' }}",
+ "prefix_lists": "{{ flowspec.split('flowspec prefix-list ')[1].split(' ')|d() if flowspec is defined and\
+ 'prefix-list' in flowspec else ''}}",
+ },
+ "next_hop": {
+ "set": "{{ True if next_hop is defined and next_hop.split(' ')|length == 1 }}",
+ "acls": "{{ next_hop.split('next-hop ')[1].split(' ') if next_hop is defined and\
+ 'prefix-list' not in next_hop else '' }}",
+ "prefix_lists": "{{ next_hop.split('next-hop prefix-list ')[1].split(' ') if next_hop is defined and\
+ 'prefix-list' in next_hop and next_hop.split('next-hop prefix-list ')[1] is not none else '' }}",
+ },
+ "redistribution_source": {
+ "set": "{{ True if redistribution_source is defined and redistribution_source.split(' ')|length == 1 }}",
+ "acls": "{{ redistribution_source.split('redistribution-source ')[1].split(' ')|d()\
+ if redistribution_source is defined and 'prefix-list' not in redistribution_source else '' }}",
+ "prefix_lists": "{{ redistribution_source.split('redistribution-source prefix-list ')[1].split(' ')|d()\
+ if redistribution_source is defined and 'prefix-list' in redistribution_source else '' }}",
+ },
+ "route_source": {
+ "set": "{{ True if route_source is defined and route_source.split(' ')|length == 1 }}",
+ "redistribution_source": "{{ True if route_source is defined and 'redistribution-source' in route_source }}",
+ "acls": "{{ route_source.split('route-source ')[1].split(' ') if route_source is defined and\
+ 'prefix-list' not in route_source else '' }}",
+ "prefix_lists": "{{ route_source.split('route-source prefix-list ')[1].split(' ') if route_source is defined and\
+ 'prefix-list' in route_source else '' }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "match.ipv6",
+ "getval": re.compile(
+ r"""
+ \s+match*
+ \s*(?P<ipv6>ipv6)*
+ \s*(?P<address>address\sprefix-list\s\S.*|address\s\S.*)*
+ \s*(?P<flowspec>flowspec\sdest-pfx\s(prefix-list\s\S.*|\S.*)|flowspec\ssrc-pfx\s(prefix-list\s\S.*|\S.*))*
+ \s*(?P<next_hop>next-hop\sprefix-list\s\S.*|next-hop\s\S.*)*
+ \s*(?P<route_source>route-source\sprefix-list\s\S.*|route-source\s\S.*)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_route_map_match_ipv6,
+ "compval": "match",
+ "result": {
+ "{{ route_map }}": {
+ "{{ action|d() + '_' + sequence|d() }}": {
+ "entries": {
+ "match": {
+ "ipv6": {
+ "address": {
+ "acl": "{{ address.split('address ')[1] if address is defined and 'prefix-list' not in address }}",
+ "prefix_list": "{{ address.split('address prefix-list ')[1] if address is defined and 'prefix-list' in address }}",
+ },
+ "flowspec": {
+ "dest_pfx": "{{ True if flowspec is defined and 'dest-pfx' in flowspec }}",
+ "src_pfx": "{{ True if flowspec is defined and 'src-pfx' in flowspec }}",
+ "acl": "{{ flowspec.split('flowspec ')[1] if flowspec is defined and 'prefix-list' not in flowspec }}",
+ "prefix_list": "{{ flowspec.split('flowspec prefix-list ')[1] if flowspec is defined and 'prefix-list' in flowspec }}",
+ },
+ "next_hop": {
+ "acl": "{{ next_hop.split('next-hop ')[1] if next_hop is defined and 'prefix-list' not in next_hop }}",
+ "prefix_list": "{{ next_hop.split('next-hop prefix-list ')[1] if next_hop is defined and 'prefix-list' in next_hop }}",
+ },
+ "route_source": {
+ "acl": "{{ route_source.split('route-source ')[1] if route_source is defined and 'prefix-list' not in route_source }}",
+ "prefix_list": "{{ route_source.split('route-source prefix-list ')[1] if route_source is defined and\
+ 'prefix-list' in route_source }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "set",
+ "getval": re.compile(
+ r"""
+ \s+set*
+ \s*(?P<aigp_metric>aigp-metric\sigp-metric|aigp-metric\s\d+)*
+ \s*(?P<as_path>as-path\s(prepend\s(last-as\s\d+|\d+(?:\s\d+)*)|tag))*
+ \s*(?P<automatic_tag>automatic-tag)*
+ \s*(?P<clns>clns\snext-hop\s\S.*)*
+ \s*(?P<comm_list>comm-list\s\S+\sdelete)*
+ \s*(?P<community>community\s\S.*)*
+ \s*(?P<dampening>dampening\s\d+\s\d+\s\d+\s\d+)*
+ \s*(?P<default>default\sinterface\s\S.*)*
+ \s*(?P<extcomm_list>extcomm-list\s\S+\sdelete)*
+ \s*(?P<extcommunity>extcommunity\s\S.*)*
+ \s*(?P<global>global)*
+ \s*(?P<interfaces>interface\s\S.*)*
+ \s*(?P<level>level\s(level-1-2|level-1|level-2|nssa-only))*
+ \s*(?P<lisp>lisp\slocator-set\s\S+)*
+ \s*(?P<local_preference>local-preference\s\d+)*
+ \s*(?P<metric>metric\s\S.*)*
+ \s*(?P<metric_type>metric-type\s(external|internal|type-1|type-2))*
+ \s*(?P<mpls_label>mpls-label)*
+ \s*(?P<origin>origin\s(igp|incomplete))*
+ \s*(?P<tag>tag\s(([0-9]{1,3}\.?){4}|\d+))*
+ \s*(?P<traffic_index>traffic-index\s\d+)*
+ \s*(?P<vrf>vrf\s\S+)*
+ \s*(?P<weight>weight\s\d+)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_route_map_set,
+ "result": {
+ "{{ route_map }}": {
+ "{{ action|d() + '_' + sequence|d() }}": {
+ "entries": {
+ "set": {
+ "aigp_metric": {
+ "value": "{{ aigp_metric.split('aigp-metric ')[1] if aigp_metric is defined and\
+ 'igp-metric' not in aigp_metric.split(' ') }}",
+ "igp_metric": "{{ True if aigp_metric is defined and 'igp-metric' in aigp_metric.split(' ') }}",
+ },
+ "as_path": {
+ "prepend": {
+ "as_number": "{{ as_path.split('as-path prepend ')[1].split(' ')\
+ if as_path is defined and 'prepend' in as_path and 'last-as' not in as_path }}",
+ "last_as": "{{ as_path.split('as-path prepend last-as ')[1] if as_path is defined and 'prepend' in as_path and\
+ 'last-as' in as_path }}",
+ },
+ "tag": "{{ True if as_path is defined and 'tag' in as_path }}",
+ },
+ "automatic_tag": "{{ True if automatic_tag is defined }}",
+ "clns": "{{ clns.split('clns next-hop ')[1] if clns is defined }}",
+ "comm_list": "{{ comm_list.split(' ')[1] if comm_list is defined }}",
+ "community": {
+ "number": "{{ community.split(' ')[1:]|reject('in',\
+ ['additive','gshut','internet','local-AS','no-advertise','no-export','none']\
+ )|join(' ')}}",
+ "additive": "{{ True if community is defined and 'additive' in community }}",
+ "gshut": "{{ True if community is defined and 'gshut' in community }}",
+ "internet": "{{ True if community is defined and 'internet' in community }}",
+ "local_as": "{{ True if community is defined and 'local-AS' in community }}",
+ "no_advertise": "{{ True if community is defined and 'no-advertise' in community }}",
+ "no_export": "{{ True if community is defined and 'no-export' in community }}",
+ "none": "{{ True if community is defined and 'none' in community }}",
+ },
+ "dampening": {
+ "penalty_half_time": "{{ dampening.split(' ')[1] if dampening is defined }}",
+ "reuse_route_val": "{{ dampening.split(' ')[2] if dampening is defined }}",
+ "suppress_route_val": "{{ dampening.split(' ')[3] if dampening is defined }}",
+ "max_suppress": "{{ dampening.split(' ')[4] if dampening is defined }}",
+ },
+ "default": "{{ default.split('default interface ')[1] if default is defined }}",
+ "extcomm_list": "{{ extcomm_list.split(' ')[1] if extcomm_list is defined }}",
+ "extcommunity": {
+ "cost": {
+ "id": "{%- if extcommunity is defined and 'cost' in extcommunity and\
+ 'igp' not in extcommunity and 'pre-bestpath' not in extcommunity -%} {{ extcommunity.split(' ')[2] }}\
+ {%- elif extcommunity is defined and 'cost' in extcommunity and ('igp' in extcommunity or\
+ 'pre-bestpath' in extcommunity) -%} {{ extcommunity.split(' ')[3] }} {%- endif -%}",
+ "cost_value": "{% if extcommunity is defined and 'cost' in extcommunity and 'igp' not in extcommunity and\
+ 'pre-bestpath' not in extcommunity %} {{ extcommunity.split(' ')[3] }}\
+ {% elif extcommunity is defined and 'cost' in extcommunity and ('igp' in extcommunity or\
+ 'pre-bestpath' in extcommunity) %} {{ extcommunity.split(' ')[4] }} {% endif %}",
+ "igp": "{{ True if extcommunity is defined and 'cost' in extcommunity and 'igp' in extcommunity }}",
+ "pre_bestpath": "{{ True if extcommunity is defined and 'cost' in extcommunity and 'pre-bestpath' in extcommunity }}",
+ },
+ "rt": {
+ "address": "{{ extcommunity.split(' ')[2] if extcommunity is defined and 'rt' in extcommunity and\
+ 'range' not in extcommunity }}",
+ "range": {
+ "lower_limit": "{{ extcommunity.split('range ')[1].split(' ')[0] if extcommunity is defined and\
+ 'rt' in extcommunity and 'range' in extcommunity }}",
+ "upper_limit": "{{ extcommunity.split('range ')[1].split(' ')[1] if extcommunity is defined and\
+ 'rt' in extcommunity and 'range' in extcommunity }}",
+ },
+ "additive": "{{ True if extcommunity is defined and 'rt' in extcommunity and 'additive' in extcommunity }}",
+ },
+ "soo": "{{ extcommunity.split(' ')[2] if extcommunity is defined and 'soo' in extcommunity }}",
+ "vpn_distinguisher": {
+ "address": "{{ extcommunity.split(' ')[2] if extcommunity is defined and\
+ 'vpn-distinguisher' in extcommunity and 'range' not in extcommunity }}",
+ "range": {
+ "lower_limit": "{{ extcommunity.split('range ')[1].split(' ')[0] if extcommunity is defined and\
+ 'vpn-distinguisher' in extcommunity and 'range' in extcommunity }}",
+ "upper_limit": "{{ extcommunity.split('range ')[1].split(' ')[1] if extcommunity is defined and\
+ 'vpn-distinguisher' in extcommunity and 'range' in extcommunity }}",
+ },
+ "additive": "{{ True if extcommunity is defined and 'vpn-distinguisher' in extcommunity and\
+ 'additive' in extcommunity }}",
+ },
+ },
+ "global_route": "{{ True if global is defined }}",
+ "interfaces": "{{ interfaces.split('interface ')[1].split(' ') if interfaces is defined }}",
+ "level": {
+ "level_1": "{{ True if level is defined and 'level-1' in level and 'level-1-2' not in level }}",
+ "level_1_2": "{{ True if level is defined and 'level-1-2' in level }}",
+ "level_2": "{{ True if level is defined and 'level-2' in level }}",
+ "nssa_only": "{{ True if level is defined and 'nssa-only' in level }}",
+ },
+ "lisp": "{{ lisp.split('lisp locator-set ')[1] if lisp is defined }}",
+ "local_preference": "{{ local_preference.split('local-preference ')[1] if local_preference is defined }}",
+ "metric": {
+ "deviation": "{%- if metric is defined and '+' in metric -%}{{ 'plus' }}\
+ {%- elif metric is defined and '-' in metric -%}{{ 'minus' }}{%- endif -%}",
+ "metric_value": "{{ metric.split(' ')[1] if metric is defined and\
+ (metric.split(' ')[1] != '+' or metric.split(' ')[1] != '-') }}",
+ "eigrp_delay": "{% if metric is defined and metric.split(' ')|length > 2 and '+' in metric %}\
+ {{ metric.split('+')[1].split(' ')[0] }}\
+ {% elif metric is defined and metric.split(' ')|length > 2 and '+' in metric %}\
+ {{ metric.split('-')[1].split(' ')[0] }}\
+ {% endif %}",
+ "metric_reliability": "{% if metric is defined and metric.split(' ')|length > 2 and '+' in metric %}\
+ {{ metric.split('+')[1].split(' ')[1] }}\
+ {% elif metric is defined and metric.split(' ')|length > 2 and '+' in metric %}\
+ {{ metric.split('-')[1].split(' ')[1] }}\
+ {% endif %}",
+ "metric_bandwidth": "{% if metric is defined and metric.split(' ')|length > 2 and '+' in metric %}\
+ {{ metric.split('+')[1].split(' ')[2] }}\
+ {% elif metric is defined and metric.split(' ')|length > 2 and '+' in metric %}\
+ {{ metric.split('-')[1].split(' ')[2] }}\
+ {% endif %}",
+ "mtu": "{% if metric is defined and metric.split(' ')|length > 2 and '+' in metric %}\
+ {{ metric.split('+')[1].split(' ')[3] }}\
+ {% elif metric is defined and metric.split(' ')|length > 2 and '+' in metric %}\
+ {{ metric.split('-')[1].split(' ')[3] }}\
+ {% endif %}",
+ },
+ "metric_type": {
+ "external": "{{ True if metric_type is defined and 'external' in metric_type }}",
+ "internal": "{{ True if metric_type is defined and 'internal' in metric_type }}",
+ "type_1": "{{ True if metric_type is defined and 'type-1' in metric_type }}",
+ "type_2": "{{ True if metric_type is defined and 'type-2' in metric_type }}",
+ },
+ "mpls_label": "{{ True if mpls_label is defined }}",
+ "origin": {
+ "igp": "{{ True if origin is defined and 'igp' in origin }}",
+ "incomplete": "{{ True if origin is defined and 'incomplete' in origin }}",
+ },
+ "tag": "{{ tag.split('tag ')[1] if tag is defined }}",
+ "traffic_index": "{{ traffic_index.split('traffic-index ')[1] if traffic_index is defined }}",
+ "vrf": "{{ vrf.split('vrf ')[1] if vrf is defined }}",
+ "weight": "{{ weight.split('weight ')[1] if weight is defined }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "set.ip",
+ "getval": re.compile(
+ r"""
+ \s+set*
+ \s*(?P<ip>ip)*
+ \s*(?P<address>address\sprefix-list\s\S+)*
+ \s*(?P<default>default)*
+ \s*(?P<df>df\s\d)*
+ \s*(?P<global>global\snext-hop\s(verify-availability\s([0-9]{1,3}\.?){4}\s\d+\strack\s\d+|(([0-9]{1,3}\.?){4}).*))*
+ \s*(?P<precedence>precedence\s(critical|flash|flash-override|immediate|internet|network|priority|routine)|precedence)*
+ \s*(?P<qos_group>qos_group\s\d+)*
+ \s*(?P<tos>tos\s(max-reliability|max-throughput|min-delay|min-monetary-cost|normal)|tos)*
+ \s*(?P<vrf>vrf\s\S+\snext-hop\s\S.*)*
+ \s*(?P<next_hop>next-hop\s\S.*)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_route_map_set_ip,
+ "compval": "set",
+ "result": {
+ "{{ route_map }}": {
+ "{{ action|d() + '_' + sequence|d() }}": {
+ "entries": {
+ "set": {
+ "ip": {
+ "address": "{{ address.split('address prefix-list ')[1] if address is defined }}",
+ "default": "{{ True if default is defined }}",
+ "df": "{{ df.split('df ')[1] if df is defined }}",
+ "global_route": {
+ "address": "{% if global is defined and 'verify-availability' not in global %}{{ global.split('global next-hop ')[1] }}\
+ {% elif global is defined and 'verify-availability' in global %}{{ global.split(' ')[3] }}{% endif %}",
+ "verify_availability": {
+ "address": "{{ global.split(' ')[3] if global is defined and 'verify-availability' in global }}",
+ "sequence": "{{ global.split(' ')[4] if global is defined and 'verify-availability' in global }}",
+ "track": "{{ global.split('track ')[1] if global is defined and 'verify-availability' in global }}",
+ },
+ },
+ "next_hop": {
+ "address": "{{ next_hop.split('next-hop ')[1] if next_hop is defined and 'peer-address' not in next_hop and\
+ 'self' not in next_hop and next_hop.split(' ')|length == 2 }}",
+ "dynamic": "{{ True if next_hop is defined and 'dynamic dhcp' in next_hop }}",
+ "encapsulate": "{{ next_hop.split('next-hop encapsulate l3vpn ')[1] if next_hop is defined and\
+ 'encapsulate' in next_hop }}",
+ "peer_address": "{{ True if next_hop is defined and 'peer-address' in next_hop }}",
+ "recursive": {
+ "global_route": "{{ True if next_hop is defined and 'global' in next_hop.split(' ') }}",
+ "vrf": "{{ next_hop.split(' ')[3] if next_hop is defined and 'vrf' in next_hop }}",
+ "address": "{%- if next_hop is defined and 'global' in next_hop.split(' ') -%}\
+ {{ next_hop.split('next-hop recursive global ')[1] }}\
+ {%- elif next_hop is defined and 'vrf' in next_hop.split(' ') -%}{{ next_hop.split(' ')[4] }}\
+ {%- elif next_hop is defined and 'vrf' not in next_hop.split(' ') and 'global' not in next_hop.split(' ') -%}\
+ {{ next_hop.split(' ')[2] }} {%- endif -%}",
+ },
+ "self": "{{ True if next_hop is defined and 'self' in next_hop }}",
+ "verify_availability": {
+ "set": "{{ True if next_hop is defined and 'verify-availability' in next_hop and 'track' not in next_hop }}",
+ "address": "{{ next_hop.split(' ')[2] if next_hop is defined and 'verify-availability' in next_hop and\
+ 'track' in next_hop }}",
+ "sequence": "{{ next_hop.split(' ')[3] if next_hop is defined and 'verify-availability' in next_hop and\
+ 'track' in next_hop }}",
+ "track": "{{ next_hop.split('track ')[1] if next_hop is defined and 'verify-availability' in next_hop and\
+ 'track' in next_hop }}",
+ },
+ },
+ "precedence": {
+ "set": "{{ True if precedence is defined and precedence.split(' ')|length == 1 }}",
+ "critical": "{{ True if precedence is defined and 'critical' in precedence }}",
+ "flash": "{{ True if precedence is defined and 'flash' in precedence }}",
+ "flash_override": "{{ True if precedence is defined and 'flash-override' in precedence }}",
+ "immediate": "{{ True if precedence is defined and 'immediate' in precedence }}",
+ "internet": "{{ True if precedence is defined and 'internet' in precedence }}",
+ "network": "{{ True if precedence is defined and 'network' in precedence }}",
+ "priority": "{{ True if precedence is defined and 'priority' in precedence }}",
+ "routine": "{{ True if precedence is defined and 'routine' in precedence }}",
+ },
+ "qos_group": "{{ qos_group.split('qos-group ')[1] if qos_group is defined }}",
+ "tos": {
+ "set": "{{ True if tos is defined and tos.split(' ')|length == 1 }}",
+ "max_reliability": "{{ True if tos is defined and 'max-reliability' in tos }}",
+ "max_throughput": "{{ True if tos is defined and 'max-throughput' in tos }}",
+ "min_delay": "{{ True if tos is defined and 'min-delay' in tos }}",
+ "min_monetary_cost": "{{ True if tos is defined and 'min-monetary-cost' in tos }}",
+ "normal": "{{ True if tos is defined and 'normal' in tos }}",
+ },
+ "vrf": {
+ "name": "{{ vrf.split(' ')[1] if vrf is defined }}",
+ "address": "{{ vrf.split('next-hop ')[1] if vrf is defined and 'verify-availability' not in vrf }}",
+ "verify_availability": {
+ "set": "{{ True if vrf is defined and 'track' not in vrf }}",
+ "address": "{{ vrf.split(' ')[4] if vrf is defined and 'track' in vrf }}",
+ "sequence": "{{ vrf.split(' ')[5] if vrf is defined and 'track' in vrf }}",
+ "track": "{{ vrf.split('track ')[1] if vrf is defined and 'track' in vrf }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "set.ipv6",
+ "getval": re.compile(
+ r"""
+ \s+set*
+ \s*(?P<ipv6>ipv6)*
+ \s*(?P<address>address\sprefix-list\s\S+)*
+ \s*(?P<default>default\snext-hop\s(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\S+)*
+ \s*(?P<global>global\snext-hop\sverify-availability\s(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\S+\s\d+\strack\s\d+)*
+ \s*(?P<precedence>precedence\s\d+)*
+ \s*(?P<vrf>vrf\s\S+\snext-hop\sverify-availability\s(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\S+\s\d+\strack\s\d+)*
+ \s*(?P<next_hop>next-hop\s\S.*)*
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": _tmplt_route_map_set_ipv6,
+ "compval": "set",
+ "result": {
+ "{{ route_map }}": {
+ "{{ action|d() + '_' + sequence|d() }}": {
+ "entries": {
+ "set": {
+ "ipv6": {
+ "address": "{{ address.split('address prefix-list ')[1] if address is defined }}",
+ "default": "{{ default.split('default next-hop ')[1] if default is defined }}",
+ "global_route": {
+ "verify_availability": {
+ "address": "{{ global.split(' ')[3] if global is defined and 'verify-availability' in global }}",
+ "sequence": "{{ global.split(' ')[4] if global is defined and 'verify-availability' in global }}",
+ "track": "{{ global.split('track ')[1] if global is defined and 'verify-availability' in global }}",
+ },
+ "address": "{{ global.split(' ')[2] if global is defined and 'verify-availability' not in global }}",
+ },
+ "next_hop": {
+ "address": "{{ next_hop.split('next-hop ')[1] if next_hop is defined and\
+ next_hop.split(' ')|length == 2 and 'peer-address' not in next_hop }}",
+ "encapsulate": "{{ next_hop.split('next-hop encapsulate l3vpn ')[1] if next_hop is defined and\
+ 'encapsulate' in next_hop}}",
+ "peer_address": "{{ True if next_hop is defined and next_hop.split(' ')|length == 2 and 'peer-address' in next_hop }}",
+ "recursive": "{{ next_hop.split('next-hop recursive ')[1] if next_hop is defined }}",
+ },
+ "precedence": "{{ precedence.split(' ')[1] if precedence is defined }}",
+ "vrf": {
+ "name": "{{ vrf.split(' ')[1] if vrf is defined }}",
+ "verify_availability": {
+ "address": "{{ vrf.split(' ')[4] if vrf is defined and 'verify-availability' in vrf }}",
+ "sequence": "{{ vrf.split(' ')[5] if vrf is defined and 'verify-availability' in vrf }}",
+ "track": "{{ vrf.split('track ')[1] if vrf is defined and 'verify-availability' in vrf }}",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ ]
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/service.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/service.py
new file mode 100644
index 000000000..992892db8
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/service.py
@@ -0,0 +1,457 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 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 Service 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 ServiceTemplate(NetworkTemplate):
+ def __init__(self, lines=None, module=None):
+ super(ServiceTemplate, self).__init__(lines=lines, tmplt=self, module=module)
+
+ # fmt: off
+ PARSERS = [
+ {
+ "name": "call_home",
+ "getval": re.compile(
+ r"""
+ ^service\s(?P<call_home>call-home)
+ """, re.VERBOSE,
+ ),
+ "setval": "service call-home",
+ "result": {
+ "call_home": "{{ not not call_home }}",
+ },
+ },
+ {
+ "name": "compress_config",
+ "getval": re.compile(
+ r"""
+ ^service\s(?P<compress_config>compress-config)
+ """, re.VERBOSE,
+ ),
+ "setval": "service compress-config",
+ "result": {
+ "compress_config": "{{ not not compress_config }}",
+ },
+ },
+ {
+ "name": "config",
+ "getval": re.compile(
+ r"""
+ ^service\s(?P<config>config)
+ """, re.VERBOSE,
+ ),
+ "setval": "service config",
+ "result": {
+ "config": "{{ not not config }}",
+ },
+ },
+ {
+ "name": "counters",
+ "getval": re.compile(
+ r"""
+ ^service\scounters\smax\sage(\s(?P<max_age>\d+))?
+ """, re.VERBOSE,
+ ),
+ "setval": "service counters max age {{ counters }}",
+ "result": {
+ "counters": "{{ max_age|int }}",
+ },
+ },
+ {
+ "name": "dhcp",
+ "getval": re.compile(
+ r"""
+ ^service\sdhcp
+ """, re.VERBOSE,
+ ),
+ "setval": "service dhcp",
+ "result": {
+ "dhcp": True,
+ },
+ },
+ {
+ "name": "disable_ip_fast_frag",
+ "getval": re.compile(
+ r"""
+ ^service\s(?P<disable_ip_fast_frag>disable-ip-fast-frag)
+ """, re.VERBOSE,
+ ),
+ "setval": "service disable-ip-fast-frag",
+ "result": {
+ "disable_ip_fast_frag": "{{ not not disable_ip_fast_frag }}",
+ },
+ },
+ {
+ "name": "exec_callback",
+ "getval": re.compile(
+ r"""
+ ^service\s(?P<exec_callback>exec-callback)
+ """, re.VERBOSE,
+ ),
+ "setval": "service exec-callback",
+ "result": {
+ "exec_callback": "{{ not not exec_callback }}",
+ },
+ },
+ {
+ "name": "exec_wait",
+ "getval": re.compile(
+ r"""
+ ^service\s(?P<exec_wait>exec-wait)
+ """, re.VERBOSE,
+ ),
+ "setval": "service exec-wait",
+ "return": {
+ "exec_wait": "{{ not not exec_wait }}",
+ },
+ },
+ {
+ "name": "hide_telnet_addresses",
+ "getval": re.compile(
+ r"""
+ ^service\s(?P<hide_telnet_addresses>hide-telnet-addresses)
+ """, re.VERBOSE,
+ ),
+ "setval": "service hide-telnet-addresses",
+ "result": {
+ "hide_telnet_addresses": "{{ not not hide_telnet_addresses }}",
+ },
+ },
+ {
+ "name": "internal",
+ "getval": re.compile(
+ r"""
+ ^service\s(?P<internal>internal)
+ """, re.VERBOSE,
+ ),
+ "setval": "service internal",
+ "result": {
+ "internal": "{{ not not internal }}",
+ },
+ },
+ {
+ "name": "linenumber",
+ "getval": re.compile(
+ r"""
+ ^service\s(?P<linenumber>linenumber)
+ """, re.VERBOSE,
+ ),
+ "setval": "service linenumber",
+ "result": {
+ "linenumber": "{{ not not linenumber }}",
+ },
+ },
+ {
+ "name": "log",
+ "getval": re.compile(
+ r"""
+ ^service\slog(\s(?P<backtrace>backtrace))?
+ """, re.VERBOSE,
+ ),
+ "setval": "service log backtrace",
+ "result": {
+ "log": "{{ not not backtrace }}",
+ },
+ },
+ {
+ "name": "log_hidden",
+ "getval": re.compile(
+ r"""
+ ^service\s(?P<log_hidden>log-hidden)
+ """, re.VERBOSE,
+ ),
+ "setval": "service log-hidden",
+ "result": {
+ "log_hidden": "{{ not not log_hidden }}",
+ },
+ },
+ {
+ "name": "nagle",
+ "getval": re.compile(
+ r"""
+ ^service\s(?P<nagle>nagle)
+ """, re.VERBOSE,
+ ),
+ "setval": "service nagle",
+ "result": {
+ "nagle": "{{ not not nagle }}",
+ },
+ },
+ {
+ "name": "old_slip_prompts",
+ "getval": re.compile(
+ r"""
+ ^service\s(?P<old_slip_prompts>old-slip-prompts)
+ """, re.VERBOSE,
+ ),
+ "setval": "service old-slip-prompts",
+ "result": {
+ "old_slip_prompts": "{{ not not old_slip_prompts }}",
+ },
+ },
+ {
+ "name": "pad",
+ "getval": re.compile(
+ r"""
+ ^service\spad$
+ """, re.VERBOSE,
+ ),
+ "setval": "service pad",
+ "result": {
+ "pad": True,
+ },
+ },
+ {
+ "name": "pad_cmns",
+ "getval": re.compile(
+ r"""
+ ^service\spad\scmns
+ """, re.VERBOSE,
+ ),
+ "setval": "service pad cmns",
+ "result": {
+ "pad_cmns": True,
+ },
+ },
+ {
+ "name": "pad_from_xot",
+ "getval": re.compile(
+ r"""
+ ^service\spad\sfrom-xot
+ """, re.VERBOSE,
+ ),
+ "setval": "service pad from-xot",
+ "result": {
+ "pad_from_xot": True,
+ },
+ },
+ {
+ "name": "pad_to_xot",
+ "getval": re.compile(
+ r"""
+ ^service\spad\sto-xot
+ """, re.VERBOSE,
+ ),
+ "setval": "service pad to-xot",
+ "result": {
+ "pad_to_xot": True,
+ },
+ },
+ {
+ "name": "password_encryption",
+ "getval": re.compile(
+ r"""
+ ^service\s(?P<password_encryption>password-encryption)
+ """, re.VERBOSE,
+ ),
+ "setval": "service password-encryption",
+ "result": {
+ "password_encryption": "{{ not not password_encryption }}",
+ },
+ },
+ {
+ "name": "password_recovery",
+ "getval": re.compile(
+ r"""
+ ^service\spassword-recovery
+ """, re.VERBOSE,
+ ),
+ "setval": "service password-recovery",
+ "remval": "service password-recovery\nyes",
+ "result": {
+ "password_recovery": True,
+ },
+ },
+ {
+ "name": "prompt",
+ "getval": re.compile(
+ r"""
+ ^service\sprompt\sconfig
+ """, re.VERBOSE,
+ ),
+ "setval": "service prompt config",
+ "result": {
+ "prompt": True,
+ },
+ },
+ {
+ "name": "private_config_encryption",
+ "getval": re.compile(
+ r"""
+ ^service\sprivate-config-encryption
+ """, re.VERBOSE,
+ ),
+ "setval": "service private-config-encryption",
+ "result": {
+ "private_config_encryption": True,
+ },
+ },
+ {
+ "name": "pt_vty_logging",
+ "getval": re.compile(
+ r"""
+ ^service\s(?P<pt_vty_logging>pt-vty-logging)
+ """, re.VERBOSE,
+ ),
+ "setval": "service pt-vty-logging",
+ "result": {
+ "pt_vty_logging": "{{ not not pt_vty_logging }}",
+ },
+ },
+ {
+ "name": "scripting",
+ "getval": re.compile(
+ r"""
+ ^service\s(?P<scripting>scripting)
+ """, re.VERBOSE,
+ ),
+ "setval": "service scripting",
+ "result": {
+ "scripting": "{{ not not scripting }}",
+ },
+ },
+ {
+ "name": "sequence_numbers",
+ "getval": re.compile(
+ r"""
+ ^service\s(?P<sequence_numbers>sequence-numbers)
+ """, re.VERBOSE,
+ ),
+ "setval": "service sequence-numbers",
+ "result": {
+ "sequence_numbers": "{{ not not sequence_numbers }}",
+ },
+ },
+ {
+ "name": "slave_coredump",
+ "getval": re.compile(
+ r"""
+ ^service\s(?P<slave_coredump>slave-coredump)
+ """, re.VERBOSE,
+ ),
+ "setval": "service slave-coredump",
+ "result": {
+ "slave_coredump": "{{ not not slave_coredump }}",
+ },
+ },
+ {
+ "name": "slave_log",
+ "getval": re.compile(
+ r"""
+ ^service\sslave-log
+ """, re.VERBOSE,
+ ),
+ "setval": "service slave-log",
+ "result": {
+ "slave_log": True,
+ },
+ },
+ {
+ "name": "tcp_keepalives_in",
+ "getval": re.compile(
+ r"""
+ ^service\stcp-keepalives-in
+ """, re.VERBOSE,
+ ),
+ "setval": "service tcp-keepalives-in",
+ "result": {
+ "tcp_keepalives_in": True,
+ },
+ },
+ {
+ "name": "tcp_keepalives_out",
+ "getval": re.compile(
+ r"""
+ ^service\stcp-keepalives-out
+ """, re.VERBOSE,
+ ),
+ "setval": "service tcp-keepalives-out",
+ "result": {
+ "tcp_keepalives_out": True,
+ },
+ },
+ {
+ "name": "telnet_zeroidle",
+ "getval": re.compile(
+ r"""
+ ^service\stelnet-zeroidle
+ """, re.VERBOSE,
+ ),
+ "setval": "service telnet-zeroidle",
+ "result": {
+ "telnet_zeroidle": True,
+ },
+ },
+ {
+ "name": "timestamps",
+ "getval": re.compile(
+ r"""
+ ^service\stimestamps
+ (\s(?P<msg>\S+))?
+ (\s(?P<timestamp>\S+))?
+ (\s(?P<msec>msec))?
+ (\s(?P<localtime>localtime))?
+ (\s(?P<show_timezone>show-timezone))?
+ (\s(?P<year>year))?
+ """, re.VERBOSE,
+ ),
+ "remval": "service timestamps{{ (' ' + msg) if msg is defined else '' }}",
+ "setval": "service timestamps"
+ "{{ (' ' + msg) if msg is defined else '' }}"
+ "{% if msg is defined %}"
+ "{{ (' ' + timestamp) if timestamp is defined else '' }}"
+ "{% if timestamp == 'datetime' and datetime_options is defined %}"
+ "{{ ' msec' if datetime_options.msec else '' }}"
+ "{{ ' localtime' if datetime_options.localtime else '' }}"
+ "{{ ' show-timezone' if datetime_options.show_timezone else '' }}"
+ "{{ ' year' if datetime_options.year else '' }}"
+ "{% endif %}"
+ "{% endif %}"
+ "",
+ "result": {
+ "timestamps": [
+ {
+ "msg": "{{ msg if msg is defined else 'debug' }}",
+ "timestamp": "{{ timestamp if timestamp is defined else 'uptime' }}",
+ "datetime_options": {
+ "msec": "{{ True if msec else False}}",
+ "localtime": "{{ True if localtime else False }}",
+ "show_timezone": "{{ True if show_timezone else False }}",
+ "year": "{{ True if year else False }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "unsupported_transceiver",
+ "getval": re.compile(
+ r"""
+ ^service\sunsupported-transceiver
+ """, re.VERBOSE,
+ ),
+ "setval": "service unsupported-transceiver",
+ "result": {
+ "unsupported_transceiver": True,
+ },
+ },
+ ]
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
new file mode 100644
index 000000000..87f9e7c07
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/snmp_server.py
@@ -0,0 +1,1964 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021 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 Snmp_server 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,
+)
+
+
+def cmd_option_engine_id(config_data):
+ cmd = ""
+ if config_data:
+ cmd = "snmp-server engineID "
+ if config_data.get("local"):
+ cmd += "local"
+ if config_data.get("remote"):
+ rm = config_data.get("remote")
+ if rm.get("host"):
+ cmd += "remote {host}".format(host=rm.get("host"))
+ if rm.get("udp_port"):
+ cmd += " udp-port {udp_port}".format(udp_port=rm.get("udp_port"))
+ if rm.get("vrf"):
+ cmd += " vrf {vrf}".format(vrf=rm.get("vrf"))
+ if config_data.get("id"):
+ cmd += " {id}".format(id=config_data.get("id"))
+ return cmd
+
+
+def cmd_option_file_transfer(config_data): # contain sub list attr
+ cmd = ""
+ if config_data.get("file_transfer"):
+ conf = config_data.get("file_transfer")
+ cmd = "snmp-server file-transfer"
+ if conf.get("access_group"):
+ cmd += " access-group {ag}".format(ag=conf.get("access_group"))
+ if conf.get("protocol"):
+ cmd += " protocol"
+ for protocol in list(conf.get("protocol").keys()):
+ cmd += " {protocol}".format(protocol=protocol)
+ return cmd
+
+
+def cmd_option_hosts(config_data): # contain sub list attr
+ cmd = ""
+ if config_data:
+ cmd = "snmp-server host"
+ if config_data.get("host"):
+ cmd += " {host}".format(host=config_data.get("host"))
+ if config_data.get("informs"):
+ cmd += " informs"
+ if config_data.get("version"):
+ cmd += " version {version}".format(version=config_data.get("version"))
+ if config_data.get("version_option"):
+ cmd += " {version}".format(version=config_data.get("version_option"))
+ if config_data.get("vrf"):
+ cmd += " vrf {vrf}".format(vrf=config_data.get("vrf"))
+ if config_data.get("community_string"):
+ cmd += " {community_string}".format(
+ community_string=config_data.get("community_string"),
+ )
+ if config_data.get("traps"):
+ for protocol in list(config_data.get("traps").keys()):
+ cmd += " {protocol}".format(protocol=protocol)
+ return cmd
+
+
+def cmd_option_trap_bgp(config_data):
+ cmd = ""
+ conf = config_data.get("traps", {}).get("bgp", {})
+ 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"
+ if conf.get("state_changes").get("all"):
+ cmd += " all"
+ if conf.get("state_changes").get("backward_trans"):
+ cmd += " backward-trans"
+ if conf.get("state_changes").get("limited"):
+ cmd += " limited"
+ if conf.get("threshold"):
+ cmd += " threshold"
+ if conf.get("threshold").get("prefix"):
+ cmd += " prefix"
+ return cmd
+
+
+class Snmp_serverTemplate(NetworkTemplate):
+ def __init__(self, lines=None, module=None):
+ super(Snmp_serverTemplate, self).__init__(lines=lines, tmplt=self, module=module)
+
+ # fmt: off
+ PARSERS = [
+ {
+ "name": "accounting",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\saccounting\scommands
+ (\s(?P<command>\S+))?
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server accounting commands {{ accounting.command }}",
+ "result": {
+ "accounting": {
+ "command": "{{ command }}",
+ },
+ },
+ },
+ {
+ "name": "cache",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\scache\sinterval
+ (\s(?P<interval>\d+))?
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server cache interval {{ cache }}",
+ "result": {
+ "cache": "{{ interval }}",
+ },
+ },
+ {
+ "name": "chassis_id",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\schassis-id
+ (\s(?P<uqString>.+$))?
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server chassis-id {{ chassis_id }}",
+ "result": {
+ "chassis_id": "{{ uqString }}",
+ },
+ },
+ {
+ "name": "communities",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\scommunity
+ (\s(?P<name>\S+))?
+ (\sview\s(?P<view>\S+))?
+ (\s(?P<ro>RO))?
+ (\s(?P<rw>RW))?
+ (\sipv6\s(?P<acl_v6>\S+))?
+ (\s(?P<acl_v4>\S+|\d+))?
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server community "
+ "{{ name }}"
+ "{{ (' view ' + view) if view is defined else '' }}"
+ "{{ ' ro' if ro|d(False) else ''}}"
+ "{{ ' rw' if rw|d(False) else ''}}"
+ "{{ (' ipv6 ' + acl_v6) if acl_v6 is defined else '' }}"
+ "{{ (' ' + acl_v4) if acl_v4 is defined else '' }}",
+ "result": {
+ "communities": [
+ {
+ "name": "{{ name }}",
+ "view": "{{ view }}",
+ "ro": "{{ not not ro }}",
+ "rw": "{{ not not rw }}",
+ "acl_v6": "{{ acl_v6 }}",
+ "acl_v4": "{{ acl_v4 }}",
+ },
+ ],
+ },
+ },
+ {
+ "name": "contact",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\scontact
+ (\s(?P<contact>.+$))?
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server contact {{ contact }}",
+ "result": {
+ "contact": "{{ contact }}",
+ },
+ },
+ {
+ "name": "context",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\scontext
+ (\s(?P<context>\S+))?
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server context {{ context }}",
+ "result": {
+ "context": ["{{ context }}"],
+ },
+ },
+ {
+ "name": "drop",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\sdrop
+ (\s(?P<vrf_traffic>vrf-traffic))?
+ (\s(?P<unknown_user>unknown-user))?
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server drop"
+ "{{ ' vrf-traffic' if drop.vrf_traffic is defined else '' }}"
+ "{{ ' unknown-user' if drop.unknown_user is defined else '' }}",
+ "result": {
+ "drop": {
+ "vrf_traffic": "{{ not not vrf_traffic }}",
+ "unknown_user": "{{ not not unknown_user }}",
+ },
+ },
+ },
+ {
+ "name": "engine_id",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\sengineID
+ (\s(?P<local>local))?
+ (\sremote\s(?P<remotehost>\S+))?
+ (\sudp-port\s(?P<udp_port>\d+))?
+ (\svrf\s(?P<vrf>\S+))?
+ (\s(?P<id>\S+))?
+ """, re.VERBOSE,
+ ),
+ "setval": cmd_option_engine_id,
+ "result": {
+ "engine_id": [
+ {
+ "id": "'{{ id }}'",
+ "local": "{{ not not local }}",
+ "remote": {
+ "host": "{{ remotehost }}",
+ "udp_port": "{{ udp_port }}",
+ "vrf": "{{ vrf }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "file_transfer",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\sfile-transfer
+ (\saccess-group\s(?P<access_group>\S+))?
+ (\sprotocol\s(?P<protocol>ftp|rcp|tftp))?
+ """, re.VERBOSE,
+ ),
+ "setval": cmd_option_file_transfer,
+ "result": {
+ "file_transfer": {
+ "access_group": "{{ access_group }}",
+ "protocol": ["{{ protocol }}"],
+ },
+ },
+ },
+ {
+ "name": "groups",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\sgroup
+ (\s(?P<group>\S+))?
+ (\s(?P<version>v1|v3|v2c))?
+ (\s(?P<version_option>auth|noauth|priv))?
+ (\scontext\s(?P<context>\S+))?
+ (\sread\s(?P<read>\S+))?
+ (\swrite\s(?P<write>\S+))?
+ (\snotify\s(?P<notify>\S+))?
+ (\saccess\s(?P<acl_v4>\S+))?
+ (\saccess\sipv6\s(?P<acl_v6>\S+))?
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server group "
+ "{{ group if group is defined else '' }}"
+ "{{ (' ' + version) if version is defined else '' }}"
+ "{{ (' ' + version_option) if version_option is defined else '' }}"
+ "{{ (' context ' + context) if context is defined else '' }}"
+ "{{ (' read ' + read) if read is defined else '' }}"
+ "{{ (' write ' + write) if write is defined else '' }}"
+ "{{ (' notify ' + notify) if notify is defined else '' }}"
+ "{{ (' access ' + acl_v4) if acl_v4 is defined else '' }}"
+ "{{ (' access ipv6 ' + acl_v6) if acl_v6 is defined else '' }}",
+ "result": {
+ "groups": [
+ {
+ "group": "{{ group }}",
+ "version": "{{ version }}",
+ "version_option": "{{ version_option }}",
+ "context": "{{ context }}",
+ "notify": "{{ notify }}",
+ "read": "{{ read }}",
+ "write": "{{ write }}",
+ "acl_v4": "{{ acl_v4 }}",
+ "acl_v6": "{{ acl_v6 }}",
+ },
+ ],
+ },
+ },
+ {
+ "name": "hosts",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\shost
+ (\s(?P<host>\S+))?
+ (\s(?P<informs>informs))?
+ (\sversion\s(?P<version>1|3|2c))?
+ (\s(?P<version_option>auth|noauth|priv))?
+ (\svrf\s(?P<vrf>\S+))?
+ (\s(?P<community_string>\S+))?
+ (\s+(?P<traps>.+$))?
+ """, re.VERBOSE,
+ ),
+ "setval": cmd_option_hosts,
+ "result": {
+ "hosts": [
+ {
+ "host": "{{ host }}",
+ "informs": "{{ not not informs }}",
+ "community_string": "{{ community_string }}",
+ "traps": "{{ traps }}",
+ "version": "{{ version }}",
+ "version_option": "{{ version_option }}",
+ "vrf": "{{ vrf }}",
+ },
+ ],
+ },
+ },
+ {
+ "name": "password_policy",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\spassword-policy
+ (\s(?P<policy_name>\S+))?
+ (\s(?P<define>define))?
+ (\suser\s(?P<username>\S+))?
+ (\smin-len\s(?P<min_len>\d+))?
+ (\smax-len\s(?P<max_len>\d+))?
+ (\supper-case\s(?P<upper_case>\d+))?
+ (\slower-case\s(?P<lower_case>\d+))?
+ (\sspecial-char\s(?P<special_char>\d+))?
+ (\sdigits\s(?P<digits>\d+))?
+ (\schange\s(?P<change>\d+))?
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server password-policy "
+ "{{ policy_name if policy_name is defined else '' }}"
+ "{{ (' user ' + username) if username is defined else ' define' }}"
+ "{{ (' min-len ' + min_len|string) if min_len is defined else '' }}"
+ "{{ (' max-len ' + max_len|string) if max_len is defined else '' }}"
+ "{{ (' upper-case ' + upper_case|string) if upper_case is defined else '' }}"
+ "{{ (' lower-case ' + lower_case|string) if lower_case is defined else '' }}"
+ "{{ (' special-char ' + special_char|string) if special_char is defined else '' }}"
+ "{{ (' digits ' + digits|string) if digits is defined else '' }}"
+ "{{ (' change ' + change|string) if change is defined else '' }}",
+ "result": {
+ "password_policy": [
+ {
+ "policy_name": "{{ policy_name }}",
+ "username": "{{ username }}",
+ "min_len": "{{ min_len }}",
+ "max_len": "{{ max_len }}",
+ "upper_case": "{{ upper_case }}",
+ "lower_case": "{{ lower_case }}",
+ "special_char": "{{ special_char }}",
+ "change": "{{ change }}",
+ "digits": "{{ digits }}",
+ },
+ ],
+ },
+ },
+ {
+ "name": "users",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\suser
+ (\s(?P<username>\S+))?
+ (\s(?P<group>\S+))?
+ (\sremote\s(?P<remote>\S+))?
+ (\sudp-port\s(?P<udp_port>\d+))?
+ (\s(?P<version>v1|v3|v2c))?
+ (\s(?P<version_option>auth|encrypted))?
+ (\saccess\sipv6\s(?P<acl_v6>\S+))?
+ (\saccess\s(?P<acl_v4>\S+|\d+))?
+ (\svrf\s(?P<vrf>\S+))?
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server user "
+ "{{ username if username is defined else '' }}"
+ "{{ (' ' + group) if group is defined else '' }}"
+ "{{ (' remote ' + remote) if remote is defined else '' }}"
+ "{{ (' 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 '' }}"
+ "{{ (' vrf ' + vrf) if vrf is defined else '' }}",
+ "result": {
+ "users": [
+ {
+ "username": "{{ username }}",
+ "group": "{{ group }}",
+ "remote": "{{ remote }}",
+ "udp_port": "{{ udp_port }}",
+ "version": "{{ version }}",
+ "version_option": "{{ version_option }}",
+ "acl_v4": "{{ acl_v4 }}",
+ "acl_v6": "{{ acl_v6 }}",
+ "vrf": "{{ vrf }}",
+ },
+ ],
+ },
+ },
+ {
+ "name": "views",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\sview
+ (\s(?P<name>\S+))?
+ (\s(?P<family_name>[-\w]+))?
+ (\s(?P<excluded>excluded))?
+ (\s(?P<included>included))?
+ $""", re.VERBOSE,
+ ),
+ "setval": "snmp-server view "
+ "{{ name if name is defined else '' }}"
+ "{{ (' ' + family_name) if family_name is defined else '' }}"
+ "{{ ' excluded' if excluded is defined else '' }}"
+ "{{ ' included' if included is defined else '' }}",
+ "result": {
+ "views": [
+ {
+ "name": "{{ name }}",
+ "family_name": "{{ family_name }}",
+ "excluded": "{{ not not excluded }}",
+ "included": "{{ not not included }}",
+ },
+ ],
+ },
+ },
+ {
+ "name": "if_index",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\sifindex
+ (\s(?P<if_index>persist))?
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server ifindex persist",
+ "result": {
+ "if_index": "{{ not not if_index }}",
+ },
+ },
+ {
+ "name": "inform",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\sinform
+ (\spending\s(?P<pending>\d+))?
+ (\sretries\s(?P<retries>\d+))?
+ (\stimeout\s(?P<timeout>\d+))?
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server inform"
+ "{{ (' pending ' + inform.pending|string) if inform.pending is defined else '' }}"
+ "{{ (' retries ' + inform.retries|string) if inform.retries is defined else '' }}"
+ "{{ (' timeout ' + inform.timeout|string) if inform.timeout is defined else '' }}",
+ "result": {
+ "inform": {
+ "pending": "{{ pending }}",
+ "retries": "{{ retries }}",
+ "timeout": "{{ timeout }}",
+ },
+ },
+ },
+ {
+ "name": "ip",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\sip\sdscp
+ (\s(?P<dscp>\d+))?
+ (\sprecedence(?P<precedence>\d+))?
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server ip dscp "
+ "{{ (ip.dscp|string) if ip.dscp is defined else '' }}"
+ "{{ (' precedence ' + ip.precedence) if ip.precedence is defined else '' }}",
+ "result": {
+ "ip": {
+ "dscp": "{{ dscp }}",
+ "precedence": "{{ precedence }}",
+ },
+ },
+ },
+ {
+ "name": "location",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\slocation
+ (\s(?P<location>.+))?
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server location {{ location }}",
+ "result": {
+ "location": "{{ location }}",
+ },
+ },
+ {
+ "name": "manager",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\smanager
+ (\ssession-timeout\s(?P<manager>\d+))?
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server manager session-timeout {{ manager }}",
+ "result": {
+ "manager": "{{ manager }}",
+ },
+ },
+ {
+ "name": "packet_size",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\spacketsize
+ (\s(?P<packet_size>\d+))?
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server packetsize {{ packet_size }}",
+ "result": {
+ "packet_size": "{{ packet_size }}",
+ },
+ },
+ {
+ "name": "queue_length",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\squeue-length
+ (\s(?P<queue_length>\d+))?
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server queue-length {{ queue_length }}",
+ "result": {
+ "queue_length": "{{ queue_length }}",
+ },
+ },
+ {
+ "name": "trap_timeout",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\strap\stimeout
+ (\s(?P<ttimeout>\d+))?
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server trap timeout {{ trap_timeout }}",
+ "result": {
+ "trap_timeout": "{{ ttimeout }}",
+ },
+ },
+ {
+ "name": "source_interface",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\ssource-interface
+ (\sinforms\s(?P<interface>\S+))?
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server source-interface informs {{ source_interface }}",
+ "result": {
+ "source_interface": "{{ interface }}",
+ },
+ },
+ {
+ "name": "trap_source",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\strap-source
+ (\s(?P<interface>\S+))?
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server trap-source {{ trap_source }}",
+ "result": {
+ "trap_source": "{{ interface }}",
+ },
+ },
+
+ { # only traps
+ "name": "traps.auth_framework",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sauth-framework
+ (\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 '' }}",
+ "result": {
+ "traps": {
+ "auth_framework": {
+ "enable": True,
+ "sec_violation": "{{ not not excluded }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.bfd",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sbfd
+ (\s(?P<session_down>session-down))?
+ (\s(?P<session_up>session-up))?
+ """, re.VERBOSE,
+ ),
+ "setval": "{{ 'snmp-server enable traps bfd' if traps.bfd.enable is defined else '' }}"
+ "{{ (' session-down') if traps.bfd.session_down is defined else '' }}"
+ "{{ (' session-up') if traps.bfd.session_up is defined else '' }}",
+ "result": {
+ "traps": {
+ "bfd": {
+ "enable": True,
+ "session_down": "{{ not not session_down }}",
+ "session_up": "{{ not not session_up }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.bgp",
+ "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))?
+ """, re.VERBOSE,
+ ),
+ "setval": cmd_option_trap_bgp,
+ "remval": "snmp-server enable traps bgp",
+ "result": {
+ "traps": {
+ "bgp": {
+ "cbgp2": "{{ not not cbgp2 }}",
+ "enable": True,
+ "state_changes": {
+ "enable": "{{ not not state_changes }}",
+ "all": "{{ not not all }}",
+ "backward_trans": "{{ not not backward_trans }}",
+ "limited": "{{ not not limited }}",
+ },
+ "threshold": {
+ "prefix": "{{ not not prefix }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.bridge",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sbridge
+ (\s(?P<newroot>newroot))?
+ (\s(?P<topologychange>topologychange))?
+ """, re.VERBOSE,
+ ),
+ "setval": "{{ 'snmp-server enable traps bridge' if traps.bridge.enable is defined else '' }}"
+ "{{ (' newroot') if traps.bridge.newroot|d(False) is defined else '' }}"
+ "{{ (' topologychange') if traps.bridge.topologychange|d(False) is defined else '' }}",
+ "result": {
+ "traps": {
+ "bridge": {
+ "newroot": "{{ not not newroot }}",
+ "enable": True,
+ "topologychange": "{{ not not topologychange }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.casa",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\scasa
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps casa",
+ "result": {
+ "traps": {
+ "casa": True,
+ },
+ },
+ },
+ {
+ "name": "traps.cnpd",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\scnpd
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps cnpd",
+ "result": {
+ "traps": {
+ "cnpd": True,
+ },
+ },
+ },
+ {
+ "name": "traps.config",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sconfig
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps config",
+ "result": {
+ "traps": {
+ "config": True,
+ },
+ },
+ },
+ {
+ "name": "traps.isis",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sisis$
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps isis",
+ "result": {
+ "traps": {
+ "isis": True,
+ },
+ },
+ },
+ {
+ "name": "traps.config_copy",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sconfig-copy
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps config-copy",
+ "result": {
+ "traps": {
+ "config_copy": True,
+ },
+ },
+ },
+ {
+ "name": "traps.config_ctid",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sconfig-ctid
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps config-ctid",
+ "result": {
+ "traps": {
+ "config_ctid": True,
+ },
+ },
+ },
+ {
+ "name": "traps.dhcp",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sdhcp
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps dhcp",
+ "result": {
+ "traps": {
+ "dhcp": True,
+ },
+ },
+ },
+ {
+ "name": "traps.eigrp",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\seigrp
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps eigrp",
+ "result": {
+ "traps": {
+ "eigrp": True,
+ },
+ },
+ },
+ {
+ "name": "traps.entity",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sentity
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps entity",
+ "result": {
+ "traps": {
+ "entity": True,
+ },
+ },
+ },
+ {
+ "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.event_manager",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sevent-manager
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps event-manager",
+ "result": {
+ "traps": {
+ "event_manager": True,
+ },
+ },
+ },
+ {
+ "name": "traps.flowmon",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sflowmon
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps flowmon",
+ "result": {
+ "traps": {
+ "flowmon": True,
+ },
+ },
+ },
+ {
+ "name": "traps.fru_ctrl",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sfru-ctrl
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps fru-ctrl",
+ "result": {
+ "traps": {
+ "fru_ctrl": True,
+ },
+ },
+ },
+ {
+ "name": "traps.hsrp",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\shsrp
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps hsrp",
+ "result": {
+ "traps": {
+ "hsrp": True,
+ },
+ },
+ },
+ {
+ "name": "traps.ipsla",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sipsla
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ipsla",
+ "result": {
+ "traps": {
+ "ipsla": True,
+ },
+ },
+ },
+ {
+ "name": "traps.msdp",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\smsdp$
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps msdp",
+ "result": {
+ "traps": {
+ "msdp": True,
+ },
+ },
+ },
+ {
+ "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.mvpn",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\smvpn
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps mvpn",
+ "result": {
+ "traps": {
+ "mvpn": True,
+ },
+ },
+ },
+ {
+ "name": "traps.mpls_vpn",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\smpls\svpn
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps mpls vpn",
+ "result": {
+ "traps": {
+ "mpls_vpn": True,
+ },
+ },
+ },
+ {
+ "name": "traps.pki",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\spki
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps pki",
+ "result": {
+ "traps": {
+ "pki": 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.syslog",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\ssyslog
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps syslog",
+ "result": {
+ "traps": {
+ "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.tty",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\stty
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps tty",
+ "result": {
+ "traps": {
+ "tty": True,
+ },
+ },
+ },
+ {
+ "name": "traps.envmon.shutdown",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\senvmon\sshutdown$
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps envmon shutdown",
+ "result": {
+ "traps": {
+ "envmon": {
+ "shutdown": True,
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.envmon.status",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\senvmon\sstatus$
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps envmon status",
+ "result": {
+ "traps": {
+ "envmon": {
+ "status": True,
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.envmon.supply",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\senvmon\ssupply$
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps envmon supply",
+ "result": {
+ "traps": {
+ "envmon": {
+ "supply": True,
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.envmon.temperature",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\senvmon\stemperature$
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps envmon temperature",
+ "result": {
+ "traps": {
+ "envmon": {
+ "temperature": True,
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.envmon.fan.enable",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\senvmon\sfan$
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps envmon fan",
+ "result": {
+ "traps": {
+ "envmon": {
+ "fan": {
+ "enable": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.envmon.fan.shutdown",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\senvmon\sfan\sshutdown$
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps envmon fan shutdown",
+ "result": {
+ "traps": {
+ "envmon": {
+ "fan": {
+ "shutdown": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.envmon.fan.status",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\senvmon\sfan\sstatus$
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps envmon fan status",
+ "result": {
+ "traps": {
+ "envmon": {
+ "fan": {
+ "status": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.envmon.fan.supply",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\senvmon\sfan\ssupply$
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps envmon fan supply",
+ "result": {
+ "traps": {
+ "envmon": {
+ "fan": {
+ "supply": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.envmon.fan.temperature",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\senvmon\sfan\stemperature$
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps envmon fan temperature",
+ "result": {
+ "traps": {
+ "envmon": {
+ "fan": {
+ "temperature": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "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.ipmulticast",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sipmulticast
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ipmulticast",
+ "result": {
+ "traps": {
+ "ipmulticast": True,
+ },
+ },
+ },
+ {
+ "name": "traps.ike.policy.add",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sike\spolicy\sadd
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ike policy add",
+ "result": {
+ "traps": {
+ "ike": {
+ "policy": {
+ "add": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.ike.policy.delete",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sike\spolicy\sdelete
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ike policy delete",
+ "result": {
+ "traps": {
+ "ike": {
+ "policy": {
+ "delete": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.ike.tunnel.start",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sike\stunnel\sstart
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ike tunnel start",
+ "result": {
+ "traps": {
+ "ike": {
+ "tunnel": {
+ "start": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.ike.tunnel.stop",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sike\stunnel\sstop
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ike tunnel stop",
+ "result": {
+ "traps": {
+ "ike": {
+ "tunnel": {
+ "stop": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.ipsec.cryptomap.add",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sipsec\scryptomap\sadd
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ipsec cryptomap add",
+ "result": {
+ "traps": {
+ "ipsec": {
+ "cryptomap": {
+ "add": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.ipsec.cryptomap.delete",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sipsec\scryptomap\sdelete
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ipsec cryptomap delete",
+ "result": {
+ "traps": {
+ "ipsec": {
+ "cryptomap": {
+ "delete": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.ipsec.cryptomap.attach",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sipsec\scryptomap\sattach
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ipsec cryptomap attach",
+ "result": {
+ "traps": {
+ "ipsec": {
+ "cryptomap": {
+ "attach": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.ipsec.cryptomap.detach",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sipsec\scryptomap\sdetach
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ipsec cryptomap detach",
+ "result": {
+ "traps": {
+ "ipsec": {
+ "cryptomap": {
+ "detach": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.ipsec.tunnel.start",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sipsec\stunnel\sstart
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ipsec tunnel start",
+ "result": {
+ "traps": {
+ "ipsec": {
+ "tunnel": {
+ "start": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.ipsec.tunnel.stop",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sipsec\stunnel\sstop
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ipsec tunnel stop",
+ "result": {
+ "traps": {
+ "ipsec": {
+ "tunnel": {
+ "stop": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.ipsec.too_many_sas",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sipsec\stoo-many-sas
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ipsec too-many-sas",
+ "result": {
+ "traps": {
+ "ipsec": {
+ "too_many_sas": True,
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.ospf.cisco_specific.error",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sospf\scisco-specific\serrors
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ospf cisco-specific errors",
+ "result": {
+ "traps": {
+ "ospf": {
+ "cisco_specific": {
+ "error": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.ospf.cisco_specific.retransmit",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sospf\scisco-specific\sretransmit
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ospf cisco-specific retransmit",
+ "result": {
+ "traps": {
+ "ospf": {
+ "cisco_specific": {
+ "retransmit": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.ospf.cisco_specific.lsa",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sospf\scisco-specific\slsa
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ospf cisco-specific lsa",
+ "result": {
+ "traps": {
+ "ospf": {
+ "cisco_specific": {
+ "lsa": True,
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.ospf.cisco_specific.state_change.nssa_trans_change",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sospf\scisco-specific\sstate-change\snssa-trans-change
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ospf cisco-specific state-change nssa-trans-change",
+ "result": {
+ "traps": {
+ "ospf": {
+ "cisco_specific": {
+ "state_change": {
+ "nssa_trans_change": True,
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.ospf.cisco_specific.state_change.shamlink.interface",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sospf\scisco-specific\sstate-change\sshamlink\sinterface
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ospf cisco-specific state-change shamlink interface",
+ "result": {
+ "traps": {
+ "ospf": {
+ "cisco_specific": {
+ "state_change": {
+ "shamlink": {
+ "interface": True,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.ospf.cisco_specific.state_change.shamlink.neighbor",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sospf\scisco-specific\sstate-change\sshamlink\sneighbor
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ospf cisco-specific state-change shamlink neighbor",
+ "result": {
+ "traps": {
+ "ospf": {
+ "cisco_specific": {
+ "state_change": {
+ "shamlink": {
+ "neighbor": True,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.ospf.error",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sospf\serrors
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ospf errors",
+ "result": {
+ "traps": {
+ "ospf": {
+ "error": True,
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.ospf.retransmit",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sospf\sretransmit
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ospf retransmit",
+ "result": {
+ "traps": {
+ "ospf": {
+ "retransmit": True,
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.ospf.lsa",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sospf\slsa
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ospf lsa",
+ "result": {
+ "traps": {
+ "ospf": {
+ "lsa": True,
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.ospf.state_change",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sospf\sstate-change
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps ospf state-change",
+ "result": {
+ "traps": {
+ "ospf": {
+ "state_change": True,
+ },
+ },
+ },
+ },
+ {
+ "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",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sl2tun\ssession
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps l2tun session",
+ "result": {
+ "traps": {
+ "l2tun": {
+ "session": True,
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.cpu",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\scpu
+ (\s(?P<threshold>threshold))?
+ """, re.VERBOSE,
+ ),
+ "setval": "{{ 'snmp-server enable traps cpu' if traps.cpu.enable is defined else '' }}"
+ "{{ ' threshold' if traps.cpu.threshold is defined else '' }}",
+ "result": {
+ "traps": {
+ "cpu": {
+ "enable": True,
+ "threshold": "{{ not not threshold }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.firewall",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sfirewall
+ (\s(?P<serverstatus>serverstatus))?
+ """, re.VERBOSE,
+ ),
+ "setval": "{{ 'snmp-server enable traps firewall' if traps.firewall.enable is defined else '' }}"
+ "{{ ' serverstatus' if traps.firewall.serverstatus|d(False) else ''}}",
+ "result": {
+ "traps": {
+ "firewall": {
+ "enable": True,
+ "serverstatus": "{{ not not serverstatus }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.pim",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\spim
+ (\s(?P<neighbor_change>neighbor-change))?
+ (\s(?P<rp_mapping_change>rp-mapping-change))?
+ (\s(?P<invalid_pim_message>invalid-pim-message))?
+ """, re.VERBOSE,
+ ),
+ "setval": "{{ 'snmp-server enable traps pim' if traps.pim.enable is defined else '' }}"
+ "{{ ' neighbor-change' if traps.pim.neighbor_change|d(False) else ''}}"
+ "{{ ' rp-mapping-change' if traps.pim.rp_mapping_change|d(False) else ''}}"
+ "{{ ' invalid-pim-message' if traps.pim.invalid_pim_message|d(False) else ''}}",
+ "result": {
+ "traps": {
+ "pim": {
+ "enable": True,
+ "neighbor_change": "{{ not not neighbor_change }}",
+ "rp_mapping_change": "{{ not not rp_mapping_change }}",
+ "invalid_pim_message": "{{ not not invalid_pim_message }}",
+ },
+ },
+ },
+ },
+ {
+ "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.snmp",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\ssnmp
+ (\s(?P<authentication>authentication))?
+ (\s(?P<linkdown>linkdown))?
+ (\s(?P<linkup>linkup))?
+ (\s(?P<coldstart>coldstart))?
+ (\s(?P<warmstart>warmstart))?
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server enable traps snmp"
+ "{{ ' 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 ''}}",
+ "result": {
+ "traps": {
+ "snmp": {
+ "authentication": "{{ not not authentication }}",
+ "linkdown": "{{ not not linkdown }}",
+ "linkup": "{{ not not linkup }}",
+ "coldstart": "{{ not not coldstart }}",
+ "warmstart": "{{ not not warmstart }}",
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.frame_relay",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\senable\straps\sframe-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
+ (\scount(?P<count>\d+))?
+ (\sinterval(?P<interval>\d+))?
+ """, 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 '' }}",
+ "result": {
+ "traps": {
+ "frame_relay": {
+ "subif": {
+ "enable": "{{ not not subif }}",
+ "interval": "{{ interval }}",
+ "count": "{{ count }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "name": "traps.cef",
+ "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))?
+ """, 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 ''}}",
+ "result": {
+ "traps": {
+ "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.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' if traps.dlsw.enable is defined else '' }}"
+ "{{ ' 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.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"
+ "{{ ' 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 ''}}",
+ "result": {
+ "traps": {
+ "ethernet": {
+ "evc": {
+ "create": "{{ not not create }}",
+ "delete": "{{ not not delete }}",
+ "status": "{{ not not status }}",
+ },
+ },
+ },
+ },
+ },
+ {
+ "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.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": "system_shutdown",
+ "getval": re.compile(
+ r"""
+ ^snmp-server\ssystem-shutdown
+ """, re.VERBOSE,
+ ),
+ "setval": "snmp-server system-shutdown",
+ "result": {
+ "system_shutdown": True,
+ },
+ },
+ ]
+ # fmt: on
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
new file mode 100644
index 000000000..790f0c8df
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/rm_templates/static_routes.py
@@ -0,0 +1,141 @@
+# -*- 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 Static_routes 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 Static_routesTemplate(NetworkTemplate):
+ def __init__(self, lines=None, module=None):
+ super(Static_routesTemplate, self).__init__(lines=lines, tmplt=self, module=module)
+
+ # fmt: off
+ PARSERS = [
+ {
+ "name": "ipv4",
+ "getval": re.compile(
+ r"""
+ ^ip\sroute
+ (\stopology\s(?P<topology>\S+))?
+ (\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<forward_router_address>(?!multicast|dhcp|global|tag|track|permanent|name)\S+))?
+ (\s(?P<distance_metric>\d+))?
+ (\stag\s(?P<tag>\d+))?
+ (\s(?P<permanent>permanent))?
+ (\sname\s(?P<next_hop_name>\S+))?
+ (\strack\s(?P<track>\d+))?
+ (\s(?P<multicast>multicast))?
+ (\s(?P<dhcp>dhcp))?
+ (\s(?P<global>global))?
+ $""", re.VERBOSE,
+ ),
+ "setval": "ip route"
+ "{{ (' topology ' + ipv4.topology) if ipv4.topology is defined else '' }}"
+ "{{ (' vrf ' + ipv4.vrf) if ipv4.vrf is defined else '' }}"
+ "{{ (' ' + ipv4.dest) if ipv4.dest is defined else '' }}"
+ "{{ (' ' + ipv4.interface) if ipv4.interface is defined else '' }}"
+ "{{ (' ' + ipv4.forward_router_address) if ipv4.forward_router_address is defined else '' }}"
+ "{{ (' ' + ipv4.distance_metric|string) if ipv4.distance_metric is defined else '' }}"
+ "{{ (' tag ' + ipv4.tag|string) if ipv4.tag is defined else '' }}"
+ "{{ (' permanent' ) if ipv4.permanent|d(False) else '' }}"
+ "{{ (' name ' + ipv4.name) if ipv4.name is defined else '' }}"
+ "{{ (' track ' + ipv4.track|string) if ipv4.track is defined else '' }}"
+ "{{ (' multicast' ) if ipv4.multicast|d(False) else '' }}"
+ "{{ (' dhcp' ) if ipv4.dhcp|d(False) else '' }}"
+ "{{ (' global' ) if ipv4.global|d(False) else '' }}",
+ "result": {
+ "{{ dest }}_{{ vrf|d() }}_{{ topology|d() }}_ipv4": [
+ {
+ "_vrf": "{{ vrf }}",
+ "_topology": "{{ topology }}",
+ "_afi": "ipv4",
+ "_dest": "{{ dest }}",
+ "_netmask": "{{ netmask }}",
+ "interface": "{{ interface }}",
+ "forward_router_address": "{{ forward_router_address }}",
+ "distance_metric": "{{ distance_metric }}",
+ "tag": "{{ tag }}",
+ "permanent": "{{ not not permanent }}",
+ "name": "{{ next_hop_name }}",
+ "track": "{{ track }}",
+ "multicast": "{{ not not multicast }}",
+ "dhcp": "{{ not not dhcp }}",
+ "global": "{{ not not global }}",
+ },
+ ],
+ },
+ },
+ {
+ "name": "ipv6",
+ "getval": re.compile(
+ r"""
+ ^ipv6\sroute
+ (\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<forward_router_address>(?!multicast|unicast|tag|track|permanent|name)\S+))?
+ (\s(?P<distance_metric>\d+))?
+ (\s(?P<multicast>multicast))?
+ (\s(?P<unicast>unicast))?
+ (\stag\s(?P<tag>\d+))?
+ (\strack\s(?P<track>\d+))?
+ (\s(?P<permanent>permanent))?
+ (\sname\s(?P<next_hop_name>\S+))?
+ $""", re.VERBOSE,
+ ),
+ "setval": "ipv6 route"
+ "{{ (' topology ' + ipv6.topology) if ipv6.topology is defined else '' }}"
+ "{{ (' vrf ' + ipv6.vrf) if ipv6.vrf is defined else '' }}"
+ "{{ (' ' + ipv6.dest) if ipv6.dest is defined else '' }}"
+ "{{ (' ' + ipv6.interface) if ipv6.interface is defined else '' }}"
+ "{{ (' ' + ipv6.forward_router_address) if ipv6.forward_router_address is defined else '' }}"
+ "{{ (' ' + ipv6.distance_metric|string) if ipv6.distance_metric is defined else '' }}"
+ "{{ (' multicast' ) if ipv6.multicast|d(False) else '' }}"
+ "{{ (' unicast' ) if ipv6.unicast|d(False) else '' }}"
+ "{{ (' tag ' + ipv6.tag|string) if ipv6.tag is defined else '' }}"
+ "{{ (' track ' + ipv6.track|string) if ipv6.track is defined else '' }}"
+ "{{ (' permanent' ) if ipv6.permanent|d(False) else '' }}"
+ "{{ (' name ' + ipv6.name) if ipv6.name is defined else '' }}",
+ "result": {
+ "{{ dest }}_{{ vrf|d() }}_{{ topology|d() }}_ipv6": [
+ {
+ "_vrf": "{{ vrf }}",
+ "_topology": "{{ topology }}",
+ "_afi": "ipv6",
+ "_dest": "{{ dest }}",
+ "interface": "{{ interface }}",
+ "forward_router_address": "{{ forward_router_address }}",
+ "distance_metric": "{{ distance_metric }}",
+ "tag": "{{ tag }}",
+ "permanent": "{{ not not permanent }}",
+ "name": "{{ next_hop_name }}",
+ "track": "{{ track }}",
+ "multicast": "{{ not not multicast }}",
+ "unicast": "{{ not not unicast }}",
+ },
+ ],
+ },
+ },
+ ]
+ # fmt: on
diff --git a/ansible_collections/cisco/ios/plugins/module_utils/network/ios/utils/__init__.py b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/utils/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/utils/__init__.py
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
new file mode 100644
index 000000000..80b4b084d
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/module_utils/network/ios/utils/utils.py
@@ -0,0 +1,423 @@
+#
+# -*- coding: utf-8 -*-
+# Copyright 2019 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+# utils
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+import socket
+
+from itertools import count, groupby
+
+from ansible.module_utils.common.network import is_masklen, to_netmask
+from ansible.module_utils.six import iteritems
+
+
+def remove_command_from_config_list(interface, cmd, commands):
+ # To delete the passed config
+ if interface not in commands:
+ commands.insert(0, interface)
+ commands.append("no %s" % cmd)
+ return commands
+
+
+def add_command_to_config_list(interface, cmd, commands):
+ # To set the passed config
+ if interface not in commands:
+ commands.insert(0, interface)
+ commands.append(cmd)
+
+
+def reverify_diff_py35(want, have):
+ """Function to re-verify the set diff for py35 as it doesn't maintains dict order which results
+ into unexpected set diff
+ :param config: want and have set config
+ :returns: True/False post checking if there's any actual diff b/w want and have sets
+ """
+ if not have:
+ return True
+ for each_want in want:
+ diff = True
+ for each_have in have:
+ if each_have == sorted(each_want) or sorted(each_have) == sorted(each_want):
+ diff = False
+ if diff:
+ return True
+ return False
+
+
+def check_n_return_valid_ipv6_addr(module, input_list, filtered_ipv6_list):
+ # To verify the valid ipv6 address
+ try:
+ for each in input_list:
+ if "::" in each:
+ if "/" in each:
+ each = each.split("/")[0]
+ if socket.inet_pton(socket.AF_INET6, each):
+ filtered_ipv6_list.append(each)
+ return filtered_ipv6_list
+ except socket.error:
+ module.fail_json(msg="Incorrect IPV6 address!")
+
+
+def new_dict_to_set(input_dict, temp_list, test_set, count=0):
+ # recursive function to convert input dict to set for comparision
+ test_dict = dict()
+ if isinstance(input_dict, dict):
+ input_dict_len = len(input_dict)
+ for k, v in sorted(iteritems(input_dict)):
+ count += 1
+ if isinstance(v, list):
+ temp_list.append(k)
+ for each in v:
+ if isinstance(each, dict):
+ if [True for i in each.values() if type(i) == list]:
+ new_dict_to_set(each, temp_list, test_set, count)
+ else:
+ new_dict_to_set(each, temp_list, test_set, 0)
+ else:
+ if v is not None:
+ test_dict.update({k: v})
+ try:
+ if tuple(iteritems(test_dict)) not in test_set and count == input_dict_len:
+ test_set.add(tuple(iteritems(test_dict)))
+ count = 0
+ except TypeError:
+ temp_dict = {}
+
+ def expand_dict(dict_to_expand):
+ temp = dict()
+ for k, v in iteritems(dict_to_expand):
+ if isinstance(v, dict):
+ expand_dict(v)
+ else:
+ if v is not None:
+ temp.update({k: v})
+ temp_dict.update(tuple(iteritems(temp)))
+
+ new_dict = {k: v}
+ expand_dict(new_dict)
+ if tuple(iteritems(temp_dict)) not in test_set:
+ test_set.add(tuple(iteritems(temp_dict)))
+
+
+def dict_to_set(sample_dict):
+ # Generate a set with passed dictionary for comparison
+ test_dict = dict()
+ if isinstance(sample_dict, dict):
+ for k, v in iteritems(sample_dict):
+ if v is not None:
+ if isinstance(v, list):
+ if isinstance(v[0], dict):
+ li = []
+ for each in v:
+ for key, value in iteritems(each):
+ if isinstance(value, list):
+ each[key] = tuple(value)
+ li.append(tuple(iteritems(each)))
+ v = tuple(li)
+ else:
+ v = tuple(v)
+ elif isinstance(v, dict):
+ li = []
+ for key, value in iteritems(v):
+ if isinstance(value, list):
+ v[key] = tuple(value)
+ li.extend(tuple(iteritems(v)))
+ v = tuple(li)
+ test_dict.update({k: v})
+ return_set = set(tuple(iteritems(test_dict)))
+ else:
+ return_set = set(sample_dict)
+ return return_set
+
+
+def filter_dict_having_none_value(want, have):
+ # Generate dict with have dict value which is None in want dict
+ test_dict = dict()
+ name = want.get("name")
+ if name:
+ test_dict["name"] = name
+ diff_ip = False
+ for k, v in iteritems(want):
+ if isinstance(v, dict):
+ for key, value in iteritems(v):
+ test_key_dict = dict()
+ if value is None:
+ if have.get(k):
+ dict_val = have.get(k).get(key)
+ test_key_dict.update({key: dict_val})
+ elif k == "ipv6" and value.lower() != have.get(k)[0].get(key).lower():
+ # as multiple IPV6 address can be configured on same
+ # interface, for replace state in place update will
+ # actually create new entry, which isn't as expected
+ # for replace state, so in case of IPV6 address
+ # every time 1st delete the existing IPV6 config and
+ # then apply the new change
+ dict_val = have.get(k)[0].get(key)
+ test_key_dict.update({key: dict_val})
+ if test_key_dict:
+ test_dict.update({k: test_key_dict})
+ if isinstance(v, list):
+ for key, value in iteritems(v[0]):
+ test_key_dict = dict()
+ if value is None:
+ if have.get(k) and key in have.get(k):
+ dict_val = have.get(k)[0].get(key)
+ test_key_dict.update({key: dict_val})
+ elif have.get(k):
+ if k == "ipv6" and value.lower() != have.get(k)[0].get(key).lower():
+ dict_val = have.get(k)[0].get(key)
+ test_key_dict.update({key: dict_val})
+ if test_key_dict:
+ test_dict.update({k: test_key_dict})
+ # below conditions checks are added to check if
+ # secondary IP is configured, if yes then delete
+ # the already configured IP if want and have IP
+ # is different else if it's same no need to delete
+ for each in v:
+ if each.get("secondary"):
+ want_ip = each.get("address").split("/")
+ have_ip = have.get("ipv4")
+ if len(want_ip) > 1 and have_ip and have_ip[0].get("secondary"):
+ have_ip = have_ip[0]["address"].split(" ")[0]
+ if have_ip != want_ip[0]:
+ diff_ip = True
+ if each.get("secondary") and diff_ip is True:
+ test_key_dict.update({"secondary": True})
+ test_dict.update({"ipv4": test_key_dict})
+ if v is None:
+ val = have.get(k)
+ test_dict.update({k: val})
+ return test_dict
+
+
+def remove_duplicate_interface(commands):
+ # Remove duplicate interface from commands
+ set_cmd = []
+ for each in commands:
+ if "interface" in each:
+ if each not in set_cmd:
+ set_cmd.append(each)
+ else:
+ set_cmd.append(each)
+
+ return set_cmd
+
+
+def validate_ipv4(value, module):
+ if value:
+ address = value.split("/")
+ if len(address) != 2:
+ module.fail_json(
+ msg="address format is <ipv4 address>/<mask>, got invalid format {0}".format(value),
+ )
+
+ if not is_masklen(address[1]):
+ module.fail_json(
+ msg="invalid value for mask: {0}, mask should be in range 0-32".format(address[1]),
+ )
+
+
+def validate_ipv6(value, module):
+ if value:
+ address = value.split("/")
+ if len(address) != 2:
+ module.fail_json(
+ msg="address format is <ipv6 address>/<mask>, got invalid format {0}".format(value),
+ )
+ else:
+ if not 0 <= int(address[1]) <= 128:
+ module.fail_json(
+ msg="invalid value for mask: {0}, mask should be in range 0-128".format(
+ address[1],
+ ),
+ )
+
+
+def validate_n_expand_ipv4(module, want):
+ # Check if input IPV4 is valid IP and expand IPV4 with its subnet mask
+ ip_addr_want = want.get("address")
+ if len(ip_addr_want.split(" ")) > 1:
+ return ip_addr_want
+ validate_ipv4(ip_addr_want, module)
+ ip = ip_addr_want.split("/")
+ if len(ip) == 2:
+ ip_addr_want = "{0} {1}".format(ip[0], to_netmask(ip[1]))
+
+ return ip_addr_want
+
+
+def netmask_to_cidr(netmask):
+ # convert netmask to cidr and returns the cidr notation
+ return str(sum([bin(int(x)).count("1") for x in netmask.split(".")]))
+
+
+def is_valid_ip(ip_str):
+ valid = True
+ try:
+ if "::" in ip_str:
+ socket.inet_pton(socket.AF_INET6, ip_str) # for IPv6
+ else:
+ socket.inet_pton(socket.AF_INET, ip_str) # for IPv4
+ except socket.error:
+ valid = False
+ return valid
+
+
+def normalize_interface(name):
+ """Return the normalized interface name"""
+ if not name:
+ return
+
+ def _get_number(name):
+ digits = ""
+ for char in name:
+ if char.isdigit() or char in "/.":
+ digits += char
+ return digits
+
+ if name.lower().startswith("gi"):
+ if_type = "GigabitEthernet"
+ elif name.lower().startswith("twe"):
+ if_type = "TwentyFiveGigE"
+ elif name.lower().startswith("tw"):
+ if_type = "TwoGigabitEthernet"
+ elif name.lower().startswith("te"):
+ if_type = "TenGigabitEthernet"
+ elif name.lower().startswith("fa"):
+ if_type = "FastEthernet"
+ elif name.lower().startswith("fo"):
+ if_type = "FortyGigabitEthernet"
+ elif name.lower().startswith("fi"):
+ if_type = "FiveGigabitEthernet"
+ elif name.lower().startswith("long"):
+ if_type = "LongReachEthernet"
+ elif name.lower().startswith("et"):
+ if_type = "Ethernet"
+ elif name.lower().startswith("vl"):
+ if_type = "Vlan"
+ elif name.lower().startswith("lo"):
+ if_type = "loopback"
+ elif name.lower().startswith("po"):
+ if_type = "Port-channel"
+ elif name.lower().startswith("nv"):
+ if_type = "nve"
+ elif name.lower().startswith("hu"):
+ if_type = "HundredGigE"
+ elif name.lower().startswith("virtual-te"):
+ if_type = "Virtual-Template"
+ elif name.lower().startswith("tu"):
+ if_type = "Tunnel"
+ elif name.lower().startswith("se"):
+ if_type = "Serial"
+ else:
+ if_type = None
+
+ number_list = name.split(" ")
+ if len(number_list) == 2:
+ number = number_list[-1].strip()
+ else:
+ number = _get_number(name)
+
+ if if_type:
+ proper_interface = if_type + number
+ else:
+ proper_interface = name
+
+ return proper_interface
+
+
+def get_interface_type(interface):
+ """Gets the type of interface"""
+
+ if interface.upper().startswith("GI"):
+ return "GigabitEthernet"
+ elif interface.upper().startswith("TW"):
+ return "TwoGigabitEthernet"
+ elif interface.upper().startswith("TE"):
+ return "TenGigabitEthernet"
+ elif interface.upper().startswith("FA"):
+ return "FastEthernet"
+ elif interface.upper().startswith("FO"):
+ return "FortyGigabitEthernet"
+ elif interface.upper().startswith("FI"):
+ return "FiveGigabitEthernet"
+ elif interface.upper().startswith("LON"):
+ return "LongReachEthernet"
+ elif interface.upper().startswith("ET"):
+ return "Ethernet"
+ elif interface.upper().startswith("VL"):
+ return "Vlan"
+ elif interface.upper().startswith("LO"):
+ return "loopback"
+ elif interface.upper().startswith("PO"):
+ return "Port-channel"
+ elif interface.upper().startswith("NV"):
+ return "nve"
+ elif interface.upper().startswith("TWE"):
+ return "TwentyFiveGigE"
+ elif interface.upper().startswith("HU"):
+ return "HundredGigE"
+ elif interface.upper().startswith("VIRTUAL-TE"):
+ return "Virtual-Template"
+ elif interface.upper().startswith("TU"):
+ return "Tunnel"
+ elif interface.upper().startswith("SE"):
+ return "Serial"
+ else:
+ return "unknown"
+
+
+def get_ranges(data):
+ """
+ Returns a generator object that yields lists of
+ consecutive integers from a list of integers.
+ """
+ for _k, group in groupby(data, lambda t, c=count(): int(t) - next(c)):
+ yield list(group)
+
+
+def numerical_sort(string_int_list):
+ """Sorts list of integers that are digits in numerical order."""
+
+ as_int_list = []
+
+ for vlan in string_int_list:
+ as_int_list.append(int(vlan))
+ as_int_list.sort()
+ return as_int_list
+
+
+def vlan_list_to_range(cmd):
+ """
+ Converts a comma separated list of vlan IDs
+ into ranges.
+ """
+ ranges = []
+ for v in get_ranges(cmd):
+ ranges.append("-".join(map(str, (v[0], v[-1])[: len(v)])))
+ return ",".join(ranges)
+
+
+def vlan_range_to_list(vlans):
+ result = []
+ if vlans:
+ for part in vlans:
+ if part == "none":
+ break
+ if "-" in part:
+ a, b = part.split("-")
+ a, b = int(a), int(b)
+ result.extend(range(a, b + 1))
+ else:
+ a = int(part)
+ result.append(a)
+ return numerical_sort(result)
+ return result
diff --git a/ansible_collections/cisco/ios/plugins/modules/__init__.py b/ansible_collections/cisco/ios/plugins/modules/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_acl_interfaces.py b/ansible_collections/cisco/ios/plugins/modules/ios_acl_interfaces.py
new file mode 100644
index 000000000..dfdc08528
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_acl_interfaces.py
@@ -0,0 +1,629 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2022 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+"""
+The module file for ios_acl_interfaces
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_acl_interfaces
+short_description: Resource module to configure ACL interfaces.
+description:
+ This module configures and manages the access-control (ACL) attributes
+ of interfaces on IOS platforms.
+version_added: 1.0.0
+author:
+ - Sumit Jaiswal (@justjais)
+ - Sagar Paul (@KB-perByte)
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ config:
+ description: A dictionary of ACL interfaces options
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ Full name of the interface excluding any logical unit number,
+ i.e. GigabitEthernet0/1.
+ type: str
+ required: true
+ access_groups:
+ description: Specify access-group for IP access list (standard or extended).
+ type: list
+ elements: dict
+ suboptions:
+ afi:
+ description: Specifies the AFI for the ACLs to be configured on this interface.
+ type: str
+ required: true
+ choices:
+ - ipv4
+ - ipv6
+ acls:
+ description: Specifies the ACLs for the provided AFI.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Specifies the name of the IPv4/IPv4 ACL for the interface.
+ type: str
+ required: true
+ direction:
+ description:
+ - Specifies the direction of packets that the ACL will be applied
+ on.
+ - With one direction already assigned, other acl direction cannot
+ be same.
+ type: str
+ required: true
+ choices:
+ - in
+ - out
+ running_config:
+ description:
+ - The module, by default, will connect to the remote device and retrieve the current
+ running-config to use as a base for comparing against the contents of source.
+ There are times when it is not desirable to have the task get the current running-config
+ for every task in a playbook. The I(running_config) argument allows the implementer
+ to pass in the configuration to use as the base config for comparison. This
+ value of this option should be the output received from device by executing
+ command.
+ type: str
+ state:
+ description:
+ - The state the configuration should be left in
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device.
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result. For state I(rendered) active connection to remote host is
+ not required.
+ - The state I(gathered) will fetch the running configuration from device and transform
+ it into structured data in the format as per the resource module argspec and
+ the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result. The value of C(running_config)
+ option should be the same format as the output of command I(show running-config |
+ include ^interface|ip access-group|ipv6 traffic-filter) executed on device.
+ For state I(parsed) active
+ connection to remote host is not required.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - parsed
+ - rendered
+ default: merged
+"""
+
+EXAMPLES = """
+# Using Merged
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
+# interface Loopback888
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# interface GigabitEthernet0/2
+# ip access-group 123 out
+
+- name: Merge module attributes of given access-groups
+ cisco.ios.ios_acl_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ access_groups:
+ - afi: ipv4
+ acls:
+ - name: 110
+ direction: in
+ - name: 123
+ direction: out
+ - afi: ipv6
+ acls:
+ - name: test_v6
+ direction: out
+ - name: temp_v6
+ direction: in
+ - name: GigabitEthernet0/2
+ access_groups:
+ - afi: ipv4
+ acls:
+ - name: 100
+ direction: in
+ state: merged
+
+# Commands Fired:
+# ---------------
+#
+# interface GigabitEthernet0/1
+# ip access-group 110 in
+# ip access-group 123 out
+# ipv6 traffic-filter test_v6 out
+# ipv6 traffic-filter temp_v6 in
+# interface GigabitEthernet0/2
+# ip access-group 100 in
+
+# After state:
+# -------------
+#
+# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
+# interface Loopback888
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ip access-group 110 in
+# ip access-group 123 out
+# ipv6 traffic-filter test_v6 out
+# ipv6 traffic-filter temp_v6 in
+# interface GigabitEthernet0/2
+# ip access-group 110 in
+# ip access-group 123 out
+
+# Using Replaced
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
+# interface Loopback888
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ip access-group 110 in
+# ip access-group 123 out
+# ipv6 traffic-filter test_v6 out
+# ipv6 traffic-filter temp_v6 in
+# interface GigabitEthernet0/2
+# ip access-group 110 in
+# ip access-group 123 out
+
+- name: Replace module attributes of given access-groups
+ cisco.ios.ios_acl_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ access_groups:
+ - afi: ipv4
+ acls:
+ - name: 100
+ direction: out
+ - name: 110
+ direction: in
+ state: replaced
+
+# Commands Fired:
+# ---------------
+#
+# interface GigabitEthernet0/1
+# no ip access-group 123 out
+# no ipv6 traffic-filter temp_v6 in
+# no ipv6 traffic-filter test_v6 out
+# ip access-group 100 out
+
+# After state:
+# -------------
+#
+# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
+# interface Loopback888
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ip access-group 100 out
+# ip access-group 110 in
+# interface GigabitEthernet0/2
+# ip access-group 110 in
+# ip access-group 123 out
+
+# Using Overridden
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
+# interface Loopback888
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ip access-group 110 in
+# ip access-group 123 out
+# ipv6 traffic-filter test_v6 out
+# ipv6 traffic-filter temp_v6 in
+# interface GigabitEthernet0/2
+# ip access-group 110 in
+# ip access-group 123 out
+
+- name: Overridden module attributes of given access-groups
+ cisco.ios.ios_acl_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ access_groups:
+ - afi: ipv4
+ acls:
+ - name: 100
+ direction: out
+ - name: 110
+ direction: in
+ state: overridden
+
+# Commands Fired:
+# ---------------
+#
+# interface GigabitEthernet0/1
+# no ip access-group 123 out
+# no ipv6 traffic-filter test_v6 out
+# no ipv6 traffic-filter temp_v6 in
+# ip access-group 100 out
+# interface GigabitEthernet0/2
+# no ip access-group 110 in
+# no ip access-group 123 out
+
+# After state:
+# -------------
+#
+# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
+# interface Loopback888
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ip access-group 100 out
+# ip access-group 110 in
+# interface GigabitEthernet0/2
+
+# Using Deleted
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
+# interface Loopback888
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ip access-group 110 in
+# ip access-group 123 out
+# ipv6 traffic-filter test_v6 out
+# ipv6 traffic-filter temp_v6 in
+# interface GigabitEthernet0/2
+# ip access-group 110 in
+# ip access-group 123 out
+
+- name: Delete module attributes of given Interface
+ cisco.ios.ios_acl_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ state: deleted
+
+# Commands Fired:
+# ---------------
+#
+# interface GigabitEthernet0/1
+# no ip access-group 110 in
+# no ip access-group 123 out
+# no ipv6 traffic-filter test_v6 out
+# no ipv6 traffic-filter temp_v6 in
+
+# After state:
+# -------------
+#
+# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
+# interface Loopback888
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# interface GigabitEthernet0/2
+# ip access-group 110 in
+# ip access-group 123 out
+
+# Using DELETED without any config passed
+#"(NOTE: This will delete all of configured resource module attributes from each configured interface)"
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
+# interface Loopback888
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ip access-group 110 in
+# ip access-group 123 out
+# ipv6 traffic-filter test_v6 out
+# ipv6 traffic-filter temp_v6 in
+# interface GigabitEthernet0/2
+# ip access-group 110 in
+# ip access-group 123 out
+
+- name: Delete module attributes of given access-groups from ALL Interfaces
+ cisco.ios.ios_acl_interfaces:
+ config:
+ state: deleted
+
+# Commands Fired:
+# ---------------
+#
+# interface GigabitEthernet0/1
+# no ip access-group 110 in
+# no ip access-group 123 out
+# no ipv6 traffic-filter test_v6 out
+# no ipv6 traffic-filter temp_v6 in
+# interface GigabitEthernet0/2
+# no ip access-group 110 out
+# no ip access-group 123 out
+
+# After state:
+# -------------
+#
+# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
+# interface Loopback888
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# interface GigabitEthernet0/2
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
+# interface Loopback888
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ip access-group 110 in
+# ip access-group 123 out
+# ipv6 traffic-filter test_v6 out
+# ipv6 traffic-filter temp_v6 in
+# interface GigabitEthernet0/2
+# ip access-group 110 in
+# ip access-group 123 out
+
+- name: Gather listed acl interfaces with provided configurations
+ cisco.ios.ios_acl_interfaces:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": [
+# {
+# "name": "Loopback888"
+# },
+# {
+# "name": "GigabitEthernet0/0"
+# },
+# {
+# "access_groups": [
+# {
+# "acls": [
+# {
+# "direction": "in",
+# "name": "110"
+# },
+# {
+# "direction": "out",
+# "name": "123"
+# }
+# ],
+# "afi": "ipv4"
+# },
+# {
+# "acls": [
+# {
+# "direction": "in",
+# "name": "temp_v6"
+# },
+# {
+# "direction": "out",
+# "name": "test_v6"
+# }
+# ],
+# "afi": "ipv6"
+# }
+# ],
+# "name": "GigabitEthernet0/1"
+# },
+# {
+# "access_groups": [
+# {
+# "acls": [
+# {
+# "direction": "in",
+# "name": "100"
+# },
+# {
+# "direction": "out",
+# "name": "123"
+# }
+# ],
+# "afi": "ipv4"
+# }
+# ],
+# "name": "GigabitEthernet0/2"
+# }
+# ]
+
+# After state:
+# ------------
+#
+# vios#sh running-config | include interface|ip access-group|ipv6 traffic-filter
+# interface Loopback888
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ip access-group 110 in
+# ip access-group 123 out
+# ipv6 traffic-filter test_v6 out
+# ipv6 traffic-filter temp_v6 in
+# interface GigabitEthernet0/2
+# ip access-group 110 in
+# ip access-group 123 out
+
+# Using Rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_acl_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ access_groups:
+ - afi: ipv4
+ acls:
+ - name: 110
+ direction: in
+ - name: 123
+ direction: out
+ - afi: ipv6
+ acls:
+ - name: test_v6
+ direction: out
+ - name: temp_v6
+ direction: in
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "interface GigabitEthernet0/1",
+# "ip access-group 110 in",
+# "ip access-group 123 out",
+# "ipv6 traffic-filter temp_v6 in",
+# "ipv6 traffic-filter test_v6 out"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# interface GigabitEthernet0/1
+# ip access-group 110 in
+# ip access-group 123 out
+# ipv6 traffic-filter temp_v6 in
+# ipv6 traffic-filter test_v6 out
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_acl_interfaces:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": [
+# {
+# "access_groups": [
+# {
+# "acls": [
+# {
+# "direction": "in",
+# "name": "110"
+# }
+# ],
+# "afi": "ipv4"
+# },
+# {
+# "acls": [
+# {
+# "direction": "in",
+# "name": "temp_v6"
+# }
+# ],
+# "afi": "ipv6"
+# }
+# ],
+# "name": "GigabitEthernet0/1"
+# }
+# ]
+"""
+
+
+RETURN = """
+before:
+ description: The configuration prior to the module execution.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+after:
+ description: The resulting configuration after module execution.
+ returned: when changed
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: list
+ sample:
+ - "interface GigabitEthernet0/1"
+ - "no ip access-group 123 out"
+ - "no ipv6 traffic-filter test_v6 out"
+rendered:
+ description: The provided configuration in the task rendered in device-native format (offline).
+ returned: when I(state) is C(rendered)
+ type: list
+ sample:
+ - "interface GigabitEthernet0/1"
+ - "no ip access-group 123 out"
+ - "no ipv6 traffic-filter test_v6 out"
+gathered:
+ description: Facts about the network resource gathered from the remote device as structured data.
+ returned: when I(state) is C(gathered)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+parsed:
+ description: The device native config provided in I(running_config) option parsed into structured data as per module argspec.
+ returned: when I(state) is C(parsed)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.acl_interfaces.acl_interfaces import (
+ Acl_interfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.acl_interfaces.acl_interfaces import (
+ Acl_interfaces,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ module = AnsibleModule(
+ argument_spec=Acl_interfacesArgs.argument_spec,
+ mutually_exclusive=[["config", "running_config"]],
+ required_if=[
+ ["state", "merged", ["config"]],
+ ["state", "replaced", ["config"]],
+ ["state", "overridden", ["config"]],
+ ["state", "rendered", ["config"]],
+ ["state", "parsed", ["running_config"]],
+ ],
+ supports_check_mode=True,
+ )
+
+ result = Acl_interfaces(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_acls.py b/ansible_collections/cisco/ios/plugins/modules/ios_acls.py
new file mode 100644
index 000000000..00c5b563c
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_acls.py
@@ -0,0 +1,1508 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2021 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+"""
+The module file for ios_acls
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+author:
+ - Sumit Jaiswal (@justjais)
+ - Sagar Paul (@KB-perByte)
+description: This module configures and manages the named or numbered ACLs on IOS platforms.
+module: ios_acls
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - Module behavior is not idempotent when sequence for aces are not mentioned
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ config:
+ description: A list of ACL configuration options.
+ elements: dict
+ suboptions:
+ acls:
+ description:
+ - A list of Access Control Lists (ACL) attributes.
+ elements: dict
+ suboptions:
+ aces:
+ description: The entries within the ACL.
+ elements: dict
+ suboptions:
+ destination:
+ description: Specify the packet destination.
+ suboptions:
+ address:
+ description: Host address to match, or any single host address.
+ type: str
+ any:
+ description: Match any source address.
+ type: bool
+ host:
+ description: A single destination host
+ type: str
+ object_group:
+ description: Destination network object group
+ type: str
+ port_protocol:
+ description:
+ - Specify the destination port along with protocol.
+ - Note, Valid with TCP/UDP protocol_options
+ suboptions:
+ eq:
+ description: Match only packets on a given port number.
+ type: str
+ gt:
+ description: Match only packets with a greater port number.
+ type: str
+ lt:
+ description: Match only packets with a lower port number.
+ type: str
+ neq:
+ description: Match only packets not on a given port number.
+ type: str
+ range:
+ description: Port group.
+ suboptions:
+ end:
+ description: Specify the end of the port range.
+ type: int
+ start:
+ description: Specify the start of the port range.
+ type: int
+ type: dict
+ type: dict
+ wildcard_bits:
+ description: Destination wildcard bits, valid with IPV4 address.
+ type: str
+ type: dict
+ dscp:
+ description: Match packets with given dscp value.
+ type: str
+ evaluate:
+ description: Evaluate an access list
+ type: str
+ fragments:
+ description:
+ - Check non-initial fragments.
+ - This option is DEPRECATED and is replaced with enable_fragments which
+ accepts bool as input this attribute will be removed after 2024-01-01.
+ type: str
+ enable_fragments:
+ description: Enable non-initial fragments.
+ type: bool
+ grant:
+ choices:
+ - permit
+ - deny
+ description: Specify the action.
+ type: str
+ log:
+ description: Log matches against this entry.
+ suboptions:
+ set:
+ description: Enable Log matches against this entry
+ type: bool
+ user_cookie:
+ description: User defined cookie (max of 64 char)
+ type: str
+ type: dict
+ log_input:
+ description: Log matches against this entry, including input interface.
+ suboptions:
+ set:
+ description: Enable Log matches against this entry, including input interface.
+ type: bool
+ user_cookie:
+ description: User defined cookie (max of 64 char)
+ type: str
+ type: dict
+ option:
+ description:
+ - Match packets with given IP Options value.
+ - Valid only for named acls.
+ suboptions:
+ add_ext:
+ description: Match packets with Address Extension Option (147).
+ type: bool
+ any_options:
+ description: Match packets with ANY Option.
+ type: bool
+ com_security:
+ description: Match packets with Commercial Security Option (134).
+ type: bool
+ dps:
+ description: Match packets with Dynamic Packet State Option (151).
+ type: bool
+ encode:
+ description: Match packets with Encode Option (15).
+ type: bool
+ eool:
+ description: Match packets with End of Options (0).
+ type: bool
+ ext_ip:
+ description: Match packets with Extended IP Option (145).
+ type: bool
+ ext_security:
+ description: Match packets with Extended Security Option (133).
+ type: bool
+ finn:
+ description: Match packets with Experimental Flow Control Option (205).
+ type: bool
+ imitd:
+ description: Match packets with IMI Traffic Desriptor Option (144).
+ type: bool
+ lsr:
+ description: Match packets with Loose Source Route Option (131).
+ type: bool
+ mtup:
+ description: Match packets with MTU Probe Option (11).
+ type: bool
+ mtur:
+ description: Match packets with MTU Reply Option (12).
+ type: bool
+ no_op:
+ description: Match packets with No Operation Option (1).
+ type: bool
+ nsapa:
+ description: Match packets with NSAP Addresses Option (150).
+ type: bool
+ record_route:
+ description: Match packets with Record Route Option (7).
+ type: bool
+ router_alert:
+ description: Match packets with Router Alert Option (148).
+ type: bool
+ sdb:
+ description: Match packets with Selective Directed Broadcast Option (149).
+ type: bool
+ security:
+ description: Match packets with Basic Security Option (130).
+ type: bool
+ ssr:
+ description: Match packets with Strict Source Routing Option (137).
+ type: bool
+ stream_id:
+ description: Match packets with Stream ID Option (136).
+ type: bool
+ timestamp:
+ description: Match packets with Time Stamp Option (68).
+ type: bool
+ traceroute:
+ description: Match packets with Trace Route Option (82).
+ type: bool
+ ump:
+ description: Match packets with Upstream Multicast Packet Option (152).
+ type: bool
+ visa:
+ description: Match packets with Experimental Access Control Option (142).
+ type: bool
+ zsu:
+ description: Match packets with Experimental Measurement Option (10).
+ type: bool
+ type: dict
+ precedence:
+ description: Match packets with given precedence value.
+ type: str
+ protocol:
+ description:
+ - Specify the protocol to match.
+ - Refer to vendor documentation for valid values.
+ type: str
+ protocol_options:
+ description: protocol type.
+ suboptions:
+ ahp:
+ description: Authentication Header Protocol.
+ type: bool
+ eigrp:
+ description: Cisco's EIGRP routing protocol.
+ type: bool
+ esp:
+ description: Encapsulation Security Payload.
+ type: bool
+ gre:
+ description: Cisco's GRE tunneling.
+ type: bool
+ hbh:
+ description: Hop by Hop options header. Valid for IPV6
+ type: bool
+ icmp:
+ description: Internet Control Message Protocol.
+ suboptions:
+ administratively_prohibited:
+ description: Administratively prohibited
+ type: bool
+ alternate_address:
+ description: Alternate address
+ type: bool
+ conversion_error:
+ description: Datagram conversion
+ type: bool
+ dod_host_prohibited:
+ description: Host prohibited
+ type: bool
+ dod_net_prohibited:
+ description: Net prohibited
+ type: bool
+ echo:
+ description: Echo (ping)
+ type: bool
+ echo_reply:
+ description: Echo reply
+ type: bool
+ general_parameter_problem:
+ description: Parameter problem
+ type: bool
+ host_isolated:
+ description: Host isolated
+ type: bool
+ host_precedence_unreachable:
+ description: Host unreachable for precedence
+ type: bool
+ host_redirect:
+ description: Host redirect
+ type: bool
+ host_tos_redirect:
+ description: Host redirect for TOS
+ type: bool
+ host_tos_unreachable:
+ description: Host unreachable for TOS
+ type: bool
+ host_unknown:
+ description: Host unknown
+ type: bool
+ host_unreachable:
+ description: Host unreachable
+ type: bool
+ information_reply:
+ description: Information replies
+ type: bool
+ information_request:
+ description: Information requests
+ type: bool
+ mask_reply:
+ description: Mask replies
+ type: bool
+ mask_request:
+ description: mask_request
+ type: bool
+ mobile_redirect:
+ description: Mobile host redirect
+ type: bool
+ net_redirect:
+ description: Network redirect
+ type: bool
+ net_tos_redirect:
+ description: Net redirect for TOS
+ type: bool
+ net_tos_unreachable:
+ description: Network unreachable for TOS
+ type: bool
+ net_unreachable:
+ description: Net unreachable
+ type: bool
+ network_unknown:
+ description: Network unknown
+ type: bool
+ no_room_for_option:
+ description: Parameter required but no room
+ type: bool
+ option_missing:
+ description: Parameter required but not present
+ type: bool
+ packet_too_big:
+ description: Fragmentation needed and DF set
+ type: bool
+ parameter_problem:
+ description: All parameter problems
+ type: bool
+ port_unreachable:
+ description: Port unreachable
+ type: bool
+ precedence_unreachable:
+ description: Precedence cutoff
+ type: bool
+ protocol_unreachable:
+ description: Protocol unreachable
+ type: bool
+ reassembly_timeout:
+ description: Reassembly timeout
+ type: bool
+ redirect:
+ description: All redirects
+ type: bool
+ router_advertisement:
+ description: Router discovery advertisements
+ type: bool
+ router_solicitation:
+ description: Router discovery solicitations
+ type: bool
+ source_quench:
+ description: Source quenches
+ type: bool
+ source_route_failed:
+ description: Source route failed
+ type: bool
+ time_exceeded:
+ description: All time exceededs
+ type: bool
+ timestamp_reply:
+ description: Timestamp replies
+ type: bool
+ timestamp_request:
+ description: Timestamp requests
+ type: bool
+ traceroute:
+ description: Traceroute
+ type: bool
+ ttl_exceeded:
+ description: TTL exceeded
+ type: bool
+ unreachable:
+ description: All unreachables
+ type: bool
+ type: dict
+ igmp:
+ description: Internet Gateway Message Protocol.
+ suboptions:
+ dvmrp:
+ description: Distance Vector Multicast Routing Protocol(2)
+ type: bool
+ host_query:
+ description: IGMP Membership Query(0)
+ type: bool
+ mtrace_resp:
+ description: Multicast Traceroute Response(7)
+ type: bool
+ mtrace_route:
+ description: Multicast Traceroute(8)
+ type: bool
+ pim:
+ description: Protocol Independent Multicast(3)
+ type: bool
+ trace:
+ description: Multicast trace(4)
+ type: bool
+ v1host_report:
+ description: IGMPv1 Membership Report(1)
+ type: bool
+ v2host_report:
+ description: IGMPv2 Membership Report(5)
+ type: bool
+ v2leave_group:
+ description: IGMPv2 Leave Group(6)
+ type: bool
+ v3host_report:
+ description: IGMPv3 Membership Report(9)
+ type: bool
+ type: dict
+ ip:
+ description: Any Internet Protocol.
+ type: bool
+ ipinip:
+ description: IP in IP tunneling.
+ type: bool
+ ipv6:
+ description: Any IPv6.
+ type: bool
+ nos:
+ description: KA9Q NOS compatible IP over IP tunneling.
+ type: bool
+ ospf:
+ description: OSPF routing protocol.
+ type: bool
+ pcp:
+ description: Payload Compression Protocol.
+ type: bool
+ pim:
+ description: Protocol Independent Multicast.
+ type: bool
+ protocol_number:
+ description: An IP protocol number
+ type: int
+ sctp:
+ description: Stream Control Transmission Protocol.
+ type: bool
+ tcp:
+ description: Match TCP packet flags
+ suboptions:
+ ack:
+ description: Match on the ACK bit
+ type: bool
+ established:
+ description: Match established connections
+ type: bool
+ fin:
+ description: Match on the FIN bit
+ type: bool
+ psh:
+ description: Match on the PSH bit
+ type: bool
+ rst:
+ description: Match on the RST bit
+ type: bool
+ syn:
+ description: Match on the SYN bit
+ type: bool
+ urg:
+ description: Match on the URG bit
+ type: bool
+ type: dict
+ udp:
+ description: User Datagram Protocol.
+ type: bool
+ type: dict
+ remarks:
+ description: The remarks/description of the ACL.
+ elements: str
+ type: list
+ sequence:
+ description:
+ - Sequence Number for the Access Control Entry(ACE).
+ - Refer to vendor documentation for valid values.
+ type: int
+ source:
+ description: Specify the packet source.
+ suboptions:
+ address:
+ description: Source network address.
+ type: str
+ any:
+ description: Match any source address.
+ type: bool
+ host:
+ description: A single source host
+ type: str
+ object_group:
+ description: Source network object group
+ type: str
+ port_protocol:
+ description:
+ - Specify the source port along with protocol.
+ - Note, Valid with TCP/UDP protocol_options
+ suboptions:
+ eq:
+ description: Match only packets on a given port number.
+ type: str
+ gt:
+ description: Match only packets with a greater port number.
+ type: str
+ lt:
+ description: Match only packets with a lower port number.
+ type: str
+ neq:
+ description: Match only packets not on a given port number.
+ type: str
+ range:
+ description: Port group.
+ suboptions:
+ end:
+ description: Specify the end of the port range.
+ type: int
+ start:
+ description: Specify the start of the port range.
+ type: int
+ type: dict
+ type: dict
+ wildcard_bits:
+ description: Source wildcard bits, valid with IPV4 address.
+ type: str
+ type: dict
+ time_range:
+ description: Specify a time-range.
+ type: str
+ tos:
+ description:
+ - Match packets with given TOS value.
+ - Note, DSCP and TOS are mutually exclusive
+ suboptions:
+ max_reliability:
+ description: Match packets with max reliable TOS (2).
+ type: bool
+ max_throughput:
+ description: Match packets with max throughput TOS (4).
+ type: bool
+ min_delay:
+ description: Match packets with min delay TOS (8).
+ type: bool
+ min_monetary_cost:
+ description: Match packets with min monetary cost TOS (1).
+ type: bool
+ normal:
+ description: Match packets with normal TOS (0).
+ type: bool
+ service_value:
+ description: Type of service value
+ type: int
+ type: dict
+ ttl:
+ description: Match packets with given TTL value.
+ suboptions:
+ eq:
+ description: Match only packets on a given TTL number.
+ type: int
+ gt:
+ description: Match only packets with a greater TTL number.
+ type: int
+ lt:
+ description: Match only packets with a lower TTL number.
+ type: int
+ neq:
+ description: Match only packets not on a given TTL number.
+ type: int
+ range:
+ description: Match only packets in the range of TTLs.
+ suboptions:
+ end:
+ description: Specify the end of the port range.
+ type: int
+ start:
+ description: Specify the start of the port range.
+ type: int
+ type: dict
+ type: dict
+ type: list
+ acl_type:
+ choices:
+ - extended
+ - standard
+ description:
+ - ACL type
+ - Note, it's mandatory and required for Named ACL, but for Numbered ACL it's not mandatory.
+ type: str
+ name:
+ description: The name or the number of the ACL.
+ required: true
+ type: str
+ type: list
+ afi:
+ choices:
+ - ipv4
+ - ipv6
+ description:
+ - The Address Family Indicator (AFI) for the Access Control Lists (ACL).
+ required: true
+ type: str
+ type: list
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from
+ the IOS device by executing the command B(sh access-list).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - rendered
+ - parsed
+ default: merged
+ description:
+ - The state the configuration should be left in
+ - The state I(merged) is the default state which merges the want and
+ have config, but for ACL module as the IOS platform doesn't allow
+ update of ACE over an pre-existing ACE sequence in ACL, same way ACLs
+ resource module will error out for respective scenario and only addition
+ of new ACE over new sequence will be allowed with merge state.
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any
+ change on the device.
+ - The state I(rendered) will transform the configuration in C(config)
+ option to platform specific CLI commands which will be returned in
+ the I(rendered) key within the result. For state I(rendered) active
+ connection to remote host is not required.
+ - The state I(gathered) will fetch the running configuration from device
+ and transform it into structured data in the format as per the resource
+ module argspec and the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option
+ and transforms it into JSON format as per the resource module parameters
+ and the value is returned in the I(parsed) key within the result. The
+ value of C(running_config) option should be the same format as the output
+ of commands I(show access-list) and
+ I(show running-config | include ip(v6)* access-list|remark) executed on
+ device. Config data from both the commands should be kept together one after
+ another for the parsers to pick the commands correctly.
+ For state I(parsed) active connection to remote host is not required.
+ - The state I(overridden), modify/add the ACLs defined, deleted all other ACLs.
+ - The state I(replaced), modify/add only the ACEs of the ACLs defined only.
+ It does not perform any other change on the device.
+ - The state I(deleted), deletes only the specified ACLs, or all if not specified.
+ type: str
+short_description: Resource module to configure ACLs.
+version_added: 1.0.0
+"""
+
+EXAMPLES = """
+# Using merged
+
+# Before state:
+# -------------
+#
+# vios#sh access-lists
+# Extended IP access list 100
+# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 echo dscp ef ttl eq 10
+
+- name: Merge provided configuration with device configuration
+ cisco.ios.ios_acls:
+ config:
+ - afi: ipv4
+ acls:
+ - name: 100
+ aces:
+ - sequence: 10
+ protocol_options:
+ icmp:
+ traceroute: true
+ state: merged
+
+# After state:
+# ------------
+#
+# Play Execution fails, with error:
+# Cannot update existing sequence 10 of ACLs 100 with state merged.
+# Please use state replaced or overridden.
+
+# Before state:
+# -------------
+#
+# vios#sh access-lists
+# Extended IP access list 110
+# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 echo dscp ef ttl eq 10
+
+- name: Merge provided configuration with device configuration
+ cisco.ios.ios_acls:
+ config:
+ - afi: ipv4
+ acls:
+ - name: std_acl
+ acl_type: standard
+ aces:
+ - grant: deny
+ source:
+ address: 192.168.1.200
+ - grant: deny
+ source:
+ address: 192.168.2.0
+ wildcard_bits: 0.0.0.255
+ - name: 110
+ aces:
+ - sequence: 10
+ protocol_options:
+ icmp:
+ traceroute: true
+ - grant: deny
+ protocol_options:
+ tcp:
+ ack: true
+ source:
+ host: 198.51.100.0
+ destination:
+ host: 198.51.110.0
+ port_protocol:
+ eq: telnet
+ - name: test
+ acl_type: extended
+ aces:
+ - grant: deny
+ protocol_options:
+ tcp:
+ fin: true
+ source:
+ address: 192.0.2.0
+ wildcard_bits: 0.0.0.255
+ destination:
+ address: 192.0.3.0
+ wildcard_bits: 0.0.0.255
+ port_protocol:
+ eq: www
+ option:
+ traceroute: true
+ ttl:
+ eq: 10
+ - name: 123
+ aces:
+ - remarks:
+ - "remarks for extended ACL 1"
+ - "check ACL"
+ - grant: deny
+ protocol_options:
+ tcp:
+ ack: true
+ source:
+ address: 198.51.100.0
+ wildcard_bits: 0.0.0.255
+ destination:
+ address: 198.51.101.0
+ wildcard_bits: 0.0.0.255
+ port_protocol:
+ eq: telnet
+ tos:
+ service_value: 12
+ - grant: deny
+ protocol_options:
+ tcp:
+ ack: true
+ source:
+ address: 192.0.3.0
+ wildcard_bits: 0.0.0.255
+ destination:
+ address: 192.0.4.0
+ wildcard_bits: 0.0.0.255
+ port_protocol:
+ eq: www
+ dscp: ef
+ ttl:
+ lt: 20
+ - afi: ipv6
+ acls:
+ - name: R1_TRAFFIC
+ aces:
+ - grant: deny
+ protocol_options:
+ tcp:
+ ack: true
+ source:
+ any: true
+ port_protocol:
+ eq: www
+ destination:
+ any: true
+ port_protocol:
+ eq: telnet
+ dscp: af11
+ state: merged
+
+# Commands fired:
+# ---------------
+#
+# - ip access-list standard std_acl
+# - deny 192.168.1.200
+# - deny 192.168.2.0 0.0.0.255
+# - ip access-list extended 110
+# - 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
+# - deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
+# - ip access-list extended test
+# - deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
+# - ip access-list extended 123
+# - deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
+# - deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
+# - remark remarks for extended ACL 1
+# - remark check ACL
+# - ipv6 access-list R1_TRAFFIC
+# - deny tcp any eq www any eq telnet ack dscp af11
+
+# After state:
+# ------------
+#
+# vios#sh access-lists
+# Standard IP access list std_acl
+# 10 deny 192.168.1.200
+# 20 deny 192.168.2.0, wildcard bits 0.0.0.255
+# Extended IP access list 100
+# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 echo dscp ef ttl eq 10
+# Extended IP access list 110
+# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
+# 20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
+# Extended IP access list 123
+# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
+# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
+# Extended IP access list test
+# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
+# IPv6 access list R1_TRAFFIC
+# deny tcp any eq www any eq telnet ack dscp af11 sequence 10
+
+# Using replaced
+
+# Before state:
+# -------------
+#
+# vios#sh access-lists
+# Standard IP access list std_acl
+# 10 deny 192.168.1.200
+# 20 deny 192.168.2.0, wildcard bits 0.0.0.255
+# Extended IP access list 110
+# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
+# 20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
+# Extended IP access list 123
+# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
+# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
+# Extended IP access list test
+# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
+# IPv6 access list R1_TRAFFIC
+# deny tcp any eq www any eq telnet ack dscp af11 sequence 10
+
+- name: Replaces device configuration of listed acls with provided configuration
+ cisco.ios.ios_acls:
+ config:
+ - afi: ipv4
+ acls:
+ - name: 110
+ aces:
+ - grant: deny
+ protocol_options:
+ tcp:
+ syn: true
+ source:
+ address: 192.0.2.0
+ wildcard_bits: 0.0.0.255
+ destination:
+ address: 192.0.3.0
+ wildcard_bits: 0.0.0.255
+ port_protocol:
+ eq: www
+ dscp: ef
+ ttl:
+ eq: 10
+ - name: 150
+ aces:
+ - grant: deny
+ sequence: 20
+ protocol_options:
+ tcp:
+ syn: true
+ source:
+ address: 198.51.100.0
+ wildcard_bits: 0.0.0.255
+ port_protocol:
+ eq: telnet
+ destination:
+ address: 198.51.110.0
+ wildcard_bits: 0.0.0.255
+ port_protocol:
+ eq: telnet
+ dscp: ef
+ ttl:
+ eq: 10
+ state: replaced
+
+# Commands fired:
+# ---------------
+#
+# - no ip access-list extended 110
+# - ip access-list extended 110
+# - deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www syn dscp ef ttl eq 10
+# - ip access-list extended 150
+# - 20 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq telnet syn dscp ef ttl eq 10
+
+# After state:
+# -------------
+#
+# vios#sh access-lists
+# Standard IP access list std_acl
+# 10 deny 192.168.1.200
+# 20 deny 192.168.2.0, wildcard bits 0.0.0.255
+# Extended IP access list 110
+# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www syn dscp ef ttl eq 10
+# Extended IP access list 123
+# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
+# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
+# Extended IP access list 150
+# 20 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq telnet syn dscp ef ttl eq 10
+# Extended IP access list test
+# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
+# IPv6 access list R1_TRAFFIC
+# deny tcp any eq www any eq telnet ack dscp af11 sequence 10
+
+# Using overridden
+
+# Before state:
+# -------------
+#
+# vios#sh access-lists
+# Standard IP access list std_acl
+# 10 deny 192.168.1.200
+# 20 deny 192.168.2.0, wildcard bits 0.0.0.255
+# Extended IP access list 110
+# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
+# 20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
+# Extended IP access list 123
+# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
+# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
+# Extended IP access list test
+# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
+# IPv6 access list R1_TRAFFIC
+# deny tcp any eq www any eq telnet ack dscp af11 sequence 10
+
+- name: Override device configuration of all acls with provided configuration
+ cisco.ios.ios_acls:
+ config:
+ - afi: ipv4
+ acls:
+ - name: 110
+ aces:
+ - grant: deny
+ sequence: 20
+ protocol_options:
+ tcp:
+ ack: true
+ source:
+ address: 198.51.100.0
+ wildcard_bits: 0.0.0.255
+ port_protocol:
+ eq: telnet
+ destination:
+ address: 198.51.110.0
+ wildcard_bits: 0.0.0.255
+ port_protocol:
+ eq: www
+ dscp: ef
+ ttl:
+ eq: 10
+ - name: 150
+ aces:
+ - grant: deny
+ sequence: 10
+ protocol_options:
+ tcp:
+ syn: true
+ source:
+ address: 198.51.100.0
+ wildcard_bits: 0.0.0.255
+ port_protocol:
+ eq: telnet
+ destination:
+ address: 198.51.110.0
+ wildcard_bits: 0.0.0.255
+ port_protocol:
+ eq: telnet
+ dscp: ef
+ ttl:
+ eq: 10
+ state: overridden
+
+# Commands fired:
+# ---------------
+#
+# - no ip access-list standard std_acl
+# - no ip access-list extended 110
+# - no ip access-list extended 123
+# - no ip access-list extended 150
+# - no ip access-list extended test
+# - no ipv6 access-list R1_TRAFFIC
+# - ip access-list extended 150
+# - 10 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq telnet syn dscp ef ttl eq 10
+# - ip access-list extended 110
+# - 20 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq www ack dscp ef ttl eq 10
+
+# After state:
+# -------------
+#
+# vios#sh access-lists
+# Extended IP access list 110
+# 20 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq www ack dscp ef ttl eq 10
+# Extended IP access list 150
+# 10 deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq telnet syn dscp ef ttl eq 10
+
+# Using Deleted
+
+# Before state:
+# -------------
+#
+# vios#sh access-lists
+# Standard IP access list std_acl
+# 10 deny 192.168.1.200
+# 20 deny 192.168.2.0, wildcard bits 0.0.0.255
+# Extended IP access list 110
+# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
+# 20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
+# Extended IP access list 123
+# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
+# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
+# Extended IP access list test
+# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
+# IPv6 access list R1_TRAFFIC
+# deny tcp any eq www any eq telnet ack dscp af11 sequence 10
+
+- name: "Delete ACLs (Note: This won't delete the all configured ACLs)"
+ cisco.ios.ios_acls:
+ config:
+ - afi: ipv4
+ acls:
+ - name: test
+ acl_type: extended
+ - name: 110
+ - afi: ipv6
+ acls:
+ - name: R1_TRAFFIC
+ state: deleted
+
+# Commands fired:
+# ---------------
+#
+# - no ip access-list extended test
+# - no ip access-list extended 110
+# - no ipv6 access-list R1_TRAFFIC
+
+# After state:
+# -------------
+#
+# vios#sh access-lists
+# Standard IP access list std_acl
+# 10 deny 192.168.1.200
+# 20 deny 192.168.2.0, wildcard bits 0.0.0.255
+# Extended IP access list 123
+# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
+# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
+
+# Before state:
+# -------------
+#
+# vios#sh access-lists
+# Standard IP access list std_acl
+# 10 deny 192.168.1.200
+# 20 deny 192.168.2.0, wildcard bits 0.0.0.255
+# Extended IP access list 110
+# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
+# 20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
+# Extended IP access list 123
+# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
+# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
+# Extended IP access list test
+# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
+# IPv6 access list R1_TRAFFIC
+# deny tcp any eq www any eq telnet ack dscp af11 sequence 10
+
+- name: "Delete ACLs based on AFI (Note: This won't delete the all configured ACLs)"
+ cisco.ios.ios_acls:
+ config:
+ - afi: ipv4
+ state: deleted
+
+# Commands fired:
+# ---------------
+#
+# - no ip access-list standard std_acl
+# - no ip access-list extended test
+# - no ip access-list extended 110
+# - no ip access-list extended 123
+
+# After state:
+# -------------
+#
+# vios#sh access-lists
+# IPv6 access list R1_TRAFFIC
+# deny tcp any eq www any eq telnet ack dscp af11 sequence 10
+
+# Using Deleted without any config passed
+#"(NOTE: This will delete all of configured ACLs)"
+
+# Before state:
+# -------------
+#
+# vios#sh access-lists
+# Standard IP access list std_acl
+# 10 deny 192.168.1.200
+# 20 deny 192.168.2.0, wildcard bits 0.0.0.255
+# Extended IP access list 110
+# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
+# 20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
+# Extended IP access list 123
+# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
+# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
+# Extended IP access list test
+# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
+# IPv6 access list R1_TRAFFIC
+# deny tcp any eq www any eq telnet ack dscp af11 sequence 10
+
+- name:
+ "Delete ALL of configured ACLs (Note: This WILL delete the all configured
+ ACLs)"
+ cisco.ios.ios_acls:
+ state: deleted
+
+# Commands fired:
+# ---------------
+#
+# - no ip access-list extended test
+# - no ip access-list extended 110
+# - no ip access-list extended 123
+# - no ip access-list extended test
+# - no ipv6 access-list R1_TRAFFIC
+
+# After state:
+# -------------
+#
+# vios#sh access-lists
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# vios#sh access-lists
+# Standard IP access list std_acl
+# 10 deny 192.168.1.200
+# 20 deny 192.168.2.0, wildcard bits 0.0.0.255
+# Extended IP access list 110
+# 10 deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 traceroute dscp ef ttl eq 10
+# 20 deny tcp host 198.51.100.0 host 198.51.110.0 eq telnet ack
+# Extended IP access list 123
+# 10 deny tcp 198.51.100.0 0.0.0.255 198.51.101.0 0.0.0.255 eq telnet ack tos 12
+# 20 deny tcp 192.0.3.0 0.0.0.255 192.0.4.0 0.0.0.255 eq www ack dscp ef ttl lt 20
+# Extended IP access list test
+# 10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www fin option traceroute ttl eq 10
+# IPv6 access list R1_TRAFFIC
+# deny tcp any eq www any eq telnet ack dscp af11 sequence 10
+
+- name: Gather listed acls with provided configurations
+ cisco.ios.ios_acls:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": [
+# {
+# "acls": [
+# {
+# "aces": [
+# {
+# "destination": {
+# "address": "192.0.3.0",
+# "wildcard_bits": "0.0.0.255"
+# },
+# "dscp": "ef",
+# "grant": "deny",
+# "protocol_options": {
+# "icmp": {
+# "echo": true
+# }
+# },
+# "sequence": 10,
+# "source": {
+# "address": "192.0.2.0",
+# "wildcard_bits": "0.0.0.255"
+# },
+# "ttl": {
+# "eq": 10
+# }
+# }
+# ],
+# "acl_type": "extended",
+# "name": "110"
+# },
+# {
+# "aces": [
+# {
+# "destination": {
+# "address": "198.51.101.0",
+# "port_protocol": {
+# "eq": "telnet"
+# },
+# "wildcard_bits": "0.0.0.255"
+# },
+# "grant": "deny",
+# "protocol_options": {
+# "tcp": {
+# "ack": true
+# }
+# },
+# "sequence": 10,
+# "source": {
+# "address": "198.51.100.0",
+# "wildcard_bits": "0.0.0.255"
+# },
+# "tos": {
+# "service_value": 12
+# }
+# },
+# {
+# "destination": {
+# "address": "192.0.4.0",
+# "port_protocol": {
+# "eq": "www"
+# },
+# "wildcard_bits": "0.0.0.255"
+# },
+# "dscp": "ef",
+# "grant": "deny",
+# "protocol_options": {
+# "tcp": {
+# "ack": true
+# }
+# },
+# "sequence": 20,
+# "source": {
+# "address": "192.0.3.0",
+# "wildcard_bits": "0.0.0.255"
+# },
+# "ttl": {
+# "lt": 20
+# }
+# }
+# ],
+# "acl_type": "extended",
+# "name": "123"
+# },
+# {
+# "aces": [
+# {
+# "destination": {
+# "address": "192.0.3.0",
+# "port_protocol": {
+# "eq": "www"
+# },
+# "wildcard_bits": "0.0.0.255"
+# },
+# "grant": "deny",
+# "option": {
+# "traceroute": true
+# },
+# "protocol_options": {
+# "tcp": {
+# "fin": true
+# }
+# },
+# "sequence": 10,
+# "source": {
+# "address": "192.0.2.0",
+# "wildcard_bits": "0.0.0.255"
+# },
+# "ttl": {
+# "eq": 10
+# }
+# }
+# ],
+# "acl_type": "extended",
+# "name": "test_acl"
+# }
+# ],
+# "afi": "ipv4"
+# },
+# {
+# "acls": [
+# {
+# "aces": [
+# {
+# "destination": {
+# "any": true,
+# "port_protocol": {
+# "eq": "telnet"
+# }
+# },
+# "dscp": "af11",
+# "grant": "deny",
+# "protocol_options": {
+# "tcp": {
+# "ack": true
+# }
+# },
+# "sequence": 10,
+# "source": {
+# "any": true,
+# "port_protocol": {
+# "eq": "www"
+# }
+# }
+# }
+# ],
+# "name": "R1_TRAFFIC"
+# }
+# ],
+# "afi": "ipv6"
+# }
+# ]
+
+# Using Rendered
+
+- name: Rendered the provided configuration with the existing running configuration
+ cisco.ios.ios_acls:
+ config:
+ - afi: ipv4
+ acls:
+ - name: 110
+ aces:
+ - grant: deny
+ sequence: 10
+ protocol_options:
+ tcp:
+ syn: true
+ source:
+ address: 192.0.2.0
+ wildcard_bits: 0.0.0.255
+ destination:
+ address: 192.0.3.0
+ wildcard_bits: 0.0.0.255
+ port_protocol:
+ eq: www
+ dscp: ef
+ ttl:
+ eq: 10
+ - name: 150
+ aces:
+ - grant: deny
+ protocol_options:
+ tcp:
+ syn: true
+ source:
+ address: 198.51.100.0
+ wildcard_bits: 0.0.0.255
+ port_protocol:
+ eq: telnet
+ destination:
+ address: 198.51.110.0
+ wildcard_bits: 0.0.0.255
+ port_protocol:
+ eq: telnet
+ dscp: ef
+ ttl:
+ eq: 10
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "ip access-list extended 110",
+# "10 deny tcp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 eq www syn dscp ef ttl eq 10",
+# "ip access-list extended 150",
+# "deny tcp 198.51.100.0 0.0.0.255 eq telnet 198.51.110.0 0.0.0.255 eq telnet syn dscp ef ttl eq 10"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# IPv6 access-list R1_TRAFFIC
+# deny tcp any eq www any eq telnet ack dscp af11
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_acls:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": [
+# {
+# "acls": [
+# {
+# "aces": [
+# {
+# "destination": {
+# "any": true,
+# "port_protocol": {
+# "eq": "telnet"
+# }
+# },
+# "dscp": "af11",
+# "grant": "deny",
+# "protocol_options": {
+# "tcp": {
+# "ack": true
+# }
+# },
+# "source": {
+# "any": true,
+# "port_protocol": {
+# "eq": "www"
+# }
+# }
+# }
+# ],
+# "name": "R1_TRAFFIC"
+# }
+# ],
+# "afi": "ipv6"
+# }
+# ]
+"""
+
+RETURN = """
+before:
+ description: The configuration prior to the module execution.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+after:
+ description: The resulting configuration after module execution.
+ returned: when changed
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: list
+ sample:
+ - ip access-list extended 110
+ - deny icmp 192.0.2.0 0.0.0.255 192.0.3.0 0.0.0.255 echo dscp ef ttl eq 10
+ - permit ip host 2.2.2.2 host 3.3.3.3
+rendered:
+ description: The provided configuration in the task rendered in device-native format (offline).
+ returned: when I(state) is C(rendered)
+ type: list
+ sample:
+ - ip access-list extended test
+ - permit ip host 2.2.2.2 host 3.3.3.3
+ - permit tcp host 1.1.1.1 host 5.5.5.5 eq www
+gathered:
+ description: Facts about the network resource gathered from the remote device as structured data.
+ returned: when I(state) is C(gathered)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+parsed:
+ description: The device native config provided in I(running_config) option parsed into structured data as per module argspec.
+ returned: when I(state) is C(parsed)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.acls.acls import (
+ AclsArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.acls.acls import Acls
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ module = AnsibleModule(
+ argument_spec=AclsArgs.argument_spec,
+ mutually_exclusive=[["config", "running_config"]],
+ required_if=[
+ ["state", "merged", ["config"]],
+ ["state", "replaced", ["config"]],
+ ["state", "overridden", ["config"]],
+ ["state", "rendered", ["config"]],
+ ["state", "parsed", ["running_config"]],
+ ],
+ supports_check_mode=True,
+ )
+
+ result = Acls(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_banner.py b/ansible_collections/cisco/ios/plugins/modules/ios_banner.py
new file mode 100644
index 000000000..7c937b122
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_banner.py
@@ -0,0 +1,205 @@
+#!/usr/bin/python
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_banner
+author: Ricardo Carrillo Cruz (@rcarrillocruz)
+short_description: Module to configure multiline banners.
+description:
+ - This will configure both login and motd banners on remote devices running Cisco
+ IOS. It allows playbooks to add or remote banner text from the active running configuration.
+version_added: 1.0.0
+extends_documentation_fragment:
+ - cisco.ios.ios
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ banner:
+ description:
+ - Specifies which banner should be configured on the remote device. In Ansible
+ 2.4 and earlier only I(login) and I(motd) were supported.
+ required: true
+ choices:
+ - login
+ - motd
+ - exec
+ - incoming
+ - slip-ppp
+ type: str
+ multiline_delimiter:
+ description:
+ - Specify the delimiting character than will be used for configuration.
+ default: "@"
+ type: str
+ text:
+ description:
+ - The banner text that should be present in the remote device running configuration. This
+ argument accepts a multiline string, with no empty lines. Requires I(state=present).
+ type: str
+ state:
+ description:
+ - Specifies whether or not the configuration is present in the current devices
+ active running configuration.
+ default: present
+ type: str
+ choices:
+ - present
+ - absent
+"""
+
+EXAMPLES = """
+- name: Configure the login banner
+ cisco.ios.ios_banner:
+ banner: login
+ text: |
+ this is my login banner
+ that contains a multiline
+ string
+ state: present
+
+- name: Remove the motd banner
+ cisco.ios.ios_banner:
+ banner: motd
+ state: absent
+
+- name: Configure banner from file
+ cisco.ios.ios_banner:
+ banner: motd
+ text: "{{ lookup('file', './config_partial/raw_banner.cfg') }}" # Use unix formatted text files (LF not CRLF) to avoid idempotency issues.
+ state: present
+
+- name: Configure the login banner using delimiter
+ cisco.ios.ios_banner:
+ banner: login
+ multiline_delimiter: x
+ text: this is my login banner
+ state: present
+"""
+
+RETURN = """
+commands:
+ description: The list of configuration mode commands to send to the device
+ returned: always
+ type: list
+ sample:
+ - banner login
+ - this is my login banner
+ - that contains a multiline
+ - string
+"""
+from re import M, search
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ get_config,
+ load_config,
+)
+
+
+def map_obj_to_commands(updates, module):
+ commands = list()
+ want, have = updates
+ state = module.params["state"]
+ multiline_delimiter = module.params.get("multiline_delimiter")
+ if state == "absent" and "text" in have.keys() and have["text"]:
+ commands.append("no banner %s" % module.params["banner"])
+ elif state == "present":
+ if have.get("text") and len(have.get("text")) > 1:
+ haved = have.get("text").rstrip("\n")
+ else:
+ haved = ""
+ if want["text"] and (want["text"].rstrip("\n") != haved):
+ banner_cmd = "banner %s" % module.params["banner"]
+ banner_cmd += " {0}\n".format(multiline_delimiter)
+ banner_cmd += want["text"].strip("\n")
+ banner_cmd += "\n{0}".format(multiline_delimiter)
+ commands.append(banner_cmd)
+ return commands
+
+
+def map_config_to_obj(module):
+ """
+ This function gets the banner config without stripping any whitespaces,
+ and then fetches the required banner from it.
+ :param module:
+ :return: banner config dict object.
+ """
+ out = get_config(module, flags="| begin banner %s" % module.params["banner"])
+ if out:
+ regex = search("banner " + module.params["banner"] + " \\^C{1,}\n", out, M)
+ if regex:
+ regex = regex.group()
+ output = str((out.split(regex))[1].split("^C\n")[0])
+ else:
+ output = None
+ else:
+ output = None
+ obj = {"banner": module.params["banner"], "state": "absent"}
+ if output:
+ obj["text"] = output
+ obj["state"] = "present"
+ return obj
+
+
+def map_params_to_obj(module):
+ text = module.params["text"]
+ return {
+ "banner": module.params["banner"],
+ "text": text,
+ "multiline_delimiter": module.params["multiline_delimiter"],
+ "state": module.params["state"],
+ }
+
+
+def main():
+ """main entry point for module execution"""
+ argument_spec = dict(
+ banner=dict(required=True, choices=["login", "motd", "exec", "incoming", "slip-ppp"]),
+ multiline_delimiter=dict(default="@"),
+ text=dict(),
+ state=dict(default="present", choices=["present", "absent"]),
+ )
+ required_if = [("state", "present", ("text",))]
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_if=required_if,
+ supports_check_mode=True,
+ )
+ warnings = list()
+ result = {"changed": False}
+ if warnings:
+ result["warnings"] = warnings
+ want = map_params_to_obj(module)
+ have = map_config_to_obj(module)
+ commands = map_obj_to_commands((want, have), module)
+ result["commands"] = commands
+ if commands:
+ if not module.check_mode:
+ load_config(module, commands)
+ result["changed"] = True
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_bgp.py b/ansible_collections/cisco/ios/plugins/modules/ios_bgp.py
new file mode 100644
index 000000000..b01f99428
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_bgp.py
@@ -0,0 +1,504 @@
+#!/usr/bin/python
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_bgp
+author: Nilashish Chakraborty (@NilashishC)
+short_description: Module to configure BGP protocol settings.
+description:
+ - This module provides configuration management of global BGP parameters on devices
+ running Cisco IOS
+version_added: 1.0.0
+deprecated:
+ alternative: ios_bgp_global
+ why: Newer and updated modules released with more functionality
+ removed_at_date: "2023-08-24"
+notes:
+ - Tested against Cisco IOS Version 15.6(3)M2
+options:
+ config:
+ description:
+ - Specifies the BGP related configuration.
+ type: dict
+ suboptions:
+ bgp_as:
+ description:
+ - Specifies the BGP Autonomous System (AS) number to configure on the device.
+ type: int
+ required: true
+ router_id:
+ description:
+ - Configures the BGP routing process router-id value.
+ type: str
+ default:
+ log_neighbor_changes:
+ description:
+ - Enable/disable logging neighbor up/down and reset reason.
+ type: bool
+ neighbors:
+ description:
+ - Specifies BGP neighbor related configurations.
+ type: list
+ elements: dict
+ suboptions:
+ neighbor:
+ description:
+ - Neighbor router address.
+ required: true
+ type: str
+ remote_as:
+ description:
+ - Remote AS of the BGP neighbor to configure.
+ type: int
+ required: true
+ update_source:
+ description:
+ - Source of the routing updates.
+ type: str
+ password:
+ description:
+ - Password to authenticate the BGP peer connection.
+ type: str
+ enabled:
+ description:
+ - Administratively shutdown or enable a neighbor.
+ type: bool
+ description:
+ description:
+ - Neighbor specific description.
+ type: str
+ ebgp_multihop:
+ description:
+ - Specifies the maximum hop count for EBGP neighbors not on directly connected
+ networks.
+ - The range is from 1 to 255.
+ type: int
+ peer_group:
+ description:
+ - Name of the peer group that the neighbor is a member of.
+ type: str
+ timers:
+ description:
+ - Specifies BGP neighbor timer related configurations.
+ type: dict
+ suboptions:
+ keepalive:
+ description:
+ - Frequency (in seconds) with which the device sends keepalive messages
+ to its peer.
+ - The range is from 0 to 65535.
+ type: int
+ required: true
+ holdtime:
+ description:
+ - Interval (in seconds) after not receiving a keepalive message that
+ IOS declares a peer dead.
+ - The range is from 0 to 65535.
+ type: int
+ required: true
+ min_neighbor_holdtime:
+ description:
+ - Interval (in seconds) specifying the minimum acceptable hold-time
+ from a BGP neighbor.
+ - The minimum acceptable hold-time must be less than, or equal to,
+ the interval specified in the holdtime argument.
+ - The range is from 0 to 65535.
+ type: int
+ local_as:
+ description:
+ - The local AS number for the neighbor.
+ type: int
+ networks:
+ description:
+ - Specify Networks to announce via BGP.
+ - For operation replace, this option is mutually exclusive with networks option
+ under address_family.
+ - For operation replace, if the device already has an address family activated,
+ this option is not allowed.
+ type: list
+ elements: dict
+ suboptions:
+ prefix:
+ description:
+ - Network ID to announce via BGP.
+ required: true
+ type: str
+ masklen:
+ description:
+ - Subnet mask length for the Network to announce(e.g, 8, 16, 24, etc.).
+ type: int
+ route_map:
+ description:
+ - Route map to modify the attributes.
+ type: str
+ address_family:
+ description:
+ - Specifies BGP address family related configurations.
+ type: list
+ elements: dict
+ suboptions:
+ afi:
+ description:
+ - Type of address family to configure.
+ choices:
+ - ipv4
+ - ipv6
+ required: true
+ type: str
+ safi:
+ description:
+ - Specifies the type of cast for the address family.
+ choices:
+ - flowspec
+ - unicast
+ - multicast
+ - labeled-unicast
+ default: unicast
+ type: str
+ synchronization:
+ description:
+ - Enable/disable IGP synchronization.
+ type: bool
+ auto_summary:
+ description:
+ - Enable/disable automatic network number summarization.
+ type: bool
+ redistribute:
+ description:
+ - Specifies the redistribute information from another routing protocol.
+ type: list
+ elements: dict
+ suboptions:
+ protocol:
+ description:
+ - Specifies the protocol for configuring redistribute information.
+ choices:
+ - ospf
+ - ospfv3
+ - eigrp
+ - isis
+ - static
+ - connected
+ - odr
+ - lisp
+ - mobile
+ - rip
+ required: true
+ type: str
+ id:
+ description:
+ - Identifier for the routing protocol for configuring redistribute
+ information.
+ - Valid for protocols 'ospf', 'ospfv3' and 'eigrp'.
+ type: str
+ metric:
+ description:
+ - Specifies the metric for redistributed routes.
+ type: int
+ route_map:
+ description:
+ - Specifies the route map reference.
+ type: str
+ networks:
+ description:
+ - Specify Networks to announce via BGP.
+ - For operation replace, this option is mutually exclusive with root level
+ networks option.
+ type: list
+ elements: dict
+ suboptions:
+ prefix:
+ description:
+ - Network ID to announce via BGP.
+ required: true
+ type: str
+ masklen:
+ description:
+ - Subnet mask length for the Network to announce(e.g, 8, 16, 24, etc.).
+ type: int
+ route_map:
+ description:
+ - Route map to modify the attributes.
+ type: str
+ neighbors:
+ description:
+ - Specifies BGP neighbor related configurations in Address Family configuration
+ mode.
+ type: list
+ elements: dict
+ suboptions:
+ neighbor:
+ description:
+ - Neighbor router address.
+ required: true
+ type: str
+ advertisement_interval:
+ description:
+ - Minimum interval between sending BGP routing updates for this neighbor.
+ type: int
+ route_reflector_client:
+ description:
+ - Specify a neighbor as a route reflector client.
+ type: bool
+ route_server_client:
+ description:
+ - Specify a neighbor as a route server client.
+ type: bool
+ activate:
+ description:
+ - Enable the Address Family for this Neighbor.
+ type: bool
+ remove_private_as:
+ description:
+ - Remove the private AS number from outbound updates.
+ type: bool
+ next_hop_self:
+ description:
+ - Enable/disable the next hop calculation for this neighbor.
+ type: bool
+ next_hop_unchanged:
+ description:
+ - Propagate next hop unchanged for iBGP paths to this neighbor.
+ type: bool
+ maximum_prefix:
+ description:
+ - Maximum number of prefixes to accept from this peer.
+ - The range is from 1 to 2147483647.
+ type: int
+ prefix_list_in:
+ description:
+ - Name of ip prefix-list to apply to incoming prefixes.
+ type: str
+ prefix_list_out:
+ description:
+ - Name of ip prefix-list to apply to outgoing prefixes.
+ type: str
+ operation:
+ description:
+ - Specifies the operation to be performed on the BGP process configured on the
+ device.
+ - In case of merge, the input configuration will be merged with the existing BGP
+ configuration on the device.
+ - In case of replace, if there is a diff between the existing configuration and
+ the input configuration, the existing configuration will be replaced by the
+ input configuration for every option that has the diff.
+ - In case of override, all the existing BGP configuration will be removed from
+ the device and replaced with the input configuration.
+ - In case of delete the existing BGP configuration will be removed from the device.
+ default: merge
+ type: str
+ choices:
+ - merge
+ - replace
+ - override
+ - delete
+
+"""
+
+EXAMPLES = """
+- name: Configure global bgp as 64496
+ cisco.ios.ios_bgp:
+ config:
+ bgp_as: 64496
+ router_id: 192.0.2.1
+ log_neighbor_changes: true
+ neighbors:
+ - neighbor: 203.0.113.5
+ remote_as: 64511
+ timers:
+ keepalive: 300
+ holdtime: 360
+ min_neighbor_holdtime: 360
+ - neighbor: 198.51.100.2
+ remote_as: 64498
+ networks:
+ - prefix: 198.51.100.0
+ route_map: RMAP_1
+ - prefix: 192.0.2.0
+ masklen: 23
+ address_family:
+ - afi: ipv4
+ safi: unicast
+ redistribute:
+ - protocol: ospf
+ id: 223
+ metric: 10
+ operation: merge
+
+- name: Configure BGP neighbors
+ cisco.ios.ios_bgp:
+ config:
+ bgp_as: 64496
+ neighbors:
+ - neighbor: 192.0.2.10
+ remote_as: 64496
+ password: ansible
+ description: IBGP_NBR_1
+ ebgp_multihop: 100
+ timers:
+ keepalive: 300
+ holdtime: 360
+ min_neighbor_holdtime: 360
+ - neighbor: 192.0.2.15
+ remote_as: 64496
+ description: IBGP_NBR_2
+ ebgp_multihop: 150
+ operation: merge
+
+- name: Configure root-level networks for BGP
+ cisco.ios.ios_bgp:
+ config:
+ bgp_as: 64496
+ networks:
+ - prefix: 203.0.113.0
+ masklen: 27
+ route_map: RMAP_1
+ - prefix: 203.0.113.32
+ masklen: 27
+ route_map: RMAP_2
+ operation: merge
+
+- name: Configure BGP neighbors under address family mode
+ cisco.ios.ios_bgp:
+ config:
+ bgp_as: 64496
+ address_family:
+ - afi: ipv4
+ safi: unicast
+ neighbors:
+ - neighbor: 203.0.113.10
+ activate: true
+ maximum_prefix: 250
+ advertisement_interval: 120
+ - neighbor: 192.0.2.15
+ activate: true
+ route_reflector_client: true
+ operation: merge
+
+- name: Remove bgp as 64496 from config
+ cisco.ios.ios_bgp:
+ config:
+ bgp_as: 64496
+ operation: delete
+"""
+
+RETURN = """
+commands:
+ description: The list of configuration mode commands to send to the device
+ returned: always
+ type: list
+ sample:
+ - router bgp 64496
+ - bgp router-id 192.0.2.1
+ - bgp log-neighbor-changes
+ - neighbor 203.0.113.5 remote-as 64511
+ - neighbor 203.0.113.5 timers 300 360 360
+ - neighbor 198.51.100.2 remote-as 64498
+ - network 198.51.100.0 route-map RMAP_1
+ - network 192.0.2.0 mask 255.255.254.0
+ - address-family ipv4
+ - redistribute ospf 223 metric 70
+ - exit-address-family
+"""
+from ansible.module_utils._text import to_text
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.providers.cli.config.bgp.process import (
+ REDISTRIBUTE_PROTOCOLS,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.providers.module import (
+ NetworkModule,
+)
+
+
+def main():
+ """main entry point for module execution"""
+ network_spec = {"prefix": dict(required=True), "masklen": dict(type="int"), "route_map": dict()}
+ redistribute_spec = {
+ "protocol": dict(choices=REDISTRIBUTE_PROTOCOLS, required=True),
+ "id": dict(),
+ "metric": dict(type="int"),
+ "route_map": dict(),
+ }
+ timer_spec = {
+ "keepalive": dict(type="int", required=True),
+ "holdtime": dict(type="int", required=True),
+ "min_neighbor_holdtime": dict(type="int"),
+ }
+ neighbor_spec = {
+ "neighbor": dict(required=True),
+ "remote_as": dict(type="int", required=True),
+ "local_as": dict(type="int"),
+ "update_source": dict(),
+ "password": dict(no_log=True),
+ "enabled": dict(type="bool"),
+ "description": dict(),
+ "ebgp_multihop": dict(type="int"),
+ "timers": dict(type="dict", options=timer_spec),
+ "peer_group": dict(),
+ }
+ af_neighbor_spec = {
+ "neighbor": dict(required=True),
+ "activate": dict(type="bool"),
+ "advertisement_interval": dict(type="int"),
+ "remove_private_as": dict(type="bool"),
+ "next_hop_self": dict(type="bool"),
+ "next_hop_unchanged": dict(type="bool"),
+ "route_reflector_client": dict(type="bool"),
+ "route_server_client": dict(type="bool"),
+ "maximum_prefix": dict(type="int"),
+ "prefix_list_in": dict(),
+ "prefix_list_out": dict(),
+ }
+ address_family_spec = {
+ "afi": dict(choices=["ipv4", "ipv6"], required=True),
+ "safi": dict(
+ choices=["flowspec", "labeled-unicast", "multicast", "unicast"],
+ default="unicast",
+ ),
+ "auto_summary": dict(type="bool"),
+ "synchronization": dict(type="bool"),
+ "networks": dict(type="list", elements="dict", options=network_spec),
+ "redistribute": dict(type="list", elements="dict", options=redistribute_spec),
+ "neighbors": dict(type="list", elements="dict", options=af_neighbor_spec),
+ }
+ config_spec = {
+ "bgp_as": dict(type="int", required=True),
+ "router_id": dict(),
+ "log_neighbor_changes": dict(type="bool"),
+ "neighbors": dict(type="list", elements="dict", options=neighbor_spec),
+ "address_family": dict(type="list", elements="dict", options=address_family_spec),
+ "networks": dict(type="list", elements="dict", options=network_spec),
+ }
+ argument_spec = {
+ "config": dict(type="dict", options=config_spec),
+ "operation": dict(default="merge", choices=["merge", "replace", "override", "delete"]),
+ }
+ module = NetworkModule(argument_spec=argument_spec, supports_check_mode=True)
+ try:
+ result = module.edit_config(config_filter="| section ^router bgp")
+ except Exception as exc:
+ module.fail_json(msg=to_text(exc))
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_bgp_address_family.py b/ansible_collections/cisco/ios/plugins/modules/ios_bgp_address_family.py
new file mode 100644
index 000000000..2021d2aec
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_bgp_address_family.py
@@ -0,0 +1,3010 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2022 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+"""
+The module file for ios_bgp_address_family
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_bgp_address_family
+short_description: Resource module to configure BGP Address family.
+description: This module configures and manages the attributes of bgp address family on Cisco IOS.
+version_added: 1.2.0
+author:
+ - Sagar Paul (@KB-perByte)
+ - Sumit Jaiswal (@justjais)
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+ - The module examples uses callback plugin (stdout_callback = yaml) to generate task
+ output in yaml format.
+options:
+ config:
+ description: A list of configurations for bgp address family.
+ type: dict
+ suboptions:
+ as_number:
+ description: Autonomous system number.
+ type: str
+ address_family:
+ description: A list of configurations for bgp address family.
+ type: list
+ elements: dict
+ suboptions:
+ afi:
+ description: Address Family
+ type: str
+ choices:
+ ["ipv4", "ipv6", "l2vpn", "nsap", "rtfilter", "vpnv4", "vpnv6"]
+ safi:
+ description: Address Family modifier
+ type: str
+ choices: ["flowspec", "mdt", "multicast", "mvpn", "evpn", "unicast"]
+ vrf:
+ description: Specify parameters for a VPN Routing/Forwarding instance
+ type: str
+ aggregate_addresses:
+ description: Configure BGP aggregate entries
+ type: list
+ elements: dict
+ aliases:
+ - aggregate_address
+ suboptions:
+ address:
+ description: Aggregate address(A.B.C.D)
+ type: str
+ netmask:
+ description: Aggregate mask(A.B.C.D)
+ type: str
+ advertise_map:
+ description: Set condition to advertise attribute
+ type: str
+ as_confed_set:
+ description: Generate AS confed set path information
+ type: bool
+ as_set:
+ description: Generate AS set path information
+ type: bool
+ attribute_map:
+ description: Set attributes of aggregate
+ type: str
+ summary_only:
+ description: Filter more specific routes from updates
+ type: bool
+ suppress_map:
+ description: Conditionally filter more specific routes from updates
+ type: str
+ auto_summary:
+ description: Enable automatic network number summarization
+ type: bool
+ bgp:
+ description: Configure BGP aggregate entries
+ type: dict
+ suboptions:
+ additional_paths:
+ description: Additional paths in the BGP table
+ type: dict
+ suboptions:
+ receive:
+ description: Receive additional paths from neighbors
+ type: bool
+ select:
+ description: Selection criteria to pick the paths
+ type: dict
+ suboptions:
+ all:
+ description: Select all available paths
+ type: bool
+ backup:
+ description: Select backup path
+ type: bool
+ best:
+ description: Select best N paths (2-3).
+ type: int
+ best_external:
+ description: Select best-external path
+ type: bool
+ group_best:
+ description: Select group-best path
+ type: bool
+ send:
+ description: Send additional paths to neighbors
+ type: bool
+ install:
+ description: Additional paths to install into RIB
+ type: bool
+ aggregate_timer:
+ description:
+ - Configure Aggregation Timer
+ - Please refer vendor documentation for valid values
+ type: int
+ dampening:
+ description: Enable route-flap dampening
+ type: dict
+ suboptions:
+ penalty_half_time:
+ description:
+ - Half-life time for the penalty
+ - Please refer vendor documentation for valid values
+ type: int
+ reuse_route_val:
+ description:
+ - Value to start reusing a route
+ - Please refer vendor documentation for valid values
+ type: int
+ suppress_route_val:
+ description:
+ - Value to start suppressing a route
+ - Please refer vendor documentation for valid values
+ type: int
+ max_suppress:
+ description:
+ - Maximum duration to suppress a stable route
+ - Please refer vendor documentation for valid values
+ type: int
+ route_map:
+ description: Route-map to specify criteria for dampening
+ type: str
+ dmzlink_bw:
+ description: Use DMZ Link Bandwidth as weight for BGP multipaths
+ type: bool
+ nexthop:
+ description: Nexthop tracking commands
+ type: dict
+ suboptions:
+ route_map:
+ description: Route map for valid nexthops
+ type: str
+ trigger:
+ description: Nexthop triggering
+ type: dict
+ suboptions:
+ delay:
+ description:
+ - Set the delay to tigger nexthop tracking
+ - Please refer vendor documentation for valid values
+ type: int
+ enable:
+ description: Enable nexthop tracking
+ type: bool
+ redistribute_internal:
+ description: Allow redistribution of iBGP into IGPs (dangerous)
+ type: bool
+ route_map:
+ description:
+ - route-map control commands
+ - Have route-map set commands take priority over BGP commands such as next-hop unchanged
+ type: bool
+ scan_time:
+ description:
+ - Configure background scanner interval
+ - Please refer vendor documentation for valid values
+ type: int
+ slow_peer:
+ description:
+ - Nexthop triggering
+ - This option is DEPRECATED and replaced with slow_peer_options,
+ this attribute will be removed after 2025-01-01.
+ type: list
+ elements: dict
+ suboptions:
+ detection:
+ description: Slow-peer detection
+ type: dict
+ suboptions:
+ enable:
+ description: Enable slow-peer detection
+ type: bool
+ threshold:
+ description:
+ - Set the slow-peer detection threshold
+ - Threshold value (seconds)
+ - Please refer vendor documentation for valid values
+ type: int
+ split_update_group:
+ description: Configure slow-peer split-update-group
+ type: dict
+ suboptions:
+ dynamic:
+ description: Dynamically split the slow peer to slow-update group
+ type: bool
+ permanent:
+ description: Keep the slow-peer permanently in slow-update group
+ type: bool
+ slow_peer_options:
+ description: Nexthop triggering
+ type: dict
+ suboptions:
+ detection:
+ description: Slow-peer detection
+ type: dict
+ suboptions:
+ enable:
+ description: Enable slow-peer detection
+ type: bool
+ threshold:
+ description:
+ - Set the slow-peer detection threshold
+ - Threshold value (seconds)
+ - Please refer vendor documentation for valid values
+ type: int
+ split_update_group:
+ description: Configure slow-peer split-update-group
+ type: dict
+ suboptions:
+ dynamic:
+ description: Dynamically split the slow peer to slow-update group
+ type: bool
+ permanent:
+ description: Keep the slow-peer permanently in slow-update group
+ type: bool
+ soft_reconfig_backup:
+ description: Use soft-reconfiguration inbound only when route-refresh is not negotiated
+ type: bool
+ update_group:
+ description:
+ - Manage peers in bgp update groups
+ - Split update groups based on Policy
+ - Keep peers with as-override in different update groups
+ type: bool
+ default:
+ description: Set a command to its defaults
+ type: bool
+ default_information:
+ description:
+ - Distribution of default information
+ - Distribute default route
+ type: bool
+ default_metric:
+ description: Set metric of redistributed routes
+ type: int
+ distance:
+ description: Define an administrative distance
+ type: dict
+ suboptions:
+ external:
+ description: Distance for routes external to the AS
+ type: int
+ internal:
+ description: Distance for routes internal to the AS
+ type: int
+ local:
+ description: Distance for local routes
+ type: int
+ neighbors:
+ description: Specify a neighbor router
+ type: list
+ elements: dict
+ aliases:
+ - neighbor
+ suboptions:
+ neighbor_address:
+ description:
+ - Neighbor address (A.B.C.D)
+ - Neighbor tag
+ - Neighbor ipv6 address (X:X:X:X::X)
+ type: str
+ address:
+ description:
+ - Neighbor address (A.B.C.D)
+ - This option is DEPRECATED and replaced with neighbor_address,
+ this attribute will be removed after 2025-01-01.
+ type: str
+ tag:
+ description:
+ - Neighbor tag
+ - This option is DEPRECATED and replaced with neighbor_address,
+ this attribute will be removed after 2025-01-01.
+ type: str
+ ipv6_address:
+ description:
+ - Neighbor ipv6 address (X:X:X:X::X)
+ - This option is DEPRECATED and replaced with neighbor_address,
+ this attribute will be removed after 2025-01-01.
+ type: str
+ aliases:
+ - ipv6_adddress
+ activate:
+ description: Enable the Address Family for this Neighbor
+ type: bool
+ additional_paths:
+ description: Negotiate additional paths capabilities with this neighbor
+ type: dict
+ suboptions:
+ disable:
+ description: Disable additional paths for this neighbor
+ type: bool
+ receive:
+ description: Receive additional paths from neighbors
+ type: bool
+ send:
+ description: Send additional paths to this neighbor
+ type: bool
+ advertise:
+ description:
+ - Advertise to this neighbor
+ - Advertise additional paths
+ type: dict
+ suboptions:
+ all:
+ description: Select all available paths
+ type: bool
+ best:
+ description: Select best N paths (2-3).
+ type: int
+ group_best:
+ description: Select group-best path
+ type: bool
+ advertises:
+ description: Advertise to this neighbor
+ type: dict
+ suboptions:
+ additional_paths:
+ description: Advertise additional paths
+ type: dict
+ suboptions:
+ all:
+ description: Select all available paths
+ type: bool
+ best:
+ description: Select best N paths (2-3).
+ type: int
+ group_best:
+ description: Select group-best path
+ type: bool
+ best_external:
+ description: Advertise best-external (at RRs best-internal) path
+ type: bool
+ diverse_path:
+ description: Advertise additional paths
+ type: dict
+ suboptions:
+ backup:
+ description: Diverse path can be backup path
+ type: bool
+ mpath:
+ description: Diverse path can be multipath
+ type: bool
+ advertise_map:
+ description: specify route-map for conditional advertisement
+ type: dict
+ suboptions:
+ name:
+ description: advertise route-map name
+ type: str
+ exist_map:
+ description:
+ - advertise prefix only if prefix is in the condition exists
+ - condition route-map name
+ type: str
+ non_exist_map:
+ description:
+ - advertise prefix only if prefix in the condition does not exist
+ - condition route-map name
+ type: str
+ advertisement_interval:
+ description: Minimum interval between sending BGP routing updates
+ type: int
+ aigp:
+ description: Enable a AIGP on neighbor
+ type: dict
+ suboptions:
+ enable:
+ description: Enable a AIGP on neighbor
+ type: str
+ send:
+ description: Cost community or MED carrying AIGP VALUE
+ type: dict
+ suboptions:
+ cost_community:
+ description: Cost extended community carrying AIGP Value
+ type: dict
+ suboptions:
+ id:
+ description:
+ - Community ID
+ - Please refer vendor documentation for valid values
+ type: int
+ poi:
+ description: Point of Insertion
+ type: dict
+ suboptions:
+ igp_cost:
+ description: Point of Insertion After IGP
+ type: bool
+ pre_bestpath:
+ description: Point of Insertion At Beginning
+ type: bool
+ transitive:
+ description: Cost community is Transitive
+ type: bool
+ med:
+ description: Med carrying AIGP Value
+ type: bool
+ allow_policy:
+ description: Enable the policy support for this IBGP Neighbor
+ type: bool
+ allowas_in:
+ description:
+ - Accept as-path with my AS present in it
+ - Please refer vendor documentation for valid values
+ type: int
+ as_override:
+ description: Override matching AS-number while sending update
+ type: dict
+ suboptions:
+ set:
+ description: Enable AS override
+ type: bool
+ split_horizon:
+ description: Maintain Split Horizon while sending update
+ type: bool
+ bmp_activate:
+ description: Activate the BMP monitoring for a BGP peer
+ type: dict
+ suboptions:
+ all:
+ description: Activate BMP monitoring for all servers
+ type: bool
+ server:
+ description:
+ - Activate BMP for server
+ - BMP Server Number
+ - Please refer vendor documentation for valid values
+ type: int
+ capability:
+ description:
+ - Advertise capability to the peer
+ - Advertise ORF capability to the peer
+ - Advertise prefixlist ORF capability to this neighbor
+ type: dict
+ suboptions:
+ both:
+ description: Capability to SEND and RECEIVE the ORF to/from this neighbor
+ type: bool
+ receive:
+ description: Capability to RECEIVE the ORF from this neighbor
+ type: bool
+ send:
+ description: Capability to SEND the ORF to this neighbor
+ type: bool
+ cluster_id:
+ description:
+ - Configure Route-Reflector Cluster-id (peers may reset)
+ - Route-Reflector Cluster-id as 32 bit quantity, or
+ Route-Reflector Cluster-id in IP address format (A.B.C.D)
+ type: str
+ default_originate:
+ description: Originate default route to this neighbor
+ type: dict
+ suboptions:
+ set:
+ description: Set default route to this neighbor
+ type: bool
+ route_map:
+ description: Route-map to specify criteria to originate default
+ type: str
+ description:
+ description: Neighbor specific description
+ type: str
+ disable_connected_check:
+ description: one-hop away EBGP peer using loopback address
+ type: bool
+ distribute_list:
+ description: Filter updates to/from this neighbor
+ type: dict
+ suboptions:
+ acl:
+ description: ACL id/name
+ type: str
+ in:
+ description: Filter incoming updates
+ type: bool
+ out:
+ description: Filter outgoing updates
+ type: bool
+ dmzlink_bw:
+ description: Propagate the DMZ link bandwidth
+ type: bool
+ ebgp_multihop:
+ description: Allow EBGP neighbors not on directly connected networks
+ type: dict
+ suboptions:
+ enable:
+ description: Allow EBGP neighbors not on directly connected networks
+ type: bool
+ hop_count:
+ description:
+ - Maximum hop count
+ - Please refer vendor documentation for valid values
+ type: int
+ fall_over:
+ description: Session fall on peer route lost
+ type: dict
+ suboptions:
+ bfd:
+ description: Use BFD to detect failure
+ type: dict
+ suboptions:
+ set:
+ description: set bfd
+ type: bool
+ multi_hop:
+ description: Force BFD multi-hop to detect failure
+ type: bool
+ single_hop:
+ description: Force BFD single-hop to detect failure
+ type: bool
+ route_map:
+ description: Route map for peer route
+ type: str
+ filter_list:
+ description: Establish BGP filters
+ type: dict
+ suboptions:
+ as_path_acl:
+ description:
+ - AS path access list
+ - Please refer vendor documentation for valid values
+ type: int
+ in:
+ description: Filter incoming updates
+ type: bool
+ out:
+ description: Filter outgoing updates
+ type: bool
+ ha_mode:
+ description: high availability mode
+ type: dict
+ suboptions:
+ set:
+ description: set ha-mode and graceful-restart for this peer
+ type: bool
+ disable:
+ description: disable graceful-restart
+ type: bool
+ inherit:
+ description:
+ - Inherit a template
+ - Inherit a peer-policy template
+ type: str
+ internal_vpn_client:
+ description: Stack iBGP-CE Neighbor Path in ATTR_SET for vpn update
+ type: bool
+ local_as:
+ description: Specify a local-as number
+ type: dict
+ suboptions:
+ set:
+ description: set local-as number
+ type: bool
+ number:
+ description:
+ - AS number used as local AS
+ - Please refer vendor documentation for valid values
+ type: int
+ dual_as:
+ description: Accept either real AS or local AS from the ebgp peer
+ type: bool
+ no_prepend:
+ description: Do not prepend local-as to updates from ebgp peers
+ type: dict
+ suboptions:
+ set:
+ description: Set prepend
+ type: bool
+ replace_as:
+ description: Replace real AS with local AS in the EBGP updates
+ type: bool
+ log_neighbor_changes:
+ description: Log neighbor up/down and reset reason
+ type: dict
+ suboptions:
+ set:
+ description: set Log neighbor up/down and reset
+ type: bool
+ disable:
+ description: disable Log neighbor up/down and reset
+ type: bool
+ maximum_prefix:
+ description: Establish BGP filters
+ type: dict
+ suboptions:
+ number:
+ description:
+ - maximum no. of prefix limit
+ - Please refer vendor documentation for valid values
+ type: int
+ threshold_value:
+ description:
+ - Threshold value (%) at which to generate a warning msg
+ - Please refer vendor documentation for valid values
+ type: int
+ restart:
+ description: Restart bgp connection after limit is exceeded
+ type: int
+ warning_only:
+ description: Only give warning message when limit is exceeded
+ type: bool
+ next_hop_self:
+ description:
+ - Disable the next hop calculation for this neighbor
+ - This option is DEPRECATED and is replaced with nexthop_self which
+ accepts dict as input this attribute will be removed after 2023-06-01.
+ type: bool
+ nexthop_self:
+ description: Disable the next hop calculation for this neighbor
+ type: dict
+ suboptions:
+ set:
+ description: set the next hop self
+ type: bool
+ all:
+ description: Enable next-hop-self for both eBGP and iBGP received paths
+ type: bool
+ next_hop_unchanged:
+ description:
+ - Propagate next hop unchanged for iBGP paths to this neighbor
+ - Propagate next hop unchanged for all paths (iBGP and eBGP) to this neighbor
+ type: dict
+ suboptions:
+ set:
+ description: Enable next-hop-unchanged
+ type: bool
+ allpaths:
+ description: Propagate next hop unchanged for all paths (iBGP and eBGP) to this neighbor
+ type: bool
+ password:
+ description:
+ - Set a password
+ - This option is DEPRECATED and is replaced with password_options which
+ accepts dict as input, this attribute will be removed after 2024-06-01.
+ type: str
+ password_options:
+ description: Set a password with encryption type
+ type: dict
+ suboptions:
+ encryption:
+ description: Encryption type (0 to disable encryption, 7 for proprietary)
+ type: int
+ pass_key:
+ description: The password
+ type: str
+ path_attribute:
+ description: BGP optional attribute filtering
+ type: dict
+ suboptions:
+ discard:
+ description: Discard matching path-attribute for this neighbor
+ type: dict
+ suboptions:
+ type:
+ description:
+ - path attribute type
+ - Please refer vendor documentation for valid values
+ type: int
+ range:
+ description: path attribute range
+ type: dict
+ suboptions:
+ start:
+ description:
+ - path attribute range start value
+ - Please refer vendor documentation for valid values
+ type: int
+ end:
+ description:
+ - path attribute range end value
+ - Please refer vendor documentation for valid values
+ type: int
+ in:
+ description: Perform inbound path-attribute filtering
+ type: bool
+ treat_as_withdraw:
+ description: Treat-as-withdraw matching path-attribute for this neighbor
+ type: dict
+ suboptions:
+ type:
+ description:
+ - path attribute type
+ - Please refer vendor documentation for valid values
+ type: int
+ range:
+ description: path attribute range
+ type: dict
+ suboptions:
+ start:
+ description:
+ - path attribute range start value
+ - Please refer vendor documentation for valid values
+ type: int
+ end:
+ description:
+ - path attribute range end value
+ - Please refer vendor documentation for valid values
+ type: int
+ in:
+ description: Perform inbound path-attribute filtering
+ type: bool
+ peer_group:
+ description: Member of the peer-group
+ type: bool
+ peer_group_name:
+ description: Member of the peer-group
+ type: str
+ prefix_list:
+ description:
+ - Filter updates to/from this neighbor
+ - This option is DEPRECATED and is replaced with prefix_lists which
+ accepts list of dict as input
+ type: dict
+ suboptions:
+ name:
+ description: Name of a prefix list
+ type: str
+ in:
+ description: Filter incoming updates
+ type: bool
+ out:
+ description: Filter outgoing updates
+ type: bool
+ prefix_lists:
+ description: Filter updates to/from this neighbor
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Name of a prefix list
+ type: str
+ in:
+ description: Filter incoming updates
+ type: bool
+ out:
+ description: Filter outgoing updates
+ type: bool
+ remote_as:
+ description:
+ - Specify a BGP neighbor
+ - AS of remote neighbor
+ type: int
+ remove_private_as:
+ description: Remove private AS number from outbound updates
+ type: dict
+ suboptions:
+ set:
+ description: Remove private AS number from outbound updates
+ type: bool
+ all:
+ description: Remove all private AS numbers
+ type: bool
+ replace_as:
+ description: Replace all private AS numbers with local AS
+ type: bool
+ route_map:
+ description:
+ - Apply route map to neighbor
+ - This option is DEPRECATED and is replaced with route_maps which
+ accepts list of dict as input
+ type: dict
+ suboptions:
+ name:
+ description: Name of route map
+ type: str
+ in:
+ description: Apply map to incoming routes
+ type: bool
+ out:
+ description: Apply map to outbound routes
+ type: bool
+ route_maps:
+ description: Apply route map to neighbor
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Name of route map
+ type: str
+ in:
+ description: Apply map to incoming routes
+ type: bool
+ out:
+ description: Apply map to outbound routes
+ type: bool
+ route_reflector_client:
+ description: Configure a neighbor as Route Reflector client
+ type: bool
+ route_server_client:
+ description: Configure a neighbor as Route Server client
+ type: bool
+ send_community:
+ description: Send Community attribute to this neighbor
+ type: dict
+ suboptions:
+ set:
+ description:
+ - Send Standard Community attribute.
+ - Maintains backwards compatibility for configurations that do not specify a send-community type.
+ type: bool
+ both:
+ description: Send Standard and Extended Community attributes
+ type: bool
+ extended:
+ description: Send Extended Community attribute
+ type: bool
+ standard:
+ description: Send Standard Community attribute
+ type: bool
+ shutdown:
+ description: Administratively shut down this neighbor
+ type: dict
+ suboptions:
+ set:
+ description: shut down
+ type: bool
+ graceful:
+ description:
+ - Gracefully shut down this neighbor
+ - time in seconds
+ - Please refer vendor documentation for valid values
+ type: int
+ slow_peer:
+ description:
+ - Configure slow-peer
+ - This option is DEPRECATED and replaced with slow_peer_options,
+ this attribute will be removed after 2025-01-01.
+ type: list
+ elements: dict
+ suboptions:
+ detection:
+ description: Configure slow-peer
+ type: dict
+ suboptions:
+ enable:
+ description: Enable slow-peer detection
+ type: bool
+ disable:
+ description: Disable slow-peer detection
+ type: bool
+ threshold:
+ description: Set the slow-peer detection threshold
+ type: int
+ split_update_group:
+ description: Configure slow-peer
+ type: dict
+ suboptions:
+ dynamic:
+ description: Configure slow-peer
+ type: dict
+ suboptions:
+ enable:
+ description: Configure slow-peer
+ type: bool
+ disable:
+ description: Configure slow-peer
+ type: bool
+ permanent:
+ description: Configure slow-peer
+ type: bool
+ static:
+ description: Configure slow-peer
+ type: bool
+ slow_peer_options:
+ description: Configure slow-peer options
+ type: dict
+ suboptions:
+ detection:
+ description: Configure slow-peer
+ type: dict
+ suboptions:
+ enable:
+ description: Enable slow-peer detection
+ type: bool
+ disable:
+ description: Disable slow-peer detection
+ type: bool
+ threshold:
+ description: Set the slow-peer detection threshold
+ type: int
+ split_update_group:
+ description: Configure slow-peer
+ type: dict
+ suboptions:
+ dynamic:
+ description: Configure slow-peer
+ type: dict
+ suboptions:
+ enable:
+ description: Configure slow-peer
+ type: bool
+ disable:
+ description: Configure slow-peer
+ type: bool
+ permanent:
+ description: Configure slow-peer
+ type: bool
+ static:
+ description: Configure slow-peer
+ type: bool
+ soft_reconfiguration:
+ description:
+ - Per neighbor soft reconfiguration
+ - Allow inbound soft reconfiguration for this neighbor
+ type: bool
+ soo:
+ description: Site-of-Origin extended community
+ type: str
+ timers:
+ description: BGP per neighbor timers
+ type: dict
+ suboptions:
+ interval:
+ description: Keepalive interval
+ type: int
+ holdtime:
+ description: Holdtime
+ type: int
+ min_holdtime:
+ description: Minimum hold time from neighbor
+ type: int
+ transport:
+ description: Transport options
+ type: dict
+ suboptions:
+ connection_mode:
+ description: Specify passive or active connection
+ type: dict
+ suboptions:
+ active:
+ description: Actively establish the TCP session
+ type: bool
+ passive:
+ description: Passively establish the TCP session
+ type: bool
+ multi_session:
+ description: Use Multi-session for transport
+ type: bool
+ path_mtu_discovery:
+ description: Use transport path MTU discovery
+ type: dict
+ suboptions:
+ set:
+ description: Use path MTU discovery
+ type: bool
+ disable:
+ description: disable
+ type: bool
+ ttl_security:
+ description:
+ - BGP ttl security check
+ - maximum number of hops
+ - Please refer vendor documentation for valid values
+ type: int
+ unsuppress_map:
+ description: Route-map to selectively unsuppress suppressed routes
+ type: str
+ version:
+ description:
+ - Set the BGP version to match a neighbor
+ - Neighbor's BGP version
+ - Please refer vendor documentation for valid values
+ type: int
+ weight:
+ description: Set default weight for routes from this neighbor
+ type: int
+ networks:
+ description: Specify a network to announce via BGP
+ type: list
+ elements: dict
+ aliases:
+ - network
+ suboptions:
+ address:
+ description: Network number (A.B.C.D)
+ type: str
+ mask:
+ description: Network mask (A.B.C.D)
+ type: str
+ backdoor:
+ description: Specify a BGP backdoor route
+ type: bool
+ evpn:
+ description: Advertise or Export to EVPN address-family
+ type: bool
+ route_map:
+ description: Route-map to modify the attributes
+ type: str
+ redistribute:
+ description:
+ - Redistribute information from another routing protocol
+ type: list
+ elements: dict
+ suboptions:
+ application:
+ description: Application
+ type: dict
+ suboptions:
+ name:
+ description: Application name
+ type: str
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ bgp:
+ description: Border Gateway Protocol (BGP)
+ type: dict
+ suboptions:
+ as_number:
+ description: Autonomous system number
+ type: str
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ connected:
+ description: Connected
+ type: dict
+ suboptions:
+ set:
+ description:
+ - Redistribute automatically established IP connected routes.
+ - This only needs to be set if metric or route_map aren't used.
+ type: bool
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ eigrp:
+ description: Enhanced Interior Gateway Routing Protocol (EIGRP)
+ type: dict
+ suboptions:
+ as_number:
+ description: Autonomous system number
+ type: str
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ isis:
+ description: ISO IS-IS
+ type: dict
+ suboptions:
+ area_tag:
+ description: ISO routing area tag
+ type: str
+ clns:
+ description: Redistribution of OSI dynamic routes
+ type: bool
+ ip:
+ description: Redistribution of IP dynamic routes
+ type: bool
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ iso_igrp:
+ description: IGRP for OSI networks
+ type: dict
+ suboptions:
+ area_tag:
+ description: ISO routing area tag
+ type: str
+ route_map:
+ description: Route map reference
+ type: str
+ lisp:
+ description: Locator ID Separation Protocol (LISP)
+ type: dict
+ suboptions:
+ set:
+ description: Set the top level attribute
+ type: bool
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ mobile:
+ description: Mobile routes
+ type: dict
+ suboptions:
+ set:
+ description: Set the top level attribute
+ type: bool
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ odr:
+ description: On Demand stub Routes
+ type: dict
+ suboptions:
+ set:
+ description: Set the top level attribute
+ type: bool
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ ospf:
+ description: Open Shortest Path First (OSPF)
+ type: dict
+ suboptions:
+ process_id:
+ description: Process ID
+ type: int
+ include_connected:
+ description: Include connected. Only applicable under IPv6 AFI
+ type: bool
+ match:
+ description: Redistribute matched routes
+ type: dict
+ suboptions:
+ external:
+ description:
+ - Redistribute OSPF external routes
+ - This option is DEPRECATED and replaced with externals option,
+ this attribute will be removed after 2025-01-01.
+ type: bool
+ externals:
+ description: Redistribute OSPF external routes
+ type: dict
+ suboptions:
+ type_1:
+ description: Redistribute OSPF External type 1 routes
+ type: bool
+ type_2:
+ description: Redistribute OSPF External type 1 routes
+ type: bool
+ internal:
+ description: Redistribute OSPF internal routes
+ type: bool
+ nssa_external:
+ description:
+ - Redistribute OSPF NSSA external routes
+ - This option is DEPRECATED and replaced with nssa_externals option,
+ this attribute will be removed after 2025-01-01.
+ type: bool
+ type_1:
+ description:
+ - Redistribute NSSA external type 1 routes
+ - This option is DEPRECATED and replaced with nssa_externals.type_1 option,
+ this attribute will be removed after 2025-01-01.
+ type: bool
+ type_2:
+ description:
+ - Redistribute NSSA external type 2 routes
+ - This option is DEPRECATED and replaced with nssa_externals.type_2 option,
+ this attribute will be removed after 2025-01-01.
+ type: bool
+ nssa_externals:
+ description: Redistribute OSPF NSSA external routes
+ type: dict
+ suboptions:
+ type_1:
+ description: Redistribute NSSA external type 1 routes
+ type: bool
+ type_2:
+ description: Redistribute NSSA external type 2 routes
+ type: bool
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ vrf:
+ description: VPN Routing/Forwarding Instance
+ type: str
+ ospfv3:
+ description: OSPFv3
+ type: dict
+ suboptions:
+ process_id:
+ description: Process ID
+ type: int
+ match:
+ description: Redistribute matched routes
+ type: dict
+ suboptions:
+ external:
+ description:
+ - Redistribute OSPF external routes
+ - This option is DEPRECATED and replaced with externals,
+ this attribute will be removed after 2025-01-01.
+ type: bool
+ externals:
+ description: Redistribute OSPF external routes
+ type: dict
+ suboptions:
+ type_1:
+ description: Redistribute OSPF External type 1 routes
+ type: bool
+ type_2:
+ description: Redistribute OSPF External type 1 routes
+ type: bool
+ internal:
+ description: Redistribute OSPF internal routes
+ type: bool
+ nssa_external:
+ description:
+ - Redistribute OSPF internal routes
+ - This option is DEPRECATED and replaced with nssa_externals,
+ this attribute will be removed after 2025-01-01.
+ type: bool
+ type_1:
+ description:
+ - Redistribute NSSA external type 1 routes
+ - This option is DEPRECATED and replaced with nssa_externals.type_1 option,
+ this attribute will be removed after 2025-01-01.
+ type: bool
+ type_2:
+ description:
+ - Redistribute NSSA external type 2 routes
+ - This option is DEPRECATED and replaced with nssa_externals.type_2 option,
+ this attribute will be removed after 2025-01-01.
+ type: bool
+ nssa_externals:
+ description: Redistribute OSPF NSSA external routes
+ type: dict
+ suboptions:
+ type_1:
+ description: Redistribute NSSA external type 1 routes
+ type: bool
+ type_2:
+ description: Redistribute NSSA external type 2 routes
+ type: bool
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ rip:
+ description: Routing Information Protocol (RIP)
+ type: dict
+ suboptions:
+ set:
+ description: Set the top level attribute
+ type: bool
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ static:
+ description: Static routes
+ type: dict
+ suboptions:
+ set:
+ description: Set the top level attribute
+ type: bool
+ clns:
+ description: Redistribution of OSI static routes
+ type: bool
+ ip:
+ description: Redistribution of IP static routes
+ type: bool
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ vrf:
+ description: Specify a source VRF
+ type: dict
+ suboptions:
+ name:
+ description: Source VRF name
+ type: str
+ global:
+ description: global VRF
+ type: bool
+ snmp:
+ description: Modify snmp parameters
+ type: dict
+ suboptions:
+ context:
+ description:
+ - Configure a SNMP context
+ - Context Name
+ type: dict
+ suboptions:
+ name:
+ description: Context Name
+ type: str
+ community:
+ description: Configure a SNMP v2c Community string and access privs
+ type: dict
+ suboptions:
+ snmp_community:
+ description: SNMP community string
+ type: str
+ acl:
+ description:
+ - Standard IP accesslist allowing access with this community string
+ - Expanded IP accesslist allowing access with this community string
+ - Access-list name
+ type: str
+ ipv6:
+ description:
+ - Specify IPv6 Named Access-List
+ - IPv6 Access-list name
+ type: str
+ ro:
+ description: Read-only access with this community string
+ type: bool
+ rw:
+ description: Read-write access with this community string
+ type: bool
+ user:
+ description: Configure a SNMP v3 user
+ type: dict
+ suboptions:
+ name:
+ description: SNMP community string
+ type: str
+ access:
+ description: specify an access-list associated with this group
+ type: dict
+ suboptions:
+ acl:
+ description: SNMP community string
+ type: str
+ ipv6:
+ description:
+ - Specify IPv6 Named Access-List
+ - IPv6 Access-list name
+ type: str
+ auth:
+ description: authentication parameters for the user
+ type: dict
+ suboptions:
+ md5:
+ description:
+ - Use HMAC MD5 algorithm for authentication
+ - authentication password for user
+ type: str
+ sha:
+ description:
+ - Use HMAC SHA algorithm for authentication
+ - authentication password for user
+ type: str
+ priv:
+ description: encryption parameters for the user
+ type: dict
+ suboptions:
+ des:
+ description: Use 56 bit DES algorithm for encryption
+ type: str
+ des56:
+ description: Use 56 bit DES algorithm for encryption
+ type: str
+ aes128:
+ description: Use 128 bit AES algorithm for encryption
+ type: str
+ aes192:
+ description: Use 192 bit 3DES algorithm for encryption
+ type: str
+ aes256:
+ description: Use 256 bit DES algorithm for encryption
+ type: str
+ credential:
+ description: If the user password is already configured and saved
+ type: bool
+ encrypted:
+ description: specifying passwords as MD5 or SHA digests
+ type: bool
+ table_map:
+ description: Map external entry attributes into routing table
+ type: dict
+ suboptions:
+ name:
+ description: route-map name
+ type: str
+ filter:
+ description: Selective route download
+ type: bool
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS
+ device by executing the command B(sh running-config | section ^router bgp).
+ - The state I(parsed) reads the configuration from C(running_config)
+ option and transforms it into Ansible structured data as per the
+ resource module's argspec and the value is then returned in the
+ I(parsed) key within the result.
+ type: str
+ state:
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - rendered
+ - parsed
+ default: merged
+ description:
+ - The state the configuration should be left in
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device.
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result. For state I(rendered) active connection to remote host is
+ not required.
+ - The state I(gathered) will fetch the running configuration from device and transform
+ it into structured data in the format as per the resource module argspec and
+ the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result. The value of C(running_config)
+ option should be the same format as the output of command I(show running-config
+ | include ip route|ipv6 route) executed on device. For state I(parsed) active
+ connection to remote host is not required.
+ type: str
+"""
+
+EXAMPLES = """
+# Using merged
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp log-neighbor-changes
+# bgp nopeerup-delay cold-boot 20
+
+- name: Merge provided configuration with device configuration
+ cisco.ios.ios_bgp_address_family:
+ config:
+ as_number: 65000
+ address_family:
+ - afi: ipv4
+ safi: multicast
+ vrf: blue
+ aggregate_address:
+ - address: 192.0.2.1
+ netmask: 255.255.255.255
+ as_confed_set: true
+ bgp:
+ aggregate_timer: 10
+ dampening:
+ penalty_half_time: 1
+ reuse_route_val: 1
+ suppress_route_val: 1
+ max_suppress: 1
+ slow_peer:
+ - detection:
+ threshold: 150
+ neighbor:
+ - address: 198.51.100.1
+ aigp:
+ send:
+ cost_community:
+ id: 100
+ poi:
+ igp_cost: true
+ transitive: true
+ slow_peer:
+ - detection:
+ threshold: 150
+ remote_as: 10
+ route_map:
+ - name: test-route-out
+ out: true
+ - name: test-route-in
+ in: true
+ route_server_client: true
+ network:
+ - address: 198.51.110.10
+ mask: 255.255.255.255
+ backdoor: true
+ snmp:
+ context:
+ name: snmp_con
+ community:
+ snmp_community: community
+ ro: true
+ acl: 10
+ - afi: ipv4
+ safi: mdt
+ bgp:
+ dmzlink_bw: true
+ dampening:
+ penalty_half_time: 1
+ reuse_route_val: 10
+ suppress_route_val: 100
+ max_suppress: 5
+ soft_reconfig_backup: true
+ - afi: ipv4
+ safi: multicast
+ aggregate_address:
+ - address: 192.0.3.1
+ netmask: 255.255.255.255
+ as_confed_set: true
+ default_metric: 12
+ distance:
+ external: 10
+ internal: 10
+ local: 100
+ network:
+ - address: 198.51.111.11
+ mask: 255.255.255.255
+ route_map: test
+ table_map:
+ name: test_tableMap
+ filter: true
+ state: merged
+
+# Task Output:
+# ------------
+#
+# before: {}
+# commands:
+# - router bgp 65000
+# - address-family ipv4 multicast vrf blue
+# - bgp aggregate-timer 10
+# - bgp dampening 1 1 1 1
+# - bgp slow-peer detection threshold 150
+# - snmp context snmp_con community community ro 10
+# - neighbor 198.51.100.1 remote-as 10
+# - neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive
+# - neighbor 198.51.100.1 slow-peer detection threshold 150
+# - network 198.51.110.10 mask 255.255.255.255 backdoor
+# - aggregate-address 192.0.2.1 255.255.255.255 as-confed-set
+# - address-family ipv4 multicast
+# - default-metric 12
+# - distance bgp 10 10 100
+# - table-map test_tableMap filter
+# - network 198.51.111.11 mask 255.255.255.255 route-map test
+# - aggregate-address 192.0.3.1 255.255.255.255 as-confed-set
+# - address-family ipv4 mdt
+# - bgp dmzlink-bw
+# - bgp soft-reconfig-backup
+# - bgp dampening 1 10 100 5
+# after:
+# address_family:
+# - afi: ipv4
+# aggregate_addresses:
+# - address: 192.0.2.1
+# as_confed_set: true
+# netmask: 255.255.255.255
+# bgp:
+# aggregate_timer: 10
+# dampening:
+# max_suppress: 1
+# penalty_half_time: 1
+# reuse_route_val: 1
+# suppress_route_val: 1
+# slow_peer_options:
+# detection:
+# threshold: 150
+# neighbors:
+# - activate: true
+# aigp:
+# send:
+# cost_community:
+# id: 100
+# poi:
+# igp_cost: true
+# transitive: true
+# neighbor_address: 198.51.100.1
+# slow_peer_options:
+# detection:
+# threshold: 150
+# networks:
+# - address: 198.51.110.10
+# backdoor: true
+# mask: 255.255.255.255
+# snmp:
+# context:
+# community:
+# acl: '10'
+# ro: true
+# snmp_community: community
+# name: snmp_con
+# - afi: ipv4
+# aggregate_addresses:
+# - address: 192.0.3.1
+# as_confed_set: true
+# netmask: 255.255.255.255
+# default_metric: 12
+# distance:
+# external: 10
+# internal: 10
+# local: 100
+# networks:
+# - address: 198.51.111.11
+# mask: 255.255.255.255
+# route_map: test
+# safi: multicast
+# table_map:
+# filter: true
+# name: test_tableMap
+# - afi: ipv4
+# bgp:
+# dampening:
+# max_suppress: 5
+# penalty_half_time: 1
+# reuse_route_val: 10
+# suppress_route_val: 100
+# dmzlink_bw: true
+# soft_reconfig_backup: true
+# safi: mdt
+# as_number: '65000'
+
+# After state:
+# ------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp log-neighbor-changes
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# snmp context snmp_con community community RO 10
+# neighbor 198.51.100.1 remote-as 10
+# !
+# address-family ipv4
+# snmp context snmp_con community community RO 10
+# bgp aggregate-timer 10
+# bgp slow-peer detection threshold 150
+# bgp dampening 1 1 1 1
+# network 198.51.110.10 mask 255.255.255.255 backdoor
+# aggregate-address 192.0.2.1 255.255.255.255 as-confed-set
+# neighbor 198.51.100.1 activate
+# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive
+# neighbor 198.51.100.1 slow-peer detection threshold 150
+# exit-address-family
+# !
+# address-family ipv4 multicast
+# table-map test_tableMap filter
+# network 198.51.111.11 mask 255.255.255.255 route-map test
+# aggregate-address 192.0.3.1 255.255.255.255 as-confed-set
+# default-metric 12
+# distance bgp 10 10 100
+# exit-address-family
+# !
+# address-family ipv4 mdt
+# bgp dampening 1 10 100 5
+# bgp dmzlink-bw
+# bgp soft-reconfig-backup
+# exit-address-family
+
+# Using replaced
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp log-neighbor-changes
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# snmp context snmp_con community community RO 10
+# neighbor 198.51.100.1 remote-as 10
+# !
+# address-family ipv4
+# snmp context snmp_con community community RO 10
+# bgp aggregate-timer 10
+# bgp slow-peer detection threshold 150
+# bgp dampening 1 1 1 1
+# network 198.51.110.10 mask 255.255.255.255 backdoor
+# aggregate-address 192.0.2.1 255.255.255.255 as-confed-set
+# neighbor 198.51.100.1 activate
+# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive
+# neighbor 198.51.100.1 slow-peer detection threshold 150
+# exit-address-family
+# !
+# address-family ipv4 multicast
+# table-map test_tableMap filter
+# network 198.51.111.11 mask 255.255.255.255 route-map test
+# aggregate-address 192.0.3.1 255.255.255.255 as-confed-set
+# default-metric 12
+# distance bgp 10 10 100
+# exit-address-family
+# !
+# address-family ipv4 mdt
+# bgp dampening 1 10 100 5
+# bgp dmzlink-bw
+# bgp soft-reconfig-backup
+# exit-address-family
+
+- name: Replaces device configuration of listed AF BGP with provided configuration
+ cisco.ios.ios_bgp_address_family:
+ config:
+ as_number: 65000
+ address_family:
+ - afi: ipv4
+ safi: multicast
+ vrf: blue
+ aggregate_address:
+ - address: 192.0.2.1
+ netmask: 255.255.255.255
+ as_confed_set: true
+ bgp:
+ aggregate_timer: 10
+ dampening:
+ penalty_half_time: 1
+ reuse_route_val: 1
+ suppress_route_val: 1
+ max_suppress: 1
+ slow_peer:
+ - detection:
+ threshold: 150
+ neighbor:
+ - address: 198.51.110.1
+ activate: true
+ aigp:
+ send:
+ cost_community:
+ id: 200
+ poi:
+ igp_cost: true
+ transitive: true
+ slow_peer:
+ - detection:
+ threshold: 150
+ remote_as: 10
+ network:
+ - address: 198.51.110.10
+ mask: 255.255.255.255
+ backdoor: true
+ - afi: ipv4
+ safi: multicast
+ bgp:
+ aggregate_timer: 10
+ dampening:
+ penalty_half_time: 10
+ reuse_route_val: 10
+ suppress_route_val: 10
+ max_suppress: 10
+ slow_peer:
+ - detection:
+ threshold: 200
+ network:
+ - address: 192.0.2.1
+ mask: 255.255.255.255
+ route_map: test
+ state: replaced
+
+# Task Output:
+# ------------
+# before:
+# address_family:
+# - afi: ipv4
+# aggregate_addresses:
+# - address: 192.0.2.1
+# as_confed_set: true
+# netmask: 255.255.255.255
+# bgp:
+# aggregate_timer: 10
+# dampening:
+# max_suppress: 1
+# penalty_half_time: 1
+# reuse_route_val: 1
+# suppress_route_val: 1
+# slow_peer_options:
+# detection:
+# threshold: 150
+# neighbors:
+# - activate: true
+# aigp:
+# send:
+# cost_community:
+# id: 100
+# poi:
+# igp_cost: true
+# transitive: true
+# neighbor_address: 198.51.100.1
+# slow_peer_options:
+# detection:
+# threshold: 150
+# networks:
+# - address: 198.51.110.10
+# backdoor: true
+# mask: 255.255.255.255
+# snmp:
+# context:
+# community:
+# acl: '10'
+# ro: true
+# snmp_community: community
+# name: snmp_con
+# - afi: ipv4
+# aggregate_addresses:
+# - address: 192.0.3.1
+# as_confed_set: true
+# netmask: 255.255.255.255
+# default_metric: 12
+# distance:
+# external: 10
+# internal: 10
+# local: 100
+# networks:
+# - address: 198.51.111.11
+# mask: 255.255.255.255
+# route_map: test
+# safi: multicast
+# table_map:
+# filter: true
+# name: test_tableMap
+# - afi: ipv4
+# bgp:
+# dampening:
+# max_suppress: 5
+# penalty_half_time: 1
+# reuse_route_val: 10
+# suppress_route_val: 100
+# dmzlink_bw: true
+# soft_reconfig_backup: true
+# safi: mdt
+# as_number: '65000'
+# commands:
+# - router bgp 65000
+# - address-family ipv4 multicast vrf blue
+# - bgp aggregate-timer 10
+# - bgp dampening 1 1 1 1
+# - bgp slow-peer detection threshold 150
+# - neighbor 198.51.110.1 remote-as 10
+# - neighbor 198.51.110.1 activate
+# - neighbor 198.51.110.1 aigp send cost-community 200 poi igp-cost transitive
+# - neighbor 198.51.110.1 slow-peer detection threshold 150
+# - network 198.51.110.10 mask 255.255.255.255 backdoor
+# - aggregate-address 192.0.2.1 255.255.255.255 as-confed-set
+# - address-family ipv4 multicast
+# - no default-metric 12
+# - no distance bgp 10 10 100
+# - no table-map test_tableMap filter
+# - bgp aggregate-timer 10
+# - bgp dampening 10 10 10 10
+# - bgp slow-peer detection threshold 200
+# - network 192.0.2.1 mask 255.255.255.255 route-map test
+# - no network 198.51.111.11 mask 255.255.255.255 route-map test
+# - no aggregate-address 192.0.3.1 255.255.255.255 as-confed-set
+# after:
+# address_family:
+# - afi: ipv4
+# aggregate_addresses:
+# - address: 192.0.2.1
+# as_confed_set: true
+# netmask: 255.255.255.255
+# bgp:
+# aggregate_timer: 10
+# dampening:
+# max_suppress: 1
+# penalty_half_time: 1
+# reuse_route_val: 1
+# suppress_route_val: 1
+# slow_peer_options:
+# detection:
+# threshold: 150
+# neighbors:
+# - activate: true
+# aigp:
+# send:
+# cost_community:
+# id: 100
+# poi:
+# igp_cost: true
+# transitive: true
+# neighbor_address: 198.51.100.1
+# slow_peer_options:
+# detection:
+# threshold: 150
+# - activate: true
+# aigp:
+# send:
+# cost_community:
+# id: 200
+# poi:
+# igp_cost: true
+# transitive: true
+# neighbor_address: 198.51.110.1
+# slow_peer_options:
+# detection:
+# threshold: 150
+# networks:
+# - address: 198.51.110.10
+# backdoor: true
+# mask: 255.255.255.255
+# snmp:
+# context:
+# community:
+# acl: '10'
+# ro: true
+# snmp_community: community
+# name: snmp_con
+# - afi: ipv4
+# bgp:
+# aggregate_timer: 10
+# dampening:
+# max_suppress: 10
+# penalty_half_time: 10
+# reuse_route_val: 10
+# suppress_route_val: 10
+# slow_peer_options:
+# detection:
+# threshold: 200
+# networks:
+# - address: 192.0.2.1
+# mask: 255.255.255.255
+# route_map: test
+# safi: multicast
+# - afi: ipv4
+# bgp:
+# dampening:
+# max_suppress: 5
+# penalty_half_time: 1
+# reuse_route_val: 10
+# suppress_route_val: 100
+# dmzlink_bw: true
+# soft_reconfig_backup: true
+# safi: mdt
+# as_number: '65000'
+
+# After state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp log-neighbor-changes
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# snmp context snmp_con community community RO 10
+# neighbor 198.51.100.1 remote-as 10
+# neighbor 198.51.110.1 remote-as 10
+# !
+# address-family ipv4
+# snmp context snmp_con community community RO 10
+# bgp aggregate-timer 10
+# bgp slow-peer detection threshold 150
+# bgp dampening 1 1 1 1
+# network 198.51.110.10 mask 255.255.255.255 backdoor
+# aggregate-address 192.0.2.1 255.255.255.255 as-confed-set
+# neighbor 198.51.100.1 activate
+# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive
+# neighbor 198.51.100.1 slow-peer detection threshold 150
+# neighbor 198.51.110.1 activate
+# neighbor 198.51.110.1 aigp send cost-community 200 poi igp-cost transitive
+# neighbor 198.51.110.1 slow-peer detection threshold 150
+# exit-address-family
+# !
+# address-family ipv4 multicast
+# bgp aggregate-timer 10
+# bgp slow-peer detection threshold 200
+# bgp dampening 10 10 10 10
+# network 192.0.2.1 mask 255.255.255.255 route-map test
+# exit-address-family
+# !
+# address-family ipv4 mdt
+# bgp dampening 1 10 100 5
+# bgp dmzlink-bw
+# bgp soft-reconfig-backup
+# exit-address-family
+
+# Using overridden
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp log-neighbor-changes
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# snmp context snmp_con community community RO 10
+# neighbor 198.51.100.1 remote-as 10
+# neighbor 198.51.110.1 remote-as 10
+# !
+# address-family ipv4
+# snmp context snmp_con community community RO 10
+# bgp aggregate-timer 10
+# bgp slow-peer detection threshold 150
+# bgp dampening 1 1 1 1
+# network 198.51.110.10 mask 255.255.255.255 backdoor
+# aggregate-address 192.0.2.1 255.255.255.255 as-confed-set
+# neighbor 198.51.100.1 activate
+# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive
+# neighbor 198.51.100.1 slow-peer detection threshold 150
+# neighbor 198.51.110.1 activate
+# neighbor 198.51.110.1 aigp send cost-community 200 poi igp-cost transitive
+# neighbor 198.51.110.1 slow-peer detection threshold 150
+# exit-address-family
+# !
+# address-family ipv4 multicast
+# bgp aggregate-timer 10
+# bgp slow-peer detection threshold 200
+# bgp dampening 10 10 10 10
+# network 192.0.2.1 mask 255.255.255.255 route-map test
+# exit-address-family
+# !
+# address-family ipv4 mdt
+# bgp dampening 1 10 100 5
+# bgp dmzlink-bw
+# bgp soft-reconfig-backup
+# exit-address-family
+
+- name: Override device configuration of all AF BGP with provided configuration
+ cisco.ios.ios_bgp_address_family:
+ config:
+ as_number: 65000
+ address_family:
+ - afi: ipv4
+ safi: multicast
+ vrf: blue
+ aggregate_address:
+ - address: 192.0.2.1
+ netmask: 255.255.255.255
+ as_confed_set: true
+ bgp:
+ aggregate_timer: 10
+ dampening:
+ penalty_half_time: 10
+ reuse_route_val: 10
+ suppress_route_val: 100
+ max_suppress: 50
+ slow_peer:
+ - detection:
+ threshold: 150
+ neighbor:
+ - address: 198.51.110.1
+ activate: true
+ log_neighbor_changes:
+ disable: true
+ maximum_prefix:
+ number: 1
+ threshold_value: 10
+ restart: 100
+ slow_peer:
+ - detection:
+ threshold: 150
+ remote_as: 100
+ version: 4
+ network:
+ - address: 198.51.110.10
+ mask: 255.255.255.255
+ backdoor: true
+ - afi: ipv6
+ safi: multicast
+ default_information: true
+ bgp:
+ aggregate_timer: 10
+ dampening:
+ penalty_half_time: 10
+ reuse_route_val: 10
+ suppress_route_val: 10
+ max_suppress: 10
+ slow_peer:
+ - detection:
+ threshold: 200
+ network:
+ - address: 2001:DB8:0:3::/64
+ route_map: test_ipv6
+ state: overridden
+
+# Task Output:
+# ------------
+#
+# before:
+# address_family:
+# - afi: ipv4
+# aggregate_addresses:
+# - address: 192.0.2.1
+# as_confed_set: true
+# netmask: 255.255.255.255
+# bgp:
+# aggregate_timer: 10
+# dampening:
+# max_suppress: 10
+# penalty_half_time: 10
+# reuse_route_val: 10
+# suppress_route_val: 10
+# slow_peer_options:
+# detection:
+# threshold: 200
+# default_information: true
+# neighbors:
+# - activate: true
+# aigp:
+# send:
+# cost_community:
+# id: 100
+# poi:
+# igp_cost: true
+# transitive: true
+# neighbor_address: 198.51.100.1
+# slow_peer_options:
+# detection:
+# threshold: 150
+# - activate: true
+# aigp:
+# send:
+# cost_community:
+# id: 200
+# poi:
+# igp_cost: true
+# transitive: true
+# maximum_prefix:
+# number: 1
+# restart: 100
+# threshold_value: 10
+# neighbor_address: 198.51.110.1
+# slow_peer_options:
+# detection:
+# threshold: 150
+# networks:
+# - address: 198.51.110.10
+# backdoor: true
+# mask: 255.255.255.255
+# - afi: ipv4
+# safi: multicast
+# - afi: ipv4
+# safi: mdt
+# - afi: ipv6
+# safi: multicast
+# as_number: '65000'
+# commands:
+# - router bgp 65000
+# - address-family ipv4
+# - no default-information originate
+# - no bgp aggregate-timer 10
+# - no bgp dampening 10 10 10 10
+# - no bgp slow-peer detection threshold 200
+# - no neighbor 198.51.100.1
+# - no neighbor 198.51.110.1
+# - no network 198.51.110.10 mask 255.255.255.255 backdoor
+# - no aggregate-address 192.0.2.1 255.255.255.255 as-confed-set
+# - address-family ipv4 multicast vrf blue
+# - bgp aggregate-timer 10
+# - bgp dampening 10 10 100 50
+# - bgp slow-peer detection threshold 150
+# - neighbor 198.51.110.1 remote-as 100
+# - neighbor 198.51.110.1 activate
+# - neighbor 198.51.110.1 disable
+# - neighbor 198.51.110.1 maximum-prefix 1 10 restart 100
+# - neighbor 198.51.110.1 slow-peer detection threshold 150
+# - neighbor 198.51.110.1 version 4
+# - network 198.51.110.10 mask 255.255.255.255 backdoor
+# - aggregate-address 192.0.2.1 255.255.255.255 as-confed-set
+# - address-family ipv6 multicast
+# - default-information originate
+# - bgp aggregate-timer 10
+# - bgp dampening 10 10 10 10
+# - bgp slow-peer detection threshold 200
+# after:
+# address_family:
+# - afi: ipv4
+# aggregate_addresses:
+# - address: 192.0.2.1
+# as_confed_set: true
+# netmask: 255.255.255.255
+# bgp:
+# aggregate_timer: 10
+# dampening:
+# max_suppress: 10
+# penalty_half_time: 10
+# reuse_route_val: 10
+# suppress_route_val: 10
+# slow_peer_options:
+# detection:
+# threshold: 200
+# default_information: true
+# neighbors:
+# - activate: true
+# aigp:
+# send:
+# cost_community:
+# id: 100
+# poi:
+# igp_cost: true
+# transitive: true
+# neighbor_address: 198.51.100.1
+# slow_peer_options:
+# detection:
+# threshold: 150
+# - activate: true
+# aigp:
+# send:
+# cost_community:
+# id: 200
+# poi:
+# igp_cost: true
+# transitive: true
+# maximum_prefix:
+# number: 1
+# restart: 100
+# threshold_value: 10
+# neighbor_address: 198.51.110.1
+# slow_peer_options:
+# detection:
+# threshold: 150
+# networks:
+# - address: 198.51.110.10
+# backdoor: true
+# mask: 255.255.255.255
+# - afi: ipv4
+# safi: multicast
+# - afi: ipv4
+# safi: mdt
+# - afi: ipv6
+# safi: multicast
+# as_number: '65000'
+
+# After state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp log-neighbor-changes
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# neighbor 198.51.100.1 remote-as 10
+# neighbor 198.51.110.1 remote-as 100
+# neighbor 198.51.110.1 disable-connected-check
+# neighbor 198.51.110.1 version 4
+# !
+# address-family ipv4
+# bgp aggregate-timer 10
+# bgp slow-peer detection threshold 200
+# bgp dampening 10 10 10 10
+# network 198.51.110.10 mask 255.255.255.255 backdoor
+# aggregate-address 192.0.2.1 255.255.255.255 as-confed-set
+# neighbor 198.51.100.1 activate
+# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive
+# neighbor 198.51.100.1 slow-peer detection threshold 150
+# neighbor 198.51.110.1 activate
+# neighbor 198.51.110.1 aigp send cost-community 200 poi igp-cost transitive
+# neighbor 198.51.110.1 slow-peer detection threshold 150
+# neighbor 198.51.110.1 maximum-prefix 1 10 restart 100
+# default-information originate
+# exit-address-family
+# !
+# address-family ipv4 multicast
+# exit-address-family
+# !
+# address-family ipv4 mdt
+# exit-address-family
+# !
+# address-family ipv6 multicast
+# exit-address-family
+
+# Using deleted
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp log-neighbor-changes
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# neighbor 198.51.100.1 remote-as 10
+# neighbor 198.51.110.1 remote-as 100
+# neighbor 198.51.110.1 disable-connected-check
+# neighbor 198.51.110.1 version 4
+# !
+# address-family ipv4
+# bgp aggregate-timer 10
+# bgp slow-peer detection threshold 200
+# bgp dampening 10 10 10 10
+# network 198.51.110.10 mask 255.255.255.255 backdoor
+# aggregate-address 192.0.2.1 255.255.255.255 as-confed-set
+# neighbor 198.51.100.1 activate
+# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive
+# neighbor 198.51.100.1 slow-peer detection threshold 150
+# neighbor 198.51.110.1 activate
+# neighbor 198.51.110.1 aigp send cost-community 200 poi igp-cost transitive
+# neighbor 198.51.110.1 slow-peer detection threshold 150
+# neighbor 198.51.110.1 maximum-prefix 1 10 restart 100
+# default-information originate
+# exit-address-family
+# !
+# address-family ipv4 multicast
+# exit-address-family
+# !
+# address-family ipv4 mdt
+# exit-address-family
+# !
+# address-family ipv6 multicast
+# exit-address-family
+
+- name: "Delete AF BGP (Note: This won't delete the all configured AF BGP)"
+ cisco.ios.ios_bgp_address_family:
+ config:
+ as_number: 65000
+ address_family:
+ - afi: ipv4
+ safi: multicast
+ - afi: ipv4
+ safi: mdt
+ state: deleted
+
+# Task Output:
+# ------------
+#
+# before:
+# address_family:
+# - afi: ipv4
+# aggregate_addresses:
+# - address: 192.0.2.1
+# as_confed_set: true
+# netmask: 255.255.255.255
+# bgp:
+# aggregate_timer: 10
+# dampening:
+# max_suppress: 10
+# penalty_half_time: 10
+# reuse_route_val: 10
+# suppress_route_val: 10
+# slow_peer_options:
+# detection:
+# threshold: 200
+# default_information: true
+# neighbors:
+# - activate: true
+# aigp:
+# send:
+# cost_community:
+# id: 100
+# poi:
+# igp_cost: true
+# transitive: true
+# neighbor_address: 198.51.100.1
+# slow_peer_options:
+# detection:
+# threshold: 150
+# - activate: true
+# aigp:
+# send:
+# cost_community:
+# id: 200
+# poi:
+# igp_cost: true
+# transitive: true
+# maximum_prefix:
+# number: 1
+# restart: 100
+# threshold_value: 10
+# neighbor_address: 198.51.110.1
+# slow_peer_options:
+# detection:
+# threshold: 150
+# networks:
+# - address: 198.51.110.10
+# backdoor: true
+# mask: 255.255.255.255
+# - afi: ipv4
+# safi: multicast
+# - afi: ipv4
+# safi: mdt
+# - afi: ipv6
+# safi: multicast
+# as_number: '65000'
+# commands:
+# - router bgp 65000
+# - no address-family ipv4 multicast
+# - no address-family ipv4 mdt
+# after:
+# address_family:
+# - afi: ipv4
+# aggregate_addresses:
+# - address: 192.0.2.1
+# as_confed_set: true
+# netmask: 255.255.255.255
+# bgp:
+# aggregate_timer: 10
+# dampening:
+# max_suppress: 10
+# penalty_half_time: 10
+# reuse_route_val: 10
+# suppress_route_val: 10
+# slow_peer_options:
+# detection:
+# threshold: 200
+# default_information: true
+# neighbors:
+# - activate: true
+# aigp:
+# send:
+# cost_community:
+# id: 100
+# poi:
+# igp_cost: true
+# transitive: true
+# neighbor_address: 198.51.100.1
+# slow_peer_options:
+# detection:
+# threshold: 150
+# - activate: true
+# aigp:
+# send:
+# cost_community:
+# id: 200
+# poi:
+# igp_cost: true
+# transitive: true
+# maximum_prefix:
+# number: 1
+# restart: 100
+# threshold_value: 10
+# neighbor_address: 198.51.110.1
+# slow_peer_options:
+# detection:
+# threshold: 150
+# networks:
+# - address: 198.51.110.10
+# backdoor: true
+# mask: 255.255.255.255
+# - afi: ipv6
+# safi: multicast
+# as_number: '65000'
+
+# After state:
+# -------------
+#
+# vios#sh running-config | section ^router bg
+# hostname#show running-config | section ^router bgp
+# router bgp 65000
+# bgp log-neighbor-changes
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# neighbor 198.51.100.1 remote-as 10
+# neighbor 198.51.110.1 remote-as 100
+# neighbor 198.51.110.1 disable-connected-check
+# neighbor 198.51.110.1 version 4
+# !
+# address-family ipv4
+# bgp aggregate-timer 10
+# bgp slow-peer detection threshold 200
+# bgp dampening 10 10 10 10
+# network 198.51.110.10 mask 255.255.255.255 backdoor
+# aggregate-address 192.0.2.1 255.255.255.255 as-confed-set
+# neighbor 198.51.100.1 activate
+# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive
+# neighbor 198.51.100.1 slow-peer detection threshold 150
+# neighbor 198.51.110.1 activate
+# neighbor 198.51.110.1 aigp send cost-community 200 poi igp-cost transitive
+# neighbor 198.51.110.1 slow-peer detection threshold 150
+# neighbor 198.51.110.1 maximum-prefix 1 10 restart 100
+# default-information originate
+# exit-address-family
+# !
+# address-family ipv6 multicast
+# exit-address-family
+
+# Using Deleted without any config passed (delete all)
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^router bg
+# hostname#show running-config | section ^router bgp
+# router bgp 65000
+# bgp log-neighbor-changes
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# neighbor 198.51.100.1 remote-as 10
+# neighbor 198.51.110.1 remote-as 100
+# neighbor 198.51.110.1 disable-connected-check
+# neighbor 198.51.110.1 version 4
+# !
+# address-family ipv4
+# bgp aggregate-timer 10
+# bgp slow-peer detection threshold 200
+# bgp dampening 10 10 10 10
+# network 198.51.110.10 mask 255.255.255.255 backdoor
+# aggregate-address 192.0.2.1 255.255.255.255 as-confed-set
+# neighbor 198.51.100.1 activate
+# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive
+# neighbor 198.51.100.1 slow-peer detection threshold 150
+# neighbor 198.51.110.1 activate
+# neighbor 198.51.110.1 aigp send cost-community 200 poi igp-cost transitive
+# neighbor 198.51.110.1 slow-peer detection threshold 150
+# neighbor 198.51.110.1 maximum-prefix 1 10 restart 100
+# default-information originate
+# exit-address-family
+# !
+# address-family ipv6 multicast
+# exit-address-family
+
+- name: "Delete ALL of configured AF BGP"
+ cisco.ios.ios_bgp_address_family:
+ state: deleted
+
+# Task Output:
+# ------------
+#
+# before:
+# address_family:
+# - afi: ipv4
+# aggregate_addresses:
+# - address: 192.0.2.1
+# as_confed_set: true
+# netmask: 255.255.255.255
+# bgp:
+# aggregate_timer: 10
+# dampening:
+# max_suppress: 10
+# penalty_half_time: 10
+# reuse_route_val: 10
+# suppress_route_val: 10
+# slow_peer_options:
+# detection:
+# threshold: 200
+# default_information: true
+# neighbors:
+# - activate: true
+# aigp:
+# send:
+# cost_community:
+# id: 100
+# poi:
+# igp_cost: true
+# transitive: true
+# neighbor_address: 198.51.100.1
+# slow_peer_options:
+# detection:
+# threshold: 150
+# - activate: true
+# aigp:
+# send:
+# cost_community:
+# id: 200
+# poi:
+# igp_cost: true
+# transitive: true
+# maximum_prefix:
+# number: 1
+# restart: 100
+# threshold_value: 10
+# neighbor_address: 198.51.110.1
+# slow_peer_options:
+# detection:
+# threshold: 150
+# networks:
+# - address: 198.51.110.10
+# backdoor: true
+# mask: 255.255.255.255
+# - afi: ipv6
+# safi: multicast
+# as_number: '65000'
+# commands:
+# - router bgp 65000
+# - no address-family ipv4
+# - no address-family ipv6 multicast
+# after:
+# address_family:
+# - afi: ipv4
+# bgp:
+# aggregate_timer: 10
+# as_number: '65000'
+
+# After state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp log-neighbor-changes
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# neighbor 198.51.100.1 remote-as 10
+# neighbor 198.51.110.1 remote-as 100
+# neighbor 198.51.110.1 disable-connected-check
+# neighbor 198.51.110.1 version 4
+# !
+# address-family ipv4
+# bgp aggregate-timer 10
+# no neighbor 198.51.100.1 activate
+# no neighbor 198.51.110.1 activate
+# exit-address-family
+
+# Using gathered
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp log-neighbor-changes
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# snmp context snmp_con community community RO 10
+# neighbor 198.51.100.1 remote-as 10
+# !
+# address-family ipv4
+# snmp context snmp_con community community RO 10
+# bgp aggregate-timer 10
+# bgp slow-peer detection threshold 150
+# bgp dampening 1 1 1 1
+# network 198.51.110.10 mask 255.255.255.255 backdoor
+# aggregate-address 192.0.2.1 255.255.255.255 as-confed-set
+# neighbor 198.51.100.1 activate
+# neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive
+# neighbor 198.51.100.1 slow-peer detection threshold 150
+# exit-address-family
+# !
+# address-family ipv4 multicast
+# table-map test_tableMap filter
+# network 198.51.111.11 mask 255.255.255.255 route-map test
+# aggregate-address 192.0.3.1 255.255.255.255 as-confed-set
+# default-metric 12
+# distance bgp 10 10 100
+# exit-address-family
+# !
+# address-family ipv4 mdt
+# bgp dampening 1 10 100 5
+# bgp dmzlink-bw
+# bgp soft-reconfig-backup
+# exit-address-family
+
+- name: Gather listed AF BGP with provided configurations
+ cisco.ios.ios_bgp_address_family:
+ config:
+ state: gathered
+
+# Task Output:
+# ------------
+#
+# gathered:
+# address_family:
+# - afi: ipv4
+# aggregate_addresses:
+# - address: 192.0.2.1
+# as_confed_set: true
+# netmask: 255.255.255.255
+# bgp:
+# aggregate_timer: 10
+# dampening:
+# max_suppress: 1
+# penalty_half_time: 1
+# reuse_route_val: 1
+# suppress_route_val: 1
+# slow_peer_options:
+# detection:
+# threshold: 150
+# neighbors:
+# - activate: true
+# aigp:
+# send:
+# cost_community:
+# id: 100
+# poi:
+# igp_cost: true
+# transitive: true
+# neighbor_address: 198.51.100.1
+# slow_peer_options:
+# detection:
+# threshold: 150
+# networks:
+# - address: 198.51.110.10
+# backdoor: true
+# mask: 255.255.255.255
+# snmp:
+# context:
+# community:
+# acl: '10'
+# ro: true
+# snmp_community: community
+# name: snmp_con
+# - afi: ipv4
+# aggregate_addresses:
+# - address: 192.0.3.1
+# as_confed_set: true
+# netmask: 255.255.255.255
+# default_metric: 12
+# distance:
+# external: 10
+# internal: 10
+# local: 100
+# networks:
+# - address: 198.51.111.11
+# mask: 255.255.255.255
+# route_map: test
+# safi: multicast
+# table_map:
+# filter: true
+# name: test_tableMap
+# - afi: ipv4
+# bgp:
+# dampening:
+# max_suppress: 5
+# penalty_half_time: 1
+# reuse_route_val: 10
+# suppress_route_val: 100
+# dmzlink_bw: true
+# soft_reconfig_backup: true
+# safi: mdt
+# as_number: '65000'
+
+# Using rendered
+
+- name: Rendered the provided configuration with the existing running configuration
+ cisco.ios.ios_bgp_address_family:
+ config:
+ as_number: 65000
+ address_family:
+ - afi: ipv4
+ safi: multicast
+ vrf: blue
+ aggregate_address:
+ - address: 192.0.2.1
+ netmask: 255.255.255.255
+ as_confed_set: true
+ bgp:
+ aggregate_timer: 10
+ dampening:
+ penalty_half_time: 1
+ reuse_route_val: 1
+ suppress_route_val: 1
+ max_suppress: 1
+ slow_peer:
+ - detection:
+ threshold: 150
+ neighbor:
+ - address: 198.51.100.1
+ aigp:
+ send:
+ cost_community:
+ id: 100
+ poi:
+ igp_cost: true
+ transitive: true
+ slow_peer:
+ - detection:
+ threshold: 150
+ remote_as: 10
+ route_maps:
+ - name: test-route
+ out: true
+ route_server_client: true
+ network:
+ - address: 198.51.110.10
+ mask: 255.255.255.255
+ backdoor: true
+ snmp:
+ context:
+ name: snmp_con
+ community:
+ snmp_community: community
+ ro: true
+ acl: 10
+ - afi: ipv4
+ safi: mdt
+ bgp:
+ dmzlink_bw: true
+ dampening:
+ penalty_half_time: 1
+ reuse_route_val: 10
+ suppress_route_val: 100
+ max_suppress: 5
+ soft_reconfig_backup: true
+ state: rendered
+
+# Task Output:
+# ------------
+#
+# rendered:
+# - router bgp 65000
+# - address-family ipv4 multicast vrf blue
+# - bgp aggregate-timer 10
+# - bgp dampening 1 1 1 1
+# - bgp slow-peer detection threshold 150
+# - snmp context snmp_con community community ro 10
+# - neighbor 198.51.100.1 remote-as 10
+# - neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive
+# - neighbor 198.51.100.1 slow-peer detection threshold 150
+# - network 198.51.110.10 mask 255.255.255.255 backdoor
+# - aggregate-address 192.0.2.1 255.255.255.255 as-confed-set
+# - address-family ipv4 mdt
+# - bgp dmzlink-bw
+# - bgp soft-reconfig-backup
+# - bgp dampening 1 10 100 5
+
+# Using parsed
+
+# File: parsed.cfg
+# ----------------
+# router bgp 65000
+# bgp log-neighbor-changes
+# bgp nopeerup-delay cold-boot 20
+# !
+# address-family ipv4 multicast
+# table-map test_tableMap filter
+# network 1.1.1.1 mask 255.255.255.255 route-map test
+# aggregate-address 192.0.3.1 255.255.255.255 as-confed-set
+# default-metric 12
+# distance bgp 10 10 100
+# exit-address-family
+# !
+# address-family ipv4 mdt
+# bgp dampening 1 10 100 5
+# bgp dmzlink-bw
+# bgp soft-reconfig-backup
+# exit-address-family
+# !
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_bgp_address_family:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Task Output:
+# ------------
+#
+# parsed:
+# address_family:
+# - afi: ipv4
+# aggregate_addresses:
+# - address: 192.0.2.1
+# as_confed_set: true
+# netmask: 255.255.255.255
+# bgp:
+# aggregate_timer: 10
+# dampening:
+# max_suppress: 1
+# penalty_half_time: 1
+# reuse_route_val: 1
+# suppress_route_val: 1
+# slow_peer_options:
+# detection:
+# threshold: 150
+# neighbors:
+# - activate: true
+# aigp:
+# send:
+# cost_community:
+# id: 100
+# poi:
+# igp_cost: true
+# transitive: true
+# neighbor_address: 198.51.100.1
+# slow_peer_options:
+# detection:
+# threshold: 150
+# networks:
+# - address: 198.51.110.10
+# backdoor: true
+# mask: 255.255.255.255
+# snmp:
+# context:
+# community:
+# acl: '10'
+# ro: true
+# snmp_community: community
+# name: snmp_con
+# - afi: ipv4
+# aggregate_addresses:
+# - address: 192.0.3.1
+# as_confed_set: true
+# netmask: 255.255.255.255
+# default_metric: 12
+# distance:
+# external: 10
+# internal: 10
+# local: 100
+# networks:
+# - address: 198.51.111.11
+# mask: 255.255.255.255
+# route_map: test
+# safi: multicast
+# table_map:
+# filter: true
+# name: test_tableMap
+# - afi: ipv4
+# bgp:
+# dampening:
+# max_suppress: 5
+# penalty_half_time: 1
+# reuse_route_val: 10
+# suppress_route_val: 100
+# dmzlink_bw: true
+# soft_reconfig_backup: true
+# safi: mdt
+# as_number: '65000'
+"""
+
+
+RETURN = """
+before:
+ description: The configuration prior to the module execution.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+after:
+ description: The resulting configuration after module execution.
+ returned: when changed
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: list
+ sample:
+ - router bgp 65000
+ - address-family ipv4 multicast
+ - table-map test_tableMap filter
+ - network 1.1.1.1 mask 255.255.255.255 route-map test
+ - aggregate-address 192.0.3.1 255.255.255.255 as-confed-set
+rendered:
+ description: The provided configuration in the task rendered in device-native format (offline).
+ returned: when I(state) is C(rendered)
+ type: list
+ sample:
+ - router bgp 65000
+ - address-family ipv4 multicast
+ - table-map test_tableMap filter
+ - network 1.1.1.1 mask 255.255.255.255 route-map test
+ - aggregate-address 192.0.3.1 255.255.255.255 as-confed-set
+gathered:
+ description: Facts about the network resource gathered from the remote device as structured data.
+ returned: when I(state) is C(gathered)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+parsed:
+ description: The device native config provided in I(running_config) option parsed into structured data as per module argspec.
+ returned: when I(state) is C(parsed)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.bgp_address_family.bgp_address_family import (
+ Bgp_address_familyArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.bgp_address_family.bgp_address_family import (
+ Bgp_address_family,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ module = AnsibleModule(
+ argument_spec=Bgp_address_familyArgs.argument_spec,
+ mutually_exclusive=[["config", "running_config"]],
+ required_if=[
+ ["state", "merged", ["config"]],
+ ["state", "replaced", ["config"]],
+ ["state", "overridden", ["config"]],
+ ["state", "rendered", ["config"]],
+ ["state", "parsed", ["running_config"]],
+ ],
+ supports_check_mode=True,
+ )
+
+ result = Bgp_address_family(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_bgp_global.py b/ansible_collections/cisco/ios/plugins/modules/ios_bgp_global.py
new file mode 100644
index 000000000..0639b6e8a
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_bgp_global.py
@@ -0,0 +1,3063 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2022 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+"""
+The module file for ios_bgp_global
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_bgp_global
+short_description: Resource module to configure BGP.
+description: This module configures and manages the attributes of global bgp on Cisco IOS.
+version_added: 1.3.0
+author:
+ - Sumit Jaiswal (@justjais)
+ - Sagar Paul (@KB-perByte)
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+ - The module examples uses callback plugin (stdout_callback = yaml) to generate task
+ output in yaml format.
+options:
+ config:
+ description: A dictionary of options for bgp configurations.
+ type: dict
+ suboptions:
+ as_number:
+ description: Autonomous system number
+ type: str
+ aggregate_address:
+ description:
+ - Configure BGP aggregate entry
+ - This option is DEPRECATED and is replaced with aggregate_addresses which
+ accepts list of dict as input, this attribute will be removed after 2024-06-01.
+ type: dict
+ suboptions:
+ address:
+ description: Specify aggregate address
+ type: str
+ netmask:
+ description: Specify aggregate mask
+ type: str
+ advertise_map:
+ description: Set condition to advertise attribute
+ type: str
+ as_confed_set:
+ description: Generate AS confed set path information
+ type: bool
+ as_set:
+ description: Generate AS set path information
+ type: bool
+ attribute_map:
+ description: Set attributes of aggregate
+ type: str
+ summary_only:
+ description: Filter more specific routes from updates
+ type: bool
+ suppress_map:
+ description: Conditionally filter more specific routes from updates
+ type: str
+ aggregate_addresses:
+ description: Configure BGP aggregate entries
+ type: list
+ elements: dict
+ suboptions:
+ address:
+ description: Specify aggregate address
+ type: str
+ netmask:
+ description: Specify aggregate mask
+ type: str
+ advertise_map:
+ description: Set condition to advertise attribute
+ type: str
+ as_confed_set:
+ description: Generate AS confed set path information
+ type: bool
+ as_set:
+ description: Generate AS set path information
+ type: bool
+ attribute_map:
+ description: Set attributes of aggregate
+ type: str
+ summary_only:
+ description: Filter more specific routes from updates
+ type: bool
+ suppress_map:
+ description: Conditionally filter more specific routes from updates
+ type: str
+ auto_summary:
+ description: Enable automatic network number summarization
+ type: bool
+ bgp:
+ description: Enable address family and enter its config mode
+ type: dict
+ suboptions:
+ additional_paths:
+ description: Additional paths in the BGP table
+ type: dict
+ suboptions:
+ install:
+ description: Additional paths to install into RIB
+ type: bool
+ receive:
+ description: Receive additional paths from neighbors
+ type: bool
+ select:
+ description: Selection criteria to pick the paths
+ type: dict
+ suboptions:
+ all:
+ description: Select all available paths
+ type: bool
+ best:
+ description: Select best N paths (2-3).
+ type: int
+ best_external:
+ description: Select best-external path
+ type: bool
+ group_best:
+ description: Select group-best path
+ type: bool
+ send:
+ description: Send additional paths to neighbors
+ type: bool
+ advertise_best_external:
+ description: Advertise best external path to internal peers
+ type: bool
+ aggregate_timer:
+ description:
+ - Configure Aggregation Timer
+ - Please refer vendor documentation for valid values
+ type: int
+ always_compare_med:
+ description: Allow comparing MED from different neighbors
+ type: bool
+ asnotation:
+ description:
+ - Change the default as plain notation
+ - asdot notation
+ type: bool
+ bestpath:
+ description:
+ - Change the default bestpath selection
+ - This option is DEPRECATED and replaced with bestpath_options of type dict,
+ this attribute will be removed after 2024-06-01.
+ type: list
+ elements: dict
+ suboptions:
+ aigp:
+ description:
+ - if both paths doesn't have aigp ignore on bestpath comparison
+ - ignore
+ type: bool
+ compare_routerid:
+ description: Compare router-id for identical EBGP paths
+ type: bool
+ cost_community:
+ description: cost community
+ type: bool
+ igp_metric:
+ description:
+ - igp metric
+ - Ignore igp metric in bestpath selection
+ type: bool
+ med:
+ description: MED attribute
+ type: dict
+ suboptions:
+ confed:
+ description: Compare MED among confederation paths
+ type: bool
+ missing_as_worst:
+ description: Treat missing MED as the least preferred one
+ type: bool
+ bestpath_options:
+ description:
+ - Change the default bestpath selection
+ type: dict
+ suboptions:
+ aigp:
+ description:
+ - if both paths doesn't have aigp ignore on bestpath comparison
+ - ignore
+ type: bool
+ compare_routerid:
+ description: Compare router-id for identical EBGP paths
+ type: bool
+ cost_community:
+ description: cost community
+ type: bool
+ igp_metric:
+ description:
+ - igp metric
+ - Ignore igp metric in bestpath selection
+ type: bool
+ med:
+ description: MED attribute
+ type: dict
+ suboptions:
+ confed:
+ description: Compare MED among confederation paths
+ type: bool
+ missing_as_worst:
+ description: Treat missing MED as the least preferred one
+ type: bool
+ client_to_client:
+ description: Configure client to client route reflection
+ type: dict
+ suboptions:
+ set:
+ description: set reflection of routes allowed
+ type: bool
+ all:
+ description: inter-cluster and intra-cluster (default)
+ type: bool
+ intra_cluster:
+ description:
+ - intra cluster reflection
+ - intra-cluster reflection for cluster-id
+ type: str
+ cluster_id:
+ description:
+ - Configure Route-Reflector Cluster-id (peers may reset)
+ - A.B.C.D/Please refer vendor documentation for valid Route-Reflector Cluster-id
+ type: str
+ confederation:
+ description: AS confederation parameters
+ type: dict
+ suboptions:
+ identifier:
+ description:
+ - Set routing domain confederation AS
+ - AS number
+ type: str
+ peers:
+ description:
+ - Peer ASs in BGP confederation
+ - AS number
+ type: str
+ consistency_checker:
+ description: Consistency-checker
+ type: dict
+ suboptions:
+ auto_repair:
+ description: Auto-Repair
+ type: dict
+ suboptions:
+ set:
+ description: Enable Auto-Repair
+ type: bool
+ interval:
+ description:
+ - Set the bgp consistency checker
+ - Please refer vendor documentation for valid values
+ type: int
+ error_message:
+ description: Log Error-Msg
+ type: dict
+ suboptions:
+ set:
+ description: Enable Error-Msg
+ type: bool
+ interval:
+ description:
+ - Set the bgp consistency checker
+ - Please refer vendor documentation for valid values
+ type: int
+ dampening:
+ description: Enable route-flap dampening
+ type: dict
+ suboptions:
+ penalty_half_time:
+ description:
+ - Half-life time for the penalty
+ - Please refer vendor documentation for valid values
+ type: int
+ reuse_route_val:
+ description:
+ - Value to start reusing a route
+ - Please refer vendor documentation for valid values
+ type: int
+ suppress_route_val:
+ description:
+ - Value to start suppressing a route
+ - Please refer vendor documentation for valid values
+ type: int
+ max_suppress:
+ description:
+ - Maximum duration to suppress a stable route
+ - Please refer vendor documentation for valid values
+ type: int
+ route_map:
+ description: Route-map to specify criteria for dampening
+ type: str
+ deterministic_med:
+ description: Pick the best-MED path among paths advertised from the neighboring AS
+ type: bool
+ dmzlink_bw:
+ description: Use DMZ Link Bandwidth as weight for BGP multipaths
+ type: bool
+ enforce_first_as:
+ description: Enforce the first AS for EBGP routes(default)
+ type: bool
+ enhanced_error:
+ description: Enabled BGP Enhanced error handling
+ type: bool
+ fast_external_fallover:
+ description: Immediately reset session if a link to a directly connected external peer goes down
+ type: bool
+ graceful_restart:
+ description: Graceful restart capability parameters
+ type: dict
+ suboptions:
+ set:
+ description: Set Graceful-Restart
+ type: bool
+ extended:
+ description: Enable Graceful-Restart Extension
+ type: bool
+ restart_time:
+ description:
+ - Set the max time needed to restart and come back up
+ - Please refer vendor documentation for valid values
+ type: int
+ stalepath_time:
+ description:
+ - Set the max time to hold onto restarting peer's stale paths
+ - Please refer vendor documentation for valid values
+ type: int
+ graceful_shutdown:
+ description: Graceful shutdown capability parameters
+ type: dict
+ suboptions:
+ neighbors:
+ description: Gracefully shut down all neighbors
+ type: dict
+ suboptions:
+ time:
+ description:
+ - time in seconds
+ - Please refer vendor documentation for valid values
+ type: int
+ activate:
+ description: Activate graceful shutdown of all neighbors
+ type: bool
+ vrfs:
+ description: Gracefully shut down all vrf neighbors
+ type: dict
+ suboptions:
+ time:
+ description:
+ - time in seconds
+ - Please refer vendor documentation for valid values
+ type: int
+ activate:
+ description: Activate graceful shutdown of all neighbors
+ type: bool
+ community:
+ description:
+ - Set Community for Gshut routes
+ - community number/community number in aa:nn format
+ type: str
+ local_preference:
+ description:
+ - Set Local Preference for Gshut routes
+ - Please refer vendor documentation for valid values
+ type: int
+ inject_map:
+ description:
+ - Routemap which specifies prefixes to inject
+ - This option is DEPRECATED and is updated with inject_maps which is a
+ list of dict, this attribute will be removed after 2024-06-01.
+ type: dict
+ suboptions:
+ name:
+ description: route-map name
+ type: str
+ exist_map_name:
+ description: route-map name
+ type: str
+ copy_attributes:
+ description: Copy attributes from aggregate
+ type: bool
+ inject_maps:
+ description: Routemap which specifies prefixes to inject
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: route-map name
+ type: str
+ exist_map_name:
+ description: route-map name
+ type: str
+ copy_attributes:
+ description: Copy attributes from aggregate
+ type: bool
+ listen:
+ description: Neighbor subnet range listener
+ type: dict
+ suboptions:
+ limit:
+ description:
+ - Set the max limit for the dynamic subnet range neighbors
+ - Please refer vendor documentation for valid values
+ type: int
+ range:
+ description: Subnet network range
+ type: dict
+ suboptions:
+ ipv4_with_subnet:
+ description:
+ - IPv4 subnet range(A.B.C.D/nn)
+ - This option is DEPRECATED and is updated with host_with_subnet which is a
+ common attribute for address, this attribute will be removed after 2024-06-01.
+ type: str
+ ipv6_with_subnet:
+ description:
+ - IPv6 subnet range(X:X:X:X::X/<0-128>)
+ - This option is DEPRECATED and is updated with host_with_subnet which is a
+ common attribute for address attribute will be removed after 2024-06-01.
+ type: str
+ host_with_subnet:
+ description:
+ - IPv4 subnet range(A.B.C.D/nn)
+ - IPv6 subnet range(X:X:X:X::X/<0-128>)
+ type: str
+ peer_group:
+ description: Member of the peer-group
+ type: str
+ log_neighbor_changes:
+ description: Log neighbor up/down and reset reason
+ type: bool
+ maxas_limit:
+ description:
+ - Allow AS-PATH attribute from any neighbor imposing a limit on number of ASes
+ - Please refer vendor documentation for valid values
+ type: int
+ maxcommunity_limit:
+ description:
+ - Allow COMMUNITY attribute from any neighbor imposing a limit on number of communities
+ - Please refer vendor documentation for valid values
+ type: int
+ maxextcommunity_limit:
+ description:
+ - Allow EXTENDED COMMUNITY attribute from any neighbor imposing a limit on number of extended communities
+ - Please refer vendor documentation for valid values
+ type: int
+ nexthop:
+ description: Nexthop tracking commands
+ type: dict
+ suboptions:
+ route_map:
+ description: Route map for valid nexthops
+ type: str
+ trigger:
+ description: nexthop trackings
+ type: dict
+ suboptions:
+ delay:
+ description:
+ - Set the delay to trigger nexthop tracking
+ - Please refer vendor documentation for valid values
+ type: int
+ enable:
+ description: Enable nexthop tracking
+ type: bool
+ nopeerup_delay:
+ description:
+ - Set how long BGP will wait for the first peer to come up before beginning the update delay or
+ graceful restart timers (in seconds)
+ - This option is DEPRECATED and is replaced with nopeerup_delay_options which is of type dict,
+ this attribute will be removed after 2024-06-01.
+ type: list
+ elements: dict
+ suboptions:
+ cold_boot:
+ description:
+ - How long to wait for the first peer to come up upon a cold boot
+ - Please refer vendor documentation for valid values
+ type: int
+ nsf_switchover:
+ description:
+ - How long to wait for the first peer, post NSF switchover
+ - Please refer vendor documentation for valid values
+ type: int
+ post_boot:
+ description:
+ - How long to wait for the first peer to come up once the system is already
+ booted and all peers go down
+ - Please refer vendor documentation for valid values
+ type: int
+ user_initiated:
+ description:
+ - How long to wait for the first peer, post a manual clear of BGP peers by the admin user
+ - Please refer vendor documentation for valid values
+ type: int
+ nopeerup_delay_options:
+ description:
+ Set how long BGP will wait for the first peer to come up before beginning the update delay or
+ graceful restart timers (in seconds)
+ type: dict
+ suboptions:
+ cold_boot:
+ description:
+ - How long to wait for the first peer to come up upon a cold boot
+ - Please refer vendor documentation for valid values
+ type: int
+ nsf_switchover:
+ description:
+ - How long to wait for the first peer, post NSF switchover
+ - Please refer vendor documentation for valid values
+ type: int
+ post_boot:
+ description:
+ - How long to wait for the first peer to come up once the system is already
+ booted and all peers go down
+ - Please refer vendor documentation for valid values
+ type: int
+ user_initiated:
+ description:
+ - How long to wait for the first peer, post a manual clear of BGP peers by the admin user
+ - Please refer vendor documentation for valid values
+ type: int
+ recursion:
+ description:
+ - recursion rule for the nexthops
+ - recursion via host for the nexthops
+ type: bool
+ redistribute_internal:
+ description: Allow redistribution of iBGP into IGPs (dangerous)
+ type: bool
+ refresh:
+ description: refresh
+ type: dict
+ suboptions:
+ max_eor_time:
+ description:
+ - Configure refresh max-eor time
+ - Please refer vendor documentation for valid values
+ type: int
+ stalepath_time:
+ description:
+ - Configure refresh stale-path time
+ - Please refer vendor documentation for valid values
+ type: int
+ regexp:
+ description:
+ - Select regular expression engine
+ - Enable bounded-execution-time regular expression engine
+ type: bool
+ route_map:
+ description:
+ - route-map control commands
+ - Have route-map set commands take priority over BGP commands such as next-hop unchanged
+ type: bool
+ router_id:
+ description: Override configured router identifier (peers will reset)
+ type: dict
+ suboptions:
+ address:
+ description: Manually configured router identifier(A.B.C.D)
+ type: str
+ interface:
+ description: Use IPv4 address on interface
+ type: str
+ vrf:
+ description:
+ - vrf-specific router id configuration
+ - Automatically assign per-vrf bgp router id
+ type: bool
+ scan_time:
+ description:
+ - Configure background scanner interval
+ - Please refer vendor documentation for valid values
+ type: int
+ slow_peer:
+ description: Configure slow-peer
+ type: dict
+ suboptions:
+ detection:
+ description: Slow-peer detection
+ type: dict
+ suboptions:
+ set:
+ description: Slow-peer detection
+ type: bool
+ threshold:
+ description:
+ - Set the slow-peer detection threshold
+ - Please refer vendor documentation for valid values
+ type: int
+ split_update_group:
+ description: Configure slow-peer split-update-group
+ type: dict
+ suboptions:
+ dynamic:
+ description: Dynamically split the slow peer to slow-update group
+ type: bool
+ permanent:
+ description: Keep the slow-peer permanently in slow-update group
+ type: bool
+ snmp:
+ description:
+ - BGP SNMP options
+ - BGP SNMP trap options
+ - Use cbgp Peer2Type as part of index for traps
+ type: bool
+ sso:
+ description:
+ - Stateful Switchover
+ - Enable SSO only for Route-Refresh capable peers
+ type: bool
+ soft_reconfig_backup:
+ description: Use soft-reconfiguration inbound only when route-refresh is not negotiated
+ type: bool
+ suppress_inactive:
+ description: Suppress routes that are not in the routing table
+ type: bool
+ transport:
+ description:
+ - Global enable/disable transport session parameters
+ - Transport path MTU discovery
+ type: bool
+ update_delay:
+ description:
+ - Set the max initial delay for sending update
+ - Please refer vendor documentation for valid values
+ type: int
+ update_group:
+ description:
+ - Manage peers in bgp update groups
+ - Split update groups based on Policy
+ - Keep peers with as-override in different update groups
+ type: bool
+ upgrade_cli:
+ description: Upgrade to hierarchical AFI mode
+ type: dict
+ suboptions:
+ set:
+ description: enable upgrade to hierarchical AFI mode
+ type: bool
+ af_mode:
+ description: Upgrade to AFI mode
+ type: bool
+ bmp:
+ description: BGP Monitoring Protocol
+ type: dict
+ suboptions:
+ buffer_size:
+ description:
+ - BMP Buffer Size
+ - Please refer vendor documentation for valid values
+ type: int
+ initial_refresh:
+ description: Initial Refresh options
+ type: dict
+ suboptions:
+ delay:
+ description: Delay before Initial Refresh
+ type: int
+ skip:
+ description: skip all refreshes
+ type: bool
+ server:
+ description:
+ - Server Information
+ - Please refer vendor documentation for valid values
+ type: int
+ server_options:
+ description: bmp server options
+ type: dict
+ suboptions:
+ activate:
+ description: activate server
+ type: bool
+ address:
+ description: skip all refreshes
+ type: dict
+ suboptions:
+ host:
+ description: host address
+ type: str
+ port:
+ description: port number BMP server
+ type: int
+ default_information:
+ description:
+ - Control distribution of default information
+ - Distribute a default route
+ type: bool
+ default_metric:
+ description:
+ - Set metric of redistributed routes
+ - Please refer vendor documentation for valid values
+ type: int
+ distance:
+ description: Define an administrative distance
+ type: dict
+ suboptions:
+ admin:
+ description: Administrative distance
+ type: dict
+ suboptions:
+ distance:
+ description:
+ - Administrative distance
+ - Please refer vendor documentation for valid values
+ type: int
+ address:
+ description: IP Source address (A.B.C.D)
+ type: str
+ wildcard_bit:
+ description: Wildcard bits (A.B.C.D)
+ type: str
+ acl:
+ description:
+ - IP Standard access list number
+ - IP Standard expanded access list number
+ - Standard access-list name
+ type: str
+ bgp:
+ description: BGP distance
+ type: dict
+ suboptions:
+ routes_external:
+ description:
+ - Distance for routes external to the AS
+ - Please refer vendor documentation for valid values
+ type: int
+ routes_internal:
+ description:
+ - Distance for routes internal to the AS
+ - Please refer vendor documentation for valid values
+ type: int
+ routes_local:
+ description:
+ - Distance for local routes
+ - Please refer vendor documentation for valid values
+ type: int
+ mbgp:
+ description: MBGP distance
+ type: dict
+ suboptions:
+ routes_external:
+ description:
+ - Distance for routes external to the AS
+ - Please refer vendor documentation for valid values
+ type: int
+ routes_internal:
+ description:
+ - Distance for routes internal to the AS
+ - Please refer vendor documentation for valid values
+ type: int
+ routes_local:
+ description:
+ - Distance for local routes
+ - Please refer vendor documentation for valid values
+ type: int
+ distributes:
+ description: Filter networks in routing updates
+ type: list
+ elements: dict
+ suboptions:
+ prefix:
+ description: Filtering incoming updates based on gateway
+ type: str
+ gateway:
+ description: Filter prefixes in routing updates
+ type: str
+ acl:
+ description: IP access list number/name
+ type: str
+ in:
+ description: Filter incoming routing updates
+ type: bool
+ out:
+ description: Filter outgoing routing updates
+ type: bool
+ interface:
+ description: interface details
+ type: str
+ distribute_list:
+ description:
+ - Filter networks in routing updates
+ - This option is DEPRECATED and is replaced with distributes which is of type list of dict,
+ this attribute will be removed after 2024-06-01.
+ type: dict
+ suboptions:
+ acl:
+ description: IP access list number/name
+ type: str
+ in:
+ description: Filter incoming routing updates
+ type: bool
+ out:
+ description: Filter outgoing routing updates
+ type: bool
+ interface:
+ description: interface details
+ type: str
+ maximum_paths:
+ description: Forward packets over multiple paths
+ type: dict
+ suboptions:
+ paths:
+ description: Number of paths
+ type: int
+ eibgp:
+ description: Both eBGP and iBGP paths as multipath
+ type: int
+ ibgp:
+ description: iBGP-multipath
+ type: int
+ maximum_secondary_paths:
+ description: Maximum secondary paths
+ type: dict
+ suboptions:
+ paths:
+ description: Number of secondary paths
+ type: int
+ eibgp:
+ description: Both eBGP and iBGP paths as secondary multipath
+ type: int
+ ibgp:
+ description: iBGP-secondary-multipath
+ type: int
+ neighbors:
+ description: Specify a neighbor router
+ type: list
+ elements: dict
+ aliases:
+ - neighbor
+ suboptions:
+ neighbor_address:
+ description:
+ - Neighbor address (A.B.C.D)
+ - Neighbor tag
+ - Neighbor ipv6 address (X:X:X:X::X)
+ type: str
+ address:
+ description:
+ - Neighbor address (A.B.C.D)
+ - This option is DEPRECATED and replaced with neighbor_address,
+ this attribute will be removed after 2024-06-01.
+ type: str
+ tag:
+ description:
+ - Neighbor tag
+ - This option is DEPRECATED and replaced with neighbor_address,
+ this attribute will be removed after 2024-06-01.
+ type: str
+ ipv6_adddress:
+ description:
+ - Neighbor ipv6 address (X:X:X:X::X)
+ - This option is DEPRECATED and replaced with neighbor_address,
+ this attribute will be removed after 2024-06-01.
+ type: str
+ activate:
+ description: Enable the Address Family for this Neighbor
+ type: bool
+ additional_paths:
+ description: Negotiate additional paths capabilities with this neighbor
+ type: dict
+ suboptions:
+ disable:
+ description: Disable additional paths for this neighbor
+ type: bool
+ receive:
+ description: Receive additional paths from neighbors
+ type: bool
+ send:
+ description: Send additional paths to neighbors
+ type: bool
+ advertise:
+ description: Advertise to this neighbor
+ type: dict
+ suboptions:
+ additional_paths:
+ description: Advertise additional paths
+ type: dict
+ suboptions:
+ all:
+ description: Select all available paths
+ type: bool
+ best:
+ description: Select best N paths (2-3).
+ type: int
+ group_best:
+ description: Select group-best path
+ type: bool
+ best_external:
+ description: Advertise best-external (at RRs best-internal) path
+ type: bool
+ diverse_path:
+ description: Advertise additional paths
+ type: dict
+ suboptions:
+ backup:
+ description: Diverse path can be backup path
+ type: bool
+ mpath:
+ description: Diverse path can be multipath
+ type: bool
+ advertise_map:
+ description: specify route-map for conditional advertisement
+ type: dict
+ suboptions:
+ name:
+ description: advertise route-map name
+ type: str
+ exist_map:
+ description:
+ - advertise prefix only if prefix is in the condition exists
+ - condition route-map name
+ type: str
+ non_exist_map:
+ description:
+ - advertise prefix only if prefix in the condition does not exist
+ - condition route-map name
+ type: str
+ advertisement_interval:
+ description: Minimum interval between sending BGP routing updates
+ type: int
+ aigp:
+ description: AIGP on neighbor
+ type: dict
+ suboptions:
+ enable:
+ description: Enable AIGP
+ type: bool
+ send:
+ description: Cost community or MED carrying AIGP VALUE
+ type: dict
+ suboptions:
+ cost_community:
+ description: Cost extended community carrying AIGP Value
+ type: dict
+ suboptions:
+ id:
+ description:
+ - Community ID
+ - Please refer vendor documentation for valid values
+ type: int
+ poi:
+ description: Point of Insertion
+ type: dict
+ suboptions:
+ igp_cost:
+ description: Point of Insertion After IGP
+ type: bool
+ pre_bestpath:
+ description: Point of Insertion At Beginning
+ type: bool
+ transitive:
+ description: Cost community is Transitive
+ type: bool
+ med:
+ description: Med carrying AIGP Value
+ type: bool
+ allow_policy:
+ description: Enable the policy support for this IBGP Neighbor
+ type: bool
+ allowas_in:
+ description: Accept as-path with my AS present in it
+ type: int
+ as_override:
+ description:
+ - Override matching AS-number while sending update
+ - Maintain Split Horizon while sending update
+ type: bool
+ bmp_activate:
+ description: Activate the BMP monitoring for a BGP peer
+ type: dict
+ suboptions:
+ all:
+ description: Activate BMP monitoring for all servers
+ type: bool
+ server:
+ description:
+ - Activate BMP for server
+ - BMP Server Number
+ - Please refer vendor documentation for valid values
+ type: int
+ capability:
+ description:
+ - Advertise capability to the peer
+ - Advertise ORF capability to the peer
+ - Advertise prefix-list ORF capability to this neighbor
+ type: dict
+ suboptions:
+ both:
+ description: Capability to SEND and RECEIVE the ORF to/from this neighbor
+ type: bool
+ receive:
+ description: Capability to RECEIVE the ORF from this neighbor
+ type: bool
+ send:
+ description: Capability to SEND the ORF to this neighbor
+ type: bool
+ cluster_id:
+ description:
+ - Configure Route-Reflector Cluster-id (peers may reset)
+ - Route-Reflector Cluster-id as 32 bit quantity, or
+ Route-Reflector Cluster-id in IP address format (A.B.C.D)
+ type: str
+ default_originate:
+ description: Originate default route to this neighbor
+ type: dict
+ suboptions:
+ set:
+ description: Originate default route to this neighbor
+ type: bool
+ route_map:
+ description: Route-map to specify criteria to originate default
+ type: str
+ description:
+ description: Neighbor specific description
+ type: str
+ disable_connected_check:
+ description: one-hop away EBGP peer using loopback address
+ type: bool
+ distribute_list:
+ description: Filter updates to/from this neighbor
+ type: dict
+ suboptions:
+ acl:
+ description: IP access list number/name
+ type: str
+ in:
+ description: Filter incoming updates
+ type: bool
+ out:
+ description: Filter outgoing updates
+ type: bool
+ dmzlink_bw:
+ description: Propagate the DMZ link bandwidth
+ type: bool
+ ebgp_multihop:
+ description: Allow EBGP neighbors not on directly connected networks
+ type: dict
+ suboptions:
+ enable:
+ description: Allow EBGP neighbors not on directly connected networks
+ type: bool
+ hop_count:
+ description:
+ - Maximum hop count
+ - Please refer vendor documentation for valid values
+ type: int
+ fall_over:
+ description: Session fall on peer route lost
+ type: dict
+ suboptions:
+ bfd:
+ description: Use BFD to detect failure
+ type: dict
+ suboptions:
+ set:
+ description: set bfd
+ type: bool
+ multi_hop:
+ description: Force BFD multi-hop to detect failure
+ type: bool
+ single_hop:
+ description: Force BFD single-hop to detect failure
+ type: bool
+ route_map:
+ description: Route map for peer route
+ type: str
+ filter_list:
+ description: Establish BGP filters
+ type: dict
+ suboptions:
+ path_acl:
+ description: AS path access list
+ type: str
+ in:
+ description: Filter incoming updates
+ type: bool
+ out:
+ description: Filter outgoing updates
+ type: bool
+ ha_mode:
+ description: high availability mode
+ type: dict
+ suboptions:
+ set:
+ description: set ha-mode and graceful-restart for this peer
+ type: bool
+ disable:
+ description: disable graceful-restart
+ type: bool
+ inherit:
+ description:
+ - Inherit a template
+ - Inherit a peer-session template and Template name
+ type: str
+ local_as:
+ description: Specify a local-as number
+ type: dict
+ suboptions:
+ set:
+ description: set local-as number
+ type: bool
+ number:
+ description:
+ - AS number used as local AS
+ - Please refer vendor documentation for valid values
+ type: int
+ dual_as:
+ description: Accept either real AS or local AS from the ebgp peer
+ type: bool
+ no_prepend:
+ description: Do not prepend local-as to updates from ebgp peers
+ type: dict
+ suboptions:
+ set:
+ description: Set prepend
+ type: bool
+ replace_as:
+ description: Replace real AS with local AS in the EBGP updates
+ type: bool
+ log_neighbor_changes:
+ description: Log neighbor up/down and reset reason
+ type: dict
+ suboptions:
+ set:
+ description: set Log neighbor up/down and reset
+ type: bool
+ disable:
+ description: disable Log neighbor up/down and reset
+ type: bool
+ maximum_prefix:
+ description: Maximum number of prefixes accepted from this peer
+ type: dict
+ suboptions:
+ max_no:
+ description: maximum no. of prefix limit
+ type: int
+ threshold_val:
+ description: Threshold value (%) at which to generate a warning msg
+ type: int
+ restart:
+ description: Restart bgp connection after limit is exceeded
+ type: int
+ warning_only:
+ description: Only give warning message when limit is exceeded
+ type: bool
+ next_hop_self:
+ description: Disable the next hop calculation for this neighbor
+ type: dict
+ suboptions:
+ set:
+ description: Enable next-hop-self
+ type: bool
+ all:
+ description: Enable next-hop-self for both eBGP and iBGP received paths
+ type: bool
+ next_hop_unchanged:
+ description:
+ - Propagate next hop unchanged for iBGP paths to this neighbor
+ - Propagate next hop unchanged for all paths (iBGP and eBGP) to this neighbor
+ type: dict
+ suboptions:
+ set:
+ description: Enable next-hop-unchanged
+ type: bool
+ allpaths:
+ description: Propagate next hop unchanged for all paths (iBGP and eBGP) to this neighbor
+ type: bool
+ password:
+ description:
+ - Set a password
+ - This option is DEPRECATED and is replaced with password_options which
+ accepts dict as input, this attribute will be removed after 2024-06-01.
+ type: str
+ password_options:
+ description: Set a password with encryption type
+ type: dict
+ suboptions:
+ encryption:
+ description: Encryption type (0 to disable encryption, 7 for proprietary)
+ type: int
+ pass_key:
+ description: The password
+ type: str
+ path_attribute:
+ description: BGP optional attribute filtering
+ type: dict
+ suboptions:
+ discard:
+ description: Discard matching path-attribute for this neighbor
+ type: dict
+ suboptions:
+ type:
+ description:
+ - path attribute type
+ - Please refer vendor documentation for valid values
+ type: int
+ range:
+ description: path attribute range
+ type: dict
+ suboptions:
+ start:
+ description:
+ - path attribute range start value
+ - Please refer vendor documentation for valid values
+ type: int
+ end:
+ description:
+ - path attribute range end value
+ - Please refer vendor documentation for valid values
+ type: int
+ in:
+ description: Perform inbound path-attribute filtering
+ type: bool
+ treat_as_withdraw:
+ description: Treat-as-withdraw matching path-attribute for this neighbor
+ type: dict
+ suboptions:
+ type:
+ description:
+ - path attribute type
+ - Please refer vendor documentation for valid values
+ type: int
+ range:
+ description: path attribute range
+ type: dict
+ suboptions:
+ start:
+ description:
+ - path attribute range start value
+ - Please refer vendor documentation for valid values
+ type: int
+ end:
+ description:
+ - path attribute range end value
+ - Please refer vendor documentation for valid values
+ type: int
+ in:
+ description: Perform inbound path-attribute filtering
+ type: bool
+ peer_group:
+ description: Member of the peer-group
+ type: str
+ remote_as:
+ description:
+ - Specify a BGP neighbor
+ - AS of remote neighbor
+ type: str
+ remove_private_as:
+ description: Remove private AS number from outbound updates
+ type: dict
+ suboptions:
+ set:
+ description: Remove private AS number
+ type: bool
+ all:
+ description: Remove all private AS numbers
+ type: bool
+ replace_as:
+ description: Replace all private AS numbers with local AS
+ type: bool
+ route_map:
+ description:
+ - Apply route map to neighbor
+ - This option is DEPRECATED and is replaced with route_maps which
+ accepts list of dict as input, this attribute will be removed after 2024-06-01.
+ type: dict
+ suboptions:
+ name:
+ description: Replace all private AS numbers with local AS
+ type: str
+ in:
+ description: Apply map to incoming routes
+ type: bool
+ out:
+ description: Apply map to outbound routes
+ type: bool
+ route_maps:
+ description: Apply a list of route maps to neighbor
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Replace all private AS numbers with local AS
+ type: str
+ in:
+ description: Apply map to incoming routes
+ type: bool
+ out:
+ description: Apply map to outbound routes
+ type: bool
+ route_reflector_client:
+ description: Configure a neighbor as Route Reflector client
+ type: bool
+ route_server_client:
+ description: Configure a neighbor as Route Server client
+ type: dict
+ suboptions:
+ set:
+ description: Set Route Server client
+ type: bool
+ context:
+ description:
+ - Specify Route Server context for neighbor
+ - Route Server context name
+ type: str
+ send_community:
+ description: Send Community attribute to this neighbor
+ type: dict
+ suboptions:
+ set:
+ description: Set send Community attribute to this neighbor
+ type: bool
+ both:
+ description: Send Standard and Extended Community attributes
+ type: bool
+ extended:
+ description: Send Extended Community attribute
+ type: bool
+ standard:
+ description: Send Standard Community attribute
+ type: bool
+ send_label:
+ description: Send NLRI + MPLS Label to this peer
+ type: dict
+ suboptions:
+ set:
+ description: Set send NLRI + MPLS Label to this peer
+ type: bool
+ explicit_null:
+ description: Advertise Explicit Null label in place of Implicit Null
+ type: bool
+ shutdown:
+ description: Administratively shut down this neighbor
+ type: dict
+ suboptions:
+ set:
+ description: shut down
+ type: bool
+ graceful:
+ description:
+ - Gracefully shut down this neighbor
+ - time in seconds
+ - Please refer vendor documentation for valid values
+ type: int
+ community:
+ description: Set Community for Gshut routes
+ type: int
+ local_preference:
+ description: Set Local Preference for Gshut routes
+ type: bool
+ slow_peer:
+ description: Configure slow-peer
+ type: dict
+ suboptions:
+ detection:
+ description: Configure slow-peer
+ type: dict
+ suboptions:
+ enable:
+ description: Enable slow-peer detection
+ type: bool
+ disable:
+ description: Disable slow-peer detection
+ type: bool
+ threshold:
+ description: Set the slow-peer detection threshold
+ type: int
+ split_update_group:
+ description: Configure slow-peer split-update-group
+ type: dict
+ suboptions:
+ dynamic:
+ description: Dynamically split the slow peer to slow-update group
+ type: dict
+ suboptions:
+ enable:
+ description: Enable slow-peer detection
+ type: bool
+ disable:
+ description: Disable slow-peer detection
+ type: bool
+ permanent:
+ description: Keep the slow-peer permanently in slow-update group
+ type: bool
+ static:
+ description: Static slow-peer
+ type: bool
+ soft_reconfiguration:
+ description:
+ - Per neighbor soft reconfiguration
+ - Allow inbound soft reconfiguration for this neighbor
+ type: bool
+ timers:
+ description: BGP per neighbor timers
+ type: dict
+ suboptions:
+ interval:
+ description: Keepalive interval
+ type: int
+ holdtime:
+ description: Holdtime
+ type: int
+ min_holdtime:
+ description: Minimum hold time from neighbor
+ type: int
+ translate_update:
+ description: Translate Update to MBGP format
+ type: dict
+ suboptions:
+ set:
+ description: Set Translate Update
+ type: bool
+ nlri:
+ description: Specify type of nlri to translate to
+ type: dict
+ suboptions:
+ multicast:
+ description: Translate Update to multicast nlri
+ type: bool
+ unicast:
+ description: Process Update as unicast nlri
+ type: bool
+ transport:
+ description: Transport options
+ type: dict
+ suboptions:
+ connection_mode:
+ description: Specify passive or active connection
+ type: dict
+ suboptions:
+ active:
+ description: Actively establish the TCP session
+ type: bool
+ passive:
+ description: Passively establish the TCP session
+ type: bool
+ multi_session:
+ description: Use Multi-session for transport
+ type: bool
+ path_mtu_discovery:
+ description: Use transport path MTU discovery
+ type: dict
+ suboptions:
+ set:
+ description: Use path MTU discovery
+ type: bool
+ disable:
+ description: disable
+ type: bool
+ ttl_security:
+ description:
+ - BGP ttl security check
+ - maximum number of hops
+ - Please refer vendor documentation for valid values
+ type: int
+ unsuppress_map:
+ description:
+ - Route-map to selectively un-suppress suppressed routes
+ - Name of route map
+ type: str
+ update_source:
+ description: Source of routing updates
+ type: str
+ version:
+ description:
+ - Set the BGP version to match a neighbor
+ - Neighbor's BGP version
+ - Please refer vendor documentation for valid values
+ type: int
+ weight:
+ description: Set default weight for routes from this neighbor
+ type: int
+ networks:
+ description: Specify a network to announce via BGP
+ type: list
+ elements: dict
+ suboptions:
+ address:
+ description: Specify network address
+ type: str
+ netmask:
+ description: Specify network mask
+ type: str
+ route_map:
+ description: Route-map to modify the attributes
+ type: str
+ backdoor:
+ description: Specify a BGP backdoor route
+ type: bool
+ redistribute:
+ description: Redistribute information from another routing protocol
+ type: list
+ elements: dict
+ suboptions:
+ application:
+ description: Application
+ type: dict
+ suboptions:
+ name:
+ description: Application name
+ type: str
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ bgp:
+ description: Border Gateway Protocol (BGP)
+ type: dict
+ suboptions:
+ as_number:
+ description: Autonomous system number
+ type: str
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ connected:
+ description: Connected
+ type: dict
+ suboptions:
+ set:
+ description: Set the top level attribute
+ type: bool
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ eigrp:
+ description: Enhanced Interior Gateway Routing Protocol (EIGRP)
+ type: dict
+ suboptions:
+ as_number:
+ description: Autonomous system number
+ type: str
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ isis:
+ description: ISO IS-IS
+ type: dict
+ suboptions:
+ area_tag:
+ description: ISO routing area tag
+ type: str
+ clns:
+ description: Redistribution of OSI dynamic routes
+ type: bool
+ ip:
+ description: Redistribution of IP dynamic routes
+ type: bool
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ iso_igrp:
+ description: IGRP for OSI networks
+ type: dict
+ suboptions:
+ area_tag:
+ description: ISO routing area tag
+ type: str
+ route_map:
+ description: Route map reference
+ type: str
+ lisp:
+ description: Locator ID Separation Protocol (LISP)
+ type: dict
+ suboptions:
+ set:
+ description: Set the top level attribute
+ type: bool
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ mobile:
+ description: Mobile routes
+ type: dict
+ suboptions:
+ set:
+ description: Set the top level attribute
+ type: bool
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ odr:
+ description: On Demand stub Routes
+ type: dict
+ suboptions:
+ set:
+ description: Set the top level attribute
+ type: bool
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ ospf:
+ description: Open Shortest Path First (OSPF)
+ type: dict
+ suboptions:
+ process_id:
+ description: Process ID
+ type: int
+ match:
+ description: On Demand stub Routes
+ type: dict
+ suboptions:
+ external:
+ description: Redistribute OSPF external routes
+ type: bool
+ internal:
+ description: Redistribute OSPF internal routes
+ type: bool
+ nssa_external:
+ description: Redistribute OSPF NSSA external routes
+ type: bool
+ type_1:
+ description: Redistribute NSSA external type 1 routes
+ type: bool
+ type_2:
+ description: Redistribute NSSA external type 2 routes
+ type: bool
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ vrf:
+ description: VPN Routing/Forwarding Instance
+ type: str
+ ospfv3:
+ description: OSPFv3
+ type: dict
+ suboptions:
+ process_id:
+ description: Process ID
+ type: int
+ match:
+ description: On Demand stub Routes
+ type: dict
+ suboptions:
+ external:
+ description: Redistribute OSPF external routes
+ type: bool
+ internal:
+ description: Redistribute OSPF internal routes
+ type: bool
+ nssa_external:
+ description: Redistribute OSPF NSSA external routes
+ type: bool
+ type_1:
+ description: Redistribute NSSA external type 1 routes
+ type: bool
+ type_2:
+ description: Redistribute NSSA external type 2 routes
+ type: bool
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ rip:
+ description: Routing Information Protocol (RIP)
+ type: dict
+ suboptions:
+ set:
+ description: Set the top level attribute
+ type: bool
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ static:
+ description: Static routes
+ type: dict
+ suboptions:
+ set:
+ description: Set the top level attribute
+ type: bool
+ clns:
+ description: Redistribution of OSI static routes
+ type: bool
+ ip:
+ description: Redistribution of IP static routes
+ type: bool
+ metric:
+ description: Metric for redistributed routes
+ type: int
+ route_map:
+ description: Route map reference
+ type: str
+ vrf:
+ description: Specify a source VRF
+ type: dict
+ suboptions:
+ name:
+ description: Source VRF name
+ type: str
+ global:
+ description: global VRF
+ type: bool
+ route_server_context:
+ description:
+ - Enter route server context command mode
+ - This option is DEPRECATED as it is out of scope of the module,
+ this attribute will be removed after 2024-06-01.
+ type: dict
+ suboptions:
+ name:
+ description: Name of route server context
+ type: str
+ address_family:
+ description: Enter address family command mode
+ type: dict
+ suboptions:
+ afi:
+ description: Address family
+ type: str
+ choices: ["ipv4", "ipv6"]
+ modifier:
+ description: Address Family modifier
+ type: str
+ choices: ["multicast", "unicast"]
+ import_map:
+ description:
+ - Import matching routes using a route map
+ - Name of route map
+ type: str
+ description:
+ description: Textual description of the router server context
+ type: str
+ scope:
+ description:
+ - Enter scope command mode
+ - This option is DEPRECATED as is not valid within the scope of module,
+ this attribute will be removed after 2024-06-01.
+ type: dict
+ suboptions:
+ global:
+ description: Global scope
+ type: bool
+ vrf:
+ description:
+ - VRF scope
+ - VPN Routing/Forwarding instance name
+ type: str
+ synchronization:
+ description: Perform IGP synchronization
+ type: bool
+ table_map:
+ description: Map external entry attributes into routing table
+ type: dict
+ suboptions:
+ name:
+ description: route-map name
+ type: str
+ filter:
+ description: Selective route download
+ type: bool
+ template:
+ description:
+ - Enter template command mode
+ - This option is DEPRECATED as is not valid within the scope of module,
+ this attribute will be removed after 2024-06-01.
+ type: dict
+ suboptions:
+ peer_policy:
+ description: Template configuration for policy parameters
+ type: str
+ peer_session:
+ description: Template configuration for session parameters
+ type: str
+ timers:
+ description:
+ - Adjust routing timers
+ - BGP timers
+ type: dict
+ suboptions:
+ keepalive:
+ description: Keepalive interval
+ type: int
+ holdtime:
+ description: Holdtime
+ type: int
+ min_holdtime:
+ description: Minimum hold time from neighbor
+ type: int
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS
+ device by executing the command B(sh running-config | section ^router bgp).
+ - The state I(parsed) reads the configuration from C(running_config)
+ option and transforms it into Ansible structured data as per the
+ resource module's argspec and the value is then returned in the
+ I(parsed) key within the result.
+ type: str
+ state:
+ choices:
+ - merged
+ - replaced
+ - deleted
+ - purged
+ - gathered
+ - rendered
+ - parsed
+ default: merged
+ description:
+ - The state the configuration should be left in
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device.
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result. For state I(rendered) active connection to remote host is
+ not required.
+ - The state I(gathered) will fetch the running configuration from device and transform
+ it into structured data in the format as per the resource module argspec and
+ the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result. The value of C(running_config)
+ option should be the same format as the output of command I(show running-config
+ | include ip route|ipv6 route) executed on device. For state I(parsed) active
+ connection to remote host is not required.
+ type: str
+"""
+
+EXAMPLES = """
+# Using merged
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+
+- name: Merge provided configuration with device configuration
+ cisco.ios.ios_bgp_global:
+ config:
+ as_number: 65000
+ bgp:
+ advertise_best_external: true
+ bestpath:
+ - compare_routerid: true
+ dampening:
+ penalty_half_time: 1
+ reuse_route_val: 1
+ suppress_route_val: 1
+ max_suppress: 1
+ graceful_shutdown:
+ neighbors:
+ time: 50
+ community: 100
+ local_preference: 100
+ log_neighbor_changes: true
+ nopeerup_delay:
+ - post_boot: 10
+ networks:
+ - address: 192.0.2.3
+ - address: 192.0.2.2
+ neighbor:
+ - address: 192.0.2.1
+ description: merge neighbor
+ remote_as: 100
+ aigp:
+ send:
+ cost_community:
+ id: 100
+ poi:
+ igp_cost: true
+ transitive: true
+ route_map:
+ name: test-route
+ out: true
+ redistribute:
+ - connected:
+ metric: 10
+ timers:
+ keepalive: 100
+ holdtime: 200
+ min_holdtime: 150
+ state: merged
+
+# Task Output:
+# ------------
+#
+# before: {}
+# commands:
+# - router bgp 65000
+# - timers bgp 100 200 150
+# - bgp advertise-best-external
+# - bgp bestpath compare-routerid
+# - bgp dampening 1 1 1 1
+# - bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# - bgp log-neighbor-changes
+# - bgp nopeerup-delay post-boot 10
+# - network 192.0.2.3
+# - network 192.0.2.2
+# - neighbor 192.0.2.1 remote-as 100
+# - neighbor 192.0.2.1 description merge neighbor
+# - neighbor 192.0.2.1 aigp send cost-community 100 poi igp-cost transitive
+# - neighbor 192.0.2.1 route-map test-route out
+# - redistribute connected metric 10
+# after:
+# as_number: '65000'
+# bgp:
+# advertise_best_external: true
+# bestpath_options:
+# compare_routerid: true
+# dampening:
+# max_suppress: 1
+# penalty_half_time: 1
+# reuse_route_val: 1
+# suppress_route_val: 1
+# graceful_shutdown:
+# community: '100'
+# local_preference: 100
+# neighbors:
+# time: 50
+# log_neighbor_changes: true
+# nopeerup_delay_options:
+# post_boot: 10
+# neighbors:
+# - aigp:
+# send:
+# cost_community:
+# id: 100
+# poi:
+# igp_cost: true
+# transitive: true
+# description: merge neighbor
+# neighbor_address: 192.0.2.1
+# remote_as: '100'
+# route_maps:
+# - name: test-route
+# out: true
+# networks:
+# - address: 192.0.2.2
+# - address: 192.0.2.3
+# redistribute:
+# - connected:
+# metric: 10
+# set: true
+# timers:
+# holdtime: 200
+# keepalive: 100
+# min_holdtime: 150
+
+# After state:
+# ------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp log-neighbor-changes
+# bgp nopeerup-delay post-boot 10
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# bgp bestpath compare-routerid
+# bgp dampening 1 1 1 1
+# bgp advertise-best-external
+# network 192.0.2.2
+# network 192.0.2.3
+# timers bgp 100 200 150
+# redistribute connected metric 10
+# neighbor 192.0.2.1 remote-as 100
+# neighbor 192.0.2.1 description merge neighbor
+# neighbor 192.0.2.1 aigp send cost-community 100 poi igp-cost transitive
+# neighbor 192.0.2.1 route-map test-route out
+
+# Using replaced
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp nopeerup-delay post-boot 10
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# bgp bestpath compare-routerid
+# bgp dampening 1 1 1 1
+# network 192.0.2.2
+# network 192.0.2.3
+# bgp advertise-best-external
+# neighbor 198.0.2.1 remote-as 100
+# neighbor 198.0.2.1 description merge neighbor
+# neighbor 198.0.2.1 aigp send cost-community 100 poi igp-cost transitive
+# neighbor 198.0.2.1 route-map test-route out
+
+- name: Replaces device configuration of listed global BGP with provided configuration
+ cisco.ios.ios_bgp_global:
+ config:
+ as_number: 65000
+ bgp:
+ advertise_best_external: true
+ bestpath:
+ - med:
+ confed: true
+ log_neighbor_changes: true
+ nopeerup_delay:
+ - post_boot: 10
+ cold_boot: 20
+ networks:
+ - address: 192.0.2.4
+ neighbor:
+ - address: 192.0.2.5
+ description: replace neighbor
+ remote_as: 100
+ slow_peer:
+ detection:
+ disable: true
+ state: replaced
+
+# Task Output:
+# ------------
+#
+# before:
+# as_number: '65000'
+# bgp:
+# advertise_best_external: true
+# bestpath_options:
+# compare_routerid: true
+# dampening:
+# max_suppress: 1
+# penalty_half_time: 1
+# reuse_route_val: 1
+# suppress_route_val: 1
+# graceful_shutdown:
+# community: '100'
+# local_preference: 100
+# neighbors:
+# time: 50
+# log_neighbor_changes: true
+# nopeerup_delay_options:
+# post_boot: 10
+# neighbors:
+# - aigp:
+# send:
+# cost_community:
+# id: 100
+# poi:
+# igp_cost: true
+# transitive: true
+# description: merge neighbor
+# neighbor_address: 198.0.2.1
+# remote_as: '100'
+# route_maps:
+# - name: test-route
+# out: true
+# networks:
+# - address: 192.0.2.2
+# - address: 192.0.2.3
+# commands:
+# - router bgp 65000
+# - no bgp bestpath compare-routerid
+# - bgp bestpath med confed
+# - no bgp dampening 1 1 1 1
+# - no bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# - bgp nopeerup-delay cold-boot 20
+# - network 192.0.2.4
+# - no network 192.0.2.2
+# - no network 192.0.2.3
+# - neighbor 192.0.2.5 remote-as 100
+# - neighbor 192.0.2.5 description replace neighbor
+# - neighbor 192.0.2.5 slow-peer detection disable
+# - no neighbor 198.0.2.1
+# after:
+# as_number: '65000'
+# bgp:
+# advertise_best_external: true
+# bestpath_options:
+# med:
+# confed: true
+# log_neighbor_changes: true
+# nopeerup_delay_options:
+# cold_boot: 20
+# post_boot: 10
+# neighbors:
+# - description: replace neighbor
+# neighbor_address: 192.0.2.5
+# remote_as: '100'
+# slow_peer:
+# detection:
+# disable: true
+# networks:
+# - address: 192.0.2.4
+
+# After state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp log-neighbor-changes
+# bgp nopeerup-delay cold-boot 20
+# bgp nopeerup-delay post-boot 10
+# bgp bestpath med confed
+# bgp advertise-best-external
+# network 192.0.2.4
+# neighbor 192.0.2.5 remote-as 100
+# neighbor 192.0.2.5 description replace neighbor
+# neighbor 192.0.2.5 slow-peer detection disable
+
+# Using Deleted
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp nopeerup-delay post-boot 10
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# bgp bestpath compare-routerid
+# bgp dampening 1 1 1 1
+# bgp advertise-best-external
+# neighbor 192.0.2.1 remote-as 100
+# neighbor 192.0.2.1 description merge neighbor
+# neighbor 192.0.2.1 aigp send cost-community 100 poi igp-cost transitive
+# neighbor 192.0.2.1 route-map test-route out
+
+- name: "Delete global BGP (Note: This won't delete the configured global BGP)"
+ cisco.ios.ios_bgp_global:
+ config:
+ as_number: 65000
+ state: deleted
+
+# Task Output:
+# ------------
+#
+# before:
+# as_number: '65000'
+# bgp:
+# advertise_best_external: true
+# bestpath_options:
+# compare_routerid: true
+# dampening:
+# max_suppress: 1
+# penalty_half_time: 1
+# reuse_route_val: 1
+# suppress_route_val: 1
+# graceful_shutdown:
+# community: '100'
+# local_preference: 100
+# neighbors:
+# time: 50
+# log_neighbor_changes: true
+# nopeerup_delay_options:
+# post_boot: 10
+# neighbors:
+# - aigp:
+# send:
+# cost_community:
+# id: 100
+# poi:
+# igp_cost: true
+# transitive: true
+# description: merge neighbor
+# neighbor_address: 192.0.2.1
+# remote_as: '100'
+# route_maps:
+# - name: test-route
+# out: true
+# commands:
+# - router bgp 65000
+# - no bgp advertise-best-external
+# - no bgp bestpath compare-routerid
+# - no bgp dampening 1 1 1 1
+# - no bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# - no bgp log-neighbor-changes
+# - no bgp nopeerup-delay post-boot 10
+# - no neighbor 192.0.2.1
+# after:
+# as_number: '65000'
+
+# After state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+
+# Using Deleted without any config passed
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp nopeerup-delay post-boot 10
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# bgp bestpath compare-routerid
+# bgp dampening 1 1 1 1
+# bgp advertise-best-external
+# neighbor 192.0.2.1 remote-as 100
+# neighbor 192.0.2.1 description merge neighbor
+# neighbor 192.0.2.1 aigp send cost-community 100 poi igp-cost transitive
+# neighbor 192.0.2.1 route-map test-route out
+
+- name: Delete global BGP without config
+ cisco.ios.ios_bgp_global:
+ state: deleted
+
+# Task Output:
+# ------------
+#
+# before:
+# as_number: '65000'
+# bgp:
+# advertise_best_external: true
+# bestpath_options:
+# compare_routerid: true
+# dampening:
+# max_suppress: 1
+# penalty_half_time: 1
+# reuse_route_val: 1
+# suppress_route_val: 1
+# graceful_shutdown:
+# community: '100'
+# local_preference: 100
+# neighbors:
+# time: 50
+# log_neighbor_changes: true
+# nopeerup_delay_options:
+# post_boot: 10
+# neighbors:
+# - aigp:
+# send:
+# cost_community:
+# id: 100
+# poi:
+# igp_cost: true
+# transitive: true
+# description: merge neighbor
+# neighbor_address: 192.0.2.1
+# remote_as: '100'
+# route_maps:
+# - name: test-route
+# out: true
+# commands:
+# - router bgp 65000
+# - no bgp advertise-best-external
+# - no bgp bestpath compare-routerid
+# - no bgp dampening 1 1 1 1
+# - no bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# - no bgp nopeerup-delay post-boot 10
+# - no neighbor 198.51.100.1
+# after:
+# as_number: '65000'
+
+# After state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+
+# Using purged - would delete all configuration
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp nopeerup-delay post-boot 10
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# bgp bestpath compare-routerid
+# bgp dampening 1 1 1 1
+# bgp advertise-best-external
+# neighbor 192.0.2.1 remote-as 100
+# neighbor 192.0.2.1 description merge neighbor
+# neighbor 192.0.2.1 aigp send cost-community 100 poi igp-cost transitive
+# neighbor 192.0.2.1 route-map test-route out
+
+- name:
+ "Delete the configured global BGP (Note: This WILL delete the the configured
+ global BGP)"
+ cisco.ios.ios_bgp_global:
+ state: purged
+
+# Task Output:
+# ------------
+#
+# before:
+# as_number: '65000'
+# bgp:
+# advertise_best_external: true
+# bestpath_options:
+# compare_routerid: true
+# dampening:
+# max_suppress: 1
+# penalty_half_time: 1
+# reuse_route_val: 1
+# suppress_route_val: 1
+# graceful_shutdown:
+# community: '100'
+# local_preference: 100
+# neighbors:
+# time: 50
+# log_neighbor_changes: true
+# nopeerup_delay_options:
+# post_boot: 10
+# neighbors:
+# - aigp:
+# send:
+# cost_community:
+# id: 100
+# poi:
+# igp_cost: true
+# transitive: true
+# description: merge neighbor
+# neighbor_address: 192.0.2.1
+# remote_as: '100'
+# route_maps:
+# - name: test-route
+# out: true
+# commands:
+# - no router bgp 65000
+# after: {}
+
+# After state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+
+# Using gathered
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^router bgp
+# router bgp 65000
+# bgp log-neighbor-changes
+# bgp nopeerup-delay post-boot 10
+# bgp graceful-shutdown all neighbors 50 local-preference 100 community 100
+# bgp bestpath compare-routerid
+# bgp dampening 1 1 1 1
+# bgp advertise-best-external
+# network 192.0.2.3
+# timers bgp 100 200 150
+# redistribute connected metric 10
+# neighbor 192.0.2.1 remote-as 100
+# neighbor 192.0.2.1 description merge neighbor
+# neighbor 192.0.2.1 aigp send cost-community 100 poi igp-cost transitive
+# neighbor 192.0.2.1 route-map test-route out
+
+- name: Gather facts for bgp_global
+ cisco.ios.ios_bgp_global:
+ config:
+ state: gathered
+
+# Task Output:
+# ------------
+#
+# gathered:
+# as_number: '65000'
+# bgp:
+# advertise_best_external: true
+# bestpath_options:
+# compare_routerid: true
+# dampening:
+# max_suppress: 1
+# penalty_half_time: 1
+# reuse_route_val: 1
+# suppress_route_val: 1
+# graceful_shutdown:
+# community: '100'
+# local_preference: 100
+# neighbors:
+# time: 50
+# log_neighbor_changes: true
+# nopeerup_delay_options:
+# post_boot: 10
+# neighbors:
+# - aigp:
+# send:
+# cost_community:
+# id: 100
+# poi:
+# igp_cost: true
+# transitive: true
+# description: merge neighbor
+# neighbor_address: 192.0.2.1
+# remote_as: '100'
+# route_maps:
+# - name: test-route
+# out: true
+# networks:
+# - address: 192.0.2.3
+# redistribute:
+# - connected:
+# metric: 10
+# set: true
+# timers:
+# holdtime: 200
+# keepalive: 100
+# min_holdtime: 150
+
+# Using Rendered
+
+- name: Rendered the provided configuration with the existing running configuration
+ cisco.ios.ios_bgp_global:
+ config:
+ aggregate_addresses:
+ - address: 192.0.2.1
+ attribute_map: testMap1
+ netmask: 255.255.255.0
+ summary_only: true
+ - address: 192.0.2.2
+ as_set: true
+ netmask: 255.255.255.0
+ - address: 192.0.2.3
+ as_set: true
+ netmask: 255.255.255.0
+ as_number: "65000"
+ auto_summary: true
+ bgp:
+ additional_paths:
+ install: true
+ receive: true
+ aggregate_timer: 0
+ always_compare_med: true
+ asnotation: true
+ bestpath_options:
+ aigp: true
+ compare_routerid: true
+ med:
+ confed: true
+ missing_as_worst: true
+ confederation:
+ identifier: "22"
+ consistency_checker:
+ error_message:
+ interval: 10
+ set: true
+ dampening:
+ route_map: routeMap1Test
+ deterministic_med: true
+ graceful_restart:
+ restart_time: 2
+ stalepath_time: 22
+ graceful_shutdown:
+ community: "77"
+ local_preference: 230
+ vrfs:
+ time: 31
+ inject_maps:
+ - copy_attributes: true
+ exist_map_name: Testmap3
+ name: map2
+ - copy_attributes: true
+ exist_map_name: Testmap2
+ name: map1
+ listen:
+ limit: 200
+ range:
+ host_with_subnet: 192.0.2.1/24
+ peer_group: PaulNetworkGroup
+ log_neighbor_changes: true
+ maxas_limit: 2
+ maxcommunity_limit: 3
+ maxextcommunity_limit: 3
+ nexthop:
+ route_map: RouteMap1
+ trigger:
+ delay: 2
+ nopeerup_delay_options:
+ cold_boot: 2
+ nsf_switchover: 10
+ post_boot: 22
+ user_initiated: 22
+ recursion: true
+ redistribute_internal: true
+ refresh:
+ max_eor_time: 700
+ stalepath_time: 800
+ router_id:
+ vrf: true
+ scan_time: 22
+ slow_peer:
+ detection:
+ threshold: 345
+ split_update_group:
+ dynamic: true
+ permanent: true
+ sso: true
+ suppress_inactive: true
+ update_delay: 2
+ update_group: true
+ bmp:
+ buffer_size: 22
+ server: 2
+ distance:
+ bgp:
+ routes_external: 2
+ routes_internal: 3
+ routes_local: 4
+ mbgp:
+ routes_external: 2
+ routes_internal: 3
+ routes_local: 5
+ distributes:
+ - in: true
+ prefix: prefixTest
+ - gateway: gatewayTest
+ out: true
+ - acl: "300"
+ interface: Loopback0
+ out: true
+ maximum_paths:
+ ibgp: 2
+ paths: 2
+ maximum_secondary_paths:
+ ibgp: 22
+ paths: 22
+ neighbors:
+ - neighbor_address: 192.0.2.10
+ remote_as: "64500"
+ update_source: Loopback1
+ - activate: true
+ neighbor_address: 192.0.2.11
+ remote_as: "45000"
+ send_community:
+ extended: true
+ - activate: true
+ neighbor_address: 192.0.2.12
+ remote_as: "45000"
+ - neighbor_address: 192.0.2.13
+ remote_as: "6553601"
+ - advertise:
+ diverse_path:
+ backup: true
+ neighbor_address: 192.0.2.8
+ route_reflector_client: true
+ - neighbor_address: 192.0.2.9
+ remote_as: "64500"
+ route_maps:
+ - in: true
+ name: rmp1
+ - in: true
+ name: rmp2
+ update_source: Loopback0
+ - activate: true
+ advertise:
+ additional_paths:
+ group_best: true
+ neighbor_address: 2001:DB8::1037
+ - neighbor_address: testNebTag
+ peer_group: "5"
+ soft_reconfiguration: true
+ version: 4
+ networks:
+ - address: 192.0.2.15
+ backdoor: true
+ netmask: 55.255.255.0
+ route_map: mp1
+ - address: 192.0.2.16
+ backdoor: true
+ netmask: 255.255.255.0
+ route_map: mp2
+ - address: 192.0.2.17
+ backdoor: true
+ netmask: 255.255.255.0
+ route_map: mp2
+ redistribute:
+ - static:
+ metric: 33
+ route_map: rmp1
+ set: true
+ - application:
+ metric: 22
+ name: app1
+ - application:
+ metric: 33
+ name: app2
+ route_map: mp1
+ - connected:
+ metric: 22
+ set: true
+ - mobile:
+ metric: 211
+ set: true
+ state: rendered
+
+# Task Output:
+# ------------
+#
+# rendered:
+# - router bgp 65000
+# - auto-summary
+# - bmp buffer-size 22
+# - bmp server 2
+# - distance bgp 2 3 4
+# - distance mbgp 2 3 5
+# - maximum-paths 2
+# - maximum-paths ibgp 2
+# - maximum-secondary-paths 22
+# - maximum-secondary-paths ibgp 22
+# - bgp additional-paths install receive
+# - bgp aggregate-timer 0
+# - bgp always-compare-med
+# - bgp asnotation dot
+# - bgp bestpath aigp ignore
+# - bgp bestpath compare-routerid
+# - bgp bestpath med confed missing-as-worst
+# - bgp confederation identifier 22
+# - bgp consistency-checker error-message interval 10
+# - bgp dampening route-map routeMap1Test
+# - bgp deterministic-med
+# - bgp graceful-restart restart-time 2
+# - bgp graceful-restart stalepath-time 22
+# - bgp graceful-shutdown all vrfs 31 local-preference 230 community 77
+# - bgp listen limit 200
+# - bgp listen range 192.0.2.1/24 peer-group PaulNetworkGroup
+# - bgp log-neighbor-changes
+# - bgp maxas-limit 2
+# - bgp maxcommunity-limit 3
+# - bgp maxextcommunity-limit 3
+# - bgp nexthop route-map RouteMap1
+# - bgp nexthop trigger delay 2
+# - bgp nopeerup-delay cold-boot 2
+# - bgp nopeerup-delay post-boot 22
+# - bgp nopeerup-delay nsf-switchover 10
+# - bgp nopeerup-delay user-initiated 22
+# - bgp recursion host
+# - bgp redistribute-internal
+# - bgp refresh max-eor-time 700
+# - bgp refresh stalepath-time 800
+# - bgp router-id vrf auto-assign
+# - bgp scan-time 22
+# - bgp slow-peer detection threshold 345
+# - bgp slow-peer split-update-group dynamic permanent
+# - bgp sso route-refresh-enable
+# - bgp suppress-inactive
+# - bgp update-delay 2
+# - bgp update-group split as-override
+# - bgp inject-map map2 exist-map Testmap3 copy-attributes
+# - bgp inject-map map1 exist-map Testmap2 copy-attributes
+# - distribute-list prefix prefixTest in
+# - distribute-list gateway gatewayTest out
+# - distribute-list 300 out Loopback0
+# - aggregate-address 192.0.2.1 255.255.255.0 summary-only attribute-map testMap1
+# - aggregate-address 192.0.2.2 255.255.255.0 as-set
+# - aggregate-address 192.0.2.3 255.255.255.0 as-set
+# - network 192.0.2.15 mask 55.255.255.0 route-map mp1 backdoor
+# - network 192.0.2.16 mask 255.255.255.0 route-map mp2 backdoor
+# - network 192.0.2.17 mask 255.255.255.0 route-map mp2 backdoor
+# - neighbor 192.0.2.10 remote-as 64500
+# - neighbor 192.0.2.10 update-source Loopback1
+# - neighbor 192.0.2.11 remote-as 45000
+# - neighbor 192.0.2.11 activate
+# - neighbor 192.0.2.11 send-community extended
+# - neighbor 192.0.2.12 remote-as 45000
+# - neighbor 192.0.2.12 activate
+# - neighbor 192.0.2.13 remote-as 6553601
+# - neighbor 192.0.2.8 advertise diverse-path backup
+# - neighbor 192.0.2.8 route-reflector-client
+# - neighbor 192.0.2.9 remote-as 64500
+# - neighbor 192.0.2.9 update-source Loopback0
+# - neighbor 192.0.2.9 route-map rmp1 in
+# - neighbor 192.0.2.9 route-map rmp2 in
+# - neighbor 2001:DB8::1037 activate
+# - neighbor 2001:DB8::1037 advertise additional-paths group-best
+# - neighbor testNebTag peer-group 5
+# - neighbor testNebTag soft-reconfiguration inbound
+# - neighbor testNebTag version 4
+# - redistribute static metric 33 route-map rmp1
+# - redistribute application app1 metric 22
+# - redistribute application app2 metric 33 route-map mp1
+# - redistribute connected metric 22
+# - redistribute mobile metric 211
+
+# Using parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# router bgp 65000
+# auto-summary
+# bmp buffer-size 22
+# bmp server 2
+# distance bgp 2 3 4
+# distance mbgp 2 3 5
+# maximum-paths 2
+# maximum-paths ibgp 2
+# maximum-secondary-paths 22
+# maximum-secondary-paths ibgp 22
+# description checking description as line
+# bgp additional-paths install receive
+# bgp aggregate-timer 0
+# bgp always-compare-med
+# bgp asnotation dot
+# bgp bestpath aigp ignore
+# bgp bestpath compare-routerid
+# bgp bestpath med confed missing-as-worst
+# bgp confederation identifier 22
+# bgp consistency-checker error-message interval 10
+# bgp dampening route-map routeMap1Test
+# bgp deterministic-med
+# bgp graceful-restart restart-time 2
+# bgp graceful-restart stalepath-time 22
+# bgp graceful-shutdown all vrfs 31 local-preference 230 community 77
+# bgp listen limit 200
+# bgp listen range 192.0.2.1/24 peer-group PaulNetworkGroup
+# bgp log-neighbor-changes
+# bgp maxas-limit 2
+# bgp maxcommunity-limit 3
+# bgp maxextcommunity-limit 3
+# bgp nexthop route-map RouteMap1
+# bgp nexthop trigger delay 2
+# bgp nopeerup-delay cold-boot 2
+# bgp nopeerup-delay post-boot 22
+# bgp nopeerup-delay nsf-switchover 10
+# bgp nopeerup-delay user-initiated 22
+# bgp recursion host
+# bgp redistribute-internal
+# bgp refresh max-eor-time 700
+# bgp refresh stalepath-time 800
+# bgp router-id vrf auto-assign
+# bgp scan-time 22
+# bgp slow-peer detection threshold 345
+# bgp slow-peer split-update-group dynamic permanent
+# bgp sso route-refresh-enable
+# bgp suppress-inactive
+# bgp update-delay 2
+# bgp update-group split as-override
+# bgp inject-map map2 exist-map Testmap3 copy-attributes
+# bgp inject-map map1 exist-map Testmap2 copy-attributes
+# distribute-list prefix prefixTest in
+# distribute-list gateway gatewayTest out
+# distribute-list 300 out Loopback0
+# aggregate-address 192.0.2.1 255.255.255.0 summary-only attribute-map testMap1
+# aggregate-address 192.0.2.2 255.255.255.0 as-set
+# aggregate-address 192.0.2.3 255.255.255.0 as-set
+# network 192.0.2.15 mask 55.255.255.0 route-map mp1 backdoor
+# network 192.0.2.16 mask 255.255.255.0 route-map mp2 backdoor
+# network 192.0.2.17 mask 255.255.255.0 route-map mp2 backdoor
+# neighbor 192.0.2.8 advertise diverse-path backup
+# neighbor 192.0.2.8 route-reflector-client
+# neighbor 192.0.2.9 remote-as 64500
+# neighbor 192.0.2.9 update-source Loopback0
+# neighbor 192.0.2.9 route-map rmp1 in
+# neighbor 192.0.2.9 route-map rmp2 in
+# neighbor 192.0.2.10 remote-as 64500
+# neighbor 192.0.2.10 update-source Loopback1
+# neighbor 192.0.2.11 remote-as 45000
+# neighbor 192.0.2.11 activate
+# neighbor 192.0.2.11 send-community extended
+# neighbor 192.0.2.12 remote-as 45000
+# neighbor 192.0.2.12 activate
+# neighbor 192.0.2.13 remote-as 6553601
+# neighbor 192.0.2.13 shutdown graceful 10 community 20
+# neighbor 2001:DB8::1037 activate
+# neighbor 2001:DB8::1037 advertise additional-paths group-best
+# neighbor testNebTag peer-group 5
+# neighbor testNebTag soft-reconfiguration inbound
+# neighbor testNebTag version 4
+# redistribute static metric 33 route-map rmp1
+# redistribute application app1 metric 22
+# redistribute application app2 metric 33 route-map mp1
+# redistribute connected metric 22
+# redistribute mobile metric 21
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_bgp_global:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Task Output:
+# ------------
+#
+# parsed:
+# aggregate_addresses:
+# - address: 192.0.2.1
+# attribute_map: testMap1
+# netmask: 255.255.255.0
+# summary_only: true
+# - address: 192.0.2.2
+# as_set: true
+# netmask: 255.255.255.0
+# - address: 192.0.2.3
+# as_set: true
+# netmask: 255.255.255.0
+# as_number: '65000'
+# auto_summary: true
+# bgp:
+# additional_paths:
+# install: true
+# receive: true
+# aggregate_timer: 0
+# always_compare_med: true
+# asnotation: true
+# bestpath_options:
+# aigp: true
+# compare_routerid: true
+# med:
+# confed: true
+# missing_as_worst: true
+# confederation:
+# identifier: '22'
+# consistency_checker:
+# error_message:
+# interval: 10
+# set: true
+# dampening:
+# route_map: routeMap1Test
+# deterministic_med: true
+# graceful_restart:
+# restart_time: 2
+# stalepath_time: 22
+# graceful_shutdown:
+# community: '77'
+# local_preference: 230
+# vrfs:
+# time: 31
+# inject_maps:
+# - copy_attributes: true
+# exist_map_name: Testmap3
+# name: map2
+# - copy_attributes: true
+# exist_map_name: Testmap2
+# name: map1
+# listen:
+# limit: 200
+# range:
+# host_with_subnet: 192.0.2.1/24
+# peer_group: PaulNetworkGroup
+# log_neighbor_changes: true
+# maxas_limit: 2
+# maxcommunity_limit: 3
+# maxextcommunity_limit: 3
+# nexthop:
+# route_map: RouteMap1
+# trigger:
+# delay: 2
+# nopeerup_delay_options:
+# cold_boot: 2
+# nsf_switchover: 10
+# post_boot: 22
+# user_initiated: 22
+# recursion: true
+# redistribute_internal: true
+# refresh:
+# max_eor_time: 700
+# stalepath_time: 800
+# router_id:
+# vrf: true
+# scan_time: 22
+# slow_peer:
+# detection:
+# threshold: 345
+# split_update_group:
+# dynamic: true
+# permanent: true
+# sso: true
+# suppress_inactive: true
+# update_delay: 2
+# update_group: true
+# bmp:
+# buffer_size: 22
+# server: 2
+# distance:
+# bgp:
+# routes_external: 2
+# routes_internal: 3
+# routes_local: 4
+# mbgp:
+# routes_external: 2
+# routes_internal: 3
+# routes_local: 5
+# distributes:
+# - in: true
+# prefix: prefixTest
+# - gateway: gatewayTest
+# out: true
+# - acl: '300'
+# interface: Loopback0
+# out: true
+# maximum_paths:
+# ibgp: 2
+# paths: 2
+# maximum_secondary_paths:
+# ibgp: 22
+# paths: 22
+# neighbors:
+# - neighbor_address: 192.0.2.10
+# remote_as: '64500'
+# update_source: Loopback1
+# - activate: true
+# neighbor_address: 192.0.2.11
+# remote_as: '45000'
+# send_community:
+# extended: true
+# - activate: true
+# neighbor_address: 192.0.2.12
+# remote_as: '45000'
+# - neighbor_address: 192.0.2.13
+# remote_as: '6553601'
+# - advertise:
+# diverse_path:
+# backup: true
+# neighbor_address: 192.0.2.8
+# route_reflector_client: true
+# - neighbor_address: 192.0.2.9
+# remote_as: '64500'
+# route_maps:
+# - in: true
+# name: rmp1
+# - in: true
+# name: rmp2
+# update_source: Loopback0
+# - activate: true
+# advertise:
+# additional_paths:
+# group_best: true
+# neighbor_address: 2001:DB8::1037
+# - neighbor_address: testNebTag
+# peer_group: '5'
+# soft_reconfiguration: true
+# version: 4
+# networks:
+# - address: 192.0.2.15
+# backdoor: true
+# netmask: 55.255.255.0
+# route_map: mp1
+# - address: 192.0.2.16
+# backdoor: true
+# netmask: 255.255.255.0
+# route_map: mp2
+# - address: 192.0.2.17
+# backdoor: true
+# netmask: 255.255.255.0
+# route_map: mp2
+# redistribute:
+# - static:
+# metric: 33
+# route_map: rmp1
+# set: true
+# - application:
+# metric: 22
+# name: app1
+# - application:
+# metric: 33
+# name: app2
+# route_map: mp1
+# - connected:
+# metric: 22
+# set: true
+# - mobile:
+# metric: 21
+# set: true
+"""
+
+
+RETURN = """
+before:
+ description: The configuration prior to the module execution.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+after:
+ description: The resulting configuration after module execution.
+ returned: when changed
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: list
+ sample:
+ - "router bgp 65000"
+ - "neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive"
+ - "bgp graceful-shutdown all neighbors 50 local-preference 100 community 100"
+rendered:
+ description: The provided configuration in the task rendered in device-native format (offline).
+ returned: when I(state) is C(rendered)
+ type: list
+ sample:
+ - "router bgp 65000"
+ - "neighbor 198.51.100.1 aigp send cost-community 100 poi igp-cost transitive"
+ - "bgp graceful-shutdown all neighbors 50 local-preference 100 community 100"
+gathered:
+ description: Facts about the network resource gathered from the remote device as structured data.
+ returned: when I(state) is C(gathered)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+parsed:
+ description: The device native config provided in I(running_config) option parsed into structured data as per module argspec.
+ returned: when I(state) is C(parsed)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.bgp_global.bgp_global import (
+ Bgp_globalArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.bgp_global.bgp_global import (
+ Bgp_global,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ module = AnsibleModule(
+ argument_spec=Bgp_globalArgs.argument_spec,
+ mutually_exclusive=[["config", "running_config"]],
+ required_if=[
+ ["state", "merged", ["config"]],
+ ["state", "replaced", ["config"]],
+ ["state", "rendered", ["config"]],
+ ["state", "parsed", ["running_config"]],
+ ],
+ supports_check_mode=True,
+ )
+
+ result = Bgp_global(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_command.py b/ansible_collections/cisco/ios/plugins/modules/ios_command.py
new file mode 100644
index 000000000..e73f8212f
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_command.py
@@ -0,0 +1,431 @@
+#!/usr/bin/python
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_command
+author: Peter Sprygada (@privateip)
+short_description: Module to run commands on remote devices.
+description:
+ - Sends arbitrary commands to an ios node and returns the results read from the device.
+ This module includes an argument that will cause the module to wait for a specific
+ condition before returning or timing out if the condition is not met.
+ - This module does not support running commands in configuration mode. Please use
+ L(ios_config,https://docs.ansible.com/ansible/latest/collections/cisco/ios/ios_config_module.html#ansible-collections-cisco-ios-ios-config-module)
+ to configure IOS devices.
+version_added: 1.0.0
+extends_documentation_fragment:
+ - cisco.ios.ios
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ commands:
+ description:
+ - List of commands to send to the remote ios device over the configured provider.
+ The resulting output from the command is returned. If the I(wait_for) argument
+ is provided, the module is not returned until the condition is satisfied or
+ the number of retries has expired. If a command sent to the device requires
+ answering a prompt, it is possible to pass a dict containing I(command), I(answer)
+ and I(prompt). Common answers are 'y' or "\\r" (carriage return, must be double
+ quotes). See examples.
+ required: true
+ type: list
+ elements: raw
+ wait_for:
+ description:
+ - List of conditions to evaluate against the output of the command. The task will
+ wait for each condition to be true before moving forward. If the conditional
+ is not true within the configured number of retries, the task fails. See examples.
+ aliases:
+ - waitfor
+ type: list
+ elements: str
+ match:
+ description:
+ - The I(match) argument is used in conjunction with the I(wait_for) argument to
+ specify the match policy. Valid values are C(all) or C(any). If the value
+ is set to C(all) then all conditionals in the wait_for must be satisfied. If
+ the value is set to C(any) then only one of the values must be satisfied.
+ default: all
+ type: str
+ choices:
+ - any
+ - all
+ retries:
+ description:
+ - Specifies the number of retries a command should by tried before it is considered
+ failed. The command is run on the target device every retry and evaluated against
+ the I(wait_for) conditions.
+ default: 9
+ type: int
+ interval:
+ description:
+ - Configures the interval in seconds to wait between retries of the command. If
+ the command does not pass the specified conditions, the interval indicates how
+ long to wait before trying the command again.
+ default: 1
+ type: int
+"""
+
+EXAMPLES = r"""
+- name: Run show version on remote devices
+ cisco.ios.ios_command:
+ commands: show version'
+
+# output-
+
+# ok: [iosxeappliance] => {
+# "changed": false,
+# "invocation": {
+# "module_args": {
+# "commands": [
+# "show version"
+# ],
+# "interval": 1,
+# "match": "all",
+# "retries": 10,
+# "wait_for": null
+# }
+# },
+# "stdout": [
+# "Cisco IOS XE Software, Version 17.03.04a\nCisco IOS Software [Amsterdam], Virtual XE Software ... register is 0x2102"
+# ],
+# "stdout_lines": [
+# [
+# "Cisco IOS XE Software, Version 17.03.04a",
+# "Cisco IOS Software [Amsterdam], Virtual XE Software",
+# "..."
+# "Configuration register is 0x2102"
+# ]
+# ]
+# }
+
+- name: Run show version and check to see if output contains IOS
+ cisco.ios.ios_command:
+ commands: show version
+ wait_for: result[0] contains IOS
+
+# output-
+
+# ok: [iosxeappliance] => {
+# "changed": false,
+# "invocation": {
+# "module_args": {
+# "commands": [
+# "show version"
+# ],
+# "interval": 1,
+# "match": "all",
+# "retries": 10,
+# "wait_for": [
+# "result[0] contains IOS"
+# ]
+# }
+# },
+# "stdout": [
+# "Cisco IOS XE Software, Version 17.03.04a\nCisco IOS Software [Amsterdam], Virtual XE Software ... register is 0x2102"
+# ],
+# "stdout_lines": [
+# [
+# "Cisco IOS XE Software, Version 17.03.04a",
+# "Cisco IOS Software [Amsterdam], Virtual XE Software",
+# "..."
+# "Configuration register is 0x2102"
+# ]
+# ]
+# }
+
+- name: Run multiple commands on remote nodes
+ cisco.ios.ios_command:
+ commands:
+ - show version
+ - show interfaces
+
+# output-
+
+# ok: [iosxeappliance] => {
+# "changed": false,
+# "invocation": {
+# "module_args": {
+# "commands": [
+# "show version",
+# "show interfaces"
+# ],
+# "interval": 1,
+# "match": "all",
+# "retries": 10,
+# "wait_for": null
+# }
+# },
+# "stdout": [
+# "Cisco IOS XE Software, Version 17.03.04a\nCisco IOS Software [Amsterdam], Virtual XE Software Configuration register is 0x2102",
+# "Loopback999 is up, line protocol is up ...failures, 0 output buffers swapped out"
+# ],
+# "stdout_lines": [
+# [
+# "Cisco IOS XE Software, Version 17.03.04a",
+# "Cisco IOS Software [Amsterdam], Virtual XE Software",
+# "..."
+# "Configuration register is 0x2102"
+# ],
+# [
+# "Loopback999 is up, line protocol is up ",
+# " Hardware is Loopback",
+# " Description: this is a test",
+# " MTU 1514 bytes, BW 8000000 Kbit/sec, DLY 5000 usec, ",
+# " reliability 255/255, txload 1/255, rxload 1/255",
+# " Encapsulation LOOPBACK, loopback not set",
+# " Keepalive set (10 sec)",
+# " Last input never, output never, output hang never",
+# " Last clearing of \"show interface\" counters never",
+# " Input queue: 0/75/0/0 (size/max/drops/flushes); Total output drops: 0",
+# " Queueing strategy: fifo",
+# " Output queue: 0/0 (size/max)",
+# " 5 minute input rate 0 bits/sec, 0 packets/sec",
+# " 5 minute output rate 0 bits/sec, 0 packets/sec",
+# " 0 packets input, 0 bytes, 0 no buffer",
+# " Received 0 broadcasts (0 IP multicasts)",
+# " 0 runts, 0 giants, 0 throttles ",
+# " 0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored, 0 abort",
+# " 0 packets output, 0 bytes, 0 underruns",
+# " Output 0 broadcasts (0 IP multicasts)",
+# " 0 output errors, 0 collisions, 0 interface resets",
+# " 0 unknown protocol drops",
+# " 0 output buffer failures, 0 output buffers swapped out"
+# ]
+# ]
+# }
+
+- name: Run multiple commands and evaluate the output
+ cisco.ios.ios_command:
+ commands:
+ - show version
+ - show interfaces
+ wait_for:
+ - result[0] contains IOS
+ - result[1] contains Loopback0
+
+# output-
+# failed play as result[1] contains Loopback0 is false
+
+# fatal: [iosxeappliance]: FAILED! => {
+# "changed": false,
+# "failed_conditions": [
+# "result[1] contains Loopback0"
+# ],
+# "invocation": {
+# "module_args": {
+# "commands": [
+# "show version",
+# "show interfaces"
+# ],
+# "interval": 1,
+# "match": "all",
+# "retries": 10,
+# "wait_for": [
+# "result[0] contains IOS",
+# "result[1] contains Loopback0"
+# ]
+# }
+# },
+# "msg": "One or more conditional statements have not been satisfied"
+# }
+
+- name: Run commands that require answering a prompt
+ cisco.ios.ios_command:
+ commands:
+ - command: "clear counters GigabitEthernet2"
+ prompt: 'Clear "show interface" counters on this interface \[confirm\]'
+ answer: "y"
+ - command: "clear counters GigabitEthernet3"
+ prompt: "[confirm]"
+ answer: "\r"
+
+# output-
+
+# ok: [iosxeappliance] => {
+# "changed": false,
+# "invocation": {
+# "module_args": {
+# "commands": [
+# {
+# "answer": "y",
+# "check_all": false,
+# "command": "clear counters GigabitEthernet2",
+# "newline": true,
+# "output": null,
+# "prompt": "Clear \"show interface\" counters on this interface \\[confirm\\]",
+# "sendonly": false
+# },
+# {
+# "answer": "\r",
+# "check_all": false,
+# "command": "clear counters GigabitEthernet3",
+# "newline": true,
+# "output": null,
+# "prompt": "[confirm]",
+# "sendonly": false
+# }
+# ],
+# "interval": 1,
+# "match": "all",
+# "retries": 10,
+# "wait_for": null
+# }
+# },
+# "stdout": [
+# "Clear \"show interface\" counters on this interface [confirm]y",
+# "Clear \"show interface\" counters on this interface [confirm]"
+# ],
+# "stdout_lines": [
+# [
+# "Clear \"show interface\" counters on this interface [confirm]y"
+# ],
+# [
+# "Clear \"show interface\" counters on this interface [confirm]"
+# ]
+# ]
+# }
+
+- name: Run commands with complex values like special characters in variables
+ cisco.ios.ios_command:
+ commands:
+ ["{{ 'test aaa group TEST ' ~ user ~ ' ' ~ password ~ ' new-code' }}"]
+ vars:
+ user: "dummy"
+ password: "!dummy"
+
+# ok: [iosxeappliance] => {
+# "changed": false,
+# "invocation": {
+# "module_args": {
+# "commands": [
+# "test aaa group group test !dummy new-code"
+# ],
+# "interval": 1,
+# "match": "all",
+# "retries": 10,
+# "wait_for": null
+# }
+# },
+# "stdout": [
+# "User was successfully authenticated."
+# ],
+# "stdout_lines": [
+# [
+# "User was successfully authenticated."
+# ]
+# ]
+# }
+
+"""
+
+RETURN = """
+stdout:
+ description: The set of responses from the commands
+ returned: always apart from low level errors (such as action plugin)
+ type: list
+ sample: ['...', '...']
+stdout_lines:
+ description: The value of stdout split into a list
+ returned: always apart from low level errors (such as action plugin)
+ type: list
+ sample: [['...', '...'], ['...'], ['...']]
+failed_conditions:
+ description: The list of conditionals that have failed
+ returned: failed
+ type: list
+ sample: ['...', '...']
+"""
+import time
+
+from ansible.module_utils._text import to_text
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.parsing import (
+ Conditional,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ to_lines,
+ transform_commands,
+)
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import run_commands
+
+
+def parse_commands(module, warnings):
+ commands = transform_commands(module)
+ if module.check_mode:
+ for item in list(commands):
+ if not item["command"].startswith("show"):
+ warnings.append(
+ "Only show commands are supported when using check mode, not executing %s"
+ % item["command"],
+ )
+ commands.remove(item)
+ return commands
+
+
+def main():
+ """main entry point for module execution"""
+ argument_spec = dict(
+ commands=dict(type="list", elements="raw", required=True),
+ wait_for=dict(type="list", elements="str", aliases=["waitfor"]),
+ match=dict(default="all", choices=["all", "any"]),
+ retries=dict(default=9, type="int"),
+ interval=dict(default=1, type="int"),
+ )
+ module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
+ warnings = list()
+ result = {"changed": False, "warnings": warnings}
+ commands = parse_commands(module, warnings)
+ wait_for = module.params["wait_for"] or list()
+ conditionals = []
+ try:
+ conditionals = [Conditional(c) for c in wait_for]
+ except AttributeError as exc:
+ module.fail_json(msg=to_text(exc))
+ retries = module.params["retries"]
+ interval = module.params["interval"]
+ match = module.params["match"]
+ while retries >= 0:
+ responses = run_commands(module, commands)
+ for item in list(conditionals):
+ if item(responses):
+ if match == "any":
+ conditionals = list()
+ break
+ conditionals.remove(item)
+ if not conditionals:
+ break
+ time.sleep(interval)
+ retries -= 1
+ if conditionals:
+ failed_conditions = [item.raw for item in conditionals]
+ msg = "One or more conditional statements have not been satisfied"
+ module.fail_json(msg=msg, failed_conditions=failed_conditions)
+ result.update({"stdout": responses, "stdout_lines": list(to_lines(responses))})
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_config.py b/ansible_collections/cisco/ios/plugins/modules/ios_config.py
new file mode 100644
index 000000000..d86a7dd9d
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_config.py
@@ -0,0 +1,584 @@
+#!/usr/bin/python
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_config
+author: Peter Sprygada (@privateip)
+short_description: Module to manage configuration sections.
+description:
+ - Cisco IOS configurations use a simple block indent file syntax for segmenting configuration
+ into sections. This module provides an implementation for working with IOS configuration
+ sections in a deterministic way.
+version_added: 1.0.0
+extends_documentation_fragment:
+ - cisco.ios.ios
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - Abbreviated commands are NOT idempotent, see
+ U(https://docs.ansible.com/ansible/latest/network/user_guide/faq.html#why-do-the-config-modules-always-return-changed-true-with-abbreviated-commands)
+ - To ensure idempotency and correct diff the configuration lines in the relevant module options should be similar to how they
+ appear if present in the running configuration on device including the indentation.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ lines:
+ description:
+ - The ordered set of commands that should be configured in the section. The commands
+ must be the exact same commands as found in the device running-config to ensure
+ idempotency and correct diff. Be sure to note the configuration command syntax as
+ some commands are automatically modified by the device config parser.
+ type: list
+ elements: str
+ aliases:
+ - commands
+ parents:
+ description:
+ - The ordered set of parents that uniquely identify the section or hierarchy the
+ commands should be checked against. If the parents argument is omitted, the
+ commands are checked against the set of top level or global commands.
+ type: list
+ elements: str
+ src:
+ description:
+ - Specifies the source path to the file that contains the configuration or configuration
+ template to load. The path to the source file can either be the full path on
+ the Ansible control host or a relative path from the playbook or role root directory. This
+ argument is mutually exclusive with I(lines), I(parents). The configuration lines in the
+ source file should be similar to how it will appear if present in the running-configuration
+ of the device including the indentation to ensure idempotency and correct diff.
+ type: str
+ before:
+ description:
+ - The ordered set of commands to push on to the command stack if a change needs
+ to be made. This allows the playbook designer the opportunity to perform configuration
+ commands prior to pushing any changes without affecting how the set of commands
+ are matched against the system.
+ type: list
+ elements: str
+ after:
+ description:
+ - The ordered set of commands to append to the end of the command stack if a change
+ needs to be made. Just like with I(before) this allows the playbook designer
+ to append a set of commands to be executed after the command set.
+ type: list
+ elements: str
+ match:
+ description:
+ - Instructs the module on the way to perform the matching of the set of commands
+ against the current device config. If match is set to I(line), commands are
+ matched line by line. If match is set to I(strict), command lines are matched
+ with respect to position. If match is set to I(exact), command lines must be
+ an equal match. Finally, if match is set to I(none), the module will not attempt
+ to compare the source configuration with the running configuration on the remote
+ device.
+ choices:
+ - line
+ - strict
+ - exact
+ - none
+ type: str
+ default: line
+ replace:
+ description:
+ - Instructs the module on the way to perform the configuration on the device.
+ If the replace argument is set to I(line) then the modified lines are pushed
+ to the device in configuration mode. If the replace argument is set to I(block)
+ then the entire command block is pushed to the device in configuration mode
+ if any line is not correct.
+ default: line
+ choices:
+ - line
+ - block
+ type: str
+ multiline_delimiter:
+ description:
+ - This argument is used when pushing a multiline configuration element to the
+ IOS device. It specifies the character to use as the delimiting character. This
+ only applies to the configuration action.
+ default: "@"
+ type: str
+ backup:
+ description:
+ - This argument will cause the module to create a full backup of the current C(running-config)
+ from the remote device before any changes are made. If the C(backup_options)
+ value is not given, the backup file is written to the C(backup) folder in the
+ playbook root directory or role root directory, if playbook is part of an ansible
+ role. If the directory does not exist, it is created.
+ type: bool
+ default: false
+ running_config:
+ description:
+ - The module, by default, will connect to the remote device and retrieve the current
+ running-config to use as a base for comparing against the contents of source.
+ There are times when it is not desirable to have the task get the current running-config
+ for every task in a playbook. The I(running_config) argument allows the implementer
+ to pass in the configuration to use as the base config for comparison.
+ The configuration lines for this option should be similar to how it will appear if present
+ in the running-configuration of the device including the indentation to ensure idempotency
+ and correct diff.
+ type: str
+ aliases:
+ - config
+ defaults:
+ description:
+ - This argument specifies whether or not to collect all defaults when getting
+ the remote device running config. When enabled, the module will get the current
+ config by issuing the command C(show running-config all).
+ type: bool
+ default: false
+ save_when:
+ description:
+ - When changes are made to the device running-configuration, the changes are not
+ copied to non-volatile storage by default. Using this argument will change
+ that before. If the argument is set to I(always), then the running-config will
+ always be copied to the startup-config and the I(modified) flag will always
+ be set to True. If the argument is set to I(modified), then the running-config
+ will only be copied to the startup-config if it has changed since the last save
+ to startup-config. If the argument is set to I(never), the running-config will
+ never be copied to the startup-config. If the argument is set to I(changed),
+ then the running-config will only be copied to the startup-config if the task
+ has made a change. I(changed) was added in Ansible 2.5.
+ default: never
+ choices:
+ - always
+ - never
+ - modified
+ - changed
+ type: str
+ diff_against:
+ description:
+ - When using the C(ansible-playbook --diff) command line argument the module can
+ generate diffs against different sources.
+ - When this option is configure as I(startup), the module will return the diff
+ of the running-config against the startup-config.
+ - When this option is configured as I(intended), the module will return the diff
+ of the running-config against the configuration provided in the C(intended_config)
+ argument.
+ - When this option is configured as I(running), the module will return the before
+ and after diff of the running-config with respect to any changes made to the
+ device configuration.
+ type: str
+ choices:
+ - running
+ - startup
+ - intended
+ diff_ignore_lines:
+ description:
+ - Use this argument to specify one or more lines that should be ignored during
+ the diff. This is used for lines in the configuration that are automatically
+ updated by the system. This argument takes a list of regular expressions or
+ exact line matches.
+ type: list
+ elements: str
+ intended_config:
+ description:
+ - The C(intended_config) provides the master configuration that the node should
+ conform to and is used to check the final running-config against. This argument
+ will not modify any settings on the remote device and is strictly used to check
+ the compliance of the current device's configuration against. When specifying
+ this argument, the task should also modify the C(diff_against) value and set
+ it to I(intended). The configuration lines for this value should be similar to how it
+ will appear if present in the running-configuration of the device including the indentation
+ to ensure correct diff.
+ type: str
+ backup_options:
+ description:
+ - This is a dict object containing configurable options related to backup file
+ path. The value of this option is read only when C(backup) is set to I(yes),
+ if C(backup) is set to I(no) this option will be silently ignored.
+ suboptions:
+ filename:
+ description:
+ - The filename to be used to store the backup configuration. If the filename
+ is not given it will be generated based on the hostname, current time and
+ date in format defined by <hostname>_config.<current-date>@<current-time>
+ type: str
+ dir_path:
+ description:
+ - This option provides the path ending with directory name in which the backup
+ configuration file will be stored. If the directory does not exist it will
+ be first created and the filename is either the value of C(filename) or
+ default filename as described in C(filename) options description. If the
+ path value is not given in that case a I(backup) directory will be created
+ in the current working directory and backup configuration will be copied
+ in C(filename) within I(backup) directory.
+ type: path
+ type: dict
+"""
+
+EXAMPLES = """
+- name: Configure top level configuration
+ cisco.ios.ios_config:
+ lines: hostname {{ inventory_hostname }}
+
+- name: Configure interface settings
+ cisco.ios.ios_config:
+ lines:
+ - description test interface
+ - ip address 172.31.1.1 255.255.255.0
+ parents: interface Ethernet1
+
+- name: Configure ip helpers on multiple interfaces
+ cisco.ios.ios_config:
+ lines:
+ - ip helper-address 172.26.1.10
+ - ip helper-address 172.26.3.8
+ parents: "{{ item }}"
+ with_items:
+ - interface Ethernet1
+ - interface Ethernet2
+ - interface GigabitEthernet1
+
+- name: Configure policer in Scavenger class
+ cisco.ios.ios_config:
+ lines:
+ - conform-action transmit
+ - exceed-action drop
+ parents:
+ - policy-map Foo
+ - class Scavenger
+ - police cir 64000
+
+- name: Load new acl into device
+ cisco.ios.ios_config:
+ lines:
+ - 10 permit ip host 192.0.2.1 any log
+ - 20 permit ip host 192.0.2.2 any log
+ - 30 permit ip host 192.0.2.3 any log
+ - 40 permit ip host 192.0.2.4 any log
+ - 50 permit ip host 192.0.2.5 any log
+ parents: ip access-list extended test
+ before: no ip access-list extended test
+ match: exact
+
+- name: Check the running-config against master config
+ cisco.ios.ios_config:
+ diff_against: intended
+ intended_config: "{{ lookup('file', 'master.cfg') }}"
+
+- name: Check the startup-config against the running-config
+ cisco.ios.ios_config:
+ diff_against: startup
+ diff_ignore_lines:
+ - ntp clock .*
+
+- name: Save running to startup when modified
+ cisco.ios.ios_config:
+ save_when: modified
+
+- name: For idempotency, use full-form commands
+ cisco.ios.ios_config:
+ lines:
+ # - shut
+ - shutdown
+ # parents: int gig1/0/11
+ parents: interface GigabitEthernet1/0/11
+
+# Set boot image based on comparison to a group_var (version) and the version
+# that is returned from the `ios_facts` module
+- name: Setting boot image
+ cisco.ios.ios_config:
+ lines:
+ - no boot system
+ - boot system flash bootflash:{{new_image}}
+ host: "{{ inventory_hostname }}"
+ when: ansible_net_version != version
+
+- name: Render a Jinja2 template onto an IOS device
+ cisco.ios.ios_config:
+ backup: true
+ src: ios_template.j2
+
+- name: Configurable backup path
+ cisco.ios.ios_config:
+ src: ios_template.j2
+ backup: true
+ backup_options:
+ filename: backup.cfg
+ dir_path: /home/user
+
+# Example ios_template.j2
+# ip access-list extended test
+# permit ip host 192.0.2.1 any log
+# permit ip host 192.0.2.2 any log
+# permit ip host 192.0.2.3 any log
+# permit ip host 192.0.2.4 any log
+
+"""
+
+RETURN = """
+updates:
+ description: The set of commands that will be pushed to the remote device
+ returned: always
+ type: list
+ sample: ['hostname foo', 'router ospf 1', 'router-id 192.0.2.1']
+commands:
+ description: The set of commands that will be pushed to the remote device
+ returned: always
+ type: list
+ sample: ['hostname foo', 'router ospf 1', 'router-id 192.0.2.1']
+backup_path:
+ description: The full path to the backup file
+ returned: when backup is yes
+ type: str
+ sample: /playbooks/ansible/backup/ios_config.2016-07-16@22:28:34
+filename:
+ description: The name of the backup file
+ returned: when backup is yes and filename is not specified in backup options
+ type: str
+ sample: ios_config.2016-07-16@22:28:34
+shortname:
+ description: The full path to the backup file excluding the timestamp
+ returned: when backup is yes and filename is not specified in backup options
+ type: str
+ sample: /playbooks/ansible/backup/ios_config
+date:
+ description: The date extracted from the backup file name
+ returned: when backup is yes
+ type: str
+ sample: "2016-07-16"
+time:
+ description: The time extracted from the backup file name
+ returned: when backup is yes
+ type: str
+ sample: "22:28:34"
+"""
+import json
+
+from ansible.module_utils._text import to_text
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.connection import ConnectionError
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import (
+ NetworkConfig,
+ dumps,
+)
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ get_config,
+ get_connection,
+ get_defaults_flag,
+ run_commands,
+)
+
+
+def check_args(module, warnings):
+ if module.params["multiline_delimiter"]:
+ if len(module.params["multiline_delimiter"]) != 1:
+ module.fail_json(msg="multiline_delimiter value can only be a single character")
+
+
+def edit_config_or_macro(connection, commands):
+ # only catch the macro configuration command,
+ # not negated 'no' variation.
+ if commands[0].startswith("macro name"):
+ connection.edit_macro(candidate=commands)
+ else:
+ connection.edit_config(candidate=commands)
+
+
+def get_candidate_config(module):
+ candidate = ""
+ if module.params["src"]:
+ candidate = module.params["src"]
+ elif module.params["lines"]:
+ candidate_obj = NetworkConfig(indent=1)
+ parents = module.params["parents"] or list()
+ candidate_obj.add(module.params["lines"], parents=parents)
+ candidate = dumps(candidate_obj, "raw")
+ return candidate
+
+
+def get_running_config(module, current_config=None, flags=None):
+ running = module.params["running_config"]
+ if not running:
+ if not module.params["defaults"] and current_config:
+ running = current_config
+ else:
+ running = get_config(module, flags=flags)
+ return running
+
+
+def save_config(module, result):
+ result["changed"] = True
+ if not module.check_mode:
+ run_commands(module, "copy running-config startup-config\r")
+ else:
+ module.warn(
+ "Skipping command `copy running-config startup-config` due to check_mode. Configuration not copied to non-volatile storage",
+ )
+
+
+def main():
+ """main entry point for module execution"""
+ backup_spec = dict(filename=dict(), dir_path=dict(type="path"))
+ argument_spec = dict(
+ src=dict(type="str"),
+ lines=dict(aliases=["commands"], type="list", elements="str"),
+ parents=dict(type="list", elements="str"),
+ before=dict(type="list", elements="str"),
+ after=dict(type="list", elements="str"),
+ match=dict(default="line", choices=["line", "strict", "exact", "none"]),
+ replace=dict(default="line", choices=["line", "block"]),
+ multiline_delimiter=dict(default="@"),
+ running_config=dict(aliases=["config"]),
+ intended_config=dict(),
+ defaults=dict(type="bool", default=False),
+ backup=dict(type="bool", default=False),
+ backup_options=dict(type="dict", options=backup_spec),
+ save_when=dict(choices=["always", "never", "modified", "changed"], default="never"),
+ diff_against=dict(choices=["startup", "intended", "running"]),
+ diff_ignore_lines=dict(type="list", elements="str"),
+ )
+ mutually_exclusive = [("lines", "src"), ("parents", "src")]
+ required_if = [
+ ("match", "strict", ["lines"]),
+ ("match", "exact", ["lines"]),
+ ("replace", "block", ["lines"]),
+ ("diff_against", "intended", ["intended_config"]),
+ ]
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ mutually_exclusive=mutually_exclusive,
+ required_if=required_if,
+ supports_check_mode=True,
+ )
+ result = {"changed": False}
+ warnings = list()
+ check_args(module, warnings)
+ result["warnings"] = warnings
+ diff_ignore_lines = module.params["diff_ignore_lines"]
+ config = None
+ contents = None
+ flags = get_defaults_flag(module) if module.params["defaults"] else []
+ connection = get_connection(module)
+ if module.params["backup"] or module._diff and module.params["diff_against"] == "running":
+ contents = get_config(module, flags=flags)
+ config = NetworkConfig(indent=1, contents=contents)
+ if module.params["backup"]:
+ result["__backup__"] = contents
+ if any((module.params["lines"], module.params["src"])):
+ match = module.params["match"]
+ replace = module.params["replace"]
+ path = module.params["parents"]
+ candidate = get_candidate_config(module)
+ running = get_running_config(module, contents, flags=flags)
+ try:
+ response = connection.get_diff(
+ candidate=candidate,
+ running=running,
+ diff_match=match,
+ diff_ignore_lines=diff_ignore_lines,
+ path=path,
+ diff_replace=replace,
+ )
+ except ConnectionError as exc:
+ module.fail_json(msg=to_text(exc, errors="surrogate_then_replace"))
+ config_diff = response["config_diff"]
+ banner_diff = response["banner_diff"]
+ if config_diff or banner_diff:
+ commands = config_diff.split("\n")
+ if module.params["before"]:
+ commands[:0] = module.params["before"]
+ if module.params["after"]:
+ commands.extend(module.params["after"])
+ result["commands"] = commands
+ result["updates"] = commands
+ result["banners"] = banner_diff
+
+ # send the configuration commands to the device and merge
+ # them with the current running config
+ if not module.check_mode:
+ if commands:
+ edit_config_or_macro(connection, commands)
+ if banner_diff:
+ connection.edit_banner(
+ candidate=json.dumps(banner_diff),
+ multiline_delimiter=module.params["multiline_delimiter"],
+ )
+ result["changed"] = True
+ running_config = module.params["running_config"]
+ startup_config = None
+ if module.params["save_when"] == "always":
+ save_config(module, result)
+ elif module.params["save_when"] == "modified":
+ output = run_commands(module, ["show running-config", "show startup-config"])
+ running_config = NetworkConfig(indent=1, contents=output[0], ignore_lines=diff_ignore_lines)
+ startup_config = NetworkConfig(indent=1, contents=output[1], ignore_lines=diff_ignore_lines)
+ if running_config.sha1 != startup_config.sha1:
+ save_config(module, result)
+ elif module.params["save_when"] == "changed" and result["changed"]:
+ save_config(module, result)
+ if module._diff:
+ if not running_config:
+ output = run_commands(module, "show running-config")
+ contents = output[0]
+ else:
+ contents = running_config
+
+ # recreate the object in order to process diff_ignore_lines
+ running_config = NetworkConfig(indent=1, contents=contents, ignore_lines=diff_ignore_lines)
+ if module.params["diff_against"] == "running":
+ if module.check_mode:
+ module.warn("unable to perform diff against running-config due to check mode")
+ contents = None
+ else:
+ contents = config.config_text
+ elif module.params["diff_against"] == "startup":
+ if not startup_config:
+ output = run_commands(module, "show startup-config")
+ contents = output[0]
+ else:
+ contents = startup_config.config_text
+ elif module.params["diff_against"] == "intended":
+ contents = module.params["intended_config"]
+ if contents is not None:
+ base_config = NetworkConfig(indent=1, contents=contents, ignore_lines=diff_ignore_lines)
+ if running_config.sha1 != base_config.sha1:
+ before, after = "", ""
+ if module.params["diff_against"] == "intended":
+ before = running_config
+ after = base_config
+ elif module.params["diff_against"] in ("startup", "running"):
+ before = base_config
+ after = running_config
+ result.update(
+ {"changed": True, "diff": {"before": str(before), "after": str(after)}},
+ )
+
+ if result.get("changed") and any((module.params["src"], module.params["lines"])):
+ msg = (
+ "To ensure idempotency and correct diff the input configuration lines should be"
+ " similar to how they appear if present in"
+ " the running configuration on device"
+ )
+ if module.params["src"]:
+ msg += " including the indentation"
+ if "warnings" in result:
+ result["warnings"].append(msg)
+ else:
+ result["warnings"] = msg
+
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_facts.py b/ansible_collections/cisco/ios/plugins/modules/ios_facts.py
new file mode 100644
index 000000000..fd4c786f5
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_facts.py
@@ -0,0 +1,246 @@
+#!/usr/bin/python
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_facts
+author:
+ - Peter Sprygada (@privateip)
+ - Sumit Jaiswal (@justjais)
+short_description: Module to collect facts from remote devices.
+description:
+ - Collects a base set of device facts from a remote device that is running IOS. This
+ module prepends all of the base network fact keys with C(ansible_net_<fact>). The
+ facts module will always collect a base set of facts from the device and can enable
+ or disable collection of additional facts.
+version_added: 1.0.0
+extends_documentation_fragment:
+ - cisco.ios.ios
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML and IOS 15.6 for L2 specific resource.
+ - Facts gathering for L3 devices are supposed to produce blank output for unsupported
+ resources like vlan.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ gather_subset:
+ description:
+ - When supplied, this argument restricts the facts collected to a given subset.
+ - Possible values for this argument include C(all), C(min), C(default), C(hardware), C(config),
+ and C(interfaces).
+ - Specify a list of values to include a larger subset.
+ - Use a value with an initial C(!) to collect all facts except that subset.
+ required: false
+ default: "min"
+ type: list
+ elements: str
+ gather_network_resources:
+ description:
+ - When supplied, this argument will restrict the facts collected to a given subset.
+ Possible values for this argument include all and the resources like interfaces,
+ vlans etc. Can specify a list of values to include a larger subset. Values can
+ also be used with an initial C(!) to specify that a specific subset should
+ not be collected. Valid subsets are 'bgp_global', 'l3_interfaces', 'lag_interfaces',
+ 'ntp_global', 'acls', 'hostname', 'interfaces', 'lldp_interfaces', 'logging_global',
+ 'ospf_interfaces', 'ospfv2', 'prefix_lists', 'static_routes', 'acl_interfaces',
+ 'all', 'bgp_address_family', 'l2_interfaces', 'lacp', 'lacp_interfaces', 'lldp_global',
+ 'ospfv3', 'snmp_server', 'vlans', 'service'.
+ type: list
+ elements: str
+ available_network_resources:
+ description: When 'True' a list of network resources for which resource modules are available will be provided.
+ type: bool
+ default: false
+"""
+
+EXAMPLES = """
+- name: Gather all legacy facts
+ cisco.ios.ios_facts:
+ gather_subset: all
+
+- name: Gather only the config and default facts
+ cisco.ios.ios_facts:
+ gather_subset:
+ - config
+
+- name: Do not gather hardware facts
+ cisco.ios.ios_facts:
+ gather_subset:
+ - "!hardware"
+
+- name: Gather legacy and resource facts
+ cisco.ios.ios_facts:
+ gather_subset: all
+ gather_network_resources: all
+
+- name: Gather only the interfaces resource facts and no legacy facts
+ cisco.ios.ios_facts:
+ gather_subset:
+ - "!all"
+ - "!min"
+ gather_network_resources:
+ - interfaces
+
+- name: Gather interfaces resource and minimal legacy facts
+ cisco.ios.ios_facts:
+ gather_subset: min
+ gather_network_resources: interfaces
+
+- name: Gather L2 interfaces resource and minimal legacy facts
+ cisco.ios.ios_facts:
+ gather_subset: min
+ gather_network_resources: l2_interfaces
+
+- name: Gather L3 interfaces resource and minimal legacy facts
+ cisco.ios.ios_facts:
+ gather_subset: min
+ gather_network_resources: l3_interfaces
+"""
+
+RETURN = """
+ansible_net_gather_subset:
+ description: The list of fact subsets collected from the device
+ returned: always
+ type: list
+
+ansible_net_gather_network_resources:
+ description: The list of fact for network resource subsets collected from the device
+ returned: when the resource is configured
+ type: list
+
+# default
+ansible_net_model:
+ description: The model name returned from the device
+ returned: always
+ type: str
+ansible_net_serialnum:
+ description: The serial number of the remote device
+ returned: always
+ type: str
+ansible_net_version:
+ description: The operating system version running on the remote device
+ returned: always
+ type: str
+ansible_net_iostype:
+ description: The operating system type (IOS or IOS-XE) running on the remote device
+ returned: always
+ type: str
+ansible_net_hostname:
+ description: The configured hostname of the device
+ returned: always
+ type: str
+ansible_net_image:
+ description: The image file the device is running
+ returned: always
+ type: str
+ansible_net_stacked_models:
+ description: The model names of each device in the stack
+ returned: when multiple devices are configured in a stack
+ type: list
+ansible_net_stacked_serialnums:
+ description: The serial numbers of each device in the stack
+ returned: when multiple devices are configured in a stack
+ type: list
+ansible_net_api:
+ description: The name of the transport
+ returned: always
+ type: str
+ansible_net_python_version:
+ description: The Python version Ansible controller is using
+ returned: always
+ type: str
+
+# hardware
+ansible_net_filesystems:
+ description: All file system names available on the device
+ returned: when hardware is configured
+ type: list
+ansible_net_filesystems_info:
+ description: A hash of all file systems containing info about each file system (e.g. free and total space)
+ returned: when hardware is configured
+ type: dict
+ansible_net_memfree_mb:
+ description: The available free memory on the remote device in Mb
+ returned: when hardware is configured
+ type: int
+ansible_net_memtotal_mb:
+ description: The total memory on the remote device in Mb
+ returned: when hardware is configured
+ type: int
+
+# config
+ansible_net_config:
+ description: The current active config from the device
+ returned: when config is configured
+ type: str
+
+# interfaces
+ansible_net_all_ipv4_addresses:
+ description: All IPv4 addresses configured on the device
+ returned: when interfaces is configured
+ type: list
+ansible_net_all_ipv6_addresses:
+ description: All IPv6 addresses configured on the device
+ returned: when interfaces is configured
+ type: list
+ansible_net_interfaces:
+ description: A hash of all interfaces running on the system
+ returned: when interfaces is configured
+ type: dict
+ansible_net_neighbors:
+ description:
+ - The list of CDP and LLDP neighbors from the remote device. If both,
+ CDP and LLDP neighbor data is present on one port, CDP is preferred.
+ returned: when interfaces is configured
+ type: dict
+"""
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.facts.facts import (
+ FactsArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.facts import (
+ FACT_RESOURCE_SUBSETS,
+ Facts,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: ansible_facts
+ """
+ argument_spec = FactsArgs.argument_spec
+ module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
+ warnings = []
+
+ ansible_facts = {}
+ if module.params.get("available_network_resources"):
+ ansible_facts["available_network_resources"] = sorted(FACT_RESOURCE_SUBSETS.keys())
+ result = Facts(module).get_facts()
+ additional_facts, additional_warnings = result
+ ansible_facts.update(additional_facts)
+ warnings.extend(additional_warnings)
+ module.exit_json(ansible_facts=ansible_facts, warnings=warnings)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_hostname.py b/ansible_collections/cisco/ios/plugins/modules/ios_hostname.py
new file mode 100644
index 000000000..2949fc584
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_hostname.py
@@ -0,0 +1,332 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2022 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+"""
+The module file for ios_hostname
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_hostname
+short_description: Resource module to configure hostname.
+description:
+ - This module provides declarative management of hostname on Cisco IOS devices.
+version_added: 2.7.0
+author:
+ - Sagar Paul (@KB-perByte)
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+options:
+ config:
+ description: A dictionary of hostname options
+ type: dict
+ suboptions:
+ hostname:
+ description: set hostname for IOS
+ type: str
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device
+ by executing the command B(show running-config | section ^hostname).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - rendered
+ - gathered
+ - parsed
+ default: merged
+ description:
+ - The state the configuration should be left in
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device.
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result. For state I(rendered) active connection to remote host is
+ not required.
+ - The states I(merged), I(replaced) and I(overridden) have identical
+ behaviour for this module.
+ - The state I(gathered) will fetch the running configuration from device and transform
+ it into structured data in the format as per the resource module argspec and
+ the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result. The value of C(running_config)
+ option should be the same format as the output of command
+ I(show running-config | section ^hostname) executed on device. For state I(parsed) active
+ connection to remote host is not required.
+ type: str
+"""
+
+EXAMPLES = """
+# Using state: merged
+
+# Before state:
+# -------------
+
+# router-ios#show running-config | section ^hostname
+# hostname Router
+
+# Merged play:
+# ------------
+
+- name: Apply the provided configuration
+ cisco.ios.ios_hostname:
+ config:
+ hostname: Router1
+ state: merged
+
+# Commands Fired:
+# ---------------
+
+# "commands": [
+# "hostname Router1",
+# ],
+
+# After state:
+# ------------
+
+# router-ios#show running-config | section ^hostname
+# hostname Router1
+
+# Using state: deleted
+
+# Before state:
+# -------------
+
+# router-ios#show running-config | section ^hostname
+# hostname RouterTest
+
+# Deleted play:
+# -------------
+
+- name: Remove all existing configuration
+ cisco.ios.ios_hostname:
+ state: deleted
+
+# Commands Fired:
+# ---------------
+
+# "commands": [
+# "no hostname RouterTest",
+# ],
+
+# After state:
+# ------------
+
+# router-ios#show running-config | section ^hostname
+# hostname Router
+
+# Using state: overridden
+
+# Before state:
+# -------------
+
+# router-ios#show running-config | section ^hostname
+# hostname Router
+
+# Overridden play:
+# ----------------
+
+- name: Override commands with provided configuration
+ cisco.ios.ios_hostname:
+ config:
+ hostname: RouterTest
+ state: overridden
+
+# Commands Fired:
+# ---------------
+# "commands": [
+# "hostname RouterTest",
+# ],
+
+# After state:
+# ------------
+
+# router-ios#show running-config | section ^hostname
+# hostname RouterTest
+
+# Using state: replaced
+
+# Before state:
+# -------------
+
+# router-ios#show running-config | section ^hostname
+# hostname RouterTest
+
+# Replaced play:
+# --------------
+
+- name: Replace commands with provided configuration
+ cisco.ios.ios_hostname:
+ config:
+ hostname: RouterTest
+ state: replaced
+
+# Commands Fired:
+# ---------------
+
+# "commands": [],
+
+# After state:
+# ------------
+
+# router-ios#show running-config | section ^hostname
+# hostname RouterTest
+
+# Using state: gathered
+
+# Before state:
+# -------------
+
+#router-ios#show running-config | section ^hostname
+# hostname RouterTest
+
+# Gathered play:
+# --------------
+
+- name: Gather listed hostname config
+ cisco.ios.ios_hostname:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+
+# "gathered": {
+# "hostname": "RouterTest"
+# },
+
+# Using state: rendered
+
+# Rendered play:
+# --------------
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_hostname:
+ config:
+ hostname: RouterTest
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+
+# "rendered": [
+# "hostname RouterTest",
+# ]
+
+# Using state: parsed
+
+# File: parsed.cfg
+# ----------------
+
+# hostname RouterTest
+
+# Parsed play:
+# ------------
+
+- name: Parse the provided configuration with the existing running configuration
+ cisco.ios.ios_hostname:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+
+# "parsed": {
+# "hostname": "RouterTest"
+# }
+"""
+
+RETURN = """
+before:
+ description: The configuration prior to the module execution.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+after:
+ description: The resulting configuration after module execution.
+ returned: when changed
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: list
+ sample:
+ - hostname Router1
+rendered:
+ description: The provided configuration in the task rendered in device-native format (offline).
+ returned: when I(state) is C(rendered)
+ type: list
+ sample:
+ - hostname Switch1
+gathered:
+ description: Facts about the network resource gathered from the remote device as structured data.
+ returned: when I(state) is C(gathered)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+parsed:
+ description: The device native config provided in I(running_config) option parsed into structured data as per module argspec.
+ returned: when I(state) is C(parsed)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.hostname.hostname import (
+ HostnameArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.hostname.hostname import (
+ Hostname,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ module = AnsibleModule(
+ argument_spec=HostnameArgs.argument_spec,
+ mutually_exclusive=[["config", "running_config"]],
+ required_if=[
+ ["state", "merged", ["config"]],
+ ["state", "replaced", ["config"]],
+ ["state", "overridden", ["config"]],
+ ["state", "rendered", ["config"]],
+ ["state", "parsed", ["running_config"]],
+ ],
+ supports_check_mode=True,
+ )
+
+ result = Hostname(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_interfaces.py b/ansible_collections/cisco/ios/plugins/modules/ios_interfaces.py
new file mode 100644
index 000000000..b87cc1408
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_interfaces.py
@@ -0,0 +1,1009 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2022 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+"""
+The module file for ios_interfaces
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_interfaces
+short_description: Resource module to configure interfaces.
+description: This module manages the interface attributes of Cisco IOS network devices.
+version_added: 1.0.0
+author:
+ - Sumit Jaiswal (@justjais)
+ - Sagar Paul (@KB-perByte)
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+ - The module examples uses callback plugin (stdout_callback = yaml) to generate task
+ output in yaml format.
+options:
+ config:
+ description: A dictionary of interface options
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Full name of interface, e.g. GigabitEthernet0/2, loopback999.
+ type: str
+ required: true
+ description:
+ description:
+ - Interface description.
+ type: str
+ enabled:
+ description:
+ - Administrative state of the interface.
+ - Set the value to C(true) to administratively enable the interface or C(false)
+ to disable it.
+ type: bool
+ default: true
+ speed:
+ description:
+ - Interface link speed. Applicable for Ethernet interfaces only.
+ type: str
+ mtu:
+ description:
+ - MTU for a specific interface. Applicable for Ethernet interfaces only.
+ - Refer to vendor documentation for valid values.
+ type: int
+ mode:
+ description:
+ - Manage Layer2 or Layer3 state of the interface.
+ - For a Layer 2 appliance mode Layer2 adds switchport command ( default impacts idempotency).
+ - For a Layer 2 appliance mode Layer3 adds no switchport command.
+ - For a Layer 3 appliance mode Layer3/2 has no impact rather command fails on apply.
+ choices:
+ - layer2
+ - layer3
+ type: str
+ duplex:
+ description:
+ - Interface link status. Applicable for Ethernet interfaces only, either in
+ half duplex, full duplex or in automatic state which negotiates the duplex
+ automatically.
+ type: str
+ choices:
+ - full
+ - half
+ - auto
+ template:
+ description:
+ - IOS template name.
+ type: str
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device by
+ executing the command B(show running-config | section ^interface).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - rendered
+ - gathered
+ - purged
+ - parsed
+ default: merged
+ description:
+ - The state the configuration should be left in
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device.
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result. For state I(rendered) active connection to remote host is
+ not required.
+ - The state I(gathered) will fetch the running configuration from device and transform
+ it into structured data in the format as per the resource module argspec and
+ the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result. The value of C(running_config)
+ option should be the same format as the output of command I(show running-config
+ | include ip route|ipv6 route) executed on device. For state I(parsed) active
+ connection to remote host is not required.
+ - The state I(purged) negates virtual/logical interfaces that are specified in task
+ from running-config.
+ type: str
+"""
+
+EXAMPLES = """
+# Using merged
+
+# Before state:
+# -------------
+#
+# Router#sh running-config | section interface
+# interface Loopback888
+# no ip address
+# interface Loopback999
+# no ip address
+# interface GigabitEthernet1
+# ip address dhcp
+# negotiation auto
+# interface GigabitEthernet2
+# description Configured and Merged by Ansible Network
+# ip address dhcp
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3
+# no ip address
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+
+- name: Merge provided configuration with device configuration
+ cisco.ios.ios_interfaces:
+ config:
+ - name: GigabitEthernet2
+ description: Configured and Merged by Ansible Network
+ enabled: true
+ - name: GigabitEthernet3
+ description: Configured and Merged by Ansible Network
+ mtu: 3800
+ enabled: false
+ speed: 100
+ duplex: full
+ state: merged
+
+# Task Output
+# -----------
+#
+# before:
+# - enabled: true
+# name: GigabitEthernet1
+# - description: Configured and Merged by Ansible Network
+# enabled: true
+# name: GigabitEthernet2
+# speed: '1000'
+# - description: Configured and Merged by Ansible Network
+# enabled: false
+# mtu: 3800
+# name: GigabitEthernet3
+# speed: '1000'
+# - enabled: false
+# name: GigabitEthernet4
+# - enabled: true
+# name: Loopback888
+# - enabled: true
+# name: Loopback999
+# commands:
+# - interface GigabitEthernet3
+# - description Configured and Merged by Ansible Network
+# - speed 100
+# - mtu 3800
+# - duplex full
+# - shutdown
+# after:
+# - enabled: true
+# name: GigabitEthernet1
+# - description: Configured and Merged by Ansible Network
+# enabled: true
+# name: GigabitEthernet2
+# speed: '1000'
+# - description: Configured and Merged by Ansible Network
+# enabled: true
+# mtu: 2800
+# name: GigabitEthernet3
+# speed: '1000'
+# - enabled: false
+# name: GigabitEthernet4
+# - enabled: true
+# name: Loopback888
+# - enabled: true
+# name: Loopback999
+
+# After state:
+# ------------
+#
+# Router#show running-config | section ^interface
+# interface Loopback888
+# no ip address
+# interface Loopback999
+# no ip address
+# interface GigabitEthernet1
+# ip address dhcp
+# negotiation auto
+# interface GigabitEthernet2
+# description Configured and Merged by Ansible Network
+# ip address dhcp
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3
+# description Configured and Merged by Ansible Network
+# mtu 3800
+# no ip address
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+
+# Using merged - with mode attribute
+
+# Before state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface GigabitEthernet1
+# description Configured by Ansible
+# interface GigabitEthernet2
+# description This is test
+# interface GigabitEthernet3
+# description This is test
+# no switchport
+
+- name: Merge provided configuration with device configuration
+ cisco.ios.ios_interfaces:
+ config:
+ - name: GigabitEthernet2
+ description: Configured and Merged by Ansible Network
+ enabled: true
+ mode: layer2
+ - name: GigabitEthernet3
+ description: Configured and Merged by Ansible Network
+ mode: layer3
+ state: merged
+
+# Task Output
+# -----------
+#
+# before:
+# - enabled: true
+# name: GigabitEthernet1
+# - description: Configured and Merged by Ansible Network
+# name: GigabitEthernet2
+# - description: Configured and Merged by Ansible Network
+# name: GigabitEthernet3
+# commands:
+# - interface GigabitEthernet2
+# - description Configured and Merged by Ansible Network
+# - switchport
+# - interface GigabitEthernet3
+# - description Configured and Merged by Ansible Network
+# after:
+# - enabled: true
+# name: GigabitEthernet1
+# - description: Configured and Merged by Ansible Network
+# enabled: true
+# name: GigabitEthernet2
+# - description: Configured and Merged by Ansible Network
+# name: GigabitEthernet3
+# mode: layer3
+
+# After state:
+# ------------
+#
+# vios#show running-config | section ^interface
+# interface GigabitEthernet1
+# description Configured by Ansible
+# interface GigabitEthernet2
+# description Configured and Merged by Ansible Network
+# interface GigabitEthernet3
+# description Configured and Merged by Ansible Network
+# no switchport
+
+# Using replaced
+
+# Before state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Loopback888
+# no ip address
+# interface Loopback999
+# no ip address
+# interface GigabitEthernet1
+# description Management interface do not change
+# ip address dhcp
+# negotiation auto
+# interface GigabitEthernet2
+# ip address dhcp
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3
+# no ip address
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+# interface Vlan50
+# ip address dhcp hostname testHostname
+
+- name: Replaces device configuration of listed interfaces with provided configuration
+ cisco.ios.ios_interfaces:
+ config:
+ - name: GigabitEthernet3
+ description: Configured and Replaced by Ansible Network
+ enabled: false
+ speed: 1000
+ state: replaced
+
+# Task Output
+# -----------
+#
+# before:
+# - description: Management interface do not change
+# enabled: true
+# name: GigabitEthernet1
+# - enabled: true
+# name: GigabitEthernet2
+# speed: '1000'
+# - enabled: true
+# name: GigabitEthernet3
+# speed: '1000'
+# - enabled: false
+# name: GigabitEthernet4
+# - enabled: true
+# name: Loopback888
+# - enabled: true
+# name: Loopback999
+# - enabled: true
+# name: Vlan50
+# commands:
+# - interface GigabitEthernet3
+# - description Configured and Replaced by Ansible Network
+# - shutdown
+# after:
+# - description: Management interface do not change
+# enabled: true
+# name: GigabitEthernet1
+# - enabled: true
+# name: GigabitEthernet2
+# speed: '1000'
+# - description: Configured and Replaced by Ansible Network
+# enabled: false
+# name: GigabitEthernet3
+# speed: '1000'
+# - enabled: false
+# name: GigabitEthernet4
+# - enabled: true
+# name: Loopback888
+# - enabled: true
+# name: Loopback999
+# - enabled: true
+# name: Vlan50
+
+# After state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Loopback888
+# no ip address
+# interface Loopback999
+# no ip address
+# interface GigabitEthernet1
+# description Management interface do not change
+# ip address dhcp
+# negotiation auto
+# interface GigabitEthernet2
+# ip address dhcp
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3
+# description Configured and Replaced by Ansible Network
+# no ip address
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+# interface Vlan50
+# ip address dhcp hostname testHostname
+
+# Using overridden
+
+# Before state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Loopback888
+# no ip address
+# interface Loopback999
+# no ip address
+# interface GigabitEthernet1
+# description Management interface do not change
+# ip address dhcp
+# negotiation auto
+# interface GigabitEthernet2
+# ip address dhcp
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3
+# description Configured and Replaced by Ansible Network
+# no ip address
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+# interface Vlan50
+# ip address dhcp hostname testHostname
+
+- name: Override device configuration of all interfaces with provided configuration
+ cisco.ios.ios_interfaces:
+ config:
+ - description: Management interface do not change
+ enabled: true
+ name: GigabitEthernet1
+ - name: GigabitEthernet2
+ description: Configured and Overridden by Ansible Network
+ speed: 10000
+ - name: GigabitEthernet3
+ description: Configured and Overridden by Ansible Network
+ enabled: false
+ state: overridden
+
+# Task Output
+# -----------
+#
+# before:
+# - description: Management interface do not change
+# enabled: true
+# name: GigabitEthernet1
+# - enabled: true
+# name: GigabitEthernet2
+# speed: '1000'
+# - description: Configured and Replaced by Ansible Network
+# enabled: false
+# name: GigabitEthernet3
+# speed: '1000'
+# - enabled: false
+# name: GigabitEthernet4
+# - enabled: true
+# name: Loopback888
+# - enabled: true
+# name: Loopback999
+# - enabled: true
+# name: Vlan50
+# commands:
+# - interface loopback888
+# - shutdown
+# - interface loopback999
+# - shutdown
+# - interface Vlan50
+# - shutdown
+# - interface GigabitEthernet2
+# - description Configured and Overridden by Ansible Network
+# - speed 10000
+# - interface GigabitEthernet3
+# - description Configured and Overridden by Ansible Network
+# - no speed 1000
+# after:
+# - description: Management interface do not change
+# enabled: true
+# name: GigabitEthernet1
+# - description: Configured and Overridden by Ansible Network
+# enabled: true
+# name: GigabitEthernet2
+# speed: '10000'
+# - description: Configured and Overridden by Ansible Network
+# enabled: false
+# name: GigabitEthernet3
+# speed: '1000'
+# - enabled: false
+# name: GigabitEthernet4
+# - enabled: false
+# name: Loopback888
+# - enabled: false
+# name: Loopback999
+# - enabled: false
+# name: Vlan50
+
+# After state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Loopback888
+# no ip address
+# shutdown
+# interface Loopback999
+# no ip address
+# shutdown
+# interface GigabitEthernet1
+# description Management interface do not change
+# ip address dhcp
+# negotiation auto
+# interface GigabitEthernet2
+# description Configured and Overridden by Ansible Network
+# ip address dhcp
+# speed 10000
+# no negotiation auto
+# interface GigabitEthernet3
+# description Configured and Overridden by Ansible Network
+# no ip address
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+# interface Vlan50
+# ip address dhcp hostname testHostname
+# shutdown
+
+# Using Deleted
+
+# Before state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Loopback888
+# no ip address
+# shutdown
+# interface Loopback999
+# no ip address
+# shutdown
+# interface GigabitEthernet1
+# description Management interface do not change
+# ip address dhcp
+# negotiation auto
+# interface GigabitEthernet2
+# description Configured and Overridden by Ansible Network
+# ip address dhcp
+# speed 10000
+# no negotiation auto
+# interface GigabitEthernet3
+# description Configured and Overridden by Ansible Network
+# no ip address
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+# interface Vlan50
+# ip address dhcp hostname testHostname
+# shutdown
+
+- name: "Delete interface attributes (Note: This won't delete the interface itself)"
+ cisco.ios.ios_interfaces:
+ config:
+ - name: GigabitEthernet2
+ state: deleted
+
+# Task Output
+# -----------
+#
+# before:
+# - description: Management interface do not change
+# enabled: true
+# name: GigabitEthernet1
+# - description: Configured and Overridden by Ansible Network
+# enabled: true
+# name: GigabitEthernet2
+# speed: '10000'
+# - description: Configured and Overridden by Ansible Network
+# enabled: false
+# name: GigabitEthernet3
+# speed: '1000'
+# - enabled: false
+# name: GigabitEthernet4
+# - enabled: false
+# name: Loopback888
+# - enabled: false
+# name: Loopback999
+# - enabled: false
+# name: Vlan50
+# commands:
+# - interface GigabitEthernet2
+# - no description Configured and Overridden by Ansible Network
+# - no speed 10000
+# - shutdown
+# after:
+# - description: Management interface do not change
+# enabled: true
+# name: GigabitEthernet1
+# - enabled: false
+# name: GigabitEthernet2
+# speed: '1000'
+# - description: Configured and Overridden by Ansible Network
+# enabled: false
+# name: GigabitEthernet3
+# speed: '1000'
+# - enabled: false
+# name: GigabitEthernet4
+# - enabled: false
+# name: Loopback888
+# - enabled: false
+# name: Loopback999
+# - enabled: false
+# name: Vlan50
+
+# After state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Loopback888
+# no ip address
+# shutdown
+# interface Loopback999
+# no ip address
+# shutdown
+# interface GigabitEthernet1
+# description Management interface do not change
+# ip address dhcp
+# negotiation auto
+# interface GigabitEthernet2
+# ip address dhcp
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3
+# description Configured and Overridden by Ansible Network
+# no ip address
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+# interface Vlan50
+# ip address dhcp hostname testHostname
+# shutdown
+
+# Using Purged
+
+# Before state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Loopback888
+# no ip address
+# shutdown
+# interface Loopback999
+# no ip address
+# shutdown
+# interface GigabitEthernet1
+# description Management interface do not change
+# ip address dhcp
+# negotiation auto
+# interface GigabitEthernet2
+# ip address dhcp
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3
+# description Configured and Overridden by Ansible Network
+# no ip address
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+# interface Vlan50
+# ip address dhcp hostname testHostname
+# shutdown
+
+- name: "Purge given interfaces (Note: This will delete the interface itself)"
+ cisco.ios.ios_interfaces:
+ config:
+ - name: Loopback888
+ - name: Vlan50
+ state: purged
+
+# Task Output
+# -----------
+#
+# before:
+# - description: Management interface do not change
+# enabled: true
+# name: GigabitEthernet1
+# - enabled: false
+# name: GigabitEthernet2
+# speed: '1000'
+# - description: Configured and Overridden by Ansible Network
+# enabled: false
+# name: GigabitEthernet3
+# speed: '1000'
+# - enabled: false
+# name: GigabitEthernet4
+# - enabled: false
+# name: Loopback888
+# - enabled: false
+# name: Loopback999
+# - enabled: false
+# name: Vlan50
+# commands:
+# - no interface loopback888
+# - no interface Vlan50
+# after:
+# - description: Management interface do not change
+# enabled: true
+# name: GigabitEthernet1
+# - enabled: false
+# name: GigabitEthernet2
+# speed: '1000'
+# - description: Configured and Overridden by Ansible Network
+# enabled: false
+# name: GigabitEthernet3
+# speed: '1000'
+# - enabled: false
+# name: GigabitEthernet4
+# - enabled: false
+# name: Loopback999
+
+# After state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Loopback999
+# no ip address
+# shutdown
+# interface GigabitEthernet1
+# description Management interface do not change
+# ip address dhcp
+# negotiation auto
+# interface GigabitEthernet2
+# ip address dhcp
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3
+# description Configured and Overridden by Ansible Network
+# no ip address
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+
+# Using gathered
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^interface
+# interface Loopback999
+# no ip address
+# shutdown
+# interface GigabitEthernet1
+# description Management interface do not change
+# ip address dhcp
+# negotiation auto
+# interface GigabitEthernet2
+# ip address dhcp
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3
+# description Configured and Overridden by Ansible Network
+# no ip address
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+
+- name: Gather facts of interfaces
+ cisco.ios.ios_interfaces:
+ config:
+ state: gathered
+
+# Task Output
+# -----------
+#
+# gathered:
+# - description: Management interface do not change
+# enabled: true
+# name: GigabitEthernet1
+# - enabled: false
+# name: GigabitEthernet2
+# speed: '1000'
+# - description: Configured and Overridden by Ansible Network
+# enabled: false
+# name: GigabitEthernet3
+# speed: '1000'
+# - enabled: false
+# name: GigabitEthernet4
+# - enabled: false
+# name: Loopback999
+
+# Using rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_interfaces:
+ config:
+ - name: GigabitEthernet1
+ description: Configured by Ansible-Network
+ mtu: 110
+ enabled: true
+ duplex: half
+ - name: GigabitEthernet2
+ description: Configured by Ansible-Network
+ mtu: 2800
+ enabled: false
+ speed: 100
+ duplex: full
+ state: rendered
+
+# Task Output
+# -----------
+#
+# rendered:
+# - interface GigabitEthernet1
+# - description Configured by Ansible-Network
+# - mtu 110
+# - duplex half
+# - no shutdown
+# - interface GigabitEthernet2
+# - description Configured by Ansible-Network
+# - speed 100
+# - mtu 2800
+# - duplex full
+# - shutdown
+
+# Using parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# interface Loopback999
+# no ip address
+# shutdown
+# interface GigabitEthernet1
+# description Management interface do not change
+# ip address dhcp
+# negotiation auto
+# interface GigabitEthernet2
+# ip address dhcp
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3
+# description Configured and Overridden by Ansible Network
+# no ip address
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+
+- name: Parse the provided configuration
+ cisco.ios.ios_interfaces:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Task Output
+# -----------
+#
+# parsed:
+# - description: Management interface do not change
+# enabled: true
+# name: GigabitEthernet1
+# - enabled: false
+# name: GigabitEthernet2
+# speed: '1000'
+# - description: Configured and Overridden by Ansible Network
+# enabled: false
+# name: GigabitEthernet3
+# speed: '1000'
+# - enabled: false
+# name: GigabitEthernet4
+# - enabled: false
+# name: Loopback999
+"""
+
+RETURN = """
+before:
+ description: The configuration prior to the module execution.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+after:
+ description: The resulting configuration after module execution.
+ returned: when changed
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: list
+ sample:
+ - interface GigabitEthernet2
+ - speed 1200
+ - mtu 1800
+rendered:
+ description: The provided configuration in the task rendered in device-native format (offline).
+ returned: when I(state) is C(rendered)
+ type: list
+ sample:
+ - interface GigabitEthernet1
+ - description Interface description
+ - shutdown
+gathered:
+ description: Facts about the network resource gathered from the remote device as structured data.
+ returned: when I(state) is C(gathered)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+parsed:
+ description: The device native config provided in I(running_config) option parsed into structured data as per module argspec.
+ returned: when I(state) is C(parsed)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.interfaces.interfaces import (
+ InterfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.interfaces.interfaces import (
+ Interfaces,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ module = AnsibleModule(
+ argument_spec=InterfacesArgs.argument_spec,
+ mutually_exclusive=[["config", "running_config"]],
+ required_if=[
+ ["state", "merged", ["config"]],
+ ["state", "replaced", ["config"]],
+ ["state", "overridden", ["config"]],
+ ["state", "rendered", ["config"]],
+ ["state", "purged", ["config"]],
+ ["state", "parsed", ["running_config"]],
+ ],
+ supports_check_mode=True,
+ )
+
+ result = Interfaces(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_l2_interfaces.py b/ansible_collections/cisco/ios/plugins/modules/ios_l2_interfaces.py
new file mode 100644
index 000000000..16c9ff468
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_l2_interfaces.py
@@ -0,0 +1,754 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2022 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+"""
+The module file for ios_l2_interfaces
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_l2_interfaces
+short_description: Resource module to configure L2 interfaces.
+description:
+ This module provides declarative management of Layer-2 interface on Cisco
+ IOS devices.
+version_added: 1.0.0
+author:
+ - Sagar Paul (@KB-petByte)
+ - Sumit Jaiswal (@justjais)
+notes:
+ - Tested against Cisco IOSv Version 15.2 on CML.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+ - The module examples uses callback plugin (stdout_callback = yaml) to generate task
+ output in yaml format.
+options:
+ config:
+ description: A dictionary of Layer-2 interface options
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Full name of the interface excluding any logical unit
+ number, i.e GigabitEthernet0/1.
+ type: str
+ required: true
+ access:
+ description:
+ - Switchport mode access command to configure the interface as a layer 2 access.
+ type: dict
+ suboptions:
+ vlan:
+ description:
+ - Configure given VLAN in access port. It's used as the access VLAN ID.
+ type: int
+ vlan_name:
+ description:
+ - Set VLAN when interface is in access mode.
+ type: str
+ voice:
+ description:
+ - Switchport mode voice command to configure the interface with a voice vlan.
+ type: dict
+ suboptions:
+ vlan:
+ description:
+ - Configure given voice VLAN on access port. It's used as the voice VLAN
+ ID.
+ type: int
+ vlan_tag:
+ description:
+ - Set VLAN Tag.
+ dot1p (Priority tagged on PVID)
+ none (Don't tell telephone about voice vlan)
+ untagged (Untagged on PVID)
+ choices:
+ - dot1p
+ - none
+ - untagged
+ type: str
+ vlan_name:
+ description:
+ - Set VLAN when interface is in access mode.
+ type: str
+ trunk:
+ description:
+ - Switchport mode trunk command to configure the interface as a Layer 2 trunk.
+ Note The encapsulation is always set to dot1q.
+ type: dict
+ suboptions:
+ allowed_vlans:
+ description:
+ - List of allowed VLANs in a given trunk port. These are the only VLANs
+ that will be configured on the trunk.
+ type: list
+ elements: str
+ native_vlan:
+ description:
+ - Native VLAN to be configured in trunk port. It's used as the trunk native
+ VLAN ID.
+ type: int
+ encapsulation:
+ description:
+ - Trunking encapsulation when interface is in trunking mode.
+ choices:
+ - dot1q
+ - isl
+ - negotiate
+ type: str
+ pruning_vlans:
+ description:
+ - Pruning VLAN to be configured in trunk port. It's used as the trunk
+ pruning VLAN ID.
+ type: list
+ elements: str
+ mode:
+ description:
+ - Mode in which interface needs to be configured.
+ - An interface whose trunk encapsulation is "Auto" can not be configured to
+ "trunk" mode.
+ type: str
+ choices:
+ - access
+ - trunk
+ - dot1q_tunnel
+ - dynamic
+ - dynamic_auto
+ - dynamic_desirable
+ - private_vlan_host
+ - private_vlan_promiscuous
+ - private_vlan_trunk
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device by
+ executing the command B(show running-config | section ^interface).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - rendered
+ - gathered
+ - parsed
+ default: merged
+ description:
+ - The state the configuration should be left in
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device.
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result. For state I(rendered) active connection to remote host is
+ not required.
+ - The state I(gathered) will fetch the running configuration from device and
+ transform it into structured data in the format as per the resource module
+ argspec and the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result. The value of
+ C(running_config) option should be the same format as the output of
+ command I(show running-config | include ip route|ipv6 route) executed on device.
+ For state I(parsed) active connection to remote host is not required.
+ type: str
+"""
+
+EXAMPLES = """
+# Using merged
+
+# Before state:
+# -------------
+#
+# viosl2#show running-config | section ^interface
+# interface GigabitEthernet0/1
+# description Configured by Ansible
+# negotiation auto
+# interface GigabitEthernet0/2
+# description This is test
+# switchport access vlan 20
+# media-type rj45
+# negotiation auto
+
+- name: Merge provided configuration with device configuration
+ cisco.ios.ios_l2_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ mode: access
+ access:
+ vlan: 10
+ voice:
+ vlan: 40
+ - name: GigabitEthernet0/2
+ mode: trunk
+ trunk:
+ allowed_vlans: 10-20,40
+ native_vlan: 20
+ pruning_vlans: 10,20
+ encapsulation: dot1q
+ state: merged
+
+# Task Output
+# -----------
+#
+# before:
+# - name: GigabitEthernet0/1
+# - access:
+# vlan: 20
+# name: GigabitEthernet0/2
+# commands:
+# - interface GigabitEthernet0/1
+# - switchport access vlan 10
+# - switchport voice vlan 40
+# - switchport mode access
+# - interface GigabitEthernet0/2
+# - switchport mode trunk
+# - switchport trunk encapsulation dot1q
+# - switchport trunk native vlan 20
+# - switchport trunk allowed vlan 10-20,40
+# - switchport trunk pruning vlan 10,20
+# after:
+# - access:
+# vlan: 10
+# mode: access
+# name: GigabitEthernet0/1
+# voice:
+# vlan: 40
+# - mode: trunk
+# name: GigabitEthernet0/2
+# trunk:
+# allowed_vlans:
+# - 10-20
+# - '40'
+# encapsulation: dot1q
+# native_vlan: 20
+# pruning_vlans:
+# - '10'
+# - '20'
+
+# After state:
+# ------------
+#
+# viosl2#show running-config | section ^interface
+# interface GigabitEthernet0/1
+# description Configured by Ansible
+# switchport access vlan 10
+# switchport voice vlan 40
+# switchport mode access
+# negotiation auto
+# interface GigabitEthernet0/2
+# description This is test
+# switchport trunk allowed vlan 10-20,40
+# switchport trunk encapsulation dot1q
+# switchport trunk native vlan 20
+# switchport trunk pruning vlan 10,20
+# switchport mode trunk
+# media-type rj45
+# negotiation auto
+
+# Using replaced
+
+# Before state:
+# -------------
+#
+# viosl2#show running-config | section ^interface
+# interface GigabitEthernet0/1
+# description Configured by Ansible
+# switchport access vlan 20
+# negotiation auto
+# interface GigabitEthernet0/2
+# description This is test
+# switchport access vlan 20
+# media-type rj45
+# negotiation auto
+
+- name: Replaces device configuration with provided configuration
+ cisco.ios.ios_l2_interfaces:
+ config:
+ - name: GigabitEthernet0/2
+ trunk:
+ allowed_vlans: 20-25,40
+ native_vlan: 20
+ pruning_vlans: 10
+ encapsulation: isl
+ state: replaced
+
+# Task Output
+# -----------
+#
+# before:
+# - name: GigabitEthernet0/1
+# - access:
+# vlan: 20
+# name: GigabitEthernet0/2
+# commands:
+# - interface GigabitEthernet0/2
+# - no switchport access vlan
+# - switchport trunk encapsulation isl
+# - switchport trunk native vlan 20
+# - switchport trunk allowed vlan 20-25,40
+# - switchport trunk pruning vlan 10
+# after:
+# - access:
+# vlan: 20
+# name: GigabitEthernet0/1
+# - name: GigabitEthernet0/2
+# trunk:
+# allowed_vlans:
+# - 20-25
+# - '40'
+# encapsulation: isl
+# native_vlan: 20
+# pruning_vlans:
+# - '10'
+
+# After state:
+# -------------
+#
+# viosl2#show running-config | section ^interface
+# interface GigabitEthernet0/1
+# description Configured by Ansible
+# switchport access vlan 20
+# negotiation auto
+# interface GigabitEthernet0/2
+# description This is test
+# switchport trunk allowed vlan 20-25,40
+# switchport trunk encapsulation isl
+# switchport trunk native vlan 20
+# switchport trunk pruning vlan 10
+# media-type rj45
+# negotiation auto
+
+# Using overridden
+
+# Before state:
+# -------------
+#
+# viosl2#show running-config | section ^interface
+# interface GigabitEthernet0/1
+# description Configured by Ansible
+# switchport trunk encapsulation dot1q
+# switchport trunk native vlan 20
+# negotiation auto
+# interface GigabitEthernet0/2
+# description This is test
+# switchport access vlan 20
+# switchport trunk encapsulation dot1q
+# switchport trunk native vlan 20
+# media-type rj45
+# negotiation auto
+
+- name: Override device configuration of all l2 interfaces with provided configuration
+ cisco.ios.ios_l2_interfaces:
+ config:
+ - name: GigabitEthernet0/2
+ access:
+ vlan: 20
+ voice:
+ vlan: 40
+ state: overridden
+
+# Task Output
+# -----------
+#
+# before:
+# - name: GigabitEthernet0/1
+# trunk:
+# encapsulation: dot1q
+# native_vlan: 20
+# - access:
+# vlan: 20
+# name: GigabitEthernet0/2
+# trunk:
+# encapsulation: dot1q
+# native_vlan: 20
+# commands:
+# - interface GigabitEthernet0/1
+# - no switchport trunk encapsulation
+# - no switchport trunk native vlan
+# - interface GigabitEthernet0/2
+# - switchport voice vlan 40
+# - no switchport trunk encapsulation
+# - no switchport trunk native vlan
+# after:
+# - name: GigabitEthernet0/1
+# - access:
+# vlan: 20
+# name: GigabitEthernet0/2
+# voice:
+# vlan: 40
+
+# After state:
+# -------------
+#
+# viosl2#show running-config | section ^interface
+# interface GigabitEthernet0/1
+# description Configured by Ansible
+# negotiation auto
+# interface GigabitEthernet0/2
+# description This is test
+# switchport access vlan 20
+# switchport voice vlan 40
+# media-type rj45
+# negotiation auto
+
+# Using deleted
+
+# Before state:
+# -------------
+#
+# viosl2#show running-config | section ^interface
+# interface GigabitEthernet0/1
+# description Configured by Ansible
+# switchport access vlan 20
+# negotiation auto
+# interface GigabitEthernet0/2
+# description This is test
+# switchport access vlan 20
+# switchport trunk allowed vlan 20-40,60,80
+# switchport trunk encapsulation dot1q
+# switchport trunk native vlan 10
+# switchport trunk pruning vlan 10
+# media-type rj45
+# negotiation auto
+
+- name: Delete IOS L2 interfaces as in given arguments
+ cisco.ios.ios_l2_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ state: deleted
+
+# Task Output
+# -----------
+#
+# before:
+# - access:
+# vlan: 20
+# name: GigabitEthernet0/1
+# - access:
+# vlan: 20
+# name: GigabitEthernet0/2
+# trunk:
+# allowed_vlans:
+# - 20-40
+# - '60'
+# - '80'
+# encapsulation: dot1q
+# native_vlan: 10
+# pruning_vlans:
+# - '10'
+# commands:
+# - interface GigabitEthernet0/1
+# - no switchport access vlan
+# after:
+# - name: GigabitEthernet0/1
+# - access:
+# vlan: 20
+# name: GigabitEthernet0/2
+# trunk:
+# allowed_vlans:
+# - 20-40
+# - '60'
+# - '80'
+# encapsulation: dot1q
+# native_vlan: 10
+# pruning_vlans:
+# - '10'
+
+# After state:
+# -------------
+#
+# viosl2#show running-config | section ^interface
+# interface GigabitEthernet0/1
+# description Configured by Ansible
+# negotiation auto
+# interface GigabitEthernet0/2
+# description This is test
+# switchport access vlan 20
+# switchport trunk allowed vlan 20-40,60,80
+# switchport trunk encapsulation dot1q
+# switchport trunk native vlan 10
+# switchport trunk pruning vlan 10
+# media-type rj45
+# negotiation auto
+
+# Using deleted without config - delete all configuration
+
+# Before state:
+# -------------
+#
+# viosl2#show running-config | section ^interface
+# interface GigabitEthernet0/1
+# description Configured by Ansible
+# switchport access vlan 20
+# negotiation auto
+# interface GigabitEthernet0/2
+# description This is test
+# switchport access vlan 20
+# switchport trunk allowed vlan 20-40,60,80
+# switchport trunk encapsulation dot1q
+# switchport trunk native vlan 10
+# switchport trunk pruning vlan 10
+# media-type rj45
+# negotiation auto
+
+- name: Delete IOS L2 interfaces as in given arguments
+ cisco.ios.ios_l2_interfaces:
+ state: deleted
+
+# Task Output
+# -----------
+#
+# before:
+# - access:
+# vlan: 20
+# name: GigabitEthernet0/1
+# - access:
+# vlan: 20
+# name: GigabitEthernet0/2
+# trunk:
+# allowed_vlans:
+# - 20-40
+# - '60'
+# - '80'
+# encapsulation: dot1q
+# native_vlan: 10
+# pruning_vlans:
+# - '10'
+# commands:
+# - interface GigabitEthernet0/1
+# - no switchport access vlan
+# - interface GigabitEthernet0/2
+# - no switchport access vlan
+# - no switchport trunk encapsulation
+# - no switchport trunk native vlan
+# - no switchport trunk allowed vlan
+# - no switchport trunk pruning vlan
+# after:
+# - name: GigabitEthernet0/1
+# - name: GigabitEthernet0/2
+
+# After state:
+# -------------
+#
+# viosl2#show running-config | section ^interface
+# interface GigabitEthernet0/1
+# description Configured by Ansible
+# negotiation auto
+# interface GigabitEthernet0/2
+# description This is test
+# media-type rj45
+# negotiation auto
+
+# Using gathered
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^interface
+# interface GigabitEthernet0/1
+# description Configured by Ansible
+# switchport access vlan 20
+# negotiation auto
+# interface GigabitEthernet0/2
+# description This is test
+# switchport access vlan 20
+# switchport trunk allowed vlan 20-40,60,80
+# switchport trunk encapsulation dot1q
+# switchport trunk native vlan 10
+# switchport trunk pruning vlan 10
+# media-type rj45
+# negotiation auto
+
+- name: Gather facts for l2 interfaces
+ cisco.ios.ios_l2_interfaces:
+ config:
+ state: gathered
+
+# Task Output
+# -----------
+#
+# gathered:
+# - access:
+# vlan: 20
+# name: GigabitEthernet0/1
+# - access:
+# vlan: 20
+# name: GigabitEthernet0/2
+# trunk:
+# allowed_vlans:
+# - 20-40
+# - '60'
+# - '80'
+# encapsulation: dot1q
+# native_vlan: 10
+# pruning_vlans:
+# - '10'
+
+# Using rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_l2_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ access:
+ vlan: 30
+ - name: GigabitEthernet0/2
+ trunk:
+ allowed_vlans: 10-20,40
+ native_vlan: 20
+ pruning_vlans: 10,20
+ encapsulation: dot1q
+ state: rendered
+
+# Task Output
+# -----------
+#
+# rendered:
+# - interface GigabitEthernet0/1
+# - switchport access vlan 30
+# - interface GigabitEthernet0/2
+# - switchport trunk encapsulation dot1q
+# - switchport trunk native vlan 20
+# - switchport trunk allowed vlan 10-20,40
+# - switchport trunk pruning vlan 10,20
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# interface GigabitEthernet0/1
+# description Configured by Ansible
+# switchport access vlan 20
+# negotiation auto
+# interface GigabitEthernet0/2
+# description This is test
+# switchport access vlan 20
+# switchport trunk allowed vlan 20-40,60,80
+# switchport trunk encapsulation dot1q
+# switchport trunk native vlan 10
+# switchport trunk pruning vlan 10
+# media-type rj45
+# negotiation auto
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_l2_interfaces:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Task Output
+# -----------
+#
+# parsed:
+# - access:
+# vlan: 20
+# name: GigabitEthernet0/1
+# - access:
+# vlan: 20
+# name: GigabitEthernet0/2
+# trunk:
+# allowed_vlans:
+# - 20-40
+# - '60'
+# - '80'
+# encapsulation: dot1q
+# native_vlan: 10
+# pruning_vlans:
+# - '10'
+"""
+
+RETURN = """
+before:
+ description: The configuration prior to the module execution.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+after:
+ description: The resulting configuration after module execution.
+ returned: when changed
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: list
+ sample:
+ - interface GigabitEthernet0/2
+ - switchport trunk allowed vlan 15-20,40
+ - switchport trunk encapsulation dot1q
+rendered:
+ description: The provided configuration in the task rendered in device-native format (offline).
+ returned: when I(state) is C(rendered)
+ type: list
+ sample:
+ - interface GigabitEthernet0/1
+ - switchport access vlan 30
+ - switchport trunk encapsulation dot1q
+gathered:
+ description: Facts about the network resource gathered from the remote device as structured data.
+ returned: when I(state) is C(gathered)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+parsed:
+ description: The device native config provided in I(running_config) option parsed into structured data as per module argspec.
+ returned: when I(state) is C(parsed)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.l2_interfaces.l2_interfaces import (
+ L2_interfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.l2_interfaces.l2_interfaces import (
+ L2_interfaces,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ module = AnsibleModule(
+ argument_spec=L2_interfacesArgs.argument_spec,
+ mutually_exclusive=[["config", "running_config"]],
+ required_if=[
+ ["state", "merged", ["config"]],
+ ["state", "replaced", ["config"]],
+ ["state", "overridden", ["config"]],
+ ["state", "rendered", ["config"]],
+ ["state", "parsed", ["running_config"]],
+ ],
+ supports_check_mode=True,
+ )
+
+ result = L2_interfaces(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_l3_interfaces.py b/ansible_collections/cisco/ios/plugins/modules/ios_l3_interfaces.py
new file mode 100644
index 000000000..7ea6d0d7a
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_l3_interfaces.py
@@ -0,0 +1,914 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2021 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+"""
+The module file for ios_l3_interfaces
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_l3_interfaces
+short_description: Resource module to configure L3 interfaces.
+description:
+ - This module provides declarative management of Layer-3 interface on Cisco IOS devices.
+version_added: 1.0.0
+author:
+ - Sagar Paul (@KB-perByte)
+ - Sumit Jaiswal (@justjais)
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - Using deleted state without config will delete all l3 attributes from all the interfaces.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+ - The module examples uses callback plugin (stdout_callback = yaml) to generate task
+ output in yaml format.
+options:
+ config:
+ description: A dictionary of Layer-3 interface options
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Full name of the interface excluding any logical unit number, i.e. GigabitEthernet0/1.
+ type: str
+ required: true
+ ipv4:
+ description:
+ - IPv4 address to be set for the Layer-3 interface mentioned in I(name) option.
+ The address format is <ipv4 address>/<mask>, the mask is number in range
+ 0-32 eg. 192.168.0.1/24.
+ type: list
+ elements: dict
+ suboptions:
+ address:
+ description:
+ - Configures the IPv4 address for Interface.
+ type: str
+ secondary:
+ description:
+ - Configures the IP address as a secondary address.
+ type: bool
+ dhcp_client:
+ description:
+ - Configures and specifies client-id to use over DHCP ip. Note, This option
+ shall work only when dhcp is configured as IP.
+ - GigabitEthernet interface number
+ - This option is DEPRECATED and is replaced with dhcp which
+ accepts dict as input this attribute will be removed after 2023-08-01.
+ type: str
+ dhcp_hostname:
+ description:
+ - Configures and specifies value for hostname option over DHCP ip. Note,
+ This option shall work only when dhcp is configured as IP.
+ - This option is DEPRECATED and is replaced with dhcp which
+ accepts dict as input this attribute will be removed after 2023-08-01.
+ type: str
+ dhcp:
+ description: IP Address negotiated via DHCP.
+ type: dict
+ suboptions:
+ enable:
+ description: Enable dhcp.
+ type: bool
+ client_id:
+ description: Specify client-id to use.
+ type: str
+ hostname:
+ description: Specify value for hostname option.
+ type: str
+ pool:
+ description: IP Address auto-configured from a local DHCP pool.
+ type: str
+ ipv6:
+ description:
+ - IPv6 address to be set for the Layer-3 interface mentioned in I(name) option.
+ - The address format is <ipv6 address>/<mask>, the mask is number in range
+ 0-128 eg. fd5d:12c9:2201:1::1/64
+ type: list
+ elements: dict
+ suboptions:
+ address:
+ description:
+ - Configures the IPv6 address for Interface.
+ type: str
+ autoconfig:
+ description: Obtain address using auto-configuration.
+ type: dict
+ suboptions:
+ enable:
+ description: enable auto-configuration.
+ type: bool
+ default:
+ description: Insert default route.
+ type: bool
+ dhcp:
+ description: Obtain a ipv6 address using DHCP.
+ type: dict
+ suboptions:
+ enable:
+ description: Enable dhcp.
+ type: bool
+ rapid_commit:
+ description: Enable Rapid-Commit.
+ type: bool
+ anycast:
+ description: Configure as an anycast
+ type: bool
+ cga:
+ description: Use CGA interface identifier
+ type: bool
+ eui:
+ description: Use eui-64 interface identifier
+ type: bool
+ link_local:
+ description: Use link-local address
+ type: bool
+ segment_routing:
+ description: Segment Routing submode
+ type: dict
+ suboptions:
+ enable:
+ description: Enable segmented routing.
+ type: bool
+ default:
+ description: Set a command to its defaults.
+ type: bool
+ ipv6_sr:
+ description: Set ipv6_sr.
+ type: bool
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device
+ by executing the command B(show running-config | section ^interface).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - rendered
+ - gathered
+ - parsed
+ default: merged
+ description:
+ - The state the configuration should be left in
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device.
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result. For state I(rendered) active connection to remote host is
+ not required.
+ - The state I(gathered) will fetch the running configuration from device and transform
+ it into structured data in the format as per the resource module argspec and
+ the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result. The value of C(running_config)
+ option should be the same format as the output of command
+ I(show running-config | section ^interface) executed on device. For state I(parsed) active
+ connection to remote host is not required.
+ type: str
+"""
+
+EXAMPLES = """
+# Using merged
+
+# Before state:
+# -------------
+#
+# Router#show running-config | section ^interface
+# interface Loopback999
+# no ip address
+# shutdown
+# interface GigabitEthernet1
+# description Management interface do not change
+# ip address dhcp
+# negotiation auto
+# interface GigabitEthernet2
+# ip address dhcp
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3
+# description Configured and Overridden by Ansible Network
+# no ip address
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+
+- name: Merge provided configuration with device configuration
+ cisco.ios.ios_l3_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ ipv4:
+ - address: 192.168.0.1/24
+ secondary: true
+ - name: GigabitEthernet2
+ ipv4:
+ - address: 192.168.0.2/24
+ - name: GigabitEthernet3
+ ipv6:
+ - address: fd5d:12c9:2201:1::1/64
+ - name: GigabitEthernet3.100
+ ipv4:
+ - address: 192.168.0.3/24
+ state: merged
+
+# Task Output
+# -----------
+#
+# before:
+# - ipv4:
+# - dhcp:
+# enable: true
+# name: GigabitEthernet1
+# - ipv4:
+# - dhcp:
+# enable: true
+# name: GigabitEthernet2
+# - name: GigabitEthernet3
+# - name: GigabitEthernet4
+# - name: Loopback999
+# commands:
+# - interface GigabitEthernet2
+# - ip address 192.168.0.2 255.255.255.0
+# - interface GigabitEthernet3
+# - ipv6 address fd5d:12c9:2201:1::1/64
+# - interface GigabitEthernet3.100
+# - ip address 192.168.0.3 255.255.255.0
+# after:
+# - ipv4:
+# - dhcp:
+# enable: true
+# name: GigabitEthernet1
+# - ipv4:
+# - address: 192.168.0.2/24
+# name: GigabitEthernet2
+# - ipv6:
+# - address: FD5D:12C9:2201:1::1/64
+# name: GigabitEthernet3
+# - name: GigabitEthernet3.100
+# ipv4:
+# - address: 192.168.0.3/24
+# - name: GigabitEthernet4
+# - name: Loopback999
+
+# After state:
+# ------------
+#
+# Router#show running-config | section ^interface
+# interface Loopback999
+# no ip address
+# shutdown
+# interface GigabitEthernet1
+# description Management interface do not change
+# ip address dhcp
+# negotiation auto
+# interface GigabitEthernet2
+# ip address 192.168.0.2 255.255.255.0
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3
+# description Configured and Overridden by Ansible Network
+# no ip address
+# shutdown
+# speed 1000
+# no negotiation auto
+# ipv6 address FD5D:12C9:2201:1::1/64
+# interface GigabitEthernet3.100
+# ip address 192.168.0.3 255.255.255.0
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+
+# Using replaced
+
+# Before state:
+# -------------
+#
+# Router#show running-config | section ^interface
+# interface Loopback999
+# no ip address
+# shutdown
+# interface GigabitEthernet1
+# description Management interface do not change
+# ip address dhcp
+# negotiation auto
+# interface GigabitEthernet2
+# ip address 192.168.0.2 255.255.255.0
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3
+# description Configured and Overridden by Ansible Network
+# no ip address
+# shutdown
+# speed 1000
+# no negotiation auto
+# ipv6 address FD5D:12C9:2201:1::1/64
+# interface GigabitEthernet3.100
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+
+- name: Replaces device configuration of listed interfaces with provided configuration
+ cisco.ios.ios_l3_interfaces:
+ config:
+ - name: GigabitEthernet2
+ ipv4:
+ - address: 192.168.2.0/24
+ - name: GigabitEthernet3
+ ipv4:
+ - dhcp:
+ client_id: GigabitEthernet2
+ hostname: test.com
+ state: replaced
+
+# Task Output
+# -----------
+#
+# before:
+# - ipv4:
+# - dhcp:
+# enable: true
+# name: GigabitEthernet1
+# - ipv4:
+# - address: 192.168.0.2/24
+# name: GigabitEthernet2
+# - ipv6:
+# - address: FD5D:12C9:2201:1::1/64
+# name: GigabitEthernet3
+# - name: GigabitEthernet3.100
+# - name: GigabitEthernet4
+# - name: Loopback999
+# commands:
+# - interface GigabitEthernet2
+# - ip address 192.168.0.3 255.255.255.0
+# - no ip address 192.168.0.2 255.255.255.0
+# - interface GigabitEthernet3
+# - ip address dhcp client-id GigabitEthernet2 hostname test.com
+# - no ipv6 address fd5d:12c9:2201:1::1/64
+# after:
+# - ipv4:
+# - dhcp:
+# enable: true
+# name: GigabitEthernet1
+# - ipv4:
+# - address: 192.168.0.3/24
+# name: GigabitEthernet2
+# - ipv4:
+# - dhcp:
+# client_id: GigabitEthernet2
+# enable: true
+# hostname: test.com
+# name: GigabitEthernet3
+# - name: GigabitEthernet3.100
+# - name: GigabitEthernet4
+# - name: Loopback999
+
+# After state:
+# ------------
+#
+# router-ios#show running-config | section ^interface
+# interface Loopback999
+# no ip address
+# shutdown
+# interface GigabitEthernet1
+# description Management interface do not change
+# ip address dhcp
+# negotiation auto
+# interface GigabitEthernet2
+# ip address 192.168.0.3 255.255.255.0
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3
+# description Configured and Overridden by Ansible Network
+# ip address dhcp client-id GigabitEthernet2 hostname test.com
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3.100
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+
+# Using overridden
+
+# Before state:
+# -------------
+#
+# router-ios#show running-config | section ^interface
+# interface Loopback999
+# no ip address
+# shutdown
+# interface GigabitEthernet1
+# description Management interface do not change
+# ip address dhcp
+# negotiation auto
+# interface GigabitEthernet2
+# ip address 192.168.0.3 255.255.255.0
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3
+# description Configured and Overridden by Ansible Network
+# ip address dhcp client-id GigabitEthernet2 hostname test.com
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3.100
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+
+- name: Override device configuration of all interfaces with provided configuration
+ cisco.ios.ios_l3_interfaces:
+ config:
+ - ipv4:
+ - dhcp:
+ enable: true
+ name: GigabitEthernet1
+ - name: GigabitEthernet2
+ ipv4:
+ - address: 192.168.0.1/24
+ - name: GigabitEthernet3
+ state: overridden
+
+# Task Output
+# -----------
+# before:
+# - ipv4:
+# - dhcp:
+# enable: true
+# name: GigabitEthernet1
+# - ipv4:
+# - address: 192.168.0.3/24
+# name: GigabitEthernet2
+# - ipv4:
+# - dhcp:
+# client_id: GigabitEthernet2
+# enable: true
+# hostname: test.com
+# name: GigabitEthernet3
+# - name: GigabitEthernet3.100
+# - name: GigabitEthernet4
+# - name: Loopback999
+# commands:
+# - interface GigabitEthernet2
+# - ip address 192.168.0.1 255.255.255.0
+# - no ip address 192.168.0.3 255.255.255.0
+# - interface GigabitEthernet3
+# - no ip address dhcp client-id GigabitEthernet2 hostname test.com
+# after:
+# - ipv4:
+# - dhcp:
+# enable: true
+# name: GigabitEthernet1
+# - ipv4:
+# - address: 192.168.0.1/24
+# name: GigabitEthernet2
+# - name: GigabitEthernet3
+# - name: GigabitEthernet3.100
+# - name: GigabitEthernet4
+# - name: Loopback999
+
+# After state:
+# ------------
+#
+# router-ios#show running-config | section ^interface
+# interface Loopback999
+# no ip address
+# shutdown
+# interface GigabitEthernet1
+# description Management interface do not change
+# ip address dhcp
+# negotiation auto
+# interface GigabitEthernet2
+# ip address 192.168.0.1 255.255.255.0
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3
+# description Configured and Overridden by Ansible Network
+# no ip address
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3.100
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+
+# Using deleted
+
+# Before state:
+# -------------
+#
+# router-ios#show running-config | section ^interface
+# interface Loopback999
+# no ip address
+# shutdown
+# interface GigabitEthernet1
+# description Management interface do not change
+# ip address dhcp
+# negotiation auto
+# interface GigabitEthernet2
+# ip address 192.168.0.1 255.255.255.0
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3
+# description Configured and Overridden by Ansible Network
+# no ip address
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3.100
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+
+- name: "Delete attributes of given interfaces (NOTE: This won't delete the interfaces)"
+ cisco.ios.ios_l3_interfaces:
+ config:
+ - name: GigabitEthernet2
+ - name: GigabitEthernet3.100
+ state: deleted
+
+# Task Output
+# -----------
+#
+# before:
+# - ipv4:
+# - dhcp:
+# enable: true
+# name: GigabitEthernet1
+# - ipv4:
+# - address: 192.168.0.1/24
+# name: GigabitEthernet2
+# - name: GigabitEthernet3
+# - name: GigabitEthernet3.100
+# - name: GigabitEthernet4
+# - name: Loopback999
+# commands:
+# - interface GigabitEthernet2
+# - no ip address 192.168.0.1 255.255.255.0
+# after:
+# - ipv4:
+# - dhcp:
+# enable: true
+# name: GigabitEthernet1
+# - name: GigabitEthernet2
+# - name: GigabitEthernet3
+# - name: GigabitEthernet3.100
+# - name: GigabitEthernet4
+# - name: Loopback999
+
+# After state:
+# -------------
+#
+# router-ios#show running-config | section ^interface
+# interface Loopback999
+# no ip address
+# shutdown
+# interface GigabitEthernet1
+# description Management interface do not change
+# ip address dhcp
+# negotiation auto
+# interface GigabitEthernet2
+# no ip address
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3
+# description Configured and Overridden by Ansible Network
+# no ip address
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3.100
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+
+# Using deleted without config passed, only interface's configuration will be negated
+
+# Before state:
+# -------------
+
+# router-ios#show running-config | section ^interface
+# interface Loopback999
+# no ip address
+# shutdown
+# interface GigabitEthernet1
+# description Management interface do not change
+# ip address dhcp
+# negotiation auto
+# interface GigabitEthernet2
+# ip address 192.168.0.2 255.255.255.0
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3
+# description Configured and Overridden by Ansible Network
+# no ip address
+# shutdown
+# speed 1000
+# no negotiation auto
+# ipv6 address FD5D:12C9:2201:1::1/64
+# interface GigabitEthernet3.100
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+
+- name: "Delete L3 config of all interfaces"
+ cisco.ios.ios_l3_interfaces:
+ state: deleted
+
+# Task Output
+# -----------
+#
+# before:
+# - ipv4:
+# - dhcp:
+# enable: true
+# name: GigabitEthernet1
+# - ipv4:
+# - address: 192.168.0.2/24
+# name: GigabitEthernet2
+# - ipv6:
+# - address: FD5D:12C9:2201:1::1/64
+# name: GigabitEthernet3
+# - name: GigabitEthernet3.100
+# - name: GigabitEthernet4
+# - name: Loopback999
+# commands:
+# - interface GigabitEthernet1
+# - no ip address dhcp
+# - interface GigabitEthernet2
+# - no ip address 192.168.0.2 255.255.255.0
+# - interface GigabitEthernet3
+# - no ipv6 address fd5d:12c9:2201:1::1/64
+# after:
+# - name: GigabitEthernet1
+# - name: GigabitEthernet2
+# - name: GigabitEthernet3
+# - name: GigabitEthernet3.100
+# - name: GigabitEthernet4
+# - name: Loopback999
+
+# After state:
+# -------------
+#
+# interface Loopback999
+# no ip address
+# shutdown
+# interface GigabitEthernet1
+# description Management interface do not change
+# negotiation auto
+# interface GigabitEthernet2
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3
+# description Configured and Overridden by Ansible Network
+# no ip address
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3.100
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+
+# Using gathered
+
+# Before state:
+# -------------
+#
+# Router#show running-config | section ^interface
+# interface Loopback999
+# no ip address
+# shutdown
+# interface GigabitEthernet1
+# description Management interface do not change
+# ip address dhcp
+# negotiation auto
+# interface GigabitEthernet2
+# ip address 192.168.0.3 255.255.255.0
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3
+# description Configured and Overridden by Ansible Network
+# ip address dhcp client-id GigabitEthernet2 hostname test.com
+# shutdown
+# speed 1000
+# no negotiation auto
+# interface GigabitEthernet3.100
+# interface GigabitEthernet4
+# no ip address
+# shutdown
+# negotiation auto
+
+- name: Gather facts for l3 interfaces
+ cisco.ios.ios_l3_interfaces:
+ state: gathered
+
+# Task Output
+# -----------
+#
+# gathered:
+# - ipv4:
+# - dhcp:
+# enable: true
+# name: GigabitEthernet1
+# - ipv4:
+# - address: 192.168.0.3/24
+# name: GigabitEthernet2
+# - ipv4:
+# - dhcp:
+# client_id: GigabitEthernet2
+# enable: true
+# hostname: test.com
+# name: GigabitEthernet3
+# - name: GigabitEthernet3.100
+# - name: GigabitEthernet4
+# - name: Loopback999
+
+# Using rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_l3_interfaces:
+ config:
+ - name: GigabitEthernet1
+ ipv4:
+ - dhcp:
+ client_id: GigabitEthernet0/0
+ hostname: test.com
+ - name: GigabitEthernet2
+ ipv4:
+ - address: 198.51.100.1/24
+ secondary: true
+ - address: 198.51.100.2/24
+ ipv6:
+ - address: 2001:db8:0:3::/64
+ state: rendered
+
+# Task Output
+# -----------
+#
+# rendered:
+# - interface GigabitEthernet1
+# - ip address dhcp client-id GigabitEthernet0/0 hostname test.com
+# - interface GigabitEthernet2
+# - ip address 198.51.100.1 255.255.255.0 secondary
+# - ip address 198.51.100.2 255.255.255.0
+# - ipv6 address 2001:db8:0:3::/64
+
+# Using parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# interface GigabitEthernet0/1
+# ip address dhcp client-id GigabitEthernet 0/0 hostname test.com
+# interface GigabitEthernet0/2
+# ip address 198.51.100.1 255.255.255.0
+# ip address 198.51.100.2 255.255.255.0 secondary
+# ipv6 address 2001:db8:0:3::/64
+
+- name: Parse the provided configuration
+ cisco.ios.ios_l3_interfaces:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Task Output
+# -----------
+#
+# parsed:
+# - ipv4:
+# - dhcp:
+# client_id: GigabitEthernet0/0
+# hostname: test.com
+# name: GigabitEthernet0/1
+# - ipv4:
+# - address: 198.51.100.1/24
+# secondary: true
+# - address: 198.51.100.2/24
+# ipv6:
+# - address: 2001:db8:0:3::/64
+# name: GigabitEthernet0/2
+
+"""
+
+RETURN = """
+before:
+ description: The configuration prior to the module execution.
+ returned: when state is I(merged), I(replaced), I(overridden), I(deleted) or I(purged)
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+after:
+ description: The resulting configuration after module execution.
+ returned: when changed
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: when state is I(merged), I(replaced), I(overridden), I(deleted) or I(purged)
+ type: list
+ sample:
+ - "ip address 192.168.0.3 255.255.255.0"
+ - "ipv6 address dhcp rapid-commit"
+ - "ipv6 address fd5d:12c9:2201:1::1/64 anycast"
+rendered:
+ description: The provided configuration in the task rendered in device-native format (offline).
+ returned: when state is I(rendered)
+ type: list
+ sample:
+ - "ipv6 address FD5D:12C9:2201:1::1/64"
+ - "ip address 192.168.0.3 255.255.255.0"
+ - "ip address autoconfig"
+gathered:
+ description: Facts about the network resource gathered from the remote device as structured data.
+ returned: when state is I(gathered)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+parsed:
+ description: The device native config provided in I(running_config) option parsed into structured data as per module argspec.
+ returned: when state is I(parsed)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.l3_interfaces.l3_interfaces import (
+ L3_interfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.l3_interfaces.l3_interfaces import (
+ L3_interfaces,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ module = AnsibleModule(
+ argument_spec=L3_interfacesArgs.argument_spec,
+ mutually_exclusive=[["config", "running_config"]],
+ required_if=[
+ ["state", "merged", ["config"]],
+ ["state", "replaced", ["config"]],
+ ["state", "overridden", ["config"]],
+ ["state", "rendered", ["config"]],
+ ["state", "parsed", ["running_config"]],
+ ],
+ supports_check_mode=True,
+ )
+
+ result = L3_interfaces(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_lacp.py b/ansible_collections/cisco/ios/plugins/modules/ios_lacp.py
new file mode 100644
index 000000000..705b0fced
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_lacp.py
@@ -0,0 +1,275 @@
+#!/usr/bin/python
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+"""
+The module file for ios_lacp
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+module: ios_lacp
+short_description: Resource module to configure LACP.
+description:
+ This module provides declarative management of Global LACP on Cisco IOS
+ network devices.
+version_added: 1.0.0
+author: Sumit Jaiswal (@justjais)
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ config:
+ description: The provided configurations.
+ type: dict
+ suboptions:
+ system:
+ description: This option sets the default system parameters for LACP.
+ type: dict
+ suboptions:
+ priority:
+ description:
+ - LACP priority for the system.
+ - Refer to vendor documentation for valid values.
+ type: int
+ required: true
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device by
+ executing the command B(show lacp sys-id).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ description:
+ - The state the configuration should be left in
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device.
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result. For state I(rendered) active connection to remote host is
+ not required.
+ - The state I(gathered) will fetch the running configuration from device and transform
+ it into structured data in the format as per the resource module argspec and
+ the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result. The value of C(running_config)
+ option should be the same format as the output of command I(show running-config
+ | include ip route|ipv6 route) executed on device. For state I(parsed) active
+ connection to remote host is not required.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - deleted
+ - rendered
+ - parsed
+ - gathered
+ default: merged
+"""
+
+EXAMPLES = """
+# Using merged
+#
+# Before state:
+# -------------
+#
+# vios#show lacp sys-id
+# 32768, 5e00.0000.8000
+
+- name: Merge provided configuration with device configuration
+ cisco.ios.ios_lacp:
+ config:
+ system:
+ priority: 123
+ state: merged
+
+# After state:
+# ------------
+#
+# vios#show lacp sys-id
+# 123, 5e00.0000.8000
+
+# Using replaced
+#
+# Before state:
+# -------------
+#
+# vios#show lacp sys-id
+# 500, 5e00.0000.8000
+
+- name: Replaces Global LACP configuration
+ cisco.ios.ios_lacp:
+ config:
+ system:
+ priority: 123
+ state: replaced
+
+# After state:
+# ------------
+#
+# vios#show lacp sys-id
+# 123, 5e00.0000.8000
+
+# Using Deleted
+#
+# Before state:
+# -------------
+#
+# vios#show lacp sys-id
+# 500, 5e00.0000.8000
+
+- name: Delete Global LACP attribute
+ cisco.ios.ios_lacp:
+ state: deleted
+
+# After state:
+# -------------
+#
+# vios#show lacp sys-id
+# 32768, 5e00.0000.8000
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# vios#show lacp sys-id
+# 123, 5e00.0000.8000
+
+- name: Gather listed LACP with provided configurations
+ cisco.ios.ios_lacp:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": {
+# "system": {
+# "priority": 500
+# }
+# }
+
+# After state:
+# ------------
+#
+# vios#show lacp sys-id
+# 123, 5e00.0000.8000
+
+# Using Rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_lacp:
+ config:
+ system:
+ priority: 123
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "lacp system-priority 10"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# lacp system-priority 123
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_lacp:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": {
+# "system": {
+# "priority": 123
+# }
+# }
+"""
+
+RETURN = """
+before:
+ description: The configuration as structured data prior to module invocation.
+ returned: always
+ type: list
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+after:
+ description: The configuration as structured data after module completion.
+ returned: when changed
+ type: list
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: always
+ type: list
+ sample: ['lacp system-priority 10']
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.lacp.lacp import (
+ LacpArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.lacp.lacp import Lacp
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ required_if = [
+ ("state", "merged", ("config",)),
+ ("state", "replaced", ("config",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+
+ mutually_exclusive = [("config", "running_config")]
+
+ module = AnsibleModule(
+ argument_spec=LacpArgs.argument_spec,
+ required_if=required_if,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+ result = Lacp(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_lacp_interfaces.py b/ansible_collections/cisco/ios/plugins/modules/ios_lacp_interfaces.py
new file mode 100644
index 000000000..fe8e92bcc
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_lacp_interfaces.py
@@ -0,0 +1,514 @@
+#!/usr/bin/python
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+"""
+The module file for ios_lacp_interfaces
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+module: ios_lacp_interfaces
+short_description: Resource module to configure LACP interfaces.
+description:
+ This module provides declarative management of LACP on Cisco IOS network
+ devices lacp_interfaces.
+version_added: 1.0.0
+author: Sumit Jaiswal (@justjais)
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ config:
+ description: A dictionary of LACP lacp_interfaces option
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Name of the Interface for configuring LACP.
+ type: str
+ required: true
+ port_priority:
+ description:
+ - LACP priority on this interface.
+ - Refer to vendor documentation for valid port values.
+ type: int
+ fast_switchover:
+ description:
+ - LACP fast switchover supported on this port channel.
+ type: bool
+ max_bundle:
+ description:
+ - LACP maximum number of ports to bundle in this port channel.
+ - Refer to vendor documentation for valid port values.
+ type: int
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device by
+ executing the command B(show running-config | section ^interface).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ description:
+ - The state the configuration should be left in
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device.
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result. For state I(rendered) active connection to remote host is
+ not required.
+ - The state I(gathered) will fetch the running configuration from device and transform
+ it into structured data in the format as per the resource module argspec and
+ the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result. The value of C(running_config)
+ option should be the same format as the output of command I(show running-config
+ | include ip route|ipv6 route) executed on device. For state I(parsed) active
+ connection to remote host is not required.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - rendered
+ - gathered
+ - parsed
+ default: merged
+"""
+
+EXAMPLES = """
+# Using merged
+#
+# Before state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Port-channel10
+# interface Port-channel20
+# interface Port-channel30
+# interface GigabitEthernet0/1
+# shutdown
+# interface GigabitEthernet0/2
+# shutdown
+# interface GigabitEthernet0/3
+# shutdown
+
+- name: Merge provided configuration with device configuration
+ cisco.ios.ios_lacp_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ port_priority: 10
+ - name: GigabitEthernet0/2
+ port_priority: 20
+ - name: GigabitEthernet0/3
+ port_priority: 30
+ - name: Port-channel10
+ fast_switchover: true
+ max_bundle: 5
+ state: merged
+
+# After state:
+# ------------
+#
+# vios#show running-config | section ^interface
+# interface Port-channel10
+# lacp fast-switchover
+# lacp max-bundle 5
+# interface Port-channel20
+# interface Port-channel30
+# interface GigabitEthernet0/1
+# shutdown
+# lacp port-priority 10
+# interface GigabitEthernet0/2
+# shutdown
+# lacp port-priority 20
+# interface GigabitEthernet0/3
+# shutdown
+# lacp port-priority 30
+
+# Using overridden
+#
+# Before state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Port-channel10
+# lacp fast-switchover
+# interface Port-channel20
+# interface Port-channel30
+# interface GigabitEthernet0/1
+# shutdown
+# lacp port-priority 10
+# interface GigabitEthernet0/2
+# shutdown
+# lacp port-priority 20
+# interface GigabitEthernet0/3
+# shutdown
+# lacp port-priority 30
+
+- name: Override device configuration of all lacp_interfaces with provided configuration
+ cisco.ios.ios_lacp_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ port_priority: 20
+ - name: Port-channel10
+ max_bundle: 2
+ state: overridden
+
+# After state:
+# ------------
+#
+# vios#show running-config | section ^interface
+# interface Port-channel10
+# lacp max-bundle 2
+# interface Port-channel20
+# interface Port-channel30
+# interface GigabitEthernet0/1
+# shutdown
+# lacp port-priority 20
+# interface GigabitEthernet0/2
+# shutdown
+# interface GigabitEthernet0/3
+# shutdown
+
+# Using replaced
+#
+# Before state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Port-channel10
+# lacp max-bundle 5
+# interface Port-channel20
+# interface Port-channel30
+# interface GigabitEthernet0/1
+# shutdown
+# lacp port-priority 10
+# interface GigabitEthernet0/2
+# shutdown
+# lacp port-priority 20
+# interface GigabitEthernet0/3
+# shutdown
+# lacp port-priority 30
+
+- name: Replaces device configuration of listed lacp_interfaces with provided configuration
+ cisco.ios.ios_lacp_interfaces:
+ config:
+ - name: GigabitEthernet0/3
+ port_priority: 40
+ - name: Port-channel10
+ fast_switchover: true
+ max_bundle: 2
+ state: replaced
+
+# After state:
+# ------------
+#
+# vios#show running-config | section ^interface
+# interface Port-channel10
+# lacp fast-switchover
+# lacp max-bundle 2
+# interface Port-channel20
+# interface Port-channel30
+# interface GigabitEthernet0/1
+# shutdown
+# lacp port-priority 10
+# interface GigabitEthernet0/2
+# shutdown
+# lacp port-priority 20
+# interface GigabitEthernet0/3
+# shutdown
+# lacp port-priority 40
+
+# Using Deleted
+#
+# Before state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Port-channel10
+# flowcontrol receive on
+# interface Port-channel20
+# interface Port-channel30
+# interface GigabitEthernet0/1
+# shutdown
+# lacp port-priority 10
+# interface GigabitEthernet0/2
+# shutdown
+# lacp port-priority 20
+# interface GigabitEthernet0/3
+# shutdown
+# lacp port-priority 30
+
+- name: "Delete LACP attributes of given interfaces (Note: This won't delete the interface itself)"
+ cisco.ios.ios_lacp_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ state: deleted
+
+# After state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Port-channel10
+# interface Port-channel20
+# interface Port-channel30
+# interface GigabitEthernet0/1
+# shutdown
+# interface GigabitEthernet0/2
+# shutdown
+# lacp port-priority 20
+# interface GigabitEthernet0/3
+# shutdown
+# lacp port-priority 30
+
+# Using Deleted without any config passed
+# "(NOTE: This will delete all of configured LLDP module attributes)"
+#
+# Before state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Port-channel10
+# lacp fast-switchover
+# interface Port-channel20
+# lacp max-bundle 2
+# interface Port-channel30
+# interface GigabitEthernet0/1
+# shutdown
+# lacp port-priority 10
+# interface GigabitEthernet0/2
+# shutdown
+# lacp port-priority 20
+# interface GigabitEthernet0/3
+# shutdown
+# lacp port-priority 30
+
+- name: "Delete LACP attributes for all configured interfaces (Note: This won't delete the interface itself)"
+ cisco.ios.ios_lacp_interfaces:
+ state: deleted
+
+# After state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Port-channel10
+# interface Port-channel20
+# interface Port-channel30
+# interface GigabitEthernet0/1
+# shutdown
+# interface GigabitEthernet0/2
+# shutdown
+# interface GigabitEthernet0/3
+# shutdown
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^interface
+# interface Port-channel10
+# lacp fast-switchover
+# lacp max-bundle 2
+# interface Port-channel40
+# lacp max-bundle 5
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# lacp port-priority 30
+# interface GigabitEthernet0/2
+# lacp port-priority 20
+
+- name: Gather listed LACP interfaces with provided configurations
+ cisco.ios.ios_lacp_interfaces:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": [
+# {
+# "fast_switchover": true,
+# "max_bundle": 2,
+# "name": "Port-channel10"
+# },
+# {
+# "max_bundle": 5,
+# "name": "Port-channel40"
+# },
+# {
+# "name": "GigabitEthernet0/0"
+# },
+# {
+# "name": "GigabitEthernet0/1",
+# "port_priority": 30
+# },
+# {
+# "name": "GigabitEthernet0/2",
+# "port_priority": 20
+# }
+# ]
+
+# After state:
+# ------------
+#
+# vios#sh running-config | section ^interface
+# interface Port-channel10
+# lacp fast-switchover
+# lacp max-bundle 2
+# interface Port-channel40
+# lacp max-bundle 5
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# lacp port-priority 30
+# interface GigabitEthernet0/2
+# lacp port-priority 20
+
+# Using Rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_lacp_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ port_priority: 10
+ - name: GigabitEthernet0/2
+ port_priority: 20
+ - name: Port-channel10
+ fast_switchover: true
+ max_bundle: 2
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "interface GigabitEthernet0/1",
+# "lacp port-priority 10",
+# "interface GigabitEthernet0/2",
+# "lacp port-priority 20",
+# "interface Port-channel10",
+# "lacp max-bundle 2",
+# "lacp fast-switchover"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# interface GigabitEthernet0/1
+# lacp port-priority 10
+# interface GigabitEthernet0/2
+# lacp port-priority 20
+# interface Port-channel10
+# lacp max-bundle 2 fast-switchover
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_lacp_interfaces:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": [
+# {
+# "name": "GigabitEthernet0/1",
+# "port_priority": 10
+# },
+# {
+# "name": "GigabitEthernet0/2",
+# "port_priority": 20
+# },
+# {
+# "fast_switchover": true,
+# "max_bundle": 2,
+# "name": "Port-channel10"
+# }
+# ]
+
+"""
+
+RETURN = """
+before:
+ description: The configuration as structured data prior to module invocation.
+ returned: always
+ type: list
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+after:
+ description: The configuration as structured data after module completion.
+ returned: when changed
+ type: list
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: always
+ type: list
+ sample: ['interface GigabitEthernet 0/1', 'lacp port-priority 30']
+"""
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.lacp_interfaces.lacp_interfaces import (
+ Lacp_InterfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.lacp_interfaces.lacp_interfaces import (
+ Lacp_Interfaces,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ required_if = [
+ ("state", "merged", ("config",)),
+ ("state", "replaced", ("config",)),
+ ("state", "overridden", ("config",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ mutually_exclusive = [("config", "running_config")]
+
+ module = AnsibleModule(
+ argument_spec=Lacp_InterfacesArgs.argument_spec,
+ required_if=required_if,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+ result = Lacp_Interfaces(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_lag_interfaces.py b/ansible_collections/cisco/ios/plugins/modules/ios_lag_interfaces.py
new file mode 100644
index 000000000..64a43f700
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_lag_interfaces.py
@@ -0,0 +1,647 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2022 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+"""
+The module file for ios_lag_interfaces
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_lag_interfaces
+short_description: Resource module to configure LAG interfaces.
+description:
+ This module manages properties of Link Aggregation Group on Cisco IOS
+ devices.
+version_added: 1.0.0
+author:
+ - Sagar Paul (@KB-perByte)
+ - Sumit Jaiswal (@justjais)
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ config:
+ description: A list of link aggregation group configurations.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - ID of Ethernet Channel of interfaces.
+ - Refer to vendor documentation for valid port values.
+ type: str
+ required: true
+ members:
+ description:
+ - Interface options for the link aggregation group.
+ type: list
+ elements: dict
+ suboptions:
+ member:
+ description:
+ - Interface member of the link aggregation group.
+ type: str
+ mode:
+ description:
+ - Etherchannel Mode of the interface for link aggregation.
+ - On mode has to be quoted as 'on' or else pyyaml will convert
+ to True before it gets to Ansible.
+ type: str
+ choices:
+ - auto
+ - "on"
+ - desirable
+ - active
+ - passive
+ link:
+ description:
+ - Assign a link identifier used for load-balancing.
+ - Refer to vendor documentation for valid values.
+ - NOTE, parameter only supported on Cisco IOS XE platform.
+ type: int
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device
+ by executing the command B(show running-config | section ^interface).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ description:
+ - The state the configuration should be left in
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device.
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result. For state I(rendered) active connection to remote host is
+ not required.
+ - The state I(gathered) will fetch the running configuration from device and transform
+ it into structured data in the format as per the resource module argspec and
+ the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result. The value of C(running_config)
+ option should be the same format as the output of command I(show running-config
+ | include ip route|ipv6 route) executed on device. For state I(parsed) active
+ connection to remote host is not required.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - rendered
+ - parsed
+ - gathered
+ default: merged
+"""
+
+EXAMPLES = """
+# Using merged
+#
+# Before state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Port-channel10
+# interface GigabitEthernet0/1
+# shutdown
+# interface GigabitEthernet0/2
+# shutdown
+# interface GigabitEthernet0/3
+# shutdown
+# interface GigabitEthernet0/4
+# shutdown
+
+- name: Merge provided configuration with device configuration
+ cisco.ios.ios_lag_interfaces:
+ config:
+ - name: Port-channel10
+ members:
+ - member: GigabitEthernet0/1
+ mode: auto
+ - member: GigabitEthernet0/2
+ mode: auto
+ - name: Port-channel20
+ members:
+ - member: GigabitEthernet0/3
+ mode: on
+ - name: Port-channel30
+ members:
+ - member: GigabitEthernet0/4
+ mode: active
+ state: merged
+
+# Task Output:
+# ---------------
+
+# commands:
+# - interface GigabitEthernet0/1
+# - channel-group 10 mode auto
+# - interface GigabitEthernet0/2
+# - channel-group 10 mode auto
+# - interface GigabitEthernet0/3
+# - channel-group 20 mode on
+# - interface GigabitEthernet0/4
+# - channel-group 30 mode active
+
+# After state:
+# ------------
+#
+# vios#show running-config | section ^interface
+# interface Port-channel10
+# interface Port-channel20
+# interface Port-channel30
+# interface GigabitEthernet0/1
+# shutdown
+# channel-group 10 mode auto
+# interface GigabitEthernet0/2
+# shutdown
+# channel-group 10 mode auto
+# interface GigabitEthernet0/3
+# shutdown
+# channel-group 20 mode on
+# interface GigabitEthernet0/4
+# shutdown
+# channel-group 30 mode active
+
+# Using overridden
+#
+# Before state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Port-channel10
+# interface Port-channel20
+# interface Port-channel30
+# interface GigabitEthernet0/1
+# shutdown
+# channel-group 10 mode auto
+# interface GigabitEthernet0/2
+# shutdown
+# channel-group 10 mode auto
+# interface GigabitEthernet0/3
+# shutdown
+# channel-group 20 mode on
+# interface GigabitEthernet0/4
+# shutdown
+# channel-group 30 mode active
+
+- name: Override device configuration of all interfaces with provided configuration
+ cisco.ios.ios_lag_interfaces:
+ config:
+ - name: Port-channel20
+ members:
+ - member: GigabitEthernet0/2
+ mode: auto
+ - member: GigabitEthernet0/3
+ mode: auto
+ state: overridden
+
+# Task Output:
+# ---------------
+
+# commands:
+# - interface GigabitEthernet0/1
+# - no channel-group 10 mode auto
+# - interface GigabitEthernet0/2
+# - no channel-group 10 mode auto
+# - interface GigabitEthernet0/4
+# - no channel-group 30 mode active
+# - interface GigabitEthernet0/2
+# - channel-group 20 mode auto
+# - interface GigabitEthernet0/3
+# - channel-group 20 mode auto
+
+# After state:
+# ------------
+#
+# vios#show running-config | section ^interface
+# interface Port-channel10
+# interface Port-channel20
+# interface Port-channel30
+# interface GigabitEthernet0/1
+# shutdown
+# interface GigabitEthernet0/2
+# shutdown
+# channel-group 20 mode auto
+# interface GigabitEthernet0/3
+# shutdown
+# channel-group 20 mode auto
+# interface GigabitEthernet0/4
+# shutdown
+
+# Using replaced
+#
+# Before state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Port-channel10
+# interface Port-channel20
+# interface Port-channel30
+# interface GigabitEthernet0/1
+# shutdown
+# channel-group 10 mode auto
+# interface GigabitEthernet0/2
+# shutdown
+# channel-group 10 mode auto
+# interface GigabitEthernet0/3
+# shutdown
+# channel-group 20 mode on
+# interface GigabitEthernet0/4
+# shutdown
+# channel-group 30 mode active
+
+- name: Replaces device configuration of listed interfaces with provided configuration
+ cisco.ios.ios_lag_interfaces:
+ config:
+ - name: Port-channel30
+ members:
+ - member: GigabitEthernet0/3
+ mode: auto
+ state: replaced
+
+# Task Output:
+# ---------------
+
+# commands:
+# - interface GigabitEthernet0/3
+# - channel-group 30 mode auto
+# - interface GigabitEthernet0/4
+# - no channel-group 30 mode active
+
+# After state:
+# ------------
+#
+# vios#show running-config | section ^interface
+# interface Port-channel10
+# interface Port-channel20
+# interface Port-channel30
+# interface GigabitEthernet0/1
+# shutdown
+# channel-group 10 mode auto
+# interface GigabitEthernet0/2
+# shutdown
+# channel-group 10 mode auto
+# interface GigabitEthernet0/3
+# shutdown
+# channel-group 30 mode auto
+# interface GigabitEthernet0/4
+# shutdown
+
+# Using Deleted
+#
+# Before state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Port-channel10
+# interface Port-channel20
+# interface Port-channel30
+# interface GigabitEthernet0/1
+# shutdown
+# channel-group 10 mode auto
+# interface GigabitEthernet0/2
+# shutdown
+# channel-group 10 mode auto
+# interface GigabitEthernet0/3
+# shutdown
+# channel-group 20 mode on
+# interface GigabitEthernet0/4
+# shutdown
+# channel-group 30 mode active
+
+- name: "Delete LAG attributes of given interfaces (Note: This won't delete the interface itself)"
+ cisco.ios.ios_lag_interfaces:
+ config:
+ - name: Port-channel10
+ - name: Port-channel20
+ state: deleted
+
+# Task Output:
+# ---------------
+
+# commands:
+# - interface GigabitEthernet0/1
+# - no channel-group 10 mode auto
+# - interface GigabitEthernet0/2
+# - no channel-group 10 mode auto
+# - interface GigabitEthernet0/3
+# - no channel-group 20 mode on
+
+# After state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Port-channel10
+# interface Port-channel20
+# interface Port-channel30
+# interface GigabitEthernet0/1
+# shutdown
+# interface GigabitEthernet0/2
+# shutdown
+# interface GigabitEthernet0/3
+# shutdown
+# interface GigabitEthernet0/4
+# shutdown
+# channel-group 30 mode active
+
+# Using Deleted without any config passed
+#"(NOTE: This will delete all of configured LLDP module attributes)"
+
+#
+# Before state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Port-channel10
+# interface Port-channel20
+# interface Port-channel30
+# interface GigabitEthernet0/1
+# shutdown
+# channel-group 10 mode auto
+# interface GigabitEthernet0/2
+# shutdown
+# channel-group 10 mode auto
+# interface GigabitEthernet0/3
+# shutdown
+# channel-group 20 mode on
+# interface GigabitEthernet0/4
+# shutdown
+# channel-group 30 mode active
+
+- name: "Delete all configured LAG attributes for interfaces (Note: This won't delete the interface itself)"
+ cisco.ios.ios_lag_interfaces:
+ state: deleted
+
+# Task Output:
+# ---------------
+
+# commands:
+# - interface GigabitEthernet0/1
+# - no channel-group 10 mode auto
+# - interface GigabitEthernet0/2
+# - no channel-group 10 mode auto
+# - interface GigabitEthernet0/3
+# - no channel-group 20 mode on
+# - interface GigabitEthernet0/4
+# - no channel-group 30 mode active
+
+# After state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Port-channel10
+# interface Port-channel20
+# interface Port-channel30
+# interface GigabitEthernet0/1
+# shutdown
+# interface GigabitEthernet0/2
+# shutdown
+# interface GigabitEthernet0/3
+# shutdown
+# interface GigabitEthernet0/4
+# shutdown
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# vios#show running-config | section ^interface
+# interface Port-channel10
+# interface Port-channel20
+# interface Port-channel30
+# interface GigabitEthernet0/1
+# shutdown
+# channel-group 10 mode auto
+# interface GigabitEthernet0/2
+# shutdown
+# channel-group 10 mode auto
+# interface GigabitEthernet0/3
+# shutdown
+# channel-group 20 mode on
+# interface GigabitEthernet0/4
+# shutdown
+# channel-group 30 mode active
+
+- name: Gather listed LAG interfaces with provided configurations
+ cisco.ios.ios_lag_interfaces:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": [
+# {
+# "members": [
+# {
+# "member": "GigabitEthernet0/1",
+# "mode": "auto"
+# },
+# {
+# "member": "GigabitEthernet0/2",
+# "mode": "auto"
+# }
+# ],
+# "name": "Port-channel10"
+# },
+# {
+# "members": [
+# {
+# "member": "GigabitEthernet0/3",
+# "mode": "on"
+# }
+# ],
+# "name": "Port-channel20"
+# },
+# {
+# "members": [
+# {
+# "member": "GigabitEthernet0/4",
+# "mode": "active"
+# }
+# ],
+# "name": "Port-channel30"
+# }
+# ]
+
+# After state:
+# ------------
+#
+# vios#sh running-config | section ^interface
+# interface Port-channel10
+# interface Port-channel20
+# interface Port-channel30
+# interface GigabitEthernet0/1
+# shutdown
+# channel-group 10 mode auto
+# interface GigabitEthernet0/2
+# shutdown
+# channel-group 10 mode auto
+# interface GigabitEthernet0/3
+# shutdown
+# channel-group 20 mode on
+# interface GigabitEthernet0/4
+# shutdown
+# channel-group 30 mode active
+
+# Using Rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_lag_interfaces:
+ config:
+ - name: Port-channel11
+ members:
+ - member: GigabitEthernet0/1
+ mode: active
+ - name: Port-channel22
+ members:
+ - member: GigabitEthernet0/2
+ mode: passive
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "interface GigabitEthernet0/1",
+# "channel-group 11 mode active",
+# "interface GigabitEthernet0/2",
+# "channel-group 22 mode passive",
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# interface GigabitEthernet0/1
+# channel-group 11 mode active
+# interface GigabitEthernet0/2
+# channel-group 22 mode passive
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_lag_interfaces:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": [
+# {
+# "members": [
+# {
+# "member": "GigabitEthernet0/1",
+# "mode": "active"
+# }
+# ],
+# "name": "Port-channel11"
+# },
+# {
+# "members": [
+# {
+# "member": "GigabitEthernet0/2",
+# "mode": "passive"
+# }
+# ],
+# "name": "Port-channel22"
+# }
+# ]
+"""
+
+RETURN = """
+before:
+ description: The configuration prior to the module execution.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+after:
+ description: The resulting configuration after module execution.
+ returned: when changed
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: list
+ sample:
+ - interface GigabitEthernet0/1
+ - channel-group 10 mode auto
+ - channel-group 10 mode active link 20
+rendered:
+ description: The provided configuration in the task rendered in device-native format (offline).
+ returned: when I(state) is C(rendered)
+ type: list
+ sample:
+ - interface GigabitEthernet0/2
+ - channel-group 20 mode auto
+ - channel-group 20 mode active link 60
+gathered:
+ description: Facts about the network resource gathered from the remote device as structured data.
+ returned: when I(state) is C(gathered)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+parsed:
+ description: The device native config provided in I(running_config) option parsed into structured data as per module argspec.
+ returned: when I(state) is C(parsed)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.lag_interfaces.lag_interfaces import (
+ Lag_InterfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.lag_interfaces.lag_interfaces import (
+ Lag_interfaces,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ module = AnsibleModule(
+ argument_spec=Lag_InterfacesArgs.argument_spec,
+ mutually_exclusive=[["config", "running_config"]],
+ required_if=[
+ ["state", "merged", ["config"]],
+ ["state", "replaced", ["config"]],
+ ["state", "overridden", ["config"]],
+ ["state", "rendered", ["config"]],
+ ["state", "parsed", ["running_config"]],
+ ],
+ supports_check_mode=True,
+ )
+
+ result = Lag_interfaces(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_linkagg.py b/ansible_collections/cisco/ios/plugins/modules/ios_linkagg.py
new file mode 100644
index 000000000..cadc5551c
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_linkagg.py
@@ -0,0 +1,354 @@
+#!/usr/bin/python
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = r"""
+module: ios_linkagg
+author: Trishna Guha (@trishnaguha)
+short_description: Module to configure link aggregation groups.
+deprecated:
+ alternative: ios_lag_interfaces
+ why: Updated modules released with more functionality.
+ removed_at_date: "2024-06-01"
+description:
+ - This module provides declarative management of link aggregation groups on Cisco
+ IOS network devices.
+version_added: 1.0.0
+notes:
+ - Tested against IOS 15.2
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ group:
+ description:
+ - Channel-group number for the port-channel Link aggregation group. Range 1-255.
+ type: int
+ mode:
+ description:
+ - Mode of the link aggregation group.
+ - On mode has to be quoted as 'on' or else pyyaml will convert
+ to True before it gets to Ansible.
+ choices:
+ - active
+ - "on"
+ - passive
+ - auto
+ - desirable
+ type: str
+ members:
+ description:
+ - List of members of the link aggregation group.
+ type: list
+ elements: str
+ aggregate:
+ description: List of link aggregation definitions.
+ type: list
+ elements: dict
+ suboptions:
+ group:
+ description:
+ - Channel-group number for the port-channel Link aggregation group. Range 1-255.
+ type: str
+ required: true
+ mode:
+ description:
+ - Mode of the link aggregation group.
+ - On mode has to be quoted as 'on' or else pyyaml will convert
+ to True before it gets to Ansible.
+ choices:
+ - active
+ - "on"
+ - passive
+ - auto
+ - desirable
+ type: str
+ members:
+ description:
+ - List of members of the link aggregation group.
+ type: list
+ elements: str
+ state:
+ description:
+ - State of the link aggregation group.
+ choices:
+ - present
+ - absent
+ type: str
+ state:
+ description:
+ - State of the link aggregation group.
+ default: present
+ choices:
+ - present
+ - absent
+ type: str
+ purge:
+ description:
+ - Purge links not defined in the I(aggregate) parameter.
+ default: false
+ type: bool
+extends_documentation_fragment:
+ - cisco.ios.ios
+"""
+
+EXAMPLES = """
+- name: Create link aggregation group
+ cisco.ios.ios_linkagg:
+ group: 10
+ state: present
+
+- name: Delete link aggregation group
+ cisco.ios.ios_linkagg:
+ group: 10
+ state: absent
+
+- name: Set link aggregation group to members
+ cisco.ios.ios_linkagg:
+ group: 200
+ mode: active
+ members:
+ - GigabitEthernet0/0
+ - GigabitEthernet0/1
+
+- name: Remove link aggregation group from GigabitEthernet0/0
+ cisco.ios.ios_linkagg:
+ group: 200
+ mode: active
+ members:
+ - GigabitEthernet0/1
+
+- name: Create aggregate of linkagg definitions
+ cisco.ios.ios_linkagg:
+ aggregate:
+ - { group: 3, mode: on, members: [GigabitEthernet0/1] }
+ - { group: 100, mode: passive, members: [GigabitEthernet0/2] }
+
+"""
+
+RETURN = """
+commands:
+ description: The list of configuration mode commands to send to the device
+ returned: always, except for the platforms that use Netconf transport to manage the device.
+ type: list
+ sample:
+ - interface port-channel 30
+ - interface GigabitEthernet0/3
+ - channel-group 30 mode on
+ - no interface port-channel 30
+"""
+import re
+
+from copy import deepcopy
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import (
+ CustomNetworkConfig,
+)
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_default_spec,
+)
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ get_config,
+ load_config,
+)
+
+
+def search_obj_in_list(group, lst):
+ for o in lst:
+ if o["group"] == group:
+ return o
+
+
+def map_obj_to_commands(updates, module):
+ commands = list()
+ want, have = updates
+ purge = module.params["purge"]
+ for w in want:
+ group = w["group"]
+ mode = w["mode"]
+ members = w.get("members") or []
+ state = w["state"]
+ del w["state"]
+ obj_in_have = search_obj_in_list(group, have)
+ if state == "absent":
+ if obj_in_have:
+ commands.append("no interface port-channel {0}".format(group))
+ elif state == "present":
+ cmd = ["interface port-channel {0}".format(group), "end"]
+ if not obj_in_have:
+ if not group:
+ module.fail_json(msg="group is a required option")
+ commands.extend(cmd)
+ if members:
+ for m in members:
+ commands.append("interface {0}".format(m))
+ commands.append("channel-group {0} mode {1}".format(group, mode))
+ elif members:
+ if "members" not in obj_in_have.keys():
+ for m in members:
+ commands.extend(cmd)
+ commands.append("interface {0}".format(m))
+ commands.append("channel-group {0} mode {1}".format(group, mode))
+ elif set(members) != set(obj_in_have["members"]):
+ missing_members = list(set(members) - set(obj_in_have["members"]))
+ for m in missing_members:
+ commands.extend(cmd)
+ commands.append("interface {0}".format(m))
+ commands.append("channel-group {0} mode {1}".format(group, mode))
+ superfluous_members = list(set(obj_in_have["members"]) - set(members))
+ for m in superfluous_members:
+ commands.extend(cmd)
+ commands.append("interface {0}".format(m))
+ commands.append("no channel-group {0} mode {1}".format(group, mode))
+ if purge:
+ for h in have:
+ obj_in_want = search_obj_in_list(h["group"], want)
+ if not obj_in_want:
+ commands.append("no interface port-channel {0}".format(h["group"]))
+ return commands
+
+
+def map_params_to_obj(module):
+ obj = []
+ aggregate = module.params.get("aggregate")
+ if aggregate:
+ for item in aggregate:
+ for key in item:
+ if item.get(key) is None:
+ item[key] = module.params[key]
+ d = item.copy()
+ d["group"] = str(d["group"])
+ obj.append(d)
+ else:
+ obj.append(
+ {
+ "group": str(module.params["group"]),
+ "mode": module.params["mode"],
+ "members": module.params["members"],
+ "state": module.params["state"],
+ },
+ )
+ return obj
+
+
+def parse_mode(module, config, group, member):
+ mode = None
+ netcfg = CustomNetworkConfig(indent=1, contents=config)
+ parents = ["interface {0}".format(member)]
+ body = netcfg.get_section(parents)
+ match_int = re.findall("interface {0}\\n".format(member), body, re.M)
+ if match_int:
+ match = re.search("channel-group {0} mode (\\S+)".format(group), body, re.M)
+ if match:
+ mode = match.group(1)
+ return mode
+
+
+def parse_members(module, config, group):
+ members = []
+ for line in config.strip().split("!"):
+ l = line.strip()
+ if l.startswith("interface"):
+ match_group = re.findall("channel-group {0} mode".format(group), l, re.M)
+ if match_group:
+ match = re.search("interface (\\S+)", l, re.M)
+ if match:
+ members.append(match.group(1))
+ return members
+
+
+def get_channel(module, config, group):
+ match = re.findall("^interface (\\S+)", config, re.M)
+ if not match:
+ return {}
+ channel = {}
+ for item in set(match):
+ member = item
+ channel["mode"] = parse_mode(module, config, group, member)
+ channel["members"] = parse_members(module, config, group)
+ return channel
+
+
+def map_config_to_obj(module):
+ objs = list()
+ config = get_config(module)
+ for line in config.split("\n"):
+ l = line.strip()
+ match = re.search("interface Port-channel(\\S+)", l, re.M)
+ if match:
+ obj = {}
+ group = match.group(1)
+ obj["group"] = group
+ obj.update(get_channel(module, config, group))
+ objs.append(obj)
+ return objs
+
+
+def main():
+ """main entry point for module execution"""
+ element_spec = dict(
+ group=dict(type="int"),
+ mode=dict(choices=["active", "on", "passive", "auto", "desirable"]),
+ members=dict(type="list", elements="str"),
+ state=dict(default="present", choices=["present", "absent"]),
+ )
+ aggregate_spec = deepcopy(element_spec)
+ aggregate_spec["group"] = dict(required=True)
+ required_one_of = [["group", "aggregate"]]
+ required_together = [["members", "mode"]]
+ mutually_exclusive = [["group", "aggregate"]]
+ # remove default in aggregate spec, to handle common arguments
+ remove_default_spec(aggregate_spec)
+ argument_spec = dict(
+ aggregate=dict(
+ type="list",
+ elements="dict",
+ options=aggregate_spec,
+ required_together=required_together,
+ ),
+ purge=dict(default=False, type="bool"),
+ )
+ argument_spec.update(element_spec)
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_one_of=required_one_of,
+ required_together=required_together,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+ warnings = list()
+ result = {"changed": False}
+ if warnings:
+ result["warnings"] = warnings
+ want = map_params_to_obj(module)
+ have = map_config_to_obj(module)
+ commands = map_obj_to_commands((want, have), module)
+ result["commands"] = commands
+ if commands:
+ if not module.check_mode:
+ load_config(module, commands)
+ result["changed"] = True
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_lldp.py b/ansible_collections/cisco/ios/plugins/modules/ios_lldp.py
new file mode 100644
index 000000000..5d3f53380
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_lldp.py
@@ -0,0 +1,114 @@
+#!/usr/bin/python
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_lldp
+author: Ganesh Nalawade (@ganeshrn)
+short_description: (deprecated, removed after 2024-06-01) Manage LLDP configuration on Cisco IOS network devices.
+description:
+ - This module provides declarative management of LLDP service on Cisco IOS network
+ devices.
+version_added: 1.0.0
+deprecated:
+ alternative: ios_lldp_global
+ why: Newer and updated modules released with more functionality.
+ removed_at_date: "2024-06-01"
+notes:
+ - Tested against IOS 15.2
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ state:
+ description:
+ - State of the LLDP configuration. If value is I(present) lldp will be enabled
+ else if it is I(absent) it will be disabled.
+ default: present
+ choices:
+ - present
+ - absent
+ - enabled
+ - disabled
+ type: str
+extends_documentation_fragment:
+ - cisco.ios.ios
+"""
+
+EXAMPLES = """
+- name: Enable LLDP service
+ cisco.ios.ios_lldp:
+ state: present
+
+- name: Disable LLDP service
+ cisco.ios.ios_lldp:
+ state: absent
+"""
+
+RETURN = """
+commands:
+ description: The list of configuration mode commands to send to the device
+ returned: always, except for the platforms that use Netconf transport to manage the device.
+ type: list
+ sample:
+ - lldp run
+"""
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ load_config,
+ run_commands,
+)
+
+
+def has_lldp(module):
+ output = run_commands(module, ["show lldp"])
+ is_lldp_enable = False
+ if len(output) > 0 and "LLDP is not enabled" not in output[0]:
+ is_lldp_enable = True
+ return is_lldp_enable
+
+
+def main():
+ """main entry point for module execution"""
+ argument_spec = dict(
+ state=dict(default="present", choices=["present", "absent", "enabled", "disabled"]),
+ )
+ module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
+ warnings = list()
+ result = {"changed": False}
+ if warnings:
+ result["warnings"] = warnings
+ HAS_LLDP = has_lldp(module)
+ commands = []
+ if module.params["state"] == "absent" and HAS_LLDP:
+ commands.append("no lldp run")
+ elif module.params["state"] == "present" and not HAS_LLDP:
+ commands.append("lldp run")
+ result["commands"] = commands
+ if commands:
+ if not module.check_mode:
+ load_config(module, commands)
+ result["changed"] = True
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_lldp_global.py b/ansible_collections/cisco/ios/plugins/modules/ios_lldp_global.py
new file mode 100644
index 000000000..3cbeac6d1
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_lldp_global.py
@@ -0,0 +1,356 @@
+#!/usr/bin/python
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+"""
+The module file for ios_lldp_global
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_lldp_global
+short_description: Resource module to configure LLDP.
+description:
+ This module configures and manages the Link Layer Discovery Protocol(LLDP)
+ attributes on IOS platforms.
+version_added: 1.0.0
+author: Sumit Jaiswal (@justjais)
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ config:
+ description: A dictionary of LLDP options
+ type: dict
+ suboptions:
+ holdtime:
+ description:
+ - LLDP holdtime (in sec) to be sent in packets.
+ - Refer to vendor documentation for valid values.
+ type: int
+ reinit:
+ description:
+ - Specify the delay (in secs) for LLDP to initialize.
+ - Refer to vendor documentation for valid values.
+ - NOTE, if LLDP reinit is configured with a starting value, idempotency won't
+ be maintained as the Cisco device doesn't record the starting reinit configured
+ value. As such, Ansible cannot verify if the respective starting reinit
+ value is already configured or not from the device side. If you try to apply
+ starting reinit value in every play run, Ansible will show changed as True.
+ For any other reinit value, idempotency will be maintained since any other
+ reinit value is recorded in the Cisco device.
+ type: int
+ enabled:
+ description:
+ - Enable LLDP
+ type: bool
+ timer:
+ description:
+ - Specify the rate at which LLDP packets are sent (in sec).
+ - Refer to vendor documentation for valid values.
+ type: int
+ tlv_select:
+ description:
+ - Selection of LLDP TLVs i.e. type-length-value to send
+ - NOTE, if tlv-select is configured idempotency won't be maintained as Cisco
+ device doesn't record configured tlv-select options. As such, Ansible cannot
+ verify if the respective tlv-select options is already configured or not
+ from the device side. If you try to apply tlv-select option in every play
+ run, Ansible will show changed as True.
+ type: dict
+ suboptions:
+ four_wire_power_management:
+ description:
+ - Cisco 4-wire Power via MDI TLV
+ type: bool
+ mac_phy_cfg:
+ description:
+ - IEEE 802.3 MAC/Phy Configuration/status TLV
+ type: bool
+ management_address:
+ description:
+ - Management Address TLV
+ type: bool
+ port_description:
+ description:
+ - Port Description TLV
+ type: bool
+ port_vlan:
+ description:
+ - Port VLAN ID TLV
+ type: bool
+ power_management:
+ description:
+ - IEEE 802.3 DTE Power via MDI TLV
+ type: bool
+ system_capabilities:
+ description:
+ - System Capabilities TLV
+ type: bool
+ system_description:
+ description:
+ - System Description TLV
+ type: bool
+ system_name:
+ description:
+ - System Name TLV
+ type: bool
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device
+ by executing the command B(show running-config | section ^lldp).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ description:
+ - The state the configuration should be left in
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device.
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result. For state I(rendered) active connection to remote host is
+ not required.
+ - The state I(gathered) will fetch the running configuration from device and transform
+ it into structured data in the format as per the resource module argspec and
+ the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result. The value of C(running_config)
+ option should be the same format as the output of command I(show running-config
+ | include ip route|ipv6 route) executed on device. For state I(parsed) active
+ connection to remote host is not required.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - deleted
+ - rendered
+ - gathered
+ - parsed
+ default: merged
+"""
+
+EXAMPLES = """
+# Using merged
+
+# Before state:
+# -------------
+# vios#sh running-config | section ^lldp
+# vios1#
+
+- name: Merge provided configuration with device configuration
+ cisco.ios.ios_lldp_global:
+ config:
+ holdtime: 10
+ enabled: true
+ reinit: 3
+ timer: 10
+ state: merged
+
+# After state:
+# ------------
+# vios#sh running-config | section ^lldp
+# lldp timer 10
+# lldp holdtime 10
+# lldp reinit 3
+# lldp run
+
+# Using replaced
+
+# Before state:
+# -------------
+# vios#sh running-config | section ^lldp
+# lldp timer 10
+# lldp holdtime 10
+# lldp reinit 3
+# lldp run
+
+- name: Replaces LLDP device configuration with provided configuration
+ cisco.ios.ios_lldp_global:
+ config:
+ holdtime: 20
+ reinit: 5
+ state: replaced
+
+# After state:
+# -------------
+# vios#sh running-config | section ^lldp
+# lldp holdtime 20
+# lldp reinit 5
+
+# Using Deleted without any config passed
+#"(NOTE: This will delete all of configured LLDP module attributes)"
+
+# Before state:
+# -------------
+# vios#sh running-config | section ^lldp
+# lldp timer 10
+# lldp holdtime 10
+# lldp reinit 3
+# lldp run
+
+- name: Delete LLDP attributes
+ cisco.ios.ios_lldp_global:
+ state: deleted
+
+# After state:
+# -------------
+# vios#sh running-config | section ^lldp
+# vios1#
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# vios#sh running-config | section ^lldp
+# lldp timer 10
+# lldp holdtime 10
+# lldp reinit 3
+# lldp run
+
+- name: Gather listed interfaces with provided configurations
+ cisco.ios.ios_lldp_global:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": {
+# "enabled": true,
+# "holdtime": 10,
+# "reinit": 3,
+# "timer": 10
+# }
+
+# After state:
+# ------------
+#
+# vios#sh running-config | section ^lldp
+# lldp timer 10
+# lldp holdtime 10
+# lldp reinit 3
+# lldp run
+
+# Using Rendered
+- name: Render the commands for provided configuration
+ cisco.ios.ios_lldp_global:
+ config:
+ holdtime: 10
+ enabled: true
+ reinit: 3
+ timer: 10
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "lldp holdtime 10",
+# "lldp run",
+# "lldp timer 10",
+# "lldp reinit 3"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# lldp timer 10
+# lldp holdtime 10
+# lldp reinit 3
+# lldp run
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_lldp_global:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": {
+# "enabled": true,
+# "holdtime": 10,
+# "reinit": 3,
+# "timer": 10
+# }
+
+"""
+
+RETURN = """
+before:
+ description: The configuration as structured data prior to module invocation.
+ returned: always
+ type: dict
+ sample: The configuration returned will always be in the same format of the parameters above.
+after:
+ description: The configuration as structured data after module completion.
+ returned: when changed
+ type: dict
+ sample: The configuration returned will always be in the same format of the parameters above.
+commands:
+ description: The set of commands pushed to the remote device
+ returned: always
+ type: list
+ sample: ['lldp holdtime 10', 'lldp run', 'lldp timer 10']
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.lldp_global.lldp_global import (
+ Lldp_globalArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.lldp_global.lldp_global import (
+ Lldp_global,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ required_if = [
+ ("state", "merged", ("config",)),
+ ("state", "replaced", ("config",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ mutually_exclusive = [("config", "running_config")]
+
+ module = AnsibleModule(
+ argument_spec=Lldp_globalArgs.argument_spec,
+ required_if=required_if,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+ result = Lldp_global(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_lldp_interfaces.py b/ansible_collections/cisco/ios/plugins/modules/ios_lldp_interfaces.py
new file mode 100644
index 000000000..09eacb11b
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_lldp_interfaces.py
@@ -0,0 +1,671 @@
+#!/usr/bin/python
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+"""
+The module file for ios_lldp_interfaces
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+module: ios_lldp_interfaces
+short_description: Resource module to configure LLDP interfaces.
+description:
+ This module manages link layer discovery protocol (LLDP) attributes of
+ interfaces on Cisco IOS devices.
+version_added: 1.0.0
+author: Sumit Jaiswal (@justjais)
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ config:
+ description: A dictionary of LLDP options
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Full name of the interface excluding any logical unit number, i.e. GigabitEthernet0/1.
+ type: str
+ required: true
+ receive:
+ description:
+ - Enable LLDP reception on interface.
+ type: bool
+ transmit:
+ description:
+ - Enable LLDP transmission on interface.
+ type: bool
+ med_tlv_select:
+ description:
+ - Selection of LLDP MED TLVs to send
+ - NOTE, if med-tlv-select is configured idempotency won't be maintained as
+ Cisco device doesn't record configured med-tlv-select options. As such,
+ Ansible cannot verify if the respective med-tlv-select options is already
+ configured or not from the device side. If you try to apply med-tlv-select
+ option in every play run, Ansible will show changed as True.
+ type: dict
+ suboptions:
+ inventory_management:
+ description:
+ - LLDP MED Inventory Management TLV
+ type: bool
+ tlv_select:
+ description:
+ - Selection of LLDP type-length-value i.e. TLVs to send
+ - NOTE, if tlv-select is configured idempotency won't be maintained as Cisco
+ device doesn't record configured tlv-select options. As such, Ansible cannot
+ verify if the respective tlv-select options is already configured or not
+ from the device side. If you try to apply tlv-select option in every play
+ run, Ansible will show changed as True.
+ type: dict
+ suboptions:
+ power_management:
+ description:
+ - IEEE 802.3 DTE Power via MDI TLV
+ type: bool
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device by
+ executing the command B(sh lldp interface).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ description:
+ - The state the configuration should be left in
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device.
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result. For state I(rendered) active connection to remote host is
+ not required.
+ - The state I(gathered) will fetch the running configuration from device and transform
+ it into structured data in the format as per the resource module argspec and
+ the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result. The value of C(running_config)
+ option should be the same format as the output of command I(show running-config
+ | include ip route|ipv6 route) executed on device. For state I(parsed) active
+ connection to remote host is not required.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - rendered
+ - gathered
+ - parsed
+ default: merged
+"""
+
+EXAMPLES = """
+# Using merged
+#
+# Before state:
+# -------------
+#
+# vios#sh lldp interface
+# GigabitEthernet0/0:
+# Tx: enabled
+# Rx: disabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/1:
+# Tx: disabled
+# Rx: disabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/2:
+# Tx: disabled
+# Rx: disabled
+# Tx state: IDLE
+# Rx state: INIT
+#
+# GigabitEthernet0/3:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+
+- name: Merge provided configuration with device configuration
+ cisco.ios.ios_lldp_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ receive: true
+ transmit: true
+ - name: GigabitEthernet0/2
+ receive: true
+ - name: GigabitEthernet0/3
+ transmit: true
+ state: merged
+
+# After state:
+# ------------
+#
+# vios#sh lldp interface
+# GigabitEthernet0/0:
+# Tx: enabled
+# Rx: disabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/1:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/2:
+# Tx: disabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: INIT
+#
+# GigabitEthernet0/3:
+# Tx: enabled
+# Rx: disabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+
+# Using overridden
+#
+# Before state:
+# -------------
+#
+# vios#sh lldp interface
+# GigabitEthernet0/0:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/1:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/2:
+# Tx: disabled
+# Rx: disabled
+# Tx state: IDLE
+# Rx state: INIT
+#
+# GigabitEthernet0/3:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+
+- name: Override device configuration of all lldp_interfaces with provided configuration
+ cisco.ios.ios_lldp_interfaces:
+ config:
+ - name: GigabitEthernet0/2
+ receive: true
+ transmit: true
+ state: overridden
+
+# After state:
+# ------------
+#
+# vios#sh lldp interface
+# GigabitEthernet0/0:
+# Tx: disabled
+# Rx: disabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/1:
+# Tx: disabled
+# Rx: disabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/2:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: INIT
+#
+# GigabitEthernet0/3:
+# Tx: disabled
+# Rx: disabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+
+# Using replaced
+#
+# Before state:
+# -------------
+#
+# vios#sh lldp interface
+# GigabitEthernet0/0:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/1:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/2:
+# Tx: disabled
+# Rx: disabled
+# Tx state: IDLE
+# Rx state: INIT
+#
+# GigabitEthernet0/3:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+
+- name: Replaces device configuration of listed lldp_interfaces with provided configuration
+ cisco.ios.ios_lldp_interfaces:
+ config:
+ - name: GigabitEthernet0/2
+ receive: true
+ transmit: true
+ - name: GigabitEthernet0/3
+ receive: true
+ state: replaced
+
+# After state:
+# ------------
+#
+# vios#sh lldp interface
+# GigabitEthernet0/0:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/1:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/2:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: INIT
+#
+# GigabitEthernet0/3:
+# Tx: disabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+
+# Using Deleted
+#
+# Before state:
+# -------------
+#
+# vios#sh lldp interface
+# GigabitEthernet0/0:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/1:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/2:
+# Tx: disabled
+# Rx: disabled
+# Tx state: IDLE
+# Rx state: INIT
+#
+# GigabitEthernet0/3:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+
+- name: "Delete LLDP attributes of given interfaces (Note: This won't delete the interface itself)"
+ cisco.ios.ios_lldp_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ state: deleted
+
+# After state:
+# -------------
+#
+# vios#sh lldp interface
+# GigabitEthernet0/0:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/1:
+# Tx: disabled
+# Rx: disabled
+# Tx state: IDLE
+# Rx state: INIT
+#
+# GigabitEthernet0/2:
+# Tx: disabled
+# Rx: disabled
+# Tx state: IDLE
+# Rx state: INIT
+#
+# GigabitEthernet0/3:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+
+# Using Deleted without any config passed
+# "(NOTE: This will delete all of configured LLDP module attributes)"
+#
+# Before state:
+# -------------
+#
+# vios#sh lldp interface
+# GigabitEthernet0/0:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/1:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/2:
+# Tx: disabled
+# Rx: disabled
+# Tx state: IDLE
+# Rx state: INIT
+#
+# GigabitEthernet0/3:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+
+- name: "Delete LLDP attributes for all configured interfaces (Note: This won't delete the interface itself)"
+ cisco.ios.ios_lldp_interfaces:
+ state: deleted
+
+# After state:
+# -------------
+#
+# vios#sh lldp interface
+# GigabitEthernet0/0:
+# Tx: disabled
+# Rx: disabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/1:
+# Tx: disabled
+# Rx: disabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/2:
+# Tx: disabled
+# Rx: disabled
+# Tx state: IDLE
+# Rx state: INIT
+#
+# GigabitEthernet0/3:
+# Tx: disabled
+# Rx: disabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# vios#sh lldp interface
+# GigabitEthernet0/0:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/1:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/2:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+
+- name: Gather listed LLDP interfaces with provided configurations
+ cisco.ios.ios_lldp_interfaces:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": [
+# {
+# "name": "GigabitEthernet0/0",
+# "receive": true,
+# "transmit": true
+# },
+# {
+# "name": "GigabitEthernet0/1",
+# "receive": true,
+# "transmit": true
+# },
+# {
+# "name": "GigabitEthernet0/2",
+# "receive": true,
+# "transmit": true
+# }
+# ]
+
+# After state:
+# ------------
+#
+# vios#sh lldp interface
+# GigabitEthernet0/0:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/1:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+
+# GigabitEthernet0/2:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+
+# Using Rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_lldp_interfaces:
+ config:
+ - name: GigabitEthernet0/0
+ receive: true
+ transmit: true
+ - name: GigabitEthernet0/1
+ receive: true
+ transmit: true
+ - name: GigabitEthernet0/2
+ receive: true
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "interface GigabitEthernet0/0",
+# "lldp receive",
+# "lldp transmit",
+# "interface GigabitEthernet0/1",
+# "lldp receive",
+# "lldp transmit",
+# "interface GigabitEthernet0/2",
+# "lldp receive"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# GigabitEthernet0/0:
+# Tx: enabled
+# Rx: disabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/1:
+# Tx: enabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: WAIT FOR FRAME
+#
+# GigabitEthernet0/2:
+# Tx: disabled
+# Rx: enabled
+# Tx state: IDLE
+# Rx state: INIT
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_lldp_interfaces:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": [
+# {
+# "name": "GigabitEthernet0/0",
+# "receive": false,
+# "transmit": true
+# },
+# {
+# "name": "GigabitEthernet0/1",
+# "receive": true,
+# "transmit": true
+# },
+# {
+# "name": "GigabitEthernet0/2",
+# "receive": true,
+# "transmit": false
+# }
+# ]
+"""
+
+RETURN = """
+before:
+ description: The configuration as structured data prior to module invocation.
+ returned: always
+ type: list
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+after:
+ description: The configuration as structured data after module completion.
+ returned: when changed
+ type: list
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: always
+ type: list
+ sample: ['interface GigabitEthernet 0/1', 'lldp transmit', 'lldp receive']
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.lldp_interfaces.lldp_interfaces import (
+ Lldp_InterfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.lldp_interfaces.lldp_interfaces import (
+ Lldp_Interfaces,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ required_if = [
+ ("state", "merged", ("config",)),
+ ("state", "replaced", ("config",)),
+ ("state", "overridden", ("config",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ mutually_exclusive = [("config", "running_config")]
+
+ module = AnsibleModule(
+ argument_spec=Lldp_InterfacesArgs.argument_spec,
+ required_if=required_if,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+ result = Lldp_Interfaces(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_logging.py b/ansible_collections/cisco/ios/plugins/modules/ios_logging.py
new file mode 100644
index 000000000..492e94d85
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_logging.py
@@ -0,0 +1,498 @@
+#!/usr/bin/python
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_logging
+author: Trishna Guha (@trishnaguha)
+short_description: (deprecated, removed after 2023-06-01) Manage logging on network devices
+description:
+ - This module provides declarative management of logging on Cisco Ios devices.
+version_added: 1.0.0
+deprecated:
+ alternative: ios_logging_global
+ why: Newer and updated modules released with more functionality.
+ removed_at_date: "2023-06-01"
+notes:
+ - Tested against IOS 15.6
+ - The 'Default System Message Logging Configuration' of the ios device
+ like facility Local7 or logging on is not subjected to idempotency causes
+options:
+ dest:
+ description:
+ - Destination of the logs.
+ - On dest has to be quoted as 'on' or else pyyaml will convert
+ to True before it gets to Ansible.
+ choices:
+ - "on"
+ - host
+ - console
+ - monitor
+ - buffered
+ - trap
+ type: str
+ name:
+ description:
+ - The hostname or IP address of the destination.
+ - Required when I(dest=host).
+ type: str
+ size:
+ description:
+ - Size of buffer. The acceptable value is in range from 4096 to 4294967295 bytes.
+ type: int
+ facility:
+ description:
+ - Set logging facility.
+ type: str
+ level:
+ description:
+ - Set logging severity levels.
+ default: debugging
+ choices:
+ - emergencies
+ - alerts
+ - critical
+ - errors
+ - warnings
+ - notifications
+ - informational
+ - debugging
+ type: str
+ aggregate:
+ description: List of logging definitions.
+ type: list
+ elements: dict
+ suboptions:
+ dest:
+ description:
+ - Destination of the logs.
+ - On dest has to be quoted as 'on' or else pyyaml will convert
+ to True before it gets to Ansible.
+ choices:
+ - "on"
+ - host
+ - console
+ - monitor
+ - buffered
+ - trap
+ type: str
+ name:
+ description:
+ - The hostname or IP address of the destination.
+ - Required when I(dest=host).
+ type: str
+ size:
+ description:
+ - Size of buffer. The acceptable value is in range from 4096 to 4294967295 bytes.
+ type: int
+ facility:
+ description:
+ - Set logging facility.
+ type: str
+ level:
+ description:
+ - Set logging severity levels.
+ type: str
+ choices:
+ - emergencies
+ - alerts
+ - critical
+ - errors
+ - warnings
+ - notifications
+ - informational
+ - debugging
+ state:
+ description:
+ - State of the logging configuration.
+ choices:
+ - present
+ - absent
+ type: str
+ state:
+ description:
+ - State of the logging configuration.
+ default: present
+ choices:
+ - present
+ - absent
+ type: str
+extends_documentation_fragment:
+ - cisco.ios.ios
+"""
+
+EXAMPLES = """
+- name: Configure host logging
+ cisco.ios.ios_logging:
+ dest: host
+ name: 172.16.0.1
+ state: present
+
+- name: Remove host logging configuration
+ cisco.ios.ios_logging:
+ dest: host
+ name: 172.16.0.1
+ state: absent
+
+- name: Configure console logging level and facility
+ cisco.ios.ios_logging:
+ dest: console
+ facility: local7
+ level: debugging
+ state: present
+
+- name: Enable logging to all
+ cisco.ios.ios_logging:
+ dest: on
+
+- name: Configure buffer size
+ cisco.ios.ios_logging:
+ dest: buffered
+ size: 5000
+
+- name: Configure logging using aggregate
+ cisco.ios.ios_logging:
+ aggregate:
+ - { dest: console, level: notifications }
+ - { dest: buffered, size: 9000 }
+
+- name: Remove logging using aggregate
+ cisco.ios.ios_logging:
+ aggregate:
+ - { dest: console, level: notifications }
+ - { dest: buffered, size: 9000 }
+ state: absent
+"""
+
+RETURN = """
+commands:
+ description: The list of configuration mode commands to send to the device
+ returned: always
+ type: list
+ sample:
+ - logging facility local7
+ - logging host 172.16.0.1
+"""
+import re
+
+from copy import deepcopy
+
+from ansible.module_utils._text import to_text
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.common.validation import check_required_if
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_default_spec,
+ validate_ip_address,
+)
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ get_capabilities,
+ get_config,
+ load_config,
+)
+
+
+def validate_size(value, module):
+ if value:
+ if not int(4096) <= int(value) <= int(4294967295):
+ module.fail_json(msg="size must be between 4096 and 4294967295")
+ else:
+ return value
+
+
+def map_obj_to_commands(updates, module, os_version):
+ dest_group = "console", "monitor", "buffered", "on", "trap"
+ commands = list()
+ want, have = updates
+ for w in want:
+ dest = w["dest"]
+ name = w["name"]
+ size = w["size"]
+ facility = w["facility"]
+ level = w["level"]
+ state = w["state"]
+ del w["state"]
+ if facility:
+ w["dest"] = "facility"
+ if state == "absent" and w in have:
+ if dest:
+ if dest == "host":
+ if os_version.startswith("12."):
+ commands.append("no logging {0}".format(name))
+ else:
+ commands.append("no logging host {0}".format(name))
+ elif dest in dest_group:
+ commands.append("no logging {0}".format(dest))
+ else:
+ module.fail_json(
+ msg="dest must be among console, monitor, buffered, host, on, trap",
+ )
+ if facility:
+ commands.append("no logging facility {0}".format(facility))
+ if state == "present" and w not in have:
+ if facility:
+ present = False
+ for entry in have:
+ if entry["dest"] == "facility" and entry["facility"] == facility:
+ present = True
+ if not present:
+ commands.append("logging facility {0}".format(facility))
+ if dest == "host":
+ if os_version.startswith("12."):
+ commands.append("logging {0}".format(name))
+ else:
+ commands.append("logging host {0}".format(name))
+ elif dest == "on":
+ commands.append("logging on")
+ elif dest == "buffered" and size:
+ present = False
+ for entry in have:
+ if (
+ entry["dest"] == "buffered"
+ and entry["size"] == size
+ and entry["level"] == level
+ ):
+ present = True
+ if not present:
+ if level and level != "debugging":
+ commands.append("logging buffered {0} {1}".format(size, level))
+ else:
+ commands.append("logging buffered {0}".format(size))
+ elif dest:
+ dest_cmd = "logging {0}".format(dest)
+ if level:
+ dest_cmd += " {0}".format(level)
+ commands.append(dest_cmd)
+ return commands
+
+
+def parse_facility(line, dest):
+ facility = None
+ if dest == "facility":
+ match = re.search("logging facility (\\S+)", line, re.M)
+ if match:
+ facility = match.group(1)
+ return facility
+
+
+def parse_size(line, dest):
+ size = None
+ if dest == "buffered":
+ match = re.search("logging buffered(?: (\\d+))?(?: [a-z]+)?", line, re.M)
+ if match:
+ if match.group(1) is not None:
+ size = match.group(1)
+ else:
+ size = "4096"
+ return size
+
+
+def parse_name(line, dest):
+ if dest == "host":
+ match = re.search("logging host (\\S+)", line, re.M)
+ if match:
+ name = match.group(1)
+ else:
+ name = None
+ return name
+
+
+def parse_level(line, dest):
+ level_group = (
+ "emergencies",
+ "alerts",
+ "critical",
+ "errors",
+ "warnings",
+ "notifications",
+ "informational",
+ "debugging",
+ )
+ if dest == "host":
+ level = "debugging"
+ else:
+ if dest == "buffered":
+ match = re.search("logging buffered(?: \\d+)?(?: ([a-z]+))?", line, re.M)
+ else:
+ match = re.search("logging {0} (\\S+)".format(dest), line, re.M)
+ if match and match.group(1) in level_group:
+ level = match.group(1)
+ else:
+ level = "debugging"
+ return level
+
+
+def map_config_to_obj(module):
+ obj = []
+ dest_group = ("console", "host", "monitor", "buffered", "on", "facility", "trap")
+ data = get_config(module, flags=["| include logging"])
+ for line in data.split("\n"):
+ match = re.search("^logging (\\S+)", line, re.M)
+ if match:
+ if match.group(1) in dest_group:
+ dest = match.group(1)
+ obj.append(
+ {
+ "dest": dest,
+ "name": parse_name(line, dest),
+ "size": parse_size(line, dest),
+ "facility": parse_facility(line, dest),
+ "level": parse_level(line, dest),
+ },
+ )
+ elif validate_ip_address(match.group(1)):
+ dest = "host"
+ obj.append(
+ {
+ "dest": dest,
+ "name": match.group(1),
+ "size": parse_size(line, dest),
+ "facility": parse_facility(line, dest),
+ "level": parse_level(line, dest),
+ },
+ )
+ else:
+ ip_match = re.search("\\d+\\.\\d+\\.\\d+\\.\\d+", match.group(1), re.M)
+ if ip_match:
+ dest = "host"
+ obj.append(
+ {
+ "dest": dest,
+ "name": match.group(1),
+ "size": parse_size(line, dest),
+ "facility": parse_facility(line, dest),
+ "level": parse_level(line, dest),
+ },
+ )
+ return obj
+
+
+def map_params_to_obj(module, required_if=None):
+ obj = []
+ aggregate = module.params.get("aggregate")
+ if aggregate:
+ for item in aggregate:
+ for key in item:
+ if item.get(key) is None:
+ item[key] = module.params[key]
+ try:
+ check_required_if(required_if, item)
+ except TypeError as exc:
+ module.fail_json(to_text(exc))
+ d = item.copy()
+ if d["dest"] != "host":
+ d["name"] = None
+ if d["dest"] == "buffered":
+ if "size" in d:
+ d["size"] = str(validate_size(d["size"], module))
+ elif "size" not in d:
+ d["size"] = str(4096)
+ else:
+ pass
+ if d["dest"] != "buffered":
+ d["size"] = None
+ obj.append(d)
+ else:
+ if module.params["dest"] != "host":
+ module.params["name"] = None
+ if module.params["dest"] == "buffered":
+ if not module.params["size"]:
+ module.params["size"] = str(4096)
+ else:
+ module.params["size"] = None
+ if module.params["size"] is None:
+ obj.append(
+ {
+ "dest": module.params["dest"],
+ "name": module.params["name"],
+ "size": module.params["size"],
+ "facility": module.params["facility"],
+ "level": module.params["level"],
+ "state": module.params["state"],
+ },
+ )
+ else:
+ obj.append(
+ {
+ "dest": module.params["dest"],
+ "name": module.params["name"],
+ "size": str(validate_size(module.params["size"], module)),
+ "facility": module.params["facility"],
+ "level": module.params["level"],
+ "state": module.params["state"],
+ },
+ )
+ return obj
+
+
+def main():
+ """main entry point for module execution"""
+ element_spec = dict(
+ dest=dict(type="str", choices=["on", "host", "console", "monitor", "buffered", "trap"]),
+ name=dict(type="str"),
+ size=dict(type="int"),
+ facility=dict(type="str"),
+ level=dict(
+ type="str",
+ default="debugging",
+ choices=[
+ "emergencies",
+ "alerts",
+ "critical",
+ "errors",
+ "warnings",
+ "notifications",
+ "informational",
+ "debugging",
+ ],
+ ),
+ state=dict(default="present", choices=["present", "absent"]),
+ )
+ aggregate_spec = deepcopy(element_spec)
+ # remove default in aggregate spec, to handle common arguments
+ remove_default_spec(aggregate_spec)
+ argument_spec = dict(aggregate=dict(type="list", elements="dict", options=aggregate_spec))
+ argument_spec.update(element_spec)
+ required_if = [("dest", "host", ["name"])]
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ required_if=required_if,
+ supports_check_mode=True,
+ )
+ device_info = get_capabilities(module)
+ os_version = device_info["device_info"]["network_os_version"]
+ warnings = list()
+ result = {"changed": False}
+ if warnings:
+ result["warnings"] = warnings
+ want = map_params_to_obj(module, required_if=required_if)
+ have = map_config_to_obj(module)
+ commands = map_obj_to_commands((want, have), module, os_version)
+ result["commands"] = commands
+ if commands:
+ if not module.check_mode:
+ load_config(module, commands)
+ result["changed"] = True
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_logging_global.py b/ansible_collections/cisco/ios/plugins/modules/ios_logging_global.py
new file mode 100644
index 000000000..a77ca1115
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_logging_global.py
@@ -0,0 +1,1084 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2021 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+"""
+The module file for ios_logging_global
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_logging_global
+version_added: 2.2.0
+short_description: Resource module to configure logging.
+description: This module manages the logging attributes of Cisco IOS network devices
+author: Sagar Paul (@KB-perByte)
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+ - The Configuration defaults of the Cisco IOS network devices
+ are supposed to hinder idempotent behavior of plays
+options:
+ config:
+ description: A dictionary of logging options
+ type: dict
+ suboptions:
+ buffered:
+ description: Set buffered logging parameters
+ type: dict
+ suboptions:
+ size: &size
+ description: Logging buffer size
+ type: int
+ severity: &severity
+ description: Logging severity level
+ type: str
+ choices: &severity_subgroup
+ - alerts
+ - critical
+ - debugging
+ - emergencies
+ - errors
+ - informational
+ - notifications
+ - warnings
+ discriminator: &discriminator
+ description: Establish MD-Buffer association
+ type: str
+ filtered: &filtered
+ description: Enable filtered logging
+ type: bool
+ xml: &xml
+ description: Enable logging in XML to XML logging buffer
+ type: bool
+ buginf:
+ description: Enable buginf logging for debugging
+ type: bool
+ cns_events:
+ description: Set CNS Event logging level
+ type: str
+ choices: *severity_subgroup
+ console:
+ description: Set console logging parameters
+ type: dict
+ suboptions:
+ severity:
+ description: Logging severity level
+ type: str
+ choices:
+ [
+ "alerts",
+ "critical",
+ "debugging",
+ "emergencies",
+ "errors",
+ "informational",
+ "notifications",
+ "warnings",
+ "guaranteed",
+ ]
+ discriminator: *discriminator
+ filtered: *filtered
+ xml: *xml
+ count:
+ description: Count every log message and timestamp last occurrence
+ type: bool
+ delimiter:
+ description: Append delimiter to syslog messages
+ type: dict
+ suboptions:
+ tcp:
+ description: Append delimiter to syslog messages over TCP
+ type: bool
+ discriminator:
+ description: Create or modify a message discriminator
+ type: list
+ elements: str
+ dmvpn:
+ description: DMVPN Configuration
+ type: dict
+ suboptions:
+ rate_limit: &rate_limit
+ description: rate in messages/minute, default is 600 messages/minute (1-10000)
+ type: int
+ esm:
+ description: Set ESM filter restrictions
+ type: dict
+ suboptions:
+ config:
+ description: Permit/Deny configuration changes from ESM filters
+ type: bool
+ exception:
+ description: Limit size of exception flush output (4096-2147483647)
+ type: int
+ facility:
+ description: Facility parameter for syslog messages
+ type: str
+ choices:
+ - auth
+ - cron
+ - daemon
+ - kern
+ - local0
+ - local1
+ - local2
+ - local3
+ - local4
+ - local5
+ - local6
+ - local7
+ - lpr
+ - mail
+ - news
+ - sys10
+ - sys11
+ - sys12
+ - sys13
+ - sys14
+ - sys9
+ - syslog
+ - user
+ - uucp
+ filter:
+ description: Specify logging filter
+ type: list
+ elements: dict
+ suboptions:
+ url:
+ description: Filter Uniform Resource Locator
+ type: str
+ order:
+ description: Order of filter execution
+ type: int
+ args:
+ description: Arguments passed to filter module.
+ type: str
+ history:
+ description: Configure syslog history table
+ type: dict
+ suboptions:
+ size: *size
+ severity: *severity
+ hosts:
+ description: Set syslog server IP address and parameters
+ type: list
+ elements: dict
+ suboptions:
+ discriminator: *discriminator
+ filtered: *filtered
+ sequence_num_session: &sequence_num_session
+ description: Include session sequence number tag in syslog message
+ type: bool
+ session_id: &session_id
+ description: Specify syslog message session ID tagging
+ type: dict
+ suboptions: &session_id_suboptions
+ tag:
+ description: Include hostname in session ID tag
+ type: str
+ choices: ["hostname", "ipv4", "ipv6"]
+ text:
+ description: Include custom string in session ID tag
+ type: str
+ stream: &stream
+ description: This server should only receive messages from a numbered stream
+ type: int
+ transport: &transport
+ description: Specify the transport protocol (default=UDP)
+ type: dict
+ suboptions:
+ tcp:
+ description: Transport Control Protocol
+ type: dict
+ suboptions:
+ audit:
+ description: Set this host for IOS firewall audit logging
+ type: bool
+ discriminator: *discriminator
+ stream: *stream
+ filtered: *filtered
+ port:
+ description: Specify the TCP port number (default=601) (1 - 65535)
+ type: int
+ sequence_num_session: *sequence_num_session
+ session_id: *session_id
+ xml: *xml
+ udp:
+ description: User Datagram Protocol
+ type: dict
+ suboptions:
+ discriminator: *discriminator
+ stream: *stream
+ filtered: *filtered
+ port:
+ description: Specify the UDP port number (default=514) (1 - 65535)
+ type: int
+ sequence_num_session: *sequence_num_session
+ session_id: *session_id
+ xml: *xml
+ vrf:
+ description: Set VRF option
+ type: str
+ xml: *xml
+ ipv6:
+ description: Configure IPv6 syslog server
+ type: str
+ host:
+ description: IP address of the syslog server
+ type: str
+ aliases:
+ - hostname
+ message_counter:
+ description: Configure log message to include certain counter value
+ type: list
+ elements: str
+ choices: ["log", "debug", "syslog"]
+ monitor:
+ description: Set terminal line (monitor) logging parameters
+ type: dict
+ suboptions:
+ severity: *severity
+ discriminator: *discriminator
+ filtered: *filtered
+ xml: *xml
+ logging_on:
+ description: Enable logging to all enabled destinations
+ type: str
+ choices: ["enable", "disable"]
+ origin_id:
+ description: Add origin ID to syslog messages
+ type: dict
+ suboptions:
+ tag:
+ description: Include hostname in session ID tag
+ type: str
+ choices: ["hostname", "ip", "ipv6"]
+ text:
+ description: Include custom string in session ID tag
+ type: str
+ persistent:
+ description: Set persistent logging parameters
+ type: dict
+ suboptions:
+ batch:
+ description: Set batch size for writing to persistent storage (4096-2142715904)
+ type: int
+ filesize:
+ description: Set size of individual log files (4096-2142715904)
+ type: int
+ immediate:
+ description: Write log entry to storage immediately (no buffering).
+ type: bool
+ notify:
+ description: Notify when show logging [persistent] is activated.
+ type: bool
+ protected:
+ description: Eliminates manipulation on logging-persistent files.
+ type: bool
+ size:
+ description: Set disk space for writing log messages (4096-2142715904)
+ type: int
+ threshold:
+ description: Set threshold for logging persistent
+ type: int
+ url:
+ description: URL to store logging messages
+ type: str
+ policy_firewall:
+ description: Firewall configuration
+ type: dict
+ suboptions:
+ rate_limit:
+ description: (0-3600) value in seconds, default is 30 Sec.
+ type: int
+ queue_limit:
+ description: Set logger message queue size
+ type: dict
+ suboptions:
+ size:
+ description: (100-2147483647) set new queue size
+ type: int
+ esm:
+ description: (100-2147483647) set new queue size
+ type: int
+ trap:
+ description: (100-2147483647) set new queue size
+ type: int
+ rate_limit:
+ description: Set messages per second limit
+ type: dict
+ suboptions:
+ size: &rate_limit_size
+ description: (1-10000) message per second
+ type: int
+ required: true
+ all:
+ description: (1-10000) message per second
+ type: bool
+ console:
+ description: (1-10000) message per second
+ type: bool
+ except_severity:
+ description: Messages of this severity or higher
+ type: str
+ choices: *severity_subgroup
+ reload:
+ description: Set reload logging level
+ type: dict
+ suboptions:
+ severity: *severity
+ message_limit:
+ description: Number of messages (1-4294967295)
+ type: int
+ server_arp:
+ description: Enable sending ARP requests for syslog servers when first configured
+ type: bool
+ snmp_trap:
+ description: Set syslog level for sending snmp trap
+ type: list
+ elements: str
+ choices: *severity_subgroup
+ source_interface:
+ description: Specify interface for source address in logging transactions
+ type: list
+ elements: dict
+ suboptions:
+ interface:
+ description: Interface name with number
+ type: str
+ vrf:
+ description: VPN Routing/Forwarding instance name
+ type: str
+ trap:
+ description: Set syslog server logging level
+ type: str
+ choices: *severity_subgroup
+ userinfo:
+ description: Enable logging of user info on privileged mode enabling
+ type: bool
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device by
+ executing the command B(show running-config | include logging).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - parsed
+ - rendered
+ default: merged
+ description:
+ - The state the configuration should be left in
+ - With state I(replaced), for the listed logging configurations,
+ that are in running-config and can have multiple set of commands
+ but not in the task are negated.
+ - With state I(overridden), all configurations that are in running-config but
+ not in the task are negated.
+ - Please refer to examples for more details.
+ type: str
+"""
+
+EXAMPLES = """
+# Using state: merged
+
+# Before state:
+# -------------
+
+# router-ios#show running-config | section logging
+# no logging exception
+# no logging buffered
+# no logging reload
+# no logging rate-limit
+# no logging console
+# no logging monitor
+# no logging cns-events
+# no logging trap
+
+- name: Apply the provided configuration
+ cisco.ios.ios_logging_global:
+ config:
+ buffered:
+ severity: notifications
+ size: 5099
+ xml: true
+ console:
+ severity: critical
+ xml: true
+ facility: local5
+ hosts:
+ - hostname: 172.16.1.12
+ - hostname: 172.16.1.11
+ xml: true
+ - hostname: 172.16.1.10
+ filtered: true
+ stream: 10
+ - hostname: 172.16.1.13
+ transport:
+ tcp:
+ port: 514
+ monitor:
+ severity: warnings
+ message_counter: log
+ snmp_trap:
+ - errors
+ trap: errors
+ userinfo: true
+ policy_firewall:
+ rate_limit: 10
+ logging_on: enable
+ exception: 4099
+ dmvpn:
+ rate_limit: 10
+ cns_events: warnings
+ state: merged
+
+# Commands Fired:
+# ---------------
+
+# "commands": [
+# "logging buffered xml 5099 notifications",
+# "logging cns-events warnings",
+# "logging console xml critical",
+# "logging dmvpn rate-limit 10",
+# "logging exception 4099",
+# "logging facility local5",
+# "logging monitor warnings",
+# "logging on",
+# "logging policy-firewall rate-limit 10",
+# "logging trap errors",
+# "logging userinfo",
+# "logging host 172.16.1.12",
+# "logging host 172.16.1.10 filtered stream 10",
+# "logging host 172.16.1.13 transport tcp port 514",
+# "logging message-counter log",
+# "logging snmp-trap errors",
+# "logging host 172.16.1.11 xml"
+# ],
+
+# After state:
+# ------------
+
+# router-ios#show running-config | section logging
+# logging exception 4099
+# logging message-counter log
+# logging userinfo
+# logging buffered xml 5099 notifications
+# no logging reload
+# no logging rate-limit
+# logging console xml critical
+# logging monitor warnings
+# logging cns-events warnings
+# logging policy-firewall rate-limit 10
+# logging dmvpn rate-limit 10
+# logging trap errors
+# logging facility local5
+# logging snmp-trap errors
+# logging snmp-trap warnings
+# logging host 172.16.1.13 transport tcp port 514
+# logging host 172.16.1.11 xml
+# logging host 172.16.1.12
+# logging host 172.16.1.10 filtered stream 10
+
+# Using state: deleted
+
+# Before state:
+# -------------
+
+# router-ios#show running-config | section logging
+# logging exception 4099
+# logging message-counter log
+# logging userinfo
+# logging buffered xml 5099 notifications
+# no logging reload
+# no logging rate-limit
+# logging console xml critical
+# logging monitor warnings
+# logging cns-events warnings
+# logging policy-firewall rate-limit 10
+# logging dmvpn rate-limit 10
+# logging trap errors
+# logging facility local5
+# logging snmp-trap errors
+# logging host 172.16.1.13 transport tcp port 514
+# logging host 172.16.1.11 xml
+# logging host 172.16.1.12
+# logging host 172.16.1.10 filtered stream 10
+
+- name: Remove all existing configuration
+ cisco.ios.ios_logging_global:
+ state: deleted
+
+# Commands Fired:
+# ---------------
+
+# "commands": [
+# "no logging message-counter log",
+# "no logging snmp-trap errors",
+# "no logging host 172.16.1.13",
+# "no logging host 172.16.1.11",
+# "no logging host 172.16.1.12",
+# "no logging host 172.16.1.10",
+# "no logging exception 4099",
+# "no logging userinfo",
+# "no logging buffered xml 5099 notifications",
+# "no logging console xml critical",
+# "no logging monitor warnings",
+# "no logging cns-events warnings",
+# "no logging policy-firewall rate-limit 10",
+# "no logging dmvpn rate-limit 10",
+# "no logging trap errors",
+# "no logging facility local5"
+# ],
+
+# After state:
+# ------------
+
+# router-ios#show running-config | section logging
+# no logging exception
+# no logging buffered
+# no logging reload
+# no logging rate-limit
+# no logging console
+# no logging monitor
+# no logging cns-events
+# no logging trap
+
+# Using state: overridden
+
+# Before state:
+# -------------
+
+# router-ios#show running-config | section logging
+# logging exception 4099
+# logging message-counter log
+# logging userinfo
+# logging buffered 6000 critical
+# no logging reload
+# no logging rate-limit
+# logging console xml critical
+# logging monitor warnings
+# logging cns-events warnings
+# logging policy-firewall rate-limit 10
+# logging dmvpn rate-limit 10
+# logging trap errors
+# logging facility local6
+# logging host 172.16.1.13 transport tcp port 514
+# logging host 172.16.1.12
+# logging host 172.16.1.10 filtered stream 10
+# logging host 172.16.1.25 filtered
+
+- name: Override commands with provided configuration
+ cisco.ios.ios_logging_global:
+ config:
+ hosts:
+ - hostname: 172.16.1.27
+ filtered: true
+ state: overridden
+
+# Commands Fired:
+# ---------------
+# "commands": [
+# "no logging message-counter log",
+# "no logging host 172.16.1.12",
+# "no logging host 172.16.1.10",
+# "no logging host 172.16.1.13",
+# "no logging exception 4099",
+# "no logging userinfo",
+# "no logging console xml critical",
+# "no logging monitor warnings",
+# "no logging cns-events warnings",
+# "no logging policy-firewall rate-limit 10",
+# "no logging dmvpn rate-limit 10",
+# "no logging trap errors",
+# "no logging buffered 6000 critical",
+# "no logging facility local6",
+# "logging host 172.16.1.27 filtered",
+# ],
+
+# After state:
+# ------------
+
+# router-ios#show running-config | section logging
+# no logging exception
+# no logging buffered
+# no logging reload
+# no logging rate-limit
+# no logging console
+# no logging monitor
+# no logging cns-events
+# no logging trap
+# logging host 172.16.1.27 filtered
+
+# Using state: replaced
+
+# Before state:
+# -------------
+
+# router-ios#show running-config | section logging
+# logging exception 4099
+# logging message-counter log
+# logging userinfo
+# logging buffered xml 5099 notifications
+# no logging reload
+# no logging rate-limit
+# logging console xml critical
+# logging monitor warnings
+# logging cns-events warnings
+# logging policy-firewall rate-limit 10
+# logging dmvpn rate-limit 10
+# logging trap errors
+# logging facility local5
+# logging snmp-trap errors
+# logging host 172.16.1.13 transport tcp port 514
+# logging host 172.16.1.11 xml
+# logging host 172.16.1.12
+# logging host 172.16.1.10 filtered stream 10
+
+- name: Replace commands with provided configuration
+ cisco.ios.ios_logging_global:
+ config:
+ buffered:
+ severity: alerts
+ size: 6025
+ facility: local6
+ hosts:
+ - hostname: 172.16.1.19
+ - hostname: 172.16.1.10
+ filtered: true
+ stream: 15
+ state: replaced
+
+# Commands Fired:
+# ---------------
+
+# "commands": [
+# "no logging host 172.16.1.13",
+# "no logging host 172.16.1.11",
+# "no logging host 172.16.1.12",
+# "no logging host 172.16.1.10",
+# "logging host 172.16.1.19",
+# "logging host 172.16.1.10 filtered stream 15",
+# "logging buffered 6025 alerts",
+# "logging facility local6"
+# ],
+
+# After state:
+# ------------
+
+# router-ios#show running-config | section logging
+# logging exception 4099
+# logging message-counter log
+# logging userinfo
+# logging buffered 6025 alerts
+# no logging reload
+# no logging rate-limit
+# logging console xml critical
+# logging monitor warnings
+# logging cns-events warnings
+# logging policy-firewall rate-limit 10
+# logging dmvpn rate-limit 10
+# logging trap errors
+# logging facility local6
+# logging snmp-trap errors
+# logging host 172.16.1.19
+
+# Using state: gathered
+
+# Before state:
+# -------------
+
+#router-ios#show running-config | section logging
+# logging exception 4099
+# logging message-counter log
+# logging userinfo
+# logging buffered xml 5099 notifications
+# no logging reload
+# no logging rate-limit
+# logging console xml critical
+# logging monitor warnings
+# logging cns-events warnings
+# logging policy-firewall rate-limit 10
+# logging dmvpn rate-limit 10
+# logging trap errors
+# logging facility local5
+# logging snmp-trap errors
+# logging host 172.16.1.13 transport tcp port 514
+# logging host 172.16.1.11 xml
+# logging host 172.16.1.12
+# logging host 172.16.1.10 filtered stream 10
+# logging host 172.16.1.25 filtered
+
+- name: Gather listed logging config
+ cisco.ios.ios_logging_global:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+
+# "gathered": {
+# "buffered": {
+# "severity": "notifications",
+# "size": 5099,
+# "xml": true
+# },
+# "cns_events": "warnings",
+# "console": {
+# "severity": "critical",
+# "xml": true
+# },
+# "dmvpn": {
+# "rate_limit": 10
+# },
+# "exception": 4099,
+# "facility": "local5",
+# "hosts": [
+# {
+# "hostname": "172.16.1.11",
+# "xml": true
+# },
+# {
+# "hostname": "172.16.1.12"
+# },
+# {
+# "filtered": true,
+# "hostname": "172.16.1.10",
+# "stream": 10
+# },
+# {
+# "hostname": "172.16.1.13",
+# "transport": {
+# "tcp": {
+# "port": 514
+# }
+# }
+# },
+# {
+# "filtered": true,
+# "hostname": "172.16.1.25"
+# }
+# ],
+# "message_counter": [
+# "log"
+# ],
+# "monitor": {
+# "severity": "warnings"
+# },
+# "policy_firewall": {
+# "rate_limit": 10
+# },
+# "snmp_trap": [
+# "errors"
+# ],
+# "trap": "errors",
+# "userinfo": true
+# },
+
+# After state:
+# -------------
+
+# router-ios#show running-config | section logging
+# logging exception 4099
+# logging message-counter log
+# logging userinfo
+# logging buffered xml 5099 notifications
+# no logging reload
+# no logging rate-limit
+# logging console xml critical
+# logging monitor warnings
+# logging cns-events warnings
+# logging policy-firewall rate-limit 10
+# logging dmvpn rate-limit 10
+# logging trap errors
+# logging facility local5
+# logging snmp-trap errors
+# logging host 172.16.1.13 transport tcp port 514
+# logging host 172.16.1.11 xml
+# logging host 172.16.1.12
+# logging host 172.16.1.10 filtered stream 10
+# logging host 172.16.1.25 filtered
+
+# Using state: rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_logging_global:
+ config:
+ buffered:
+ severity: notifications
+ size: 5099
+ xml: true
+ console:
+ severity: critical
+ xml: true
+ facility: local5
+ hosts:
+ - hostname: 172.16.1.12
+ - hostname: 172.16.1.11
+ xml: true
+ - hostname: 172.16.1.10
+ filtered: true
+ stream: 10
+ - hostname: 172.16.1.13
+ transport:
+ tcp:
+ port: 514
+ monitor:
+ severity: warnings
+ message_counter: log
+ snmp_trap: errors
+ trap: errors
+ userinfo: true
+ policy_firewall:
+ rate_limit: 10
+ logging_on: enable
+ exception: 10
+ dmvpn:
+ rate_limit: 10
+ cns_events: warnings
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+
+# "rendered": [
+# "logging host 172.16.1.12",
+# "logging host 172.16.1.11 xml",
+# "logging host 172.16.1.10 filtered stream 10",
+# "logging host 172.16.1.13 transport tcp port 514",
+# "logging message-counter log",
+# "logging snmp-trap errors",
+# "logging buffered xml 5099 notifications",
+# "logging console xml critical",
+# "logging facility local5",
+# "logging monitor warnings",
+# "logging trap errors",
+# "logging userinfo",
+# "logging policy-firewall rate-limit 10",
+# "logging on",
+# "logging exception 10",
+# "logging dmvpn rate-limit 10",
+# "logging cns-events warnings"
+# ]
+
+# Using state: parsed
+
+# File: parsed.cfg
+# ----------------
+
+# logging on
+# logging count
+# logging userinfo
+# logging trap errors
+# logging reload alerts
+# logging host 172.16.1.1
+# logging exception 4099
+# logging history alerts
+# logging facility local5
+# logging snmp-trap errors
+# logging monitor warnings
+# logging origin-id hostname
+# logging host 172.16.1.11 xml
+# logging cns-events warnings
+# logging dmvpn rate-limit 10
+# logging message-counter log
+# logging console xml critical
+# logging message-counter debug
+# logging persistent batch 4444
+# logging host 172.16.1.25 filtered
+# logging source-interface GBit1/0
+# logging source-interface CTunnel2
+# logging policy-firewall rate-limit 10
+# logging buffered xml 5099 notifications
+# logging rate-limit all 2 except warnings
+# logging host 172.16.1.10 filtered stream 10
+# logging host 172.16.1.13 transport tcp port 514
+# logging discriminator msglog01 severity includes 5
+# logging filter tftp://172.16.2.18/ESM/elate.tcl args TESTInst2
+# logging filter tftp://172.16.2.14/ESM/escalate.tcl args TESTInst
+
+- name: Parse the provided configuration with the existing running configuration
+ cisco.ios.ios_logging_global:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+
+# "parsed": {
+# "buffered": {
+# "severity": "notifications",
+# "size": 5099,
+# "xml": true
+# },
+# "cns_events": "warnings",
+# "console": {
+# "severity": "critical",
+# "xml": true
+# },
+# "count": true,
+# "discriminator": [
+# "msglog01 severity includes 5"
+# ],
+# "dmvpn": {
+# "rate_limit": 10
+# },
+# "exception": 4099,
+# "facility": "local5",
+# "filter": [
+# {
+# "args": "TESTInst2",
+# "url": "tftp://172.16.2.18/ESM/elate.tcl"
+# },
+# {
+# "args": "TESTInst",
+# "url": "tftp://172.16.2.14/ESM/escalate.tcl"
+# }
+# ],
+# "history": {
+# "severity": "alerts"
+# },
+# "hosts": [
+# {
+# "hostname": "172.16.1.1"
+# },
+# {
+# "hostname": "172.16.1.11",
+# "xml": true
+# },
+# {
+# "filtered": true,
+# "hostname": "172.16.1.25"
+# },
+# {
+# "filtered": true,
+# "hostname": "172.16.1.10",
+# "stream": 10
+# },
+# {
+# "hostname": "172.16.1.13",
+# "transport": {
+# "tcp": {
+# "port": 514
+# }
+# }
+# }
+# ],
+# "logging_on": "enable",
+# "message_counter": [
+# "log",
+# "debug"
+# ],
+# "monitor": {
+# "severity": "warnings"
+# },
+# "origin_id": {
+# "tag": "hostname"
+# },
+# "persistent": {
+# "batch": 4444
+# },
+# "policy_firewall": {
+# "rate_limit": 10
+# },
+# "rate_limit": {
+# "all": true,
+# "except_severity": "warnings",
+# "size": 2
+# },
+# "reload": {
+# "severity": "alerts"
+# },
+# "snmp_trap": [
+# "errors"
+# ],
+# "source_interface": [
+# {
+# "interface": "GBit1/0"
+# },
+# {
+# "interface": "CTunnel2"
+# }
+# ],
+# "trap": "errors",
+# "userinfo": true
+# }
+"""
+
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: dict
+after:
+ description: The resulting configuration model invocation.
+ returned: when changed
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: dict
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: always
+ type: list
+ sample:
+ - "logging on"
+ - "logging userinfo"
+ - "logging trap errors"
+ - "logging host 172.16.1.12"
+ - "logging console xml critical"
+ - "logging message-counter log"
+ - "logging policy-firewall rate-limit 10"
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.logging_global.logging_global import (
+ Logging_globalArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.logging_global.logging_global import (
+ Logging_global,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ module = AnsibleModule(
+ argument_spec=Logging_globalArgs.argument_spec,
+ mutually_exclusive=[["config", "running_config"]],
+ required_if=[
+ ["state", "merged", ["config"]],
+ ["state", "replaced", ["config"]],
+ ["state", "overridden", ["config"]],
+ ["state", "rendered", ["config"]],
+ ["state", "parsed", ["running_config"]],
+ ],
+ supports_check_mode=True,
+ )
+
+ result = Logging_global(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_ntp.py b/ansible_collections/cisco/ios/plugins/modules/ios_ntp.py
new file mode 100644
index 000000000..2eeb2b088
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_ntp.py
@@ -0,0 +1,356 @@
+#!/usr/bin/python
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_ntp
+extends_documentation_fragment:
+ - cisco.ios.ios
+short_description: (deprecated, removed after 2024-01-01) Manages core NTP configuration.
+description:
+ - Manages core NTP configuration.
+version_added: 1.0.0
+deprecated:
+ alternative: ios_ntp_global
+ why: Updated module released with more functionality.
+ removed_at_date: "2024-01-01"
+author:
+ - Federico Olivieri (@Federico87)
+ - Joanie Sylvain (@JoanieAda)
+options:
+ server:
+ description:
+ - Network address of NTP server.
+ type: str
+ source_int:
+ description:
+ - Source interface for NTP packets.
+ type: str
+ acl:
+ description:
+ - ACL for peer/server access restricition.
+ type: str
+ logging:
+ description:
+ - Enable NTP logs. Data type boolean.
+ type: bool
+ default: false
+ auth:
+ description:
+ - Enable NTP authentication. Data type boolean.
+ type: bool
+ default: false
+ auth_key:
+ description:
+ - md5 NTP authentication key of tye 7.
+ type: str
+ key_id:
+ description:
+ - auth_key id. Data type string
+ type: str
+ state:
+ description:
+ - Manage the state of the resource.
+ default: present
+ choices:
+ - present
+ - absent
+ type: str
+ vrf:
+ description:
+ - VRF configuration for NTP servers
+ type: str
+"""
+
+EXAMPLES = """
+# Set new NTP server and source interface
+- name: Example ntp play
+ cisco.ios.ios_ntp:
+ server: 10.0.255.10
+ source_int: Loopback0
+ logging: false
+ state: present
+
+# Remove NTP ACL and logging
+- name: Example ntp play absent
+ cisco.ios.ios_ntp:
+ acl: NTP_ACL
+ logging: true
+ state: absent
+
+# Set NTP authentication
+- name: Example ntp play auth
+ cisco.ios.ios_ntp:
+ key_id: 10
+ auth_key: 15435A030726242723273C21181319000A
+ auth: true
+ state: present
+
+# Set new NTP configuration
+- name: Example ntp play auth
+ cisco.ios.ios_ntp:
+ server: 10.0.255.10
+ source_int: Loopback0
+ acl: NTP_ACL
+ logging: true
+ vrf: mgmt
+ key_id: 10
+ auth_key: 15435A030726242723273C21181319000A
+ auth: true
+ state: present
+
+"""
+RETURN = """
+commands:
+ description: command sent to the device
+ returned: always
+ type: list
+ sample: ["no ntp server 10.0.255.10", "no ntp source Loopback0"]
+"""
+import re
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ get_config,
+ load_config,
+)
+
+
+def parse_server(line, dest):
+ if dest == "server":
+ vrf, server = None, None
+ match = re.search(
+ "(ntp\\sserver\\s)(vrf\\s\\w+\\s)?(\\d+\\.\\d+\\.\\d+\\.\\d+)",
+ line,
+ re.M,
+ )
+
+ if match and match.group(2) and match.group(3):
+ vrf = match.group(2)
+ server = match.group(3)
+ return vrf, server
+
+ if match and match.group(3):
+ server = match.group(3)
+ return vrf, server
+
+
+def parse_source_int(line, dest):
+ if dest == "source":
+ match = re.search("(ntp\\ssource\\s)(\\S+)", line, re.M)
+ if match:
+ source = match.group(2)
+ return source
+
+
+def parse_acl(line, dest):
+ if dest == "access-group":
+ match = re.search("ntp\\saccess-group\\s(?:peer|serve)(?:\\s+)(\\S+)", line, re.M)
+ if match:
+ acl = match.group(1)
+ return acl
+
+
+def parse_logging(line, dest):
+ if dest == "logging":
+ logging = dest
+ return logging
+
+
+def parse_auth_key(line, dest):
+ if dest == "authentication-key":
+ match = re.search("(ntp\\sauthentication-key\\s\\d+\\smd5\\s)(\\w+)", line, re.M)
+ if match:
+ auth_key = match.group(2)
+ return auth_key
+
+
+def parse_key_id(line, dest):
+ if dest == "trusted-key":
+ match = re.search("(ntp\\strusted-key\\s)(\\d+)", line, re.M)
+ if match:
+ auth_key = match.group(2)
+ return auth_key
+
+
+def parse_auth(dest):
+ if dest == "authenticate":
+ return dest
+
+
+def map_config_to_obj(module):
+ obj_dict = dict()
+ obj = list()
+ server_list = list()
+ config = get_config(module, flags=["| include ntp"])
+ for line in config.splitlines():
+ match = re.search("ntp\\s(\\S+)", line, re.M)
+
+ if match:
+ dest = match.group(1)
+ server = parse_server(line, dest)
+ source_int = parse_source_int(line, dest)
+ acl = parse_acl(line, dest)
+ logging = parse_logging(line, dest)
+ auth = parse_auth(dest)
+ auth_key = parse_auth_key(line, dest)
+ key_id = parse_key_id(line, dest)
+
+ if server:
+ if server[0] is None:
+ server_list.append((server[0], server[1]))
+ else:
+ server_list.append((server[0].split()[1], server[1]))
+ if source_int:
+ obj_dict["source_int"] = source_int
+ if acl:
+ obj_dict["acl"] = acl
+ if logging:
+ obj_dict["logging"] = True
+ if auth:
+ obj_dict["auth"] = True
+ if auth_key:
+ obj_dict["auth_key"] = auth_key
+ if key_id:
+ obj_dict["key_id"] = key_id
+ obj_dict["server"] = server_list
+ obj.append(obj_dict)
+ return obj
+
+
+def map_params_to_obj(module):
+ obj = list()
+
+ obj.append(
+ {
+ "state": module.params["state"],
+ "server": module.params["server"],
+ "source_int": module.params["source_int"],
+ "logging": module.params["logging"],
+ "acl": module.params["acl"],
+ "auth": module.params["auth"],
+ "auth_key": module.params["auth_key"],
+ "key_id": module.params["key_id"],
+ "vrf": module.params["vrf"],
+ },
+ )
+
+ return obj
+
+
+def map_obj_to_commands(want, have, module):
+ commands = list()
+
+ server_have = have[0].get("server", None)
+ source_int_have = have[0].get("source_int", None)
+ acl_have = have[0].get("acl", None)
+ logging_have = have[0].get("logging", None)
+ auth_have = have[0].get("auth", None)
+ auth_key_have = have[0].get("auth_key", None)
+ key_id_have = have[0].get("key_id", None)
+
+ for w in want:
+ server = w["server"]
+ source_int = w["source_int"]
+ acl = w["acl"]
+ logging = w["logging"]
+ state = w["state"]
+ auth = w["auth"]
+ auth_key = w["auth_key"]
+ key_id = w["key_id"]
+ vrf = w["vrf"]
+ if vrf == "":
+ vrf = None
+
+ if state == "absent":
+ if server_have and (vrf, server) in server_have:
+ if vrf is not None:
+ commands.append("no ntp server vrf {0} {1}".format(vrf, server))
+ else:
+ commands.append("no ntp server {0}".format(server))
+ if source_int and source_int_have:
+ commands.append("no ntp source {0}".format(source_int))
+ if acl and acl_have:
+ commands.append("no ntp access-group peer {0}".format(acl))
+ if logging is True and logging_have:
+ commands.append("no ntp logging")
+ if auth is True and auth_have:
+ commands.append("no ntp authenticate")
+ if key_id and key_id_have:
+ commands.append("no ntp trusted-key {0}".format(key_id))
+ if auth_key and auth_key_have:
+ if key_id and key_id_have:
+ commands.append(
+ "no ntp authentication-key {0} md5 {1} 7".format(key_id, auth_key),
+ )
+ elif state == "present":
+ if server is not None and (vrf, server) not in server_have:
+ if vrf is not None:
+ commands.append("ntp server vrf {0} {1}".format(vrf, server))
+ else:
+ commands.append("ntp server {0}".format(server))
+ if source_int is not None and source_int != source_int_have:
+ commands.append("ntp source {0}".format(source_int))
+ if acl is not None and acl != acl_have:
+ commands.append("ntp access-group peer {0}".format(acl))
+ if logging is not None and logging != logging_have and logging is not False:
+ commands.append("ntp logging")
+ if auth is not None and auth != auth_have and auth is not False:
+ commands.append("ntp authenticate")
+ if key_id is not None and key_id != key_id_have:
+ commands.append("ntp trusted-key {0}".format(key_id))
+ if auth_key is not None and auth_key != auth_key_have:
+ if key_id is not None:
+ commands.append("ntp authentication-key {0} md5 {1} 7".format(key_id, auth_key))
+ return commands
+
+
+def main():
+ argument_spec = dict(
+ server=dict(),
+ source_int=dict(),
+ acl=dict(),
+ logging=dict(type="bool", default=False),
+ auth=dict(type="bool", default=False),
+ auth_key=dict(no_log=True),
+ key_id=dict(),
+ state=dict(choices=["absent", "present"], default="present"),
+ vrf=dict(),
+ )
+ module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
+ result = {"changed": False}
+ warnings = list()
+ if warnings:
+ result["warnings"] = warnings
+ want = map_params_to_obj(module)
+ have = map_config_to_obj(module)
+ commands = map_obj_to_commands(want, have, module)
+ result["commands"] = commands
+ if commands:
+ if not module.check_mode:
+ load_config(module, commands)
+ result["changed"] = True
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_ntp_global.py b/ansible_collections/cisco/ios/plugins/modules/ios_ntp_global.py
new file mode 100644
index 000000000..87c37a25f
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_ntp_global.py
@@ -0,0 +1,1097 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2021 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+"""
+The module file for ios_ntp_global
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_ntp_global
+short_description: Resource module to configure NTP.
+description:
+ - This module provides declarative management of ntp on Cisco IOS devices.
+version_added: 2.5.0
+author:
+ - Sagar Paul (@KB-perByte)
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+options:
+ config:
+ description: A dictionary of ntp options
+ type: dict
+ suboptions:
+ access_group:
+ description: Control NTP access
+ type: dict
+ suboptions:
+ peer:
+ description: Provide full access
+ type: list
+ elements: dict
+ suboptions:
+ access_list: &access_group_acl
+ description: name or number of access list
+ type: str
+ kod: &kod
+ description: Send a Kiss-o-Death packet for failing peers
+ type: bool
+ ipv4: &ipv4
+ description: ipv4 access lists (Default not idempotent)
+ type: bool
+ ipv6: &ipv6
+ description: ipv6 access lists (Default not idempotent)
+ type: bool
+ query_only:
+ description: Allow only control queries
+ type: list
+ elements: dict
+ suboptions:
+ access_list: *access_group_acl
+ kod: *kod
+ ipv4: *ipv4
+ ipv6: *ipv6
+ serve:
+ description: Provide server and query access
+ type: list
+ elements: dict
+ suboptions:
+ access_list: *access_group_acl
+ kod: *kod
+ ipv4: *ipv4
+ ipv6: *ipv6
+ serve_only:
+ description: Provide only server access
+ type: list
+ elements: dict
+ suboptions:
+ access_list: *access_group_acl
+ kod: *kod
+ ipv4: *ipv4
+ ipv6: *ipv6
+ allow:
+ description: Allow processing of packets
+ type: dict
+ suboptions:
+ control:
+ description: Allow processing control mode packets
+ type: dict
+ suboptions:
+ rate_limit:
+ description: Rate-limit delay.
+ type: int
+ private:
+ description: Allow processing private mode packets
+ type: bool
+ authenticate:
+ description: Authenticate time sources
+ type: bool
+ authentication_keys:
+ description: Authentication key for trusted time sources
+ type: list
+ elements: dict
+ suboptions:
+ id:
+ description: Key number
+ type: int
+ algorithm:
+ description: Authentication type
+ type: str
+ key:
+ description: Password
+ type: str
+ encryption:
+ description: Authentication key encryption type
+ type: int
+ broadcast_delay:
+ description: Estimated round-trip delay
+ type: int
+ clock_period:
+ description: Length of hardware clock tick, clock period in 2^-32 seconds
+ type: int
+ logging:
+ description: Enable NTP message logging
+ type: bool
+ master:
+ description: Act as NTP master clock
+ type: dict
+ suboptions:
+ enabled:
+ description: Enable master clock
+ type: bool
+ stratum:
+ description: Stratum number
+ type: int
+ max_associations:
+ description: Set maximum number of associations
+ type: int
+ max_distance:
+ description: Maximum Distance for synchronization
+ type: int
+ min_distance:
+ description: Minimum distance to consider for clockhop
+ type: int
+ orphan:
+ description: Threshold Stratum for orphan mode
+ type: int
+ panic_update:
+ description: Reject time updates > panic threshold (default 1000Sec)
+ type: bool
+ passive:
+ description: NTP passive mode
+ type: bool
+ peers:
+ description: Configure NTP peer
+ type: list
+ elements: dict
+ suboptions:
+ peer:
+ description: ipv4/ipv6 address or hostname of the peer
+ type: str
+ use_ipv4: &use_ipv4
+ description: Use IP for DNS resolution
+ type: bool
+ use_ipv6: &use_ipv6
+ description: Use IPv6 for DNS resolution
+ type: bool
+ vrf: &vrf
+ description: VPN Routing/Forwarding Information
+ type: str
+ burst: &burst
+ description: Send a burst when peer is reachable (Default)
+ type: bool
+ iburst: &iburst
+ description: Send a burst when peer is unreachable (Default)
+ type: bool
+ key_id: &key
+ description: Configure peer authentication key
+ type: int
+ aliases:
+ - key
+ maxpoll: &maxpoll
+ description: Maximum poll interval Poll value in Log2
+ type: int
+ minpoll: &minpoll
+ description: Minimum poll interval Poll value in Log2
+ type: int
+ normal_sync: &normal_sync
+ description: Disable rapid sync at startup
+ type: bool
+ prefer: &prefer
+ description: Prefer this peer when possible
+ type: bool
+ source: &source
+ description: Interface for source address
+ type: str
+ version: &version
+ description: Configure NTP version
+ type: int
+ servers:
+ description: Configure NTP server
+ type: list
+ elements: dict
+ suboptions:
+ server:
+ description: ipv4/ipv6 address or hostname of the server
+ type: str
+ use_ipv4: *use_ipv4
+ use_ipv6: *use_ipv6
+ vrf: *vrf
+ burst: *burst
+ iburst: *iburst
+ key_id: *key
+ maxpoll: *maxpoll
+ minpoll: *minpoll
+ normal_sync: *normal_sync
+ prefer: *prefer
+ source: *source
+ version: *version
+ source:
+ description: Configure interface for source address
+ type: str
+ trusted_keys:
+ description: Key numbers for trusted time sources
+ type: list
+ elements: dict
+ suboptions:
+ range_start:
+ description: Start / key number
+ type: int
+ range_end:
+ description: End key number
+ type: int
+ update_calendar:
+ description: Periodically update calendar with NTP time
+ type: bool
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device
+ by executing the command B(show running-config | section ^ntp).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - rendered
+ - gathered
+ - parsed
+ default: merged
+ description:
+ - The state the configuration should be left in
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device.
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result. For state I(rendered) active connection to remote host is
+ not required.
+ - The states I(replaced) and I(overridden) have identical
+ behaviour for this module.
+ - The state I(gathered) will fetch the running configuration from device and transform
+ it into structured data in the format as per the resource module argspec and
+ the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result. The value of C(running_config)
+ option should be the same format as the output of command
+ I(show running-config | section ^ntp) executed on device. For state I(parsed) active
+ connection to remote host is not required.
+ type: str
+"""
+
+EXAMPLES = """
+# Using state: merged
+
+# Before state:
+# -------------
+
+# router-ios#show running-config | section ^ntp
+# --------------------- EMPTY -----------------
+
+# Merged play:
+# ------------
+
+- name: Apply the provided configuration
+ cisco.ios.ios_ntp_global:
+ config:
+ access_group:
+ peer:
+ - access_list: DHCP-Server
+ ipv4: true
+ kod: true
+ - access_list: preauth_ipv6_acl
+ ipv6: true
+ kod: true
+ - access_list: "2"
+ kod: true
+ query_only:
+ - access_list: "10"
+ allow:
+ control:
+ rate_limit: 4
+ private: true
+ authenticate: true
+ authentication_keys:
+ - algorithm: md5
+ encryption: 22
+ id: 2
+ key: SomeSecurePassword
+ broadcast_delay: 22
+ clock_period: 5
+ logging: true
+ master:
+ stratum: 4
+ max_associations: 34
+ max_distance: 3
+ min_distance: 10
+ orphan: 4
+ panic_update: true
+ peers:
+ - peer: 172.16.1.10
+ version: 2
+ - key: 2
+ minpoll: 5
+ peer: 172.16.1.11
+ prefer: true
+ version: 2
+ - peer: checkPeerDomainIpv4.com
+ prefer: true
+ use_ipv4: true
+ - peer: checkPeerDomainIpv6.com
+ use_ipv6: true
+ - peer: testPeerDomainIpv6.com
+ prefer: true
+ use_ipv6: true
+ servers:
+ - server: 172.16.1.12
+ version: 2
+ - server: checkServerDomainIpv6.com
+ use_ipv6: true
+ - server: 172.16.1.13
+ source: GigabitEthernet0/1
+ source: GigabitEthernet0/1
+ trusted_keys:
+ - range_end: 3
+ range_start: 3
+ - range_start: 21
+ state: merged
+
+# Commands Fired:
+# ---------------
+
+# "commands": [
+# "ntp allow mode control 4",
+# "ntp allow mode private",
+# "ntp authenticate",
+# "ntp broadcastdelay 22",
+# "ntp clock-period 5",
+# "ntp logging",
+# "ntp master 4",
+# "ntp max-associations 34",
+# "ntp maxdistance 3",
+# "ntp mindistance 10",
+# "ntp orphan 4",
+# "ntp panic update",
+# "ntp source GigabitEthernet0/1",
+# "ntp access-group ipv4 peer DHCP-Server kod",
+# "ntp access-group ipv6 peer preauth_ipv6_acl kod",
+# "ntp access-group peer 2 kod",
+# "ntp access-group query-only 10",
+# "ntp authentication-key 2 md5 SomeSecurePassword 22",
+# "ntp peer 172.16.1.10 version 2",
+# "ntp peer 172.16.1.11 key 2 minpoll 5 prefer version 2",
+# "ntp peer ip checkPeerDomainIpv4.com prefer",
+# "ntp peer ipv6 checkPeerDomainIpv6.com",
+# "ntp peer ipv6 testPeerDomainIpv6.com prefer",
+# "ntp server 172.16.1.12 version 2",
+# "ntp server ipv6 checkServerDomainIpv6.com",
+# "ntp server 172.16.1.13 source GigabitEthernet0/1",
+# "ntp trusted-key 3 - 3",
+# "ntp trusted-key 21"
+# ],
+
+# After state:
+# ------------
+
+# router-ios#show running-config | section ^ntp
+# ntp max-associations 34
+# ntp logging
+# ntp allow mode control 4
+# ntp panic update
+# ntp authentication-key 2 md5 0635002C497D0C1A1005173B0D17393C2B3A37 7
+# ntp authenticate
+# ntp trusted-key 3 - 3
+# ntp trusted-key 21
+# ntp orphan 4
+# ntp mindistance 10
+# ntp maxdistance 3
+# ntp broadcastdelay 22
+# ntp source GigabitEthernet0/1
+# ntp access-group peer 2 kod
+# ntp access-group ipv6 peer preauth_ipv6_acl kod
+# ntp master 4
+# ntp peer 172.16.1.10 version 2
+# ntp peer 172.16.1.11 key 2 minpoll 5 prefer version 2
+# ntp server 172.16.1.12 version 2
+# ntp server 172.16.1.13 source GigabitEthernet0/1
+# ntp peer ip checkPeerDomainIpv4.com prefer
+# ntp peer ipv6 checkPeerDomainIpv6.com
+# ntp peer ipv6 testPeerDomainIpv6.com prefer
+# ntp server ipv6 checkServerDomainIpv6.com
+
+# Using state: deleted
+
+# Before state:
+# -------------
+
+# router-ios#show running-config | section ^ntp
+# ntp max-associations 34
+# ntp logging
+# ntp allow mode control 4
+# ntp panic update
+# ntp authentication-key 2 md5 0635002C497D0C1A1005173B0D17393C2B3A37 7
+# ntp authenticate
+# ntp trusted-key 3 - 3
+# ntp trusted-key 21
+# ntp orphan 4
+# ntp mindistance 10
+# ntp maxdistance 3
+# ntp broadcastdelay 22
+# ntp source GigabitEthernet0/1
+# ntp access-group peer 2 kod
+# ntp access-group ipv6 peer preauth_ipv6_acl kod
+# ntp master 4
+# ntp peer 172.16.1.10 version 2
+# ntp peer 172.16.1.11 key 2 minpoll 5 prefer version 2
+# ntp server 172.16.1.12 version 2
+# ntp server 172.16.1.13 source GigabitEthernet0/1
+# ntp peer ip checkPeerDomainIpv4.com prefer
+# ntp peer ipv6 checkPeerDomainIpv6.com
+# ntp peer ipv6 testPeerDomainIpv6.com prefer
+# ntp server ipv6 checkServerDomainIpv6.com
+
+# Deleted play:
+# -------------
+
+- name: Remove all existing configuration
+ cisco.ios.ios_ntp_global:
+ state: deleted
+
+# Commands Fired:
+# ---------------
+
+# "commands": [
+# "no ntp allow mode control 4",
+# "no ntp authenticate",
+# "no ntp broadcastdelay 22",
+# "no ntp logging",
+# "no ntp master 4",
+# "no ntp max-associations 34",
+# "no ntp maxdistance 3",
+# "no ntp mindistance 10",
+# "no ntp orphan 4",
+# "no ntp panic update",
+# "no ntp source GigabitEthernet0/1",
+# "no ntp access-group peer 2 kod",
+# "no ntp access-group ipv6 peer preauth_ipv6_acl kod",
+# "no ntp authentication-key 2 md5 0635002C497D0C1A1005173B0D17393C2B3A37 7",
+# "no ntp peer 172.16.1.10 version 2",
+# "no ntp peer 172.16.1.11 key 2 minpoll 5 prefer version 2",
+# "no ntp peer ip checkPeerDomainIpv4.com prefer",
+# "no ntp peer ipv6 checkPeerDomainIpv6.com",
+# "no ntp peer ipv6 testPeerDomainIpv6.com prefer",
+# "no ntp server 172.16.1.12 version 2",
+# "no ntp server 172.16.1.13 source GigabitEthernet0/1",
+# "no ntp server ipv6 checkServerDomainIpv6.com",
+# "no ntp trusted-key 21",
+# "no ntp trusted-key 3 - 3"
+# ],
+
+# After state:
+# ------------
+
+# router-ios#show running-config | section ^ntp
+# --------------------- EMPTY -----------------
+
+# Using state: overridden
+
+# Before state:
+# -------------
+
+# router-ios#show running-config | section ^ntp
+# ntp panic update
+# ntp authentication-key 2 md5 00371C0B01680E051A33497E080A16001D1908 7
+# ntp authenticate
+# ntp trusted-key 3 - 4
+# ntp trusted-key 21
+# ntp source GigabitEthernet0/1
+# ntp peer 172.16.1.10 version 2
+# ntp server 172.16.1.12 version 2
+# ntp peer ip checkPeerDomainIpv4.com prefer
+# ntp server ipv6 checkServerDomainIpv6.com
+
+# Overridden play:
+# ----------------
+
+- name: Override commands with provided configuration
+ cisco.ios.ios_ntp_global:
+ config:
+ peers:
+ - peer: ipv6DomainNew.com
+ use_ipv6: true
+ - peer: 172.16.1.100
+ prefer: true
+ use_ipv4: true
+ access_group:
+ peer:
+ - access_list: DHCP-Server
+ ipv6: true
+ state: overridden
+
+# Commands Fired:
+# ---------------
+# "commands": [
+# "no ntp authenticate",
+# "no ntp panic update",
+# "no ntp source GigabitEthernet0/1",
+# "ntp access-group ipv6 peer DHCP-Server",
+# "no ntp authentication-key 2 md5 00371C0B01680E051A33497E080A16001D1908 7",
+# "ntp peer ipv6 ipv6DomainNew.com",
+# "ntp peer 172.16.1.100 prefer",
+# "no ntp peer 172.16.1.10 version 2",
+# "no ntp peer ip checkPeerDomainIpv4.com prefer",
+# "no ntp server 172.16.1.12 version 2",
+# "no ntp server ipv6 checkServerDomainIpv6.com",
+# "no ntp trusted-key 21",
+# "no ntp trusted-key 3 - 4"
+# ],
+
+# After state:
+# ------------
+
+# router-ios#show running-config | section ^ntp
+# ntp access-group ipv6 peer DHCP-Server
+# ntp peer ipv6 ipv6DomainNew.com
+# ntp peer 172.16.1.100 prefer
+
+# Using state: replaced
+
+# Before state:
+# -------------
+
+# router-ios#show running-config | section ^ntp
+# ntp access-group ipv6 peer DHCP-Server
+# ntp peer ipv6 ipv6DomainNew.com
+# ntp peer 172.16.1.100 prefer
+
+# Replaced play:
+# --------------
+
+- name: Replace commands with provided configuration
+ cisco.ios.ios_ntp_global:
+ config:
+ broadcast_delay: 22
+ clock_period: 5
+ logging: true
+ master:
+ stratum: 4
+ max_associations: 34
+ max_distance: 3
+ min_distance: 10
+ orphan: 4
+ state: replaced
+
+# Commands Fired:
+# ---------------
+
+# "commands": [
+# "ntp broadcastdelay 22",
+# "ntp clock-period 5",
+# "ntp logging",
+# "ntp master 4",
+# "ntp max-associations 34",
+# "ntp maxdistance 3",
+# "ntp mindistance 10",
+# "ntp orphan 4",
+# "no ntp access-group ipv6 peer DHCP-Server",
+# "no ntp peer 172.16.1.100 prefer",
+# "no ntp peer ipv6 ipv6DomainNew.com"
+# ],
+
+# After state:
+# ------------
+
+# router-ios#show running-config | section ^ntp
+# ntp max-associations 34
+# ntp logging
+# ntp orphan 4
+# ntp mindistance 10
+# ntp maxdistance 3
+# ntp broadcastdelay 22
+# ntp master 4
+
+# Using state: gathered
+
+# Before state:
+# -------------
+
+#router-ios#show running-config | section ^ntp
+# ntp max-associations 34
+# ntp logging
+# ntp allow mode control 4
+# ntp panic update
+# ntp authentication-key 2 md5 0635002C497D0C1A1005173B0D17393C2B3A37 7
+# ntp authenticate
+# ntp trusted-key 3 - 3
+# ntp trusted-key 21
+# ntp orphan 4
+# ntp mindistance 10
+# ntp maxdistance 3
+# ntp broadcastdelay 22
+# ntp source GigabitEthernet0/1
+# ntp access-group peer 2 kod
+# ntp access-group ipv6 peer preauth_ipv6_acl kod
+# ntp master 4
+# ntp update-calendar
+# ntp peer 172.16.1.10 version 2
+# ntp peer 172.16.1.11 key 2 minpoll 5 prefer version 2
+# ntp server 172.16.1.12 version 2
+# ntp server 172.16.1.13 source GigabitEthernet0/1
+# ntp peer ip checkPeerDomainIpv4.com prefer
+# ntp peer ipv6 checkPeerDomainIpv6.com
+# ntp peer ipv6 testPeerDomainIpv6.com prefer
+# ntp server ipv6 checkServerDomainIpv6.com
+
+# Gathered play:
+# --------------
+
+- name: Gather listed ntp config
+ cisco.ios.ios_ntp_global:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+
+# "gathered": {
+# "access_group": {
+# "peer": [
+# {
+# "access_list": "2",
+# "kod": true
+# },
+# {
+# "access_list": "preauth_ipv6_acl",
+# "ipv6": true,
+# "kod": true
+# }
+# ]
+# },
+# "allow": {
+# "control": {
+# "rate_limit": 4
+# }
+# },
+# "authenticate": true,
+# "authentication_keys": [
+# {
+# "algorithm": "md5",
+# "encryption": 7,
+# "id": 2,
+# "key": "0635002C497D0C1A1005173B0D17393C2B3A37"
+# }
+# ],
+# "broadcast_delay": 22,
+# "logging": true,
+# "master": {
+# "stratum": 4
+# },
+# "max_associations": 34,
+# "max_distance": 3,
+# "min_distance": 10,
+# "orphan": 4,
+# "panic_update": true,
+# "peers": [
+# {
+# "peer": "172.16.1.10",
+# "version": 2
+# },
+# {
+# "key": 2,
+# "minpoll": 5,
+# "peer": "172.16.1.11",
+# "prefer": true,
+# "version": 2
+# },
+# {
+# "peer": "checkPeerDomainIpv4.com",
+# "prefer": true,
+# "use_ipv4": true
+# },
+# {
+# "peer": "checkPeerDomainIpv6.com",
+# "use_ipv6": true
+# },
+# {
+# "peer": "testPeerDomainIpv6.com",
+# "prefer": true,
+# "use_ipv6": true
+# }
+# ],
+# "servers": [
+# {
+# "server": "172.16.1.12",
+# "version": 2
+# },
+# {
+# "server": "172.16.1.13",
+# "source": "GigabitEthernet0/1"
+# },
+# {
+# "server": "checkServerDomainIpv6.com",
+# "use_ipv6": true
+# }
+# ],
+# "source": "GigabitEthernet0/1",
+# "trusted_keys": [
+# {
+# "range_start": 21
+# },
+# {
+# "range_end": 3,
+# "range_start": 3
+# }
+# ],
+# "update_calendar": true
+# },
+
+# After state:
+# -------------
+
+# router-ios#show running-config | section ^ntp
+# ntp max-associations 34
+# ntp logging
+# ntp allow mode control 4
+# ntp panic update
+# ntp authentication-key 2 md5 0635002C497D0C1A1005173B0D17393C2B3A37 7
+# ntp authenticate
+# ntp trusted-key 3 - 3
+# ntp trusted-key 21
+# ntp orphan 4
+# ntp mindistance 10
+# ntp maxdistance 3
+# ntp broadcastdelay 22
+# ntp source GigabitEthernet0/1
+# ntp access-group peer 2 kod
+# ntp access-group ipv6 peer preauth_ipv6_acl kod
+# ntp master 4
+# ntp update-calendar
+# ntp peer 172.16.1.10 version 2
+# ntp peer 172.16.1.11 key 2 minpoll 5 prefer version 2
+# ntp server 172.16.1.12 version 2
+# ntp server 172.16.1.13 source GigabitEthernet0/1
+# ntp peer ip checkPeerDomainIpv4.com prefer
+# ntp peer ipv6 checkPeerDomainIpv6.com
+# ntp peer ipv6 testPeerDomainIpv6.com prefer
+# ntp server ipv6 checkServerDomainIpv6.com
+
+# Using state: rendered
+
+# Rendered play:
+# --------------
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_ntp_global:
+ config:
+ access_group:
+ peer:
+ - access_list: DHCP-Server
+ ipv4: true
+ kod: true
+ - access_list: preauth_ipv6_acl
+ ipv6: true
+ kod: true
+ - access_list: "2"
+ kod: true
+ query_only:
+ - access_list: "10"
+ allow:
+ control:
+ rate_limit: 4
+ private: true
+ authenticate: true
+ authentication_keys:
+ - algorithm: md5
+ encryption: 22
+ id: 2
+ key: SomeSecurePassword
+ broadcast_delay: 22
+ clock_period: 5
+ logging: true
+ master:
+ stratum: 4
+ max_associations: 34
+ max_distance: 3
+ min_distance: 10
+ orphan: 4
+ panic_update: true
+ peers:
+ - peer: 172.16.1.10
+ version: 2
+ - key: 2
+ minpoll: 5
+ peer: 172.16.1.11
+ prefer: true
+ version: 2
+ - peer: checkPeerDomainIpv4.com
+ prefer: true
+ use_ipv4: true
+ - peer: checkPeerDomainIpv6.com
+ use_ipv6: true
+ - peer: testPeerDomainIpv6.com
+ prefer: true
+ use_ipv6: true
+ servers:
+ - server: 172.16.1.12
+ version: 2
+ - server: checkServerDomainIpv6.com
+ use_ipv6: true
+ - server: 172.16.1.13
+ source: GigabitEthernet0/1
+ source: GigabitEthernet0/1
+ trusted_keys:
+ - range_end: 3
+ range_start: 10
+ - range_start: 21
+ update_calendar: true
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+
+# "rendered": [
+# "ntp allow mode control 4",
+# "ntp allow mode private",
+# "ntp authenticate",
+# "ntp broadcastdelay 22",
+# "ntp clock-period 5",
+# "ntp logging",
+# "ntp master 4",
+# "ntp max-associations 34",
+# "ntp maxdistance 3",
+# "ntp mindistance 10",
+# "ntp orphan 4",
+# "ntp panic update",
+# "ntp source GigabitEthernet0/1",
+# "ntp update-calendar",
+# "ntp access-group ipv4 peer DHCP-Server kod",
+# "ntp access-group ipv6 peer preauth_ipv6_acl kod",
+# "ntp access-group peer 2 kod",
+# "ntp access-group query-only 10",
+# "ntp authentication-key 2 md5 SomeSecurePassword 22",
+# "ntp peer 172.16.1.10 version 2",
+# "ntp peer 172.16.1.11 key 2 minpoll 5 prefer version 2",
+# "ntp peer ip checkPeerDomainIpv4.com prefer",
+# "ntp peer ipv6 checkPeerDomainIpv6.com",
+# "ntp peer ipv6 testPeerDomainIpv6.com prefer",
+# "ntp server 172.16.1.12 version 2",
+# "ntp server ipv6 checkServerDomainIpv6.com",
+# "ntp server 172.16.1.13 source GigabitEthernet0/1",
+# "ntp trusted-key 3 - 3",
+# "ntp trusted-key 21"
+# ]
+
+# Using state: parsed
+
+# File: parsed.cfg
+# ----------------
+
+# ntp allow mode control 4
+# ntp allow mode private
+# ntp authenticate
+# ntp broadcastdelay 22
+# ntp clock-period 5
+# ntp logging
+# ntp master 4
+# ntp max-associations 34
+# ntp maxdistance 3
+# ntp mindistance 10
+# ntp orphan 4
+# ntp panic update
+# ntp source GigabitEthernet0/1
+# ntp update-calendar
+# ntp access-group ipv4 peer DHCP-Server kod
+# ntp access-group ipv6 peer preauth_ipv6_acl kod
+# ntp access-group peer 2 kod
+# ntp access-group query-only 10
+# ntp authentication-key 2 md5 SomeSecurePassword 22
+# ntp peer 172.16.1.10 version 2
+# ntp peer 172.16.1.11 key 2 minpoll 5 prefer version 2
+# ntp peer ip checkPeerDomainIpv4.com prefer
+# ntp peer ipv6 checkPeerDomainIpv6.com
+# ntp peer ipv6 testPeerDomainIpv6.com prefer
+# ntp server 172.16.1.12 version 2
+# ntp server ipv6 checkServerDomainIpv6.com
+# ntp server 172.16.1.13 source GigabitEthernet0/1
+# ntp trusted-key 3 - 13
+# ntp trusted-key 21
+
+# Parsed play:
+# ------------
+
+- name: Parse the provided configuration with the existing running configuration
+ cisco.ios.ios_ntp_global:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+
+# "parsed": {
+# "access_group": {
+# "peer": [
+# {
+# "access_list": "2",
+# "kod": true
+# },
+# {
+# "access_list": "DHCP-Server",
+# "ipv4": true,
+# "kod": true
+# },
+# {
+# "access_list": "preauth_ipv6_acl",
+# "ipv6": true,
+# "kod": true
+# }
+# ],
+# "query_only": [
+# {
+# "access_list": "10"
+# }
+# ]
+# },
+# "allow": {
+# "control": {
+# "rate_limit": 4
+# },
+# "private": true
+# },
+# "authenticate": true,
+# "authentication_keys": [
+# {
+# "algorithm": "md5",
+# "encryption": 22,
+# "id": 2,
+# "key": "SomeSecurePassword"
+# }
+# ],
+# "broadcast_delay": 22,
+# "clock_period": 5,
+# "logging": true,
+# "master": {
+# "stratum": 4
+# },
+# "max_associations": 34,
+# "max_distance": 3,
+# "min_distance": 10,
+# "orphan": 4,
+# "panic_update": true,
+# "peers": [
+# {
+# "peer": "172.16.1.10",
+# "version": 2
+# },
+# {
+# "peer": "checkPeerDomainIpv6.com",
+# "use_ipv6": true
+# }
+# ],
+# "servers": [
+# {
+# "server": "172.16.1.12",
+# "version": 2
+# },
+# {
+# "server": "172.16.1.13",
+# "source": "GigabitEthernet0/1"
+# },
+# {
+# "server": "checkServerDomainIpv6.com",
+# "use_ipv6": true
+# }
+# ],
+# "source": "GigabitEthernet0/1",
+# "trusted_keys": [
+# {
+# "range_start": 21
+# },
+# {
+# "range_end": 13,
+# "range_start": 3
+# }
+# ],
+# "update_calendar": true
+# }
+"""
+
+RETURN = """
+before:
+ description: The configuration prior to the module execution.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+after:
+ description: The resulting configuration after module execution.
+ returned: when changed
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: list
+ sample:
+ - ntp peer 20.18.11.3 key 6 minpoll 15 prefer version 2
+ - ntp access-group ipv4 peer DHCP-Server kod
+ - ntp trusted-key 9 - 96
+ - ntp master stratum 2
+ - ntp orphan 4
+ - ntp panic update
+rendered:
+ description: The provided configuration in the task rendered in device-native format (offline).
+ returned: when state is I(rendered)
+ type: list
+ sample:
+ - ntp master stratum 2
+ - ntp server ip testserver.com prefer
+ - ntp authentication-key 2 md5 testpass 22
+ - ntp allow mode control 4
+ - ntp max-associations 34
+ - ntp broadcastdelay 22
+gathered:
+ description: Facts about the network resource gathered from the remote device as structured data.
+ returned: when I(state) is C(gathered)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+parsed:
+ description: The device native config provided in I(running_config) option parsed into structured data as per module argspec.
+ returned: when I(state) is C(parsed)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.ntp_global.ntp_global import (
+ Ntp_globalArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.ntp_global.ntp_global import (
+ Ntp_global,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ module = AnsibleModule(
+ argument_spec=Ntp_globalArgs.argument_spec,
+ mutually_exclusive=[["config", "running_config"]],
+ required_if=[
+ ["state", "merged", ["config"]],
+ ["state", "replaced", ["config"]],
+ ["state", "overridden", ["config"]],
+ ["state", "rendered", ["config"]],
+ ["state", "parsed", ["running_config"]],
+ ],
+ supports_check_mode=True,
+ )
+
+ result = Ntp_global(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_ospf_interfaces.py b/ansible_collections/cisco/ios/plugins/modules/ios_ospf_interfaces.py
new file mode 100644
index 000000000..386020f3a
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_ospf_interfaces.py
@@ -0,0 +1,1107 @@
+#!/usr/bin/python
+# -*- 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)
+
+"""
+The module file for ios_ospf_interfaces
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_ospf_interfaces
+short_description: Resource module to configure OSPF interfaces.
+description:
+ This module configures and manages the Open Shortest Path First (OSPF)
+ version 2 on IOS platforms.
+version_added: 1.0.0
+author:
+ - Sagar Paul (@KB-perByte)
+ - Sumit Jaiswal (@justjais)
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ config:
+ description: A dictionary of OSPF interfaces options.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Full name of the interface excluding any logical unit number,
+ i.e. GigabitEthernet0/1.
+ type: str
+ required: true
+ address_family:
+ description:
+ - OSPF interfaces settings on the interfaces in address-family
+ context.
+ type: list
+ elements: dict
+ suboptions:
+ afi:
+ description:
+ - Address Family Identifier (AFI) for OSPF interfaces settings
+ on the interfaces.
+ type: str
+ choices:
+ - ipv4
+ - ipv6
+ required: true
+ process:
+ description: OSPF interfaces process config
+ type: dict
+ suboptions:
+ id:
+ description:
+ - Address Family Identifier (AFI) for OSPF interfaces settings
+ on the interfaces. Please refer vendor documentation of Valid
+ values.
+ type: int
+ area_id:
+ description:
+ - OSPF interfaces area ID as a decimal value. Please
+ refer vendor documentation of Valid values.
+ - OSPF interfaces area ID in IP address format(e.g.
+ A.B.C.D)
+ type: str
+ secondaries:
+ description:
+ - Include or exclude secondary IP addresses.
+ - Valid only with IPv4 config
+ type: bool
+ instance_id:
+ description:
+ - Set the OSPF instance based on ID
+ - Valid only with IPv6 OSPF config
+ type: int
+ adjacency:
+ description: Adjacency staggering
+ type: bool
+ authentication:
+ description: Enable authentication
+ type: dict
+ suboptions:
+ key_chain:
+ description: Use a key-chain for cryptographic
+ authentication keys
+ type: str
+ message_digest:
+ description: Use message-digest authentication
+ type: bool
+ "null":
+ description: Use no authentication
+ type: bool
+ bfd:
+ description:
+ - BFD configuration commands
+ - Enable/Disable BFD on this interface
+ type: bool
+ cost:
+ description: Interface cost
+ type: dict
+ suboptions:
+ interface_cost:
+ description: Interface cost or Route cost of this interface
+ type: int
+ dynamic_cost:
+ description:
+ - Specify dynamic cost options
+ - Valid only with IPv6 OSPF config
+ type: dict
+ suboptions:
+ default:
+ description: Specify default link metric value
+ type: int
+ hysteresis:
+ description: Specify hysteresis value for LSA dampening
+ type: dict
+ suboptions:
+ percent:
+ description: Specify hysteresis percent changed.
+ Please refer vendor documentation of Valid values.
+ type: int
+ threshold:
+ description: Specify hysteresis threshold value.
+ Please refer vendor documentation of Valid values.
+ type: int
+ weight:
+ description: Specify weight to be placed on individual
+ metrics
+ type: dict
+ suboptions:
+ l2_factor:
+ description:
+ - Specify weight to be given to L2-factor metric
+ - Percentage weight of L2-factor metric. Please refer
+ vendor documentation of Valid values.
+ type: int
+ latency:
+ description:
+ - Specify weight to be given to latency metric.
+ - Percentage weight of latency metric. Please refer
+ vendor documentation of Valid values.
+ type: int
+ oc:
+ description:
+ - Specify weight to be given to cdr/mdr for oc
+ - Give 100 percent weightage for current data rate(0
+ for maxdatarate)
+ type: bool
+ resources:
+ description:
+ - Specify weight to be given to resources metric
+ - Percentage weight of resources metric. Please refer
+ vendor documentation of Valid values.
+ type: int
+ throughput:
+ description:
+ - Specify weight to be given to throughput metric
+ - Percentage weight of throughput metric. Please refer
+ vendor documentation of Valid values.
+ type: int
+ database_filter:
+ description: Filter OSPF LSA during synchronization and flooding
+ type: bool
+ dead_interval:
+ description: Interval after which a neighbor is declared dead
+ type: dict
+ suboptions:
+ time:
+ description: time in seconds
+ type: int
+ minimal:
+ description:
+ - Set to 1 second and set multiplier for Hellos
+ - Number of Hellos sent within 1 second. Please refer
+ vendor documentation of Valid values.
+ - Valid only with IP OSPF config
+ type: int
+ demand_circuit:
+ description: OSPF Demand Circuit, enable or disable
+ the demand circuit'
+ type: dict
+ suboptions:
+ enable:
+ description: Enable Demand Circuit
+ type: bool
+ ignore:
+ description: Ignore demand circuit auto-negotiation requests
+ type: bool
+ disable:
+ description:
+ - Disable demand circuit on this interface
+ - Valid only with IPv6 OSPF config
+ type: bool
+ flood_reduction:
+ description: OSPF Flood Reduction
+ type: bool
+ hello_interval:
+ description:
+ - Time between HELLO packets
+ - Please refer vendor documentation of Valid values.
+ type: int
+ lls:
+ description:
+ - Link-local Signaling (LLS) support
+ - Valid only with IP OSPF config
+ type: bool
+ manet:
+ description:
+ - Mobile Adhoc Networking options
+ - MANET Peering options
+ - Valid only with IPv6 OSPF config
+ type: dict
+ suboptions:
+ cost:
+ description: Redundant path cost improvement required to peer
+ type: dict
+ suboptions:
+ percent:
+ description: Relative incremental path cost.
+ Please refer vendor documentation of Valid values.
+ type: int
+ threshold:
+ description: Absolute incremental path cost.
+ Please refer vendor documentation of Valid values.
+ type: int
+ link_metrics:
+ description: Redundant path cost improvement required to peer
+ type: dict
+ suboptions:
+ set:
+ description: Enable link-metrics
+ type: bool
+ cost_threshold:
+ description: Minimum link cost threshold.
+ Please refer vendor documentation of Valid values.
+ type: int
+ mtu_ignore:
+ description: Ignores the MTU in DBD packets
+ type: bool
+ multi_area:
+ description:
+ - Set the OSPF multi-area ID
+ - Valid only with IP OSPF config
+ type: dict
+ suboptions:
+ id:
+ description:
+ - OSPF multi-area ID as a decimal value. Please refer vendor
+ documentation of Valid values.
+ - OSPF multi-area ID in IP address format(e.g. A.B.C.D)
+ type: int
+ cost:
+ description: Interface cost
+ type: int
+ neighbor:
+ description:
+ - OSPF neighbor link-local IPv6 address (X:X:X:X::X)
+ - Valid only with IPv6 OSPF config
+ type: dict
+ suboptions:
+ address:
+ description: Neighbor link-local IPv6 address
+ type: str
+ cost:
+ description: OSPF cost for point-to-multipoint neighbor
+ type: int
+ database_filter:
+ description: Filter OSPF LSA during synchronization and flooding for point-to-multipoint neighbor
+ type: bool
+ poll_interval:
+ description: OSPF dead-router polling interval
+ type: int
+ priority:
+ description: OSPF priority of non-broadcast neighbor
+ type: int
+ network:
+ description: Network type
+ type: dict
+ suboptions:
+ broadcast:
+ description: Specify OSPF broadcast multi-access network
+ type: bool
+ manet:
+ description:
+ - Specify MANET OSPF interface type
+ - Valid only with IPv6 OSPF config
+ type: bool
+ non_broadcast:
+ description: Specify OSPF NBMA network
+ type: bool
+ point_to_multipoint:
+ description: Specify OSPF point-to-multipoint network
+ type: bool
+ point_to_point:
+ description: Specify OSPF point-to-point network
+ type: bool
+ prefix_suppression:
+ description: Enable/Disable OSPF prefix suppression
+ type: bool
+ priority:
+ description: Router priority. Please refer vendor documentation
+ of Valid values.
+ type: int
+ resync_timeout:
+ description: Interval after which adjacency is reset if oob-resync
+ is not started. Please refer vendor documentation of Valid values.
+ type: int
+ retransmit_interval:
+ description: Time between retransmitting lost link state
+ advertisements. Please refer vendor documentation of Valid values.
+ type: int
+ shutdown:
+ description: Set OSPF protocol's state to disable under
+ current interface
+ type: bool
+ transmit_delay:
+ description: Link state transmit delay.
+ Please refer vendor documentation of Valid values.
+ type: int
+ ttl_security:
+ description:
+ - TTL security check
+ - Valid only with IPV4 OSPF config
+ type: dict
+ suboptions:
+ set:
+ description: Enable TTL Security on all interfaces
+ type: bool
+ hops:
+ description:
+ - Maximum number of IP hops allowed
+ - Please refer vendor documentation of Valid values.
+ type: int
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS
+ device by executing the command B(sh running-config | section
+ ^interface).
+ - The state I(parsed) reads the configuration from C(running_config)
+ option and transforms it into Ansible structured data as per the
+ resource module's argspec and the value is then returned in the
+ I(parsed) key within the result.
+ type: str
+ state:
+ description:
+ - The state the configuration should be left in
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any
+ change on the device.
+ - The state I(rendered) will transform the configuration in C(config)
+ option to platform specific CLI commands which will be returned in the
+ I(rendered) key within the result. For state I(rendered) active
+ connection to remote host is not required.
+ - The state I(gathered) will fetch the running configuration from device
+ and transform it into structured data in the format as per the resource
+ module argspec and the value is returned in the I(gathered) key within
+ the result.
+ - The state I(parsed) reads the configuration from C(running_config)
+ option and transforms it into JSON format as per the resource module
+ parameters and the value is returned in the I(parsed) key within the
+ result. The value of C(running_config) option should be the same format
+ as the output of command I(show running-config | section ^interface) executed on device. For state I(parsed) active connection to
+ remote host is not required.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - rendered
+ - parsed
+ default: merged
+"""
+
+EXAMPLES = """
+# Using deleted
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^interface
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ipv6 ospf 55 area 105
+# ipv6 ospf priority 20
+# ipv6 ospf transmit-delay 30
+# ipv6 ospf adjacency stagger disable
+# interface GigabitEthernet0/2
+# ip ospf priority 40
+# ip ospf adjacency stagger disable
+# ip ospf ttl-security hops 50
+# ip ospf 10 area 20
+# ip ospf cost 30
+
+- name: Delete provided OSPF Interface config
+ cisco.ios.ios_ospf_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ state: deleted
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "interface GigabitEthernet0/1",
+# "no ipv6 ospf 55 area 105",
+# "no ipv6 ospf adjacency stagger disable",
+# "no ipv6 ospf priority 20",
+# "no ipv6 ospf transmit-delay 30"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^interface
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# interface GigabitEthernet0/2
+# ip ospf priority 40
+# ip ospf adjacency stagger disable
+# ip ospf ttl-security hops 50
+# ip ospf 10 area 20
+# ip ospf cost 30
+
+# Using deleted without any config passed (NOTE: This will delete all OSPF Interfaces configuration from device)
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^interface
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ipv6 ospf 55 area 105
+# ipv6 ospf priority 20
+# ipv6 ospf transmit-delay 30
+# ipv6 ospf adjacency stagger disable
+# interface GigabitEthernet0/2
+# ip ospf priority 40
+# ip ospf adjacency stagger disable
+# ip ospf ttl-security hops 50
+# ip ospf 10 area 20
+# ip ospf cost 30
+
+- name: Delete all OSPF config from interfaces
+ cisco.ios.ios_ospf_interfaces:
+ state: deleted
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "interface GigabitEthernet0/2",
+# "no ip ospf 10 area 20",
+# "no ip ospf adjacency stagger disable",
+# "no ip ospf cost 30",
+# "no ip ospf priority 40",
+# "no ip ospf ttl-security hops 50",
+# "interface GigabitEthernet0/1",
+# "no ipv6 ospf 55 area 105",
+# "no ipv6 ospf adjacency stagger disable",
+# "no ipv6 ospf priority 20",
+# "no ipv6 ospf transmit-delay 30"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^interface
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# interface GigabitEthernet0/2
+
+# Using merged
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^interface
+# router-ios#
+
+- name: Merge provided OSPF Interfaces configuration
+ cisco.ios.ios_ospf_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ address_family:
+ - afi: ipv4
+ process:
+ id: 10
+ area_id: 30
+ adjacency: true
+ bfd: true
+ cost:
+ interface_cost: 5
+ dead_interval:
+ time: 5
+ demand_circuit:
+ ignore: true
+ network:
+ broadcast: true
+ priority: 25
+ resync_timeout: 10
+ shutdown: true
+ ttl_security:
+ hops: 50
+ - afi: ipv6
+ process:
+ id: 35
+ area_id: 45
+ adjacency: true
+ database_filter: true
+ manet:
+ link_metrics:
+ cost_threshold: 10
+ priority: 55
+ transmit_delay: 45
+ state: merged
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "interface GigabitEthernet0/1",
+# "ip ospf 10 area 30",
+# "ip ospf adjacency stagger disable",
+# "ip ospf bfd",
+# "ip ospf cost 5",
+# "ip ospf dead-interval 5",
+# "ip ospf demand-circuit ignore",
+# "ip ospf network broadcast",
+# "ip ospf priority 25",
+# "ip ospf resync-timeout 10",
+# "ip ospf shutdown",
+# "ip ospf ttl-security hops 50",
+# "ipv6 ospf 35 area 45",
+# "ipv6 ospf adjacency stagger disable",
+# "ipv6 ospf database-filter all out",
+# "ipv6 ospf manet peering link-metrics 10",
+# "ipv6 ospf priority 55",
+# "ipv6 ospf transmit-delay 45"
+# ]
+
+# After state:
+# -------------
+#
+# router-ios#sh running-config | section ^interface
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ip ospf network broadcast
+# ip ospf resync-timeout 10
+# ip ospf dead-interval 5
+# ip ospf priority 25
+# ip ospf demand-circuit ignore
+# ip ospf bfd
+# ip ospf adjacency stagger disable
+# ip ospf ttl-security hops 50
+# ip ospf shutdown
+# ip ospf 10 area 30
+# ip ospf cost 5
+# ipv6 ospf 35 area 45
+# ipv6 ospf priority 55
+# ipv6 ospf transmit-delay 45
+# ipv6 ospf database-filter all out
+# ipv6 ospf adjacency stagger disable
+# ipv6 ospf manet peering link-metrics 10
+# interface GigabitEthernet0/2
+
+# Using overridden
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^interface
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ip ospf network broadcast
+# ip ospf resync-timeout 10
+# ip ospf dead-interval 5
+# ip ospf priority 25
+# ip ospf demand-circuit ignore
+# ip ospf bfd
+# ip ospf adjacency stagger disable
+# ip ospf ttl-security hops 50
+# ip ospf shutdown
+# ip ospf 10 area 30
+# ip ospf cost 5
+# ipv6 ospf 35 area 45
+# ipv6 ospf priority 55
+# ipv6 ospf transmit-delay 45
+# ipv6 ospf database-filter all out
+# ipv6 ospf adjacency stagger disable
+# ipv6 ospf manet peering link-metrics 10
+# interface GigabitEthernet0/2
+
+- name: Override provided OSPF Interfaces configuration
+ cisco.ios.ios_ospf_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ address_family:
+ - afi: ipv6
+ process:
+ id: 55
+ area_id: 105
+ adjacency: true
+ priority: 20
+ transmit_delay: 30
+ - name: GigabitEthernet0/2
+ address_family:
+ - afi: ipv4
+ process:
+ id: 10
+ area_id: 20
+ adjacency: true
+ cost:
+ interface_cost: 30
+ priority: 40
+ ttl_security:
+ hops: 50
+ state: overridden
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "interface GigabitEthernet0/2",
+# "ip ospf 10 area 20",
+# "ip ospf adjacency stagger disable",
+# "ip ospf cost 30",
+# "ip ospf priority 40",
+# "ip ospf ttl-security hops 50",
+# "interface GigabitEthernet0/1",
+# "ipv6 ospf 55 area 105",
+# "no ipv6 ospf database-filter all out",
+# "no ipv6 ospf manet peering link-metrics 10",
+# "ipv6 ospf priority 20",
+# "ipv6 ospf transmit-delay 30",
+# "no ip ospf 10 area 30",
+# "no ip ospf adjacency stagger disable",
+# "no ip ospf bfd",
+# "no ip ospf cost 5",
+# "no ip ospf dead-interval 5",
+# "no ip ospf demand-circuit ignore",
+# "no ip ospf network broadcast",
+# "no ip ospf priority 25",
+# "no ip ospf resync-timeout 10",
+# "no ip ospf shutdown",
+# "no ip ospf ttl-security hops 50"
+# ]
+
+# After state:
+# -------------
+#
+# router-ios#sh running-config | section ^interface
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ipv6 ospf 55 area 105
+# ipv6 ospf priority 20
+# ipv6 ospf transmit-delay 30
+# ipv6 ospf adjacency stagger disable
+# interface GigabitEthernet0/2
+# ip ospf priority 40
+# ip ospf adjacency stagger disable
+# ip ospf ttl-security hops 50
+# ip ospf 10 area 20
+# ip ospf cost 30
+
+# Using replaced
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^interface
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ip ospf network broadcast
+# ip ospf resync-timeout 10
+# ip ospf dead-interval 5
+# ip ospf priority 25
+# ip ospf demand-circuit ignore
+# ip ospf bfd
+# ip ospf adjacency stagger disable
+# ip ospf ttl-security hops 50
+# ip ospf shutdown
+# ip ospf 10 area 30
+# ip ospf cost 5
+# ipv6 ospf 35 area 45
+# ipv6 ospf priority 55
+# ipv6 ospf transmit-delay 45
+# ipv6 ospf database-filter all out
+# ipv6 ospf adjacency stagger disable
+# ipv6 ospf manet peering link-metrics 10
+# interface GigabitEthernet0/2
+
+- name: Replaced provided OSPF Interfaces configuration
+ cisco.ios.ios_ospf_interfaces:
+ config:
+ - name: GigabitEthernet0/2
+ address_family:
+ - afi: ipv6
+ process:
+ id: 55
+ area_id: 105
+ adjacency: true
+ priority: 20
+ transmit_delay: 30
+ state: replaced
+
+# Commands Fired:
+# ---------------
+# "commands": [
+# "interface GigabitEthernet0/2",
+# "ipv6 ospf 55 area 105",
+# "ipv6 ospf adjacency stagger disable",
+# "ipv6 ospf priority 20",
+# "ipv6 ospf transmit-delay 30"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^interface
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ip ospf network broadcast
+# ip ospf resync-timeout 10
+# ip ospf dead-interval 5
+# ip ospf priority 25
+# ip ospf demand-circuit ignore
+# ip ospf bfd
+# ip ospf adjacency stagger disable
+# ip ospf ttl-security hops 50
+# ip ospf shutdown
+# ip ospf 10 area 30
+# ip ospf cost 5
+# ipv6 ospf 35 area 45
+# ipv6 ospf priority 55
+# ipv6 ospf transmit-delay 45
+# ipv6 ospf database-filter all out
+# ipv6 ospf adjacency stagger disable
+# ipv6 ospf manet peering link-metrics 10
+# interface GigabitEthernet0/2
+# ipv6 ospf 55 area 105
+# ipv6 ospf priority 20
+# ipv6 ospf transmit-delay 30
+# ipv6 ospf adjacency stagger disable
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^interface
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ip ospf network broadcast
+# ip ospf resync-timeout 10
+# ip ospf dead-interval 5
+# ip ospf priority 25
+# ip ospf demand-circuit ignore
+# ip ospf bfd
+# ip ospf adjacency stagger disable
+# ip ospf ttl-security hops 50
+# ip ospf shutdown
+# ip ospf 10 area 30
+# ip ospf cost 5
+# ipv6 ospf 35 area 45
+# ipv6 ospf priority 55
+# ipv6 ospf transmit-delay 45
+# ipv6 ospf database-filter all out
+# ipv6 ospf adjacency stagger disable
+# ipv6 ospf manet peering link-metrics 10
+# interface GigabitEthernet0/2
+
+- name: Gather OSPF Interfaces provided configurations
+ cisco.ios.ios_ospf_interfaces:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": [
+# {
+# "name": "GigabitEthernet0/2"
+# },
+# {
+# "address_family": [
+# {
+# "adjacency": true,
+# "afi": "ipv4",
+# "bfd": true,
+# "cost": {
+# "interface_cost": 5
+# },
+# "dead_interval": {
+# "time": 5
+# },
+# "demand_circuit": {
+# "ignore": true
+# },
+# "network": {
+# "broadcast": true
+# },
+# "priority": 25,
+# "process": {
+# "area_id": "30",
+# "id": 10
+# },
+# "resync_timeout": 10,
+# "shutdown": true,
+# "ttl_security": {
+# "hops": 50
+# }
+# },
+# {
+# "adjacency": true,
+# "afi": "ipv6",
+# "database_filter": true,
+# "manet": {
+# "link_metrics": {
+# "cost_threshold": 10
+# }
+# },
+# "priority": 55,
+# "process": {
+# "area_id": "45",
+# "id": 35
+# },
+# "transmit_delay": 45
+# }
+# ],
+# "name": "GigabitEthernet0/1"
+# },
+# {
+# "name": "GigabitEthernet0/0"
+# }
+# ]
+
+# After state:
+# ------------
+#
+# router-ios#sh running-config | section ^interface
+# interface GigabitEthernet0/0
+# interface GigabitEthernet0/1
+# ip ospf network broadcast
+# ip ospf resync-timeout 10
+# ip ospf dead-interval 5
+# ip ospf priority 25
+# ip ospf demand-circuit ignore
+# ip ospf bfd
+# ip ospf adjacency stagger disable
+# ip ospf ttl-security hops 50
+# ip ospf shutdown
+# ip ospf 10 area 30
+# ip ospf cost 5
+# ipv6 ospf 35 area 45
+# ipv6 ospf priority 55
+# ipv6 ospf transmit-delay 45
+# ipv6 ospf database-filter all out
+# ipv6 ospf adjacency stagger disable
+# ipv6 ospf manet peering link-metrics 10
+# interface GigabitEthernet0/2
+
+# Using Rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_ospf_interfaces:
+ config:
+ - name: GigabitEthernet0/1
+ address_family:
+ - afi: ipv4
+ process:
+ id: 10
+ area_id: 30
+ adjacency: true
+ bfd: true
+ cost:
+ interface_cost: 5
+ dead_interval:
+ time: 5
+ demand_circuit:
+ ignore: true
+ network:
+ broadcast: true
+ priority: 25
+ resync_timeout: 10
+ shutdown: true
+ ttl_security:
+ hops: 50
+ - afi: ipv6
+ process:
+ id: 35
+ area_id: 45
+ adjacency: true
+ database_filter: true
+ manet:
+ link_metrics:
+ cost_threshold: 10
+ priority: 55
+ transmit_delay: 45
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "interface GigabitEthernet0/1",
+# "ip ospf 10 area 30",
+# "ip ospf adjacency stagger disable",
+# "ip ospf bfd",
+# "ip ospf cost 5",
+# "ip ospf dead-interval 5",
+# "ip ospf demand-circuit ignore",
+# "ip ospf network broadcast",
+# "ip ospf priority 25",
+# "ip ospf resync-timeout 10",
+# "ip ospf shutdown",
+# "ip ospf ttl-security hops 50",
+# "ipv6 ospf 35 area 45",
+# "ipv6 ospf adjacency stagger disable",
+# "ipv6 ospf database-filter all out",
+# "ipv6 ospf manet peering link-metrics 10",
+# "ipv6 ospf priority 55",
+# "ipv6 ospf transmit-delay 45"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# interface GigabitEthernet0/2
+# interface GigabitEthernet0/1
+# ip ospf network broadcast
+# ip ospf resync-timeout 10
+# ip ospf dead-interval 5
+# ip ospf priority 25
+# ip ospf demand-circuit ignore
+# ip ospf bfd
+# ip ospf adjacency stagger disable
+# ip ospf ttl-security hops 50
+# ip ospf shutdown
+# ip ospf 10 area 30
+# ip ospf cost 5
+# ipv6 ospf 35 area 45
+# ipv6 ospf priority 55
+# ipv6 ospf transmit-delay 45
+# ipv6 ospf database-filter all out
+# ipv6 ospf adjacency stagger disable
+# ipv6 ospf manet peering link-metrics 10
+# interface GigabitEthernet0/0
+
+- name: Parse the provided configuration with the existing running configuration
+ cisco.ios.ios_ospf_interfaces:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": [
+# },
+# {
+# "name": "GigabitEthernet0/2"
+# },
+# {
+# "address_family": [
+# {
+# "adjacency": true,
+# "afi": "ipv4",
+# "bfd": true,
+# "cost": {
+# "interface_cost": 5
+# },
+# "dead_interval": {
+# "time": 5
+# },
+# "demand_circuit": {
+# "ignore": true
+# },
+# "network": {
+# "broadcast": true
+# },
+# "priority": 25,
+# "process": {
+# "area_id": "30",
+# "id": 10
+# },
+# "resync_timeout": 10,
+# "shutdown": true,
+# "ttl_security": {
+# "hops": 50
+# }
+# },
+# {
+# "adjacency": true,
+# "afi": "ipv6",
+# "database_filter": true,
+# "manet": {
+# "link_metrics": {
+# "cost_threshold": 10
+# }
+# },
+# "priority": 55,
+# "process": {
+# "area_id": "45",
+# "id": 35
+# },
+# "transmit_delay": 45
+# }
+# ],
+# "name": "GigabitEthernet0/1"
+# },
+# {
+# "name": "GigabitEthernet0/0"
+# }
+# ]
+"""
+
+RETURN = """
+before:
+ description: The configuration prior to the module execution.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+after:
+ description: The resulting configuration after module execution.
+ returned: when changed
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: list
+ sample:
+ - interface GigabitEthernet2
+ - ip ospf priority 40
+ - ip ospf adjacency stagger disable
+rendered:
+ description: The provided configuration in the task rendered in device-native format (offline).
+ returned: when I(state) is C(rendered)
+ type: list
+ sample:
+ - interface GigabitEthernet2
+ - ip ospf priority 40
+ - ip ospf adjacency stagger disable
+gathered:
+ description: Facts about the network resource gathered from the remote device as structured data.
+ returned: when I(state) is C(gathered)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+parsed:
+ description: The device native config provided in I(running_config) option parsed into structured data as per module argspec.
+ returned: when I(state) is C(parsed)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.ospf_interfaces.ospf_interfaces import (
+ Ospf_interfacesArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.ospf_interfaces.ospf_interfaces import (
+ Ospf_interfaces,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ module = AnsibleModule(
+ argument_spec=Ospf_interfacesArgs.argument_spec,
+ mutually_exclusive=[["config", "running_config"]],
+ required_if=[
+ ["state", "merged", ["config"]],
+ ["state", "replaced", ["config"]],
+ ["state", "overridden", ["config"]],
+ ["state", "rendered", ["config"]],
+ ["state", "parsed", ["running_config"]],
+ ],
+ supports_check_mode=True,
+ )
+
+ result = Ospf_interfaces(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_ospfv2.py b/ansible_collections/cisco/ios/plugins/modules/ios_ospfv2.py
new file mode 100644
index 000000000..a00b8d05d
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_ospfv2.py
@@ -0,0 +1,1728 @@
+#!/usr/bin/python
+#
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#############################################
+# WARNING #
+#############################################
+#
+# This file is auto generated by the resource
+# module builder playbook.
+#
+# Do not edit this file manually.
+#
+# Changes to this file will be over written
+# by the resource module builder.
+#
+# Changes should be made in the model used to
+# generate this file or in the resource module
+# builder template.
+#
+#############################################
+
+"""
+The module file for ios_ospfv2
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+module: ios_ospfv2
+short_description: Resource module to configure OSPFv2.
+description:
+ This module configures and manages the Open Shortest Path First (OSPF)
+ version 2 on IOS platforms.
+version_added: 1.0.0
+author: Sumit Jaiswal (@justjais)
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ config:
+ description: A dictionary of OSPF options.
+ type: dict
+ suboptions:
+ processes:
+ description:
+ - List of OSPF instance configurations.
+ type: list
+ elements: dict
+ suboptions:
+ process_id:
+ description: Process ID
+ required: true
+ type: int
+ vrf:
+ description: Specify parameters for a VPN Routing/Forwarding instance
+ type: str
+ address_family:
+ description: Router Address Family configuration mode
+ type: dict
+ suboptions:
+ default:
+ description: Set a command to its defaults
+ type: bool
+ snmp_context:
+ description:
+ - Modify snmp parameters
+ - Configure SNMP context name
+ type: str
+ topology:
+ description: Associate the routing protocol to a topology instance
+ type: dict
+ suboptions:
+ name:
+ description: Routing topology instance name
+ type: str
+ base:
+ description: Entering router topology sub mode
+ type: bool
+ tid:
+ description:
+ - Configuring the routing protocol topology tid
+ - Note, please refer vendor documentation for valid values
+ type: bool
+ adjacency:
+ description: To configure control adjacency formation
+ type: dict
+ suboptions:
+ min_adjacency:
+ description:
+ - Initial number of adjacencies allowed to be forming in an area
+ - Please refer vendor documentation for valid values
+ type: int
+ max_adjacency:
+ description:
+ - Maximum number of adjacencies allowed to be forming
+ - Please refer vendor documentation for valid values
+ type: int
+ none:
+ description: No initial
+ type: bool
+ areas:
+ description: OSPF area parameters
+ type: list
+ elements: dict
+ suboptions:
+ area_id:
+ description:
+ - OSPF area ID as a decimal value. Please refer vendor documentation
+ of Valid values.
+ - OSPF area ID in IP address format(e.g. A.B.C.D)
+ type: str
+ authentication:
+ description: Area authentication
+ type: dict
+ suboptions:
+ enable:
+ description: Enable area authentication
+ type: bool
+ message_digest:
+ description: Use IPsec authentication
+ type: bool
+ capability:
+ description:
+ - Enable area specific capability
+ - Enable exclusion of links from base topology
+ type: bool
+ default_cost:
+ description:
+ - Set the summary default-cost of a NSSA/stub area
+ - Stub's advertised external route metric
+ - Note, please refer vendor documentation for respective valid values
+ type: int
+ filter_list:
+ description: Filter networks between OSPF areas
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Name of an IP prefix-list
+ type: str
+ direction:
+ description: The direction to apply on the filter networks sent to and from this area.
+ type: str
+ choices: ["in", "out"]
+ required: true
+ nssa:
+ description: Specify a NSSA area
+ type: dict
+ suboptions:
+ set:
+ description: Enable a NSSA area
+ type: bool
+ default_information_originate:
+ description: Originate Type 7 default into NSSA area
+ type: dict
+ suboptions:
+ metric:
+ description: OSPF default metric
+ type: int
+ metric_type:
+ description:
+ - OSPF metric type for default routes
+ - OSPF Link State type
+ type: int
+ choices: [1, 2]
+ nssa_only:
+ description: Limit default advertisement to this NSSA area
+ type: bool
+ no_ext_capability:
+ description: Do not send domain specific capabilities into NSSA
+ type: bool
+ no_redistribution:
+ description: No redistribution into this NSSA area
+ type: bool
+ no_summary:
+ description: Do not send summary LSA into NSSA
+ type: bool
+ translate:
+ description:
+ - Translate LSA
+ - Always translate LSAs on this ABR
+ - Suppress forwarding address in translated LSAs
+ type: str
+ choices: ["always", "suppress-fa"]
+ ranges:
+ description: Summarize routes matching address/mask (border routers only)
+ type: list
+ elements: dict
+ suboptions:
+ address:
+ description: IP address to match
+ type: str
+ netmask:
+ description: IP mask for address
+ type: str
+ advertise:
+ description:
+ - Advertise this range (default)
+ - Since, advertise when enabled is not shown in running-config
+ idempotency won't be maintained for the play in the second or
+ next run of the play.
+ type: bool
+ cost:
+ description: User specified metric for this range
+ type: int
+ not_advertise:
+ description: DoNotAdvertise this range
+ type: bool
+ sham_link:
+ description: Define a sham link and its parameters
+ type: dict
+ suboptions:
+ source:
+ description: IP addr associated with sham-link source (A.B.C.D)
+ type: str
+ destination:
+ description: IP addr associated with sham-link destination (A.B.C.D)
+ type: str
+ cost:
+ description:
+ - Associate a cost with the sham-link
+ - Cost of the sham-link
+ - Note, please refer vendor documentation for respective valid values
+ type: int
+ ttl_security:
+ description:
+ - TTL security check
+ - Maximum number of IP hops allowed
+ type: int
+ stub:
+ description:
+ - Specify a stub area
+ - Backbone can not be configured as stub area
+ type: dict
+ suboptions:
+ set:
+ description: Enable a stub area
+ type: bool
+ no_ext_capability:
+ description: Do not send domain specific capabilities into stub area
+ type: bool
+ no_summary:
+ description: Do not send summary LSA into stub area
+ type: bool
+ auto_cost:
+ description: Calculate OSPF interface cost according to bandwidth
+ type: dict
+ suboptions:
+ set:
+ description: Enable OSPF auto-cost
+ type: bool
+ reference_bandwidth:
+ description:
+ - Use reference bandwidth method to assign OSPF cost
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ bfd:
+ description:
+ - BFD configuration commands
+ - Enable BFD on all interfaces
+ type: bool
+ capability:
+ description: Enable specific OSPF feature
+ type: dict
+ suboptions:
+ lls:
+ description: Link-local Signaling (LLS) support
+ type: bool
+ opaque:
+ description: Opaque LSA
+ type: bool
+ transit:
+ description: Transit Area
+ type: bool
+ vrf_lite:
+ description: Do not perform PE specific checks
+ type: bool
+ compatible:
+ description: OSPF router compatibility list
+ type: dict
+ suboptions:
+ rfc1583:
+ description: compatible with RFC 1583
+ type: bool
+ rfc1587:
+ description: compatible with RFC 1587
+ type: bool
+ rfc5243:
+ description: supports DBD exchange optimization
+ type: bool
+ default_information:
+ description: Control distribution of default information
+ type: dict
+ suboptions:
+ originate:
+ description: Distribute a default route
+ type: bool
+ always:
+ description: Always advertise default route
+ type: bool
+ metric:
+ description:
+ - OSPF default metric
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ metric_type:
+ description:
+ - OSPF metric type for default routes
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ route_map:
+ description: Route-map reference name
+ type: str
+ default_metric:
+ description: Set metric of redistributed routes
+ type: int
+ discard_route:
+ description: Enable or disable discard-route installation
+ type: dict
+ suboptions:
+ set:
+ description: Enable discard-route installation
+ type: bool
+ external:
+ description:
+ - Discard route for redistributed summarised routes
+ - Administrative distance for redistributed summarised routes
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ internal:
+ description:
+ - Discard route for summarised internal routes
+ - Administrative distance for summarised internal routes
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ distance:
+ description: Define an administrative distance
+ type: dict
+ suboptions:
+ admin_distance:
+ description: OSPF Administrative distance
+ type: dict
+ suboptions:
+ distance:
+ description: Administrative distance
+ type: int
+ address:
+ description: IP Source address
+ type: str
+ wildcard_bits:
+ description: Wildcard bits
+ type: str
+ acl:
+ description: Access-list name/number
+ type: str
+ ospf:
+ description: OSPF distance
+ type: dict
+ suboptions:
+ external:
+ description: External type 5 and type 7 routes
+ type: int
+ inter_area:
+ description: Inter-area routes
+ type: int
+ intra_area:
+ description: Intra-area routes
+ type: int
+ distribute_list:
+ description: Filter networks in routing updates
+ type: dict
+ suboptions:
+ acls:
+ description: IP access list
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: IP access list name/number
+ type: str
+ required: true
+ direction:
+ description: Filter incoming and outgoing routing updates.
+ type: str
+ required: true
+ choices: ["in", "out"]
+ interface:
+ description:
+ - Interface configuration (GigabitEthernet A/B)
+ - Valid with incoming traffic
+ type: str
+ protocol:
+ description:
+ - Protocol config (bgp 1).
+ - Valid with outgoing traffic
+ type: str
+ prefix:
+ description: Filter prefixes in routing updates
+ type: dict
+ suboptions:
+ name:
+ description: Name of an IP prefix-list
+ type: str
+ required: true
+ gateway_name:
+ description: Gateway name for filtering incoming updates based on gateway
+ type: str
+ direction:
+ description: Filter incoming and outgoing routing updates.
+ type: str
+ required: true
+ choices: ["in", "out"]
+ interface:
+ description:
+ - Interface configuration (GigabitEthernet A/B)
+ - Valid with incoming traffic
+ type: str
+ protocol:
+ description:
+ - Protocol config (bgp 1).
+ - Valid with outgoing traffic
+ type: str
+ route_map:
+ description: Filter prefixes in routing updates
+ type: dict
+ suboptions:
+ name:
+ description: Route-map name
+ type: str
+ required: true
+ domain_id:
+ description: OSPF domain-id
+ type: dict
+ suboptions:
+ ip_address:
+ description: IP address
+ type: dict
+ suboptions:
+ address:
+ description: OSPF domain ID in IP address format
+ type: str
+ secondary:
+ description: Secondary Domain-ID
+ type: bool
+ "null":
+ description: Null Domain-ID
+ type: bool
+ domain_tag:
+ description:
+ - OSPF domain-tag which is OSPF domain tag - 32-bit value
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ event_log:
+ description: Event Logging
+ type: dict
+ suboptions:
+ enable:
+ description: Enable event Logging
+ type: bool
+ one_shot:
+ description: Disable Logging When Log Buffer Becomes Full
+ type: bool
+ pause:
+ description: Pause Event Logging
+ type: bool
+ size:
+ description:
+ - Maximum Number of Events Stored in the Event Log
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ help:
+ description: Description of the interactive help system
+ type: bool
+ ignore:
+ description:
+ - Do not complain about specific event
+ - Do not complain upon receiving LSA of the specified type, MOSPF Type 6 LSA
+ type: bool
+ interface_id:
+ description:
+ - Source of the interface ID
+ - SNMP MIB ifIndex
+ type: bool
+ ispf:
+ description: Enable incremental SPF computation
+ type: bool
+ limit:
+ description: Limit a specific OSPF feature and LS update, DBD, and LS request retransmissions
+ type: dict
+ suboptions:
+ dc:
+ description: Demand circuit retransmissions
+ type: dict
+ suboptions:
+ number:
+ description: The maximum number of retransmissions
+ type: int
+ disable:
+ description: Disble the feature
+ type: bool
+ non_dc:
+ description: Non-demand-circuit retransmissions
+ type: dict
+ suboptions:
+ number:
+ description: The maximum number of retransmissions
+ type: int
+ disable:
+ description: Disble the feature
+ type: bool
+ local_rib_criteria:
+ description: Enable or disable usage of local RIB as route criteria
+ type: dict
+ suboptions:
+ enable:
+ description: Enable usage of local RIB as route criteria
+ type: bool
+ forwarding_address:
+ description: Local RIB used to validate external/NSSA forwarding addresses
+ type: bool
+ inter_area_summary:
+ description: Local RIB used as criteria for inter-area summaries
+ type: bool
+ nssa_translation:
+ description: Local RIB used as criteria for NSSA translation
+ type: bool
+ log_adjacency_changes:
+ description: Log changes in adjacency state
+ type: dict
+ suboptions:
+ set:
+ description: Log changes in adjacency state
+ type: bool
+ detail:
+ description: Log all state changes
+ type: bool
+ max_lsa:
+ description: Maximum number of non self-generated LSAs to accept
+ type: dict
+ suboptions:
+ number:
+ description:
+ - Maximum number of non self-generated LSAs to accept
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ threshold_value:
+ description:
+ - Threshold value (%) at which to generate a warning msg
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ ignore_count:
+ description:
+ - Maximum number of times adjacencies can be suppressed
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ ignore_time:
+ description:
+ - Number of minutes during which all adjacencies are suppressed
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ reset_time:
+ description:
+ - Number of minutes after which ignore-count is reset to zero
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ warning_only:
+ description: Only give a warning message when limit is exceeded
+ type: bool
+ max_metric:
+ description: Set maximum metric
+ type: dict
+ suboptions:
+ router_lsa:
+ description: Maximum metric in self-originated router-LSAs
+ type: bool
+ required: true
+ external_lsa:
+ description:
+ - Override external-lsa metric with max-metric value
+ - Overriding metric in external-LSAs
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ include_stub:
+ description: Set maximum metric for stub links in router-LSAs
+ type: bool
+ on_startup:
+ description: Set maximum metric temporarily after reboot
+ type: dict
+ suboptions:
+ time:
+ description:
+ - Time, in seconds, router-LSAs are originated with max-metric
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ wait_for_bgp:
+ description: Let BGP decide when to originate router-LSA with normal metric
+ type: bool
+ summary_lsa:
+ description:
+ - Override summary-lsa metric with max-metric value
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ maximum_paths:
+ description:
+ - Forward packets over multiple paths
+ - Number of paths
+ type: int
+ mpls:
+ description: Configure MPLS routing protocol parameters
+ type: dict
+ suboptions:
+ ldp:
+ description: routing protocol commands for MPLS LDP
+ type: dict
+ suboptions:
+ autoconfig:
+ description: routing protocol commands for MPLS LDP
+ type: dict
+ suboptions:
+ set:
+ description: Configure LDP automatic configuration and set the config
+ type: bool
+ area:
+ description: Configure an OSPF area to run MPLS LDP
+ type: str
+ sync:
+ description: Configure LDP-IGP Synchronization
+ type: bool
+ traffic_eng:
+ description: Let BGP decide when to originate router-LSA with normal metric
+ type: dict
+ suboptions:
+ area:
+ description:
+ - Configure an ospf area to run MPLS Traffic Engineering
+ - OSPF area ID as a decimal value or in IP address format
+ type: str
+ autoroute_exclude:
+ description:
+ - MPLS TE autoroute exclude
+ - Filter prefixes based on name of an IP prefix-list
+ type: str
+ interface:
+ description: MPLS TE interface configuration for this OSPF process
+ type: dict
+ suboptions:
+ interface_type:
+ description: TE Interface configuration (GigabitEthernet A/B)
+ type: str
+ area:
+ description:
+ - Advertise MPLS TE information for this interface into area
+ - OSPF area ID as a decimal value
+ type: int
+ mesh_group:
+ description: Traffic Engineering Mesh-Group advertisement
+ type: dict
+ suboptions:
+ id:
+ description: Mesh Group Id
+ type: int
+ interface:
+ description: Interface configuration (GigabitEthernet A/B)
+ type: str
+ area:
+ description: configure flooding scope as area
+ type: str
+ multicast_intact:
+ description: MPLS TE and PIM interaction
+ type: bool
+ router_id_interface:
+ description: Router Interface configuration (GigabitEthernet A/B)
+ type: str
+ neighbor:
+ description: Specify a neighbor router
+ type: dict
+ suboptions:
+ address:
+ description: Neighbor address (A.B.C.D)
+ type: str
+ cost:
+ description:
+ - OSPF cost for point-to-multipoint neighbor metric
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ database_filter:
+ description:
+ - Filter OSPF LSA during synchronization and flooding for point-to-multipoint neighbor
+ - Filter all outgoing LSA
+ type: bool
+ poll_interval:
+ description: OSPF dead-router polling interval of non-broadcast neighbor in Seconds
+ type: int
+ priority:
+ description: OSPF priority of non-broadcast neighbor priority
+ type: int
+ network:
+ description: Enable routing on an IP network
+ type: list
+ elements: dict
+ suboptions:
+ address:
+ description: Network number
+ type: str
+ wildcard_bits:
+ description: OSPF wild card bits
+ type: str
+ area:
+ description: Set the OSPF area ID
+ type: str
+ nsf:
+ description: Non-stop forwarding
+ type: dict
+ suboptions:
+ cisco:
+ description: Cisco Non-stop forwarding
+ type: dict
+ suboptions:
+ helper:
+ description: helper support
+ type: bool
+ disable:
+ description: disable helper support
+ type: bool
+ ietf:
+ description: IETF graceful restart
+ type: dict
+ suboptions:
+ helper:
+ description: helper support
+ type: bool
+ disable:
+ description: disable helper support
+ type: bool
+ strict_lsa_checking:
+ description: enable helper strict LSA checking
+ type: bool
+ passive_interface:
+ description:
+ - passive_interface param is deprecated and a newer param passive_interfaces
+ with added functionality's is introduced, please meke use of the new available
+ passive_interfaces instead.
+ - Suppress routing updates on an interface (GigabitEthernet A/B)
+ - Interface name with respective interface number
+ type: str
+ passive_interfaces:
+ description: Suppress routing updates on an interface
+ type: dict
+ suboptions:
+ default:
+ description: Suppress routing updates on all interfaces
+ type: bool
+ interface:
+ description: Suppress/Un-Suppress routing updates on interface
+ type: dict
+ suboptions:
+ set_interface:
+ description: Suppress/Un-Suppress routing updates
+ type: bool
+ name:
+ description: Name of interface (GigabitEthernet A/B)
+ type: list
+ elements: str
+ prefix_suppression:
+ description: Enable prefix suppression
+ type: bool
+ priority:
+ description:
+ - OSPF topology priority
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ queue_depth:
+ description: Hello/Router process queue depth
+ type: dict
+ suboptions:
+ hello:
+ description: OSPF Hello process queue depth
+ type: dict
+ suboptions:
+ max_packets:
+ description: maximum number of packets in the queue
+ type: int
+ unlimited:
+ description: Unlimited queue depth
+ type: bool
+ update:
+ description: OSPF Router process queue depth
+ type: dict
+ suboptions:
+ max_packets:
+ description: maximum number of packets in the queue
+ type: int
+ unlimited:
+ description: Unlimited queue depth
+ type: bool
+ router_id:
+ description:
+ - Router-id address for this OSPF process
+ - OSPF router-id in IP address format (A.B.C.D)
+ type: str
+ shutdown:
+ description: Shutdown the router process
+ type: bool
+ summary_address:
+ description: Configure IP address summaries
+ type: dict
+ suboptions:
+ address:
+ description: IP summary address
+ type: str
+ mask:
+ description: IP Summary mask
+ type: str
+ not_advertise:
+ description: Do not advertise or translate
+ type: bool
+ nssa_only:
+ description: Limit summary to NSSA areas
+ type: bool
+ tag:
+ description: Set tag
+ type: int
+ timers:
+ description: Adjust routing timers
+ type: dict
+ suboptions:
+ lsa:
+ description:
+ - OSPF LSA timers, arrival timer
+ - The minimum interval in milliseconds between accepting the same LSA
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ pacing:
+ description: OSPF pacing timers
+ type: dict
+ suboptions:
+ flood:
+ description:
+ - OSPF flood pacing timer
+ - The minimum interval in msec to pace limit flooding on interface
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ lsa_group:
+ description:
+ - OSPF LSA group pacing timer
+ - Interval in sec between group of LSA being refreshed or maxaged
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ retransmission:
+ description:
+ - OSPF retransmission pacing timer
+ - The minimum interval in msec between neighbor retransmissions
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ throttle:
+ description: OSPF throttle timers
+ type: dict
+ suboptions:
+ lsa:
+ description: OSPF LSA throttle timers
+ type: dict
+ suboptions:
+ first_delay:
+ description:
+ - Delay to generate first occurrence of LSA in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ min_delay:
+ description:
+ - Minimum delay between originating the same LSA in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ max_delay:
+ description:
+ - Maximum delay between originating the same LSA in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ spf:
+ description: OSPF SPF throttle timers
+ - Delay between receiving a change to SPF calculation in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: dict
+ suboptions:
+ receive_delay:
+ description:
+ - Delay between receiving a change to SPF calculation in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ between_delay:
+ description:
+ - Delay between first and second SPF calculation in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ max_delay:
+ description:
+ - Maximum wait time in milliseconds for SPF calculations
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ traffic_share:
+ description:
+ - How to compute traffic share over alternate paths
+ - All traffic shared among min metric paths
+ - Use different interfaces for equal-cost paths
+ type: bool
+ ttl_security:
+ description: TTL security check
+ type: dict
+ suboptions:
+ set:
+ description: Enable TTL Security on all interfaces
+ type: bool
+ hops:
+ description:
+ - Maximum number of IP hops allowed
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS
+ device by executing the command B(sh running-config | section ^router ospf).
+ - The state I(parsed) reads the configuration from C(running_config)
+ option and transforms it into Ansible structured data as per the
+ resource module's argspec and the value is then returned in the
+ I(parsed) key within the result.
+ type: str
+ state:
+ description:
+ - The state the configuration should be left in
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device.
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result. For state I(rendered) active connection to remote host is
+ not required.
+ - The state I(gathered) will fetch the running configuration from device and transform
+ it into structured data in the format as per the resource module argspec and
+ the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result. The value of C(running_config)
+ option should be the same format as the output of command I(show running-config
+ | include ip route|ipv6 route) executed on device. For state I(parsed) active
+ connection to remote host is not required.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - parsed
+ - rendered
+ default: merged
+"""
+
+EXAMPLES = """
+# Using deleted
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospf
+# router ospf 200 vrf blue
+# domain-id 192.0.3.1
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# area 10 capability default-exclusion
+# distribute-list 10 out
+# distribute-list 123 in
+# router ospf 1
+# max-metric router-lsa on-startup 110
+# area 10 authentication message-digest
+# area 10 nssa default-information-originate metric 10
+# area 10 nssa translate type7 suppress-fa
+# area 10 default-cost 10
+# area 10 filter-list prefix test_prefix_out out
+# network 198.51.100.0 0.0.0.255 area 5
+# default-information originate
+
+- name: Delete provided OSPF V2 processes
+ cisco.ios.ios_ospfv2:
+ config:
+ processes:
+ - process_id: 1
+ - process_id: 200
+ vrf: blue
+ state: deleted
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "no router ospf 1"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^router ospf
+# router ospf 200 vrf blue
+# domain-id 192.0.3.1
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# area 10 capability default-exclusion
+# distribute-list 10 out
+# distribute-list 123 in
+
+# Using deleted without any config passed (NOTE: This will delete all OSPFV2 configuration from device)
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospf
+# router ospf 200 vrf blue
+# domain-id 192.0.3.1
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# area 10 capability default-exclusion
+# distribute-list 10 out
+# distribute-list 123 in
+# router ospf 1
+# max-metric router-lsa on-startup 110
+# area 10 authentication message-digest
+# area 10 nssa default-information-originate metric 10
+# area 10 nssa translate type7 suppress-fa
+# area 10 default-cost 10
+# area 10 filter-list prefix test_prefix_out out
+# network 198.51.100.0 0.0.0.255 area 5
+# default-information originate
+
+- name: Delete all OSPF processes
+ cisco.ios.ios_ospfv2:
+ state: deleted
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "no router ospf 200 vrf blue",
+# "no router ospf 1"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^router ospf
+# router-ios#
+
+# Using merged
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospf
+# router-ios#
+
+- name: Merge provided OSPF V2 configuration
+ cisco.ios.ios_ospfv2:
+ config:
+ processes:
+ - process_id: 1
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 110
+ areas:
+ - area_id: "5"
+ capability: true
+ authentication:
+ enable: true
+ - area_id: "10"
+ authentication:
+ message_digest: true
+ nssa:
+ default_information_originate:
+ metric: 10
+ translate: suppress-fa
+ default_cost: 10
+ filter_list:
+ - name: test_prefix_in
+ direction: in
+ - name: test_prefix_out
+ direction: out
+ network:
+ - address: 198.51.100.0
+ wildcard_bits: 0.0.0.255
+ area: 5
+ default_information:
+ originate: true
+ passive_interfaces:
+ default: true
+ interface:
+ set_interface: False
+ name:
+ - GigabitEthernet0/1
+ - GigabitEthernet0/2
+ - process_id: 200
+ vrf: blue
+ domain_id:
+ ip_address:
+ address: 192.0.3.1
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 100
+ auto_cost:
+ reference_bandwidth: 4
+ areas:
+ - area_id: "10"
+ capability: true
+ distribute_list:
+ acls:
+ - name: 10
+ direction: out
+ - name: 123
+ direction: in
+ state: merged
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "router ospf 200 vrf blue",
+# "auto-cost reference-bandwidth 4",
+# "distribute-list 10 out",
+# "distribute-list 123 in",
+# "domain-id 192.0.3.1",
+# "max-metric router-lsa on-startup 100",
+# "area 10 capability default-exclusion",
+# "router ospf 1",
+# "default-information originate",
+# "max-metric router-lsa on-startup 110",
+# "network 198.51.100.0 0.0.0.255 area 5",
+# "area 10 authentication message-digest",
+# "area 10 default-cost 10",
+# "area 10 nssa translate type7 suppress-fa",
+# "area 10 nssa default-information-originate metric 10",
+# "area 10 filter-list prefix test_prefix_out out",
+# "area 10 filter-list prefix test_prefix_in in",
+# "area 5 authentication",
+# "area 5 capability default-exclusion"
+# "passive-interface default"
+# "no passive-interface GigabitEthernet0/1"
+# ]
+
+# After state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospf
+# router ospf 200 vrf blue
+# domain-id 192.0.3.1
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# area 10 capability default-exclusion
+# distribute-list 10 out
+# distribute-list 123 in
+# router ospf 1
+# max-metric router-lsa on-startup 110
+# area 10 authentication message-digest
+# area 10 nssa default-information-originate metric 10
+# area 10 nssa translate type7 suppress-fa
+# area 10 default-cost 10
+# area 10 filter-list prefix test_prefix_out out
+# network 198.51.100.0 0.0.0.255 area 5
+# default-information originate
+# passive-interface default
+# no passive-interface GigabitEthernet0/1
+# no passive-interface GigabitEthernet0/2
+
+# Using overridden
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospf
+# router ospf 200 vrf blue
+# domain-id 192.0.3.1
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# area 10 capability default-exclusion
+# distribute-list 10 out
+# distribute-list 123 in
+# router ospf 1
+# max-metric router-lsa on-startup 110
+# area 10 authentication message-digest
+# area 10 nssa default-information-originate metric 10
+# area 10 nssa translate type7 suppress-fa
+# area 10 default-cost 10
+# area 10 filter-list prefix test_prefix_out out
+# network 198.51.100.0 0.0.0.255 area 5
+# default-information originate
+
+- name: Override provided OSPF V2 configuration
+ cisco.ios.ios_ospfv2:
+ config:
+ processes:
+ - process_id: 200
+ vrf: blue
+ domain_id:
+ ip_address:
+ address: 192.0.4.1
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 200
+ maximum_paths: 15
+ ttl_security:
+ hops: 7
+ areas:
+ - area_id: "10"
+ default_cost: 10
+ authentication:
+ message_digest: true
+ - process_id: 100
+ vrf: ospf_vrf
+ domain_id:
+ ip_address:
+ address: 192.0.5.1
+ auto_cost:
+ reference_bandwidth: 5
+ areas:
+ - area_id: "5"
+ authentication:
+ message_digest: true
+ nssa:
+ default_information_originate:
+ metric: 10
+ translate: suppress-fa
+ state: overridden
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "no router ospf 1",
+# "router ospf 100 vrf ospf_vrf",
+# "auto-cost reference-bandwidth 5",
+# "domain-id 192.0.5.1",
+# "area 5 authentication message-digest",
+# "area 5 nssa translate type7 suppress-fa",
+# "area 5 nssa default-information-originate metric 10",
+# "router ospf 200 vrf blue",
+# "no auto-cost reference-bandwidth 4",
+# "no distribute-list 10 out",
+# "no distribute-list 123 in",
+# "domain-id 192.0.4.1",
+# "max-metric router-lsa on-startup 200",
+# "maximum-paths 15",
+# "ttl-security all-interfaces hops 7",
+# "area 10 authentication message-digest",
+# "no area 10 capability default-exclusion",
+# "area 10 default-cost 10"
+# ]
+
+# After state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospf
+# router ospf 200 vrf blue
+# domain-id 192.0.4.1
+# max-metric router-lsa on-startup 200
+# ttl-security all-interfaces hops 7
+# area 10 authentication message-digest
+# area 10 default-cost 10
+# maximum-paths 15
+# router ospf 100 vrf ospf_vrf
+# domain-id 192.0.5.1
+# auto-cost reference-bandwidth 5
+# area 5 authentication message-digest
+# area 5 nssa default-information-originate metric 10
+# area 5 nssa translate type7 suppress-fa
+
+# Using replaced
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospf
+# router ospf 200 vrf blue
+# domain-id 192.0.3.1
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# area 10 capability default-exclusion
+# distribute-list 10 out
+# distribute-list 123 in
+# router ospf 1
+# max-metric router-lsa on-startup 110
+# area 10 authentication message-digest
+# area 10 nssa default-information-originate metric 10
+# area 10 nssa translate type7 suppress-fa
+# area 10 default-cost 10
+# area 10 filter-list prefix test_prefix_out out
+# network 198.51.100.0 0.0.0.255 area 5
+# default-information originate
+
+- name: Replaced provided OSPF V2 configuration
+ cisco.ios.ios_ospfv2:
+ config:
+ processes:
+ - process_id: 200
+ vrf: blue
+ domain_id:
+ ip_address:
+ address: 192.0.4.1
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 200
+ maximum_paths: 15
+ ttl_security:
+ hops: 7
+ areas:
+ - area_id: "10"
+ default_cost: 10
+ authentication:
+ message_digest: true
+ - process_id: 100
+ vrf: ospf_vrf
+ domain_id:
+ ip_address:
+ address: 192.0.5.1
+ auto_cost:
+ reference_bandwidth: 5
+ areas:
+ - area_id: "5"
+ authentication:
+ message_digest: true
+ nssa:
+ default_information_originate:
+ metric: 10
+ translate: suppress-fa
+ state: replaced
+
+# Commands Fired:
+# ---------------
+# "commands": [
+# "router ospf 100 vrf ospf_vrf",
+# "auto-cost reference-bandwidth 5",
+# "domain-id 192.0.5.1",
+# "area 5 authentication message-digest",
+# "area 5 nssa translate type7 suppress-fa",
+# "area 5 nssa default-information-originate metric 10",
+# "router ospf 200 vrf blue",
+# "no auto-cost reference-bandwidth 4",
+# "no distribute-list 10 out",
+# "no distribute-list 123 in",
+# "domain-id 192.0.4.1",
+# "max-metric router-lsa on-startup 200",
+# "maximum-paths 15",
+# "ttl-security all-interfaces hops 7",
+# "area 10 authentication message-digest",
+# "no area 10 capability default-exclusion",
+# "area 10 default-cost 10"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^router ospf
+# router ospf 200 vrf blue
+# domain-id 192.0.4.1
+# max-metric router-lsa on-startup 200
+# ttl-security all-interfaces hops 7
+# area 10 authentication message-digest
+# area 10 default-cost 10
+# maximum-paths 15
+# router ospf 100 vrf ospf_vrf
+# domain-id 192.0.5.1
+# auto-cost reference-bandwidth 5
+# area 5 authentication message-digest
+# area 5 nssa default-information-originate metric 10
+# area 5 nssa translate type7 suppress-fa
+# router ospf 1
+# max-metric router-lsa on-startup 110
+# area 5 capability default-exclusion
+# area 5 authentication
+# area 10 authentication message-digest
+# area 10 nssa default-information-originate metric 10
+# area 10 nssa translate type7 suppress-fa
+# area 10 default-cost 10
+# area 10 filter-list prefix test_prefix_in in
+# area 10 filter-list prefix test_prefix_out out
+# network 198.51.100.0 0.0.0.255 area 5
+# default-information originate
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospf
+# router ospf 200 vrf blue
+# domain-id 192.0.3.1
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# area 10 capability default-exclusion
+# distribute-list 10 out
+# distribute-list 123 in
+# router ospf 1
+# max-metric router-lsa on-startup 110
+# area 10 authentication message-digest
+# area 10 nssa default-information-originate metric 10
+# area 10 nssa translate type7 suppress-fa
+# area 10 default-cost 10
+# area 10 filter-list prefix test_prefix_out out
+# network 198.51.100.0 0.0.0.255 area 5
+# default-information originate
+
+- name: Gather OSPFV2 provided configurations
+ cisco.ios.ios_ospfv2:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": {
+# "processes": [
+# {
+# "areas": [
+# {
+# "area_id": "5",
+# "authentication": {
+# "enable": true
+# },
+# "capability": true
+# },
+# {
+# "area_id": "10",
+# "authentication": {
+# "message_digest": true
+# },
+# "default_cost": 10,
+# "filter_list": [
+# {
+# "direction": "in",
+# "name": "test_prefix_in"
+# },
+# {
+# "direction": "out",
+# "name": "test_prefix_out"
+# }
+# ],
+# "nssa": {
+# "default_information_originate": {
+# "metric": 10
+# },
+# "translate": "suppress-fa"
+# }
+# }
+# ],
+# "default_information": {
+# "originate": true
+# },
+# "max_metric": {
+# "on_startup": {
+# "time": 110
+# },
+# "router_lsa": true
+# },
+# "network": {
+# "address": "198.51.100.0",
+# "area": "5",
+# "wildcard_bits": "0.0.0.255"
+# },
+# "process_id": 1
+# },
+# {
+# "areas": [
+# {
+# "area_id": "10",
+# "capability": true
+# }
+# ],
+# "auto_cost": {
+# "reference_bandwidth": 4
+# },
+# "distribute_list": {
+# "acls": [
+# {
+# "direction": "out",
+# "name": "10"
+# },
+# {
+# "direction": "in",
+# "name": "123"
+# }
+# ]
+# },
+# "domain_id": {
+# "ip_address": {
+# "address": "192.0.3.1"
+# }
+# },
+# "max_metric": {
+# "on_startup": {
+# "time": 100
+# },
+# "router_lsa": true
+# },
+# "process_id": 200,
+# "vrf": "blue"
+# }
+# ]
+# }
+
+# After state:
+# ------------
+#
+# router-ios#sh running-config | section ^router ospf
+# router ospf 200 vrf blue
+# domain-id 192.0.3.1
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# area 10 capability default-exclusion
+# distribute-list 10 out
+# distribute-list 123 in
+# router ospf 1
+# max-metric router-lsa on-startup 110
+# area 10 authentication message-digest
+# area 10 nssa default-information-originate metric 10
+# area 10 nssa translate type7 suppress-fa
+# area 10 default-cost 10
+# area 10 filter-list prefix test_prefix_out out
+# network 198.51.100.0 0.0.0.255 area 5
+# default-information originate
+
+# Using Rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_ospfv2:
+ config:
+ processes:
+ - process_id: 1
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 110
+ areas:
+ - area_id: "5"
+ capability: true
+ authentication:
+ enable: true
+ - area_id: "10"
+ authentication:
+ message_digest: true
+ nssa:
+ default_information_originate:
+ metric: 10
+ translate: suppress-fa
+ default_cost: 10
+ filter_list:
+ - name: test_prefix_in
+ direction: in
+ - name: test_prefix_out
+ direction: out
+ network:
+ - address: 198.51.100.0
+ wildcard_bits: 0.0.0.255
+ area: 5
+ default_information:
+ originate: true
+ - process_id: 200
+ vrf: blue
+ domain_id:
+ ip_address:
+ address: 192.0.3.1
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 100
+ auto_cost:
+ reference_bandwidth: 4
+ areas:
+ - area_id: "10"
+ capability: true
+ distribute_list:
+ acls:
+ - name: 10
+ direction: out
+ - name: 123
+ direction: in
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "router ospf 200 vrf blue",
+# "auto-cost reference-bandwidth 4",
+# "distribute-list 10 out",
+# "distribute-list 123 in",
+# "domain-id 192.0.3.1",
+# "max-metric router-lsa on-startup 100",
+# "area 10 capability default-exclusion",
+# "router ospf 1",
+# "default-information originate",
+# "max-metric router-lsa on-startup 110",
+# "network 198.51.100.0 0.0.0.255 area 5",
+# "area 10 authentication message-digest",
+# "area 10 default-cost 10",
+# "area 10 nssa translate type7 suppress-fa",
+# "area 10 nssa default-information-originate metric 10",
+# "area 10 filter-list prefix test_prefix_out out",
+# "area 10 filter-list prefix test_prefix_in in",
+# "area 5 authentication",
+# "area 5 capability default-exclusion"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# router ospf 100
+# auto-cost reference-bandwidth 5
+# domain-id 192.0.5.1
+# area 5 authentication message-digest
+# area 5 nssa translate type7 suppress-fa
+# area 5 nssa default-information-originate metric 10
+
+- name: Parse the provided configuration with the existing running configuration
+ cisco.ios.ios_ospfv2:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": {
+# "processes": [
+# {
+# "areas": [
+# {
+# "area_id": "5",
+# "authentication": {
+# "message_digest": true
+# },
+# "nssa": {
+# "default_information_originate": {
+# "metric": 10
+# },
+# "translate": "suppress-fa"
+# }
+# }
+# ],
+# "auto_cost": {
+# "reference_bandwidth": 5
+# },
+# "domain_id": {
+# "ip_address": {
+# "address": "192.0.5.1"
+# }
+# },
+# "process_id": 100
+# }
+# ]
+# }
+"""
+
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: dict
+after:
+ description: The resulting configuration model invocation.
+ returned: when changed
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: dict
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: always
+ type: list
+ sample: ['router ospf 200 vrf blue', 'auto-cost reference-bandwidth 5', 'domain-id 192.0.4.1']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.ospfv2.ospfv2 import (
+ Ospfv2Args,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.ospfv2.ospfv2 import (
+ Ospfv2,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+ :returns: the result form module invocation
+ """
+ required_if = [
+ ("state", "merged", ("config",)),
+ ("state", "replaced", ("config",)),
+ ("state", "overridden", ("config",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+
+ mutually_exclusive = [("config", "running_config")]
+
+ module = AnsibleModule(
+ argument_spec=Ospfv2Args.argument_spec,
+ required_if=required_if,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+
+ result = Ospfv2(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_ospfv3.py b/ansible_collections/cisco/ios/plugins/modules/ios_ospfv3.py
new file mode 100644
index 000000000..376b23645
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_ospfv3.py
@@ -0,0 +1,1978 @@
+#!/usr/bin/python
+#
+# -*- coding: utf-8 -*-
+# Copyright 2020 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#############################################
+# WARNING #
+#############################################
+#
+# This file is auto generated by the resource
+# module builder playbook.
+#
+# Do not edit this file manually.
+#
+# Changes to this file will be over written
+# by the resource module builder.
+#
+# Changes should be made in the model used to
+# generate this file or in the resource module
+# builder template.
+#
+#############################################
+
+"""
+The module file for ios_ospfv3
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+
+DOCUMENTATION = """
+module: ios_ospfv3
+short_description: Resource module to configure OSPFv3.
+description:
+ This module configures and manages the Open Shortest Path First (OSPF)
+ version 3 on IOS platforms.
+version_added: 1.1.0
+author: Sumit Jaiswal (@justjais)
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ config:
+ description: A list of configurations for ospfv3.
+ type: dict
+ suboptions:
+ processes:
+ description: List of OSPF instance configurations.
+ type: list
+ elements: dict
+ suboptions:
+ process_id:
+ description: Process ID
+ required: true
+ type: int
+ address_family:
+ description: Enter Address Family command mode
+ type: list
+ elements: dict
+ suboptions:
+ afi:
+ description: Enter Address Family command mode
+ type: str
+ choices:
+ - ipv4
+ - ipv6
+ unicast:
+ description: Address Family modifier
+ type: bool
+ vrf:
+ description: Specify parameters for a VPN Routing/Forwarding instance
+ type: str
+ adjacency:
+ description: Control adjacency formation
+ type: dict
+ suboptions:
+ min_adjacency:
+ description:
+ - Initial number of adjacencies allowed to be forming in an area
+ - Please refer vendor documentation for valid values
+ type: int
+ none:
+ description: No initial
+ type: bool
+ max_adjacency:
+ description:
+ - Maximum number of adjacencies allowed to be forming
+ - Please refer vendor documentation for valid values
+ type: int
+ disable:
+ description: Disable adjacency staggering
+ type: bool
+ areas:
+ description: OSPF area parameters
+ type: list
+ elements: dict
+ suboptions:
+ area_id:
+ description:
+ - OSPF area ID as a decimal value. Please refer vendor documentation
+ of Valid values.
+ - OSPF area ID in IP address format(e.g. A.B.C.D)
+ type: str
+ authentication:
+ description: Authentication parameters
+ type: dict
+ suboptions:
+ key_chain:
+ description: Use a key-chain for cryptographic authentication keys
+ type: str
+ "null":
+ description: Use no authentication
+ type: bool
+ default_cost:
+ description:
+ - Set the summary default-cost of a NSSA/stub area
+ - Stub's advertised external route metric
+ - Note, please refer vendor documentation for respective valid values
+ type: int
+ filter_list:
+ description: Filter networks between OSPFv3 areas
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Name of an IP prefix-list
+ type: str
+ direction:
+ description: The direction to apply on the filter networks sent to and from this area.
+ type: str
+ choices: ["in", "out"]
+ required: true
+ normal:
+ description: Specify a normal area type
+ type: bool
+ nssa:
+ description: Specify a NSSA area
+ type: dict
+ suboptions:
+ set:
+ description: Enable a NSSA area
+ type: bool
+ default_information_originate:
+ description: Originate Type 7 default into NSSA area
+ type: dict
+ suboptions:
+ metric:
+ description: OSPF default metric
+ type: int
+ metric_type:
+ description:
+ - OSPF metric type for default routes
+ - OSPF Link State type
+ type: int
+ choices: [1, 2]
+ nssa_only:
+ description: Limit default advertisement to this NSSA area
+ type: bool
+ no_redistribution:
+ description: No redistribution into this NSSA area
+ type: bool
+ no_summary:
+ description: Do not send summary LSA into NSSA
+ type: bool
+ translate:
+ description:
+ - Translate LSA
+ - Always translate LSAs on this ABR
+ - Suppress forwarding address in translated LSAs
+ type: str
+ choices: ["always", "suppress-fa"]
+ ranges:
+ description: Summarize routes matching address/mask (border routers only)
+ type: list
+ elements: dict
+ suboptions:
+ address:
+ description: IP address to match
+ type: str
+ netmask:
+ description: IP mask for address
+ type: str
+ advertise:
+ description:
+ - Advertise this range (default)
+ - Since, advertise when enabled is not shown in running-config
+ idempotency won't be maintained for the play in the second or
+ next run of the play.
+ type: bool
+ cost:
+ description: User specified metric for this range
+ type: int
+ not_advertise:
+ description: DoNotAdvertise this range
+ type: bool
+ sham_link:
+ description: Define a sham link and its parameters
+ type: dict
+ suboptions:
+ source:
+ description: IPv6 address associated with sham-link source (X:X:X:X::X)
+ type: str
+ destination:
+ description: IPv6 address associated with sham-link destination (X:X:X:X::X)
+ type: str
+ authentication:
+ description: Authentication parameters
+ type: dict
+ suboptions:
+ key_chain:
+ description: Use a key-chain for cryptographic authentication keys
+ type: str
+ "null":
+ description: Use no authentication
+ type: bool
+ cost:
+ description:
+ - Associate a cost with the sham-link
+ - Cost of the sham-link
+ type: int
+ ttl_security:
+ description:
+ - TTL security check
+ - maximum number of hops allowed
+ type: int
+ stub:
+ description:
+ - Specify a stub area
+ - Backbone can not be configured as stub area
+ type: dict
+ suboptions:
+ set:
+ description: Enable a stub area
+ type: bool
+ no_summary:
+ description: Do not send summary LSA into stub area
+ type: bool
+ authentication:
+ description:
+ - Authentication parameters
+ - Authentication operation mode
+ type: dict
+ suboptions:
+ deployment:
+ description: Deployment mode of operation
+ type: bool
+ normal:
+ description: Normal mode of operation
+ type: bool
+ auto_cost:
+ description: Calculate OSPF interface cost according to bandwidth
+ type: dict
+ suboptions:
+ set:
+ description: Enable OSPF auto-cost
+ type: bool
+ reference_bandwidth:
+ description:
+ - Use reference bandwidth method to assign OSPF cost
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ bfd:
+ description: BFD configuration commands
+ type: dict
+ suboptions:
+ all_interfaces:
+ description: Enable BFD on all interfaces
+ type: bool
+ disable:
+ description: Disable BFD on all interfaces
+ type: bool
+ capability:
+ description:
+ - Enable a specific feature
+ - Do not perform PE specific checks
+ type: bool
+ compatible:
+ description: OSPFv3 router compatibility list
+ type: dict
+ suboptions:
+ rfc1583:
+ description: compatible with RFC 1583
+ type: bool
+ rfc1587:
+ description: compatible with RFC 1587
+ type: bool
+ rfc5243:
+ description: supports DBD exchange optimization
+ type: bool
+ default_information:
+ description: Control distribution of default information
+ type: dict
+ suboptions:
+ originate:
+ description: Distribute a default route
+ type: bool
+ always:
+ description: Always advertise default route
+ type: bool
+ metric:
+ description:
+ - OSPF default metric
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ metric_type:
+ description:
+ - OSPF metric type for default routes
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ route_map:
+ description: Route-map reference name
+ type: str
+ default_metric:
+ description: Set metric of redistributed routes
+ type: int
+ discard_route:
+ description: Enable or disable discard-route installation
+ type: dict
+ suboptions:
+ sham_link:
+ description: Discard route for sham-link routes
+ type: bool
+ external:
+ description: Discard route for summarised redistributed routes
+ type: bool
+ internal:
+ description: Discard route for summarised inter-area routes
+ type: bool
+ distance:
+ description:
+ - Define an administrative distance
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ distribute_list:
+ description: Filter networks in routing updates
+ type: dict
+ suboptions:
+ acls:
+ description: IP access list
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: IP access list name/number
+ type: str
+ required: true
+ direction:
+ description: Filter incoming and outgoing routing updates.
+ type: str
+ required: true
+ choices: ["in", "out"]
+ interface:
+ description:
+ - Interface configuration (GigabitEthernet A/B)
+ - Valid with incoming traffic
+ type: str
+ protocol:
+ description:
+ - Protocol config (bgp 1).
+ - Valid with outgoing traffic
+ type: str
+ prefix:
+ description: Filter prefixes in routing updates
+ type: dict
+ suboptions:
+ name:
+ description: Name of an IP prefix-list
+ type: str
+ required: true
+ gateway_name:
+ description: Gateway name for filtering incoming updates based on gateway
+ type: str
+ direction:
+ description: Filter incoming and outgoing routing updates.
+ type: str
+ required: true
+ choices: ["in", "out"]
+ interface:
+ description:
+ - Interface configuration (GigabitEthernet A/B)
+ - Valid with incoming traffic
+ type: str
+ protocol:
+ description:
+ - Protocol config (bgp 1).
+ - Valid with outgoing traffic
+ type: str
+ route_map:
+ description: Filter prefixes in routing updates
+ type: dict
+ suboptions:
+ name:
+ description: Route-map name
+ type: str
+ required: true
+ event_log:
+ description: Event Logging
+ type: dict
+ suboptions:
+ enable:
+ description: Enable event Logging
+ type: bool
+ one_shot:
+ description: Disable Logging When Log Buffer Becomes Full
+ type: bool
+ pause:
+ description: Pause Event Logging
+ type: bool
+ size:
+ description:
+ - Maximum Number of Events Stored in the Event Log
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ graceful_restart:
+ description:
+ - Graceful-restart options
+ - helper support
+ type: dict
+ suboptions:
+ enable:
+ description: helper support enabled
+ type: bool
+ disable:
+ description: disable helper support
+ type: bool
+ strict_lsa_checking:
+ description: enable helper strict LSA checking
+ type: bool
+ interface_id:
+ description: Source of the interface ID
+ type: dict
+ suboptions:
+ ios_if_index:
+ description: IOS interface number
+ type: bool
+ snmp_if_index:
+ description: SNMP MIB ifIndex
+ type: bool
+ limit:
+ description: Limit a specific OSPF feature
+ type: dict
+ suboptions:
+ dc:
+ description: Demand circuit retransmissions
+ type: dict
+ suboptions:
+ number:
+ description: The maximum number of retransmissions
+ type: int
+ disable:
+ description: Disble the feature
+ type: bool
+ non_dc:
+ description: Non-demand-circuit retransmissions
+ type: dict
+ suboptions:
+ number:
+ description: The maximum number of retransmissions
+ type: int
+ disable:
+ description: Disble the feature
+ type: bool
+ local_rib_criteria:
+ description: Enable or disable usage of local RIB as route criteria
+ type: dict
+ suboptions:
+ enable:
+ description: Enable usage of local RIB as route criteria
+ type: bool
+ forwarding_address:
+ description: Local RIB used to validate external/NSSA forwarding addresses
+ type: bool
+ inter_area_summary:
+ description: Local RIB used as criteria for inter-area summaries
+ type: bool
+ nssa_translation:
+ description: Local RIB used as criteria for NSSA translation
+ type: bool
+ log_adjacency_changes:
+ description: Log changes in adjacency state
+ type: dict
+ suboptions:
+ set:
+ description: Log changes in adjacency state
+ type: bool
+ detail:
+ description: Log all state changes
+ type: bool
+ manet:
+ description: Specify MANET OSPF parameters
+ type: dict
+ suboptions:
+ cache:
+ description: Specify MANET cache sizes
+ type: dict
+ suboptions:
+ acknowledgement:
+ description:
+ - Specify MANET acknowledgement cache size
+ - Maximum number of acknowledgements in cache
+ type: int
+ update:
+ description:
+ - Specify MANET LSA cache size
+ - Maximum number of LSAs in cache
+ type: int
+ hello:
+ description: Unicast Hellos rather than multicast
+ type: dict
+ suboptions:
+ multicast:
+ description: Multicast Hello requests and responses rather than unicast
+ type: bool
+ unicast:
+ description: Unicast Hello requests and responses rather than multicast
+ type: bool
+ peering:
+ description: MANET OSPF Smart Peering
+ type: dict
+ suboptions:
+ set:
+ description: Enable selective peering
+ type: bool
+ disable:
+ description: Disable selective peering
+ type: bool
+ per_interface:
+ description: Select peers per interface rather than per node
+ type: bool
+ redundancy:
+ description:
+ - Redundant paths
+ - Number of redundant OSPF paths
+ type: int
+ willingness:
+ description: Specify and Relay willingness value
+ type: int
+ max_lsa:
+ description: Maximum number of non self-generated LSAs to accept
+ type: dict
+ suboptions:
+ number:
+ description:
+ - Maximum number of non self-generated LSAs to accept
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ threshold_value:
+ description:
+ - Threshold value (%) at which to generate a warning msg
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ ignore_count:
+ description:
+ - Maximum number of times adjacencies can be suppressed
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ ignore_time:
+ description:
+ - Number of minutes during which all adjacencies are suppressed
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ reset_time:
+ description:
+ - Number of minutes after which ignore-count is reset to zero
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ warning_only:
+ description: Only give a warning message when limit is exceeded
+ type: bool
+ max_metric:
+ description:
+ - Set maximum metric
+ - Maximum metric in self-originated router-LSAs
+ type: dict
+ suboptions:
+ disable:
+ description: disable maximum metric in self-originated router-LSAs
+ type: bool
+ external_lsa:
+ description:
+ - Override external-lsa metric with max-metric value
+ - Overriding metric in external-LSAs
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ inter_area_lsas:
+ description:
+ - Override inter-area-lsas metric with max-metric value
+ - Overriding metric in inter-area-LSAs
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ on_startup:
+ description: Set maximum metric temporarily after reboot
+ type: dict
+ suboptions:
+ time:
+ description:
+ - Time, in seconds, router-LSAs are originated with max-metric
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ wait_for_bgp:
+ description: Let BGP decide when to originate router-LSA with normal metric
+ type: bool
+ stub_prefix_lsa:
+ description: Set maximum metric for stub links in prefix LSAs
+ type: bool
+ maximum_paths:
+ description:
+ - Forward packets over multiple paths
+ - Number of paths
+ type: int
+ passive_interface:
+ description: Suppress routing updates on an interface
+ type: str
+ prefix_suppression:
+ description: Prefix suppression
+ type: dict
+ suboptions:
+ enable:
+ description: Enable prefix suppression
+ type: bool
+ disable:
+ description: Disable prefix suppression
+ type: bool
+ queue_depth:
+ description: Hello/Router process queue depth
+ type: dict
+ suboptions:
+ hello:
+ description: OSPF Hello process queue depth
+ type: dict
+ suboptions:
+ max_packets:
+ description: maximum number of packets in the queue
+ type: int
+ unlimited:
+ description: Unlimited queue depth
+ type: bool
+ update:
+ description: OSPF Router process queue depth
+ type: dict
+ suboptions:
+ max_packets:
+ description: maximum number of packets in the queue
+ type: int
+ unlimited:
+ description: Unlimited queue depth
+ type: bool
+ router_id:
+ description:
+ - Router-id address for this OSPF process
+ - OSPF router-id in IP address format (A.B.C.D)
+ type: str
+ shutdown:
+ description: Shutdown the router process
+ type: dict
+ suboptions:
+ enable:
+ description: Shutdown the router process
+ type: bool
+ disable:
+ description: Disable Shutdown
+ type: bool
+ summary_prefix:
+ description: Configure IP address summaries
+ type: dict
+ suboptions:
+ address:
+ description:
+ - IP summary address (A.B.C.D)
+ - IP prefix <network>/<length> (A.B.C.D/nn)
+ type: str
+ mask:
+ description: IP Summary mask
+ type: str
+ not_advertise:
+ description: Do not advertise or translate
+ type: bool
+ nssa_only:
+ description: Limit summary to NSSA areas
+ type: bool
+ tag:
+ description: Set tag
+ type: int
+ timers:
+ description: Adjust routing timers
+ type: dict
+ suboptions:
+ lsa:
+ description:
+ - OSPF LSA timers, arrival timer
+ - The minimum interval in milliseconds between accepting the same LSA
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ manet:
+ description: OSPF MANET timers
+ type: dict
+ suboptions:
+ cache:
+ description: Specify MANET cache sizes
+ type: dict
+ suboptions:
+ acknowledgement:
+ description: Specify MANET acknowledgement cache size
+ type: int
+ redundancy:
+ description: Specify MANET LSA cache size
+ type: int
+ hello:
+ description:
+ - Unicast Hellos rather than multicast
+ - Unicast Hello requests and responses rather than multicast
+ type: bool
+ peering:
+ description: MANET OSPF Smart Peering
+ type: dict
+ suboptions:
+ set:
+ description: Enable selective peering
+ type: bool
+ per_interface:
+ description: Select peers per interface rather than per node
+ type: bool
+ redundancy:
+ description:
+ - Redundant paths
+ - Number of redundant OSPF paths
+ type: int
+ willingness:
+ description: Specify and Relay willingness value
+ type: int
+ pacing:
+ description: OSPF pacing timers
+ type: dict
+ suboptions:
+ flood:
+ description:
+ - OSPF flood pacing timer
+ - The minimum interval in msec to pace limit flooding on interface
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ lsa_group:
+ description:
+ - OSPF LSA group pacing timer
+ - Interval in sec between group of LSA being refreshed or maxaged
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ retransmission:
+ description:
+ - OSPF retransmission pacing timer
+ - The minimum interval in msec between neighbor retransmissions
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ throttle:
+ description: OSPF throttle timers
+ type: dict
+ suboptions:
+ lsa:
+ description: OSPF LSA throttle timers
+ type: dict
+ suboptions:
+ first_delay:
+ description:
+ - Delay to generate first occurrence of LSA in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ min_delay:
+ description:
+ - Minimum delay between originating the same LSA in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ max_delay:
+ description:
+ - Maximum delay between originating the same LSA in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ spf:
+ description: OSPF SPF throttle timers
+ - Delay between receiving a change to SPF calculation in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: dict
+ suboptions:
+ receive_delay:
+ description:
+ - Delay between receiving a change to SPF calculation in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ between_delay:
+ description:
+ - Delay between first and second SPF calculation in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ max_delay:
+ description:
+ - Maximum wait time in milliseconds for SPF calculations
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ adjacency:
+ description: Control adjacency formation
+ type: dict
+ suboptions:
+ min_adjacency:
+ description:
+ - Initial number of adjacencies allowed to be forming in an area
+ - Please refer vendor documentation for valid values
+ type: int
+ max_adjacency:
+ description:
+ - Maximum number of adjacencies allowed to be forming
+ - Please refer vendor documentation for valid values
+ type: int
+ none:
+ description: No initial
+ type: bool
+ areas:
+ description: OSPF area parameters
+ type: list
+ elements: dict
+ suboptions:
+ area_id:
+ description:
+ - OSPF area ID as a decimal value. Please refer vendor documentation
+ of Valid values.
+ - OSPF area ID in IP address format(e.g. A.B.C.D)
+ type: str
+ authentication:
+ description: Authentication parameters
+ type: dict
+ suboptions:
+ key_chain:
+ description: Use a key-chain for cryptographic authentication keys
+ type: str
+ ipsec:
+ description: Use IPsec authentication
+ type: dict
+ suboptions:
+ spi:
+ description: Set the SPI (Security Parameters Index)
+ type: int
+ md5:
+ description: Use MD5 authentication
+ type: int
+ sha1:
+ description: Use SHA-1 authentication
+ type: int
+ hex_string:
+ description: SHA-1 key (40 chars)
+ type: str
+ default_cost:
+ description:
+ - Set the summary default-cost of a NSSA/stub area
+ - Stub's advertised external route metric
+ - Note, please refer vendor documentation for respective valid values
+ type: int
+ nssa:
+ description: Specify a NSSA area
+ type: dict
+ suboptions:
+ set:
+ description: Enable a NSSA area
+ type: bool
+ default_information_originate:
+ description: Originate Type 7 default into NSSA area
+ type: dict
+ suboptions:
+ metric:
+ description: OSPF default metric
+ type: int
+ metric_type:
+ description:
+ - OSPF metric type for default routes
+ - OSPF Link State type
+ type: int
+ choices: [1, 2]
+ nssa_only:
+ description: Limit default advertisement to this NSSA area
+ type: bool
+ no_redistribution:
+ description: No redistribution into this NSSA area
+ type: bool
+ no_summary:
+ description: Do not send summary LSA into NSSA
+ type: bool
+ translate:
+ description:
+ - Translate LSA
+ - Always translate LSAs on this ABR
+ - Suppress forwarding address in translated LSAs
+ type: str
+ choices: ["always", "suppress-fa"]
+ stub:
+ description:
+ - Specify a stub area
+ - Backbone can not be configured as stub area
+ type: dict
+ suboptions:
+ set:
+ description: Enable a stub area
+ type: bool
+ no_summary:
+ description: Do not send summary LSA into stub area
+ type: bool
+ authentication:
+ description:
+ - Authentication parameter mode
+ - Deployment mode of operation
+ type: bool
+ auto_cost:
+ description: Calculate OSPF interface cost according to bandwidth
+ type: dict
+ suboptions:
+ set:
+ description: Enable OSPF auto-cost
+ type: bool
+ reference_bandwidth:
+ description:
+ - Use reference bandwidth method to assign OSPF cost
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ bfd:
+ description:
+ - BFD configuration commands
+ - Enable BFD on all interfaces
+ type: bool
+ compatible:
+ description: OSPFv3 router compatibility list
+ type: dict
+ suboptions:
+ rfc1583:
+ description: compatible with RFC 1583
+ type: bool
+ rfc1587:
+ description: compatible with RFC 1587
+ type: bool
+ rfc5243:
+ description: supports DBD exchange optimization
+ type: bool
+ event_log:
+ description: Event Logging
+ type: dict
+ suboptions:
+ enable:
+ description: Enable event Logging
+ type: bool
+ one_shot:
+ description: Disable Logging When Log Buffer Becomes Full
+ type: bool
+ pause:
+ description: Pause Event Logging
+ type: bool
+ size:
+ description:
+ - Maximum Number of Events Stored in the Event Log
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ graceful_restart:
+ description: Graceful-restart options for helper support
+ type: dict
+ suboptions:
+ disable:
+ description: disable helper support
+ type: bool
+ strict_lsa_checking:
+ description: enable helper strict LSA checking
+ type: bool
+ help:
+ description: Description of the interactive help system
+ type: bool
+ interface_id:
+ description:
+ - Source of the interface ID
+ - SNMP MIB ifIndex
+ type: bool
+ limit:
+ description: Limit a specific OSPF feature and LS update, DBD, and LS request retransmissions
+ type: dict
+ suboptions:
+ dc:
+ description: Demand circuit retransmissions
+ type: dict
+ suboptions:
+ number:
+ description: The maximum number of retransmissions
+ type: int
+ disable:
+ description: Disable the feature
+ type: bool
+ non_dc:
+ description: Non-demand-circuit retransmissions
+ type: dict
+ suboptions:
+ number:
+ description: The maximum number of retransmissions
+ type: int
+ disable:
+ description: Disable the feature
+ type: bool
+ local_rib_criteria:
+ description: Enable or disable usage of local RIB as route criteria
+ type: dict
+ suboptions:
+ enable:
+ description: Enable usage of local RIB as route criteria
+ type: bool
+ forwarding_address:
+ description: Local RIB used to validate external/NSSA forwarding addresses
+ type: bool
+ inter_area_summary:
+ description: Local RIB used as criteria for inter-area summaries
+ type: bool
+ nssa_translation:
+ description: Local RIB used as criteria for NSSA translation
+ type: bool
+ log_adjacency_changes:
+ description: Log changes in adjacency state
+ type: dict
+ suboptions:
+ set:
+ description: Log changes in adjacency state
+ type: bool
+ detail:
+ description: Log all state changes
+ type: bool
+ manet:
+ description: Specify MANET OSPF parameters
+ type: dict
+ suboptions:
+ cache:
+ description: Specify MANET cache sizes
+ type: dict
+ suboptions:
+ acknowledgement:
+ description: Specify MANET acknowledgement cache size
+ type: int
+ redundancy:
+ description: Specify MANET LSA cache size
+ type: int
+ hello:
+ description:
+ - Unicast Hellos rather than multicast
+ - Unicast Hello requests and responses rather than multicast
+ type: bool
+ peering:
+ description: MANET OSPF Smart Peering
+ type: dict
+ suboptions:
+ set:
+ description: Enable selective peering
+ type: bool
+ per_interface:
+ description: Select peers per interface rather than per node
+ type: bool
+ redundancy:
+ description:
+ - Redundant paths
+ - Number of redundant OSPF paths
+ type: int
+ willingness:
+ description: Specify and Relay willingness value
+ type: int
+ max_lsa:
+ description: Maximum number of non self-generated LSAs to accept
+ type: dict
+ suboptions:
+ number:
+ description:
+ - Maximum number of non self-generated LSAs to accept
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ threshold_value:
+ description:
+ - Threshold value (%) at which to generate a warning msg
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ ignore_count:
+ description:
+ - Maximum number of times adjacencies can be suppressed
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ ignore_time:
+ description:
+ - Number of minutes during which all adjacencies are suppressed
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ reset_time:
+ description:
+ - Number of minutes after which ignore-count is reset to zero
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ warning_only:
+ description: Only give a warning message when limit is exceeded
+ type: bool
+ max_metric:
+ description: Set maximum metric
+ type: dict
+ suboptions:
+ router_lsa:
+ description: Maximum metric in self-originated router-LSAs
+ type: bool
+ required: true
+ external_lsa:
+ description:
+ - Override external-lsa metric with max-metric value
+ - Overriding metric in external-LSAs
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ include_stub:
+ description: Set maximum metric for stub links in router-LSAs
+ type: bool
+ on_startup:
+ description: Set maximum metric temporarily after reboot
+ type: dict
+ suboptions:
+ time:
+ description:
+ - Time, in seconds, router-LSAs are originated with max-metric
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ wait_for_bgp:
+ description: Let BGP decide when to originate router-LSA with normal metric
+ type: bool
+ summary_lsa:
+ description:
+ - Override summary-lsa metric with max-metric value
+ - Note, please refer vendor documentation for respective valid range
+ type: int
+ passive_interface:
+ description: Suppress routing updates on an interface
+ type: str
+ prefix_suppression:
+ description: Enable prefix suppression
+ type: bool
+ queue_depth:
+ description: Hello/Router process queue depth
+ type: dict
+ suboptions:
+ hello:
+ description: OSPF Hello process queue depth
+ type: dict
+ suboptions:
+ max_packets:
+ description: maximum number of packets in the queue
+ type: int
+ unlimited:
+ description: Unlimited queue depth
+ type: bool
+ router_id:
+ description:
+ - Router-id address for this OSPF process
+ - OSPF router-id in IP address format (A.B.C.D)
+ type: str
+ shutdown:
+ description: Shutdown the router process
+ type: bool
+ timers:
+ description: Adjust routing timers
+ type: dict
+ suboptions:
+ lsa:
+ description:
+ - OSPF LSA timers, arrival timer
+ - The minimum interval in milliseconds between accepting the same LSA
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ manet:
+ description: OSPF MANET timers
+ type: dict
+ suboptions:
+ cache:
+ description: Specify MANET cache sizes
+ type: dict
+ suboptions:
+ acknowledgement:
+ description: Specify MANET acknowledgement cache size
+ type: int
+ redundancy:
+ description: Specify MANET LSA cache size
+ type: int
+ hello:
+ description:
+ - Unicast Hellos rather than multicast
+ - Unicast Hello requests and responses rather than multicast
+ type: bool
+ peering:
+ description: MANET OSPF Smart Peering
+ type: dict
+ suboptions:
+ set:
+ description: Enable selective peering
+ type: bool
+ per_interface:
+ description: Select peers per interface rather than per node
+ type: bool
+ redundancy:
+ description:
+ - Redundant paths
+ - Number of redundant OSPF paths
+ type: int
+ willingness:
+ description: Specify and Relay willingness value
+ type: int
+ pacing:
+ description: OSPF pacing timers
+ type: dict
+ suboptions:
+ flood:
+ description:
+ - OSPF flood pacing timer
+ - The minimum interval in msec to pace limit flooding on interface
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ lsa_group:
+ description:
+ - OSPF LSA group pacing timer
+ - Interval in sec between group of LSA being refreshed or maxaged
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ retransmission:
+ description:
+ - OSPF retransmission pacing timer
+ - The minimum interval in msec between neighbor retransmissions
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ throttle:
+ description: OSPF throttle timers
+ type: dict
+ suboptions:
+ lsa:
+ description: OSPF LSA throttle timers
+ type: dict
+ suboptions:
+ first_delay:
+ description:
+ - Delay to generate first occurrence of LSA in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ min_delay:
+ description:
+ - Minimum delay between originating the same LSA in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ max_delay:
+ description:
+ - Maximum delay between originating the same LSA in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ spf:
+ description: OSPF SPF throttle timers
+ - Delay between receiving a change to SPF calculation in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: dict
+ suboptions:
+ receive_delay:
+ description:
+ - Delay between receiving a change to SPF calculation in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ between_delay:
+ description:
+ - Delay between first and second SPF calculation in milliseconds
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ max_delay:
+ description:
+ - Maximum wait time in milliseconds for SPF calculations
+ - Note, refer vendor documentation for respective valid values
+ type: int
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device by
+ executing the command B(sh running-config | section ^router ospfv3).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ description:
+ - The state the configuration should be left in
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device.
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result. For state I(rendered) active connection to remote host is
+ not required.
+ - The state I(gathered) will fetch the running configuration from device and transform
+ it into structured data in the format as per the resource module argspec and
+ the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result. The value of C(running_config)
+ option should be the same format as the output of command I(show running-config
+ | include ip route|ipv6 route) executed on device. For state I(parsed) active
+ connection to remote host is not required.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - parsed
+ - rendered
+ default: merged
+"""
+
+EXAMPLES = """
+# Using deleted
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospfv3
+# router ospfv3 1
+# max-metric router-lsa on-startup 110
+# area 10 nssa default-information-originate metric 10
+# !
+# address-family ipv4 unicast vrf blue
+# adjacency stagger 50 50
+# area 25 nssa default-information-originate metric 25 nssa-only
+# exit-address-family
+# router ospfv3 200
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# !
+# address-family ipv4 unicast
+# adjacency stagger 200 200
+# exit-address-family
+
+- name: Delete provided OSPF V3 processes
+ cisco.ios.ios_ospfv3:
+ config:
+ processes:
+ - process_id: 1
+ state: deleted
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "no router ospfv3 1"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^router ospfv3
+# router ospfv3 200
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# !
+# address-family ipv4 unicast
+# adjacency stagger 200 200
+# exit-address-family
+
+# Using deleted without any config passed (NOTE: This will delete all OSPFV3 configuration from device)
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospfv3
+# router ospfv3 1
+# max-metric router-lsa on-startup 110
+# area 10 nssa default-information-originate metric 10
+# !
+# address-family ipv4 unicast vrf blue
+# adjacency stagger 50 50
+# area 25 nssa default-information-originate metric 25 nssa-only
+# exit-address-family
+# router ospfv3 200
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# !
+# address-family ipv4 unicast
+# adjacency stagger 200 200
+# exit-address-family
+
+- name: Delete all OSPF processes
+ cisco.ios.ios_ospfv3:
+ state: deleted
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "no router ospfv3 200",
+# "no router ospfv3 1"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^router ospfv3
+# router-ios#
+
+# Using merged
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospfv3
+# router-ios#
+
+- name: Merge provided OSPFV3 configuration
+ cisco.ios.ios_ospfv3:
+ config:
+ processes:
+ - process_id: 1
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 110
+ address_family:
+ - afi: ipv4
+ unicast: true
+ vrf: blue
+ adjacency:
+ min_adjacency: 50
+ max_adjacency: 50
+ areas:
+ - area_id: 25
+ nssa:
+ default_information_originate:
+ metric: 25
+ nssa_only: true
+ areas:
+ - area_id: "10"
+ nssa:
+ default_information_originate:
+ metric: 10
+ timers:
+ throttle:
+ lsa:
+ first_delay: 12
+ min_delay: 14
+ max_delay: 16
+ - process_id: 200
+ address_family:
+ - afi: ipv4
+ unicast: true
+ adjacency:
+ min_adjacency: 200
+ max_adjacency: 200
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 100
+ auto_cost:
+ reference_bandwidth: 4
+ state: merged
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "router ospfv3 1",
+# "max-metric router-lsa on-startup 110",
+# "area 10 nssa default-information-originate metric 10",
+# "address-family ipv4 unicast vrf blue",
+# "adjacency stagger 50 50",
+# "area 25 nssa default-information-originate metric 25 nssa-only",
+# "exit-address-family",
+# "router ospfv3 200",
+# "auto-cost reference-bandwidth 4",
+# "max-metric router-lsa on-startup 100",
+# "address-family ipv4 unicast",
+# "adjacency stagger 200 200",
+# "exit-address-family"
+# ]
+
+# After state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospfv3
+# router ospfv3 1
+# max-metric router-lsa on-startup 110
+# area 10 nssa default-information-originate metric 10
+# !
+# address-family ipv4 unicast vrf blue
+# adjacency stagger 50 50
+# area 25 nssa default-information-originate metric 25 nssa-only
+# exit-address-family
+# router ospfv3 200
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# !
+# address-family ipv4 unicast
+# adjacency stagger 200 200
+# exit-address-family
+
+# Using overridden
+
+# Before state:
+# -------------
+#
+# router ospfv3 1
+# max-metric router-lsa on-startup 110
+# area 10 nssa default-information-originate metric 10
+# !
+# address-family ipv4 unicast vrf blue
+# adjacency stagger 50 50
+# area 25 nssa default-information-originate metric 25 nssa-only
+# exit-address-family
+# router ospfv3 200
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# !
+# address-family ipv4 unicast
+# adjacency stagger 200 200
+# exit-address-family
+
+- name: Override provided OSPFV3 configuration
+ cisco.ios.ios_ospfv3:
+ config:
+ processes:
+ - process_id: 200
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 200
+ address_family:
+ - afi: ipv4
+ unicast: true
+ adjacency:
+ min_adjacency: 50
+ max_adjacency: 50
+ areas:
+ - area_id: 200
+ nssa:
+ default_information_originate:
+ metric: 200
+ nssa_only: true
+ areas:
+ - area_id: "10"
+ nssa:
+ default_information_originate:
+ metric: 10
+ state: overridden
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "no router ospfv3 1",
+# "router ospfv3 200",
+# "no auto-cost reference-bandwidth 4",
+# "max-metric router-lsa on-startup 200",
+# "area 10 nssa default-information-originate metric 10",
+# "address-family ipv4 unicast",
+# "adjacency stagger 50 50",
+# "area 200 nssa default-information-originate metric 200 nssa-only",
+# "exit-address-family"
+# ]
+
+# After state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospfv3
+# router ospfv3 200
+# max-metric router-lsa on-startup 200
+# area 10 nssa default-information-originate metric 10
+# !
+# address-family ipv4 unicast
+# adjacency stagger 50 50
+# area 200 nssa default-information-originate metric 200 nssa-only
+# exit-address-family
+
+# Using replaced
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospfv3
+# router ospfv3 1
+# max-metric router-lsa on-startup 110
+# area 10 nssa default-information-originate metric 10
+# !
+# address-family ipv4 unicast vrf blue
+# adjacency stagger 50 50
+# area 25 nssa default-information-originate metric 25 nssa-only
+# exit-address-family
+# router ospfv3 200
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# !
+# address-family ipv4 unicast
+# adjacency stagger 200 200
+# exit-address-family
+
+- name: Replaced provided OSPFV3 configuration
+ cisco.ios.ios_ospfv3:
+ config:
+ processes:
+ - process_id: 200
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 200
+ address_family:
+ - afi: ipv4
+ unicast: true
+ adjacency:
+ min_adjacency: 50
+ max_adjacency: 50
+ areas:
+ - area_id: 200
+ nssa:
+ default_information_originate:
+ metric: 200
+ nssa_only: true
+ areas:
+ - area_id: "10"
+ nssa:
+ default_information_originate:
+ metric: 10
+ state: replaced
+
+# Commands Fired:
+# ---------------
+# "commands": [
+# "router ospfv3 200",
+# "no auto-cost reference-bandwidth 4",
+# "max-metric router-lsa on-startup 200",
+# "area 10 nssa default-information-originate metric 10",
+# "address-family ipv4 unicast",
+# "adjacency stagger 50 50",
+# "area 200 nssa default-information-originate metric 200 nssa-only",
+# "exit-address-family"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^router ospfv3
+# router ospfv3 1
+# max-metric router-lsa on-startup 110
+# area 10 nssa default-information-originate metric 10
+# !
+# address-family ipv4 unicast vrf blue
+# adjacency stagger 50 50
+# area 25 nssa default-information-originate metric 25 nssa-only
+# exit-address-family
+# router ospfv3 200
+# max-metric router-lsa on-startup 200
+# area 10 nssa default-information-originate metric 10
+# !
+# address-family ipv4 unicast
+# adjacency stagger 50 50
+# area 200 nssa default-information-originate metric 200 nssa-only
+# exit-address-family
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^router ospfv3
+# router ospfv3 1
+# max-metric router-lsa on-startup 110
+# area 10 nssa default-information-originate metric 10
+# !
+# address-family ipv4 unicast vrf blue
+# adjacency stagger 50 50
+# area 25 nssa default-information-originate metric 25 nssa-only
+# exit-address-family
+# router ospfv3 200
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# !
+# address-family ipv4 unicast
+# adjacency stagger 200 200
+# exit-address-family
+
+- name: Gather OSPFV3 provided configurations
+ cisco.ios.ios_ospfv3:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": {
+# "processes": [
+# {
+# "address_family": [
+# {
+# "adjacency": {
+# "max_adjacency": 50,
+# "min_adjacency": 50
+# },
+# "afi": "ipv4",
+# "areas": [
+# {
+# "area_id": "25",
+# "nssa": {
+# "default_information_originate": {
+# "metric": 25,
+# "nssa_only": true
+# }
+# }
+# }
+# ],
+# "unicast": true,
+# "vrf": "blue"
+# }
+# ],
+# "areas": [
+# {
+# "area_id": "10",
+# "nssa": {
+# "default_information_originate": {
+# "metric": 10
+# }
+# }
+# }
+# ],
+# "max_metric": {
+# "on_startup": {
+# "time": 110
+# },
+# "router_lsa": true
+# },
+# "process_id": 1
+# },
+# {
+# "address_family": [
+# {
+# "adjacency": {
+# "max_adjacency": 200,
+# "min_adjacency": 200
+# },
+# "afi": "ipv4",
+# "unicast": true
+# }
+# ],
+# "auto_cost": {
+# "reference_bandwidth": 4
+# },
+# "max_metric": {
+# "on_startup": {
+# "time": 100
+# },
+# "router_lsa": true
+# },
+# "process_id": 200
+# }
+# ]
+# }
+
+# After state:
+# ------------
+#
+# router-ios#sh running-config | section ^router ospfv3
+# router ospfv3 1
+# max-metric router-lsa on-startup 110
+# area 10 nssa default-information-originate metric 10
+# !
+# address-family ipv4 unicast vrf blue
+# adjacency stagger 50 50
+# area 25 nssa default-information-originate metric 25 nssa-only
+# exit-address-family
+# router ospfv3 200
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# !
+# address-family ipv4 unicast
+# adjacency stagger 200 200
+# exit-address-family
+
+# Using Rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_ospfv3:
+ config:
+ processes:
+ - process_id: 1
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 110
+ address_family:
+ - afi: ipv4
+ unicast: true
+ vrf: blue
+ adjacency:
+ min_adjacency: 50
+ max_adjacency: 50
+ areas:
+ - area_id: 25
+ nssa:
+ default_information_originate:
+ metric: 25
+ nssa_only: true
+ areas:
+ - area_id: "10"
+ nssa:
+ default_information_originate:
+ metric: 10
+ timers:
+ throttle:
+ lsa:
+ first_delay: 12
+ min_delay: 14
+ max_delay: 16
+ - process_id: 200
+ address_family:
+ - afi: ipv4
+ unicast: true
+ adjacency:
+ min_adjacency: 200
+ max_adjacency: 200
+ max_metric:
+ router_lsa: true
+ on_startup:
+ time: 100
+ auto_cost:
+ reference_bandwidth: 4
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "router ospfv3 1",
+# "max-metric router-lsa on-startup 110",
+# "area 10 nssa default-information-originate metric 10",
+# "address-family ipv4 unicast vrf blue",
+# "adjacency stagger 50 50",
+# "area 25 nssa default-information-originate metric 25 nssa-only",
+# "exit-address-family",
+# "router ospfv3 200",
+# "auto-cost reference-bandwidth 4",
+# "max-metric router-lsa on-startup 100",
+# "address-family ipv4 unicast",
+# "adjacency stagger 200 200",
+# "exit-address-family"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# router ospfv3 1
+# max-metric router-lsa on-startup 110
+# area 10 nssa default-information-originate metric 10
+# !
+# address-family ipv4 unicast vrf blue
+# adjacency stagger 50 50
+# area 25 nssa default-information-originate metric 25 nssa-only
+# exit-address-family
+# router ospfv3 200
+# max-metric router-lsa on-startup 100
+# auto-cost reference-bandwidth 4
+# !
+# address-family ipv4 unicast
+# adjacency stagger 200 200
+# exit-address-family
+
+- name: Parse the provided configuration with the existing running configuration
+ cisco.ios.ios_ospfv3:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": {
+# "processes": [
+# {
+# "address_family": [
+# {
+# "adjacency": {
+# "max_adjacency": 50,
+# "min_adjacency": 50
+# },
+# "afi": "ipv4",
+# "areas": [
+# {
+# "area_id": "25",
+# "nssa": {
+# "default_information_originate": {
+# "metric": 25,
+# "nssa_only": true
+# }
+# }
+# }
+# ],
+# "unicast": true,
+# "vrf": "blue"
+# }
+# ],
+# "areas": [
+# {
+# "area_id": "10",
+# "nssa": {
+# "default_information_originate": {
+# "metric": 10
+# }
+# }
+# }
+# ],
+# "max_metric": {
+# "on_startup": {
+# "time": 110
+# },
+# "router_lsa": true
+# },
+# "process_id": 1
+# }
+# ]
+# }
+
+"""
+
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: dict
+after:
+ description: The resulting configuration model invocation.
+ returned: when changed
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: dict
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: always
+ type: list
+ sample: ['router ospfv3 1', 'address-family ipv4 unicast vrf blue', 'adjacency stagger 50 50']
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.ospfv3.ospfv3 import (
+ Ospfv3Args,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.ospfv3.ospfv3 import (
+ Ospfv3,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+ :returns: the result form module invocation
+ """
+ required_if = [
+ ("state", "merged", ("config",)),
+ ("state", "replaced", ("config",)),
+ ("state", "overridden", ("config",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+
+ mutually_exclusive = [("config", "running_config")]
+
+ module = AnsibleModule(
+ argument_spec=Ospfv3Args.argument_spec,
+ required_if=required_if,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+
+ result = Ospfv3(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_ping.py b/ansible_collections/cisco/ios/plugins/modules/ios_ping.py
new file mode 100644
index 000000000..c5fdd8153
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_ping.py
@@ -0,0 +1,171 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2022 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
+
+DOCUMENTATION = """
+module: ios_ping
+short_description: Tests reachability using ping from IOS switch.
+description:
+ - Tests reachability using ping from switch to a remote destination.
+ - For a general purpose network module, see the L(net_ping,https://docs.ansible.com/ansible/latest/collections/ansible/netcommon/net_ping_module.html)
+ module.
+ - For Windows targets, use the L(win_ping,https://docs.ansible.com/ansible/latest/collections/ansible/windows/win_ping_module.html)
+ module instead.
+ - For targets running Python, use the L(ping,https://docs.ansible.com/ansible/latest/collections/ansible/builtin/ping_module.html)
+ module instead.
+version_added: 1.0.0
+author:
+ - Jacob McGill (@jmcgill298)
+ - Sagar Paul (@KB-perByte)
+options:
+ count:
+ description:
+ - Number of packets to send.
+ type: int
+ afi:
+ description:
+ - Define echo type ip or ipv6.
+ choices:
+ - ip
+ - ipv6
+ default: ip
+ type: str
+ dest:
+ description:
+ - The IP Address or hostname (resolvable by switch) of the remote node.
+ required: true
+ type: str
+ df_bit:
+ description:
+ - Set the DF bit.
+ default: false
+ type: bool
+ source:
+ description:
+ - The source IP Address.
+ type: str
+ egress:
+ description:
+ - Force egress interface bypassing routing.
+ type: str
+ ingress:
+ description:
+ - LAN source interface for Ingress.
+ type: str
+ timeout:
+ description:
+ - specify timeout interval.
+ type: int
+ state:
+ description:
+ - Determines if the expected result is success or fail.
+ choices:
+ - absent
+ - present
+ default: present
+ type: str
+ vrf:
+ description:
+ - The VRF to use for forwarding.
+ type: str
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - For a general purpose network module, see the L(net_ping,https://docs.ansible.com/ansible/latest/collections/ansible/netcommon/net_ping_module.html)
+ module.
+ - For Windows targets, use the L(win_ping,https://docs.ansible.com/ansible/latest/collections/ansible/windows/win_ping_module.html)
+ module instead.
+ - For targets running Python, use the L(ping,https://docs.ansible.com/ansible/latest/collections/ansible/builtin/ping_module.html) module instead.
+"""
+
+EXAMPLES = """
+- name: Test reachability to 198.51.100.251 using default vrf
+ cisco.ios.ios_ping:
+ dest: 198.51.100.251
+
+- name: Test reachability to 198.51.100.252 using prod vrf
+ cisco.ios.ios_ping:
+ dest: 198.51.100.252
+ vrf: prod
+ afi: ip
+
+- name: Test un reachability to 198.51.100.253 using default vrf
+ cisco.ios.ios_ping:
+ dest: 198.51.100.253
+ state: absent
+
+- name: Test reachability to 198.51.100.250 using prod vrf and setting count and source
+ cisco.ios.ios_ping:
+ dest: 198.51.100.250
+ source: loopback0
+ vrf: prod
+ count: 20
+
+- name: Test reachability to 198.51.100.249 using df-bit and size
+ cisco.ios.ios_ping:
+ dest: 198.51.100.249
+ df_bit: true
+ size: 1400
+
+- name: Test reachability to ipv6 address
+ cisco.ios.ios_ping:
+ dest: 2001:db8:ffff:ffff:ffff:ffff:ffff:ffff
+ afi: ipv6
+"""
+
+RETURN = """
+commands:
+ description: Show the command sent.
+ returned: always
+ type: list
+ sample: ["ping vrf prod 198.51.100.251 count 20 source loopback0"]
+packet_loss:
+ description: Percentage of packets lost.
+ returned: always
+ type: str
+ sample: "0%"
+packets_rx:
+ description: Packets successfully received.
+ returned: always
+ type: int
+ sample: 20
+packets_tx:
+ description: Packets successfully transmitted.
+ returned: always
+ type: int
+ sample: 20
+rtt:
+ description: Show RTT stats.
+ returned: always
+ type: dict
+ sample: {"avg": 2, "max": 8, "min": 1}
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.ping.ping import (
+ PingArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.ping.ping import Ping
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ module = AnsibleModule(argument_spec=PingArgs.argument_spec)
+
+ result = Ping(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_prefix_lists.py b/ansible_collections/cisco/ios/plugins/modules/ios_prefix_lists.py
new file mode 100644
index 000000000..23c9de9e1
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_prefix_lists.py
@@ -0,0 +1,922 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2021 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+"""
+The module file for cisco.ios_prefix_lists
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_prefix_lists
+short_description: Resource module to configure prefix lists.
+description:
+ - This module configures and manages the attributes of prefix list on Cisco IOS.
+version_added: 2.2.0
+author: Sumit Jaiswal (@justjais)
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ config:
+ description: A list of configurations for Prefix lists.
+ type: list
+ elements: dict
+ suboptions:
+ afi:
+ description:
+ - The Address Family Indicator (AFI) for the prefix list.
+ type: str
+ choices: ["ipv4", "ipv6"]
+ prefix_lists:
+ description: List of Prefix-lists.
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Name of a prefix-list
+ type: str
+ description:
+ description: Prefix-list specific description
+ type: str
+ entries:
+ description: Prefix-lists supported params.
+ type: list
+ elements: dict
+ suboptions:
+ action:
+ description: Specify packets to be rejected or forwarded
+ type: str
+ choices: ["deny", "permit"]
+ sequence:
+ description: sequence number of an entry
+ type: int
+ description:
+ description:
+ - Prefix-list specific description
+ - Description param at entries level is DEPRECATED
+ - New Description is introduced at prefix_lists level, please
+ use the Description param defined at prefix_lists level instead of
+ Description param at entries level, as at this level description option
+ will get removed in a future release.
+ type: str
+ prefix:
+ description:
+ - IPv4 prefix <network>/<length>, e.g., A.B.C.D/nn
+ - IPv6 prefix <network>/<length>, e.g., X:X:X:X::X/<0-128>
+ type: str
+ ge:
+ description: Minimum prefix length to be matched
+ type: int
+ le:
+ description: Maximum prefix length to be matched
+ type: int
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device by
+ executing the command B(sh bgp).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ description:
+ - The state the configuration should be left in
+ - The states I(merged) is the default state which merges the want and have config, but
+ for Prefix-List module as the IOS platform doesn't allow update of Prefix-List over an
+ pre-existing Prefix-List, same way Prefix-Lists resource module will error out for
+ respective scenario and only addition of new Prefix-List over new sequence will be
+ allowed with merge state.
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device.
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result. For state I(rendered) active connection to remote host is
+ not required.
+ - The state I(gathered) will fetch the running configuration from device and transform
+ it into structured data in the format as per the resource module argspec and
+ the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result. The value of C(running_config)
+ option should be the same format as the output of command I(sh running-config
+ | section ^ip prefix-list|^ipv6 prefix-list) executed on device. For state I(parsed) active
+ connection to remote host is not required.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - parsed
+ - rendered
+ default: merged
+"""
+
+EXAMPLES = """
+# Using deleted by Name
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^ip prefix-list|^ipv6 prefix-list
+# ip prefix-list 10 description this is test description
+# ip prefix-list 10 seq 5 deny 1.0.0.0/8 le 15
+# ip prefix-list 10 seq 10 deny 35.0.0.0/8 ge 10
+# ip prefix-list 10 seq 15 deny 12.0.0.0/8 ge 15
+# ip prefix-list 10 seq 20 deny 14.0.0.0/8 ge 20 le 21
+# ip prefix-list test description this is test
+# ip prefix-list test seq 50 deny 12.0.0.0/8 ge 15
+# ip prefix-list test_prefix description this is for prefix-list
+# ip prefix-list test_prefix seq 5 deny 35.0.0.0/8 ge 10 le 15
+# ip prefix-list test_prefix seq 10 deny 35.0.0.0/8 ge 20
+# ipv6 prefix-list test_ipv6 description this is ipv6 prefix-list
+# ipv6 prefix-list test_ipv6 seq 10 deny 2001:DB8:0:4::/64 ge 80
+
+- name: Delete provided Prefix lists config by Prefix name
+ cisco.ios.ios_prefix_lists:
+ config:
+ - afi: ipv4
+ prefix_lists:
+ - name: 10
+ - name: test_prefix
+ state: deleted
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "no ip prefix-list 10",
+# "no ip prefix-list test_prefix"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^ip prefix-list|^ipv6 prefix-list
+# ip prefix-list test description this is test
+# ip prefix-list test seq 50 deny 12.0.0.0/8 ge 15
+# ipv6 prefix-list test_ipv6 description this is ipv6 prefix-list
+# ipv6 prefix-list test_ipv6 seq 10 deny 2001:DB8:0:4::/64 ge 80
+
+# Using deleted by AFI
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^ip prefix-list|^ipv6 prefix-list
+# ip prefix-list 10 description this is test description
+# ip prefix-list 10 seq 5 deny 1.0.0.0/8 le 15
+# ip prefix-list 10 seq 10 deny 35.0.0.0/8 ge 10
+# ip prefix-list 10 seq 15 deny 12.0.0.0/8 ge 15
+# ip prefix-list 10 seq 20 deny 14.0.0.0/8 ge 20 le 21
+# ip prefix-list test description this is test
+# ip prefix-list test seq 50 deny 12.0.0.0/8 ge 15
+# ip prefix-list test_prefix description this is for prefix-list
+# ip prefix-list test_prefix seq 5 deny 35.0.0.0/8 ge 10 le 15
+# ip prefix-list test_prefix seq 10 deny 35.0.0.0/8 ge 20
+# ipv6 prefix-list test_ipv6 description this is ipv6 prefix-list
+# ipv6 prefix-list test_ipv6 seq 10 deny 2001:DB8:0:4::/64 ge 80
+
+- name: Delete provided Prefix lists config by AFI
+ cisco.ios.ios_prefix_lists:
+ config:
+ - afi: ipv4
+ state: deleted
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "no ip prefix-list test",
+# "no ip prefix-list 10",
+# "no ip prefix-list test_prefix"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^ip prefix-list|^ipv6 prefix-list
+# ipv6 prefix-list test_ipv6 description this is ipv6 prefix-list
+# ipv6 prefix-list test_ipv6 seq 10 deny 2001:DB8:0:4::/64 ge 80
+
+# Using deleted without any config passed (NOTE: This will delete all Prefix lists configuration from device)
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^ip prefix-list|^ipv6 prefix-list
+# ip prefix-list 10 description this is test description
+# ip prefix-list 10 seq 5 deny 1.0.0.0/8 le 15
+# ip prefix-list 10 seq 10 deny 35.0.0.0/8 ge 10
+# ip prefix-list 10 seq 15 deny 12.0.0.0/8 ge 15
+# ip prefix-list 10 seq 20 deny 14.0.0.0/8 ge 20 le 21
+# ip prefix-list test description this is test
+# ip prefix-list test seq 50 deny 12.0.0.0/8 ge 15
+# ip prefix-list test_prefix description this is for prefix-list
+# ip prefix-list test_prefix seq 5 deny 35.0.0.0/8 ge 10 le 15
+# ip prefix-list test_prefix seq 10 deny 35.0.0.0/8 ge 20
+# ipv6 prefix-list test_ipv6 description this is ipv6 prefix-list
+# ipv6 prefix-list test_ipv6 seq 10 deny 2001:DB8:0:4::/64 ge 80
+
+- name: Delete all Prefix lists config
+ cisco.ios.ios_prefix_lists:
+ state: deleted
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "no ip prefix-list test",
+# "no ip prefix-list 10",
+# "no ip prefix-list test_prefix",
+# "no ipv6 prefix-list test_ipv6"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^ip prefix-list|^ipv6 prefix-list
+# router-ios#
+
+# Using merged
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^ip prefix-list|^ipv6 prefix-list
+# ipv6 prefix-list test_ipv6 description this is ipv6
+# ipv6 prefix-list test_ipv6 seq 10 deny 2001:DB8:0:4::/64 ge 80
+
+- name: Merge provided Prefix lists configuration
+ cisco.ios.ios_prefix_lists:
+ config:
+ - afi: ipv6
+ prefix_lists:
+ - name: test_ipv6
+ description: this is ipv6 merge test
+ entries:
+ - action: deny
+ prefix: 2001:DB8:0:4::/64
+ ge: 80
+ le: 100
+ sequence: 10
+ state: merged
+
+# After state:
+# -------------
+#
+# Play Execution fails, with error:
+# Cannot update existing sequence 10 of Prefix Lists test_ipv6 with state merged.
+# Please use state replaced or overridden.
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^ip prefix-list|^ipv6 prefix-list
+# ipv6 prefix-list test_ipv6 description this is ipv6
+# ipv6 prefix-list test_ipv6 seq 10 deny 2001:DB8:0:4::/64 ge 80
+
+- name: Merge provided Prefix lists configuration
+ cisco.ios.ios_prefix_lists:
+ config:
+ - afi: ipv4
+ prefix_lists:
+ - name: 10
+ description: this is new merge test
+ entries:
+ - action: deny
+ prefix: 1.0.0.0/8
+ le: 15
+ sequence: 5
+ - action: deny
+ prefix: 35.0.0.0/8
+ ge: 10
+ sequence: 10
+ - action: deny
+ prefix: 12.0.0.0/8
+ ge: 15
+ sequence: 15
+ - action: deny
+ prefix: 14.0.0.0/8
+ ge: 20
+ le: 21
+ sequence: 20
+ - name: test
+ description: this is merge test
+ entries:
+ - action: deny
+ prefix: 12.0.0.0/8
+ ge: 15
+ sequence: 50
+ - name: test_prefix
+ description: this is for prefix-list
+ entries:
+ - action: deny
+ prefix: 35.0.0.0/8
+ ge: 10
+ le: 15
+ sequence: 5
+ - action: deny
+ prefix: 35.0.0.0/8
+ ge: 20
+ sequence: 10
+ - afi: ipv6
+ prefix_lists:
+ - name: test_ipv6
+ description: this is ipv6 merge test
+ entries:
+ - action: deny
+ prefix: 2001:DB8:0:4::/64
+ ge: 80
+ le: 100
+ sequence: 20
+ state: merged
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "ip prefix-list test description this is merge test",
+# "ip prefix-list test seq 50 deny 12.0.0.0/8 ge 15",
+# "ip prefix-list 10 seq 15 deny 12.0.0.0/8 ge 15",
+# "ip prefix-list 10 seq 10 deny 35.0.0.0/8 ge 10",
+# "ip prefix-list 10 seq 5 deny 1.0.0.0/8 le 15",
+# "ip prefix-list 10 description this is new merge test",
+# "ip prefix-list 10 seq 20 deny 14.0.0.0/8 ge 20 le 21",
+# "ip prefix-list test_prefix seq 10 deny 35.0.0.0/8 ge 20",
+# "ip prefix-list test_prefix seq 5 deny 35.0.0.0/8 ge 10 le 15",
+# "ip prefix-list test_prefix description this is for prefix-list",
+# "ipv6 prefix-list test_ipv6 seq 20 deny 2001:DB8:0:4::/64 ge 80 le 100",
+# "ipv6 prefix-list test_ipv6 description this is ipv6 merge test"
+# ]
+
+# After state:
+# -------------
+#
+# router-ios#sh running-config | section ^ip prefix-list|^ipv6 prefix-list
+# ip prefix-list 10 description this is new merge test
+# ip prefix-list 10 seq 5 deny 1.0.0.0/8 le 15
+# ip prefix-list 10 seq 10 deny 35.0.0.0/8 ge 10
+# ip prefix-list 10 seq 15 deny 12.0.0.0/8 ge 15
+# ip prefix-list 10 seq 20 deny 14.0.0.0/8 ge 20 le 21
+# ip prefix-list test description this is merge test
+# ip prefix-list test seq 50 deny 12.0.0.0/8 ge 15
+# ip prefix-list test_prefix description this is for prefix-list
+# ip prefix-list test_prefix seq 5 deny 35.0.0.0/8 ge 10 le 15
+# ip prefix-list test_prefix seq 10 deny 35.0.0.0/8 ge 20
+# ipv6 prefix-list test_ipv6 description this is ipv6 merge test
+# ipv6 prefix-list test_ipv6 seq 10 deny 2001:DB8:0:4::/64 ge 80 le 100
+
+# Using overridden
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^ip prefix-list|^ipv6 prefix-list
+# ip prefix-list 10 description this is test description
+# ip prefix-list 10 seq 5 deny 1.0.0.0/8 le 15
+# ip prefix-list 10 seq 10 deny 35.0.0.0/8 ge 10
+# ip prefix-list 10 seq 15 deny 12.0.0.0/8 ge 15
+# ip prefix-list 10 seq 20 deny 14.0.0.0/8 ge 20 le 21
+# ip prefix-list test description this is test
+# ip prefix-list test seq 50 deny 12.0.0.0/8 ge 15
+# ip prefix-list test_prefix description this is for prefix-list
+# ip prefix-list test_prefix seq 5 deny 35.0.0.0/8 ge 10 le 15
+# ip prefix-list test_prefix seq 10 deny 35.0.0.0/8 ge 20
+# ipv6 prefix-list test_ipv6 description this is ipv6 prefix-list
+# ipv6 prefix-list test_ipv6 seq 10 deny 2001:DB8:0:4::/64 ge 80
+
+- name: Override provided Prefix lists configuration
+ cisco.ios.ios_prefix_lists:
+ config:
+ - afi: ipv4
+ prefix_lists:
+ - name: 10
+ description: this is override test
+ entries:
+ - action: deny
+ prefix: 12.0.0.0/8
+ ge: 15
+ sequence: 15
+ - action: deny
+ prefix: 14.0.0.0/8
+ ge: 20
+ le: 21
+ sequence: 20
+ - name: test_override
+ description: this is override test
+ entries:
+ - action: deny
+ prefix: 35.0.0.0/8
+ ge: 20
+ sequence: 10
+ - afi: ipv6
+ prefix_lists:
+ - name: test_ipv6
+ description: this is ipv6 override test
+ entries:
+ - action: deny
+ prefix: 2001:DB8:0:4::/64
+ ge: 80
+ le: 100
+ sequence: 10
+ state: overridden
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "no ip prefix-list test",
+# "no ip prefix-list test_prefix",
+# "ip prefix-list 10 description this is override test",
+# "no ip prefix-list 10 seq 10 deny 35.0.0.0/8 ge 10",
+# "no ip prefix-list 10 seq 5 deny 1.0.0.0/8 le 15",
+# "ip prefix-list test_override seq 10 deny 35.0.0.0/8 ge 20",
+# "ip prefix-list test_override description this is override test",
+# "no ipv6 prefix-list test_ipv6 seq 10 deny 2001:DB8:0:4::/64 ge 80",
+# "ipv6 prefix-list test_ipv6 seq 10 deny 2001:DB8:0:4::/64 ge 80 le 100",
+# "ipv6 prefix-list test_ipv6 description this is ipv6 override test"
+# ]
+
+# After state:
+# -------------
+#
+# router-ios#sh running-config | section ^ip prefix-list|^ipv6 prefix-list
+# ip prefix-list 10 description this is override test
+# ip prefix-list 10 seq 15 deny 12.0.0.0/8 ge 15
+# ip prefix-list 10 seq 20 deny 14.0.0.0/8 ge 20 le 21
+# ip prefix-list test_override description this is override test
+# ip prefix-list test_override seq 10 deny 35.0.0.0/8 ge 20
+# ipv6 prefix-list test_ipv6 description this is ipv6 override test
+# ipv6 prefix-list test_ipv6 seq 10 deny 2001:DB8:0:4::/64 ge 80 le 100
+
+# Using replaced
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^ip prefix-list|^ipv6 prefix-list
+# ip prefix-list 10 description this is test description
+# ip prefix-list 10 seq 5 deny 1.0.0.0/8 le 15
+# ip prefix-list 10 seq 10 deny 35.0.0.0/8 ge 10
+# ip prefix-list 10 seq 15 deny 12.0.0.0/8 ge 15
+# ip prefix-list 10 seq 20 deny 14.0.0.0/8 ge 20 le 21
+# ip prefix-list test description this is test
+# ip prefix-list test seq 50 deny 12.0.0.0/8 ge 15
+# ip prefix-list test_prefix description this is for prefix-list
+# ip prefix-list test_prefix seq 5 deny 35.0.0.0/8 ge 10 le 15
+# ip prefix-list test_prefix seq 10 deny 35.0.0.0/8 ge 20
+# ipv6 prefix-list test_ipv6 description this is ipv6 prefix-list
+# ipv6 prefix-list test_ipv6 seq 10 deny 2001:DB8:0:4::/64 ge 80
+
+- name: Replaced provided Prefix lists configuration
+ cisco.ios.ios_prefix_lists:
+ config:
+ - afi: ipv4
+ prefix_lists:
+ - name: 10
+ description: this is replace test
+ entries:
+ - action: deny
+ prefix: 12.0.0.0/8
+ ge: 15
+ sequence: 15
+ - action: deny
+ prefix: 14.0.0.0/8
+ ge: 20
+ le: 21
+ sequence: 20
+ - name: test_replace
+ description: this is replace test
+ entries:
+ - action: deny
+ prefix: 35.0.0.0/8
+ ge: 20
+ sequence: 10
+ - afi: ipv6
+ prefix_lists:
+ - name: test_ipv6
+ description: this is ipv6 replace test
+ entries:
+ - action: deny
+ prefix: 2001:DB8:0:4::/64
+ ge: 80
+ le: 100
+ sequence: 10
+ state: replaced
+
+# Commands Fired:
+# ---------------
+# "commands": [
+# "ip prefix-list 10 description this is replace test",
+# "no ip prefix-list 10 seq 10 deny 35.0.0.0/8 ge 10",
+# "no ip prefix-list 10 seq 5 deny 1.0.0.0/8 le 15",
+# "ip prefix-list test_replace seq 10 deny 35.0.0.0/8 ge 20",
+# "ip prefix-list test_replace description this is replace test",
+# "no ipv6 prefix-list test_ipv6 seq 10 deny 2001:DB8:0:4::/64 ge 80",
+# "ipv6 prefix-list test_ipv6 seq 10 deny 2001:DB8:0:4::/64 ge 80 le 100",
+# "ipv6 prefix-list test_ipv6 description this is ipv6 replace test"
+# ]
+
+# After state:
+# -------------
+#
+# router-ios#sh running-config | section ^ip prefix-list|^ipv6 prefix-list
+# ip prefix-list 10 description this is replace test
+# ip prefix-list 10 seq 15 deny 12.0.0.0/8 ge 15
+# ip prefix-list 10 seq 20 deny 14.0.0.0/8 ge 20 le 21
+# ip prefix-list test description this is test
+# ip prefix-list test seq 50 deny 12.0.0.0/8 ge 15
+# ip prefix-list test_prefix description this is for prefix-list
+# ip prefix-list test_prefix seq 5 deny 35.0.0.0/8 ge 10 le 15
+# ip prefix-list test_prefix seq 10 deny 35.0.0.0/8 ge 20
+# ip prefix-list test_replace description this is replace test
+# ip prefix-list test_replace seq 10 deny 35.0.0.0/8 ge 20
+# ipv6 prefix-list test_ipv6 description this is ipv6 replace test
+# ipv6 prefix-list test_ipv6 seq 10 deny 2001:DB8:0:4::/64 ge 80 le 100
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^ip prefix-list|^ipv6 prefix-list
+# ip prefix-list 10 description this is test description
+# ip prefix-list 10 seq 5 deny 1.0.0.0/8 le 15
+# ip prefix-list 10 seq 10 deny 35.0.0.0/8 ge 10
+# ip prefix-list 10 seq 15 deny 12.0.0.0/8 ge 15
+# ip prefix-list 10 seq 20 deny 14.0.0.0/8 ge 20 le 21
+# ip prefix-list test description this is test
+# ip prefix-list test seq 50 deny 12.0.0.0/8 ge 15
+# ip prefix-list test_prefix description this is for prefix-list
+# ip prefix-list test_prefix seq 5 deny 35.0.0.0/8 ge 10 le 15
+# ip prefix-list test_prefix seq 10 deny 35.0.0.0/8 ge 20
+# ipv6 prefix-list test_ipv6 description this is ipv6 prefix-list
+# ipv6 prefix-list test_ipv6 seq 10 deny 2001:DB8:0:4::/64 ge 80
+
+- name: Gather Prefix lists provided configurations
+ cisco.ios.ios_prefix_lists:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": [
+# {
+# "afi": "ipv4",
+# "prefix_lists": [
+# {
+# "description": "this is test description"
+# "entries": [
+# {
+# "action": "deny",
+# "le": 15,
+# "prefix": "1.0.0.0/8",
+# "sequence": 5
+# },
+# {
+# "action": "deny",
+# "ge": 10,
+# "prefix": "35.0.0.0/8",
+# "sequence": 10
+# },
+# {
+# "action": "deny",
+# "ge": 15,
+# "prefix": "12.0.0.0/8",
+# "sequence": 15
+# },
+# {
+# "action": "deny",
+# "ge": 20,
+# "le": 21,
+# "prefix": "14.0.0.0/8",
+# "sequence": 20
+# }
+# ],
+# "name": "10"
+# },
+# {
+# "description": "this is test"
+# "entries": [
+# {
+# "action": "deny",
+# "ge": 15,
+# "prefix": "12.0.0.0/8",
+# "sequence": 50
+# }
+# ],
+# "name": "test"
+# },
+# {
+# "description": "this is for prefix-list"
+# "entries": [
+# {
+# "action": "deny",
+# "ge": 10,
+# "le": 15,
+# "prefix": "35.0.0.0/8",
+# "sequence": 5
+# },
+# {
+# "action": "deny",
+# "ge": 20,
+# "prefix": "35.0.0.0/8",
+# "sequence": 10
+# }
+# ],
+# "name": "test_prefix"
+# }
+# ]
+# },
+# {
+# "afi": "ipv6",
+# "prefix_lists": [
+# {
+# "description": "this is ipv6 prefix-list"
+# "entries": [
+# {
+# "action": "deny",
+# "ge": 80,
+# "prefix": "2001:DB8:0:4::/64",
+# "sequence": 10
+# }
+# ],
+# "name": "test_ipv6"
+# }
+# ]
+# }
+# ]
+
+# After state:
+# ------------
+#
+# router-ios#sh running-config | section ^ip prefix-list|^ipv6 prefix-list
+# ip prefix-list 10 description this is test description
+# ip prefix-list 10 seq 5 deny 1.0.0.0/8 le 15
+# ip prefix-list 10 seq 10 deny 35.0.0.0/8 ge 10
+# ip prefix-list 10 seq 15 deny 12.0.0.0/8 ge 15
+# ip prefix-list 10 seq 20 deny 14.0.0.0/8 ge 20 le 21
+# ip prefix-list test description this is test
+# ip prefix-list test seq 50 deny 12.0.0.0/8 ge 15
+# ip prefix-list test_prefix description this is for prefix-list
+# ip prefix-list test_prefix seq 5 deny 35.0.0.0/8 ge 10 le 15
+# ip prefix-list test_prefix seq 10 deny 35.0.0.0/8 ge 20
+# ipv6 prefix-list test_ipv6 description this is ipv6 prefix-list
+# ipv6 prefix-list test_ipv6 seq 10 deny 2001:DB8:0:4::/64 ge 80
+
+# Using Rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_prefix_lists:
+ config:
+ - afi: ipv4
+ prefix_lists:
+ - name: 10
+ description: this is new merge test
+ entries:
+ - action: deny
+ prefix: 1.0.0.0/8
+ le: 15
+ sequence: 5
+ - action: deny
+ prefix: 35.0.0.0/8
+ ge: 10
+ sequence: 10
+ - action: deny
+ prefix: 12.0.0.0/8
+ ge: 15
+ sequence: 15
+ - action: deny
+ prefix: 14.0.0.0/8
+ ge: 20
+ le: 21
+ sequence: 20
+ - name: test
+ description: this is merge test
+ entries:
+ - action: deny
+ prefix: 12.0.0.0/8
+ ge: 15
+ sequence: 50
+ - name: test_prefix
+ description: this is for prefix-list
+ entries:
+ - action: deny
+ prefix: 35.0.0.0/8
+ ge: 10
+ le: 15
+ sequence: 5
+ - action: deny
+ prefix: 35.0.0.0/8
+ ge: 20
+ sequence: 10
+ - afi: ipv6
+ prefix_lists:
+ - name: test_ipv6
+ description: this is ipv6 merge test
+ entries:
+ - action: deny
+ prefix: 2001:DB8:0:4::/64
+ ge: 80
+ le: 100
+ sequence: 10
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "ip prefix-list test description this is test",
+# "ip prefix-list test seq 50 deny 12.0.0.0/8 ge 15",
+# "ip prefix-list 10 seq 15 deny 12.0.0.0/8 ge 15",
+# "ip prefix-list 10 seq 10 deny 35.0.0.0/8 ge 10",
+# "ip prefix-list 10 seq 5 deny 1.0.0.0/8 le 15",
+# "ip prefix-list 10 description this is test description",
+# "ip prefix-list 10 seq 20 deny 14.0.0.0/8 ge 20 le 21",
+# "ip prefix-list test_prefix seq 10 deny 35.0.0.0/8 ge 20",
+# "ip prefix-list test_prefix seq 5 deny 35.0.0.0/8 ge 10 le 15",
+# "ip prefix-list test_prefix description this is for prefix-list",
+# "ipv6 prefix-list test_ipv6 seq 10 deny 2001:DB8:0:4::/64 ge 80 l2 100",
+# "ipv6 prefix-list test_ipv6 description this is ipv6 prefix-list"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# ip prefix-list 10 description this is test description
+# ip prefix-list 10 seq 5 deny 1.0.0.0/8 le 15
+# ip prefix-list 10 seq 10 deny 35.0.0.0/8 ge 10
+# ip prefix-list 10 seq 15 deny 12.0.0.0/8 ge 15
+# ip prefix-list 10 seq 20 deny 14.0.0.0/8 ge 20 le 21
+# ip prefix-list test description this is test
+# ip prefix-list test seq 50 deny 12.0.0.0/8 ge 15
+# ip prefix-list test_prefix description this is for prefix-list
+# ip prefix-list test_prefix seq 5 deny 35.0.0.0/8 ge 10 le 15
+# ip prefix-list test_prefix seq 10 deny 35.0.0.0/8 ge 20
+# ipv6 prefix-list test_ipv6 description this is ipv6 prefix-list
+# ipv6 prefix-list test_ipv6 seq 10 deny 2001:DB8:0:4::/64 ge 80
+
+- name: Parse the provided configuration with the existing running configuration
+ cisco.ios.ios_prefix_lists:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": [
+# {
+# "afi": "ipv4",
+# "prefix_lists": [
+# {
+# "description": "this is test description"
+# "entries": [
+# {
+# "action": "deny",
+# "le": 15,
+# "prefix": "1.0.0.0/8",
+# "sequence": 5
+# },
+# {
+# "action": "deny",
+# "ge": 10,
+# "prefix": "35.0.0.0/8",
+# "sequence": 10
+# },
+# {
+# "action": "deny",
+# "ge": 15,
+# "prefix": "12.0.0.0/8",
+# "sequence": 15
+# },
+# {
+# "action": "deny",
+# "ge": 20,
+# "le": 21,
+# "prefix": "14.0.0.0/8",
+# "sequence": 20
+# }
+# ],
+# "name": "10"
+# },
+# {
+# "description": "this is test"
+# "entries": [
+# {
+# "action": "deny",
+# "ge": 15,
+# "prefix": "12.0.0.0/8",
+# "sequence": 50
+# }
+# ],
+# "name": "test"
+# },
+# {
+# "description": "this is for prefix-list"
+# "entries": [
+# {
+# "action": "deny",
+# "ge": 10,
+# "le": 15,
+# "prefix": "35.0.0.0/8",
+# "sequence": 5
+# },
+# {
+# "action": "deny",
+# "ge": 20,
+# "prefix": "35.0.0.0/8",
+# "sequence": 10
+# }
+# ],
+# "name": "test_prefix"
+# }
+# ]
+# },
+# {
+# "afi": "ipv6",
+# "prefix_lists": [
+# {
+# "description": "this is ipv6 prefix-list"
+# "entries": [
+# {
+# "action": "deny",
+# "ge": 80,
+# "prefix": "2001:DB8:0:4::/64",
+# "sequence": 10
+# }
+# ],
+# "name": "test_ipv6"
+# }
+# ]
+# }
+# ]
+"""
+
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: list
+after:
+ description: The resulting configuration model invocation.
+ returned: when changed
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: list
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: always
+ type: list
+ sample: ['ip prefix-list 10 description this is test description', 'ip prefix-list 10 seq 5 deny 1.0.0.0/8 le 15']
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.prefix_lists.prefix_lists import (
+ Prefix_listsArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.prefix_lists.prefix_lists import (
+ Prefix_lists,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ module = AnsibleModule(
+ argument_spec=Prefix_listsArgs.argument_spec,
+ mutually_exclusive=[["config", "running_config"]],
+ required_if=[
+ ["state", "merged", ["config"]],
+ ["state", "replaced", ["config"]],
+ ["state", "overridden", ["config"]],
+ ["state", "rendered", ["config"]],
+ ["state", "parsed", ["running_config"]],
+ ],
+ supports_check_mode=True,
+ )
+
+ result = Prefix_lists(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_route_maps.py b/ansible_collections/cisco/ios/plugins/modules/ios_route_maps.py
new file mode 100644
index 000000000..5ec2782a3
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_route_maps.py
@@ -0,0 +1,2358 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2021 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+"""
+The module file for cisco.ios_route_maps
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_route_maps
+short_description: Resource module to configure route maps.
+description:
+ - This module configures and manages the attributes of Route maps on Cisco IOS.
+version_added: 2.1.0
+author: Sumit Jaiswal (@justjais)
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ config:
+ description: A list of configurations for Route maps.
+ type: list
+ elements: dict
+ suboptions:
+ route_map:
+ description: Route map tag/name
+ type: str
+ entries:
+ description: A list of configurations entries for Route maps.
+ type: list
+ elements: dict
+ suboptions:
+ sequence:
+ description:
+ - Sequence to insert to/delete from existing route-map entry
+ - Please refer vendor documentation for valid values
+ type: int
+ action:
+ description: Route map set operations
+ type: str
+ choices: ["deny", "permit"]
+ continue_entry:
+ description: Continue on a different entry within the route-map
+ type: dict
+ suboptions:
+ set:
+ description: Set continue
+ type: bool
+ entry_sequence:
+ description:
+ - Route-map entry sequence number
+ - Please refer vendor documentation for valid values
+ type: int
+ description:
+ description: Route-map comment
+ type: str
+ match:
+ description: Match values from routing table
+ type: dict
+ suboptions:
+ additional_paths:
+ description:
+ - BGP Add-Path match policie
+ - BGP Add-Path advertise-set policy
+ type: dict
+ suboptions:
+ all:
+ description: BGP Add-Path advertise all paths
+ type: bool
+ best:
+ description: BGP Add-Path advertise best n paths (1-3)
+ type: int
+ best_range:
+ description: BGP Add-Path advertise best paths (range m to n)
+ type: dict
+ suboptions:
+ lower_limit:
+ description: BGP Add-Path best paths to advertise (lower limit) (1-3)
+ type: int
+ upper_limit:
+ description: BGP Add-Path best paths to advertise (upper limit) (1-3)
+ type: int
+ group_best:
+ description: BGP Add-Path advertise group-best path
+ type: bool
+ as_path:
+ description: Match BGP AS path list
+ type: dict
+ suboptions:
+ set:
+ description: Set AS path list
+ type: bool
+ acls:
+ description:
+ - AS path access-list
+ - Please refer vendor documentation for valid values
+ type: list
+ elements: int
+ clns:
+ description: CLNS information
+ type: dict
+ suboptions:
+ address:
+ description: Match address of route or match packet
+ type: str
+ next_hop:
+ description: Match next-hop address of route
+ type: str
+ route_source:
+ description: Match advertising source address of route
+ type: str
+ community:
+ description: Match BGP community list
+ type: dict
+ suboptions:
+ name:
+ description:
+ - Community-list number/Community-list name
+ - Please refer vendor documentation for valid values
+ type: list
+ elements: str
+ exact_match:
+ description: Do exact matching of communities
+ type: bool
+ extcommunity:
+ description:
+ - Match BGP/VPN extended community list
+ - Extended community-list number
+ - Please refer vendor documentation for valid values
+ type: list
+ elements: str
+ interfaces:
+ description: Match first hop interface of route
+ type: list
+ elements: str
+ ip:
+ description: IP specific information
+ type: dict
+ suboptions:
+ address:
+ description: Match address of route or match packet
+ type: dict
+ suboptions:
+ acls: &acls
+ description:
+ - Match entries of acl
+ - IP acl name/number
+ - Please refer vendor documentation for valid values
+ type: list
+ elements: str
+ prefix_lists: &prefix_lists
+ description:
+ - Match entries of prefix-lists
+ - IP prefix-list name
+ type: list
+ elements: str
+ flowspec:
+ description: Match src/dest prefix component of flowspec prefix
+ type: dict
+ suboptions:
+ dest_pfx:
+ description: Match dest prefix component of flowspec prefix
+ type: bool
+ src_pfx:
+ description: Match source prefix component of flowspec prefix
+ type: bool
+ acls: *acls
+ prefix_lists: *prefix_lists
+ next_hop:
+ description: Match next-hop address of route
+ type: dict
+ suboptions:
+ set:
+ description: Set next-hop address
+ type: bool
+ acls: *acls
+ prefix_lists: *prefix_lists
+ redistribution_source:
+ description: route redistribution source (EIGRP only)
+ type: dict
+ suboptions:
+ set:
+ description: Set redistribution-source
+ type: bool
+ acls: *acls
+ prefix_lists: *prefix_lists
+ route_source:
+ description: Match advertising source address of route
+ type: dict
+ suboptions:
+ set:
+ description: Set redistribution-source
+ type: bool
+ redistribution_source:
+ description: route redistribution source (EIGRP only)
+ type: bool
+ acls: *acls
+ prefix_lists: *prefix_lists
+ ipv6:
+ description: IPv6 specific information
+ type: dict
+ suboptions:
+ address:
+ type: dict
+ description: Match address of route or match packet
+ suboptions:
+ acl:
+ description: IPv6 access-list name
+ type: str
+ prefix_list:
+ description: IPv6 prefix-list name
+ type: str
+ flowspec:
+ description: Match next-hop address of route
+ type: dict
+ suboptions:
+ dest_pfx:
+ description: Match dest prefix component of flowspec prefix
+ type: bool
+ src_pfx:
+ description: Match source prefix component of flowspec prefix
+ type: bool
+ acl:
+ description: IPv6 access-list name
+ type: str
+ prefix_list:
+ description: IPv6 prefix-list name
+ type: str
+ next_hop:
+ description: Match next-hop address of route
+ type: dict
+ suboptions:
+ acl:
+ description: IPv6 access-list name
+ type: str
+ prefix_list:
+ description: IPv6 prefix-list name
+ type: str
+ route_source:
+ description: Match advertising source address of route
+ type: dict
+ suboptions:
+ acl:
+ description: IPv6 access-list name
+ type: str
+ prefix_list:
+ description: IPv6 prefix-list name
+ type: str
+ length:
+ description: Packet length
+ type: dict
+ suboptions:
+ minimum:
+ description:
+ - Minimum packet length
+ - Please refer vendor documentation for valid values
+ type: int
+ maximum:
+ description:
+ - Maximum packet length
+ - Please refer vendor documentation for valid values
+ type: int
+ local_preference:
+ description: Local preference for route
+ type: dict
+ suboptions:
+ set:
+ description: Set the Local preference for route
+ type: bool
+ value:
+ description:
+ - Local preference value
+ - Please refer vendor documentation for valid values
+ type: list
+ elements: str
+ mdt_group:
+ description: Match routes corresponding to MDT group
+ type: dict
+ suboptions:
+ set:
+ description: Set and Match routes corresponding to MDT group
+ type: bool
+ acls:
+ description:
+ - IP access-list number/IP standard access-list name
+ - Please refer vendor documentation for valid values
+ type: list
+ elements: str
+ metric:
+ description: Match metric of route
+ type: dict
+ suboptions:
+ value:
+ description:
+ - Metric value
+ - Please refer vendor documentation for valid values
+ type: int
+ external:
+ description: Match route using external protocol metric
+ type: bool
+ deviation:
+ description: Deviation option to match metric in a range
+ type: bool
+ deviation_value:
+ description:
+ - deviation value, 500 +- 10 creates the range 490 - 510
+ - Please refer vendor documentation for valid values
+ type: int
+ mpls_label:
+ description: Match routes which have MPLS labels
+ type: bool
+ policy_lists:
+ description: Match IP policy list
+ type: list
+ elements: str
+ route_type:
+ description: Match route-type of route
+ type: dict
+ suboptions:
+ external:
+ description: external route (BGP, EIGRP and OSPF type 1/2)
+ type: dict
+ suboptions:
+ set:
+ description: Set external route
+ type: bool
+ type_1:
+ description: OSPF external type 1 route
+ type: bool
+ type_2:
+ description: OSPF external type 2 route
+ type: bool
+ internal:
+ description: internal route (including OSPF intra/inter area)
+ type: bool
+ level_1:
+ description: IS-IS level-1 route
+ type: bool
+ level_2:
+ description: IS-IS level-2 route
+ type: bool
+ local:
+ description: locally generated route
+ type: bool
+ nssa_external:
+ description: nssa-external route (OSPF type 1/2)
+ type: dict
+ suboptions:
+ set:
+ description: Set nssa-external route
+ type: bool
+ type_1:
+ description: OSPF external type 1 route
+ type: bool
+ type_2:
+ description: OSPF external type 2 route
+ type: bool
+ rpki:
+ description: Match RPKI state of route
+ type: dict
+ suboptions:
+ invalid:
+ description: RPKI Invalid State
+ type: bool
+ not_found:
+ description: RPKI Not Found State
+ type: bool
+ valid:
+ description: RPKI Valid State
+ type: bool
+ security_group:
+ description: Security Group
+ type: dict
+ suboptions:
+ source:
+ description:
+ - Source Security Group, source Security tag
+ - Please refer vendor documentation for valid values
+ type: list
+ elements: int
+ destination:
+ description:
+ - Destination Security Group, destination Security tag
+ - Please refer vendor documentation for valid values
+ type: list
+ elements: int
+ source_protocol:
+ description: Match source-protocol of route
+ type: dict
+ suboptions:
+ bgp:
+ description:
+ - Border Gateway Protocol (BGP)
+ - Autonomous system number
+ - Please refer vendor documentation for valid values
+ type: str
+ connected:
+ description: Connected
+ type: bool
+ eigrp:
+ description:
+ - Enhanced Interior Gateway Routing Protocol (EIGRP)
+ - Autonomous system number
+ - Please refer vendor documentation for valid values
+ type: int
+ isis:
+ description: ISO IS-IS
+ type: bool
+ lisp:
+ description: Locator ID Separation Protocol (LISP)
+ type: bool
+ mobile:
+ description: Mobile routes
+ type: bool
+ ospf:
+ description:
+ - Open Shortest Path First (OSPF) Process ID
+ - Please refer vendor documentation for valid values
+ type: int
+ ospfv3:
+ description:
+ - OSPFv3 Process ID
+ - Please refer vendor documentation for valid values
+ type: int
+ rip:
+ description: Routing Information Protocol (RIP)
+ type: bool
+ static:
+ description: Static routes
+ type: bool
+ tag:
+ description: Match tag of route
+ type: dict
+ suboptions:
+ value:
+ description: Tag value/Tag in Dotted Decimal eg, 10.10.10.10
+ type: list
+ elements: str
+ tag_list:
+ description: Route Tag List/Tag list name
+ type: list
+ elements: str
+ track:
+ description: tracking object
+ type: int
+ set:
+ description: Match source-protocol of route
+ type: dict
+ suboptions:
+ aigp_metric:
+ description: accumulated metric value
+ type: dict
+ suboptions:
+ value:
+ description: manual value
+ type: int
+ igp_metric:
+ description: metric value from rib
+ type: bool
+ as_path:
+ description: Prepend string for a BGP AS-path attribute
+ type: dict
+ suboptions:
+ prepend:
+ description: Prepend to the as-path
+ type: dict
+ suboptions:
+ as_number:
+ description:
+ - AS number
+ - Please refer vendor documentation for valid values
+ type: list
+ elements: str
+ last_as:
+ description:
+ - Prepend last AS to the as-path
+ - Number of last-AS prepends
+ - Please refer vendor documentation for valid values
+ type: int
+ tag:
+ description: Set the tag as an AS-path attribute
+ type: bool
+ automatic_tag:
+ description: Automatically compute TAG value
+ type: bool
+ clns:
+ description:
+ - OSI summary address
+ - Next hop address
+ - CLNS summary prefix
+ type: str
+ comm_list:
+ description:
+ - set BGP community list (for deletion)
+ - Community-list name/number
+ - Delete matching communities
+ type: str
+ community:
+ description: BGP community attribute
+ type: dict
+ suboptions:
+ number:
+ description:
+ - community number
+ - community number in aa:nn format
+ - Please refer vendor documentation for valid values
+ type: str
+ additive:
+ description: Add to the existing community
+ type: bool
+ gshut:
+ description: Graceful Shutdown (well-known community)
+ type: bool
+ internet:
+ description: Internet (well-known community)
+ type: bool
+ local_as:
+ description: Do not send outside local AS (well-known community)
+ type: bool
+ no_advertise:
+ description: Do not advertise to any peer (well-known community)
+ type: bool
+ no_export:
+ description: Do not export to next AS (well-known community)
+ type: bool
+ none:
+ description: No community attribute
+ type: bool
+ dampening:
+ description: Set BGP route flap dampening parameters
+ type: dict
+ suboptions:
+ penalty_half_time:
+ description:
+ - half-life time for the penalty
+ - Please refer vendor documentation for valid values
+ type: int
+ reuse_route_val:
+ description:
+ - Penalty to start reusing a route
+ - Please refer vendor documentation for valid values
+ type: int
+ suppress_route_val:
+ description:
+ - Penalty to start suppressing a route
+ - Please refer vendor documentation for valid values
+ type: int
+ max_suppress:
+ description:
+ - Maximum duration to suppress a stable route
+ - Please refer vendor documentation for valid values
+ type: int
+ default:
+ description:
+ - Set default information
+ - Default output interface
+ type: str
+ extcomm_list:
+ description:
+ - Set BGP/VPN extended community list (for deletion)
+ - Extended community-list number/name
+ - Delete matching extended communities
+ type: str
+ extcommunity:
+ description: BGP extended community attribute
+ type: dict
+ suboptions:
+ cost:
+ description: Cost extended community
+ type: dict
+ suboptions:
+ id:
+ description:
+ - Community ID
+ - Please refer vendor documentation for valid values
+ type: str
+ cost_value:
+ description:
+ - Cost Value (No-preference Cost = 2147483647)
+ - Please refer vendor documentation for valid values
+ type: int
+ igp:
+ description: Compare following IGP cost comparison
+ type: bool
+ pre_bestpath:
+ description: Compare before all other steps in bestpath calculation
+ type: bool
+ rt:
+ description: Route Target extended community
+ type: dict
+ suboptions:
+ address:
+ description: VPN extended community
+ type: str
+ range:
+ description: Specify a range of extended community
+ type: dict
+ suboptions:
+ lower_limit:
+ description: VPN extended community
+ type: str
+ upper_limit:
+ description: VPN extended community
+ type: str
+ additive:
+ description: Add to the existing extcommunity
+ type: bool
+ soo:
+ description: Site-of-Origin extended community
+ type: str
+ vpn_distinguisher:
+ description: VPN Distinguisher
+ type: dict
+ suboptions:
+ address:
+ description: VPN extended community
+ type: str
+ range:
+ description: Specify a range of extended community
+ type: dict
+ suboptions:
+ lower_limit:
+ description: VPN extended community
+ type: str
+ upper_limit:
+ description: VPN extended community
+ type: str
+ additive:
+ description: Add to the existing extcommunity
+ type: bool
+ global_route:
+ description: Set to global routing table
+ type: bool
+ interfaces:
+ description: Output interface
+ type: list
+ elements: str
+ ip:
+ description: IP specific information
+ type: dict
+ suboptions:
+ address:
+ description:
+ - Specify IP address
+ - Prefix-list name to set ip address
+ type: str
+ df:
+ description: Set DF bit
+ choices: [0, 1]
+ type: int
+ global_route:
+ description: global routing table
+ type: dict
+ suboptions:
+ address:
+ description: IP address of next hop
+ type: str
+ verify_availability:
+ description: Verify if nexthop is reachable
+ type: dict
+ suboptions:
+ address:
+ description: IP address of next hop
+ type: str
+ sequence:
+ description:
+ - Sequence to insert into next-hop list
+ - Please refer vendor documentation for valid values
+ type: int
+ track:
+ description:
+ - Set the next hop depending on the state of a tracked object
+ - tracked object number
+ - Please refer vendor documentation for valid values
+ type: int
+ next_hop:
+ description: Next hop address
+ type: dict
+ suboptions:
+ address:
+ description: IP address of next hop
+ type: str
+ dynamic:
+ description:
+ - application dynamically sets next hop
+ - DHCP learned next hop
+ type: bool
+ encapsulate:
+ description:
+ - Encapsulation profile for VPN nexthop
+ - L3VPN
+ - Encapsulation profile name
+ type: str
+ peer_address:
+ description: Use peer address (for BGP only)
+ type: bool
+ recursive:
+ description: Recursive next-hop
+ type: dict
+ suboptions:
+ global_route:
+ description: global routing table
+ type: bool
+ vrf:
+ description: VRF
+ type: str
+ address:
+ description: IP address of recursive next hop
+ type: str
+ self:
+ description: Use self address (for BGP only)
+ type: bool
+ verify_availability:
+ description: Verify if nexthop is reachable
+ type: dict
+ suboptions:
+ set:
+ description: Set and Verify if nexthop is reachable
+ type: bool
+ address:
+ description: IP address of next hop
+ type: str
+ sequence:
+ description:
+ - Sequence to insert into next-hop list
+ - Please refer vendor documentation for valid values
+ type: int
+ track:
+ description:
+ - Set the next hop depending on the state of a tracked object
+ - tracked object number
+ - Please refer vendor documentation for valid values
+ type: int
+ precedence:
+ description: Set precedence field
+ type: dict
+ suboptions:
+ set:
+ description: Just set precedence field
+ type: bool
+ critical:
+ description: Set critical precedence (5)
+ type: bool
+ flash:
+ description: Set flash precedence (3)
+ type: bool
+ flash_override:
+ description: Set flash override precedence (4)
+ type: bool
+ immediate:
+ description: Set immediate precedence (2)
+ type: bool
+ internet:
+ description: Set internetwork control precedence (6)
+ type: bool
+ network:
+ description: Set network control precedence (7)
+ type: bool
+ priority:
+ description: Set priority precedence (1)
+ type: bool
+ routine:
+ description: Set routine precedence (0)
+ type: bool
+ qos_group:
+ description:
+ - Set QOS Group ID
+ - Please refer vendor documentation for valid values
+ type: int
+ tos:
+ description: Set type of service field
+ type: dict
+ suboptions:
+ set:
+ description: Just set type of service field
+ type: bool
+ max_reliability:
+ description: Set max reliable TOS (2)
+ type: bool
+ max_throughput:
+ description: Set max throughput TOS (4)
+ type: bool
+ min_delay:
+ description: Set min delay TOS (8)
+ type: bool
+ min_monetary_cost:
+ description: Set min monetary cost TOS (1)
+ type: bool
+ normal:
+ description: Set normal TOS (0)
+ type: bool
+ vrf:
+ description: VRF
+ type: dict
+ suboptions:
+ name:
+ description: VRF name
+ type: str
+ address:
+ description: IP address of next hop
+ type: str
+ verify_availability:
+ description: Verify if nexthop is reachable
+ type: dict
+ suboptions:
+ set:
+ description: Set and Verify if nexthop is reachable
+ type: bool
+ address:
+ description: IP address of next hop
+ type: str
+ sequence:
+ description:
+ - Sequence to insert into next-hop list
+ - Please refer vendor documentation for valid values
+ type: int
+ track:
+ description:
+ - Set the next hop depending on the state of a tracked object
+ - tracked object number
+ - Please refer vendor documentation for valid values
+ type: int
+ ipv6:
+ description: IPv6 specific information
+ type: dict
+ suboptions:
+ address:
+ description:
+ - IPv6 address
+ - IPv6 prefix-list
+ type: str
+ default:
+ description: Set default information
+ type: bool
+ global_route:
+ description: global routing table
+ type: dict
+ suboptions:
+ address:
+ description: Next hop address (X:X:X:X::X)
+ type: str
+ verify_availability:
+ description: Verify if nexthop is reachable
+ type: dict
+ suboptions:
+ address:
+ description: Next hop address (X:X:X:X::X)
+ type: str
+ sequence:
+ description:
+ - Sequence to insert into next-hop list
+ - Please refer vendor documentation for valid values
+ type: int
+ track:
+ description:
+ - Set the next hop depending on the state of a tracked object
+ - tracked object number
+ - Please refer vendor documentation for valid values
+ type: int
+ next_hop:
+ description: IPv6 Next hop
+ type: dict
+ suboptions:
+ address:
+ description: Next hop address (X:X:X:X::X)
+ type: str
+ encapsulate:
+ description:
+ - Encapsulation profile for VPN nexthop
+ - L3VPN
+ - Encapsulation profile name
+ type: str
+ peer_address:
+ description: Use peer address (for BGP only)
+ type: bool
+ recursive:
+ description:
+ - Recursive next-hop
+ - IPv6 address of recursive next-hop
+ type: str
+ precedence:
+ description:
+ - Set precedence field
+ - Precedence value
+ - Please refer vendor documentation for valid values
+ type: int
+ vrf:
+ description: VRF name
+ type: dict
+ suboptions:
+ name:
+ description: VRF name
+ type: str
+ verify_availability:
+ description: Verify if nexthop is reachable
+ type: dict
+ suboptions:
+ address:
+ description: IPv6 address of next hop
+ type: str
+ sequence:
+ description:
+ - Sequence to insert into next-hop list
+ - Please refer vendor documentation for valid values
+ type: int
+ track:
+ description:
+ - Set the next hop depending on the state of a tracked object
+ - tracked object number
+ - Please refer vendor documentation for valid values
+ type: int
+ level:
+ description: Where to import route
+ type: dict
+ suboptions:
+ level_1:
+ description: Import into a level-1 area
+ type: bool
+ level_1_2:
+ description: Import into level-1 and level-2
+ type: bool
+ level_2:
+ description: Import into level-2 sub-domain
+ type: bool
+ nssa_only:
+ description: Import only into OSPF NSSA areas and don't propagate
+ type: bool
+ lisp:
+ description:
+ - Locator ID Separation Protocol specific information
+ - Specify a locator-set to use in LISP route-import
+ - The name of the locator set
+ type: str
+ local_preference:
+ description:
+ - BGP local preference path attribute
+ - Please refer vendor documentation for valid values
+ type: int
+ metric:
+ description: Metric value for destination routing protocol
+ type: dict
+ suboptions:
+ deviation:
+ description: Add or subtract metric
+ choices: ["plus", "minus"]
+ type: str
+ metric_value:
+ description:
+ - Metric value or Bandwidth in Kbits per second
+ - Please refer vendor documentation for valid values
+ type: int
+ eigrp_delay:
+ description:
+ - EIGRP delay metric, in 10 microsecond units
+ - Please refer vendor documentation for valid values
+ type: int
+ metric_reliability:
+ description:
+ - EIGRP reliability metric where 255 is 100 reliable
+ - Please refer vendor documentation for valid values
+ type: int
+ metric_bandwidth:
+ description:
+ - EIGRP Effective bandwidth metric (Loading) where 255 is 100 loaded
+ - Please refer vendor documentation for valid values
+ type: int
+ mtu:
+ description:
+ - EIGRP MTU of the path
+ - Please refer vendor documentation for valid values
+ type: int
+ metric_type:
+ description: Type of metric for destination routing protocol
+ type: dict
+ suboptions:
+ external:
+ description: IS-IS external metric
+ type: bool
+ internal:
+ description: IS-IS internal metric or Use IGP metric as the MED for BGP
+ type: bool
+ type_1:
+ description: OSPF external type 1 metric
+ type: bool
+ type_2:
+ description: OSPF external type 2 metric
+ type: bool
+ mpls_label:
+ description: Set MPLS label for prefix
+ type: bool
+ origin:
+ description: BGP origin code
+ type: dict
+ suboptions:
+ igp:
+ description: local IGP
+ type: bool
+ incomplete:
+ description: unknown heritage
+ type: bool
+ tag:
+ description:
+ - Tag value for destination routing protocol
+ - Tag value A.B.C.D(dotted decimal format)/Tag value
+ type: str
+ traffic_index:
+ description:
+ - BGP traffic classification number for accounting
+ - Please refer vendor documentation for valid values
+ type: int
+ vrf:
+ description:
+ - Define VRF name
+ - VPN Routing/Forwarding instance name
+ type: str
+ weight:
+ description:
+ - BGP weight for routing table
+ - Please refer vendor documentation for valid values
+ type: int
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS
+ device by executing the command B(sh running-config | section ^route-map).
+ - The state I(parsed) reads the configuration from C(running_config)
+ option and transforms it into Ansible structured data as per the
+ resource module's argspec and the value is then returned in the
+ I(parsed) key within the result.
+ type: str
+ state:
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - parsed
+ - rendered
+ default: merged
+ description:
+ - The state the configuration should be left in
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device.
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result. For state I(rendered) active connection to remote host is
+ not required.
+ - The state I(gathered) will fetch the running configuration from device and transform
+ it into structured data in the format as per the resource module argspec and
+ the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result. The value of C(running_config)
+ option should be the same format as the output of command I(sh running-config
+ | section ^route-map) executed on device. For state I(parsed) active
+ connection to remote host is not required.
+ type: str
+"""
+
+EXAMPLES = """
+# Using deleted
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^route-map
+# route-map test_1 deny 10
+# description this is test route
+# match ip next-hop prefix-list test_2_new test_1_new
+# match ip route-source 10
+# match security-group source tag 10 20
+# match local-preference 100 50
+# match mpls-label
+# route-map test_1 deny 20
+# match track 105
+# match tag list test_match_tag
+# match route-type level-1
+# match additional-paths advertise-set all group-best
+# match as-path 200 100
+# match ipv6 address test_acl_20
+# continue 100
+# route-map test_2 deny 10
+# match security-group source tag 10 20
+# match local-preference 55 105
+# match mpls-label
+# match ipv6 address test_ip_acl
+# match ipv6 next-hop prefix-list test_new
+# match ipv6 route-source route_src_acl
+# set automatic-tag
+# set ip precedence critical
+# set ip address prefix-list 192.0.2.1
+# set aigp-metric 100
+# set extcommunity cost pre-bestpath 10 100
+# set ip df 1
+# set ip next-hop verify-availability 198.51.111.1 100 track 10
+# set ip next-hop recursive global 198.51.110.1
+
+- name: Delete provided Route maps config
+ cisco.ios.ios_route_maps:
+ config:
+ - route_map: test_1
+ state: deleted
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "no route-map test_1"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^route-map
+# route-map test_2 deny 10
+# match security-group source tag 10 20
+# match local-preference 55 105
+# match mpls-label
+# match ipv6 address test_ip_acl
+# match ipv6 next-hop prefix-list test_new
+# match ipv6 route-source route_src_acl
+# set automatic-tag
+# set ip precedence critical
+# set ip address prefix-list 192.0.2.1
+# set aigp-metric 100
+# set extcommunity cost pre-bestpath 10 100
+# set ip df 1
+# set ip next-hop verify-availability 198.51.111.1 100 track 10
+# set ip next-hop recursive global 198.51.110.1
+
+# Using deleted without any config passed (NOTE: This will delete all Route maps configuration from device)
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^route-map
+# route-map test_1 deny 10
+# description this is test route
+# match ip next-hop prefix-list test_2_new test_1_new
+# match ip route-source 10
+# match security-group source tag 10 20
+# match local-preference 100 50
+# match mpls-label
+# route-map test_1 deny 20
+# match track 105
+# match tag list test_match_tag
+# match route-type level-1
+# match additional-paths advertise-set all group-best
+# match as-path 200 100
+# match ipv6 address test_acl_20
+# continue 100
+# route-map test_2 deny 10
+# match security-group source tag 10 20
+# match local-preference 55 105
+# match mpls-label
+# match ipv6 address test_ip_acl
+# match ipv6 next-hop prefix-list test_new
+# match ipv6 route-source route_src_acl
+# set automatic-tag
+# set ip precedence critical
+# set ip address prefix-list 192.0.2.1
+# set aigp-metric 100
+# set extcommunity cost pre-bestpath 10 100
+# set ip df 1
+# set ip next-hop verify-availability 198.51.111.1 100 track 10
+# set ip next-hop recursive global 198.51.110.1
+
+- name: Delete all Route maps config
+ cisco.ios.ios_route_maps:
+ state: deleted
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "no route-map test_1",
+# "no route-map test_2"
+# ]
+
+# After state:
+# -------------
+# router-ios#sh running-config | section ^route-map
+# router-ios#
+
+# Using merged
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^route-map
+# router-ios#
+
+- name: Merge provided Route maps configuration
+ cisco.ios.ios_route_maps:
+ config:
+ - route_map: test_1
+ entries:
+ - sequence: 10
+ action: deny
+ description: this is test route
+ match:
+ ip:
+ next_hop:
+ prefix_lists:
+ - test_1_new
+ - test_2_new
+ route_source:
+ acls:
+ - 10
+ security_group:
+ source:
+ - 10
+ - 20
+ local_preference:
+ value:
+ - 50
+ - 100
+ mpls_label: true
+ - sequence: 20
+ action: deny
+ continue_entry:
+ entry_sequence: 100
+ match:
+ additional_paths:
+ all: true
+ group_best: true
+ as_path:
+ acls:
+ - 100
+ - 200
+ ipv6:
+ address:
+ acl: test_acl_20
+ route_type:
+ level_1: true
+ tag:
+ tag_list:
+ - test_match_tag
+ track: 105
+ - route_map: test_2
+ entries:
+ - sequence: 10
+ action: deny
+ match:
+ ipv6:
+ address:
+ acl: test_ip_acl
+ next_hop:
+ prefix_list: test_new
+ route_source:
+ acl: route_src_acl
+ security_group:
+ source:
+ - 10
+ - 20
+ local_preference:
+ value:
+ - 55
+ - 105
+ mpls_label: true
+ set:
+ aigp_metric:
+ value: 100
+ automatic_tag: true
+ extcommunity:
+ cost:
+ id: 10
+ cost_value: 100
+ pre_bestpath: true
+ ip:
+ address: 192.0.2.1
+ df: 1
+ next_hop:
+ recursive:
+ global_route: true
+ address: 198.51.110.1
+ verify_availability:
+ address: 198.51.111.1
+ sequence: 100
+ track: 10
+ precedence:
+ critical: true
+ state: merged
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "route-map test_2 deny 10",
+# "match security-group source tag 10 20",
+# "match local-preference 55 105",
+# "match mpls-label",
+# "match ipv6 next-hop prefix-list test_new",
+# "match ipv6 route-source route_src_acl",
+# "match ipv6 address test_ip_acl",
+# "set extcommunity cost pre-bestpath 10 100",
+# "set ip df 1",
+# "set ip next-hop recursive global 198.51.110.1",
+# "set ip next-hop verify-availability 198.51.111.1 100 track 10",
+# "set ip precedence critical",
+# "set ip address prefix-list 192.0.2.1",
+# "set automatic-tag",
+# "set aigp-metric 100",
+# "route-map test_1 deny 20",
+# "continue 100",
+# "match track 105",
+# "match tag list test_match_tag",
+# "match ipv6 address test_acl_20",
+# "match route-type level-1",
+# "match as-path 200 100",
+# "match additional-paths advertise-set all group-best",
+# "route-map test_1 deny 10",
+# "description this is test route",
+# "match security-group source tag 10 20",
+# "match ip next-hop prefix-list test_2_new test_1_new",
+# "match ip route-source 10",
+# "match local-preference 100 50",
+# "match mpls-label"
+# ]
+
+# After state:
+# -------------
+#
+# router-ios#sh running-config | section ^route-map
+# route-map test_1 deny 10
+# description this is test route
+# match ip next-hop prefix-list test_2_new test_1_new
+# match ip route-source 10
+# match security-group source tag 10 20
+# match local-preference 100 50
+# match mpls-label
+# route-map test_1 deny 20
+# match track 105
+# match tag list test_match_tag
+# match route-type level-1
+# match additional-paths advertise-set all group-best
+# match as-path 200 100
+# match ipv6 address test_acl_20
+# continue 100
+# route-map test_2 deny 10
+# match security-group source tag 10 20
+# match local-preference 55 105
+# match mpls-label
+# match ipv6 address test_ip_acl
+# match ipv6 next-hop prefix-list test_new
+# match ipv6 route-source route_src_acl
+# set automatic-tag
+# set ip precedence critical
+# set ip address prefix-list 192.0.2.1
+# set aigp-metric 100
+# set extcommunity cost pre-bestpath 10 100
+# set ip df 1
+# set ip next-hop verify-availability 198.51.111.1 100 track 10
+# set ip next-hop recursive global 198.51.110.1
+
+# Using overridden
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^route-map
+# route-map test_1 deny 10
+# description this is test route
+# match ip next-hop prefix-list test_2_new test_1_new
+# match ip route-source 10
+# match security-group source tag 10 20
+# match local-preference 100 50
+# match mpls-label
+# route-map test_1 deny 20
+# match track 105
+# match tag list test_match_tag
+# match route-type level-1
+# match additional-paths advertise-set all group-best
+# match as-path 200 100
+# match ipv6 address test_acl_20
+# continue 100
+# route-map test_2 deny 10
+# match security-group source tag 10 20
+# match local-preference 55 105
+# match mpls-label
+# match ipv6 address test_ip_acl
+# match ipv6 next-hop prefix-list test_new
+# match ipv6 route-source route_src_acl
+# set automatic-tag
+# set ip precedence critical
+# set ip address prefix-list 192.0.2.1
+# set aigp-metric 100
+# set extcommunity cost pre-bestpath 10 100
+# set ip df 1
+# set ip next-hop verify-availability 198.51.111.1 100 track 10
+# set ip next-hop recursive global 198.51.110.1
+
+- name: Override provided Route maps configuration
+ cisco.ios.ios_route_maps:
+ config:
+ - route_map: test_1
+ entries:
+ - sequence: 10
+ action: deny
+ description: this is override route
+ match:
+ ip:
+ next_hop:
+ acls:
+ - 10
+ - test1_acl
+ flowspec:
+ dest_pfx: true
+ acls:
+ - test_acl_1
+ - test_acl_2
+ length:
+ minimum: 10
+ maximum: 100
+ metric:
+ value: 10
+ external: true
+ security_group:
+ source:
+ - 10
+ - 20
+ mpls_label: true
+ set:
+ extcommunity:
+ vpn_distinguisher:
+ address: 192.0.2.1:12
+ additive: true
+ metric:
+ metric_value: 100
+ deviation: plus
+ eigrp_delay: 100
+ metric_reliability: 10
+ metric_bandwidth: 20
+ mtu: 30
+ - route_map: test_override
+ entries:
+ - sequence: 10
+ action: deny
+ match:
+ ipv6:
+ address:
+ acl: test_acl
+ next_hop:
+ prefix_list: test_new
+ route_source:
+ acl: route_src_acl
+ security_group:
+ source:
+ - 15
+ - 20
+ local_preference:
+ value:
+ - 105
+ - 110
+ mpls_label: true
+ set:
+ aigp_metric:
+ value: 100
+ automatic_tag: true
+ extcommunity:
+ cost:
+ id: 10
+ cost_value: 100
+ pre_bestpath: true
+ ip:
+ address: 192.0.2.1
+ df: 1
+ next_hop:
+ recursive:
+ global_route: true
+ address: 198.110.51.1
+ verify_availability:
+ address: 198.110.51.2
+ sequence: 100
+ track: 10
+ precedence:
+ critical: true
+ state: overridden
+
+# Commands Fired:
+# ---------------
+#
+# "commands": [
+# "no route-map test_2",
+# "route-map test_override deny 10",
+# "match security-group source tag 15 20",
+# "match local-preference 110 105",
+# "match mpls-label",
+# "match ipv6 next-hop prefix-list test_new",
+# "match ipv6 route-source route_src_acl",
+# "match ipv6 address test_acl",
+# "set extcommunity cost pre-bestpath 10 100",
+# "set ip df 1",
+# "set ip next-hop recursive global 198.110.51.1",
+# "set ip next-hop verify-availability 198.110.51.2 100 track 10",
+# "set ip precedence critical",
+# "set ip address prefix-list 192.0.2.1",
+# "set automatic-tag",
+# "set aigp-metric 100",
+# "route-map test_1 deny 10",
+# "no description this is test route",
+# "description this is override route",
+# "match ip flowspec dest-pfx test_acl_1 test_acl_2",
+# "no match ip next-hop prefix-list test_2_new test_1_new",
+# "match ip next-hop test1_acl 10",
+# "no match ip route-source 10",
+# "match metric external 10",
+# "match length 10 100",
+# "no match local-preference 100 50",
+# "set extcommunity vpn-distinguisher 192.0.2.1:12 additive",
+# "set metric 100 +100 10 20 30",
+# "no route-map test_1 deny 20"
+# ]
+
+# After state:
+# -------------
+#
+# router-ios#sh running-config | section ^route-map
+# route-map test_override deny 10
+# match security-group source tag 15 20
+# match local-preference 110 105
+# match mpls-label
+# match ipv6 address test_acl
+# match ipv6 next-hop prefix-list test_new
+# match ipv6 route-source route_src_acl
+# set automatic-tag
+# set ip precedence critical
+# set ip address prefix-list 192.0.2.1
+# set aigp-metric 100
+# set extcommunity cost pre-bestpath 10 100
+# set ip df 1
+# set ip next-hop verify-availability 198.110.51.2 100 track 10
+# set ip next-hop recursive global 198.110.51.1
+# route-map test_1 deny 10
+# description this is override route
+# match ip flowspec dest-pfx test_acl_1 test_acl_2
+# match ip next-hop test1_acl 10
+# match security-group source tag 10 20
+# match metric external 10
+# match mpls-label
+# match length 10 100
+# set metric 100 +100 10 20 30
+# set extcommunity vpn-distinguisher 192.0.2.1:12 additive
+
+# Using replaced
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^route-map
+# route-map test_1 deny 10
+# description this is test route
+# match ip next-hop prefix-list test_2_new test_1_new
+# match ip route-source 10
+# match security-group source tag 10 20
+# match local-preference 100 50
+# match mpls-label
+# route-map test_1 deny 20
+# match track 105
+# match tag list test_match_tag
+# match route-type level-1
+# match additional-paths advertise-set all group-best
+# match as-path 200 100
+# match ipv6 address test_acl_20
+# continue 100
+# route-map test_2 deny 10
+# match security-group source tag 10 20
+# match local-preference 55 105
+# match mpls-label
+# match ipv6 address test_ip_acl
+# match ipv6 next-hop prefix-list test_new
+# match ipv6 route-source route_src_acl
+# set automatic-tag
+# set ip precedence critical
+# set ip address prefix-list 192.0.2.1
+# set aigp-metric 100
+# set extcommunity cost pre-bestpath 10 100
+# set ip df 1
+# set ip next-hop verify-availability 198.51.111.1 100 track 10
+# set ip next-hop recursive global 198.51.110.1
+
+- name: Replaced provided Route maps configuration
+ cisco.ios.ios_route_maps:
+ config:
+ - route_map: test_1
+ entries:
+ - sequence: 10
+ action: deny
+ description: this is replaced route
+ match:
+ ip:
+ next_hop:
+ acls:
+ - 10
+ - test1_acl
+ flowspec:
+ dest_pfx: true
+ acls:
+ - test_acl_1
+ - test_acl_2
+ length:
+ minimum: 10
+ maximum: 100
+ metric:
+ value: 10
+ external: true
+ security_group:
+ source:
+ - 10
+ - 20
+ mpls_label: true
+ set:
+ extcommunity:
+ vpn_distinguisher:
+ address: 192.0.2.1:12
+ additive: true
+ metric:
+ metric_value: 100
+ deviation: plus
+ eigrp_delay: 100
+ metric_reliability: 10
+ metric_bandwidth: 20
+ mtu: 30
+ - route_map: test_replaced
+ entries:
+ - sequence: 10
+ action: deny
+ match:
+ ipv6:
+ address:
+ acl: test_acl
+ next_hop:
+ prefix_list: test_new
+ route_source:
+ acl: route_src_acl
+ security_group:
+ source:
+ - 15
+ - 20
+ local_preference:
+ value:
+ - 105
+ - 110
+ mpls_label: true
+ set:
+ aigp_metric:
+ value: 100
+ automatic_tag: true
+ extcommunity:
+ cost:
+ id: 10
+ cost_value: 100
+ pre_bestpath: true
+ ip:
+ address: 192.0.2.1
+ df: 1
+ next_hop:
+ recursive:
+ global_route: true
+ address: 198.110.51.1
+ verify_availability:
+ address: 198.110.51.2
+ sequence: 100
+ track: 10
+ precedence:
+ critical: true
+ state: replaced
+
+# Commands Fired:
+# ---------------
+# "commands": [
+# "route-map test_replaced deny 10",
+# "match security-group source tag 15 20",
+# "match local-preference 110 105",
+# "match mpls-label",
+# "match ipv6 next-hop prefix-list test_new",
+# "match ipv6 route-source route_src_acl",
+# "match ipv6 address test_acl",
+# "set extcommunity cost pre-bestpath 10 100",
+# "set ip df 1",
+# "set ip next-hop recursive global 198.110.51.1",
+# "set ip next-hop verify-availability 198.110.51.2 100 track 10",
+# "set ip precedence critical",
+# "set ip address prefix-list 192.0.2.1",
+# "set automatic-tag",
+# "set aigp-metric 100",
+# "route-map test_1 deny 10",
+# "no description this is test route",
+# "description this is replaced route",
+# "match ip flowspec dest-pfx test_acl_1 test_acl_2",
+# "no match ip next-hop prefix-list test_2_new test_1_new",
+# "match ip next-hop test1_acl 10",
+# "no match ip route-source 10",
+# "match metric external 10",
+# "match length 10 100",
+# "no match local-preference 100 50",
+# "set extcommunity vpn-distinguisher 192.0.2.1:12 additive",
+# "set metric 100 +100 10 20 30",
+# "no route-map test_1 deny 20"
+# ]
+
+# After state:
+# -------------
+#
+# router-ios#sh running-config | section ^route-map
+# route-map test_replaced deny 10
+# match security-group source tag 15 20
+# match local-preference 110 105
+# match mpls-label
+# match ipv6 address test_acl
+# match ipv6 next-hop prefix-list test_new
+# match ipv6 route-source route_src_acl
+# set automatic-tag
+# set ip precedence critical
+# set ip address prefix-list 192.0.2.1
+# set aigp-metric 100
+# set extcommunity cost pre-bestpath 10 100
+# set ip df 1
+# set ip next-hop verify-availability 198.110.51.2 100 track 10
+# set ip next-hop recursive global 198.110.51.1
+# route-map test_1 deny 10
+# description this is replaced route
+# match ip flowspec dest-pfx test_acl_1 test_acl_2
+# match ip next-hop test1_acl 10
+# match security-group source tag 10 20
+# match metric external 10
+# match mpls-label
+# match length 10 100
+# set metric 100 +100 10 20 30
+# set extcommunity vpn-distinguisher 192.0.2.1:12 additive
+# route-map test_2 deny 10
+# match security-group source tag 10 20
+# match local-preference 55 105
+# match mpls-label
+# match ipv6 address test_ip_acl
+# match ipv6 next-hop prefix-list test_new
+# match ipv6 route-source route_src_acl
+# set automatic-tag
+# set ip precedence critical
+# set ip address prefix-list 192.0.2.1
+# set aigp-metric 100
+# set extcommunity cost pre-bestpath 10 100
+# set ip df 1
+# set ip next-hop verify-availability 198.51.111.1 100 track 10
+# set ip next-hop recursive global 198.51.110.1
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# router-ios#sh running-config | section ^route-map
+# route-map test_1 deny 10
+# description this is test route
+# match ip next-hop prefix-list test_2_new test_1_new
+# match ip route-source 10
+# match security-group source tag 10 20
+# match local-preference 100 50
+# match mpls-label
+# route-map test_1 deny 20
+# match track 105
+# match tag list test_match_tag
+# match route-type level-1
+# match additional-paths advertise-set all group-best
+# match as-path 200 100
+# match ipv6 address test_acl_20
+# continue 100
+# route-map test_2 deny 10
+# match security-group source tag 10 20
+# match local-preference 55 105
+# match mpls-label
+# match ipv6 address test_ip_acl
+# match ipv6 next-hop prefix-list test_new
+# match ipv6 route-source route_src_acl
+# set automatic-tag
+# set ip precedence critical
+# set ip address prefix-list 192.0.2.1
+# set aigp-metric 100
+# set extcommunity cost pre-bestpath 10 100
+# set ip df 1
+# set ip next-hop verify-availability 198.51.111.1 100 track 10
+# set ip next-hop recursive global 198.51.110.1
+
+- name: Gather Route maps provided configurations
+ cisco.ios.ios_route_maps:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": [
+# {
+# "entries": [
+# {
+# "action": "deny",
+# "description": "this is test route",
+# "match": {
+# "ip": {
+# "next_hop": {
+# "prefix_lists": [
+# "test_2_new",
+# "test_1_new"
+# ]
+# },
+# "route_source": {
+# "acls": [
+# "10"
+# ]
+# }
+# },
+# "local_preference": {
+# "value": [
+# "100",
+# "50"
+# ]
+# },
+# "mpls_label": true,
+# "security_group": {
+# "source": [
+# 10,
+# 20
+# ]
+# }
+# },
+# "sequence": 10
+# },
+# {
+# "action": "deny",
+# "continue_entry": {
+# "entry_sequence": 100
+# },
+# "match": {
+# "additional_paths": {
+# "all": true,
+# "group_best": true
+# },
+# "as_path": {
+# "acls": [
+# 200,
+# 100
+# ]
+# },
+# "ipv6": {
+# "address": {
+# "acl": "test_acl_20"
+# }
+# },
+# "route_type": {
+# "external": {
+# "set": true
+# },
+# "level_1": true,
+# "nssa_external": {
+# "set": true
+# }
+# },
+# "tag": {
+# "tag_list": [
+# "test_match_tag"
+# ]
+# },
+# "track": 105
+# },
+# "sequence": 20
+# }
+# ],
+# "route_map": "test_1"
+# },
+# {
+# "entries": [
+# {
+# "action": "deny",
+# "match": {
+# "ipv6": {
+# "address": {
+# "acl": "test_ip_acl"
+# },
+# "next_hop": {
+# "prefix_list": "test_new"
+# },
+# "route_source": {
+# "acl": "route_src_acl"
+# }
+# },
+# "local_preference": {
+# "value": [
+# "55",
+# "105"
+# ]
+# },
+# "mpls_label": true,
+# "security_group": {
+# "source": [
+# 10,
+# 20
+# ]
+# }
+# },
+# "sequence": 10,
+# "set": {
+# "aigp_metric": {
+# "value": 100
+# },
+# "automatic_tag": true,
+# "extcommunity": {
+# "cost": {
+# "cost_value": 100,
+# "id": "10",
+# "pre_bestpath": true
+# }
+# },
+# "ip": {
+# "address": "192.0.2.1",
+# "df": 1,
+# "next_hop": {
+# "recursive": {
+# "address": "198.51.110.1",
+# "global_route": true
+# },
+# "verify_availability": {
+# "address": "198.51.111.1",
+# "sequence": 100,
+# "track": 10
+# }
+# },
+# "precedence": {
+# "critical": true
+# }
+# }
+# }
+# }
+# ],
+# "route_map": "test_2"
+# }
+# ]
+
+# After state:
+# ------------
+#
+# router-ios#sh running-config | section ^route-map
+# route-map test_1 deny 10
+# description this is test route
+# match ip next-hop prefix-list test_2_new test_1_new
+# match ip route-source 10
+# match security-group source tag 10 20
+# match local-preference 100 50
+# match mpls-label
+# route-map test_1 deny 20
+# match track 105
+# match tag list test_match_tag
+# match route-type level-1
+# match additional-paths advertise-set all group-best
+# match as-path 200 100
+# match ipv6 address test_acl_20
+# continue 100
+# route-map test_2 deny 10
+# match security-group source tag 10 20
+# match local-preference 55 105
+# match mpls-label
+# match ipv6 address test_ip_acl
+# match ipv6 next-hop prefix-list test_new
+# match ipv6 route-source route_src_acl
+# set automatic-tag
+# set ip precedence critical
+# set ip address prefix-list 192.0.2.1
+# set aigp-metric 100
+# set extcommunity cost pre-bestpath 10 100
+# set ip df 1
+# set ip next-hop verify-availability 198.51.111.1 100 track 10
+# set ip next-hop recursive global 198.51.110.1
+
+# Using Rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_route_maps:
+ config:
+ - route_map: test_1
+ entries:
+ - sequence: 10
+ action: deny
+ description: this is test route
+ match:
+ ip:
+ next_hop:
+ prefix_lists:
+ - test_1_new
+ - test_2_new
+ route_source:
+ acls:
+ - 10
+ security_group:
+ source:
+ - 10
+ - 20
+ local_preference:
+ value:
+ - 50
+ - 100
+ mpls_label: true
+ - sequence: 20
+ action: deny
+ continue_entry:
+ entry_sequence: 100
+ match:
+ additional_paths:
+ all: true
+ group_best: true
+ as_path:
+ acls:
+ - 100
+ - 200
+ ipv6:
+ address:
+ acl: test_acl_20
+ route_type:
+ level_1: true
+ tag:
+ tag_list:
+ - test_match_tag
+ track: 105
+ - route_map: test_2
+ entries:
+ - sequence: 10
+ action: deny
+ match:
+ ipv6:
+ address:
+ acl: test_ip_acl
+ next_hop:
+ prefix_list: test_new
+ route_source:
+ acl: route_src_acl
+ security_group:
+ source:
+ - 10
+ - 20
+ local_preference:
+ value:
+ - 55
+ - 105
+ mpls_label: true
+ set:
+ aigp_metric:
+ value: 100
+ automatic_tag: true
+ extcommunity:
+ cost:
+ id: 10
+ cost_value: 100
+ pre_bestpath: true
+ ip:
+ address: 192.0.2.1
+ df: 1
+ next_hop:
+ recursive:
+ global_route: true
+ address: 198.51.110.1
+ verify_availability:
+ address: 198.51.111.1
+ sequence: 100
+ track: 10
+ precedence:
+ critical: true
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "route-map test_2 deny 10",
+# "match security-group source tag 10 20",
+# "match local-preference 55 105",
+# "match mpls-label",
+# "match ipv6 next-hop prefix-list test_new",
+# "match ipv6 route-source route_src_acl",
+# "match ipv6 address test_ip_acl",
+# "set extcommunity cost pre-bestpath 10 100",
+# "set ip df 1",
+# "set ip next-hop recursive global 198.51.110.1",
+# "set ip next-hop verify-availability 198.51.111.1 100 track 10",
+# "set ip precedence critical",
+# "set ip address prefix-list 192.0.2.1",
+# "set automatic-tag",
+# "set aigp-metric 100",
+# "route-map test_1 deny 20",
+# "continue 100",
+# "match track 105",
+# "match tag list test_match_tag",
+# "match ipv6 address test_acl_20",
+# "match route-type level-1",
+# "match as-path 200 100",
+# "match additional-paths advertise-set all group-best",
+# "route-map test_1 deny 10",
+# "description this is test route",
+# "match security-group source tag 10 20",
+# "match ip next-hop prefix-list test_2_new test_1_new",
+# "match ip route-source 10",
+# "match local-preference 100 50",
+# "match mpls-label"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# route-map test_1 deny 10
+# description this is test route
+# match ip next-hop prefix-list test_2_new test_1_new
+# match ip route-source 10
+# match security-group source tag 10 20
+# match local-preference 100 50
+# match mpls-label
+# route-map test_1 deny 20
+# match track 105
+# match tag list test_match_tag
+# match route-type level-1
+# match additional-paths advertise-set all group-best
+# match as-path 200 100
+# match ipv6 address test_acl_20
+# continue 100
+# route-map test_2 deny 10
+# match security-group source tag 10 20
+# match local-preference 55 105
+# match mpls-label
+# match ipv6 address test_ip_acl
+# match ipv6 next-hop prefix-list test_new
+# match ipv6 route-source route_src_acl
+# set automatic-tag
+# set ip precedence critical
+# set ip address prefix-list 192.0.2.1
+# set aigp-metric 100
+# set extcommunity cost pre-bestpath 10 100
+# set ip df 1
+# set ip next-hop verify-availability 198.51.111.1 100 track 10
+# set ip next-hop recursive global 198.51.110.1
+
+- name: Parse the provided configuration with the existing running configuration
+ cisco.ios.ios_route_maps:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": [
+# {
+# "entries": [
+# {
+# "action": "deny",
+# "description": "this is test route",
+# "match": {
+# "ip": {
+# "next_hop": {
+# "prefix_lists": [
+# "test_2_new",
+# "test_1_new"
+# ]
+# },
+# "route_source": {
+# "acls": [
+# "10"
+# ]
+# }
+# },
+# "local_preference": {
+# "value": [
+# "100",
+# "50"
+# ]
+# },
+# "mpls_label": true,
+# "security_group": {
+# "source": [
+# 10,
+# 20
+# ]
+# }
+# },
+# "sequence": 10
+# },
+# {
+# "action": "deny",
+# "continue_entry": {
+# "entry_sequence": 100
+# },
+# "match": {
+# "additional_paths": {
+# "all": true,
+# "group_best": true
+# },
+# "as_path": {
+# "acls": [
+# 200,
+# 100
+# ]
+# },
+# "ipv6": {
+# "address": {
+# "acl": "test_acl_20"
+# }
+# },
+# "route_type": {
+# "external": {
+# "set": true
+# },
+# "level_1": true,
+# "nssa_external": {
+# "set": true
+# }
+# },
+# "tag": {
+# "tag_list": [
+# "test_match_tag"
+# ]
+# },
+# "track": 105
+# },
+# "sequence": 20
+# }
+# ],
+# "route_map": "test_1"
+# },
+# {
+# "entries": [
+# {
+# "action": "deny",
+# "match": {
+# "ipv6": {
+# "address": {
+# "acl": "test_ip_acl"
+# },
+# "next_hop": {
+# "prefix_list": "test_new"
+# },
+# "route_source": {
+# "acl": "route_src_acl"
+# }
+# },
+# "local_preference": {
+# "value": [
+# "55",
+# "105"
+# ]
+# },
+# "mpls_label": true,
+# "security_group": {
+# "source": [
+# 10,
+# 20
+# ]
+# }
+# },
+# "sequence": 10,
+# "set": {
+# "aigp_metric": {
+# "value": 100
+# },
+# "automatic_tag": true,
+# "extcommunity": {
+# "cost": {
+# "cost_value": 100,
+# "id": "10",
+# "pre_bestpath": true
+# }
+# },
+# "ip": {
+# "address": "192.0.2.1",
+# "df": 1,
+# "next_hop": {
+# "recursive": {
+# "address": "198.51.110.1",
+# "global_route": true
+# },
+# "verify_availability": {
+# "address": "198.51.111.1",
+# "sequence": 100,
+# "track": 10
+# }
+# },
+# "precedence": {
+# "critical": true
+# }
+# }
+# }
+# }
+# ],
+# "route_map": "test_2"
+# }
+# ]
+"""
+
+RETURN = """
+before:
+ description: The configuration prior to the model invocation.
+ returned: always
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: list
+after:
+ description: The resulting configuration model invocation.
+ returned: when changed
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+ type: list
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: always
+ type: list
+ sample: ['route-map test_1 deny 10', 'description this is test route', 'match ip route-source 10', 'match track 105']
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.route_maps.route_maps import (
+ Route_mapsArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.route_maps.route_maps import (
+ Route_maps,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ module = AnsibleModule(
+ argument_spec=Route_mapsArgs.argument_spec,
+ mutually_exclusive=[["config", "running_config"]],
+ required_if=[
+ ["state", "merged", ["config"]],
+ ["state", "replaced", ["config"]],
+ ["state", "overridden", ["config"]],
+ ["state", "rendered", ["config"]],
+ ["state", "parsed", ["running_config"]],
+ ],
+ supports_check_mode=True,
+ )
+
+ result = Route_maps(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_service.py b/ansible_collections/cisco/ios/plugins/modules/ios_service.py
new file mode 100644
index 000000000..89fe2ed47
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_service.py
@@ -0,0 +1,690 @@
+#!/usr/bin/python
+# -*- 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)
+
+"""
+The module file for ios_service
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+---
+module: ios_service
+short_description: Resource module to configure service.
+description:
+ - This module configures and manages service attributes on IOS platforms
+version_added: 4.6.0
+author:
+ - Ambroise Rosset (@earendilfr)
+notes:
+ - Tested against Cisco IOSXE Version 16.9
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ config:
+ description: A dictionnary of service configuration
+ suboptions:
+ call_home:
+ description: Cisco call-home service
+ type: bool
+ compress_config:
+ description: Compress the nvram configuration file
+ type: bool
+ config:
+ description: TFTP load config files
+ type: bool
+ counters:
+ description:
+ - Control aging of interface counters by setting the maximum counter aging threshold
+ type: int
+ default: 0
+ dhcp:
+ description: Enable DHCP server and relay agent
+ type: bool
+ default: true
+ disable_ip_fast_frag:
+ description: Disable IP particle-based fast fragmentation
+ type: bool
+ exec_callback:
+ description: Enable exec callback
+ type: bool
+ exec_wait:
+ description: Delay EXEC startup on noisy lines
+ type: bool
+ hide_telnet_addresses:
+ description: Hide destination addresses in telnet command
+ type: bool
+ internal:
+ description: Enable/Disable Internal commands
+ type: bool
+ linenumber:
+ description: enable line number banner for each exec
+ type: bool
+ log:
+ description: log backtrace
+ type: bool
+ log_hidden:
+ description: Enable syslog msgs for hidden/internal commands
+ type: bool
+ nagle:
+ description: Enable Nagle's congestion control algorithm
+ type: bool
+ old_slip_prompts:
+ description: Allow old scripts to operate with slip/ppp
+ type: bool
+ pad:
+ description: Enable PAD commands
+ type: bool
+ pad_cmns:
+ description: Enable PAD over CMNS connections
+ type: bool
+ pad_from_xot:
+ description: Accept XOT to PAD connections
+ type: bool
+ pad_to_xot:
+ description: Allow outgoing PAD over XOT connections
+ type: bool
+ password_encryption:
+ description: Encrypt system passwords
+ type: bool
+ password_recovery:
+ description: Password recovery
+ type: bool
+ default: true
+ prompt:
+ description: Enable mode specific prompt
+ type: bool
+ default: true
+ private_config_encryption:
+ description: Enable private config file encryption
+ type: bool
+ pt_vty_logging:
+ description: Log significant VTY-Async events
+ type: bool
+ scripting:
+ description: scripting
+ type: bool
+ sequence_numbers:
+ description: Stamp logger messages with a sequence number
+ type: bool
+ slave_coredump:
+ description: slave-coredump
+ type: bool
+ slave_log:
+ description: Enable log capability of slave IPs
+ type: bool
+ default: true
+ tcp_keepalives_in:
+ description: Generate keepalives on idle incoming network connections
+ type: bool
+ tcp_keepalives_out:
+ description: Generate keepalives on idle outgoing network connections
+ type: bool
+ tcp_small_servers:
+ description:
+ - TCP and UDP small servers are servers (daemons, in Unix parlance) that run in the
+ router which are useful for diagnostics.
+ suboptions:
+ enable:
+ description: Enable small TCP servers (e.g., ECHO)
+ type: bool
+ max_servers:
+ description:
+ - Set number of allowable TCP small servers
+ - 1 to 2147483647 or no-limit
+ type: str
+ type: dict
+ telnet_zeroidle:
+ description: Set TCP window 0 when connection is idle
+ type: bool
+ timestamps:
+ description: Timestamp debug/log messages
+ elements: dict
+ suboptions:
+ msg:
+ description: Timestamp log or debug messages
+ choices:
+ - debug
+ - log
+ type: str
+ enable:
+ description: Enable timestamp for the choosen message
+ type: bool
+ timestamp:
+ description: Timestamp with date and time or with system uptime
+ choices:
+ - datetime
+ - uptime
+ type: str
+ datetime_options:
+ description: Options for date and time timestamp
+ suboptions:
+ localtime:
+ description: Use local time zone for timestamps
+ type: bool
+ msec:
+ description: Include milliseconds in timestamp
+ type: bool
+ show_timezone:
+ description: Add time zone information to timestamp
+ type: bool
+ year:
+ description: Include year in timestam
+ type: bool
+ type: dict
+ type: list
+ udp_small_servers:
+ description:
+ - TCP and UDP small servers are servers (daemons, in Unix parlance) that run in the
+ router which are useful for diagnostics.
+ suboptions:
+ enable:
+ description: Enable small UDP servers (e.g., ECHO)
+ type: bool
+ max_servers:
+ description:
+ - Set number of allowable TCP small servers
+ - 1 to 2147483647 or no-limit
+ type: str
+ type: dict
+ unsupported_transceiver:
+ description: enable support for third-party transceivers
+ type: bool
+ type: dict
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device by
+ executing the command B(show running-config | section ^service|^no service).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ choices:
+ - merged
+ - replaced
+ - deleted
+ - gathered
+ - rendered
+ - parsed
+ default: merged
+ description:
+ - The state the configuration should be left in.
+ - Refer to examples for more details.
+ type: str
+"""
+
+EXAMPLES = """
+# Using merged
+
+# Before state:
+# -------------
+
+# router-ios#show running-config all | section ^service
+# service slave-log
+# service timestamps debug datetime msec
+# service timestamps log datetime msec
+# service private-config-encryption
+# service prompt config
+# service counters max age 0
+# service dhcp
+# service call-home
+# service password-recovery
+
+- name: Merge provided configuration with device configuration
+ cisco.ios.ios_service:
+ config:
+ tcp_keepalives_in: true
+ tcp_keepalives_out: true
+ timestamps:
+ - msg: debug
+ enable: true
+ timestamp: datetime
+ - msg: log
+ enable: true
+ timestamp: datetime
+ pad: false
+ password_encryption: true
+ state: merged
+
+# Task Output
+# -----------
+#
+# before:
+# call_home: true
+# counters: 0
+# dhcp: true
+# password_recovery: true
+# private_config_encryption: true
+# prompt: true
+# slave_log: true
+# timestamps:
+# - datetime_options:
+# msec: true
+# msg: debug
+# timestamp: datetime
+# - datetime_options:
+# msec: true
+# msg: log
+# timestamp: datetime
+# commands:
+# - service password-encryption
+# - service tcp-keepalives-in
+# - service tcp-keepalives-out
+# after:
+# call_home: true
+# counters: 0
+# dhcp: true
+# password_encryption: true
+# password_recovery: true
+# private_config_encryption: true
+# prompt: true
+# slave_log: true
+# tcp_keepalives_in: true
+# tcp_keepalives_out: true
+# timestamps:
+# - datetime_options:
+# msec: true
+# msg: debug
+# timestamp: datetime
+# - datetime_options:
+# msec: true
+# msg: log
+# timestamp: datetime
+
+# After state:
+# ------------
+
+# router-ios#show running-config all | section ^service
+# service slave-log
+# service tcp-keepalives-in
+# service tcp-keepalives-out
+# service timestamps debug datetime msec
+# service timestamps log datetime msec
+# service password-encryption
+# service private-config-encryption
+# service prompt config
+# service counters max age 0
+# service dhcp
+# service call-home
+# service password-recovery
+
+# Using replaced
+
+# Before state:
+# -------------
+
+# router-ios#show running-config all | section ^service
+# service slave-log
+# service tcp-keepalives-in
+# service tcp-keepalives-out
+# service timestamps debug datetime msec
+# service timestamps log datetime msec
+# service password-encryption
+# service private-config-encryption
+# service prompt config
+# service counters max age 0
+# service dhcp
+# service call-home
+# service password-recovery
+
+- name: Replaces device configuration of services with provided configuration
+ cisco.ios.ios_service:
+ config:
+ timestamps:
+ - msg: log
+ enable: true
+ timestamp: datetime
+ datetime_options:
+ localtime: true
+ msec: true
+ show_timezone: true
+ year: true
+ - msg: debug
+ enable: true
+ timestamp: datetime
+ pad: false
+ password_encryption: true
+ state: "replaced"
+
+# Task Output
+# -----------
+#
+# before:
+# call_home: true
+# counters: 0
+# dhcp: true
+# password_encryption: true
+# password_recovery: true
+# private_config_encryption: true
+# prompt: true
+# slave_log: true
+# tcp_keepalives_in: true
+# tcp_keepalives_out: true
+# timestamps:
+# - datetime_options:
+# msec: true
+# msg: debug
+# timestamp: datetime
+# - datetime_options:
+# msec: true
+# msg: log
+# timestamp: datetime
+# commands:
+# - no service call-home
+# - no service tcp-keepalives-in
+# - no service tcp-keepalives-out
+# - no service timestamps log
+# - service timestamps log datetime msec localtime show-timezone year
+# - no service timestamps debug
+# - service timestamps debug datetime
+# after:
+# counters: 0
+# dhcp: true
+# password_encryption: true
+# password_recovery: true
+# private_config_encryption: true
+# prompt: true
+# slave_log: true
+# timestamps:
+# - msg: debug
+# timestamp: datetime
+# - datetime_options:
+# localtime: true
+# msec: true
+# show_timezone: true
+# year: true
+# msg: log
+# timestamp: datetime
+
+# After state:
+# ------------
+
+# router-ios#show running-config all | section ^service
+# service slave-log
+# service timestamps debug datetime
+# service timestamps log datetime msec localtime show-timezone year
+# service password-encryption
+# service private-config-encryption
+# service prompt config
+# service counters max age 0
+# service dhcp
+# service password-recovery
+
+# Using Deleted
+
+# Before state:
+# -------------
+
+# router-ios#show running-config all | section ^service
+# service slave-log
+# service timestamps debug datetime
+# service timestamps log datetime msec localtime show-timezone year
+# service password-encryption
+# service private-config-encryption
+# service prompt config
+# service counters max age 0
+# service dhcp
+# service password-recovery
+
+- name: "Delete service configuration and restore default configuration for some importants service (those with a default value in module)"
+ cisco.ios.ios_service:
+ state: deleted
+
+# Task Output
+# -----------
+#
+# before:
+# counters: 0
+# dhcp: true
+# password_encryption: true
+# password_recovery: true
+# private_config_encryption: true
+# prompt: true
+# slave_log: true
+# timestamps:
+# - msg: debug
+# timestamp: datetime
+# - datetime_options:
+# localtime: true
+# msec: true
+# show_timezone: true
+# year: true
+# msg: log
+# timestamp: datetime
+# commands:
+# - no service password-encryption
+# - no service timestamps debug
+# - no service timestamps log
+# after:
+# counters: 0
+# dhcp: true
+# password_recovery: true
+# private_config_encryption: true
+# prompt: true
+# slave_log: true
+
+#·After·state:
+#·------------
+#
+# router-ios#show running-config all | section ^service
+# service slave-log
+# service private-config-encryption
+# service prompt config
+# service counters max age 0
+# service dhcp
+# service password-recovery
+
+# Using gathered
+
+# Before state:
+# -------------
+#
+# router-ios#show running-config all | section ^service
+# service slave-log
+# service timestamps debug datetime
+# service timestamps log datetime msec localtime show-timezone year
+# service password-encryption
+# service private-config-encryption
+# service prompt config
+# service counters max age 0
+# service dhcp
+# service password-recovery
+
+- name: Gather facts of interfaces
+ cisco.ios.ios_service:
+ config:
+ state: gathered
+
+# Task Output
+# -----------
+#
+# gathered:
+# counters: 0
+# dhcp: true
+# password_encryption: true
+# password_recovery: true
+# private_config_encryption: true
+# prompt: true
+# slave_log: true
+# timestamps:
+# - msg: debug
+# timestamp: datetime
+# - datetime_options:
+# localtime: true
+# msec: true
+# show_timezone: true
+# year: true
+# msg: log
+# timestamp: datetime
+
+# Using rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_service:
+ config:
+ timestamps:
+ - msg: log
+ enable: true
+ timestamp: datetime
+ datetime_options:
+ localtime: true
+ msec: true
+ show_timezone: true
+ year: true
+ - msg: debug
+ enable: true
+ timestamp: datetime
+ pad: false
+ password_encryption: true
+ state: rendered
+
+# ·Task·Output
+# -----------
+#
+# rendered:
+# - service dhcp
+# - service password-encryption
+# - service password-recovery
+# - service prompt config
+# - service slave-log
+# - service timestamps log datetime msec localtime show-timezone year
+# - service timestamps debug datetime
+
+# Using parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# no service pad
+# service password-encryption
+# service tcp-keepalives-in
+# service tcp-keepalives-out
+# service timestamps debug datetime msec localtime show-timezone year
+# service timestamps log datetime msec localtime show-timezone year
+# service counters max age 5
+
+- name: Parse the provided configuration
+ cisco.ios.ios_service:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Task Output
+# -----------
+#
+# parsed:
+# counters: 5
+# dhcp: true
+# password_encryption: true
+# password_recovery: true
+# prompt: true
+# slave_log: true
+# tcp_keepalives_in: true
+# tcp_keepalives_out: true
+# timestamps:
+# - datetime_options:
+# localtime: true
+# msec: true
+# show_timezone: true
+# year: true
+# msg: debug
+# timestamp: datetime
+# - datetime_options:
+# localtime: true
+# msec: true
+# show_timezone: true
+# year: true
+# msg: log
+# timestamp: datetime
+"""
+
+RETURN = """
+before:
+ description: The configuration prior to the module execution.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+after:
+ description: The resulting configuration after module execution.
+ returned: when changed
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: list
+ sample:
+ - no service config
+ - service tcp-keepalives-in
+ - service tcp-keepalives-out
+rendered:
+ description: The provided configuration in the task rendered in device-native format (offline).
+ returned: when I(state) is C(rendered)
+ type: list
+ sample:
+ - service dhcp
+ - service password-encryption
+ - service password-recovery
+ - service prompt config
+ - service slave-log
+gathered:
+ description: Facts about the network resource gathered from the remote device as structured data.
+ returned: when I(state) is C(gathered)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+parsed:
+ description: The device native config provided in I(running_config) option parsed into structured data as per module argspec.
+ returned: when I(state) is C(parsed)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.service.service import (
+ ServiceArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.service.service import (
+ Service,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ module = AnsibleModule(
+ argument_spec=ServiceArgs.argument_spec,
+ mutually_exclusive=[["config", "running_config"]],
+ required_if=[
+ ["state", "merged", ["config"]],
+ ["state", "replaced", ["config"]],
+ ["state", "rendered", ["config"]],
+ ["state", "parsed", ["running_config"]],
+ ],
+ supports_check_mode=True,
+ )
+
+ result = Service(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_snmp_server.py b/ansible_collections/cisco/ios/plugins/modules/ios_snmp_server.py
new file mode 100644
index 000000000..5cfc735d8
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_snmp_server.py
@@ -0,0 +1,2026 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright 2022 Red Hat
+# GNU General Public License v3.0+
+# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+"""
+The module file for ios_snmp_server
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+author:
+ - Sagar Paul (@KB-perByte)
+description:
+ - This module provides declarative management of SNMP server on Cisco IOS devices.
+module: ios_snmp_server
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+options:
+ config:
+ description: A dictionary of SNMP server configuration
+ suboptions:
+ accounting:
+ description: SNMP Accounting parameters
+ suboptions:
+ command:
+ description: For SNMP set commands
+ type: str
+ type: dict
+ cache:
+ description: Enable SNMP cache and MIB expiry interval
+ type: int
+ chassis_id:
+ description: String to uniquely identify this chassis (Hexadecimal)
+ type: str
+ communities:
+ description: Community name configuration.
+ elements: dict
+ suboptions:
+ acl_v4:
+ description: standard access-list name
+ type: str
+ acl_v6:
+ description: IPv6 access list name
+ type: str
+ name:
+ description: Community name (default RO)
+ type: str
+ ro:
+ description: Only reads are permitted
+ type: bool
+ rw:
+ description: Read-write access
+ type: bool
+ view:
+ description: MIB view name
+ type: str
+ type: list
+ contact:
+ description: Text for mib object sysContact
+ type: str
+ context:
+ description: Create/Delete a context apart from default
+ elements: str
+ type: list
+ drop:
+ description: Silently drop SNMP packets
+ suboptions:
+ unknown_user:
+ description: Silently drop unknown v3 user packets
+ type: bool
+ vrf_traffic:
+ description: Silently drop SNMP packets that come on VRF interfaces
+ type: bool
+ type: dict
+ engine_id:
+ description: Configure a local or remote SNMPv3 engineID
+ elements: dict
+ suboptions:
+ id:
+ description: engine ID octet string
+ type: str
+ local:
+ description: Local SNMP agent
+ type: bool
+ remote:
+ description: Remote SNMP agent
+ suboptions:
+ host:
+ description: Hostname or IP address of remote SNMP notification host
+ type: str
+ udp_port:
+ description: The remote SNMP notification host's UDP port number.
+ type: int
+ vrf:
+ description: The remote notification host's VPN routing instance
+ type: str
+ type: dict
+ type: list
+ file_transfer:
+ description: File transfer related commands
+ suboptions:
+ access_group:
+ description: Access control for file transfers
+ type: str
+ protocol:
+ description: Access control protocol for file transfers
+ type: list
+ elements: str
+ type: dict
+ groups:
+ description: Define a User Security Model group
+ elements: dict
+ suboptions:
+ context:
+ description: Specify a context to associate with the group
+ type: str
+ version_option:
+ choices:
+ - auth
+ - noauth
+ - priv
+ description: community name to the host.
+ type: str
+ group:
+ description: SNMP group for the user
+ type: str
+ notify:
+ description: View to restrict notifications
+ type: str
+ read:
+ description: View to restrict read access
+ type: str
+ version:
+ choices:
+ - v1
+ - v3
+ - v2c
+ description: snmp security group version
+ type: str
+ write:
+ description: View to restrict write access
+ type: str
+ acl_v4:
+ description: specify an access-list associated with this group
+ type: str
+ acl_v6:
+ description: specify an access-list associated with this group
+ type: str
+ type: list
+ hosts:
+ description: Specify hosts to receive SNMP notifications
+ elements: dict
+ suboptions:
+ host:
+ description: Hostname or IP address of SNMP notification host.
+ type: str
+ informs:
+ description: Use SNMP inform messages.
+ type: bool
+ community_string:
+ description: SNMPv1/v2c community string or SNMPv3 user name
+ type: str
+ traps:
+ description: Use SNMP trap messages
+ type: list
+ elements: str
+ version:
+ choices:
+ - "1"
+ - 2c
+ - "3"
+ description: Notification message SNMP version.
+ type: str
+ version_option:
+ choices:
+ - auth
+ - noauth
+ - priv
+ description: community name to the host.
+ type: str
+ vrf:
+ description: Specify the VRF in which the host is configured
+ type: str
+ type: list
+ if_index:
+ description: Enable ifindex persistence
+ type: bool
+ inform:
+ description: Configure SNMP Informs options
+ suboptions:
+ pending:
+ description: Set number of unacked informs to hold
+ type: int
+ retries:
+ description: Set retry count for informs
+ type: int
+ timeout:
+ description: Set timeout for informs
+ type: int
+ type: dict
+ ip:
+ description: IP ToS configuration for SNMP traffic
+ suboptions:
+ dscp:
+ description: IP DSCP value for SNMP traffic
+ type: int
+ precedence:
+ description: IP Precedence value for SNMP traffic
+ type: int
+ type: dict
+ location:
+ description: Text for mib object sysLocation
+ type: str
+ manager:
+ description: Modify SNMP manager parameters
+ type: int
+ packet_size:
+ description: Largest SNMP packet size
+ type: int
+ password_policy:
+ description: SNMP v3 users password policy
+ elements: dict
+ suboptions:
+ change:
+ description: Number of Character changes b/w old and new password
+ type: int
+ digits:
+ description: Number of digits
+ type: int
+ lower_case:
+ description: Number of lower-case characters
+ type: int
+ max_len:
+ description: Maximum password length
+ type: int
+ min_len:
+ description: Minimum password length
+ type: int
+ policy_name:
+ description: Name of the policy
+ type: str
+ special_char:
+ description: Number of special case character
+ type: int
+ upper_case:
+ description: Number of upper-case characters
+ type: int
+ username:
+ description: Name of the user
+ type: str
+ type: list
+ queue_length:
+ description: Message queue length for each TRAP host
+ type: int
+ source_interface:
+ description: Source interface to be used for sending out SNMP notifications.
+ type: str
+ system_shutdown:
+ description: Enable use of the SNMP reload command
+ type: bool
+ trap_source:
+ description: Assign an interface for the source address of all traps
+ type: str
+ trap_timeout:
+ description: Set timeout for TRAP message retransmissions
+ type: int
+ traps:
+ description: Enable SNMP Traps
+ suboptions:
+ auth_framework:
+ description: Enable SNMP CISCO-AUTH-FRAMEWORK-MIB traps
+ suboptions:
+ sec_violation:
+ description: Mode sec_violation
+ type: bool
+ enable:
+ description: Enable/disable auth framework
+ type: bool
+ type: dict
+ bfd:
+ description: Allow SNMP BFD traps
+ suboptions:
+ enable:
+ description: Enable/disable bfd
+ type: bool
+ session_down:
+ description: Enable BFD session down traps
+ type: bool
+ session_up:
+ description: Enable BFD session up traps
+ type: bool
+ type: dict
+ bgp:
+ description: Allow bgp traps
+ suboptions:
+ cbgp2:
+ description: Enable BGP MIBv2 traps
+ type: bool
+ enable:
+ description: Enable/disable bgp traps
+ type: bool
+ state_changes:
+ description: Traps for FSM state changes
+ suboptions:
+ all:
+ description: CISCO specific trap for all fsm state changes
+ type: bool
+ backward_trans:
+ description: CISCO specific trap for backward transition
+ type: bool
+ limited:
+ description: Trap for standard backward transition and established
+ type: bool
+ enable:
+ description: Enable/disable bgp state_changes traps
+ type: bool
+ type: dict
+ threshold:
+ description: Mode threshold
+ suboptions:
+ prefix:
+ description: Enable/disable bgp threshold traps
+ type: bool
+ type: dict
+ type: dict
+ bridge:
+ description: Allow bridge related traps
+ suboptions:
+ newroot:
+ description: Enable SNMP STP Bridge MIB newroot traps
+ type: bool
+ enable:
+ description: Enable/disable bridge traps
+ type: bool
+ topologychange:
+ description: Enable SNMP STP Bridge MIB topologychange traps
+ type: bool
+ type: dict
+ casa:
+ description: Enable SNMP config casa traps
+ type: bool
+ cef:
+ description: Allow cef related traps
+ suboptions:
+ inconsistency:
+ description: Enable SNMP CEF Inconsistency traps
+ type: bool
+ peer_fib_state_change:
+ description: Enable SNMP CEF Peer FIB State change traps
+ type: bool
+ peer_state_change:
+ description: Enable SNMP CEF Peer state change traps
+ type: bool
+ resource_failure:
+ description: Enable SNMP CEF Resource Failure traps
+ type: bool
+ enable:
+ description: Enable/disable cef traps
+ type: bool
+ type: dict
+ cnpd:
+ description: Enable SNMP cnpd traps
+ type: bool
+ config:
+ description: Enable SNMP config traps
+ type: bool
+ config_copy:
+ description: Enable SNMP config copy traps
+ type: bool
+ config_ctid:
+ description: Enable SNMP config ctid traps
+ type: bool
+ cpu:
+ description: Allow CPU related traps
+ suboptions:
+ enable:
+ description: Enable/disable cpu traps
+ type: bool
+ threshold:
+ description: Mode threshold
+ type: bool
+ type: dict
+ dhcp:
+ description: Enable SNMP dhcp traps
+ type: bool
+ dlsw:
+ description: Allow dlsw related traps
+ suboptions:
+ circuit:
+ description: Enable SNMP dlsw circuit traps
+ type: bool
+ enable:
+ description: Enable/disable cef traps
+ type: bool
+ tconn:
+ description: Enable SNMP dlsw peer transport connection traps
+ type: bool
+ type: dict
+ eigrp:
+ description: Enable SNMP eigrp traps
+ type: bool
+ entity:
+ description: Enable SNMP entity traps
+ type: bool
+ energywise:
+ description: Enable SNMP energywise traps
+ type: bool
+ envmon:
+ description: Allow envmon related traps
+ suboptions:
+ fan:
+ description: Enable SNMP envmon fan traps
+ suboptions:
+ shutdown:
+ description: Enable SNMP environmental monitor shutdown traps
+ type: bool
+ enable:
+ description: Enable/disable fan traps
+ type: bool
+ status:
+ description: Enable SNMP environmental status change traps
+ type: bool
+ supply:
+ description: Enable SNMP environmental monitor supply traps
+ type: bool
+ temperature:
+ description: Enable SNMP environmental monitor temperature traps
+ type: bool
+ type: dict
+ shutdown:
+ description: Enable SNMP environmental monitor shutdown traps
+ type: bool
+ status:
+ description: Enable SNMP environmental status change traps
+ type: bool
+ supply:
+ description: Enable SNMP environmental monitor supply traps
+ type: bool
+ temperature:
+ description: Enable SNMP environmental monitor temperature traps
+ type: bool
+ type: dict
+ ethernet:
+ description: Allow ethernet traps
+ suboptions:
+ cfm:
+ description: Enable SNMP Ethernet CFM traps
+ suboptions:
+ alarm:
+ description: Enable SNMP Ethernet CFM fault alarm trap
+ type: bool
+ cc:
+ description: Enable SNMP Ethernet CC trap
+ type: dict
+ suboptions:
+ config:
+ description: Enable SNMP Ethernet CFM configuration error traps
+ type: bool
+ cross_connect:
+ description: Enable SNMP Ethernet CFM cross-connect traps
+ type: bool
+ loop:
+ description: Enable SNMP Ethernet CFM loop traps
+ type: bool
+ mep_down:
+ description: Enable SNMP Ethernet CFM CC Down traps
+ type: bool
+ mep_up:
+ description: Enable SNMP Ethernet CFM CC Up traps
+ type: bool
+ crosscheck:
+ description: Enable SNMP Ethernet CC crosscheck trap
+ type: dict
+ suboptions:
+ mep_missing:
+ description: Enable SNMP Ethernet CC crosscheck missing trap
+ type: bool
+ mep_unknown:
+ description: Enable SNMP Ethernet CC crosscheck unknown traps
+ type: bool
+ service_up:
+ description: Enable SNMP Ethernet CC crosscheck service traps
+ type: bool
+ type: dict
+ evc:
+ description: Enable SNMP Ethernet EVC traps
+ suboptions:
+ create:
+ description: Enable SNMP Ethernet EVC create traps
+ type: bool
+ delete:
+ description: Enable SNMP Ethernet EVC delete traps
+ type: bool
+ status:
+ description: Enable SNMP Ethernet EVC status traps
+ type: bool
+ type: dict
+ type: dict
+ event_manager:
+ description: Enable SNMP event-manager traps
+ type: bool
+ flowmon:
+ description: Enable SNMP flowmon traps
+ type: bool
+ firewall:
+ description: Enable SNMP firewall traps
+ suboptions:
+ enable:
+ description: Enable/disable firewall traps
+ type: bool
+ serverstatus:
+ description: Enable firewall server status change trap
+ type: bool
+ type: dict
+ frame_relay:
+ description: Allow frame-relay traps
+ suboptions:
+ enable:
+ description: Enable/disable frame-relay traps
+ type: bool
+ subif:
+ description: Enable SNMP frame-relay subinterface traps
+ suboptions:
+ count:
+ description: Maximum number of traps sent per interval
+ type: int
+ interval:
+ description: Interval duration in which to limit the number of traps sent
+ type: int
+ enable:
+ description: Enable/disable subif traps
+ type: bool
+ type: dict
+ type: dict
+ fru_ctrl:
+ description: Enable SNMP fru-ctrl traps
+ type: bool
+ hsrp:
+ description: Enable SNMP hsrp traps
+ type: bool
+ ike:
+ description: Allow ike traps
+ suboptions:
+ policy:
+ description: Enable IKE Policy traps
+ suboptions:
+ add:
+ description: Enable IKE Policy add trap
+ type: bool
+ delete:
+ description: Enable IKE Policy delete trap
+ type: bool
+ type: dict
+ tunnel:
+ description: Enable IKE Tunnel traps
+ suboptions:
+ start:
+ description: Enable IKE Tunnel start trap
+ type: bool
+ stop:
+ description: Enable IKE Tunnel stop trap
+ type: bool
+ type: dict
+ type: dict
+ ipmulticast:
+ description: Enable SNMP ip multi cast traps
+ type: bool
+ ipsec:
+ description: Allow ike traps
+ suboptions:
+ cryptomap:
+ description: Enable IPsec Cryptomap traps
+ suboptions:
+ add:
+ description: Enable IPsec Cryptomap add trap
+ type: bool
+ attach:
+ description: Enable IPsec Cryptomap Attach trap
+ type: bool
+ delete:
+ description: Enable IPsec Cryptomap delete trap
+ type: bool
+ detach:
+ description: Enable IPsec Cryptomap Detach trap
+ type: bool
+ type: dict
+ too_many_sas:
+ description: Enable IPsec Tunnel Start trap
+ type: bool
+ tunnel:
+ description: Enable IPsec Tunnel traps
+ suboptions:
+ start:
+ description: Enable IPsec Tunnel start trap
+ type: bool
+ stop:
+ description: Enable IPsec Tunnel stop trap
+ type: bool
+ type: dict
+ type: dict
+ ipsla:
+ description: Enable SNMP ipsla traps
+ type: bool
+ l2tun:
+ description: Allow SNMP l2tun traps
+ suboptions:
+ pseudowire_status:
+ description: Enable BFD pseudo wire status traps
+ type: bool
+ session:
+ description: Enable BFD session traps
+ type: bool
+ type: dict
+ msdp:
+ description: Enable SNMP msdp traps
+ type: bool
+ mvpn:
+ description: Enable SNMP mvpn traps
+ type: bool
+ mpls_vpn:
+ description: Enable SNMP mpls traps
+ type: bool
+ ospf:
+ description: Allow ospf related traps
+ suboptions:
+ cisco_specific:
+ description: Cisco specific traps
+ suboptions:
+ error:
+ description: error traps
+ type: bool
+ lsa:
+ description: Lsa related traps
+ type: bool
+ retransmit:
+ description: Packet retransmit traps
+ type: bool
+ state_change:
+ description: state change traps
+ suboptions:
+ nssa_trans_change:
+ description: Nssa translator state changes
+ type: bool
+ shamlink:
+ description: Config mismatch errors on virtual interfaces
+ suboptions:
+ interface:
+ description: Sham link interface state changes
+ type: bool
+ neighbor:
+ description: Sham link neighbor state changes
+ type: bool
+ type: dict
+ type: dict
+ type: dict
+ error:
+ description: Enable error traps
+ type: bool
+ retransmit:
+ description: Enable/disable ospf retransmit traps
+ type: bool
+ lsa:
+ description: Enable/disable ospf lsa traps
+ type: bool
+ state_change:
+ description: Enable/disable state change traps
+ type: bool
+ type: dict
+ pim:
+ description: Allow PIM traps
+ suboptions:
+ invalid_pim_message:
+ description: Enable invalid pim message trap
+ type: bool
+ neighbor_change:
+ description: Enable neighbor change trap
+ type: bool
+ rp_mapping_change:
+ description: Enable rp mapping change trap
+ type: bool
+ enable:
+ description: Enable/disable PIM traps
+ type: bool
+ type: dict
+ vrfmib:
+ description: Allow vrfmib traps
+ suboptions:
+ vrf_up:
+ description: Enable vrf-up trap
+ type: bool
+ vrf_down:
+ description: Enable vrf-down trap
+ type: bool
+ vnet_trunk_up:
+ description: Enable vnet-trunk-up trap
+ type: bool
+ vnet_trunk_down:
+ description: Enable vnet-trunk-down traps
+ type: bool
+ type: dict
+ pki:
+ description: Enable SNMP pki traps
+ type: bool
+ rsvp:
+ description: Enable SNMP RSVP traps
+ type: bool
+ isis:
+ description: Enable SNMP isis traps
+ type: bool
+ pw_vc:
+ description: Enable SNMP pw vc traps
+ type: bool
+ snmp:
+ description: Enable SNMP traps
+ suboptions:
+ authentication:
+ description: Enable authentication trap
+ type: bool
+ coldstart:
+ description: Enable coldStart trap
+ type: bool
+ linkdown:
+ description: Enable linkDown trap
+ type: bool
+ linkup:
+ description: Enable linkUp trap
+ type: bool
+ warmstart:
+ description: Enable warmStart trap
+ type: bool
+ type: dict
+ syslog:
+ description: Enable SNMP syslog traps
+ type: bool
+ transceiver_all:
+ description: Enable SNMP transceiver traps
+ type: bool
+ tty:
+ description: Enable SNMP tty TCP connection traps
+ type: bool
+ vrrp:
+ description: Enable SNMP vrrp traps
+ type: bool
+ type: dict
+ users:
+ description: Define a user who can access the SNMP engine
+ elements: dict
+ suboptions:
+ acl_v6:
+ description: Access list ipv6 associated
+ type: str
+ acl_v4:
+ description: Access list ipv4 associated
+ type: str
+ authentication:
+ description:
+ - Authentication parameters for the user.
+ - Effects idempotency of module as configuration applied is not reflected
+ in running-config.
+ type: dict
+ suboptions:
+ algorithm:
+ description: Select algorithm for authentication.
+ type: str
+ choices: ["md5", "sha"]
+ password:
+ description:
+ - Authentication password for user.
+ type: str
+ encryption:
+ description:
+ - Encryption parameters for the user.
+ - Effects idempotency of module as configuration applied is not reflected
+ in running-config.
+ type: dict
+ suboptions:
+ priv:
+ description: Select algorithm for encryption.
+ type: str
+ choices: ["3des", "aes", "des"]
+ priv_option:
+ description: Add extra option for specific priv if any.
+ type: str
+ password:
+ description:
+ - Authentication password for user.
+ type: str
+ group:
+ description: SNMP group for the user.
+ type: str
+ remote:
+ description: System where an SNMPv3 user is hosted
+ type: str
+ udp_port:
+ description: UDP port used by the remote SNMP system
+ type: int
+ username:
+ description: SNMP user name
+ type: str
+ version:
+ choices:
+ - v1
+ - v2c
+ - v3
+ description: SNMP security version
+ type: str
+ version_option:
+ choices:
+ - encrypted
+ description: Enable encrypted version option.
+ type: str
+ vrf:
+ description: The remote SNMP entity's VPN Routing instance
+ type: str
+ type: list
+ views:
+ description: Define an SNMPv2 MIB view
+ elements: dict
+ suboptions:
+ excluded:
+ description: MIB family is excluded from the view
+ type: bool
+ family_name:
+ description: MIB view family name
+ type: str
+ included:
+ description: MIB family is included in the view
+ type: bool
+ name:
+ description: Name of the view
+ type: str
+ type: list
+ type: dict
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device by
+ executing the command B(show running-config | include snmp-server).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - parsed
+ - gathered
+ - rendered
+ default: merged
+ description:
+ - The state the configuration should be left in.
+ - Refer to examples for more details.
+ - The states I(replaced) and I(overridden) have identical
+ behaviour for this module.
+ type: str
+short_description: Resource module to configure snmp server.
+version_added: 2.6.0
+"""
+
+EXAMPLES = """
+# Using state: merged
+
+# Before state:
+# -------------
+
+# router-ios#show running-config | section ^snmp-server
+# --------------------- EMPTY -----------------
+
+# Merged play:
+# ------------
+
+- name: Apply the provided configuration
+ cisco.ios.ios_snmp_server:
+ config:
+ communities:
+ - acl_v4: testACL
+ name: mergedComm
+ rw: true
+ contact: contact updated using merged
+ engine_id:
+ - id: AB0C5342FF0F
+ remote:
+ host: 172.16.0.12
+ udp_port: 25
+ groups:
+ - group: mergedGroup
+ version: v3
+ version_option: auth
+ file_transfer:
+ access_group: test
+ protocol:
+ - ftp
+ hosts:
+ - community_string: mergedComm
+ host: 172.16.2.9
+ informs: true
+ traps:
+ - msdp
+ - stun
+ - pki
+ version: 2c
+ - community_string: mergedComm
+ host: 172.16.2.9
+ traps:
+ - slb
+ - pki
+ password_policy:
+ - change: 3
+ digits: 23
+ lower_case: 12
+ max_len: 24
+ policy_name: MergedPolicy
+ special_char: 32
+ upper_case: 12
+ - change: 43
+ min_len: 12
+ policy_name: MergedPolicy2
+ special_char: 22
+ upper_case: 12
+ - change: 11
+ digits: 23
+ max_len: 12
+ min_len: 12
+ policy_name: policy3
+ special_char: 22
+ upper_case: 12
+ traps:
+ cef:
+ enable: true
+ inconsistency: true
+ peer_fib_state_change: true
+ peer_state_change: true
+ resource_failure: true
+ msdp: true
+ ospf:
+ cisco_specific:
+ error: true
+ lsa: true
+ retransmit: true
+ state_change:
+ nssa_trans_change: true
+ shamlink:
+ interface: true
+ neighbor: true
+ error: true
+ lsa: true
+ retransmit: true
+ state_change: true
+ syslog: true
+ tty: true
+ users:
+ - acl_v4: "24"
+ group: dev
+ username: userPaul
+ version: v1
+ state: merged
+
+# Commands Fired:
+# ---------------
+
+# "commands": [
+# "snmp-server contact contact updated using merged",
+# "snmp-server file-transfer access-group test protocol ftp",
+# "snmp-server enable traps msdp",
+# "snmp-server enable traps syslog",
+# "snmp-server enable traps tty",
+# "snmp-server enable traps ospf cisco-specific errors",
+# "snmp-server enable traps ospf cisco-specific retransmit",
+# "snmp-server enable traps ospf cisco-specific lsa",
+# "snmp-server enable traps ospf cisco-specific state-change nssa-trans-change",
+# "snmp-server enable traps ospf cisco-specific state-change shamlink interface",
+# "snmp-server enable traps ospf cisco-specific state-change shamlink neighbor",
+# "snmp-server enable traps ospf errors",
+# "snmp-server enable traps ospf retransmit",
+# "snmp-server enable traps ospf lsa",
+# "snmp-server enable traps ospf state-change",
+# "snmp-server enable traps cef resource-failure peer-state-change peer-fib-state-change inconsistency",
+# "snmp-server host 172.16.2.9 informs version 2c mergedComm msdp stun pki",
+# "snmp-server host 172.16.2.9 mergedComm slb pki",
+# "snmp-server group mergedGroup v3 auth",
+# "snmp-server engineID remote 172.16.0.12 udp-port 25 AB0C5342FF0F",
+# "snmp-server community mergedComm rw testACL",
+# "snmp-server password-policy MergedPolicy define max-len 24 upper-case 12 lower-case 12 special-char 32 digits 23 change 3",
+# "snmp-server password-policy MergedPolicy2 define min-len 12 upper-case 12 special-char 22 change 43",
+# "snmp-server password-policy policy3 define min-len 12 max-len 12 upper-case 12 special-char 22 digits 23 change 11",
+# "snmp-server user userPaul dev v1 access 24"
+# ],
+
+# After state:
+# ------------
+
+# router-ios#show running-config | section ^snmp-server
+# snmp-server engineID remote 172.16.0.12 udp-port 25 AB0C5342FF0F
+# snmp-server user userPaul dev v1 access 24
+# snmp-server group mergedGroup v3 auth
+# snmp-server community mergedComm RW testACL
+# snmp-server contact contact updated using merged
+# snmp-server enable traps tty
+# snmp-server enable traps ospf state-change
+# snmp-server enable traps ospf errors
+# snmp-server enable traps ospf retransmit
+# snmp-server enable traps ospf lsa
+# snmp-server enable traps ospf cisco-specific state-change nssa-trans-change
+# snmp-server enable traps ospf cisco-specific state-change shamlink interface
+# snmp-server enable traps ospf cisco-specific state-change shamlink neighbor
+# snmp-server enable traps ospf cisco-specific errors
+# snmp-server enable traps ospf cisco-specific retransmit
+# snmp-server enable traps ospf cisco-specific lsa
+# snmp-server enable traps cef resource-failure peer-state-change peer-fib-state-change inconsistency
+# snmp-server enable traps msdp
+# snmp-server enable traps syslog
+# snmp-server host 172.16.2.9 informs version 2c mergedComm msdp stun pki
+# snmp-server host 172.16.2.9 mergedComm slb pki
+# snmp-server file-transfer access-group test protocol ftp
+# snmp-server password-policy MergedPolicy define max-len 24 upper-case 12 lower-case 12 special-char 32 digits 23 change 3
+# snmp-server password-policy MergedPolicy2 define min-len 12 upper-case 12 special-char 22 change 43
+# snmp-server password-policy policy3 define min-len 12 max-len 12 upper-case 12 special-char 22 digits 23 change 11
+
+# Using state: deleted
+
+# Before state:
+# -------------
+
+# router-ios#show running-config | section ^snmp-server
+# snmp-server engineID remote 172.16.0.12 udp-port 25 AB0C5342FF0F
+# snmp-server user userPaul dev v1 access 24
+# snmp-server group mergedGroup v3 auth
+# snmp-server community mergedComm RW testACL
+# snmp-server contact contact updated using merged
+# snmp-server enable traps tty
+# snmp-server enable traps ospf state-change
+# snmp-server enable traps ospf errors
+# snmp-server enable traps ospf retransmit
+# snmp-server enable traps ospf lsa
+# snmp-server enable traps ospf cisco-specific state-change nssa-trans-change
+# snmp-server enable traps ospf cisco-specific state-change shamlink interface
+# snmp-server enable traps ospf cisco-specific state-change shamlink neighbor
+# snmp-server enable traps ospf cisco-specific errors
+# snmp-server enable traps ospf cisco-specific retransmit
+# snmp-server enable traps ospf cisco-specific lsa
+# snmp-server enable traps cef resource-failure peer-state-change peer-fib-state-change inconsistency
+# snmp-server enable traps msdp
+# snmp-server enable traps syslog
+# snmp-server host 172.16.2.9 informs version 2c mergedComm msdp stun pki
+# snmp-server host 172.16.2.9 mergedComm slb pki
+# snmp-server file-transfer access-group test protocol ftp
+# snmp-server password-policy MergedPolicy define max-len 24 upper-case 12 lower-case 12 special-char 32 digits 23 change 3
+# snmp-server password-policy MergedPolicy2 define min-len 12 upper-case 12 special-char 22 change 43
+# snmp-server password-policy policy3 define min-len 12 max-len 12 upper-case 12 special-char 22 digits 23 change 11
+
+# Deleted play:
+# -------------
+
+- name: Remove all existing configuration
+ cisco.ios.ios_snmp_server:
+ state: deleted
+
+# Commands Fired:
+# ---------------
+
+# "commands": [
+# "no snmp-server contact contact updated using merged",
+# "no snmp-server file-transfer access-group test protocol ftp",
+# "no snmp-server enable traps msdp",
+# "no snmp-server enable traps syslog",
+# "no snmp-server enable traps tty",
+# "no snmp-server enable traps ospf cisco-specific errors",
+# "no snmp-server enable traps ospf cisco-specific retransmit",
+# "no snmp-server enable traps ospf cisco-specific lsa",
+# "no snmp-server enable traps ospf cisco-specific state-change nssa-trans-change",
+# "no snmp-server enable traps ospf cisco-specific state-change shamlink interface",
+# "no snmp-server enable traps ospf cisco-specific state-change shamlink neighbor",
+# "no snmp-server enable traps ospf errors",
+# "no snmp-server enable traps ospf retransmit",
+# "no snmp-server enable traps ospf lsa",
+# "no snmp-server enable traps ospf state-change",
+# "no snmp-server enable traps cef resource-failure peer-state-change peer-fib-state-change inconsistency",
+# "no snmp-server host 172.16.2.9 informs version 2c mergedComm msdp stun pki",
+# "no snmp-server host 172.16.2.9 mergedComm slb pki",
+# "no snmp-server group mergedGroup v3 auth",
+# "no snmp-server engineID remote 172.16.0.12 udp-port 25 AB0C5342FF0F",
+# "no snmp-server community mergedComm rw testACL",
+# "no snmp-server password-policy MergedPolicy define max-len 24 upper-case 12 lower-case 12 special-char 32 digits 23 change 3",
+# "no snmp-server password-policy MergedPolicy2 define min-len 12 upper-case 12 special-char 22 change 43",
+# "no snmp-server password-policy policy3 define min-len 12 max-len 12 upper-case 12 special-char 22 digits 23 change 11",
+# "no snmp-server user userPaul dev v1 access 24"
+# ],
+
+# After state:
+# ------------
+
+# router-ios#show running-config | section ^snmp-server
+# --------------------- EMPTY -----------------
+
+# Using state: overridden
+
+# Before state:
+# -------------
+
+# router-ios#show running-config | section ^snmp-server
+# snmp-server engineID remote 172.16.0.12 udp-port 25 AB0C5342FF0F
+# snmp-server user userPaul dev v1 access 24
+# snmp-server group mergedGroup v3 auth
+# snmp-server community mergedComm RW testACL
+# snmp-server contact contact updated using merged
+# snmp-server enable traps tty
+# snmp-server enable traps ospf state-change
+# snmp-server enable traps ospf errors
+# snmp-server enable traps ospf retransmit
+# snmp-server enable traps ospf lsa
+# snmp-server enable traps ospf cisco-specific state-change nssa-trans-change
+# snmp-server enable traps ospf cisco-specific state-change shamlink interface
+# snmp-server enable traps ospf cisco-specific state-change shamlink neighbor
+# snmp-server enable traps ospf cisco-specific errors
+# snmp-server enable traps ospf cisco-specific retransmit
+# snmp-server enable traps ospf cisco-specific lsa
+# snmp-server enable traps cef resource-failure peer-state-change peer-fib-state-change inconsistency
+# snmp-server enable traps msdp
+# snmp-server enable traps syslog
+# snmp-server host 172.16.2.9 informs version 2c mergedComm msdp stun pki
+# snmp-server host 172.16.2.9 mergedComm slb pki
+# snmp-server file-transfer access-group test protocol ftp
+# snmp-server password-policy MergedPolicy define max-len 24 upper-case 12 lower-case 12 special-char 32 digits 23 change 3
+# snmp-server password-policy MergedPolicy2 define min-len 12 upper-case 12 special-char 22 change 43
+# snmp-server password-policy policy3 define min-len 12 max-len 12 upper-case 12 special-char 22 digits 23 change 11
+
+# Overridden play:
+# ----------------
+
+- name: Override commands with provided configuration
+ cisco.ios.ios_snmp_server:
+ config:
+ location: "location entry for snmp"
+ packet_size: 500
+ communities:
+ - acl_v4: acl_uq
+ name: communityOverriden
+ rw: true
+ state: overridden
+
+# Commands Fired:
+# ---------------
+# "commands": [
+# "no snmp-server contact contact updated using merged",
+# "no snmp-server file-transfer access-group test protocol ftp",
+# "snmp-server location location entry for snmp",
+# "snmp-server packetsize 500",
+# "no snmp-server enable traps msdp",
+# "no snmp-server enable traps syslog",
+# "no snmp-server enable traps tty",
+# "no snmp-server enable traps ospf cisco-specific errors",
+# "no snmp-server enable traps ospf cisco-specific retransmit",
+# "no snmp-server enable traps ospf cisco-specific lsa",
+# "no snmp-server enable traps ospf cisco-specific state-change nssa-trans-change",
+# "no snmp-server enable traps ospf cisco-specific state-change shamlink interface",
+# "no snmp-server enable traps ospf cisco-specific state-change shamlink neighbor",
+# "no snmp-server enable traps ospf errors",
+# "no snmp-server enable traps ospf retransmit",
+# "no snmp-server enable traps ospf lsa",
+# "no snmp-server enable traps ospf state-change",
+# "no snmp-server enable traps cef resource-failure peer-state-change peer-fib-state-change inconsistency",
+# "no snmp-server host 172.16.2.9 informs version 2c mergedComm msdp stun pki",
+# "no snmp-server host 172.16.2.9 mergedComm slb pki",
+# "no snmp-server group mergedGroup v3 auth",
+# "no snmp-server engineID remote 172.16.0.12 udp-port 25 AB0C5342FF0F",
+# "snmp-server community communityOvverriden rw acl_uq",
+# "no snmp-server community mergedComm rw testACL",
+# "no snmp-server password-policy MergedPolicy define max-len 24 upper-case 12 lower-case 12 special-char 32 digits 23 change 3",
+# "no snmp-server password-policy MergedPolicy2 define min-len 12 upper-case 12 special-char 22 change 43",
+# "no snmp-server password-policy policy3 define min-len 12 max-len 12 upper-case 12 special-char 22 digits 23 change 11",
+# "no snmp-server user userPaul dev v1 access 24"
+# ],
+
+# After state:
+# ------------
+
+# router-ios#show running-config | section ^snmp-server
+# snmp-server community communityOverriden RW acl_uq
+# snmp-server packetsize 500
+# snmp-server location location entry for snmp
+
+# Using state: replaced
+
+# Before state:
+# -------------
+
+# router-ios#show running-config | section ^snmp-server
+# snmp-server community communityOverriden RW acl_uq
+# snmp-server packetsize 500
+# snmp-server location location entry for snmp
+
+# Replaced play:
+# --------------
+
+- name: Replace commands with provided configuration
+ cisco.ios.ios_snmp_server:
+ config:
+ location: "updated location entry"
+ packet_size: 500
+ communities:
+ - acl_v4: acl_uq
+ name: communityOverriden
+ rw: true
+ state: replaced
+
+# Commands Fired:
+# ---------------
+
+# "commands": [
+# "snmp-server location updated location entry"
+# ],
+
+# After state:
+# ------------
+
+# router-ios#show running-config | section ^snmp-server
+# snmp-server community communityOverriden RW acl_uq
+# snmp-server packetsize 500
+# snmp-server location updated location entry
+
+# Using state: gathered
+
+# Before state:
+# -------------
+
+#router-ios#show running-config | section ^snmp-server
+# snmp-server engineID remote 172.16.0.12 udp-port 25 AB0C5342FF0F
+# snmp-server user userPaul dev v1 access 24
+# snmp-server group mergedGroup v3 auth
+# snmp-server community communityOvverriden RW acl_uq
+# snmp-server community mergedComm RW testACL
+# snmp-server packetsize 500
+# snmp-server location updated location entry
+# snmp-server contact contact updated using merged
+# snmp-server enable traps tty
+# snmp-server enable traps ospf state-change
+# snmp-server enable traps ospf errors
+# snmp-server enable traps ospf retransmit
+# snmp-server enable traps ospf lsa
+# snmp-server enable traps ospf cisco-specific state-change nssa-trans-change
+# snmp-server enable traps ospf cisco-specific state-change shamlink interface
+# snmp-server enable traps ospf cisco-specific state-change shamlink neighbor
+# snmp-server enable traps ospf cisco-specific errors
+# snmp-server enable traps ospf cisco-specific retransmit
+# snmp-server enable traps ospf cisco-specific lsa
+# snmp-server enable traps cef resource-failure peer-state-change peer-fib-state-change inconsistency
+# snmp-server enable traps msdp
+# snmp-server enable traps syslog
+# snmp-server host 172.16.2.9 informs version 2c mergedComm msdp stun pki
+# snmp-server host 172.16.2.9 mergedComm slb pki
+# snmp-server file-transfer access-group test protocol ftp
+# snmp-server password-policy MergedPolicy define max-len 24 upper-case 12 lower-case 12 special-char 32 digits 23 change 3
+# snmp-server password-policy MergedPolicy2 define min-len 12 upper-case 12 special-char 22 change 43
+# snmp-server password-policy policy3 define min-len 12 max-len 12 upper-case 12 special-char 22 digits 23 change 11
+
+# Gathered play:
+# --------------
+
+- name: Gather listed snmp config
+ cisco.ios.ios_snmp_server:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+
+# "gathered": {
+# "communities": [
+# {
+# "acl_v4": "acl_uq",
+# "name": "communityOvverriden",
+# "rw": true
+# },
+# {
+# "acl_v4": "testACL",
+# "name": "mergedComm",
+# "rw": true
+# }
+# ],
+# "contact": "contact updated using merged",
+# "engine_id": [
+# {
+# "id": "AB0C5342FF0F",
+# "remote": {
+# "host": "172.16.0.12",
+# "udp_port": 25
+# }
+# }
+# ],
+# "file_transfer": {
+# "access_group": "test",
+# "protocol": [
+# "ftp"
+# ]
+# },
+# "groups": [
+# {
+# "group": "mergedGroup",
+# "version": "v3",
+# "version_option": "auth"
+# }
+# ],
+# "hosts": [
+# {
+# "community_string": "mergedComm",
+# "host": "172.16.2.9",
+# "informs": true,
+# "traps": [
+# "msdp",
+# "stun",
+# "pki"
+# ],
+# "version": "2c"
+# },
+# {
+# "community_string": "mergedComm",
+# "host": "172.16.2.9",
+# "traps": [
+# "slb",
+# "pki"
+# ]
+# }
+# ],
+# "location": "updated location entry",
+# "packet_size": 500,
+# "password_policy": [
+# {
+# "change": 3,
+# "digits": 23,
+# "lower_case": 12,
+# "max_len": 24,
+# "policy_name": "MergedPolicy",
+# "special_char": 32,
+# "upper_case": 12
+# },
+# {
+# "change": 43,
+# "min_len": 12,
+# "policy_name": "MergedPolicy2",
+# "special_char": 22,
+# "upper_case": 12
+# },
+# {
+# "change": 11,
+# "digits": 23,
+# "max_len": 12,
+# "min_len": 12,
+# "policy_name": "policy3",
+# "special_char": 22,
+# "upper_case": 12
+# }
+# ],
+# "traps": {
+# "cef": {
+# "enable": true,
+# "inconsistency": true,
+# "peer_fib_state_change": true,
+# "peer_state_change": true,
+# "resource_failure": true
+# },
+# "msdp": true,
+# "ospf": {
+# "cisco_specific": {
+# "error": true,
+# "lsa": true,
+# "retransmit": true,
+# "state_change": {
+# "nssa_trans_change": true,
+# "shamlink": {
+# "interface": true,
+# "neighbor": true
+# }
+# }
+# },
+# "error": true,
+# "lsa": true,
+# "retransmit": true,
+# "state_change": true
+# },
+# "syslog": true,
+# "tty": true
+# },
+# "users": [
+# {
+# "acl_v4": "24",
+# "group": "dev",
+# "username": "userPaul",
+# "version": "v1"
+# }
+# ]
+# },
+
+# Using state: rendered
+
+# Rendered play:
+# --------------
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_snmp_server:
+ config:
+ accounting:
+ command: default
+ cache: 2
+ chassis_id: entry for chassis id
+ communities:
+ - acl_v6: te
+ name: test
+ ro: true
+ view: terst1
+ - acl_v4: "1322"
+ name: wete
+ ro: true
+ - acl_v4: paul
+ name: weteww
+ rw: true
+ contact: details contact
+ context:
+ - contextA
+ - contextB
+ engine_id:
+ - id: AB0C5342FA0A
+ local: true
+ - id: AB0C5342FAAB
+ remote:
+ host: 172.16.0.2
+ udp_port: 23
+ - id: AB0C5342FAAA
+ remote:
+ host: 172.16.0.1
+ udp_port: 22
+ file_transfer:
+ access_group: testAcl
+ protocol:
+ - ftp
+ - rcp
+ groups:
+ - group: grpFamily
+ version: v3
+ version_option: auth
+ - context: mycontext
+ group: grpFamily
+ version: v1
+ - acl_v4: "2"
+ group: grp1
+ notify: me
+ version: v1
+ - group: newtera
+ version: v3
+ version_option: priv
+ - group: relaplacing
+ version: v3
+ version_option: noauth
+ hosts:
+ - community_string: check
+ host: 172.16.2.99
+ informs: true
+ traps:
+ - msdp
+ - stun
+ version: 2c
+ - community_string: check
+ host: 172.16.2.99
+ traps:
+ - slb
+ - pki
+ - community_string: checktrap
+ host: 172.16.2.99
+ traps:
+ - isis
+ - hsrp
+ - community_string: newtera
+ host: 172.16.2.1
+ traps:
+ - rsrb
+ - pim
+ - rsvp
+ - slb
+ - pki
+ version: "3"
+ version_option: priv
+ - community_string: relaplacing
+ host: 172.16.2.1
+ traps:
+ - slb
+ - pki
+ version: "3"
+ version_option: noauth
+ - community_string: trapsac
+ host: 172.16.2.1
+ traps:
+ - tty
+ - bgp
+ version: 2c
+ - community_string: www
+ host: 172.16.1.1
+ traps:
+ - tty
+ - bgp
+ version: "3"
+ version_option: auth
+ inform:
+ pending: 2
+ ip:
+ dscp: 2
+ location: "entry for snmp location"
+ packet_size: 500
+ password_policy:
+ - change: 3
+ digits: 23
+ lower_case: 12
+ max_len: 24
+ policy_name: policy1
+ special_char: 32
+ upper_case: 12
+ - change: 9
+ min_len: 12
+ policy_name: policy2
+ special_char: 22
+ upper_case: 12
+ - change: 11
+ digits: 23
+ max_len: 12
+ min_len: 12
+ policy_name: policy3
+ special_char: 22
+ upper_case: 12
+ queue_length: 2
+ source_interface: Loopback999
+ system_shutdown: true
+ trap_source: GigabitEthernet0/0
+ trap_timeout: 2
+ traps:
+ auth_framework:
+ enable: true
+ bgp:
+ cbgp2: true
+ enable: true
+ bfd:
+ enable: true
+ session_down: true
+ session_up: true
+ bridge:
+ enable: true
+ newroot: true
+ topologychange: true
+ casa: true
+ cef:
+ enable: true
+ inconsistency: true
+ peer_fib_state_change: true
+ peer_state_change: true
+ resource_failure: true
+ dlsw:
+ enable: true
+ eigrp: true
+ ethernet:
+ cfm:
+ alarm: true
+ evc:
+ status: true
+ event_manager: true
+ flowmon: true
+ frame_relay:
+ enable: true
+ subif:
+ enable: true
+ hsrp: true
+ ike:
+ policy:
+ add: true
+ delete: true
+ tunnel:
+ start: true
+ stop: true
+ ipmulticast: true
+ ipsec:
+ cryptomap:
+ add: true
+ attach: true
+ delete: true
+ detach: true
+ too_many_sas: true
+ tunnel:
+ start: true
+ stop: true
+ ipsla: true
+ l2tun:
+ pseudowire_status: true
+ session: true
+ msdp: true
+ ospf:
+ cisco_specific:
+ error: true
+ lsa: true
+ retransmit: true
+ state_change:
+ nssa_trans_change: true
+ shamlink:
+ interface: true
+ neighbor: true
+ error: true
+ lsa: true
+ retransmit: true
+ state_change: true
+ pim:
+ enable: true
+ invalid_pim_message: true
+ neighbor_change: true
+ rp_mapping_change: true
+ pki: true
+ rsvp: true
+ snmp:
+ authentication: true
+ coldstart: true
+ linkdown: true
+ linkup: true
+ warmstart: true
+ syslog: true
+ tty: true
+ users:
+ - acl_v4: "24"
+ group: groupFamily
+ username: paul
+ version: v1
+ - acl_v4: ipv6
+ group: groupFamily
+ username: domnic
+ version: v3
+ - group: relaplacing
+ username: relaplacing
+ version: v3
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+
+# "rendered": [
+# "snmp-server accounting commands default",
+# "snmp-server cache interval 2",
+# "snmp-server chassis-id entry for chassis id",
+# "snmp-server contact details contact",
+# "snmp-server file-transfer access-group testAcl protocol ftp rcp",
+# "snmp-server inform pending 2",
+# "snmp-server ip dscp 2",
+# "snmp-server location entry for snmp location",
+# "snmp-server packetsize 500",
+# "snmp-server queue-length 2",
+# "snmp-server trap timeout 2",
+# "snmp-server source-interface informs Loopback999",
+# "snmp-server trap-source GigabitEthernet0/0",
+# "snmp-server system-shutdown",
+# "snmp-server enable traps auth-framework",
+# "snmp-server enable traps bfd session-down session-up",
+# "snmp-server enable traps bgp cbgp2",
+# "snmp-server enable traps bridge newroot topologychange",
+# "snmp-server enable traps casa",
+# "snmp-server enable traps eigrp",
+# "snmp-server enable traps event-manager",
+# "snmp-server enable traps flowmon",
+# "snmp-server enable traps hsrp",
+# "snmp-server enable traps ipsla",
+# "snmp-server enable traps msdp",
+# "snmp-server enable traps pki",
+# "snmp-server enable traps rsvp",
+# "snmp-server enable traps syslog",
+# "snmp-server enable traps tty",
+# "snmp-server enable traps ipmulticast",
+# "snmp-server enable traps ike policy add",
+# "snmp-server enable traps ike policy delete",
+# "snmp-server enable traps ike tunnel start",
+# "snmp-server enable traps ike tunnel stop",
+# "snmp-server enable traps ipsec cryptomap add",
+# "snmp-server enable traps ipsec cryptomap delete",
+# "snmp-server enable traps ipsec cryptomap attach",
+# "snmp-server enable traps ipsec cryptomap detach",
+# "snmp-server enable traps ipsec tunnel start",
+# "snmp-server enable traps ipsec tunnel stop",
+# "snmp-server enable traps ipsec too-many-sas",
+# "snmp-server enable traps ospf cisco-specific errors",
+# "snmp-server enable traps ospf cisco-specific retransmit",
+# "snmp-server enable traps ospf cisco-specific lsa",
+# "snmp-server enable traps ospf cisco-specific state-change nssa-trans-change",
+# "snmp-server enable traps ospf cisco-specific state-change shamlink interface",
+# "snmp-server enable traps ospf cisco-specific state-change shamlink neighbor",
+# "snmp-server enable traps ospf errors",
+# "snmp-server enable traps ospf retransmit",
+# "snmp-server enable traps ospf lsa",
+# "snmp-server enable traps ospf state-change",
+# "snmp-server enable traps l2tun pseudowire status",
+# "snmp-server enable traps l2tun session",
+# "snmp-server enable traps pim neighbor-change rp-mapping-change invalid-pim-message",
+# "snmp-server enable traps snmp authentication linkdown linkup warmstart coldstart",
+# "snmp-server enable traps frame-relay",
+# "snmp-server enable traps cef resource-failure peer-state-change peer-fib-state-change inconsistency",
+# "snmp-server enable traps dlsw",
+# "snmp-server enable traps ethernet evc status",
+# "snmp-server enable traps ethernet cfm alarm",
+# "snmp-server host 172.16.2.99 informs version 2c check msdp stun",
+# "snmp-server host 172.16.2.99 check slb pki",
+# "snmp-server host 172.16.2.99 checktrap isis hsrp",
+# "snmp-server host 172.16.2.1 version 3 priv newtera rsrb pim rsvp slb pki",
+# "snmp-server host 172.16.2.1 version 3 noauth relaplacing slb pki",
+# "snmp-server host 172.16.2.1 version 2c trapsac tty bgp",
+# "snmp-server host 172.16.1.1 version 3 auth www tty bgp",
+# "snmp-server group grpFamily v1 context mycontext",
+# "snmp-server group grp1 v1 notify me access 2",
+# "snmp-server group newtera v3 priv",
+# "snmp-server group relaplacing v3 noauth",
+# "snmp-server engineID local AB0C5342FA0A",
+# "snmp-server engineID remote 172.16.0.2 udp-port 23 AB0C5342FAAB",
+# "snmp-server engineID remote 172.16.0.1 udp-port 22 AB0C5342FAAA",
+# "snmp-server community test view terst1 ro ipv6 te",
+# "snmp-server community wete ro 1322",
+# "snmp-server community weteww rw paul",
+# "snmp-server context contextA",
+# "snmp-server context contextB",
+# "snmp-server password-policy policy1 define max-len 24 upper-case 12 lower-case 12 special-char 32 digits 23 change 3",
+# "snmp-server password-policy policy2 define min-len 12 upper-case 12 special-char 22 change 9",
+# "snmp-server password-policy policy3 define min-len 12 max-len 12 upper-case 12 special-char 22 digits 23 change 11",
+# "snmp-server user paul groupFamily v1 access 24",
+# "snmp-server user domnic groupFamily v3 access ipv6",
+# "snmp-server user relaplacing relaplacing v3"
+# ]
+
+# Using state: parsed
+
+# File: parsed.cfg
+# ----------------
+
+# snmp-server engineID local AB0C5342FA0A
+# snmp-server engineID remote 172.16.0.2 udp-port 23 AB0C5342FAAB
+# snmp-server engineID remote 172.16.0.1 udp-port 22 AB0C5342FAAA
+# snmp-server user newuser newfamily v1 access 24
+# snmp-server user paul familypaul v3 access ipv6 ipv6acl
+# snmp-server user replaceUser replaceUser v3
+# snmp-server group group0 v3 auth
+# snmp-server group group1 v1 notify me access 2
+# snmp-server group group2 v3 priv
+# snmp-server group replaceUser v3 noauth
+# snmp-server community commu1 view view1 RO ipv6 te
+# snmp-server community commu2 RO 1322
+# snmp-server community commu3 RW paul
+# snmp-server trap timeout 2
+# snmp-server trap-source GigabitEthernet0/0
+# snmp-server source-interface informs Loopback999
+# snmp-server packetsize 500
+# snmp-server enable traps vrfmib vrf-up vrf-down vnet-trunk-up vnet-trunk-down
+# snmp-server host 172.16.2.99 informs version 2c check msdp stun
+# snmp-server host 172.16.2.1 version 2c trapsac tty bgp
+# snmp-server host 172.16.1.1 version 3 auth group0 tty bgp
+# snmp-server context contextWord1
+# snmp-server context contextWord2
+# snmp-server file-transfer access-group testAcl protocol ftp
+# snmp-server file-transfer access-group testAcl protocol rcp
+# snmp-server cache interval 2
+# snmp-server password-policy policy2 define min-len 12 upper-case 12 special-char 22 change 9
+# snmp-server password-policy policy3 define min-len 12 max-len 12 upper-case 12 special-char 22 digits 23 change 11
+# snmp-server accounting commands default
+# snmp-server inform pending 2
+
+# Parsed play:
+# ------------
+
+- name: Parse the provided configuration with the existing running configuration
+ cisco.ios.ios_snmp_server:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": {
+# "accounting": {
+# "command": "default"
+# },
+# "cache": 2,
+# "communities": [
+# {
+# "acl_v6": "te",
+# "name": "commu1",
+# "ro": true,
+# "view": "view1"
+# },
+# {
+# "acl_v4": "1322",
+# "name": "commu2",
+# "ro": true
+# },
+# {
+# "acl_v4": "paul",
+# "name": "commu3",
+# "rw": true
+# }
+# ],
+# "context": [
+# "contextWord1",
+# "contextWord2"
+# ],
+# "engine_id": [
+# {
+# "id": "AB0C5342FA0A",
+# "local": true
+# },
+# {
+# "id": "AB0C5342FAAA",
+# "remote": {
+# "host": "172.16.0.1",
+# "udp_port": 22
+# }
+# },
+# {
+# "id": "AB0C5342FAAB",
+# "remote": {
+# "host": "172.16.0.2",
+# "udp_port": 23
+# }
+# }
+# ],
+# "file_transfer": {
+# "access_group": "testAcl",
+# "protocol": [
+# "rcp",
+# "ftp"
+# ]
+# },
+# "groups": [
+# {
+# "group": "group0",
+# "version": "v3",
+# "version_option": "auth"
+# },
+# {
+# "acl_v4": "2",
+# "group": "group1",
+# "notify": "me",
+# "version": "v1"
+# },
+# {
+# "group": "group2",
+# "version": "v3",
+# "version_option": "priv"
+# },
+# {
+# "group": "replaceUser",
+# "version": "v3",
+# "version_option": "noauth"
+# }
+# ],
+# "hosts": [
+# {
+# "community_string": "group0",
+# "host": "172.16.1.1",
+# "traps": [
+# "tty",
+# "bgp"
+# ],
+# "version": "3",
+# "version_option": "auth"
+# },
+# {
+# "community_string": "trapsac",
+# "host": "172.16.2.1",
+# "traps": [
+# "tty",
+# "bgp"
+# ],
+# "version": "2c"
+# },
+# {
+# "community_string": "check",
+# "host": "172.16.2.99",
+# "informs": true,
+# "traps": [
+# "msdp",
+# "stun"
+# ],
+# "version": "2c"
+# }
+# ],
+# "inform": {
+# "pending": 2
+# },
+# "packet_size": 500,
+# "password_policy": [
+# {
+# "change": 9,
+# "min_len": 12,
+# "policy_name": "policy2",
+# "special_char": 22,
+# "upper_case": 12
+# },
+# {
+# "change": 11,
+# "digits": 23,
+# "max_len": 12,
+# "min_len": 12,
+# "policy_name": "policy3",
+# "special_char": 22,
+# "upper_case": 12
+# }
+# ],
+# "source_interface": "Loopback999",
+# "trap_source": "GigabitEthernet0/0",
+# "trap_timeout": 2,
+# "traps": {
+# "vrfmib": {
+# "vnet_trunk_down": true,
+# "vnet_trunk_up": true,
+# "vrf_down": true,
+# "vrf_up": true
+# }
+# },
+# "users": [
+# {
+# "acl_v4": "24",
+# "group": "newfamily",
+# "username": "newuser",
+# "version": "v1"
+# },
+# {
+# "acl_v4": "ipv6",
+# "group": "familypaul",
+# "username": "paul",
+# "version": "v3"
+# },
+# {
+# "group": "replaceUser",
+# "username": "replaceUser",
+# "version": "v3"
+# }
+# ]
+# }
+
+"""
+
+RETURN = """
+before:
+ description: The configuration prior to the module execution.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+after:
+ description: The resulting configuration after module execution.
+ returned: when changed
+ type: dict
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged)
+ type: list
+ sample:
+ - snmp-server host 172.16.2.99 informs version 2c check msdp stun
+ - snmp-server engineID remote 172.16.0.2 udp-port 23 AB0C5342FAAB
+ - snmp-server group grp1 v1 notify me access 2
+rendered:
+ description: The provided configuration in the task rendered in device-native format (offline).
+ returned: when I(state) is C(rendered)
+ type: list
+ sample:
+ - snmp-server enable traps ipsec cryptomap attach
+ - snmp-server password-policy policy1 define max-len 24 upper-case 12 lower-case 12 special-char 32 digits 23 change 3
+ - snmp-server cache interval 2
+gathered:
+ description: Facts about the network resource gathered from the remote device as structured data.
+ returned: when I(state) is C(gathered)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+parsed:
+ description: The device native config provided in I(running_config) option parsed into structured data as per module argspec.
+ returned: when I(state) is C(parsed)
+ type: list
+ sample: >
+ This output will always be in the same format as the
+ module argspec.
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.snmp_server.snmp_server import (
+ Snmp_serverArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.snmp_server.snmp_server import (
+ Snmp_server,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ module = AnsibleModule(
+ argument_spec=Snmp_serverArgs.argument_spec,
+ mutually_exclusive=[["config", "running_config"]],
+ required_if=[
+ ["state", "merged", ["config"]],
+ ["state", "replaced", ["config"]],
+ ["state", "overridden", ["config"]],
+ ["state", "rendered", ["config"]],
+ ["state", "parsed", ["running_config"]],
+ ],
+ supports_check_mode=True,
+ )
+
+ result = Snmp_server(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_static_routes.py b/ansible_collections/cisco/ios/plugins/modules/ios_static_routes.py
new file mode 100644
index 000000000..ffa7290e4
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_static_routes.py
@@ -0,0 +1,1014 @@
+#!/usr/bin/python
+# -*- 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)
+
+"""
+The module file for ios_static_routes
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_static_routes
+short_description: Resource module to configure static routes.
+description: This module configures and manages the static routes on IOS platforms.
+version_added: 1.0.0
+author:
+ - Sagar Paul (@KB-perByte)
+ - Sumit Jaiswal (@justjais)
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+ - The module examples uses callback plugin (stdout_callback = yaml) to generate task
+ output in yaml format.
+options:
+ config:
+ description: A dictionary of static route options
+ type: list
+ elements: dict
+ suboptions:
+ vrf:
+ description:
+ - IP VPN Routing/Forwarding instance name.
+ - NOTE, In case of IPV4/IPV6 VRF routing table should pre-exist before configuring.
+ - NOTE, if the vrf information is not provided then the routes shall be configured
+ under global vrf.
+ type: str
+ address_families:
+ elements: dict
+ description:
+ - Address family to use for the static routes
+ type: list
+ suboptions:
+ afi:
+ description:
+ - Top level address family indicator.
+ required: true
+ type: str
+ choices:
+ - ipv4
+ - ipv6
+ routes:
+ description: Configuring static route
+ type: list
+ elements: dict
+ suboptions:
+ dest:
+ description: Destination prefix with its subnet mask
+ type: str
+ required: true
+ topology:
+ description:
+ - Configure static route for a Topology Routing/Forwarding instance
+ - NOTE, VRF and Topology can be used together only with Multicast
+ and Topology should pre-exist before it can be used
+ type: str
+ next_hops:
+ description:
+ - next hop address or interface
+ type: list
+ elements: dict
+ suboptions:
+ forward_router_address:
+ description: Forwarding router's address
+ type: str
+ interface:
+ description: Interface for directly connected static routes
+ type: str
+ dhcp:
+ description: Default gateway obtained from DHCP
+ type: bool
+ distance_metric:
+ description: Distance metric for this route
+ type: int
+ global:
+ description: Next hop address is global
+ type: bool
+ name:
+ description: Specify name of the next hop
+ type: str
+ multicast:
+ description: multicast route
+ type: bool
+ unicast:
+ description: unicast route (ipv6 specific)
+ type: bool
+ permanent:
+ description: permanent route
+ type: bool
+ tag:
+ description:
+ - Set tag for this route
+ - Refer to vendor documentation for valid values.
+ type: int
+ track:
+ description:
+ - Install route depending on tracked item with tracked object
+ number.
+ - Tracking does not support multicast
+ - Refer to vendor documentation for valid values.
+ type: int
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS
+ device by executing the command B(show running-config | include ip route|ipv6 route).
+ - The state I(parsed) reads the configuration from C(running_config)
+ option and transforms it into Ansible structured data as per the
+ resource module's argspec and the value is then returned in the
+ I(parsed) key within the result.
+ type: str
+ state:
+ description:
+ - The state the configuration should be left in
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device.
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result. For state I(rendered) active connection to remote host is
+ not required.
+ - The state I(gathered) will fetch the running configuration from device and transform
+ it into structured data in the format as per the resource module argspec and
+ the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result. The value of C(running_config)
+ option should be the same format as the output of command I(show running-config
+ | include ip route|ipv6 route) executed on device. For state I(parsed) active
+ connection to remote host is not required.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - gathered
+ - rendered
+ - parsed
+ default: merged
+"""
+
+EXAMPLES = """
+# Using merged
+
+# Before state:
+# -------------
+#
+# vios#show running-config | include ip route|ipv6 route
+
+- name: Merge provided configuration with device configuration
+ cisco.ios.ios_static_routes:
+ config:
+ - vrf: blue
+ address_families:
+ - afi: ipv4
+ routes:
+ - dest: 192.0.2.0/24
+ next_hops:
+ - forward_router_address: 192.0.2.1
+ name: merged_blue
+ tag: 50
+ track: 150
+ - address_families:
+ - afi: ipv4
+ routes:
+ - dest: 198.51.100.0/24
+ next_hops:
+ - forward_router_address: 198.51.101.1
+ name: merged_route_1
+ distance_metric: 110
+ tag: 40
+ multicast: true
+ - forward_router_address: 198.51.101.2
+ name: merged_route_2
+ distance_metric: 30
+ - forward_router_address: 198.51.101.3
+ name: merged_route_3
+ - afi: ipv6
+ routes:
+ - dest: 2001:DB8:0:3::/64
+ next_hops:
+ - forward_router_address: 2001:DB8:0:3::2
+ name: merged_v6
+ tag: 105
+ state: merged
+
+# Task Output
+# -----------
+#
+# before:
+# - {}
+# commands:
+# - ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name merged_v6
+# - ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 tag 40 name merged_route_1 multicast
+# - ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name merged_route_2
+# - ip route 198.51.100.0 255.255.255.0 198.51.101.3 name merged_route_3
+# - ip route vrf blue 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name merged_blue track 150
+# after:
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 198.51.100.0/24
+# next_hops:
+# - forward_router_address: 198.51.101.3
+# name: merged_route_3
+# - distance_metric: 30
+# forward_router_address: 198.51.101.2
+# name: merged_route_2
+# - distance_metric: 110
+# forward_router_address: 198.51.101.1
+# multicast: true
+# name: merged_route_1
+# tag: 40
+# - afi: ipv6
+# routes:
+# - dest: 2001:DB8:0:3::/64
+# next_hops:
+# - forward_router_address: 2001:DB8:0:3::2
+# name: merged_v6
+# tag: 105
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 192.0.2.0/24
+# next_hops:
+# - forward_router_address: 192.0.2.1
+# name: merged_blue
+# tag: 50
+# track: 150
+# vrf: blue
+
+# After state:
+# ------------
+#
+# vios#show running-config | include ip route|ipv6 route
+# ip route vrf blue 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name merged_blue track 150
+# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name merged_route_3
+# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name merged_route_2
+# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 tag 40 name merged_route_1 multicast
+# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name merged_v6
+
+# Using replaced
+
+# Before state:
+# -------------
+#
+# vios#show running-config | include ip route|ipv6 route
+# ip route vrf blue 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name merged_blue track 150
+# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name merged_route_3
+# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name merged_route_2
+# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 tag 40 name merged_route_1 multicast
+# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name merged_v6
+
+- name: Replace provided configuration with device configuration
+ cisco.ios.ios_static_routes:
+ config:
+ - address_families:
+ - afi: ipv4
+ routes:
+ - dest: 198.51.100.0/24
+ next_hops:
+ - forward_router_address: 198.51.101.1
+ name: replaced_route
+ distance_metric: 175
+ tag: 70
+ multicast: true
+ state: replaced
+
+# Task Output
+# -----------
+#
+# before:
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 198.51.100.0/24
+# next_hops:
+# - forward_router_address: 198.51.101.3
+# name: merged_route_3
+# - distance_metric: 30
+# forward_router_address: 198.51.101.2
+# name: merged_route_2
+# - distance_metric: 110
+# forward_router_address: 198.51.101.1
+# multicast: true
+# name: merged_route_1
+# tag: 40
+# - afi: ipv6
+# routes:
+# - dest: 2001:DB8:0:3::/64
+# next_hops:
+# - forward_router_address: 2001:DB8:0:3::2
+# name: merged_v6
+# tag: 105
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 192.0.2.0/24
+# next_hops:
+# - forward_router_address: 192.0.2.1
+# name: merged_blue
+# tag: 50
+# track: 150
+# vrf: blue
+# commands:
+# - ip route 198.51.100.0 255.255.255.0 198.51.101.1 175 tag 70 name replaced_route multicast
+# - no ip route 198.51.100.0 255.255.255.0 198.51.101.3 name merged_route_3
+# - no ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name merged_route_2
+# after:
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 198.51.100.0/24
+# next_hops:
+# - distance_metric: 175
+# forward_router_address: 198.51.101.1
+# multicast: true
+# name: replaced_route
+# tag: 70
+# - afi: ipv6
+# routes:
+# - dest: 2001:DB8:0:3::/64
+# next_hops:
+# - forward_router_address: 2001:DB8:0:3::2
+# name: merged_v6
+# tag: 105
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 192.0.2.0/24
+# next_hops:
+# - forward_router_address: 192.0.2.1
+# name: merged_blue
+# tag: 50
+# track: 150
+# vrf: blue
+
+# After state:
+# ------------
+#
+# vios#show running-config | include ip route|ipv6 route
+# ip route vrf blue 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name merged_blue track 150
+# ip route 198.51.100.0 255.255.255.0 198.51.101.1 175 tag 70 name replaced_route multicast
+# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name merged_v6
+
+# Using overridden
+
+# Before state:
+# -------------
+#
+# vios#show running-config | include ip route|ipv6 route
+# ip route vrf blue 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name merged_blue track 150
+# ip route 198.51.100.0 255.255.255.0 198.51.101.1 175 tag 70 name replaced_route multicast
+# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name merged_v6
+
+- name: Override provided configuration with device configuration
+ cisco.ios.ios_static_routes:
+ config:
+ - vrf: blue
+ address_families:
+ - afi: ipv4
+ routes:
+ - dest: 192.0.2.0/24
+ next_hops:
+ - forward_router_address: 192.0.2.1
+ name: override_vrf
+ tag: 50
+ track: 150
+ state: overridden
+
+# Task Output
+# -----------
+#
+# before:
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 198.51.100.0/24
+# next_hops:
+# - distance_metric: 175
+# forward_router_address: 198.51.101.1
+# multicast: true
+# name: replaced_route
+# tag: 70
+# - afi: ipv6
+# routes:
+# - dest: 2001:DB8:0:3::/64
+# next_hops:
+# - forward_router_address: 2001:DB8:0:3::2
+# name: merged_v6
+# tag: 105
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 192.0.2.0/24
+# next_hops:
+# - forward_router_address: 192.0.2.1
+# name: merged_blue
+# tag: 50
+# track: 150
+# vrf: blue
+# commands:
+# - ip route vrf blue 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name override_vrf track 150
+# - no ip route 198.51.100.0 255.255.255.0 198.51.101.1 175 tag 70 name replaced_route multicast
+# - no ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name merged_v6
+# after:
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 192.0.2.0/24
+# next_hops:
+# - forward_router_address: 192.0.2.1
+# name: override_vrf
+# tag: 50
+# track: 150
+# vrf: blue
+
+# After state:
+# ------------
+#
+# vios#show running-config | include ip route|ipv6 route
+# ip route vrf blue 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name override_vrf track 150
+
+# Using deleted
+
+# Before state:
+# -------------
+# vios#show running-config | include ip route|ipv6 route
+# ip route vrf blue 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name test_vrf track 150
+# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
+# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
+# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 tag 40 name route_1 multicast
+# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name test_v6
+
+- name: Delete the exact static routes, with all the static routes explicitly mentioned in want
+ cisco.ios.ios_static_routes:
+ config:
+ - vrf: blue
+ address_families:
+ - afi: ipv4
+ routes:
+ - dest: 192.0.2.0/24
+ next_hops:
+ - forward_router_address: 192.0.2.1
+ name: test_vrf
+ tag: 50
+ track: 150
+ - address_families:
+ - afi: ipv4
+ routes:
+ - dest: 198.51.100.0/24
+ next_hops:
+ - forward_router_address: 198.51.101.1
+ name: route_1
+ distance_metric: 110
+ tag: 40
+ multicast: true
+ - forward_router_address: 198.51.101.2
+ name: route_2
+ distance_metric: 30
+ - forward_router_address: 198.51.101.3
+ name: route_3
+ - afi: ipv6
+ routes:
+ - dest: 2001:DB8:0:3::/64
+ next_hops:
+ - forward_router_address: 2001:DB8:0:3::2
+ name: test_v6
+ tag: 105
+ state: deleted
+
+# Task Output
+# -----------
+#
+# before:
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 198.51.100.0/24
+# next_hops:
+# - forward_router_address: 198.51.101.3
+# name: route_3
+# - distance_metric: 30
+# forward_router_address: 198.51.101.2
+# name: route_2
+# - distance_metric: 110
+# forward_router_address: 198.51.101.1
+# multicast: true
+# name: route_1
+# tag: 40
+# - afi: ipv6
+# routes:
+# - dest: 2001:DB8:0:3::/64
+# next_hops:
+# - forward_router_address: 2001:DB8:0:3::2
+# name: test_v6
+# tag: 105
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 192.0.2.0/24
+# next_hops:
+# - forward_router_address: 192.0.2.1
+# name: test_vrf
+# tag: 50
+# track: 150
+# vrf: blue
+# commands:
+# - no ip route vrf blue 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name test_vrf track 150
+# - no ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
+# - no ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
+# - no ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 tag 40 name route_1 multicast
+# - no ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name test_v6
+# after: {}
+
+# After state:
+# ------------
+#
+# vios#show running-config | include ip route|ipv6 route
+
+# Using deleted - delete based on specific routes
+
+# Before state:
+# -------------
+#
+# vios#show running-config | include ip route|ipv6 route
+# ip route vrf blue 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name test_vrf track 150
+# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
+# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
+# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 tag 40 name route_1 multicast
+# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name test_v6
+
+- name: Delete destination specific static routes
+ cisco.ios.ios_static_routes:
+ config:
+ - address_families:
+ - afi: ipv4
+ routes:
+ - dest: 198.51.100.0/24
+ state: deleted
+
+# Task Output
+# -----------
+#
+# before:
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 198.51.100.0/24
+# next_hops:
+# - forward_router_address: 198.51.101.3
+# name: route_3
+# - distance_metric: 30
+# forward_router_address: 198.51.101.2
+# name: route_2
+# - distance_metric: 110
+# forward_router_address: 198.51.101.1
+# multicast: true
+# name: route_1
+# tag: 40
+# - afi: ipv6
+# routes:
+# - dest: 2001:DB8:0:3::/64
+# next_hops:
+# - forward_router_address: 2001:DB8:0:3::2
+# name: test_v6
+# tag: 105
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 192.0.2.0/24
+# next_hops:
+# - forward_router_address: 192.0.2.1
+# name: test_vrf
+# tag: 50
+# track: 150
+# vrf: blue
+# commands:
+# - no ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
+# - no ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
+# - no ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 tag 40 name route_1 multicast
+# after:
+# - address_families:
+# - afi: ipv6
+# routes:
+# - dest: 2001:DB8:0:3::/64
+# next_hops:
+# - forward_router_address: 2001:DB8:0:3::2
+# name: test_v6
+# tag: 105
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 192.0.2.0/24
+# next_hops:
+# - forward_router_address: 192.0.2.1
+# name: test_vrf
+# tag: 50
+# track: 150
+# vrf: blue
+
+# After state:
+# ------------
+#
+# vios#show running-config | include ip route|ipv6 route
+# ip route vrf blue 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name test_vrf track 150
+# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name test_v6
+
+# Using deleted - delete based on vrfs
+
+# Before state:
+# -------------
+#
+# vios#show running-config | include ip route|ipv6 route
+# ip route vrf blue 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name test_vrf track 150
+# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
+# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
+# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 tag 40 name route_1 multicast
+# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name test_v6
+
+- name: Delete vrf specific static routes
+ cisco.ios.ios_static_routes:
+ config:
+ - vrf: blue
+ state: deleted
+
+# Task Output
+# -----------
+#
+# before:
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 198.51.100.0/24
+# next_hops:
+# - forward_router_address: 198.51.101.3
+# name: route_3
+# - distance_metric: 30
+# forward_router_address: 198.51.101.2
+# name: route_2
+# - distance_metric: 110
+# forward_router_address: 198.51.101.1
+# multicast: true
+# name: route_1
+# tag: 40
+# - afi: ipv6
+# routes:
+# - dest: 2001:DB8:0:3::/64
+# next_hops:
+# - forward_router_address: 2001:DB8:0:3::2
+# name: test_v6
+# tag: 105
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 192.0.2.0/24
+# next_hops:
+# - forward_router_address: 192.0.2.1
+# name: test_vrf
+# tag: 50
+# track: 150
+# vrf: blue
+# commands:
+# - no ip route vrf blue 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name test_vrf track 150
+# after:
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 198.51.100.0/24
+# next_hops:
+# - forward_router_address: 198.51.101.3
+# name: route_3
+# - distance_metric: 30
+# forward_router_address: 198.51.101.2
+# name: route_2
+# - distance_metric: 110
+# forward_router_address: 198.51.101.1
+# multicast: true
+# name: route_1
+# tag: 40
+# - afi: ipv6
+# routes:
+# - dest: 2001:DB8:0:3::/64
+# next_hops:
+# - forward_router_address: 2001:DB8:0:3::2
+# name: test_v6
+# tag: 105
+
+# After state:
+# ------------
+#
+# vios#show running-config | include ip route|ipv6 route
+# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
+# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
+# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 tag 40 name route_1 multicast
+# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name test_v6
+
+# Using deleted - delete all
+
+# Before state:
+# -------------
+#
+# vios#show running-config | include ip route|ipv6 route
+# ip route vrf blue 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name test_vrf track 150
+# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
+# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
+# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 tag 40 name route_1 multicast
+# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name test_v6
+
+- name: Delete ALL configured static routes
+ cisco.ios.ios_static_routes:
+ state: deleted
+
+# Task Output
+# -----------
+#
+# before:
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 198.51.100.0/24
+# next_hops:
+# - forward_router_address: 198.51.101.3
+# name: route_3
+# - distance_metric: 30
+# forward_router_address: 198.51.101.2
+# name: route_2
+# - distance_metric: 110
+# forward_router_address: 198.51.101.1
+# multicast: true
+# name: route_1
+# tag: 40
+# - afi: ipv6
+# routes:
+# - dest: 2001:DB8:0:3::/64
+# next_hops:
+# - forward_router_address: 2001:DB8:0:3::2
+# name: test_v6
+# tag: 105
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 192.0.2.0/24
+# next_hops:
+# - forward_router_address: 192.0.2.1
+# name: test_vrf
+# tag: 50
+# track: 150
+# vrf: blue
+# commands:
+# - no ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
+# - no ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
+# - no ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 tag 40 name route_1 multicast
+# - no ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name test_v6
+# - no ip route vrf blue 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name test_vrf track 150
+# after: {}
+
+# After state:
+# -------------
+#
+# vios#show running-config | include ip route|ipv6 route
+
+# Using gathered
+
+# Before state:
+# -------------
+#
+# vios#show running-config | include ip route|ipv6 route
+# ip route vrf blue 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name test_vrf track 150
+# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
+# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
+# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 tag 40 name route_1 multicast
+# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name test_v6
+
+- name: Gather facts of static routes
+ cisco.ios.ios_static_routes:
+ config:
+ state: gathered
+
+# Task Output
+# -----------
+#
+# gathered:
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 198.51.100.0/24
+# next_hops:
+# - forward_router_address: 198.51.101.3
+# name: route_3
+# - distance_metric: 30
+# forward_router_address: 198.51.101.2
+# name: route_2
+# - distance_metric: 110
+# forward_router_address: 198.51.101.1
+# multicast: true
+# name: route_1
+# tag: 40
+# - afi: ipv6
+# routes:
+# - dest: 2001:DB8:0:3::/64
+# next_hops:
+# - forward_router_address: 2001:DB8:0:3::2
+# name: test_v6
+# tag: 105
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 192.0.2.0/24
+# next_hops:
+# - forward_router_address: 192.0.2.1
+# name: test_vrf
+# tag: 50
+# track: 150
+# vrf: blue
+
+# Using rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_static_routes:
+ config:
+ - vrf: blue
+ address_families:
+ - afi: ipv4
+ routes:
+ - dest: 192.0.2.0/24
+ next_hops:
+ - forward_router_address: 192.0.2.1
+ name: test_vrf
+ tag: 50
+ track: 150
+ - address_families:
+ - afi: ipv4
+ routes:
+ - dest: 198.51.100.0/24
+ next_hops:
+ - forward_router_address: 198.51.101.1
+ name: route_1
+ distance_metric: 110
+ tag: 40
+ multicast: true
+ - forward_router_address: 198.51.101.2
+ name: route_2
+ distance_metric: 30
+ - forward_router_address: 198.51.101.3
+ name: route_3
+ - afi: ipv6
+ routes:
+ - dest: 2001:DB8:0:3::/64
+ next_hops:
+ - forward_router_address: 2001:DB8:0:3::2
+ name: test_v6
+ tag: 105
+ state: rendered
+
+# Task Output
+# -----------
+#
+# rendered:
+# - ip route vrf blue 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name test_vrf track 150
+# - ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 tag 40 name route_1 multicast
+# - ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
+# - ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
+# - ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name test_v6
+
+# Using parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# ip route vrf blue 192.0.2.0 255.255.255.0 192.0.2.1 tag 50 name test_vrf track 150
+# ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
+# ip route 198.51.100.0 255.255.255.0 198.51.101.2 30 name route_2
+# ip route 198.51.100.0 255.255.255.0 198.51.101.1 110 tag 40 name route_1 multicast
+# ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name test_v6
+
+- name: Parse the provided configuration
+ cisco.ios.ios_static_routes:
+ running_config: "{{ lookup('file', 'parsed.cfg') }}"
+ state: parsed
+
+# Task Output
+# -----------
+#
+# parsed:
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 198.51.100.0/24
+# next_hops:
+# - forward_router_address: 198.51.101.3
+# name: route_3
+# - distance_metric: 30
+# forward_router_address: 198.51.101.2
+# name: route_2
+# - distance_metric: 110
+# forward_router_address: 198.51.101.1
+# multicast: true
+# name: route_1
+# tag: 40
+# - afi: ipv6
+# routes:
+# - dest: 2001:DB8:0:3::/64
+# next_hops:
+# - forward_router_address: 2001:DB8:0:3::2
+# name: test_v6
+# tag: 105
+# - address_families:
+# - afi: ipv4
+# routes:
+# - dest: 192.0.2.0/24
+# next_hops:
+# - forward_router_address: 192.0.2.1
+# name: test_vrf
+# tag: 50
+# track: 150
+# vrf: blue
+
+"""
+
+RETURN = """
+before:
+ description: The configuration as structured data prior to module invocation.
+ returned: always
+ type: list
+ sample: The configuration returned will always be in the same format of the parameters above.
+after:
+ description: The configuration as structured data after module completion.
+ returned: when changed
+ type: list
+ sample: The configuration returned will always be in the same format of the parameters above.
+commands:
+ description: The set of commands pushed to the remote device
+ returned: always
+ type: list
+ sample: ['ip route vrf test 172.31.10.0 255.255.255.0 10.10.10.2 name new_test multicast']
+rendered:
+ description: The set of CLI commands generated from the value in C(config) option
+ returned: When C(state) is I(rendered)
+ type: list
+ sample:
+ - ip route 198.51.100.0 255.255.255.0 198.51.101.3 name route_3
+ - ipv6 route 2001:DB8:0:3::/64 2001:DB8:0:3::2 tag 105 name test_v6
+gathered:
+ description:
+ - The configuration as structured data transformed for the running configuration
+ fetched from remote host
+ returned: When C(state) is I(gathered)
+ type: list
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+parsed:
+ description:
+ - The configuration as structured data transformed for the value of
+ C(running_config) option
+ returned: When C(state) is I(parsed)
+ type: list
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+"""
+
+
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.static_routes.static_routes import (
+ Static_routesArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.static_routes.static_routes import (
+ Static_routes,
+)
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ module = AnsibleModule(
+ argument_spec=Static_routesArgs.argument_spec,
+ mutually_exclusive=[["config", "running_config"]],
+ required_if=[
+ ["state", "merged", ["config"]],
+ ["state", "replaced", ["config"]],
+ ["state", "overridden", ["config"]],
+ ["state", "rendered", ["config"]],
+ ["state", "parsed", ["running_config"]],
+ ],
+ supports_check_mode=True,
+ )
+
+ result = Static_routes(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_system.py b/ansible_collections/cisco/ios/plugins/modules/ios_system.py
new file mode 100644
index 000000000..33e3c936d
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_system.py
@@ -0,0 +1,351 @@
+#!/usr/bin/python
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_system
+author: Peter Sprygada (@privateip)
+short_description: Module to manage the system attributes.
+description:
+ - This module provides declarative management of node system attributes on Cisco IOS
+ devices. It provides an option to configure host system parameters or remove those
+ parameters from the device active configuration.
+version_added: 1.0.0
+extends_documentation_fragment:
+ - cisco.ios.ios
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ hostname:
+ description:
+ - Configure the device hostname parameter. This option takes an ASCII string value.
+ type: str
+ domain_name:
+ description:
+ - Configure the IP domain name on the remote device to the provided value. Value
+ should be in the dotted name form and will be appended to the C(hostname) to
+ create a fully-qualified domain name.
+ type: list
+ elements: raw
+ domain_search:
+ description:
+ - Provides the list of domain suffixes to append to the hostname for the purpose
+ of doing name resolution. This argument accepts a list of names and will be
+ reconciled with the current active configuration on the running node.
+ type: list
+ elements: raw
+ lookup_source:
+ description:
+ - Provides one or more source interfaces to use for performing DNS lookups. The
+ interface provided in C(lookup_source) must be a valid interface configured
+ on the device.
+ type: str
+ lookup_enabled:
+ description:
+ - Administrative control for enabling or disabling DNS lookups. When this argument
+ is set to True, lookups are performed and when it is set to False, lookups are
+ not performed.
+ type: bool
+ name_servers:
+ description:
+ - List of DNS name servers by IP address to use to perform name resolution lookups. This
+ argument accepts either a list of DNS servers See examples.
+ type: list
+ elements: raw
+ state:
+ description:
+ - State of the configuration values in the device's current active configuration. When
+ set to I(present), the values should be configured in the device active configuration
+ and when set to I(absent) the values should not be in the device active configuration
+ default: present
+ choices:
+ - present
+ - absent
+ type: str
+"""
+
+EXAMPLES = """
+- name: Configure hostname and domain name
+ cisco.ios.ios_system:
+ hostname: ios01
+ domain_name: test.example.com
+ domain_search:
+ - ansible.com
+ - redhat.com
+ - cisco.com
+
+- name: Remove configuration
+ cisco.ios.ios_system:
+ state: absent
+
+- name: Configure DNS lookup sources
+ cisco.ios.ios_system:
+ lookup_source: MgmtEth0/0/CPU0/0
+ lookup_enabled: true
+
+- name: Configure name servers
+ cisco.ios.ios_system:
+ name_servers:
+ - 8.8.8.8
+ - 8.8.4.4
+"""
+
+RETURN = """
+commands:
+ description: The list of configuration mode commands to send to the device
+ returned: always
+ type: list
+ sample:
+ - hostname ios01
+ - ip domain name test.example.com
+"""
+import re
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ ComplexList,
+)
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ get_config,
+ load_config,
+)
+
+
+_CONFIGURED_VRFS = None
+
+
+def has_vrf(module, vrf):
+ global _CONFIGURED_VRFS
+ if _CONFIGURED_VRFS is not None:
+ return vrf in _CONFIGURED_VRFS
+ config = get_config(module)
+ _CONFIGURED_VRFS = re.findall("vrf definition (\\S+)", config)
+ return vrf in _CONFIGURED_VRFS
+
+
+def requires_vrf(module, vrf):
+ if not has_vrf(module, vrf):
+ module.fail_json(msg="vrf %s is not configured" % vrf)
+
+
+def diff_list(want, have):
+ adds = [w for w in want if w not in have]
+ removes = [h for h in have if h not in want]
+ return adds, removes
+
+
+def map_obj_to_commands(want, have, module):
+ commands = list()
+ state = module.params["state"]
+
+ def needs_update(x):
+ return want.get(x) is not None and want.get(x) != have.get(x)
+
+ if state == "absent":
+ if have["hostname"] != "Router":
+ commands.append("no hostname")
+ if have["lookup_source"]:
+ commands.append("no ip domain lookup source-interface %s" % have["lookup_source"])
+ if have["lookup_enabled"] is False:
+ commands.append("ip domain lookup")
+ vrfs = set()
+ for item in have["domain_name"]:
+ if item["vrf"] and item["vrf"] not in vrfs:
+ vrfs.add(item["vrf"])
+ commands.append("no ip domain name vrf %s" % item["vrf"])
+ elif None not in vrfs:
+ vrfs.add(None)
+ commands.append("no ip domain name")
+ vrfs = set()
+ for item in have["domain_search"]:
+ if item["vrf"] and item["vrf"] not in vrfs:
+ vrfs.add(item["vrf"])
+ commands.append("no ip domain list vrf %s" % item["vrf"])
+ elif None not in vrfs:
+ vrfs.add(None)
+ commands.append("no ip domain list")
+ vrfs = set()
+ for item in have["name_servers"]:
+ if item["vrf"] and item["vrf"] not in vrfs:
+ vrfs.add(item["vrf"])
+ commands.append("no ip name-server vrf %s" % item["vrf"])
+ elif None not in vrfs:
+ vrfs.add(None)
+ commands.append("no ip name-server")
+ elif state == "present":
+ if needs_update("hostname"):
+ commands.append("hostname %s" % want["hostname"])
+ if needs_update("lookup_source"):
+ commands.append("ip domain lookup source-interface %s" % want["lookup_source"])
+ if needs_update("lookup_enabled"):
+ cmd = "ip domain lookup"
+ if want["lookup_enabled"] is False:
+ cmd = "no %s" % cmd
+ commands.append(cmd)
+ if want["domain_name"]:
+ adds, removes = diff_list(want["domain_name"], have["domain_name"])
+ for item in removes:
+ if item["vrf"]:
+ commands.append("no ip domain name vrf %s %s" % (item["vrf"], item["name"]))
+ else:
+ commands.append("no ip domain name %s" % item["name"])
+ for item in adds:
+ if item["vrf"]:
+ requires_vrf(module, item["vrf"])
+ commands.append("ip domain name vrf %s %s" % (item["vrf"], item["name"]))
+ else:
+ commands.append("ip domain name %s" % item["name"])
+ if want["domain_search"]:
+ adds, removes = diff_list(want["domain_search"], have["domain_search"])
+ for item in removes:
+ if item["vrf"]:
+ commands.append("no ip domain list vrf %s %s" % (item["vrf"], item["name"]))
+ else:
+ commands.append("no ip domain list %s" % item["name"])
+ for item in adds:
+ if item["vrf"]:
+ requires_vrf(module, item["vrf"])
+ commands.append("ip domain list vrf %s %s" % (item["vrf"], item["name"]))
+ else:
+ commands.append("ip domain list %s" % item["name"])
+ if want["name_servers"]:
+ adds, removes = diff_list(want["name_servers"], have["name_servers"])
+ for item in removes:
+ if item["vrf"]:
+ commands.append("no ip name-server vrf %s %s" % (item["vrf"], item["server"]))
+ else:
+ commands.append("no ip name-server %s" % item["server"])
+ for item in adds:
+ if item["vrf"]:
+ requires_vrf(module, item["vrf"])
+ commands.append("ip name-server vrf %s %s" % (item["vrf"], item["server"]))
+ else:
+ commands.append("ip name-server %s" % item["server"])
+ return commands
+
+
+def parse_hostname(config):
+ match = re.search("^hostname (\\S+)", config, re.M)
+ return match.group(1)
+
+
+def parse_domain_name(config):
+ match = re.findall("^ip domain[- ]name (?:vrf (\\S+) )*(\\S+)", config, re.M)
+ matches = list()
+ for vrf, name in match:
+ if not vrf:
+ vrf = None
+ matches.append({"name": name, "vrf": vrf})
+ return matches
+
+
+def parse_domain_search(config):
+ match = re.findall("^ip domain[- ]list (?:vrf (\\S+) )*(\\S+)", config, re.M)
+ matches = list()
+ for vrf, name in match:
+ if not vrf:
+ vrf = None
+ matches.append({"name": name, "vrf": vrf})
+ return matches
+
+
+def parse_name_servers(config):
+ match = re.findall("^ip name-server (?:vrf (\\S+) )*(.*)", config, re.M)
+ matches = list()
+ for vrf, servers in match:
+ if not vrf:
+ vrf = None
+ for server in servers.split():
+ matches.append({"server": server, "vrf": vrf})
+ return matches
+
+
+def parse_lookup_source(config):
+ match = re.search("ip domain[- ]lookup source-interface (\\S+)", config, re.M)
+ if match:
+ return match.group(1)
+
+
+def map_config_to_obj(module):
+ config = get_config(module)
+ return {
+ "hostname": parse_hostname(config),
+ "domain_name": parse_domain_name(config),
+ "domain_search": parse_domain_search(config),
+ "lookup_source": parse_lookup_source(config),
+ "lookup_enabled": "no ip domain lookup" not in config
+ and "no ip domain-lookup" not in config,
+ "name_servers": parse_name_servers(config),
+ }
+
+
+def map_params_to_obj(module):
+ obj = {
+ "hostname": module.params["hostname"],
+ "lookup_source": module.params["lookup_source"],
+ "lookup_enabled": module.params["lookup_enabled"],
+ }
+ domain_name = ComplexList(dict(name=dict(key=True), vrf=dict()), module)
+ domain_search = ComplexList(dict(name=dict(key=True), vrf=dict()), module)
+ name_servers = ComplexList(dict(server=dict(key=True), vrf=dict()), module)
+ for arg, cast in [
+ ("domain_name", domain_name),
+ ("domain_search", domain_search),
+ ("name_servers", name_servers),
+ ]:
+ if module.params[arg]:
+ obj[arg] = cast(module.params[arg])
+ else:
+ obj[arg] = None
+ return obj
+
+
+def main():
+ """Main entry point for Ansible module execution"""
+ argument_spec = dict(
+ hostname=dict(),
+ domain_name=dict(type="list", elements="raw"),
+ domain_search=dict(type="list", elements="raw"),
+ name_servers=dict(type="list", elements="raw"),
+ lookup_source=dict(),
+ lookup_enabled=dict(type="bool"),
+ state=dict(choices=["present", "absent"], default="present"),
+ )
+ module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
+ result = {"changed": False}
+ warnings = list()
+ result["warnings"] = warnings
+ want = map_params_to_obj(module)
+ have = map_config_to_obj(module)
+ commands = map_obj_to_commands(want, have, module)
+ result["commands"] = commands
+ if commands:
+ if not module.check_mode:
+ load_config(module, commands)
+ result["changed"] = True
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_user.py b/ansible_collections/cisco/ios/plugins/modules/ios_user.py
new file mode 100644
index 000000000..50f2f3455
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_user.py
@@ -0,0 +1,600 @@
+#!/usr/bin/python
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_user
+author: Trishna Guha (@trishnaguha)
+short_description: Module to manage the aggregates of local users.
+description:
+ - This module provides declarative management of the local usernames configured on
+ network devices. It allows playbooks to manage either individual usernames or the
+ aggregate of usernames in the current running config. It also supports purging usernames
+ from the configuration that are not explicitly defined.
+version_added: 1.0.0
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ aggregate:
+ description:
+ - The set of username objects to be configured on the remote Cisco IOS device.
+ The list entries can either be the username or a hash of username and properties.
+ This argument is mutually exclusive with the C(name) argument.
+ aliases:
+ - users
+ - collection
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - The username to be configured on the Cisco IOS device. This argument accepts
+ a string value and is mutually exclusive with the C(aggregate) argument. Please
+ note that this option is not same as C(provider username).
+ type: str
+ required: true
+ configured_password:
+ description:
+ - The password to be configured on the Cisco IOS device. The password needs to
+ be provided in clear and it will be encrypted on the device. Please note that
+ this option is not same as C(provider password).
+ type: str
+ update_password:
+ description:
+ - Since passwords are encrypted in the device running config, this argument will
+ instruct the module when to change the password. When set to C(always), the
+ password will always be updated in the device and when set to C(on_create) the
+ password will be updated only if the username is created.
+ choices:
+ - on_create
+ - always
+ type: str
+ password_type:
+ description:
+ - This argument determines whether a 'password' or 'secret' will be configured.
+ choices:
+ - secret
+ - password
+ type: str
+ hashed_password:
+ description:
+ - This option allows configuring hashed passwords on Cisco IOS devices.
+ type: dict
+ suboptions:
+ type:
+ description:
+ - Specifies the type of hash (e.g., 5 for MD5, 8 for PBKDF2, etc.)
+ - For this to work, the device needs to support the desired hash type
+ type: int
+ required: true
+ value:
+ description:
+ - The actual hashed password to be configured on the device
+ required: true
+ type: str
+ privilege:
+ description:
+ - The C(privilege) argument configures the privilege level of the user when logged
+ into the system. This argument accepts integer values in the range of 1 to 15.
+ type: int
+ view:
+ description:
+ - Configures the view for the username in the device running configuration. The
+ argument accepts a string value defining the view name. This argument does not
+ check if the view has been configured on the device.
+ aliases:
+ - role
+ type: str
+ sshkey:
+ description:
+ - Specifies one or more SSH public key(s) to configure for the given username.
+ - This argument accepts a valid SSH key value.
+ type: list
+ elements: str
+ nopassword:
+ description:
+ - Defines the username without assigning a password. This will allow the user
+ to login to the system without being authenticated by a password.
+ type: bool
+ state:
+ description:
+ - Configures the state of the username definition as it relates to the device
+ operational configuration. When set to I(present), the username(s) should be
+ configured in the device active configuration and when set to I(absent) the
+ username(s) should not be in the device active configuration
+ choices:
+ - present
+ - absent
+ type: str
+ name:
+ description:
+ - The username to be configured on the Cisco IOS device. This argument accepts
+ a string value and is mutually exclusive with the C(aggregate) argument. Please
+ note that this option is not same as C(provider username).
+ type: str
+ configured_password:
+ description:
+ - The password to be configured on the Cisco IOS device. The password needs to
+ be provided in clear and it will be encrypted on the device. Please note that
+ this option is not same as C(provider password).
+ type: str
+ update_password:
+ description:
+ - Since passwords are encrypted in the device running config, this argument will
+ instruct the module when to change the password. When set to C(always), the
+ password will always be updated in the device and when set to C(on_create) the
+ password will be updated only if the username is created.
+ default: always
+ choices:
+ - on_create
+ - always
+ type: str
+ password_type:
+ description:
+ - This argument determines whether a 'password' or 'secret' will be configured.
+ default: secret
+ choices:
+ - secret
+ - password
+ type: str
+ hashed_password:
+ description:
+ - This option allows configuring hashed passwords on Cisco IOS devices.
+ type: dict
+ suboptions:
+ type:
+ description:
+ - Specifies the type of hash (e.g., 5 for MD5, 8 for PBKDF2, etc.)
+ - For this to work, the device needs to support the desired hash type
+ type: int
+ required: true
+ value:
+ description:
+ - The actual hashed password to be configured on the device
+ required: true
+ type: str
+ privilege:
+ description:
+ - The C(privilege) argument configures the privilege level of the user when logged
+ into the system. This argument accepts integer values in the range of 1 to 15.
+ type: int
+ view:
+ description:
+ - Configures the view for the username in the device running configuration. The
+ argument accepts a string value defining the view name. This argument does not
+ check if the view has been configured on the device.
+ aliases:
+ - role
+ type: str
+ sshkey:
+ description:
+ - Specifies one or more SSH public key(s) to configure for the given username.
+ - This argument accepts a valid SSH key value.
+ type: list
+ elements: str
+ nopassword:
+ description:
+ - Defines the username without assigning a password. This will allow the user
+ to login to the system without being authenticated by a password.
+ type: bool
+ purge:
+ description:
+ - Instructs the module to consider the resource definition absolute. It will remove
+ any previously configured usernames on the device with the exception of the
+ `admin` user (the current defined set of users).
+ type: bool
+ default: false
+ state:
+ description:
+ - Configures the state of the username definition as it relates to the device
+ operational configuration. When set to I(present), the username(s) should be
+ configured in the device active configuration and when set to I(absent) the
+ username(s) should not be in the device active configuration
+ default: present
+ choices:
+ - present
+ - absent
+ type: str
+extends_documentation_fragment:
+ - cisco.ios.ios
+"""
+
+EXAMPLES = """
+- name: Create a new user
+ cisco.ios.ios_user:
+ name: ansible
+ nopassword: true
+ sshkey: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
+ state: present
+
+- name: Create a new user with multiple keys
+ cisco.ios.ios_user:
+ name: ansible
+ sshkey:
+ - "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
+ - "{{ lookup('file', '~/path/to/public_key') }}"
+ state: present
+
+- name: Remove all users except admin
+ cisco.ios.ios_user:
+ purge: true
+
+- name: Remove all users except admin and these listed users
+ cisco.ios.ios_user:
+ aggregate:
+ - name: testuser1
+ - name: testuser2
+ - name: testuser3
+ purge: true
+
+- name: Set multiple users to privilege level 15
+ cisco.ios.ios_user:
+ aggregate:
+ - name: netop
+ - name: netend
+ privilege: 15
+ state: present
+
+- name: Set user view/role
+ cisco.ios.ios_user:
+ name: netop
+ view: network-operator
+ state: present
+
+- name: Change Password for User netop
+ cisco.ios.ios_user:
+ name: netop
+ configured_password: "{{ new_password }}"
+ update_password: always
+ state: present
+
+- name: Aggregate of users
+ cisco.ios.ios_user:
+ aggregate:
+ - name: ansibletest2
+ - name: ansibletest3
+ view: network-admin
+
+- name: Add a user specifying password type
+ cisco.ios.ios_user:
+ name: ansibletest4
+ configured_password: "{{ new_password }}"
+ password_type: password
+
+- name: Add a user with MD5 hashed password
+ cisco.ios.ios_user:
+ name: ansibletest5
+ hashed_password:
+ type: 5
+ value: $3$8JcDilcYgFZi.yz4ApaqkHG2.8/
+
+- name: Delete users with aggregate
+ cisco.ios.ios_user:
+ aggregate:
+ - name: ansibletest1
+ - name: ansibletest2
+ - name: ansibletest3
+ state: absent
+"""
+
+RETURN = """
+commands:
+ description: The list of configuration mode commands to send to the device
+ returned: always
+ type: list
+ sample:
+ - username ansible secret password
+ - username admin secret admin
+"""
+import base64
+import hashlib
+import re
+
+from copy import deepcopy
+from functools import partial
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
+ remove_default_spec,
+)
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ get_config,
+ load_config,
+)
+
+
+def validate_privilege(value, module):
+ if value and not 1 <= value <= 15:
+ module.fail_json(msg="privilege must be between 1 and 15, got %s" % value)
+
+
+def user_del_cmd(username):
+ return {
+ "command": "no username %s" % username,
+ "prompt": "This operation will remove all username related configurations with same name",
+ "answer": "y",
+ "newline": False,
+ }
+
+
+def sshkey_fingerprint(sshkey):
+ # IOS will accept a MD5 fingerprint of the public key
+ # and is easier to configure in a single line
+ # we calculate this fingerprint here
+ if not sshkey:
+ return None
+ if " " in sshkey:
+ # ssh-rsa AAA...== comment
+ keyparts = sshkey.split(" ")
+ keyparts[1] = hashlib.md5(base64.b64decode(keyparts[1])).hexdigest().upper()
+ return " ".join(keyparts)
+ else:
+ # just the key, assume rsa type
+ return "ssh-rsa %s" % hashlib.md5(base64.b64decode(sshkey)).hexdigest().upper()
+
+
+def map_obj_to_commands(updates, module):
+ commands = list()
+ update_password = module.params["update_password"]
+ password_type = module.params["password_type"]
+
+ def needs_update(want, have, x):
+ return want.get(x) and want.get(x) != have.get(x)
+
+ def add(command, want, x):
+ command.append("username %s %s" % (want["name"], x))
+
+ def add_hashed_password(command, want, x):
+ command.append("username %s secret %s %s" % (want["name"], x.get("type"), x.get("value")))
+
+ def add_ssh(command, want, x=None):
+ command.append("ip ssh pubkey-chain")
+ if x:
+ command.append("username %s" % want["name"])
+ for item in x:
+ command.append("key-hash %s" % item)
+ command.append("exit")
+ else:
+ command.append("no username %s" % want["name"])
+ command.append("exit")
+
+ for update in updates:
+ want, have = update
+ if want["state"] == "absent":
+ if have["sshkey"]:
+ add_ssh(commands, want)
+ else:
+ commands.append(user_del_cmd(want["name"]))
+ if needs_update(want, have, "view"):
+ add(commands, want, "view %s" % want["view"])
+ if needs_update(want, have, "privilege"):
+ add(commands, want, "privilege %s" % want["privilege"])
+ if needs_update(want, have, "sshkey"):
+ add_ssh(commands, want, want["sshkey"])
+ if needs_update(want, have, "configured_password"):
+ if update_password == "always" or not have:
+ if have and have["password_type"] and password_type != have["password_type"]:
+ module.fail_json(
+ msg="Can not have both a user password and a user secret."
+ + " Please choose one or the other.",
+ )
+ add(commands, want, "%s %s" % (password_type, want["configured_password"]))
+ if needs_update(want, have, "hashed_password"):
+ add_hashed_password(commands, want, want["hashed_password"])
+ if needs_update(want, have, "nopassword"):
+ if want["nopassword"]:
+ add(commands, want, "nopassword")
+ else:
+ add(commands, want, user_del_cmd(want["name"]))
+ return commands
+
+
+def parse_view(data):
+ match = re.search("view (\\S+)", data, re.M)
+ if match:
+ return match.group(1)
+
+
+def parse_sshkey(data, user):
+ sshregex = "username %s(\\n\\s+key-hash .+$)+" % user
+ sshcfg = re.search(sshregex, data, re.M)
+ key_list = []
+ if sshcfg:
+ match = re.findall("key-hash (\\S+ \\S+(?: .+)?)$", sshcfg.group(), re.M)
+ if match:
+ key_list = match
+ return key_list
+
+
+def parse_privilege(data):
+ match = re.search("privilege (\\S+)", data, re.M)
+ if match:
+ return int(match.group(1))
+
+
+def parse_password_type(data):
+ type = None
+ if data and data.split()[-3] in ["password", "secret"]:
+ type = data.split()[-3]
+ return type
+
+
+def map_config_to_obj(module):
+ data = get_config(module, flags=["| section username"])
+ match = re.findall("(?:^(?:u|\\s{2}u))sername (\\S+)", data, re.M)
+ if not match:
+ return list()
+ instances = list()
+ for user in set(match):
+ regex = "username %s .+$" % user
+ cfg = re.findall(regex, data, re.M)
+ cfg = "\n".join(cfg)
+ obj = {
+ "name": user,
+ "state": "present",
+ "nopassword": "nopassword" in cfg,
+ "configured_password": None,
+ "hashed_password": None,
+ "password_type": parse_password_type(cfg),
+ "sshkey": parse_sshkey(data, user),
+ "privilege": parse_privilege(cfg),
+ "view": parse_view(cfg),
+ }
+ instances.append(obj)
+ return instances
+
+
+def get_param_value(key, item, module):
+ # if key doesn't exist in the item, get it from module.params
+ if not item.get(key):
+ value = module.params[key]
+ # if key does exist, do a type check on it to validate it
+ else:
+ value_type = module.argument_spec[key].get("type", "str")
+ type_checker = module._CHECK_ARGUMENT_TYPES_DISPATCHER[value_type]
+ type_checker(item[key])
+ value = item[key]
+ # validate the param value (if validator func exists)
+ validator = globals().get("validate_%s" % key)
+ if all((value, validator)):
+ validator(value, module)
+ return value
+
+
+def map_params_to_obj(module):
+ users = module.params["aggregate"]
+ if not users:
+ if not module.params["name"] and module.params["purge"]:
+ return list()
+ elif not module.params["name"]:
+ module.fail_json(msg="username is required")
+ else:
+ aggregate = [{"name": module.params["name"]}]
+ else:
+ aggregate = list()
+ for item in users:
+ if not isinstance(item, dict):
+ aggregate.append({"name": item})
+ elif "name" not in item:
+ module.fail_json(msg="name is required")
+ else:
+ aggregate.append(item)
+ objects = list()
+ for item in aggregate:
+ get_value = partial(get_param_value, item=item, module=module)
+ item["configured_password"] = get_value("configured_password")
+ item["hashed_password"] = get_value("hashed_password")
+ item["nopassword"] = get_value("nopassword")
+ item["privilege"] = get_value("privilege")
+ item["view"] = get_value("view")
+ item["sshkey"] = render_key_list(get_value("sshkey"))
+ item["state"] = get_value("state")
+ objects.append(item)
+ return objects
+
+
+def render_key_list(ssh_keys):
+ key_list = []
+ if ssh_keys:
+ for item in ssh_keys:
+ key_list.append(sshkey_fingerprint(item))
+ return key_list
+
+
+def update_objects(want, have):
+ updates = list()
+ for entry in want:
+ item = next((i for i in have if i["name"] == entry["name"]), None)
+ if all((item is None, entry["state"] == "present")):
+ updates.append((entry, {}))
+ elif item:
+ for key, value in iteritems(entry):
+ if value and value != item[key]:
+ updates.append((entry, item))
+ return updates
+
+
+def main():
+ """main entry point for module execution"""
+ hashed_password_spec = dict(
+ type=dict(type="int", required=True),
+ value=dict(no_log=True, required=True),
+ )
+ element_spec = dict(
+ name=dict(),
+ configured_password=dict(no_log=True),
+ hashed_password=dict(no_log=True, type="dict", options=hashed_password_spec),
+ nopassword=dict(type="bool"),
+ update_password=dict(default="always", choices=["on_create", "always"]),
+ password_type=dict(default="secret", choices=["secret", "password"]),
+ privilege=dict(type="int"),
+ view=dict(aliases=["role"]),
+ sshkey=dict(type="list", elements="str", no_log=False),
+ state=dict(default="present", choices=["present", "absent"]),
+ )
+ aggregate_spec = deepcopy(element_spec)
+ aggregate_spec["name"] = dict(required=True)
+ # remove default in aggregate spec, to handle common arguments
+ remove_default_spec(aggregate_spec)
+ argument_spec = dict(
+ aggregate=dict(
+ type="list",
+ elements="dict",
+ options=aggregate_spec,
+ aliases=["users", "collection"],
+ ),
+ purge=dict(type="bool", default=False),
+ )
+ argument_spec.update(element_spec)
+ mutually_exclusive = [
+ ("name", "aggregate"),
+ ("nopassword", "hashed_password", "configured_password"),
+ ]
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+ warnings = list()
+ result = {"changed": False, "warnings": warnings}
+ want = map_params_to_obj(module)
+ have = map_config_to_obj(module)
+ commands = map_obj_to_commands(update_objects(want, have), module)
+ if module.params["purge"]:
+ want_users = [x["name"] for x in want]
+ have_users = [x["name"] for x in have]
+ for item in set(have_users).difference(want_users):
+ if item != "admin":
+ commands.append(user_del_cmd(item))
+ result["commands"] = commands
+ if commands:
+ if not module.check_mode:
+ load_config(module, commands)
+ result["changed"] = True
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_vlans.py b/ansible_collections/cisco/ios/plugins/modules/ios_vlans.py
new file mode 100644
index 000000000..2877e4318
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_vlans.py
@@ -0,0 +1,822 @@
+#!/usr/bin/python
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+"""
+The module file for ios_vlans
+"""
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: ios_vlans
+short_description: Resource module to configure VLANs.
+description:
+ This module provides declarative management of VLANs on Cisco IOS network
+ devices.
+version_added: 1.0.0
+author: Sumit Jaiswal (@justjais)
+notes:
+ - Tested against Cisco IOSl2 device with Version 15.2 on VIRL.
+ - Starting from v2.5.0, this module will fail when run against Cisco IOS devices that do
+ not support VLANs. The offline states (C(rendered) and C(parsed)) will work as expected.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ config:
+ description: A dictionary of VLANs options
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description:
+ - Ascii name of the VLAN.
+ - NOTE, I(name) should not be named/appended with I(default) as it is reserved
+ for device default vlans.
+ type: str
+ vlan_id:
+ description:
+ - ID of the VLAN. Range 1-4094
+ type: int
+ required: true
+ mtu:
+ description:
+ - VLAN Maximum Transmission Unit.
+ - Refer to vendor documentation for valid values.
+ type: int
+ state:
+ description:
+ - Operational state of the VLAN
+ type: str
+ choices:
+ - active
+ - suspend
+ remote_span:
+ description:
+ - Configure as Remote SPAN VLAN
+ type: bool
+ shutdown:
+ description:
+ - Shutdown VLAN switching.
+ type: str
+ choices:
+ - enabled
+ - disabled
+ private_vlan:
+ description:
+ - Options for private vlan configuration.
+ type: dict
+ suboptions:
+ type:
+ description:
+ - Private VLAN type
+ type: str
+ choices:
+ - primary
+ - isolated
+ - community
+ associated:
+ description:
+ - "List of private VLANs associated with the primary . Only works with `type: primary`."
+ type: list
+ elements: int
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the IOS device
+ by executing the command B(show vlan).
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into Ansible structured data as per the resource module's argspec
+ and the value is then returned in the I(parsed) key within the result.
+ type: str
+ state:
+ description:
+ - The state the configuration should be left in
+ - The states I(rendered), I(gathered) and I(parsed) does not perform any change
+ on the device.
+ - The state I(rendered) will transform the configuration in C(config) option to
+ platform specific CLI commands which will be returned in the I(rendered) key
+ within the result. For state I(rendered) active connection to remote host is
+ not required.
+ - The state I(gathered) will fetch the running configuration from device and transform
+ it into structured data in the format as per the resource module argspec and
+ the value is returned in the I(gathered) key within the result.
+ - The state I(parsed) reads the configuration from C(running_config) option and
+ transforms it into JSON format as per the resource module parameters and the
+ value is returned in the I(parsed) key within the result. The value of C(running_config)
+ option should be the same format as the output of command I(show running-config
+ | include ip route|ipv6 route) executed on device. For state I(parsed) active
+ connection to remote host is not required.
+ type: str
+ choices:
+ - merged
+ - replaced
+ - overridden
+ - deleted
+ - rendered
+ - gathered
+ - parsed
+ default: merged
+"""
+
+EXAMPLES = """
+# Using merged
+
+# Before state:
+# -------------
+#
+# vios_l2#show vlan
+# VLAN Name Status Ports
+# ---- -------------------------------- --------- -------------------------------
+# 1 default active Gi0/1, Gi0/2
+# 1002 fddi-default act/unsup
+# 1003 token-ring-default act/unsup
+# 1004 fddinet-default act/unsup
+# 1005 trnet-default act/unsup
+#
+# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
+# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
+# 1 enet 100001 1500 - - - - - 0 0
+# 1002 fddi 101002 1500 - - - - - 0 0
+# 1003 tr 101003 1500 - - - - - 0 0
+# 1004 fdnet 101004 1500 - - - ieee - 0 0
+# 1005 trnet 101005 1500 - - - ibm - 0 0
+
+- name: Merge provided configuration with device configuration
+ cisco.ios.ios_vlans:
+ config:
+ - name: Vlan_10
+ vlan_id: 10
+ state: active
+ shutdown: disabled
+ remote_span: true
+ - name: Vlan_20
+ vlan_id: 20
+ mtu: 610
+ state: active
+ shutdown: enabled
+ - name: Vlan_30
+ vlan_id: 30
+ state: suspend
+ shutdown: enabled
+ state: merged
+
+# After state:
+# ------------
+#
+# vios_l2#show vlan
+# VLAN Name Status Ports
+# ---- -------------------------------- --------- -------------------------------
+# 1 default active Gi0/1, Gi0/2
+# 10 vlan_10 active
+# 20 vlan_20 act/lshut
+# 30 vlan_30 sus/lshut
+# 1002 fddi-default act/unsup
+# 1003 token-ring-default act/unsup
+# 1004 fddinet-default act/unsup
+# 1005 trnet-default act/unsup
+#
+# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
+# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
+# 1 enet 100001 1500 - - - - - 0 0
+# 10 enet 100010 1500 - - - - - 0 0
+# 20 enet 100020 610 - - - - - 0 0
+# 30 enet 100030 1500 - - - - - 0 0
+# 1002 fddi 101002 1500 - - - - - 0 0
+# 1003 tr 101003 1500 - - - - - 0 0
+# 1004 fdnet 101004 1500 - - - ieee - 0 0
+# 1005 trnet 101005 1500 - - - ibm - 0 0
+#
+# Remote SPAN VLANs
+# ------------------------------------------------------------------------------
+# 10
+
+# Using overridden
+
+# Before state:
+# -------------
+#
+# vios_l2#show vlan
+# VLAN Name Status Ports
+# ---- -------------------------------- --------- -------------------------------
+# 1 default active Gi0/1, Gi0/2
+# 10 vlan_10 active
+# 20 vlan_20 act/lshut
+# 30 vlan_30 sus/lshut
+# 1002 fddi-default act/unsup
+# 1003 token-ring-default act/unsup
+# 1004 fddinet-default act/unsup
+# 1005 trnet-default act/unsup
+#
+# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
+# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
+# 1 enet 100001 1500 - - - - - 0 0
+# 10 enet 100010 1500 - - - - - 0 0
+# 20 enet 100020 610 - - - - - 0 0
+# 30 enet 100030 1500 - - - - - 0 0
+# 1002 fddi 101002 1500 - - - - - 0 0
+# 1003 tr 101003 1500 - - - - - 0 0
+# 1004 fdnet 101004 1500 - - - ieee - 0 0
+# 1005 trnet 101005 1500 - - - ibm - 0 0
+#
+# Remote SPAN VLANs
+# ------------------------------------------------------------------------------
+# 10
+
+- name: Override device configuration of all VLANs with provided configuration
+ cisco.ios.ios_vlans:
+ config:
+ - name: Vlan_10
+ vlan_id: 10
+ mtu: 1000
+ state: overridden
+
+# After state:
+# ------------
+#
+# vios_l2#show vlan
+# VLAN Name Status Ports
+# ---- -------------------------------- --------- -------------------------------
+# 1 default active Gi0/1, Gi0/2
+# 10 Vlan_10 active
+# 1002 fddi-default act/unsup
+# 1003 token-ring-default act/unsup
+# 1004 fddinet-default act/unsup
+# 1005 trnet-default act/unsup
+#
+# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
+# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
+# 1 enet 100001 1500 - - - - - 0 0
+# 10 enet 100010 1000 - - - - - 0 0
+# 1002 fddi 101002 1500 - - - - - 0 0
+# 1003 tr 101003 1500 - - - - - 0 0
+# 1004 fdnet 101004 1500 - - - ieee - 0 0
+# 1005 trnet 101005 1500 - - - ibm - 0 0
+
+# Using replaced
+
+# Before state:
+# -------------
+#
+# vios_l2#show vlan
+# VLAN Name Status Ports
+# ---- -------------------------------- --------- -------------------------------
+# 1 default active Gi0/1, Gi0/2
+# 10 vlan_10 active
+# 20 vlan_20 act/lshut
+# 30 vlan_30 sus/lshut
+# 1002 fddi-default act/unsup
+# 1003 token-ring-default act/unsup
+# 1004 fddinet-default act/unsup
+# 1005 trnet-default act/unsup
+#
+# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
+# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
+# 1 enet 100001 1500 - - - - - 0 0
+# 10 enet 100010 1500 - - - - - 0 0
+# 20 enet 100020 610 - - - - - 0 0
+# 30 enet 100030 1500 - - - - - 0 0
+# 1002 fddi 101002 1500 - - - - - 0 0
+# 1003 tr 101003 1500 - - - - - 0 0
+# 1004 fdnet 101004 1500 - - - ieee - 0 0
+# 1005 trnet 101005 1500 - - - ibm - 0 0
+#
+# Remote SPAN VLANs
+# ------------------------------------------------------------------------------
+# 10
+
+- name: Replaces device configuration of listed VLANs with provided configuration
+ cisco.ios.ios_vlans:
+ config:
+ - vlan_id: 20
+ name: Test_VLAN20
+ mtu: 700
+ shutdown: disabled
+ - vlan_id: 50
+ name: pvlan-isolated
+ private_vlan:
+ type: isolated
+ - vlan_id: 60
+ name: pvlan-community
+ private_vlan:
+ type: community
+ - vlan_id: 70
+ name: pvlan-primary
+ private_vlan:
+ type: primary
+ associated:
+ - 50
+ - 60
+
+ state: replaced
+
+# After state:
+# ------------
+#
+# vios_l2#sh vlan
+# VLAN Name Status Ports
+# ---- -------------------------------- --------- -------------------------------
+# 1 default active Gi0/0, Gi0/1, Gi0/2, Gi0/3
+# 10 Vlan_10 active
+# 20 Test_VLAN20 active
+# 50 pvlan-isolated active
+# 60 pvlan-community active
+# 70 pvlan-primary active
+# 1002 fddi-default act/unsup
+# 1003 token-ring-default act/unsup
+# 1004 fddinet-default act/unsup
+# 1005 trnet-default act/unsup
+#
+# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
+# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
+# 1 enet 100001 1500 - - - - - 0 0
+# 10 enet 100010 1000 - - - - - 0 0
+# 20 enet 100020 700 - - - - - 0 0
+# 50 enet 100050 1500 - - - - - 0 0
+# 60 enet 100051 1500 - - - - - 0 0
+# 70 enet 100059 1500 - - - - - 0 0
+# 1002 fddi 101002 1500 - - - - - 0 0
+# 1003 tr 101003 1500 - - - - - 0 0
+# 1004 fdnet 101004 1500 - - - ieee - 0 0
+#
+# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
+# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
+# 1005 trnet 101005 1500 - - - ibm - 0 0
+#
+# Remote SPAN VLANs
+# ------------------------------------------------------------------------------
+#
+#
+# Primary Secondary Type Ports
+# ------- --------- ----------------- ------------------------------------------
+# 70 50 isolated
+# 70 60 community
+
+# Using deleted
+
+# Before state:
+# -------------
+#
+# vios_l2#show vlan
+# VLAN Name Status Ports
+# ---- -------------------------------- --------- -------------------------------
+# 1 default active Gi0/1, Gi0/2
+# 10 vlan_10 active
+# 20 vlan_20 act/lshut
+# 30 vlan_30 sus/lshut
+# 1002 fddi-default act/unsup
+# 1003 token-ring-default act/unsup
+# 1004 fddinet-default act/unsup
+# 1005 trnet-default act/unsup
+#
+# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
+# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
+# 1 enet 100001 1500 - - - - - 0 0
+# 10 enet 100010 1500 - - - - - 0 0
+# 20 enet 100020 610 - - - - - 0 0
+# 30 enet 100030 1500 - - - - - 0 0
+# 1002 fddi 101002 1500 - - - - - 0 0
+# 1003 tr 101003 1500 - - - - - 0 0
+# 1004 fdnet 101004 1500 - - - ieee - 0 0
+# 1005 trnet 101005 1500 - - - ibm - 0 0
+#
+# Remote SPAN VLANs
+# ------------------------------------------------------------------------------
+# 10
+
+- name: Delete attributes of given VLANs
+ cisco.ios.ios_vlans:
+ config:
+ - vlan_id: 10
+ - vlan_id: 20
+ state: deleted
+
+# After state:
+# -------------
+#
+# vios_l2#show vlan
+# VLAN Name Status Ports
+# ---- -------------------------------- --------- -------------------------------
+# 1 default active Gi0/1, Gi0/2
+# 30 vlan_30 sus/lshut
+# 1002 fddi-default act/unsup
+# 1003 token-ring-default act/unsup
+# 1004 fddinet-default act/unsup
+# 1005 trnet-default act/unsup
+#
+# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
+# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
+# 1 enet 100001 1500 - - - - - 0 0
+# 30 enet 100030 1500 - - - - - 0 0
+# 1002 fddi 101002 1500 - - - - - 0 0
+# 1003 tr 101003 1500 - - - - - 0 0
+# 1004 fdnet 101004 1500 - - - ieee - 0 0
+# 1005 trnet 101005 1500 - - - ibm - 0 0
+
+# Using Deleted without any config passed
+#"(NOTE: This will delete all of configured vlans attributes)"
+
+# Before state:
+# -------------
+#
+# vios_l2#show vlan
+# VLAN Name Status Ports
+# ---- -------------------------------- --------- -------------------------------
+# 1 default active Gi0/1, Gi0/2
+# 10 vlan_10 active
+# 20 vlan_20 act/lshut
+# 30 vlan_30 sus/lshut
+# 1002 fddi-default act/unsup
+# 1003 token-ring-default act/unsup
+# 1004 fddinet-default act/unsup
+# 1005 trnet-default act/unsup
+#
+# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
+# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
+# 1 enet 100001 1500 - - - - - 0 0
+# 10 enet 100010 1500 - - - - - 0 0
+# 20 enet 100020 610 - - - - - 0 0
+# 30 enet 100030 1500 - - - - - 0 0
+# 1002 fddi 101002 1500 - - - - - 0 0
+# 1003 tr 101003 1500 - - - - - 0 0
+# 1004 fdnet 101004 1500 - - - ieee - 0 0
+# 1005 trnet 101005 1500 - - - ibm - 0 0
+#
+# Remote SPAN VLANs
+# ------------------------------------------------------------------------------
+# 10
+
+- name: Delete attributes of ALL VLANs
+ cisco.ios.ios_vlans:
+ state: deleted
+
+# After state:
+# -------------
+#
+# vios_l2#show vlan
+# VLAN Name Status Ports
+# ---- -------------------------------- --------- -------------------------------
+# 1 default active Gi0/1, Gi0/2
+# 1002 fddi-default act/unsup
+# 1003 token-ring-default act/unsup
+# 1004 fddinet-default act/unsup
+# 1005 trnet-default act/unsup
+#
+# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
+# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
+# 1 enet 100001 1500 - - - - - 0 0
+# 1002 fddi 101002 1500 - - - - - 0 0
+# 1003 tr 101003 1500 - - - - - 0 0
+# 1004 fdnet 101004 1500 - - - ieee - 0 0
+# 1005 trnet 101005 1500 - - - ibm - 0 0
+
+# Using Gathered
+
+# Before state:
+# -------------
+#
+# vios_l2#show vlan
+# VLAN Name Status Ports
+# ---- -------------------------------- --------- -------------------------------
+# 1 default active Gi0/1, Gi0/2
+# 10 vlan_10 active
+# 20 vlan_20 act/lshut
+# 30 vlan_30 sus/lshut
+# 1002 fddi-default act/unsup
+# 1003 token-ring-default act/unsup
+# 1004 fddinet-default act/unsup
+# 1005 trnet-default act/unsup
+#
+# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
+# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
+# 1 enet 100001 1500 - - - - - 0 0
+# 10 enet 100010 1500 - - - - - 0 0
+# 20 enet 100020 610 - - - - - 0 0
+# 30 enet 100030 1500 - - - - - 0 0
+# 1002 fddi 101002 1500 - - - - - 0 0
+# 1003 tr 101003 1500 - - - - - 0 0
+# 1004 fdnet 101004 1500 - - - ieee - 0 0
+# 1005 trnet 101005 1500 - - - ibm - 0 0
+#
+# Remote SPAN VLANs
+# ------------------------------------------------------------------------------
+# 10
+
+- name: Gather listed vlans with provided configurations
+ cisco.ios.ios_vlans:
+ config:
+ state: gathered
+
+# Module Execution Result:
+# ------------------------
+#
+# "gathered": [
+# {
+# "mtu": 1500,
+# "name": "default",
+# "shutdown": "disabled",
+# "state": "active",
+# "vlan_id": 1
+# },
+# {
+# "mtu": 1500,
+# "name": "VLAN0010",
+# "shutdown": "disabled",
+# "state": "active",
+# "vlan_id": 10
+# },
+# {
+# "mtu": 1500,
+# "name": "VLAN0020",
+# "shutdown": "disabled",
+# "state": "active",
+# "vlan_id": 20
+# },
+# {
+# "mtu": 1500,
+# "name": "VLAN0030",
+# "shutdown": "disabled",
+# "state": "active",
+# "vlan_id": 30
+# },
+# {
+# "mtu": 1500,
+# "name": "fddi-default",
+# "shutdown": "enabled",
+# "state": "active",
+# "vlan_id": 1002
+# },
+# {
+# "mtu": 1500,
+# "name": "token-ring-default",
+# "shutdown": "enabled",
+# "state": "active",
+# "vlan_id": 1003
+# },
+# {
+# "mtu": 1500,
+# "name": "fddinet-default",
+# "shutdown": "enabled",
+# "state": "active",
+# "vlan_id": 1004
+# },
+# {
+# "mtu": 1500,
+# "name": "trnet-default",
+# "shutdown": "enabled",
+# "state": "active",
+# "vlan_id": 1005
+# }
+# ]
+
+# After state:
+# ------------
+#
+# vios_l2#show vlan
+# VLAN Name Status Ports
+# ---- -------------------------------- --------- -------------------------------
+# 1 default active Gi0/1, Gi0/2
+# 10 vlan_10 active
+# 20 vlan_20 act/lshut
+# 30 vlan_30 sus/lshut
+# 1002 fddi-default act/unsup
+# 1003 token-ring-default act/unsup
+# 1004 fddinet-default act/unsup
+# 1005 trnet-default act/unsup
+#
+# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
+# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
+# 1 enet 100001 1500 - - - - - 0 0
+# 10 enet 100010 1500 - - - - - 0 0
+# 20 enet 100020 610 - - - - - 0 0
+# 30 enet 100030 1500 - - - - - 0 0
+# 1002 fddi 101002 1500 - - - - - 0 0
+# 1003 tr 101003 1500 - - - - - 0 0
+# 1004 fdnet 101004 1500 - - - ieee - 0 0
+# 1005 trnet 101005 1500 - - - ibm - 0 0
+#
+# Remote SPAN VLANs
+# ------------------------------------------------------------------------------
+# 10
+
+# Using Rendered
+
+- name: Render the commands for provided configuration
+ cisco.ios.ios_vlans:
+ config:
+ - name: Vlan_10
+ vlan_id: 10
+ state: active
+ shutdown: disabled
+ remote_span: true
+ - name: Vlan_20
+ vlan_id: 20
+ mtu: 610
+ state: active
+ shutdown: enabled
+ - name: Vlan_30
+ vlan_id: 30
+ state: suspend
+ shutdown: enabled
+ state: rendered
+
+# Module Execution Result:
+# ------------------------
+#
+# "rendered": [
+# "vlan 10",
+# "name Vlan_10",
+# "state active",
+# "remote-span",
+# "no shutdown",
+# "vlan 20",
+# "name Vlan_20",
+# "state active",
+# "mtu 610",
+# "shutdown",
+# "vlan 30",
+# "name Vlan_30",
+# "state suspend",
+# "shutdown"
+# ]
+
+# Using Parsed
+
+# File: parsed.cfg
+# ----------------
+#
+# VLAN Name Status Ports
+# ---- -------------------------------- --------- -------------------------------
+# 1 default active Gi0/1, Gi0/2
+# 10 vlan_10 active
+# 20 vlan_20 act/lshut
+# 30 vlan_30 sus/lshut
+# 1002 fddi-default act/unsup
+# 1003 token-ring-default act/unsup
+# 1004 fddinet-default act/unsup
+# 1005 trnet-default act/unsup
+#
+# VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2
+# ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------
+# 1 enet 100001 1500 - - - - - 0 0
+# 10 enet 100010 1500 - - - - - 0 0
+# 20 enet 100020 1500 - - - - - 0 0
+# 30 enet 100030 1500 - - - - - 0 0
+# 1002 fddi 101002 1500 - - - - - 0 0
+# 1003 tr 101003 1500 - - - - - 0 0
+# 1004 fdnet 101004 1500 - - - ieee - 0 0
+# 1005 trnet 101005 1500 - - - ibm - 0 0
+
+- name: Parse the commands for provided configuration
+ cisco.ios.ios_vlans:
+ running_config: "{{ lookup('file', './parsed.cfg') }}"
+ state: parsed
+
+# Module Execution Result:
+# ------------------------
+#
+# "parsed": [
+# {
+# "mtu": 1500,
+# "name": "default",
+# "shutdown": "disabled",
+# "state": "active",
+# "vlan_id": 1
+# },
+# {
+# "mtu": 1500,
+# "name": "vlan_10",
+# "shutdown": "disabled",
+# "state": "active",
+# "vlan_id": 10
+# },
+# {
+# "mtu": 1500,
+# "name": "vlan_20",
+# "shutdown": "enabled",
+# "state": "active",
+# "vlan_id": 20
+# },
+# {
+# "mtu": 1500,
+# "name": "vlan_30",
+# "shutdown": "enabled",
+# "state": "suspend",
+# "vlan_id": 30
+# },
+# {
+# "mtu": 1500,
+# "name": "fddi-default",
+# "shutdown": "enabled",
+# "state": "active",
+# "vlan_id": 1002
+# },
+# {
+# "mtu": 1500,
+# "name": "token-ring-default",
+# "shutdown": "enabled",
+# "state": "active",
+# "vlan_id": 1003
+# },
+# {
+# "mtu": 1500,
+# "name": "fddinet-default",
+# "shutdown": "enabled",
+# "state": "active",
+# "vlan_id": 1004
+# },
+# {
+# "mtu": 1500,
+# "name": "trnet-default",
+# "shutdown": "enabled",
+# "state": "active",
+# "vlan_id": 1005
+# }
+# ]
+"""
+
+RETURN = """
+before:
+ description: The configuration as structured data prior to module invocation.
+ returned: always
+ type: list
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+after:
+ description: The configuration as structured data after module completion.
+ returned: when changed
+ type: list
+ sample: >
+ The configuration returned will always be in the same format
+ of the parameters above.
+commands:
+ description: The set of commands pushed to the remote device.
+ returned: always
+ type: list
+ sample: ['vlan 20', 'name vlan_20', 'mtu 600', 'remote-span']
+"""
+from ansible.module_utils.basic import AnsibleModule
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.argspec.vlans.vlans import (
+ VlansArgs,
+)
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.vlans.vlans import Vlans
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import get_connection
+
+
+def _is_l2_device(module):
+ """fails module if device is L3."""
+ connection = get_connection(module)
+ check_os_type = connection.get_device_info()
+ if check_os_type.get("network_os_type") == "L3":
+ return False
+ return True
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ required_if = [
+ ("state", "merged", ("config",)),
+ ("state", "replaced", ("config",)),
+ ("state", "overridden", ("config",)),
+ ("state", "rendered", ("config",)),
+ ("state", "parsed", ("running_config",)),
+ ]
+ mutually_exclusive = [("config", "running_config")]
+
+ module = AnsibleModule(
+ argument_spec=VlansArgs.argument_spec,
+ required_if=required_if,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+
+ if _is_l2_device(module) or module.params.get("state") in ["rendered", "parsed"]:
+ result = Vlans(module).execute_module()
+ module.exit_json(**result)
+ else:
+ module.fail_json("""Resource VLAN is not valid for the target device.""")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/modules/ios_vrf.py b/ansible_collections/cisco/ios/plugins/modules/ios_vrf.py
new file mode 100644
index 000000000..4165bcae5
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/modules/ios_vrf.py
@@ -0,0 +1,741 @@
+#!/usr/bin/python
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+DOCUMENTATION = """
+module: ios_vrf
+author: Peter Sprygada (@privateip)
+short_description: Module to configure VRF definitions.
+description:
+ - This module provides declarative management of VRF definitions on Cisco IOS devices. It
+ allows playbooks to manage individual or the entire VRF collection. It also supports
+ purging VRF definitions from the configuration that are not explicitly defined.
+version_added: 1.0.0
+extends_documentation_fragment:
+ - cisco.ios.ios
+notes:
+ - Tested against Cisco IOSXE Version 17.3 on CML.
+ - This module works with connection C(network_cli).
+ See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
+options:
+ vrfs:
+ description:
+ - The set of VRF definition objects to be configured on the remote IOS device. Ths
+ list entries can either be the VRF name or a hash of VRF definitions and attributes. This
+ argument is mutually exclusive with the C(name) argument.
+ type: list
+ elements: raw
+ name:
+ description:
+ - The name of the VRF definition to be managed on the remote IOS device. The
+ VRF definition name is an ASCII string name used to uniquely identify the VRF. This
+ argument is mutually exclusive with the C(vrfs) argument
+ type: str
+ description:
+ description:
+ - Provides a short description of the VRF definition in the current active configuration. The
+ VRF definition value accepts alphanumeric characters used to provide additional
+ information about the VRF.
+ type: str
+ rd:
+ description:
+ - The router-distinguisher value uniquely identifies the VRF to routing processes
+ on the remote IOS system. The RD value takes the form of C(A:B) where C(A)
+ and C(B) are both numeric values.
+ type: str
+ interfaces:
+ description:
+ - Identifies the set of interfaces that should be configured in the VRF. Interfaces
+ must be routed interfaces in order to be placed into a VRF.
+ type: list
+ elements: str
+ associated_interfaces:
+ description:
+ - This is a intent option and checks the operational state of the for given vrf
+ C(name) for associated interfaces. If the value in the C(associated_interfaces)
+ does not match with the operational state of vrf interfaces on device it will
+ result in failure.
+ type: list
+ elements: str
+ delay:
+ description:
+ - Time in seconds to wait before checking for the operational state on remote
+ device.
+ default: 10
+ type: int
+ purge:
+ description:
+ - Instructs the module to consider the VRF definition absolute. It will remove
+ any previously configured VRFs on the device.
+ default: false
+ type: bool
+ state:
+ description:
+ - Configures the state of the VRF definition as it relates to the device operational
+ configuration. When set to I(present), the VRF should be configured in the
+ device active configuration and when set to I(absent) the VRF should not be
+ in the device active configuration
+ default: present
+ choices:
+ - present
+ - absent
+ type: str
+ route_both:
+ description:
+ - Adds an export and import list of extended route target communities to the VRF.
+ type: list
+ elements: str
+ route_export:
+ description:
+ - Adds an export list of extended route target communities to the VRF.
+ type: list
+ elements: str
+ route_import:
+ description:
+ - Adds an import list of extended route target communities to the VRF.
+ type: list
+ elements: str
+ route_both_ipv4:
+ description:
+ - Adds an export and import list of extended route target communities in address-family
+ configuration submode to the VRF.
+ type: list
+ elements: str
+ route_export_ipv4:
+ description:
+ - Adds an export list of extended route target communities in address-family configuration
+ submode to the VRF.
+ type: list
+ elements: str
+ route_import_ipv4:
+ description:
+ - Adds an import list of extended route target communities in address-family configuration
+ submode to the VRF.
+ type: list
+ elements: str
+ route_both_ipv6:
+ description:
+ - Adds an export and import list of extended route target communities in address-family
+ configuration submode to the VRF.
+ type: list
+ elements: str
+ route_export_ipv6:
+ description:
+ - Adds an export list of extended route target communities in address-family configuration
+ submode to the VRF.
+ type: list
+ elements: str
+ route_import_ipv6:
+ description:
+ - Adds an import list of extended route target communities in address-family configuration
+ submode to the VRF.
+ type: list
+ elements: str
+"""
+
+EXAMPLES = """
+- name: Configure a vrf named management
+ cisco.ios.ios_vrf:
+ name: management
+ description: oob mgmt vrf
+ interfaces:
+ - Management1
+
+- name: Remove a vrf named test
+ cisco.ios.ios_vrf:
+ name: test
+ state: absent
+
+- name: Configure set of VRFs and purge any others
+ cisco.ios.ios_vrf:
+ vrfs:
+ - red
+ - blue
+ - green
+ purge: true
+
+- name: Creates a list of import RTs for the VRF with the same parameters
+ cisco.ios.ios_vrf:
+ name: test_import
+ rd: 1:100
+ route_import:
+ - 1:100
+ - 3:100
+
+- name:
+ Creates a list of import RTs in address-family configuration submode for the
+ VRF with the same parameters
+ cisco.ios.ios_vrf:
+ name: test_import_ipv4
+ rd: 1:100
+ route_import_ipv4:
+ - 1:100
+ - 3:100
+
+- name:
+ Creates a list of import RTs in address-family configuration submode for the
+ VRF with the same parameters
+ cisco.ios.ios_vrf:
+ name: test_import_ipv6
+ rd: 1:100
+ route_import_ipv6:
+ - 1:100
+ - 3:100
+
+- name: Creates a list of export RTs for the VRF with the same parameters
+ cisco.ios.ios_vrf:
+ name: test_export
+ rd: 1:100
+ route_export:
+ - 1:100
+ - 3:100
+
+- name:
+ Creates a list of export RTs in address-family configuration submode for the
+ VRF with the same parameters
+ cisco.ios.ios_vrf:
+ name: test_export_ipv4
+ rd: 1:100
+ route_export_ipv4:
+ - 1:100
+ - 3:100
+
+- name:
+ Creates a list of export RTs in address-family configuration submode for the
+ VRF with the same parameters
+ cisco.ios.ios_vrf:
+ name: test_export_ipv6
+ rd: 1:100
+ route_export_ipv6:
+ - 1:100
+ - 3:100
+
+- name:
+ Creates a list of import and export route targets for the VRF with the same
+ parameters
+ cisco.ios.ios_vrf:
+ name: test_both
+ rd: 1:100
+ route_both:
+ - 1:100
+ - 3:100
+
+- name:
+ Creates a list of import and export route targets in address-family configuration
+ submode for the VRF with the same parameters
+ cisco.ios.ios_vrf:
+ name: test_both_ipv4
+ rd: 1:100
+ route_both_ipv4:
+ - 1:100
+ - 3:100
+
+- name:
+ Creates a list of import and export route targets in address-family configuration
+ submode for the VRF with the same parameters
+ cisco.ios.ios_vrf:
+ name: test_both_ipv6
+ rd: 1:100
+ route_both_ipv6:
+ - 1:100
+ - 3:100
+
+"""
+
+RETURN = """
+commands:
+ description: The list of configuration mode commands to send to the device
+ returned: always
+ type: list
+ sample:
+ - vrf definition ansible
+ - description management vrf
+ - rd: 1:100
+start:
+ description: The time the job started
+ returned: always
+ type: str
+ sample: "2016-11-16 10:38:15.126146"
+end:
+ description: The time the job ended
+ returned: always
+ type: str
+ sample: "2016-11-16 10:38:25.595612"
+delta:
+ description: The time elapsed to perform all operations
+ returned: always
+ type: str
+ sample: "0:00:10.469466"
+"""
+import re
+import time
+
+from functools import partial
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.connection import exec_command
+from ansible.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import (
+ NetworkConfig,
+)
+
+from ansible_collections.cisco.ios.plugins.module_utils.network.ios.ios import (
+ get_config,
+ load_config,
+)
+
+
+def get_interface_type(interface):
+ if interface.upper().startswith("ET"):
+ return "ethernet"
+ elif interface.upper().startswith("VL"):
+ return "svi"
+ elif interface.upper().startswith("LO"):
+ return "loopback"
+ elif interface.upper().startswith("MG"):
+ return "management"
+ elif interface.upper().startswith("MA"):
+ return "management"
+ elif interface.upper().startswith("PO"):
+ return "portchannel"
+ elif interface.upper().startswith("NV"):
+ return "nve"
+ else:
+ return "unknown"
+
+
+def add_command_to_vrf(name, cmd, commands):
+ if "vrf definition %s" % name not in commands:
+ commands.extend(["vrf definition %s" % name])
+ commands.append(cmd)
+
+
+def map_obj_to_commands(updates, module):
+ commands = list()
+ for update in updates:
+ want, have = update
+
+ def needs_update(want, have, x):
+ if isinstance(want.get(x), list) and isinstance(have.get(x), list):
+ return (
+ want.get(x)
+ and want.get(x) != have.get(x)
+ and not all(elem in have.get(x) for elem in want.get(x))
+ )
+ return want.get(x) and want.get(x) != have.get(x)
+
+ if want["state"] == "absent":
+ commands.append("no vrf definition %s" % want["name"])
+ continue
+ if not have.get("state"):
+ commands.extend(["vrf definition %s" % want["name"]])
+ ipv6 = (
+ len(
+ [
+ k
+ for k, v in module.params.items()
+ if (k.endswith("_ipv6") or k.endswith("_both")) and v
+ ],
+ )
+ != 0
+ )
+ ipv4 = (
+ len(
+ [
+ k
+ for k, v in module.params.items()
+ if (k.endswith("_ipv4") or k.endswith("_both")) and v
+ ],
+ )
+ != 0
+ )
+ if ipv4:
+ commands.extend(["address-family ipv4", "exit"])
+ if ipv6:
+ commands.extend(["address-family ipv6", "exit"])
+ if needs_update(want, have, "description"):
+ cmd = "description %s" % want["description"]
+ add_command_to_vrf(want["name"], cmd, commands)
+ if needs_update(want, have, "rd"):
+ cmd = "rd %s" % want["rd"]
+ add_command_to_vrf(want["name"], cmd, commands)
+ if needs_update(want, have, "route_import"):
+ for route in want["route_import"]:
+ cmd = "route-target import %s" % route
+ add_command_to_vrf(want["name"], cmd, commands)
+ if needs_update(want, have, "route_export"):
+ for route in want["route_export"]:
+ cmd = "route-target export %s" % route
+ add_command_to_vrf(want["name"], cmd, commands)
+ if needs_update(want, have, "route_import_ipv4"):
+ cmd = "address-family ipv4"
+ add_command_to_vrf(want["name"], cmd, commands)
+ for route in want["route_import_ipv4"]:
+ cmd = "route-target import %s" % route
+ add_command_to_vrf(want["name"], cmd, commands)
+ cmd = "exit-address-family"
+ add_command_to_vrf(want["name"], cmd, commands)
+ if needs_update(want, have, "route_export_ipv4"):
+ cmd = "address-family ipv4"
+ add_command_to_vrf(want["name"], cmd, commands)
+ for route in want["route_export_ipv4"]:
+ cmd = "route-target export %s" % route
+ add_command_to_vrf(want["name"], cmd, commands)
+ cmd = "exit-address-family"
+ add_command_to_vrf(want["name"], cmd, commands)
+ if needs_update(want, have, "route_import_ipv6"):
+ cmd = "address-family ipv6"
+ add_command_to_vrf(want["name"], cmd, commands)
+ for route in want["route_import_ipv6"]:
+ cmd = "route-target import %s" % route
+ add_command_to_vrf(want["name"], cmd, commands)
+ cmd = "exit-address-family"
+ add_command_to_vrf(want["name"], cmd, commands)
+ if needs_update(want, have, "route_export_ipv6"):
+ cmd = "address-family ipv6"
+ add_command_to_vrf(want["name"], cmd, commands)
+ for route in want["route_export_ipv6"]:
+ cmd = "route-target export %s" % route
+ add_command_to_vrf(want["name"], cmd, commands)
+ cmd = "exit-address-family"
+ add_command_to_vrf(want["name"], cmd, commands)
+ if want["interfaces"] is not None:
+ for intf in set(have.get("interfaces", [])).difference(want["interfaces"]):
+ commands.extend(["interface %s" % intf, "no vrf forwarding %s" % want["name"]])
+ for intf in set(want["interfaces"]).difference(have.get("interfaces", [])):
+ cfg = get_config(module)
+ configobj = NetworkConfig(indent=1, contents=cfg)
+ children = configobj["interface %s" % intf].children
+ intf_config = "\n".join(children)
+ commands.extend(["interface %s" % intf, "vrf forwarding %s" % want["name"]])
+ match = re.search("ip address .+", intf_config, re.M)
+ if match:
+ commands.append(match.group())
+ return commands
+
+
+def parse_description(configobj, name):
+ cfg = configobj["vrf definition %s" % name]
+ cfg = "\n".join(cfg.children)
+ match = re.search("description (.+)$", cfg, re.M)
+ if match:
+ return match.group(1)
+
+
+def parse_rd(configobj, name):
+ cfg = configobj["vrf definition %s" % name]
+ cfg = "\n".join(cfg.children)
+ match = re.search("rd (.+)$", cfg, re.M)
+ if match:
+ return match.group(1)
+
+
+def parse_interfaces(configobj):
+ vrf_cfg = "vrf forwarding"
+ interfaces = dict()
+ for intf in set(re.findall("^interface .+", str(configobj), re.M)):
+ for line in configobj[intf].children:
+ if vrf_cfg in line:
+ try:
+ interfaces[line.split()[-1]].append(intf.split(" ")[1])
+ except KeyError:
+ interfaces[line.split()[-1]] = [intf.split(" ")[1]]
+ return interfaces
+
+
+def parse_import(configobj, name):
+ cfg = configobj["vrf definition %s" % name]
+ cfg = "\n".join(cfg.children)
+ matches = re.findall("route-target\\s+import\\s+(.+)", cfg, re.M)
+ return matches
+
+
+def parse_export(configobj, name):
+ cfg = configobj["vrf definition %s" % name]
+ cfg = "\n".join(cfg.children)
+ matches = re.findall("route-target\\s+export\\s+(.+)", cfg, re.M)
+ return matches
+
+
+def parse_both(configobj, name, address_family="global"):
+ rd_pattern = re.compile("(?P<rd>.+:.+)")
+ matches = list()
+ export_match = None
+ import_match = None
+ if address_family == "global":
+ export_match = parse_export(configobj, name)
+ import_match = parse_import(configobj, name)
+ elif address_family == "ipv4":
+ export_match = parse_export_ipv4(configobj, name)
+ import_match = parse_import_ipv4(configobj, name)
+ elif address_family == "ipv6":
+ export_match = parse_export_ipv6(configobj, name)
+ import_match = parse_import_ipv6(configobj, name)
+ if import_match and export_match:
+ for ex in export_match:
+ exrd = rd_pattern.search(ex)
+ exrd = exrd.groupdict().get("rd")
+ for im in import_match:
+ imrd = rd_pattern.search(im)
+ imrd = imrd.groupdict().get("rd")
+ if exrd == imrd:
+ matches.extend([exrd]) if exrd not in matches else None
+ matches.extend([imrd]) if imrd not in matches else None
+ return matches
+
+
+def parse_import_ipv4(configobj, name):
+ cfg = configobj["vrf definition %s" % name]
+ try:
+ subcfg = cfg["address-family ipv4"]
+ subcfg = "\n".join(subcfg.children)
+ matches = re.findall("route-target\\s+import\\s+(.+)", subcfg, re.M)
+ return matches
+ except KeyError:
+ pass
+
+
+def parse_export_ipv4(configobj, name):
+ cfg = configobj["vrf definition %s" % name]
+ try:
+ subcfg = cfg["address-family ipv4"]
+ subcfg = "\n".join(subcfg.children)
+ matches = re.findall("route-target\\s+export\\s+(.+)", subcfg, re.M)
+ return matches
+ except KeyError:
+ pass
+
+
+def parse_import_ipv6(configobj, name):
+ cfg = configobj["vrf definition %s" % name]
+ try:
+ subcfg = cfg["address-family ipv6"]
+ subcfg = "\n".join(subcfg.children)
+ matches = re.findall("route-target\\s+import\\s+(.+)", subcfg, re.M)
+ return matches
+ except KeyError:
+ pass
+
+
+def parse_export_ipv6(configobj, name):
+ cfg = configobj["vrf definition %s" % name]
+ try:
+ subcfg = cfg["address-family ipv6"]
+ subcfg = "\n".join(subcfg.children)
+ matches = re.findall("route-target\\s+export\\s+(.+)", subcfg, re.M)
+ return matches
+ except KeyError:
+ pass
+
+
+def map_config_to_obj(module):
+ config = get_config(module)
+ configobj = NetworkConfig(indent=1, contents=config)
+ match = re.findall("^vrf definition (\\S+)", config, re.M)
+ if not match:
+ return list()
+ instances = list()
+ interfaces = parse_interfaces(configobj)
+ for item in set(match):
+ obj = {
+ "name": item,
+ "state": "present",
+ "description": parse_description(configobj, item),
+ "rd": parse_rd(configobj, item),
+ "interfaces": interfaces.get(item, []),
+ "route_import": parse_import(configobj, item),
+ "route_export": parse_export(configobj, item),
+ "route_both": parse_both(configobj, item),
+ "route_import_ipv4": parse_import_ipv4(configobj, item),
+ "route_export_ipv4": parse_export_ipv4(configobj, item),
+ "route_both_ipv4": parse_both(configobj, item, address_family="ipv4"),
+ "route_import_ipv6": parse_import_ipv6(configobj, item),
+ "route_export_ipv6": parse_export_ipv6(configobj, item),
+ "route_both_ipv6": parse_both(configobj, item, address_family="ipv6"),
+ }
+ instances.append(obj)
+ return instances
+
+
+def get_param_value(key, item, module):
+ # if key doesn't exist in the item, get it from module.params
+ if not item.get(key):
+ value = module.params[key]
+ # if key does exist, do a type check on it to validate it
+ else:
+ value_type = module.argument_spec[key].get("type", "str")
+ type_checker = module._CHECK_ARGUMENT_TYPES_DISPATCHER[value_type]
+ type_checker(item[key])
+ value = item[key]
+ # validate the param value (if validator func exists)
+ validator = globals().get("validate_%s" % key)
+ if validator:
+ validator(value, module)
+ return value
+
+
+def map_params_to_obj(module):
+ vrfs = module.params.get("vrfs")
+ if not vrfs:
+ if not module.params["name"] and module.params["purge"]:
+ return list()
+ elif not module.params["name"]:
+ module.fail_json(msg="name is required")
+ collection = [{"name": module.params["name"]}]
+ else:
+ collection = list()
+ for item in vrfs:
+ if not isinstance(item, dict):
+ collection.append({"name": item})
+ elif "name" not in item:
+ module.fail_json(msg="name is required")
+ else:
+ collection.append(item)
+ objects = list()
+ for item in collection:
+ get_value = partial(get_param_value, item=item, module=module)
+ item["description"] = get_value("description")
+ item["rd"] = get_value("rd")
+ item["interfaces"] = get_value("interfaces")
+ item["state"] = get_value("state")
+ item["route_import"] = get_value("route_import")
+ item["route_export"] = get_value("route_export")
+ item["route_both"] = get_value("route_both")
+ item["route_import_ipv4"] = get_value("route_import_ipv4")
+ item["route_export_ipv4"] = get_value("route_export_ipv4")
+ item["route_both_ipv4"] = get_value("route_both_ipv4")
+ item["route_import_ipv6"] = get_value("route_import_ipv6")
+ item["route_export_ipv6"] = get_value("route_export_ipv6")
+ item["route_both_ipv6"] = get_value("route_both_ipv6")
+ both_addresses_family = ["", "_ipv6", "_ipv4"]
+ for address_family in both_addresses_family:
+ if item["route_both%s" % address_family]:
+ if not item["route_export%s" % address_family]:
+ item["route_export%s" % address_family] = list()
+ if not item["route_import%s" % address_family]:
+ item["route_import%s" % address_family] = list()
+ item["route_export%s" % address_family].extend(
+ get_value("route_both%s" % address_family),
+ )
+ item["route_import%s" % address_family].extend(
+ get_value("route_both%s" % address_family),
+ )
+ item["associated_interfaces"] = get_value("associated_interfaces")
+ objects.append(item)
+ return objects
+
+
+def update_objects(want, have):
+ updates = list()
+ for entry in want:
+ item = next((i for i in have if i["name"] == entry["name"]), None)
+ if all((item is None, entry["state"] == "present")):
+ updates.append((entry, {}))
+ else:
+ for key, value in iteritems(entry):
+ if value:
+ try:
+ if isinstance(value, list):
+ if sorted(value) != sorted(item[key]):
+ if (entry, item) not in updates:
+ updates.append((entry, item))
+ elif value != item[key]:
+ if (entry, item) not in updates:
+ updates.append((entry, item))
+ except TypeError:
+ pass
+ return updates
+
+
+def check_declarative_intent_params(want, module, result):
+ if module.params["associated_interfaces"]:
+ if result["changed"]:
+ time.sleep(module.params["delay"])
+ name = module.params["name"]
+ rc, out, err = exec_command(module, "show vrf | include {0}".format(name))
+ if rc == 0:
+ data = out.strip().split()
+ if not data:
+ return
+ vrf = data[0]
+ interface = data[-1]
+ for w in want:
+ if w["name"] == vrf:
+ if w.get("associated_interfaces") is None:
+ continue
+ for i in w["associated_interfaces"]:
+ if get_interface_type(i) is not get_interface_type(interface):
+ module.fail_json(
+ msg="Interface %s not configured on vrf %s" % (interface, name),
+ )
+
+
+def main():
+ """main entry point for module execution"""
+ argument_spec = dict(
+ vrfs=dict(type="list", elements="raw"),
+ name=dict(),
+ description=dict(),
+ rd=dict(),
+ route_export=dict(type="list", elements="str"),
+ route_import=dict(type="list", elements="str"),
+ route_both=dict(type="list", elements="str"),
+ route_export_ipv4=dict(type="list", elements="str"),
+ route_import_ipv4=dict(type="list", elements="str"),
+ route_both_ipv4=dict(type="list", elements="str"),
+ route_export_ipv6=dict(type="list", elements="str"),
+ route_import_ipv6=dict(type="list", elements="str"),
+ route_both_ipv6=dict(type="list", elements="str"),
+ interfaces=dict(type="list", elements="str"),
+ associated_interfaces=dict(type="list", elements="str"),
+ delay=dict(default=10, type="int"),
+ purge=dict(type="bool", default=False),
+ state=dict(default="present", choices=["present", "absent"]),
+ )
+ mutually_exclusive = [("name", "vrfs")]
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ mutually_exclusive=mutually_exclusive,
+ supports_check_mode=True,
+ )
+ result = {"changed": False}
+ warnings = list()
+ result["warnings"] = warnings
+ want = map_params_to_obj(module)
+ have = map_config_to_obj(module)
+ commands = map_obj_to_commands(update_objects(want, have), module)
+ if module.params["purge"]:
+ want_vrfs = [x["name"] for x in want]
+ have_vrfs = [x["name"] for x in have]
+ for item in set(have_vrfs).difference(want_vrfs):
+ cmd = "no vrf definition %s" % item
+ if cmd not in commands:
+ commands.append(cmd)
+ result["commands"] = commands
+ if commands:
+ if not module.check_mode:
+ load_config(module, commands)
+ result["changed"] = True
+ check_declarative_intent_params(want, module, result)
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/ios/plugins/plugin_utils/__init__.py b/ansible_collections/cisco/ios/plugins/plugin_utils/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/plugin_utils/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/terminal/__init__.py b/ansible_collections/cisco/ios/plugins/terminal/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/terminal/__init__.py
diff --git a/ansible_collections/cisco/ios/plugins/terminal/ios.py b/ansible_collections/cisco/ios/plugins/terminal/ios.py
new file mode 100644
index 000000000..7ba3491ef
--- /dev/null
+++ b/ansible_collections/cisco/ios/plugins/terminal/ios.py
@@ -0,0 +1,144 @@
+#
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+import json
+import re
+
+from ansible.errors import AnsibleConnectionFailure
+from ansible.module_utils._text import to_bytes, to_text
+from ansible.utils.display import Display
+from ansible_collections.ansible.netcommon.plugins.plugin_utils.terminal_base import TerminalBase
+
+
+display = Display()
+
+
+class TerminalModule(TerminalBase):
+ terminal_stdout_re = [re.compile(rb"[\r\n]?[\w\+\-\.:\/\[\]]+(?:\([^\)]+\)){0,3}(?:[>#]) ?$")]
+
+ privilege_level_re = re.compile(r"Current privilege level is (\d+)$")
+
+ terminal_stderr_re = [
+ re.compile(rb"% ?Error"),
+ # re.compile(rb"^% \w+", re.M),
+ re.compile(rb"% ?Bad secret"),
+ re.compile(rb"[\r\n%] Bad passwords"),
+ re.compile(rb"invalid input", re.I),
+ re.compile(rb"(?:incomplete|ambiguous) command", re.I),
+ re.compile(rb"connection timed out", re.I),
+ re.compile(rb"[^\r\n]+ not found"),
+ re.compile(rb"'[^']' +returned error code: ?\d+"),
+ re.compile(rb"Bad mask", re.I),
+ re.compile(rb"% ?(\S+) ?overlaps with ?(\S+)", re.I),
+ re.compile(rb"[%\S] ?Error: ?[\s]+", re.I),
+ re.compile(rb"[%\S] ?Informational: ?[\s]+", re.I),
+ re.compile(rb"Command authorization failed"),
+ re.compile(rb"Command Rejected: ?[\s]+", re.I),
+ re.compile(rb"% General session commands not allowed under the address family", re.I),
+ re.compile(rb"% BGP: Error initializing topology", re.I),
+ ]
+
+ terminal_config_prompt = re.compile(r"^.+\(config(-.*)?\)#$")
+
+ def get_privilege_level(self):
+ try:
+ cmd = {"command": "show privilege"}
+ result = self._exec_cli_command(to_bytes(json.dumps(cmd), errors="surrogate_or_strict"))
+ except AnsibleConnectionFailure as e:
+ raise AnsibleConnectionFailure(
+ "unable to fetch privilege, with error: %s" % (e.message),
+ )
+
+ prompt = self.privilege_level_re.search(result)
+ if not prompt:
+ raise AnsibleConnectionFailure("unable to check privilege level [%s]" % result)
+
+ return int(prompt.group(1))
+
+ def on_open_shell(self):
+ _is_sdWan = False # initialize to false for default IOS execution
+ try:
+ self._exec_cli_command(b"terminal length 0")
+ except AnsibleConnectionFailure:
+ try:
+ self._exec_cli_command(b"screen-length 0") # support to SD-WAN mode
+ _is_sdWan = True
+ except AnsibleConnectionFailure: # fails as length required for handling prompt
+ raise AnsibleConnectionFailure("unable to set terminal parameters")
+ try:
+ if _is_sdWan:
+ self._exec_cli_command(b"screen-width 512") # support to SD-WAN mode
+ else:
+ self._exec_cli_command(b"terminal width 512")
+ try:
+ self._exec_cli_command(b"terminal width 0")
+ except AnsibleConnectionFailure:
+ pass
+ except AnsibleConnectionFailure:
+ display.display(
+ "WARNING: Unable to set terminal/screen width, command responses may be truncated",
+ )
+
+ def on_become(self, passwd=None):
+ if self._get_prompt().endswith(b"#") and self.get_privilege_level() == 15:
+ return
+
+ cmd = {"command": "enable"}
+ if passwd:
+ # Note: python-3.5 cannot combine u"" and r"" together. Thus make
+ # an r string and use to_text to ensure it's text on both py2 and py3.
+ cmd["prompt"] = to_text(r"[\r\n]?(?:.*)?[Pp]assword: ?$", errors="surrogate_or_strict")
+ cmd["answer"] = passwd
+ cmd["prompt_retry_check"] = True
+ try:
+ self._exec_cli_command(to_bytes(json.dumps(cmd), errors="surrogate_or_strict"))
+ prompt = self._get_prompt()
+ privilege_level = self.get_privilege_level()
+ except AnsibleConnectionFailure as e:
+ prompt = self._get_prompt()
+ raise AnsibleConnectionFailure(
+ "failed to elevate privilege to enable mode, at prompt [%s] with error: %s"
+ % (prompt, e.message),
+ )
+
+ if prompt is None or not prompt.endswith(b"#") or privilege_level != 15:
+ raise AnsibleConnectionFailure(
+ "failed to elevate privilege to enable mode, still at level [%d] and prompt [%s]"
+ % (privilege_level, prompt),
+ )
+
+ def on_unbecome(self):
+ prompt = self._get_prompt()
+ if prompt is None:
+ # if prompt is None most likely the terminal is hung up at a prompt
+ return
+
+ if self.get_privilege_level() != 15:
+ return
+
+ if b"(config" in prompt:
+ self._exec_cli_command(b"end")
+ self._exec_cli_command(b"disable")
+
+ elif prompt.endswith(b"#"):
+ self._exec_cli_command(b"disable")