diff --git a/README.md b/README.md index 58187e9ec..4c3094111 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,7 @@ Name | Description [cisco.ios.ios_user](https://github.com/ansible-collections/cisco.ios/blob/main/docs/cisco.ios.ios_user_module.rst)|Module to manage the aggregates of local users. [cisco.ios.ios_vlans](https://github.com/ansible-collections/cisco.ios/blob/main/docs/cisco.ios.ios_vlans_module.rst)|Resource module to configure VLANs. [cisco.ios.ios_vrf](https://github.com/ansible-collections/cisco.ios/blob/main/docs/cisco.ios.ios_vrf_module.rst)|Module to configure VRF definitions. +[cisco.ios.ios_vrf_address_family](https://github.com/ansible-collections/cisco.ios/blob/main/docs/cisco.ios.ios_vrf_address_family_module.rst)|Resource module to configure VRF definitions. [cisco.ios.ios_vrf_global](https://github.com/ansible-collections/cisco.ios/blob/main/docs/cisco.ios.ios_vrf_global_module.rst)|Resource module to configure global VRF definitions. [cisco.ios.ios_vrf_interfaces](https://github.com/ansible-collections/cisco.ios/blob/main/docs/cisco.ios.ios_vrf_interfaces_module.rst)|Manages VRF configuration on interfaces. [cisco.ios.ios_vxlan_vtep](https://github.com/ansible-collections/cisco.ios/blob/main/docs/cisco.ios.ios_vxlan_vtep_module.rst)|Resource module to configure VXLAN VTEP interface. diff --git a/changelogs/fragments/add_vrf_address_family.yaml b/changelogs/fragments/add_vrf_address_family.yaml new file mode 100644 index 000000000..ccab55287 --- /dev/null +++ b/changelogs/fragments/add_vrf_address_family.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - Adds a new module `ios_vrf_address_family` to manage VRFs address families on Cisco IOS devices. diff --git a/docs/cisco.ios.ios_vrf_address_family_module.rst b/docs/cisco.ios.ios_vrf_address_family_module.rst new file mode 100644 index 000000000..74f8e6b88 --- /dev/null +++ b/docs/cisco.ios.ios_vrf_address_family_module.rst @@ -0,0 +1,7459 @@ +.. _cisco.ios.ios_vrf_address_family_module: + + +******************************** +cisco.ios.ios_vrf_address_family +******************************** + +**Resource module to configure VRF definitions.** + + +Version added: 7.0.0 + +.. contents:: + :local: + :depth: 1 + + +Synopsis +-------- +- This module provides declarative management of VRF definitions on Cisco IOS. + + + + +Parameters +---------- + +.. raw:: html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterChoices/DefaultsComments
+
+ config + +
+ list + / elements=dictionary +
+
+ +
A list of device configurations for VRF.
+
+
+ address_families + +
+ list + / elements=dictionary +
+
+ +
Enable address family and enter its config mode - AFI/SAFI configuration
+
+
+ afi + +
+ string +
+
+
    Choices: +
  • ipv4
  • +
  • ipv6
  • +
+
+
Address Family Identifier (AFI)
+
+
+ bgp + +
+ dictionary +
+
+ +
Commands pertaining to BGP configuration.
+
+
+ next_hop + +
+ dictionary +
+
+ +
Next-hop for the routes of a VRF in the backbone.
+
+
+ loopback + +
+ integer +
+
+ +
Loopback interface for next-hop
+
+
+ export + +
+ dictionary +
+
+ +
VRF export
+
+
+ ipv4 + +
+ dictionary +
+
+ +
Address family based VRF export
+
+
+ multicast + +
+ dictionary +
+
+ +
Export prefixes to IPv4 Multicast table
+
+
+ map + +
+ string +
+
+ +
Route-map name
+
+
+ prefix + +
+ integer +
+
+ +
Upper limit on export prefixes without hogging memory
+
+
+ unicast + +
+ dictionary +
+
+ +
Export prefixes to IPv4 Unicast table
+
+
+ allow_evpn + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Allow EVPN routes into global table
+
+
+ map + +
+ string +
+
+ +
Route-map name
+
+
+ prefix + +
+ integer +
+
+ +
Upper limit on export prefixes without hogging memory
+
+
+ map + +
+ string +
+
+ +
Route-map name
+
+
+ import_config + +
+ dictionary +
+
+ +
VRF import
+
+
+ ipv4 + +
+ dictionary +
+
+ +
Address family based VRF import
+
+
+ multicast + +
+ dictionary +
+
+ +
Import prefixes from IPv4 Multicast table
+
+
+ map + +
+ string +
+
+ +
Route-map name
+
+
+ prefix + +
+ integer +
+
+ +
Upper limit on import prefixes without hogging memory
+
+
+ unicast + +
+ dictionary +
+
+ +
Import prefixes from IPv4 Unicast table
+
+
+ allow_evpn + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
allow Global->VRF routes into EVPN
+
+
+ limit + +
+ integer +
+
+ +
Upper limit on import prefixes without hogging memory
+
+
+ map + +
+ string +
+
+ +
Route-map based VRF import
+
+
+ map + +
+ string +
+
+ +
Route-map name
+
+
+ inter_as_hybrid + +
+ dictionary +
+
+ +
Inter AS hybrid mode
+
+
+ csc + +
+ dictionary +
+
+ +
Carrier Supporting Carrier
+
+
+ next_hop + +
+ string +
+
+ +
Next-hop for the routes of a VRF in the backbone.
+
+
+ next_hop + +
+ string +
+
+ +
Next-hop for the routes of a VRF in the backbone.
+
+
+ mdt + +
+ dictionary +
+
+ +
Backbone Multicast Distribution Tree
+
+
+ auto_discovery + +
+ dictionary +
+
+ +
BGP auto-discovery for MVPN
+
+
+ ingress_replication + +
+ dictionary +
+
+ +
BGP auto-discovery for Ingress-Replication
+
+
+ inter_as + +
+ dictionary +
+
+ +
Enable Inter-AS BGP auto-discovery
+
+
+ mdt_hello_enable + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Enable PIM Hellos over MDT interface
+
+
+ mdt_hello_enable + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Enable PIM Hellos over MDT interface
+
+
+ pim + +
+ dictionary +
+
+ +
BGP auto-discovery for PIM
+
+
+ inter_as + +
+ dictionary +
+
+ +
Enable Inter-AS BGP auto-discovery
+
+
+ mdt_hello_enable + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Enable PIM Hellos over MDT interface
+
+
+ pim_tlv_announce + +
+ dictionary +
+
+ +
Announce PIM TLV for data MDT
+
+
+ mdt_hello_enable + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Enable PIM Hellos over MDT interface
+
+
+ mdt_hello_enable + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Enable PIM Hellos over MDT interface
+
+
+ pim_tlv_announce + +
+ dictionary +
+
+ +
Announce PIM TLV for data MDT
+
+
+ mdt_hello_enable + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Enable PIM Hellos over MDT interface
+
+
+ receiver_site + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
BGP receiver only site for MVPN
+
+
+ data + +
+ dictionary +
+
+ +
MDT data trees
+
+
+ ingress_replication + +
+ dictionary +
+
+ +
Use Ingress-Replication to create the data MDT
+
+
+ immediate_switch + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Switch immediately to Data MDT tree
+
+
+ list + +
+ dictionary +
+
+ +
Access-list
+
+
+ access_list_name + +
+ string +
+
+ +
IP Named Extended Access list
+
+
+ access_list_number + +
+ integer +
+
+ +
Access-list number
+
+
+ number + +
+ integer +
+
+ +
Number of data MDT
+
+
+ list + +
+ dictionary +
+
+ +
Access-list
+
+
+ access_list_name + +
+ string +
+
+ +
IP Named Extended Access list
+
+
+ access_list_number + +
+ integer +
+
+ +
Access-list number
+
+
+ threshold + +
+ integer +
+
+ +
MDT switching threshold
+
+
+ default + +
+ dictionary +
+
+ +
Default MDT configuration
+
+
+ ingress_replication + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Use Ingress-Replication for the default MDT
+
+
+ direct + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Direct MDT's
+
+
+ log_reuse + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Event logging for data MDT reuse
+
+
+ mode + +
+ dictionary +
+
+ +
The type of encapsulation
+
+
+ gre + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
GRE encapsulation
+
+
+ mtu + +
+ integer +
+
+ +
The MTU
+
+
+ overlay + +
+ dictionary +
+
+ +
MDT overlay Protocol
+
+
+ bgp + +
+ dictionary +
+
+ +
BGP Overlay signalling
+
+
+ shared_tree_prune_delay + +
+ integer +
+
+ +
Delay before shared tree is pruned at C-RP PE
+
+
+ source_tree_prune_delay + +
+ integer +
+
+ +
Delay before source tree is pruned at C-S PE
+
+
+ use_bgp + +
+ dictionary +
+
+ +
Use BGP for MDT overlay signaling
+
+
+ spt_only + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Enable SPT-only ASM mode
+
+
+ partitioned + +
+ dictionary +
+
+ +
Partitioned Multicast Distribution Tree
+
+
+ ingress_replication + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Use Ingress-Replication for the partitioned MDT
+
+
+ strict_rpf + +
+ dictionary +
+
+ +
Enable strict RPF check
+
+
+ interface + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Interface based strict RPF check
+
+
+ protection + +
+ dictionary +
+
+ +
Configure local repair
+
+
+ local_prefixes + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Enable protection for local prefixes
+
+
+ route_replicate + +
+ dictionary +
+
+ +
Replicate (import) routes from another topology (and another VRF)
+
+
+ from_config + +
+ dictionary +
+
+ +
Replicate routes from another VRF
+
+
+ multicast + +
+ dictionary +
+
+ +
Multicast SAFI
+
+
+ all + +
+ dictionary +
+
+ +
All routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ bgp + +
+ dictionary +
+
+ +
Border Gateway Protocol (BGP)
+
+
+ as_number + +
+ integer +
+
+ +
Autonomous System Number
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ eigrp + +
+ dictionary +
+
+ +
Enhanced Interior Gateway Routing Protocol (EIGRP)
+
+
+ as_number + +
+ integer +
+
+ +
Autonomous System Number
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ isis + +
+ dictionary +
+
+ +
Intermediate System-to-Intermediate System (ISIS)
+
+
+ iso_tag + +
+ string +
+
+ +
ISO routing area tag
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ mobile + +
+ dictionary +
+
+ +
Mobile routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ odr + +
+ dictionary +
+
+ +
On-Demand Stub routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ ospf + +
+ dictionary +
+
+ +
Open Shortest Path First (OSPF)
+
+
+ process_id + +
+ integer +
+
+ +
OSPF process ID
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ rip + +
+ dictionary +
+
+ +
Routing Information Protocol (RIP)
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ static + +
+ dictionary +
+
+ +
Static routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ topology + +
+ dictionary +
+
+ +
Topology name
+
+
+ base + +
+ dictionary +
+
+ +
Base topology
+
+
+ all + +
+ dictionary +
+
+ +
All routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ bgp + +
+ dictionary +
+
+ +
Border Gateway Protocol (BGP)
+
+
+ as_number + +
+ integer +
+
+ +
Autonomous System Number
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ eigrp + +
+ dictionary +
+
+ +
Enhanced Interior Gateway Routing Protocol (EIGRP)
+
+
+ as_number + +
+ integer +
+
+ +
Autonomous System Number
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ isis + +
+ dictionary +
+
+ +
Intermediate System-to-Intermediate System (ISIS)
+
+
+ iso_tag + +
+ string +
+
+ +
ISO routing area tag
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ mobile + +
+ dictionary +
+
+ +
Mobile routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ odr + +
+ dictionary +
+
+ +
On-Demand Stub routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ ospf + +
+ dictionary +
+
+ +
Open Shortest Path First (OSPF)
+
+
+ process_id + +
+ integer +
+
+ +
OSPF process ID
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ rip + +
+ dictionary +
+
+ +
Routing Information Protocol (RIP)
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ static + +
+ dictionary +
+
+ +
Static routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ unicast + +
+ dictionary +
+
+ +
Unicast SAFI
+
+
+ all + +
+ dictionary +
+
+ +
All routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ bgp + +
+ dictionary +
+
+ +
Border Gateway Protocol (BGP)
+
+
+ as_number + +
+ integer +
+
+ +
Autonomous System Number
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ connected + +
+ dictionary +
+
+ +
Connected routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ eigrp + +
+ dictionary +
+
+ +
Enhanced Interior Gateway Routing Protocol (EIGRP)
+
+
+ as_number + +
+ integer +
+
+ +
Autonomous System Number
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ isis + +
+ dictionary +
+
+ +
Intermediate System-to-Intermediate System (ISIS)
+
+
+ iso_tag + +
+ string +
+
+ +
ISO routing area tag
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ mobile + +
+ dictionary +
+
+ +
Mobile routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ odr + +
+ dictionary +
+
+ +
On-Demand Stub routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ ospf + +
+ dictionary +
+
+ +
Open Shortest Path First (OSPF)
+
+
+ process_id + +
+ integer +
+
+ +
OSPF process ID
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ rip + +
+ dictionary +
+
+ +
Routing Information Protocol (RIP)
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ static + +
+ dictionary +
+
+ +
Static routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ vrf + +
+ dictionary +
+
+ +
Specify a source VRF
+
+
+ global + +
+ dictionary +
+
+ +
global VRF
+
+
+ multicast + +
+ dictionary +
+
+ +
Multicast SAFI
+
+
+ all + +
+ dictionary +
+
+ +
All routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ bgp + +
+ dictionary +
+
+ +
Border Gateway Protocol (BGP)
+
+
+ as_number + +
+ integer +
+
+ +
Autonomous System Number
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ eigrp + +
+ dictionary +
+
+ +
Enhanced Interior Gateway Routing Protocol (EIGRP)
+
+
+ as_number + +
+ integer +
+
+ +
Autonomous System Number
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ isis + +
+ dictionary +
+
+ +
Intermediate System-to-Intermediate System (ISIS)
+
+
+ iso_tag + +
+ string +
+
+ +
ISO routing area tag
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ mobile + +
+ dictionary +
+
+ +
Mobile routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ odr + +
+ dictionary +
+
+ +
On-Demand Stub routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ ospf + +
+ dictionary +
+
+ +
Open Shortest Path First (OSPF)
+
+
+ process_id + +
+ integer +
+
+ +
OSPF process ID
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ rip + +
+ dictionary +
+
+ +
Routing Information Protocol (RIP)
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ static + +
+ dictionary +
+
+ +
Static routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ topology + +
+ dictionary +
+
+ +
Topology name
+
+
+ base + +
+ dictionary +
+
+ +
Base topology
+
+
+ all + +
+ dictionary +
+
+ +
All routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ bgp + +
+ dictionary +
+
+ +
Border Gateway Protocol (BGP)
+
+
+ as_number + +
+ integer +
+
+ +
Autonomous System Number
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ eigrp + +
+ dictionary +
+
+ +
Enhanced Interior Gateway Routing Protocol (EIGRP)
+
+
+ as_number + +
+ integer +
+
+ +
Autonomous System Number
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ isis + +
+ dictionary +
+
+ +
Intermediate System-to-Intermediate System (ISIS)
+
+
+ iso_tag + +
+ string +
+
+ +
ISO routing area tag
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ mobile + +
+ dictionary +
+
+ +
Mobile routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ odr + +
+ dictionary +
+
+ +
On-Demand Stub routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ ospf + +
+ dictionary +
+
+ +
Open Shortest Path First (OSPF)
+
+
+ process_id + +
+ integer +
+
+ +
OSPF process ID
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ rip + +
+ dictionary +
+
+ +
Routing Information Protocol (RIP)
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ static + +
+ dictionary +
+
+ +
Static routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ unicast + +
+ dictionary +
+
+ +
Unicast SAFI
+
+
+ all + +
+ dictionary +
+
+ +
All routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ bgp + +
+ dictionary +
+
+ +
Border Gateway Protocol (BGP)
+
+
+ as_number + +
+ integer +
+
+ +
Autonomous System Number
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ connected + +
+ dictionary +
+
+ +
Connected routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ eigrp + +
+ dictionary +
+
+ +
Enhanced Interior Gateway Routing Protocol (EIGRP)
+
+
+ as_number + +
+ integer +
+
+ +
Autonomous System Number
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ isis + +
+ dictionary +
+
+ +
Intermediate System-to-Intermediate System (ISIS)
+
+
+ iso_tag + +
+ string +
+
+ +
ISO routing area tag
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ mobile + +
+ dictionary +
+
+ +
Mobile routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ odr + +
+ dictionary +
+
+ +
On-Demand Stub routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ ospf + +
+ dictionary +
+
+ +
Open Shortest Path First (OSPF)
+
+
+ process_id + +
+ integer +
+
+ +
OSPF process ID
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ rip + +
+ dictionary +
+
+ +
Routing Information Protocol (RIP)
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ static + +
+ dictionary +
+
+ +
Static routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ multicast + +
+ dictionary +
+
+ +
Multicast SAFI
+
+
+ all + +
+ dictionary +
+
+ +
All routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ bgp + +
+ dictionary +
+
+ +
Border Gateway Protocol (BGP)
+
+
+ as_number + +
+ integer +
+
+ +
Autonomous System Number
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ eigrp + +
+ dictionary +
+
+ +
Enhanced Interior Gateway Routing Protocol (EIGRP)
+
+
+ as_number + +
+ integer +
+
+ +
Autonomous System Number
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ isis + +
+ dictionary +
+
+ +
Intermediate System-to-Intermediate System (ISIS)
+
+
+ iso_tag + +
+ string +
+
+ +
ISO routing area tag
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ mobile + +
+ dictionary +
+
+ +
Mobile routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ odr + +
+ dictionary +
+
+ +
On-Demand Stub routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ ospf + +
+ dictionary +
+
+ +
Open Shortest Path First (OSPF)
+
+
+ process_id + +
+ integer +
+
+ +
OSPF process ID
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ rip + +
+ dictionary +
+
+ +
Routing Information Protocol (RIP)
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ static + +
+ dictionary +
+
+ +
Static routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ topology + +
+ dictionary +
+
+ +
Topology name
+
+
+ base + +
+ dictionary +
+
+ +
Base topology
+
+
+ all + +
+ dictionary +
+
+ +
All routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ bgp + +
+ dictionary +
+
+ +
Border Gateway Protocol (BGP)
+
+
+ as_number + +
+ integer +
+
+ +
Autonomous System Number
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ eigrp + +
+ dictionary +
+
+ +
Enhanced Interior Gateway Routing Protocol (EIGRP)
+
+
+ as_number + +
+ integer +
+
+ +
Autonomous System Number
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ isis + +
+ dictionary +
+
+ +
Intermediate System-to-Intermediate System (ISIS)
+
+
+ iso_tag + +
+ string +
+
+ +
ISO routing area tag
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ mobile + +
+ dictionary +
+
+ +
Mobile routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ odr + +
+ dictionary +
+
+ +
On-Demand Stub routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ ospf + +
+ dictionary +
+
+ +
Open Shortest Path First (OSPF)
+
+
+ process_id + +
+ integer +
+
+ +
OSPF process ID
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ rip + +
+ dictionary +
+
+ +
Routing Information Protocol (RIP)
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ static + +
+ dictionary +
+
+ +
Static routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ name + +
+ string +
+
+ +
Source VRF name
+
+
+ unicast + +
+ dictionary +
+
+ +
Unicast SAFI
+
+
+ all + +
+ dictionary +
+
+ +
All routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ bgp + +
+ dictionary +
+
+ +
Border Gateway Protocol (BGP)
+
+
+ as_number + +
+ integer +
+
+ +
Autonomous System Number
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ connected + +
+ dictionary +
+
+ +
Connected routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ eigrp + +
+ dictionary +
+
+ +
Enhanced Interior Gateway Routing Protocol (EIGRP)
+
+
+ as_number + +
+ integer +
+
+ +
Autonomous System Number
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ isis + +
+ dictionary +
+
+ +
Intermediate System-to-Intermediate System (ISIS)
+
+
+ iso_tag + +
+ string +
+
+ +
ISO routing area tag
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ mobile + +
+ dictionary +
+
+ +
Mobile routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ odr + +
+ dictionary +
+
+ +
On-Demand Stub routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ ospf + +
+ dictionary +
+
+ +
Open Shortest Path First (OSPF)
+
+
+ process_id + +
+ integer +
+
+ +
OSPF process ID
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ rip + +
+ dictionary +
+
+ +
Routing Information Protocol (RIP)
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ static + +
+ dictionary +
+
+ +
Static routes
+
+
+ route_map + +
+ string +
+
+ +
Route-map reference
+
+
+ recursion_policy + +
+ dictionary +
+
+ +
Route replication recursion policy
+
+
+ destination + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Recurse in destination topology
+
+
+ route_target + +
+ dictionary +
+
+ +
Specify Target VPN Extended Communities.
+
+
+ both + +
+ string +
+
+ +
Both export and import Target-VPN community
+
+
+ export + +
+ string +
+
+ +
Export Target-VPN community.
+
+
+ import_config + +
+ string +
+
+ +
Export Target-VPN community.
+
+
+ safi + +
+ string +
+
+
    Choices: +
  • multicast
  • +
  • unicast
  • +
+
+
Address Family modifier
+
+
+ name + +
+ string + / required +
+
+ +
Name of the VRF.
+
+
+ running_config + +
+ string +
+
+ +
This option is used only with state parsed.
+
The value of this option should be the output received from the IOS device by executing the command show running-config vrf.
+
The state parsed reads the configuration from 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 parsed key within the result.
+
+
+ state + +
+ string +
+
+
    Choices: +
  • parsed
  • +
  • gathered
  • +
  • deleted
  • +
  • merged ←
  • +
  • replaced
  • +
  • rendered
  • +
  • overridden
  • +
+
+
The state the configuration should be left in
+
The states rendered, gathered and parsed does not perform any change on the device.
+
The state rendered will transform the configuration in config option to platform specific CLI commands which will be returned in the rendered key within the result. For state rendered active connection to remote host is not required.
+
The state 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 gathered key within the result.
+
The state parsed reads the configuration from running_config option and transforms it into JSON format as per the resource module parameters and the value is returned in the parsed key within the result. The value of running_config option should be the same format as the output of command show running-config vrf. connection to remote host is not required.
+
+
+ + +Notes +----- + +.. note:: + - Tested against Cisco IOSXE version 17.3 on CML. + - This module works with connection ``network_cli``. See https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html + + + +Examples +-------- + +.. code-block:: yaml + + # Using merged + # + # Before state: + # ------------- + # + # RP/0/0/CPU0:ios#show running-config | section ^vrf + # vrf defnition test + # + + - name: Merge provided configuration with device configuration + cisco.ios.ios_vrf_address_family: + config: + - name: test1 + address_families: + - afi: "ipv4" + safi: "unicast" + bgp: + next_hop: + loopback: 40 + export: + ipv4: + multicast: + map: "single" + prefix: 345 + unicast: + allow_evpn: true + map: "test-map" + prefix: 67 + map: "testing-map" + import_config: + ipv4: + multicast: + map: "import-map" + prefix: 89 + unicast: + allow_evpn: true + limit: 12 + map: "ran-map" + map: "import-map" + state: merged + + # Task Output: + # ------------ + # + # before: [] + # + # commands: + # - vrf definition test1 + # - address-family ipv4 unicast + # - bgp next-hop loopback 40 + # - export map "testing-map" + # - export ipv4 multicast 345 map "single" + # - export ipv4 unicast 67 map "test-map" allow-evpn + # - import map "import-map" + # - import ipv4 multicast 89 map "import-map" + # - import ipv4 unicast 12 map "ran-map" allow-evpn + # + # after: + # - name: test1 + # address_families: + # - afi: "ipv4" + # safi: "unicast" + # bgp: + # next_hop: + # loopback: 40 + # export: + # ipv4: + # multicast: + # map: "single" + # prefix: 345 + # unicast: + # allow_evpn: true + # map: "test-map" + # prefix: 67 + # map: "testing-map" + # import_config: + # ipv4: + # multicast: + # map: "import-map" + # prefix: 89 + # unicast: + # allow_evpn: true + # limit: 12 + # map: "ran-map" + # map: "import-map" + # + # After state: + # ------------ + # + # RP/0/0/CPU0:ios#show running-config | section ^vrf + # vrf definition test1 + # address-family ipv4 unicast + # bgp next-hop loopback 40 + # export map "testing-map" + # export ipv4 multicast 345 map "single" + # export ipv4 unicast 67 map "test-map" allow-evpn + # import map "import-map" + # import ipv4 multicast 89 map "import-map" + # import ipv4 unicast 12 map "ran-map" allow-evpn + + # Using replaced + # + # Before state: + # ------------- + # + # RP/0/0/CPU0:ios#show running-config | section ^vrf + # vrf definition test1 + # address-family ipv4 unicast + # bgp next-hop loopback 40 + # export map "testing-map" + # export ipv4 multicast 345 map "single" + # export ipv4 unicast 67 map "test-map" allow-evpn + # import map "import-map" + # import ipv4 multicast 89 map "import-map" + # import ipv4 unicast 12 map "ran-map" allow-evpn + + - name: Replace the provided configuration with the existing running configuration + cisco.ios.ios_vrf_address_family: + config: + - name: test1 + address_families: + - afi: "ipv4" + safi: "unicast" + bgp: + next_hop: + loopback: 40 + export: + ipv4: + multicast: + map: "single" + prefix: 345 + unicast: + allow_evpn: true + map: "test-map" + prefix: 67 + map: "testing-map" + import_config: + ipv4: + multicast: + map: "import-map" + prefix: 89 + unicast: + allow_evpn: true + limit: 12 + map: "ran-map" + map: "import-map" + state: replaced + + # Task Output: + # ------------ + # + # before: + # - name: test1 + # address_families: + # - afi: "ipv4" + # safi: "unicast" + # bgp: + # next_hop: + # loopback: 40 + # export: + # ipv4: + # multicast: + # map: "single" + # prefix: 345 + # unicast: + # allow_evpn: true + # map: "test-map" + # prefix: 67 + # map: "testing-map" + # import_config: + # ipv4: + # multicast: + # map: "import-map" + # prefix: 89 + # unicast: + # allow_evpn: true + # limit: 12 + # map: "ran-map" + # map: "import-map" + # + # commands: + # - vrf definition test1 + # - address-family ipv4 unicast + # - bgp next-hop loopback 40 + # - export map "testing-map" + # - export ipv4 multicast 345 map "single" + # - export ipv4 unicast 67 map "test-map" allow-evpn + # - import map "import-map" + # - import ipv4 multicast 89 map "import-map" + # - import ipv4 unicast 12 map "ran-map" allow-evpn + # + # after: + # - name: VRF1 + # address_families: + # - afi: "ipv4" + # safi: "unicast" + # bgp: + # next_hop: + # loopback: 23 + # export: + # ipv4: + # multicast: + # map: "single" + # prefix: 33 + # unicast: + # allow_evpn: true + # map: "test-map1" + # prefix: 7 + # map: "testing-map" + # import_config: + # ipv4: + # multicast: + # map: "import-map1" + # prefix: 89 + # unicast: + # allow_evpn: true + # limit: 12 + # map: "ran-map" + # map: "import-map" + # + # After state: + # ------------ + # + # RP/0/RP0/CPU0:ios(config)#show running-config vrf + # vrf definition VRF1 + # address-family ipv4 unicast + # bgp next-hop loopback 23 + # export map "testing-map" + # export ipv4 multicast 345 map "single" + # export ipv4 unicast 67 map "test-map1" allow-evpn + # import map "import-map" + # import ipv4 multicast 89 map "import-map1" + # import ipv4 unicast 12 map "ran-map" allow-evpn + + # Using overridden + # + # Before state: + # ------------- + # + # RP/0/RP0/CPU0:ios(config)#show running-config | section ^vrf + # vrf definition test1 + # address-family ipv4 unicast + # bgp next-hop loopback 40 + # export map "testing-map" + # export ipv4 multicast 345 map "single" + # export ipv4 unicast 67 map "test-map" allow-evpn + # import map "import-map" + # import ipv4 multicast 89 map "import-map" + # import ipv4 unicast 12 map "ran-map" allow-evpn + + - name: Override the provided configuration with the existing running configuration + cisco.ios.ios_vrf_address_family: + state: overridden + config: + - name: VRF7 + address_families: + - afi: "ipv4" + safi: "unicast" + bgp: + next_hop: + loopback: 89 + export: + ipv4: + multicast: + map: "single" + prefix: 345 + unicast: + allow_evpn: true + map: "test-map" + prefix: 67 + map: "testing-map" + import_config: + ipv4: + multicast: + map: "import-map" + prefix: 89 + unicast: + allow_evpn: true + limit: 12 + map: "ran-map" + map: "import-map" + # Task Output: + # ------------ + # + # before: + # - name: test1 + # address_families: + # - afi: "ipv4" + # safi: "unicast" + # bgp: + # next_hop: + # loopback: 40 + # export: + # ipv4: + # multicast: + # map: "single" + # prefix: 345 + # unicast: + # allow_evpn: true + # map: "test-map" + # prefix: 67 + # map: "testing-map" + # import_config: + # ipv4: + # multicast: + # map: "import-map" + # prefix: 89 + # unicast: + # allow_evpn: true + # limit: 12 + # map: "ran-map" + # map: "import-map" + # + # commands: + # - vrf definition VRF7 + # - address-family ipv4 unicast + # - bgp next-hop loopback 89 + # - export map "testing-map" + # - export ipv4 multicast 345 map "single" + # - export ipv4 unicast 67 map "test-map" allow-evpn + # - import map "import-map" + # - import ipv4 multicast 89 map "import-map" + # - import ipv4 unicast 12 map "ran-map" allow-evpn + + # + # After state: + # ------------- + # RP/0/RP0/CPU0:ios(config)#show running-config vrf + # vrf definition VRF4 + # vrf definition VRF7 + # address-family ipv4 unicast + # bgp next-hop loopback 89 + # export map "testing-map" + # export ipv4 multicast 345 map "single" + # export ipv4 unicast 67 map "test-map" allow-evpn + # import map "import-map" + # import ipv4 multicast 89 map "import-map1" + # import ipv4 unicast 12 map "ran-map" allow-evpn + + # Using deleted + # + # Before state: + # ------------- + # + # RP/0/RP0/CPU0:ios(config)#show running-config | section ^vrf + # vrf definition VRF4 + # vrf definition VRF6 + # address-family ipv4 unicast + # bgp next-hop loopback 40 + # import map "import-map" + # import ipv4 multicast 89 map "import-map" + # import ipv4 unicast 12 map "ran-map" allow-evpn + # export map "testing-map" + # export ipv4 multicast 345 map "single" + # export ipv4 unicast 67 map "test-map" allow-evpn + # vrf definition VRF7 + + - name: Delete the provided configuration + cisco.ios.ios_vrf_address_family: + config: + state: deleted + + # Task Output: + # ------------ + # + # before: + # - name: VRF4 + # - name: VRF6 + # address_families: + # - afi: "ipv4" + # safi: "unicast" + # bgp: + # next_hop: + # loopback: 23 + # import_config: + # ipv4: + # multicast: + # map: "import-map" + # prefix: 89 + # unicast: + # map: "ran-map" + # limit: 12 + # allow_evpn: true + # map: "import-map" + # export: + # ipv4: + # multicast: + # map: "single" + # prefix: 345 + # unicast: + # map: "test-map" + # prefix: 67 + # allow_evpn: true + # map: "testing-map" + # - name: VRF7 + + # commands: + # - vrf definition VRF4 + # - vrf definition VRF6 + # - no address-family ipv4 unicast + # - vrf definition VRF7 + # + # after: + # - name: VRF4 + # - name: VRF6 + # - name: VRF7 + # + # After state: + # ------------ + # + # RP/0/RP0/CPU0:ios(config)#show running-config | section ^vrf + # vrf definition VRF4 + # vrf definition VRF6 + # vrf definition VRF7 + + # Using rendered + # + - name: Render provided configuration with device configuration + cisco.ios.ios_vrf_address_family: + config: + - name: test + address_families: + - afi: "ipv4" + safi: "unicast" + bgp: + next_hop: + loopback: 23 + import_config: + ipv4: + multicast: + map: "import-map" + prefix: 89 + unicast: + map: "ran-map" + limit: 12 + allow_evpn: true + map: "import-map" + export: + ipv4: + multicast: + map: "single" + prefix: 345 + unicast: + map: "test-map" + prefix: 67 + allow_evpn: true + map: "testing-map" + state: rendered + + # Task Output: + # ------------ + # + # rendered: + # - vrf definition test + # - address-family ipv4 unicast + # - bgp next-hop loopback 23 + # - import map "import-map" + # - import ipv4 multicast 89 map "import-map" + # - import ipv4 unicast 12 map "ran-map" allow-evpn + # - export map "testing-map" + # - export ipv4 multicast 345 map "single" + # - export ipv4 unicast 67 map "test-map" allow-evpn + + # Using gathered + # + # Before state: + # ------------- + # + # RP/0/RP0/CPU0:ios(config)#show running-config | section ^vrf + # vrf definition test1 + # address-family ipv4 unicast + # bgp next-hop loopback 40 + # import map "import-map" + # import ipv4 multicast 89 map "import-map" + # import ipv4 unicast 12 map "ran-map" allow-evpn + # export map "testing-map" + # export ipv4 multicast 345 map "single" + # export ipv4 unicast 67 map "test-map" allow-evpn + + - name: Gather existing running configuration + cisco.ios.ios_vrf_address_family: + state: gathered + + # Task Output: + # ------------ + # + # gathered: + # - name: test1 + # address_families: + # - afi: "ipv4" + # safi: "unicast" + # bgp: + # next_hop: + # loopback: 40 + # export: + # ipv4: + # multicast: + # map: "single" + # prefix: 345 + # unicast: + # allow_evpn: true + # map: "test-map" + # prefix: 67 + # map: "testing-map" + # import_config: + # ipv4: + # multicast: + # map: "import-map" + # prefix: 89 + # unicast: + # allow_evpn: true + # limit: 12 + # map: "ran-map" + # map: "import-map" + + # Using parsed + # + # File: parsed.cfg + # ---------------- + # + # vrf definition test + # address-family ipv4 unicast + # bgp next-hop loopback 23 + # import map "import-map" + # import ipv4 multicast 89 map "import-map" + # import ipv4 unicast 12 map "ran-map" allow-evpn + # export map "testing-map" + # export ipv4 multicast 345 map "single" + # export ipv4 unicast 67 map "test-map" allow-evpn + + - name: Parse the provided configuration + cisco.ios.ios_vrf_address_family: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + + # Task Output: + # ------------ + # + # parsed: + # - address_families: + # - afi: ipv4 + # bgp: + # next_hop: + # loopback: 40 + # export: + # ipv4: + # multicast: + # map: "single" + # prefix: 345 + # unicast: + # allow_evpn: true + # map: "test-map" + # prefix: 67 + # map: "testing-map" + # import_config: + # ipv4: + # multicast: + # map: "import-map" + # prefix: 89 + # unicast: + # allow_evpn: true + # limit: 12 + # map: "ran-map" + # safi: unicast + # name: test + + + +Return Values +------------- +Common return values are documented `here `_, the following are the fields unique to this module: + +.. raw:: html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyReturnedDescription
+
+ after + +
+ list +
+
when changed +
The resulting configuration after module execution.
+
+
Sample:
+
This output will always be in the same format as the module argspec.
+
+
+ before + +
+ list +
+
when state is merged, replaced, overridden, deleted or purged +
The configuration prior to the module execution.
+
+
Sample:
+
This output will always be in the same format as the module argspec.
+
+
+ commands + +
+ list +
+
when state is merged, replaced, overridden, deleted +
The set of commands pushed to the remote device.
+
+
Sample:
+
['vrf definition test1', 'address-family ipv4 unicast', 'bgp next-hop loopback 40', 'export map "testing-map"', 'export ipv4 multicast 345 map "testmap"']
+
+
+ gathered + +
+ list +
+
when state is gathered +
Facts about the network resource gathered from the remote device as structured data.
+
+
Sample:
+
This output will always be in the same format as the module argspec.
+
+
+ parsed + +
+ list +
+
when state is parsed +
The device native config provided in running_config option parsed into structured data as per module argspec.
+
+
Sample:
+
This output will always be in the same format as the module argspec.
+
+
+ rendered + +
+ list +
+
when state is rendered +
The provided configuration in the task rendered in device-native format (offline).
+
+
Sample:
+
['vrf definition test1', 'address-family ipv4 unicast', 'bgp next-hop loopback 40', 'import map "testing-map"', 'export ipv4 multicast 345 map "testmap"']
+
+

+ + +Status +------ + + +Authors +~~~~~~~ + +- Ruchi Pakhle (@Ruchip16) diff --git a/meta/runtime.yml b/meta/runtime.yml index 3219ce3c6..3ccab7553 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -67,6 +67,8 @@ plugin_routing: redirect: cisco.ios.vrf_interfaces vxlan_vtep: redirect: cisco.ios.ios_vxlan_vtep + vrf_address_family: + redirect: cisco.ios.ios_vrf_address_family vrf_global: redirect: cisco.ios.ios_vrf_global requires_ansible: ">=2.15.0" diff --git a/plugins/action/vrf_address_family.py b/plugins/action/vrf_address_family.py new file mode 120000 index 000000000..7747aa9dd --- /dev/null +++ b/plugins/action/vrf_address_family.py @@ -0,0 +1 @@ +ios.py \ No newline at end of file diff --git a/plugins/module_utils/network/ios/argspec/vrf_address_family/__init__.py b/plugins/module_utils/network/ios/argspec/vrf_address_family/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/module_utils/network/ios/argspec/vrf_address_family/vrf_address_family.py b/plugins/module_utils/network/ios/argspec/vrf_address_family/vrf_address_family.py new file mode 100644 index 000000000..aed0b63e9 --- /dev/null +++ b/plugins/module_utils/network/ios/argspec/vrf_address_family/vrf_address_family.py @@ -0,0 +1,1153 @@ +# -*- coding: utf-8 -*- +# Copyright 2024 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_vrf_address_family module +""" + + +class Vrf_address_familyArgs(object): # pylint: disable=R0903 + """The arg spec for the ios_vrf_address_family module""" + + argument_spec = { + "config": { + "type": "list", + "elements": "dict", + "options": { + "name": {"type": "str", "required": True}, + "address_families": { + "type": "list", + "elements": "dict", + "options": { + "afi": {"type": "str", "choices": ["ipv4", "ipv6"]}, + "safi": { + "type": "str", + "choices": ["multicast", "unicast"], + }, + "bgp": { + "type": "dict", + "options": { + "next_hop": { + "type": "dict", + "options": {"loopback": {"type": "int"}}, + }, + }, + }, + "export": { + "type": "dict", + "options": { + "map": {"type": "str"}, + "ipv4": { + "type": "dict", + "options": { + "multicast": { + "type": "dict", + "options": { + "prefix": {"type": "int"}, + "map": {"type": "str"}, + }, + }, + "unicast": { + "type": "dict", + "options": { + "prefix": {"type": "int"}, + "map": {"type": "str"}, + "allow_evpn": {"type": "bool"}, + }, + }, + }, + }, + }, + }, + "import_config": { + "type": "dict", + "options": { + "map": {"type": "str"}, + "ipv4": { + "type": "dict", + "options": { + "multicast": { + "type": "dict", + "options": { + "prefix": {"type": "int"}, + "map": {"type": "str"}, + }, + }, + "unicast": { + "type": "dict", + "options": { + "limit": {"type": "int"}, + "map": {"type": "str"}, + "allow_evpn": {"type": "bool"}, + }, + }, + }, + }, + }, + }, + "inter_as_hybrid": { + "type": "dict", + "options": { + "csc": { + "type": "dict", + "options": {"next_hop": {"type": "str"}}, + }, + "next_hop": {"type": "str"}, + }, + }, + "mdt": { + "type": "dict", + "options": { + "auto_discovery": { + "type": "dict", + "options": { + "ingress_replication": { + "type": "dict", + "options": { + "inter_as": { + "type": "dict", + "options": { + "mdt_hello_enable": { + "type": "bool", + }, + }, + }, + "mdt_hello_enable": { + "type": "bool", + }, + }, + }, + "pim": { + "type": "dict", + "options": { + "inter_as": { + "type": "dict", + "options": { + "mdt_hello_enable": { + "type": "bool", + }, + "pim_tlv_announce": { + "type": "dict", + "options": { + "mdt_hello_enable": { + "type": "bool", + }, + }, + }, + }, + }, + "mdt_hello_enable": { + "type": "bool", + }, + "pim_tlv_announce": { + "type": "dict", + "options": { + "mdt_hello_enable": { + "type": "bool", + }, + }, + }, + }, + }, + "receiver_site": {"type": "bool"}, + }, + }, + "data": { + "type": "dict", + "options": { + "ingress_replication": { + "type": "dict", + "options": { + "number": {"type": "int"}, + "immediate_switch": { + "type": "bool", + }, + "list": { + "type": "dict", + "options": { + "access_list_number": { + "type": "int", + }, + "access_list_name": { + "type": "str", + }, + }, + }, + }, + }, + "list": { + "type": "dict", + "options": { + "access_list_number": { + "type": "int", + }, + "access_list_name": { + "type": "str", + }, + }, + }, + "threshold": {"type": "int"}, + }, + }, + "default": { + "type": "dict", + "options": { + "ingress_replication": {"type": "bool"}, + }, + }, + "direct": {"type": "bool"}, + "log_reuse": {"type": "bool"}, + "mode": { + "type": "dict", + "options": {"gre": {"type": "bool"}}, + }, + "mtu": {"type": "int"}, + "overlay": { + "type": "dict", + "options": { + "bgp": { + "type": "dict", + "options": { + "shared_tree_prune_delay": { + "type": "int", + }, + "source_tree_prune_delay": { + "type": "int", + }, + }, + }, + "use_bgp": { + "type": "dict", + "options": { + "spt_only": {"type": "bool"}, + }, + }, + }, + }, + "partitioned": { + "type": "dict", + "options": { + "ingress_replication": {"type": "bool"}, + }, + }, + "strict_rpf": { + "type": "dict", + "options": {"interface": {"type": "bool"}}, + }, + }, + }, + "protection": { + "type": "dict", + "options": {"local_prefixes": {"type": "bool"}}, + }, + "route_replicate": { + "type": "dict", + "options": { + "recursion_policy": { + "type": "dict", + "options": {"destination": {"type": "bool"}}, + }, + "from_config": { + "type": "dict", + "options": { + "multicast": { + "type": "dict", + "options": { + "all": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "bgp": { + "type": "dict", + "options": { + "as_number": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "eigrp": { + "type": "dict", + "options": { + "as_number": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "isis": { + "type": "dict", + "options": { + "iso_tag": {"type": "str"}, + "route_map": { + "type": "str", + }, + }, + }, + "mobile": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "odr": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "ospf": { + "type": "dict", + "options": { + "process_id": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "rip": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "static": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "topology": { + "type": "dict", + "options": { + "base": { + "type": "dict", + "options": { + "all": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "bgp": { + "type": "dict", + "options": { + "as_number": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "eigrp": { + "type": "dict", + "options": { + "as_number": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "isis": { + "type": "dict", + "options": { + "iso_tag": { + "type": "str", + }, + "route_map": { + "type": "str", + }, + }, + }, + "mobile": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "odr": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "ospf": { + "type": "dict", + "options": { + "process_id": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "rip": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "static": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + }, + }, + }, + }, + }, + }, + "unicast": { + "type": "dict", + "options": { + "all": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "bgp": { + "type": "dict", + "options": { + "as_number": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "connected": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "eigrp": { + "type": "dict", + "options": { + "as_number": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "isis": { + "type": "dict", + "options": { + "iso_tag": {"type": "str"}, + "route_map": { + "type": "str", + }, + }, + }, + "mobile": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "odr": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "ospf": { + "type": "dict", + "options": { + "process_id": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "rip": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "static": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + }, + }, + "vrf": { + "type": "dict", + "options": { + "name": {"type": "str"}, + "multicast": { + "type": "dict", + "options": { + "all": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "bgp": { + "type": "dict", + "options": { + "as_number": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "eigrp": { + "type": "dict", + "options": { + "as_number": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "isis": { + "type": "dict", + "options": { + "iso_tag": { + "type": "str", + }, + "route_map": { + "type": "str", + }, + }, + }, + "mobile": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "odr": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "ospf": { + "type": "dict", + "options": { + "process_id": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "rip": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "static": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "topology": { + "type": "dict", + "options": { + "base": { + "type": "dict", + "options": { + "all": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "bgp": { + "type": "dict", + "options": { + "as_number": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "eigrp": { + "type": "dict", + "options": { + "as_number": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "isis": { + "type": "dict", + "options": { + "iso_tag": { + "type": "str", + }, + "route_map": { + "type": "str", + }, + }, + }, + "mobile": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "odr": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "ospf": { + "type": "dict", + "options": { + "process_id": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "rip": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "static": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + }, + }, + }, + }, + }, + }, + "unicast": { + "type": "dict", + "options": { + "all": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "bgp": { + "type": "dict", + "options": { + "as_number": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "connected": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "eigrp": { + "type": "dict", + "options": { + "as_number": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "isis": { + "type": "dict", + "options": { + "iso_tag": { + "type": "str", + }, + "route_map": { + "type": "str", + }, + }, + }, + "mobile": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "odr": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "ospf": { + "type": "dict", + "options": { + "process_id": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "rip": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "static": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + }, + }, + "global": { + "type": "dict", + "options": { + "multicast": { + "type": "dict", + "options": { + "all": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "bgp": { + "type": "dict", + "options": { + "as_number": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "eigrp": { + "type": "dict", + "options": { + "as_number": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "isis": { + "type": "dict", + "options": { + "iso_tag": { + "type": "str", + }, + "route_map": { + "type": "str", + }, + }, + }, + "mobile": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "odr": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "ospf": { + "type": "dict", + "options": { + "process_id": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "rip": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "static": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "topology": { + "type": "dict", + "options": { + "base": { + "type": "dict", + "options": { + "all": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "bgp": { + "type": "dict", + "options": { + "as_number": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "eigrp": { + "type": "dict", + "options": { + "as_number": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "isis": { + "type": "dict", + "options": { + "iso_tag": { + "type": "str", + }, + "route_map": { + "type": "str", + }, + }, + }, + "mobile": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "odr": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "ospf": { + "type": "dict", + "options": { + "process_id": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "rip": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "static": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + }, + }, + }, + }, + }, + }, + "unicast": { + "type": "dict", + "options": { + "all": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "bgp": { + "type": "dict", + "options": { + "as_number": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "connected": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "eigrp": { + "type": "dict", + "options": { + "as_number": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "isis": { + "type": "dict", + "options": { + "iso_tag": { + "type": "str", + }, + "route_map": { + "type": "str", + }, + }, + }, + "mobile": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "odr": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "ospf": { + "type": "dict", + "options": { + "process_id": { + "type": "int", + }, + "route_map": { + "type": "str", + }, + }, + }, + "rip": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + "static": { + "type": "dict", + "options": { + "route_map": { + "type": "str", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "route_target": { + "type": "dict", + "options": { + "export": {"type": "str"}, + "import_config": {"type": "str"}, + "both": {"type": "str"}, + }, + }, + }, + }, + }, + }, + "running_config": {"type": "str"}, + "state": { + "choices": [ + "parsed", + "gathered", + "deleted", + "merged", + "replaced", + "rendered", + "overridden", + ], + "default": "merged", + "type": "str", + }, + } # pylint: disable=C0301 diff --git a/plugins/module_utils/network/ios/config/vrf_address_family/__init__.py b/plugins/module_utils/network/ios/config/vrf_address_family/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/module_utils/network/ios/config/vrf_address_family/vrf_address_family.py b/plugins/module_utils/network/ios/config/vrf_address_family/vrf_address_family.py new file mode 100644 index 000000000..9f061a760 --- /dev/null +++ b/plugins/module_utils/network/ios/config/vrf_address_family/vrf_address_family.py @@ -0,0 +1,217 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2024 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_vrf_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 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.vrf_address_family import ( + Vrf_address_familyTemplate, +) + + +class Vrf_address_family(ResourceModule): + """ + The ios_vrf_address_family config class + """ + + def __init__(self, module): + super(Vrf_address_family, self).__init__( + empty_fact_val={}, + facts_module=Facts(module), + module=module, + resource="vrf_address_family", + tmplt=Vrf_address_familyTemplate(), + ) + self.parsers = [ + "address_family", + "bgp.next_hop.loopback", + "export.map", + "import_config.map", + "export.ipv4.multicast", + "export.ipv4.unicast.allow_evpn", + "import_config.ipv4.multicast", + "import_config.ipv4.unicast", + "inter_as_hybrid.csc.next_hop", + "inter_as_hybrid.next_hop", + "mdt.auto_discovery.ingress_replication.inter_as.mdt_hello_enable", + "mdt.auto_discovery.pim.inter_as.mdt_hello_enable", + "mdt.auto_discovery.pim.inter_as.pim_tlv_announce.mdt_hello_enable", + "mdt.auto_discovery.ingress_replication.mdt_hello_enable", + "mdt.auto_discovery.pim.mdt_hello_enable", + "mdt.auto_discovery.pim.pim_tlv_announce.mdt_hello_enable", + "mdt.auto_discovery.receiver_site", + "mdt.data.ingress_replication.number", + "mdt.data.ingress_replication.immediate_switch", + "mdt.data.ingress_replication.number.immediate_switch", + "mdt.data.list.access_list", + "mdt.data.list.access_list_name", + "mdt.data.threshold", + "mdt.default_ingress_replication", + "mdt.direct", + "mdt.log_reuse", + "mdt.mode.gre", + "mdt.mtu.value", + "mdt.overlay.bgp.shared_tree_prune_delay", + "mdt.overlay.bgp.source_tree_prune_delay", + "mdt.overlay.use_bgp_spt_only", + "mdt.partitioned.ingress_replication", + "mdt.strict_rpf_interface", + "protection.local_prefixes", + "route_replicate.recursion_policy.destination", + "route_replicate.from.unicast.all.route_map", + "route_replicate.from.unicast.bgp.asn.route_map", + "route_replicate.from.unicast.connected.route_map", + "route_replicate.from.unicast.eigrp.asn.route_map", + "route_replicate.from.unicast.isis.route_map", + "route_replicate.from.unicast.mobile.route_map", + "route_replicate.from.unicast.odr.route_map", + "route_replicate.from.unicast.ospf.id.route_map", + "route_replicate.from.unicast.rip.route_map", + "route_replicate.from.unicast.static.route_map", + "route_replicate.from.vrf.vrf_name.unicast.all.route_map", + "route_replicate.from.vrf.vrf_name.unicast.bgp.asn.route_map", + "route_replicate.from.vrf.vrf_name.unicast.connected.route_map", + "route_replicate.from.vrf.vrf_name.unicast.eigrp.asn.route_map", + "route_replicate.from.vrf.vrf_name.unicast.isis.route_map", + "route_replicate.from.vrf.vrf_name.unicast.mobile.route_map", + "route_replicate.from.vrf.vrf_name.unicast.odr.route_map", + "route_replicate.from.vrf.vrf_name.unicast.ospf.id.route_map", + "route_replicate.from.vrf.vrf_name.unicast.rip.route_map", + "route_replicate.from.vrf.vrf_name.unicast.static.route_map", + "route_target.export", + "route_target.import_config", + ] + + 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 + + wantd = self._vrf_list_to_dict(wantd) + haved = self._vrf_list_to_dict(haved) + + # 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": + for vrfk, vrfv in iteritems(haved): + for afk, afv in iteritems(vrfv.get("address_families", {})): + adrf = wantd.get(vrfk, {}).get("address_families", {}) + if afk in adrf or not adrf: + self.addcmd( + {"name": vrfk}, + "name", + False, + ) + self.addcmd( + {"afi": afv.get("afi"), "safi": afv.get("safi")}, + "address_family", + True, + ) + + if self.state in ["overridden"]: + for vrfk, vrfv in iteritems(haved): + for k, have in iteritems(vrfv.get("address_families", {})): + wantx = wantd.get(vrfk, {}).get("address_families", {}) + if k not in wantx: + self.addcmd( + {"name": vrfk}, + "name", + False, + ) + self.addcmd( + {"afi": have.get("afi"), "safi": have.get("safi")}, + "address_family", + False, + ) + self.compare(parsers=self.parsers, want={}, have=have) + + if self.state != "deleted": + 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 Vrf network resource. + """ + for name, entry in iteritems(want): + begin = len(self.commands) + vrf_want = entry + vrf_have = have.pop(name, {}) + self._compare_afs(vrf_want, vrf_have) + if len(self.commands) != begin: + self.commands.insert(begin, "vrf definition {0}".format(name)) + + def _compare_afs(self, want, have): + """Custom handling of afs option + :params want: the want VRF dictionary + :params have: the have VRF dictionary + """ + waafs = want.get("address_families", {}) + haafs = have.get("address_families", {}) + for afk, afv in iteritems(waafs): + begin = len(self.commands) + self._compare_single_af(want=afv, have=haafs.get(afk, {})) + if len(self.commands) != begin: + self.commands.insert(begin, f"address-family {afv.get('afi')} {afv.get('safi')}") + + def _compare_single_af(self, want, have): + """Custom handling of single af option + :params want: the want VRF dictionary + :params have: the have VRF dictionary + """ + self.compare(parsers=self.parsers[1:], want=want, have=have) + + def _vrf_list_to_dict(self, entry): + """Convert list of items to dict of items + for efficient diff calculation. + :params entry: data dictionary + """ + + for vrf in entry: + if "address_families" in vrf: + vrf["address_families"] = { + (x["afi"], x.get("safi")): x for x in vrf["address_families"] + } + + entry = {x["name"]: x for x in entry} + return entry diff --git a/plugins/module_utils/network/ios/facts/facts.py b/plugins/module_utils/network/ios/facts/facts.py index 35ca7a9aa..57c03e639 100644 --- a/plugins/module_utils/network/ios/facts/facts.py +++ b/plugins/module_utils/network/ios/facts/facts.py @@ -99,6 +99,9 @@ from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.vlans.vlans import ( VlansFacts, ) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.vrf_address_family.vrf_address_family import ( + Vrf_address_familyFacts, +) from ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.vrf_global.vrf_global import ( Vrf_globalFacts, ) @@ -145,6 +148,7 @@ vxlan_vtep=Vxlan_vtepFacts, evpn_global=Evpn_globalFacts, evpn_evi=Evpn_eviFacts, + vrf_address_family=Vrf_address_familyFacts, vrf_global=Vrf_globalFacts, vrf_interfaces=Vrf_interfacesFacts, ) diff --git a/plugins/module_utils/network/ios/facts/vrf_address_family/__init__.py b/plugins/module_utils/network/ios/facts/vrf_address_family/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/module_utils/network/ios/facts/vrf_address_family/vrf_address_family.py b/plugins/module_utils/network/ios/facts/vrf_address_family/vrf_address_family.py new file mode 100644 index 000000000..ca24fa4be --- /dev/null +++ b/plugins/module_utils/network/ios/facts/vrf_address_family/vrf_address_family.py @@ -0,0 +1,112 @@ +# -*- coding: utf-8 -*- +# Copyright 2024 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 vrf_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.vrf_address_family.vrf_address_family import ( + Vrf_address_familyArgs, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates.vrf_address_family import ( + Vrf_address_familyTemplate, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.utils.utils import ( + flatten_config, +) + + +class Vrf_address_familyFacts(object): + """The ios vrf_address_family facts class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = Vrf_address_familyArgs.argument_spec + + def get_config(self, connection): + """Get the configuration from the device""" + + return connection.get("show running-config | section ^vrf") + + def _flatten_config(self, config): + dataLines = config.split("\n") + finalConfig = [] + + for line in dataLines: + if "address-family" in line and "exit-address-family" not in line: + finalConfig.append(line) + + return "\n".join(finalConfig) + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for Vrf_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 = [] + obj = {} + + if not data: + data = self.get_config(connection) + + address_data = flatten_config(data, "address-family") + data = flatten_config(address_data, "vrf") + finalConfig = self._flatten_config(data) + + # parse native config using the Vrf_address_family template + vrf_address_family_parser = Vrf_address_familyTemplate( + lines=finalConfig.splitlines(), + module=self._module, + ) + obj = vrf_address_family_parser.parse() + objs = list(obj.values()) + + for vrf in objs: + af = vrf.get("address_families", {}) + if af: + self._post_parse(vrf) + else: + vrf["address_families"] = [] + + ansible_facts["ansible_network_resources"].pop("vrf_address_family", None) + + params = utils.remove_empties( + vrf_address_family_parser.validate_config( + self.argument_spec, + {"config": objs}, + redact=True, + ), + ) + + facts["vrf_address_family"] = params.get("config", []) + ansible_facts["ansible_network_resources"].update(facts) + + return ansible_facts + + def _post_parse(self, af_data): + """Converts the intermediate data structure + to valid format as per argspec. + :param obj: dict + """ + af = af_data.get("address_families", {}) + if af: + af_data["address_families"] = list(af.values()) diff --git a/plugins/module_utils/network/ios/rm_templates/vrf_address_family.py b/plugins/module_utils/network/ios/rm_templates/vrf_address_family.py new file mode 100644 index 000000000..1dd3dfe7e --- /dev/null +++ b/plugins/module_utils/network/ios/rm_templates/vrf_address_family.py @@ -0,0 +1,2217 @@ +# -*- coding: utf-8 -*- +# Copyright 2024 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 Vrf_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, +) + + +class Vrf_address_familyTemplate(NetworkTemplate): + def __init__(self, lines=None, module=None): + super(Vrf_address_familyTemplate, self).__init__( + lines=lines, + tmplt=self, + module=module, + ) + + # fmt: off + PARSERS = [ + { + "name": "address_family", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + $""", re.VERBOSE, + ), + "setval": "address-family {{ afi }} {{ safi }}", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + }, + }, + }, + }, + "shared": True, + }, + { + "name": "export.map", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+export\smap\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": "export map {{ export.map }}", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "export": { + "map": "{{ export_map }}", + }, + }, + }, + }, + }, + }, + { + "name": "import_config.map", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+import\smap\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": "import map {{ import_config.map }}", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "import_config": { + "map": "{{ import_config_map }}", + }, + }, + }, + }, + }, + }, + { + "name": "export.ipv4.multicast", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+export\sipv4\smulticast\s(?P\d+)\smap\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "export ipv4 multicast {{ export.ipv4.multicast.prefix }} " + "map {{ export.ipv4.multicast.prefix.map }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "export": { + "ipv4": { + "multicast": { + "prefix": "{{ prefix }}", + "map": "{{ export_map }}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "export.ipv4.unicast.allow_evpn", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+export\sipv4\sunicast\s(?P\d+)\smap\s(?P\S+)\s(?Pallow-evpn) + $""", re.VERBOSE, + ), + "setval": ( + "export ipv4 unicast {{ export.ipv4.unicast.prefix }} map " + "{{ export.ipv4.unicast.map.export_map }} " + "allow-evpn" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "export": { + "ipv4": { + "unicast": { + "prefix": "{{ prefix }}", + "map": "{{ export_map }}", + "allow_evpn": ( + "{{true if allow_evpn is defined}}" + ), + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "import_config.ipv4.multicast", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+import\sipv4\smulticast\s(?P\d+)\smap\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "import ipv4 multicast {{ prefix }} map {{ import_map }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "import_config": { + "ipv4": { + "multicast": { + "prefix": "{{ prefix }}", + "map": "{{ import_map }}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "import_config.ipv4.unicast", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+import\sipv4\sunicast\s(?P\d+)\smap\s(?P\S+)\s(?Pallow-evpn) + $""", re.VERBOSE, + ), + "setval": ( + "import ipv4 unicast {{ limit }} map {{ import_map }} " + "allow-evpn" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "import_config": { + "ipv4": { + "unicast": { + "limit": "{{ limit }}", + "map": "{{ import_map }}", + "allow_evpn": ( + "{{true if allow_evpn is defined}}" + ), + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "bgp.next_hop.loopback", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+bgp\snext-hop\sLoopback(?P\d+) + $""", re.VERBOSE, + ), + "setval": "bgp next-hop Loopback {{ loopback }}", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "bgp": { + "next_hop": { + "loopback": "{{ loopback }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "inter_as_hybrid.csc.next_hop", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+inter-as-hybrid\scsc\snext-hop\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "inter-as-hybrid csc next-hop " + "{{ inter_as_hybrid.csc.next_hop }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "inter_as_hybrid": { + "csc": { + "next_hop": ( + "{{ inter_as_hybrid_csc_next_hop }}" + ), + }, + }, + }, + }, + }, + }, + }, + { + "name": "inter_as_hybrid.next_hop", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+inter-as-hybrid\snext-hop\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "inter-as-hybrid next-hop {{ inter_as_hybrid.next_hop }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "inter_as_hybrid": { + "next_hop": "{{ inter_as_hybrid_next_hop }}", + }, + }, + }, + }, + }, + }, + { + "name": ( + "mdt.auto_discovery.ingress_replication.inter_as." + "mdt_hello_enable" + ), + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\sauto-discovery\singress-replication\sinter-as\smdt-hello-enable + $""", re.VERBOSE, + ), + "setval": ( + "mdt auto-discovery ingress-replication inter-as " + "mdt-hello-enable" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "auto_discovery": { + "ingress_replication": { + "inter_as": { + "mdt_hello_enable": "{{ true }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "mdt.auto_discovery.pim.inter_as.mdt_hello_enable", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\sauto-discovery\spim\sinter-as\smdt-hello-enable + $""", re.VERBOSE, + ), + "setval": "mdt auto-discovery pim inter-as mdt-hello-enable", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "auto_discovery": { + "pim": { + "inter_as": { + "mdt_hello_enable": "{{ true }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": ( + "mdt.auto_discovery.pim.inter_as.pim_tlv_announce." + "mdt_hello_enable" + ), + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\sauto-discovery\spim\sinter-as\spim-tlv-announce\smdt-hello-enable + $""", re.VERBOSE, + ), + "setval": ( + "mdt auto-discovery pim inter-as pim-tlv-announce " + "mdt-hello-enable" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "auto_discovery": { + "pim": { + "inter_as": { + "pim_tlv_announce": { + "mdt_hello_enable": "{{true}}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "mdt.auto_discovery.ingress_replication.mdt_hello_enable", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\sauto-discovery\singress-replication\smdt-hello-enable + $""", re.VERBOSE, + ), + "setval": ( + "mdt auto-discovery ingress-replication mdt-hello-enable" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "auto_discovery": { + "ingress_replication": { + "mdt_hello_enable": "{{ true }}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "mdt.auto_discovery.pim.mdt_hello_enable", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\sauto-discovery\spim\smdt-hello-enable + $""", re.VERBOSE, + ), + "setval": "mdt auto-discovery pim mdt-hello-enable", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "auto_discovery": { + "pim": { + "mdt_hello_enable": "{{ true }}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "mdt.auto_discovery.pim.pim_tlv_announce.mdt_hello_enable", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\sauto-discovery\spim\spim-tlv-announce\smdt-hello-enable + $""", re.VERBOSE, + ), + "setval": ( + "mdt auto-discovery pim pim-tlv-announce mdt-hello-enable" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "auto_discovery": { + "pim": { + "pim_tlv_announce": { + "mdt_hello_enable": "{{ true }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "mdt.auto_discovery.receiver_site", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\sauto-discovery\sreceiver-site + $""", re.VERBOSE, + ), + "setval": "mdt auto-discovery receiver-site", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "auto_discovery": { + "receiver_site": "{{ true }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "mdt.data.ingress_replication.number", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\sdata\singress-replication\s(?P\d+) + $""", re.VERBOSE, + ), + "setval": ( + "mdt data ingress-replication " + "{{ mdt.data.ingress_replication.number }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "data": { + "ingress_replication": { + "number": ( + "{{ mdt_data_ingress_" + "replication_number }}" + ), + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "mdt.data.ingress_replication.immediate_switch", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\sdata\singress-replication\simmediate-switch + $""", re.VERBOSE, + ), + "setval": "mdt data ingress-replication immediate-switch", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "data": { + "ingress_replication": { + "immediate_switch": "{{ true }}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "mdt.data.ingress_replication.number.immediate_switch", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\sdata\singress-replication\s(?P\d+)\simmediate-switch + $""", re.VERBOSE, + ), + "setval": ( + "mdt data ingress-replication " + "{{ mdt.data.ingress_replication.number }} immediate-switch" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "data": { + "ingress_replication": { + "number": ( + "{{ mdt_data_ingress_" + "replication_number }}" + ), + "immediate_switch": "{{ true }}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "mdt.data.list.access_list", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\sdata\slist\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": "mdt data list {{ mdt.data.list.access_list }}", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "data": { + "list": { + "access_list": ( + "{{ mdt_data_list_access_list }}" + ), + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "mdt.data.list.access_list_name", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\sdata\slist\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": "mdt data list {{ mdt.data.list.access_list_name }}", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "data": { + "list": { + "access_list_name": ( + "{{ mdt_data_list_access_list_" + "name }}" + ), + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "mdt.data.threshold", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\sdata\sthreshold\s(?P\d+) + $""", re.VERBOSE, + ), + "setval": "mdt data threshold {{ mdt.data.threshold }}", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "data": { + "threshold": "{{ mdt_data_threshold }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "mdt.default_ingress_replication", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\sdefault\singress-replication + $""", re.VERBOSE, + ), + "setval": "mdt default ingress-replication", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "default": { + "ingress_replication": "{{ true }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "mdt.direct", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\sdirect + $""", re.VERBOSE, + ), + "setval": "mdt direct", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "direct": "{{ true }}", + }, + }, + }, + }, + }, + }, + { + "name": "mdt.log_reuse", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\slog-reuse + $""", re.VERBOSE, + ), + "setval": "mdt log-reuse", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "log_reuse": "{{ true }}", + }, + }, + }, + }, + }, + }, + { + "name": "mdt.mode.gre", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\smode\sgre + $""", re.VERBOSE, + ), + "setval": "mdt mode gre", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "mode": { + "gre": "{{ true }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "mdt.mtu.value", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\smtu\s(?P\d+) + $""", re.VERBOSE, + ), + "setval": "mdt mtu {{ mdt.mtu.value }}", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "mtu": "{{ mdt_value }}", + }, + }, + }, + }, + }, + }, + { + "name": "mdt.overlay.bgp.shared_tree_prune_delay", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\soverlay\sbgp\sshared-tree-prune-delay\s(?P\d+) + $""", re.VERBOSE, + ), + "setval": ( + "mdt overlay bgp shared-tree-prune-delay " + "{{ mdt.overlay.bgp.shared_tree_prune_delay }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "overlay": { + "bgp": { + "shared_tree_prune_delay": ( + "{{ shared_tree_prune_delay }}" + ), + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "mdt.overlay.bgp.source_tree_prune_delay", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\soverlay\sbgp\ssource-tree-prune-delay\s(?P\d+) + $""", re.VERBOSE, + ), + "setval": ( + "mdt overlay bgp source-tree-prune-delay " + "{{ mdt.overlay.bgp.source_tree_prune_delay }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "overlay": { + "bgp": { + "source_tree_prune_delay": ( + "{{ source_tree_prune_delay }}" + ), + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "mdt.overlay.use_bgp_spt_only", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\soverlay\suse-bgp\sspt-only + $""", re.VERBOSE, + ), + "setval": "mdt overlay use-bgp spt-only", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "overlay": { + "use_bgp": { + "spt_only": "{{ true }}", + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "mdt.partitioned.ingress_replication", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\spartitioned\singress-replication + $""", re.VERBOSE, + ), + "setval": "mdt partitioned ingress-replication", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "partitioned": { + "ingress_replication": "{{ true }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "mdt.strict_rpf_interface", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+mdt\sstrict-rpf\sinterface + $""", re.VERBOSE, + ), + "setval": "mdt strict-rpf interface", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "mdt": { + "strict_rpf": { + "interface": "{{ true }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "protection.local_prefixes", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + $""", re.VERBOSE, + ), + "setval": "protection local-prefixes", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "protection": { + "local_prefixes": "{{ true }}", + }, + }, + }, + }, + }, + }, + { + "name": "route_replicate.recursion_policy.destination", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-replicate\srecursion-policy\sdestination + $""", re.VERBOSE, + ), + "setval": "route-replicate recursion-policy destination", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_replicate": { + "recursion_policy": { + "destination": "{{ true }}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "route_replicate.from.vrf.vrf_name.unicast.all.route_map", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-replicate\sfrom\svrf\s(?P\S+)\sunicast\sall\sroute-map\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "route-replicate from vrf {{ vrf_name }} unicast all " + "route-map {{ route_map }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_replicate": { + "from_config": { + "vrf": { + "name": "{{ vrf_name }}", + "unicast": { + "all": { + "route_map": "{{ route_map }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": ( + "route_replicate.from.vrf.vrf_name.unicast.bgp.asn.route_map" + ), + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-replicate\sfrom\svrf\s(?P\S+)\sunicast\sbgp\s(?P\d+)\sroute-map\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "route-replicate from vrf {{ vrf_name }} " + "unicast bgp {{ asn }} " + "route-map {{ route_map }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_replicate": { + "from_config": { + "vrf": { + "name": "{{ vrf_name }}", + "unicast": { + "bgp": { + "as_number": "{{ asn }}", + "route_map": "{{ route_map }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": ( + "route_replicate.from.vrf.vrf_name.unicast.connected.route_map" + ), + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-replicate\sfrom\svrf\s(?P\S+)\sunicast\sconnected\sroute-map\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "route-replicate from vrf {{ vrf_name }} unicast connected " + "route-map {{ route_map }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_replicate": { + "from_config": { + "vrf": { + "name": "{{ vrf_name }}", + "unicast": { + "connected": { + "route_map": "{{ route_map }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": ( + "route_replicate.from.vrf.vrf_name.unicast.eigrp.asn." + "route_map" + ), + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-replicate\sfrom\svrf\s(?P\S+)\sunicast\seigrp\s(?P\d+)\sroute-map\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "route-replicate from vrf {{ vrf_name }} " + "unicast eigrp {{ asn }} " + "route-map {{ route_map }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_replicate": { + "from_config": { + "vrf": { + "name": "{{ vrf_name }}", + "unicast": { + "eigrp": { + "as_number": "{{ asn }}", + "route_map": "{{ route_map }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "route_replicate.from.vrf.vrf_name.unicast.isis.route_map", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-replicate\sfrom\svrf\s(?P\S+)\sunicast\sisis\s(?P\S+)\sroute-map\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "route-replicate from vrf {{ vrf_name }} unicast isis " + "{{ tag }} route-map {{ route_map }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_replicate": { + "from_config": { + "vrf": { + "name": "{{ vrf_name }}", + "unicast": { + "isis": { + "iso_tag": "{{ tag }}", + "route_map": "{{ route_map }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": ( + "route_replicate.from.vrf.vrf_name.unicast.mobile.route_map" + ), + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-replicate\sfrom\svrf\s(?P\S+)\sunicast\smobile\sroute-map\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "route-replicate from vrf {{ vrf_name }} unicast mobile " + "route-map {{ route_map }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_replicate": { + "from_config": { + "vrf": { + "name": "{{ vrf_name }}", + "unicast": { + "mobile": { + "route_map": "{{ route_map }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "route_replicate.from.vrf.vrf_name.unicast.odr.route_map", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-replicate\sfrom\svrf\s(?P\S+)\sunicast\sodr\sroute-map\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "route-replicate from vrf {{ vrf_name }} " + "unicast odr route-map {{ route_map }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_replicate": { + "from_config": { + "vrf": { + "name": "{{ vrf_name }}", + "unicast": { + "odr": { + "route_map": "{{ route_map }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": ( + "route_replicate.from.vrf.vrf_name.unicast.ospf.id." + "route_map" + ), + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-replicate\sfrom\svrf\s(?P\S+)\sunicast\sospf\s(?P\d+)\sroute-map\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "route-replicate from vrf {{ vrf_name }} unicast ospf " + "{{ process_id }} route-map " + "{{ route_map }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_replicate": { + "from_config": { + "vrf": { + "name": "{{ vrf_name }}", + "unicast": { + "ospf": { + "process_id": ( + "{{ process_id }}" + ), + "route_map": "{{ route_map }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "route_replicate.from.vrf.vrf_name.unicast.rip.route_map", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-replicate\sfrom\svrf\s(?P\S+)\sunicast\srip\sroute-map\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "route-replicate from vrf {{ vrf_name }} " + "unicast rip route-map {{ route_replicate.from.vrf.vrf_name." + "unicast.rip.route_map }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_replicate": { + "from_config": { + "vrf": { + "name": "{{ vrf_name }}", + "unicast": { + "rip": { + "route_map": "{{ route_map }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": ( + "route_replicate.from.vrf.vrf_name.unicast.static.route_map" + ), + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-replicate\sfrom\svrf\s(?P\S+)\sunicast\sstatic\sroute-map\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "route-replicate from vrf {{ vrf_name }} " + "unicast static route-map {{ route_map }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_replicate": { + "from_config": { + "vrf": { + "name": "{{ vrf_name }}", + "unicast": { + "static": { + "route_map": "{{ route_map }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "route_replicate.from.unicast.all.route_map", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-replicate\sfrom\sunicast\sall\sroute-map\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "route-replicate from unicast all route-map " + "{{ route_replicate.from.unicast.all.route_map }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_replicate": { + "from_config": { + "unicast": { + "all": { + "route_map": "{{ route_map }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "route_replicate.from.unicast.bgp.asn.route_map", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-replicate\sfrom\sunicast\sbgp\s(?P\d+)\sroute-map\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "route-replicate from unicast bgp " + "{{ route_replicate.from.unicast.bgp.asn }} " + "route-map {{ route_map }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_replicate": { + "from_config": { + "unicast": { + "bgp": { + "as_number": "{{ asn }}", + "route_map": "{{ route_map }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "route_replicate.from.unicast.connected.route_map", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-replicate\sfrom\sunicast\sconnected\sroute-map\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "route-replicate from unicast connected route-map " + "{{ route_replicate.from.unicast.connected.route_map }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_replicate": { + "from_config": { + "unicast": { + "connected": { + "route_map": "{{ route_map }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "route_replicate.from.unicast.eigrp.asn.route_map", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-replicate\sfrom\sunicast\seigrp\s(?P\d+)\sroute-map\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "route-replicate from unicast eigrp " + "{{ route_replicate.from.unicast.eigrp.asn }} " + "route-map {{ route_replicate.from.unicast.eigrp.asn." + "route_map }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_replicate": { + "from_config": { + "unicast": { + "eigrp": { + "as_number": "{{ asn }}", + "route_map": "{{ route_map }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "route_replicate.from.unicast.isis.route_map", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-replicate\sfrom\sunicast\sisis\s(?P\S+)\sroute-map\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "route-replicate from unicast isis " + "{{ route_replicate.from.unicast.isis.tag }} " + "route-map {{ route_replicate.from.unicast.isis.route_map }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_replicate": { + "from_config": { + "unicast": { + "isis": { + "tag": "{{ tag }}", + "route_map": "{{ route_map }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "route_replicate.from.unicast.mobile.route_map", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-replicate\sfrom\sunicast\smobile\sroute-map\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "route-replicate from unicast mobile route-map " + "{{ route_replicate.from.unicast.mobile.route_map }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_replicate": { + "from_config": { + "unicast": { + "mobile": { + "route_map": "{{ route_map }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "route_replicate.from.unicast.odr.route_map", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-replicate\sfrom\sunicast\sodr\sroute-map\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "route-replicate from unicast odr route-map " + "{{ route_replicate.from.unicast.odr.route_map }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_replicate": { + "from_config": { + "unicast": { + "odr": { + "route_map": "{{ route_map }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "route_replicate.from.unicast.ospf.id.route_map", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-replicate\sfrom\sunicast\sospf\s(?P\d+)\sroute-map\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "route-replicate from unicast ospf " + "{{ route_replicate.from.unicast.ospf.id }} " + "route-map {{ route_replicate.from.unicast.ospf.id.route_map}}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_replicate": { + "from_config": { + "unicast": { + "ospf": { + "process_id": "{{ process_id }}", + "route_map": "{{ route_map }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "route_replicate.from.unicast.rip.route_map", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-replicate\sfrom\sunicast\srip\sroute-map\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "route-replicate from unicast rip route-map " + "{{ route_replicate.from.unicast.rip.route_map }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_replicate": { + "from_config": { + "unicast": { + "rip": { + "route_map": "{{ route_map }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "route_replicate.from.unicast.static.route_map", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-replicate\sfrom\sunicast\sstatic\sroute-map\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": ( + "route-replicate from unicast static route-map " + "{{ route_replicate.from.unicast.static.route_map }}" + ), + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_replicate": { + "from_config": { + "unicast": { + "static": { + "route_map": "{{ route_map }}", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + "name": "route_target.export", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-target\sexport\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": "route-target export {{ route_target.export }}", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_target": { + "export": "{{ route_target_export }}", + }, + }, + }, + }, + }, + }, + { + "name": "route_target.import_config", + "getval": re.compile( + r""" + ^vrf\sdefinition\s(?P\S+) + \saddress-family + \s(?P\S+) + (\s(?P\S+))? + \s+route-target\simport\s(?P\S+) + $""", re.VERBOSE, + ), + "setval": "route-target import {{ route_target.import_config }}", + "result": { + '{{ name }}': { + 'name': '{{ name }}', + "address_families": { + '{{ "address_families_" + afi + ' + '("_" + safi if safi is defined else "_unicast") }}': { + "afi": "{{ afi }}", + "safi": ( + "{{ safi if safi is defined else " + "'unicast' }}" + ), + "route_target": { + "import_config": ( + "{{ route_target_import_config }}" + ), + }, + }, + }, + }, + }, + }, + ] + # fmt: on diff --git a/plugins/module_utils/network/ios/utils/utils.py b/plugins/module_utils/network/ios/utils/utils.py index e79dd14b7..361c4757e 100644 --- a/plugins/module_utils/network/ios/utils/utils.py +++ b/plugins/module_utils/network/ios/utils/utils.py @@ -214,6 +214,44 @@ def remove_duplicate_interface(commands): return set_cmd +def flatten_dict(x): + result = {} + if not isinstance(x, dict): + return result + + for key, value in iteritems(x): + if isinstance(value, dict): + result.update(flatten_dict(value)) + else: + result[key] = value + + return result + + +def flatten_config(data, context): + """Flatten different contexts in + the running-config for easier parsing. + :param data: dict + :param context: str + :returns: flattened running config + """ + data = data.split("\n") + in_cxt = False + cur = {} + + for index, x in enumerate(data): + cur_indent = len(x) - len(x.lstrip()) + if x.strip().startswith(context): + in_cxt = True + cur["context"] = x + cur["indent"] = cur_indent + elif cur and (cur_indent <= cur["indent"]): + in_cxt = False + elif in_cxt: + data[index] = cur["context"] + " " + x.strip() + return "\n".join(data) + + def validate_ipv4(value, module): if value: address = value.split("/") diff --git a/plugins/modules/ios_vrf_address_family.py b/plugins/modules/ios_vrf_address_family.py new file mode 100644 index 000000000..dad3f69ca --- /dev/null +++ b/plugins/modules/ios_vrf_address_family.py @@ -0,0 +1,1157 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2024 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_vrf_address_family +""" + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +DOCUMENTATION = """ +module: ios_vrf_address_family +short_description: Resource module to configure VRF definitions. +description: This module provides declarative management of VRF definitions on Cisco IOS. +version_added: 7.0.0 +author: Ruchi Pakhle (@Ruchip16) +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 device configurations for VRF. + type: list + elements: dict + suboptions: + name: + description: Name of the VRF. + type: str + required: true + address_families: + description: Enable address family and enter its config mode - AFI/SAFI configuration + type: list + elements: dict + suboptions: + afi: + description: Address Family Identifier (AFI) + type: str + choices: ['ipv4', 'ipv6'] + safi: + description: Address Family modifier + type: str + choices: ['multicast', 'unicast'] + bgp: &bgp01 + description: Commands pertaining to BGP configuration. + type: dict + suboptions: + next_hop: + description: Next-hop for the routes of a VRF in the backbone. + type: dict + suboptions: + loopback: + description: Loopback interface for next-hop + type: int + export: &export + description: VRF export + type: dict + suboptions: + map: + description: Route-map name + type: str + ipv4: + description: Address family based VRF export + type: dict + suboptions: + multicast: + description: Export prefixes to IPv4 Multicast table + type: dict + suboptions: + prefix: + description: Upper limit on export prefixes without hogging memory + type: int + map: + description: Route-map name + type: str + unicast: + description: Export prefixes to IPv4 Unicast table + type: dict + suboptions: + prefix: + description: Upper limit on export prefixes without hogging memory + type: int + map: + description: Route-map name + type: str + allow_evpn: + description: Allow EVPN routes into global table + type: bool + import_config: &import01 + description: VRF import + type: dict + suboptions: + map: + description: Route-map name + type: str + ipv4: + description: Address family based VRF import + type: dict + suboptions: + multicast: + description: Import prefixes from IPv4 Multicast table + type: dict + suboptions: + prefix: + description: Upper limit on import prefixes without hogging memory + type: int + map: + description: Route-map name + type: str + unicast: + description: Import prefixes from IPv4 Unicast table + type: dict + suboptions: + limit: + description: Upper limit on import prefixes without hogging memory + type: int + map: + description: Route-map based VRF import + type: str + allow_evpn: + description: allow Global->VRF routes into EVPN + type: bool + inter_as_hybrid: &inter_as_hybrid + description: Inter AS hybrid mode + type: dict + suboptions: + csc: + description: Carrier Supporting Carrier + type: dict + suboptions: + next_hop: &next_hop + description: Next-hop for the routes of a VRF in the backbone. + type: str + next_hop: *next_hop + mdt: + description: Backbone Multicast Distribution Tree + type: dict + suboptions: + auto_discovery: + description: BGP auto-discovery for MVPN + type: dict + suboptions: + ingress_replication: + description: BGP auto-discovery for Ingress-Replication + type: dict + suboptions: + inter_as: + description: Enable Inter-AS BGP auto-discovery + type: dict + suboptions: + mdt_hello_enable: &mdt_hello_enable + description: Enable PIM Hellos over MDT interface + type: bool + mdt_hello_enable: *mdt_hello_enable + pim: + description: BGP auto-discovery for PIM + type: dict + suboptions: + inter_as: + description: Enable Inter-AS BGP auto-discovery + type: dict + suboptions: + mdt_hello_enable: *mdt_hello_enable + pim_tlv_announce: &pim_tlv_announce + description: Announce PIM TLV for data MDT + type: dict + suboptions: + mdt_hello_enable: *mdt_hello_enable + mdt_hello_enable: *mdt_hello_enable + pim_tlv_announce: *pim_tlv_announce + receiver_site: + description: BGP receiver only site for MVPN + type: bool + data: + description: MDT data trees + type: dict + suboptions: + ingress_replication: + description: Use Ingress-Replication to create the data MDT + type: dict + suboptions: + number: + description: Number of data MDT + type: int + immediate_switch: + description: Switch immediately to Data MDT tree + type: bool + list: &list + description: Access-list + type: dict + suboptions: + access_list_number: + description: Access-list number + type: int + access_list_name: + description: IP Named Extended Access list + type: str + list: *list + threshold: + description: MDT switching threshold + type: int + default: + description: Default MDT configuration + type: dict + suboptions: + ingress_replication: + description: Use Ingress-Replication for the default MDT + type: bool + direct: + description: Direct MDT's + type: bool + log_reuse: + description: Event logging for data MDT reuse + type: bool + mode: + description: The type of encapsulation + type: dict + suboptions: + gre: + description: GRE encapsulation + type: bool + mtu: + description: The MTU + type: int + overlay: + description: MDT overlay Protocol + type: dict + suboptions: + bgp: + description: BGP Overlay signalling + type: dict + suboptions: + shared_tree_prune_delay: + description: Delay before shared tree is pruned at C-RP PE + type: int + source_tree_prune_delay: + description: Delay before source tree is pruned at C-S PE + type: int + use_bgp: + description: Use BGP for MDT overlay signaling + type: dict + suboptions: + spt_only: + description: Enable SPT-only ASM mode + type: bool + partitioned: + description: Partitioned Multicast Distribution Tree + type: dict + suboptions: + ingress_replication: + description: Use Ingress-Replication for the partitioned MDT + type: bool + strict_rpf: + description: Enable strict RPF check + type: dict + suboptions: + interface: + description: Interface based strict RPF check + type: bool + protection: + description: Configure local repair + type: dict + suboptions: + local_prefixes: + description: Enable protection for local prefixes + type: bool + route_replicate: &route_replicate + description: Replicate (import) routes from another topology (and another VRF) + type: dict + suboptions: + recursion_policy: + description: Route replication recursion policy + type: dict + suboptions: + destination: + description: Recurse in destination topology + type: bool + from_config: + description: Replicate routes from another VRF + type: dict + suboptions: + multicast: + description: Multicast SAFI + type: dict + suboptions: + all: &all + description: All routes + type: dict + suboptions: + route_map: &route_map + description: Route-map reference + type: str + bgp: &bgp + description: Border Gateway Protocol (BGP) + type: dict + suboptions: + as_number: + description: Autonomous System Number + type: int + route_map: *route_map + eigrp: &eigrp + description: Enhanced Interior Gateway Routing Protocol (EIGRP) + type: dict + suboptions: + as_number: + description: Autonomous System Number + type: int + route_map: *route_map + isis: &isis + description: Intermediate System-to-Intermediate System (ISIS) + type: dict + suboptions: + iso_tag: + description: ISO routing area tag + type: str + route_map: *route_map + mobile: &mobile + description: Mobile routes + type: dict + suboptions: + route_map: *route_map + odr: &odr + description: On-Demand Stub routes + type: dict + suboptions: + route_map: *route_map + ospf: &ospf + description: Open Shortest Path First (OSPF) + type: dict + suboptions: + process_id: + description: OSPF process ID + type: int + route_map: *route_map + rip: &rip + description: Routing Information Protocol (RIP) + type: dict + suboptions: + route_map: *route_map + static: &static + description: Static routes + type: dict + suboptions: + route_map: *route_map + topology: &topology + description: Topology name + type: dict + suboptions: + base: + description: Base topology + type: dict + suboptions: + all: *all + bgp: *bgp + eigrp: *eigrp + isis: *isis + mobile: *mobile + odr: *odr + ospf: *ospf + rip: *rip + static: *static + unicast: + description: Unicast SAFI + type: dict + suboptions: + all: *all + bgp: *bgp + connected: + description: Connected routes + type: dict + suboptions: + route_map: *route_map + eigrp: *eigrp + isis: *isis + mobile: *mobile + odr: *odr + ospf: *ospf + rip: *rip + static: *static + vrf: + description: Specify a source VRF + type: dict + suboptions: + name: + description: Source VRF name + type: str + multicast: + description: Multicast SAFI + type: dict + suboptions: + all: *all + bgp: *bgp + eigrp: *eigrp + isis: *isis + mobile: *mobile + odr: *odr + ospf: *ospf + rip: *rip + static: *static + topology: *topology + unicast: + description: Unicast SAFI + type: dict + suboptions: + all: *all + bgp: *bgp + connected: + description: Connected routes + type: dict + suboptions: + route_map: *route_map + eigrp: *eigrp + isis: *isis + mobile: *mobile + odr: *odr + ospf: *ospf + rip: *rip + static: *static + global: + description: global VRF + type: dict + suboptions: + multicast: + description: Multicast SAFI + type: dict + suboptions: + all: *all + bgp: *bgp + eigrp: *eigrp + isis: *isis + mobile: *mobile + odr: *odr + ospf: *ospf + rip: *rip + static: *static + topology: *topology + unicast: + description: Unicast SAFI + type: dict + suboptions: + all: *all + bgp: *bgp + connected: + description: Connected routes + type: dict + suboptions: + route_map: *route_map + eigrp: *eigrp + isis: *isis + mobile: *mobile + odr: *odr + ospf: *ospf + rip: *rip + static: *static + route_target: &route_target + description: Specify Target VPN Extended Communities. + type: dict + suboptions: + export: + description: Export Target-VPN community. + type: str + import_config: + description: Export Target-VPN community. + type: str + both: + description: Both export and import Target-VPN community + 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 vrf). + - 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: [parsed, gathered, deleted, merged, replaced, rendered, overridden] + 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 vrf). + connection to remote host is not required. + type: str +""" + +EXAMPLES = """ +# Using merged +# +# Before state: +# ------------- +# +# RP/0/0/CPU0:ios#show running-config | section ^vrf +# vrf defnition test +# + +- name: Merge provided configuration with device configuration + cisco.ios.ios_vrf_address_family: + config: + - name: test1 + address_families: + - afi: "ipv4" + safi: "unicast" + bgp: + next_hop: + loopback: 40 + export: + ipv4: + multicast: + map: "single" + prefix: 345 + unicast: + allow_evpn: true + map: "test-map" + prefix: 67 + map: "testing-map" + import_config: + ipv4: + multicast: + map: "import-map" + prefix: 89 + unicast: + allow_evpn: true + limit: 12 + map: "ran-map" + map: "import-map" + state: merged + +# Task Output: +# ------------ +# +# before: [] +# +# commands: +# - vrf definition test1 +# - address-family ipv4 unicast +# - bgp next-hop loopback 40 +# - export map "testing-map" +# - export ipv4 multicast 345 map "single" +# - export ipv4 unicast 67 map "test-map" allow-evpn +# - import map "import-map" +# - import ipv4 multicast 89 map "import-map" +# - import ipv4 unicast 12 map "ran-map" allow-evpn +# +# after: +# - name: test1 +# address_families: +# - afi: "ipv4" +# safi: "unicast" +# bgp: +# next_hop: +# loopback: 40 +# export: +# ipv4: +# multicast: +# map: "single" +# prefix: 345 +# unicast: +# allow_evpn: true +# map: "test-map" +# prefix: 67 +# map: "testing-map" +# import_config: +# ipv4: +# multicast: +# map: "import-map" +# prefix: 89 +# unicast: +# allow_evpn: true +# limit: 12 +# map: "ran-map" +# map: "import-map" +# +# After state: +# ------------ +# +# RP/0/0/CPU0:ios#show running-config | section ^vrf +# vrf definition test1 +# address-family ipv4 unicast +# bgp next-hop loopback 40 +# export map "testing-map" +# export ipv4 multicast 345 map "single" +# export ipv4 unicast 67 map "test-map" allow-evpn +# import map "import-map" +# import ipv4 multicast 89 map "import-map" +# import ipv4 unicast 12 map "ran-map" allow-evpn + +# Using replaced +# +# Before state: +# ------------- +# +# RP/0/0/CPU0:ios#show running-config | section ^vrf +# vrf definition test1 +# address-family ipv4 unicast +# bgp next-hop loopback 40 +# export map "testing-map" +# export ipv4 multicast 345 map "single" +# export ipv4 unicast 67 map "test-map" allow-evpn +# import map "import-map" +# import ipv4 multicast 89 map "import-map" +# import ipv4 unicast 12 map "ran-map" allow-evpn + +- name: Replace the provided configuration with the existing running configuration + cisco.ios.ios_vrf_address_family: + config: + - name: test1 + address_families: + - afi: "ipv4" + safi: "unicast" + bgp: + next_hop: + loopback: 40 + export: + ipv4: + multicast: + map: "single" + prefix: 345 + unicast: + allow_evpn: true + map: "test-map" + prefix: 67 + map: "testing-map" + import_config: + ipv4: + multicast: + map: "import-map" + prefix: 89 + unicast: + allow_evpn: true + limit: 12 + map: "ran-map" + map: "import-map" + state: replaced + +# Task Output: +# ------------ +# +# before: +# - name: test1 +# address_families: +# - afi: "ipv4" +# safi: "unicast" +# bgp: +# next_hop: +# loopback: 40 +# export: +# ipv4: +# multicast: +# map: "single" +# prefix: 345 +# unicast: +# allow_evpn: true +# map: "test-map" +# prefix: 67 +# map: "testing-map" +# import_config: +# ipv4: +# multicast: +# map: "import-map" +# prefix: 89 +# unicast: +# allow_evpn: true +# limit: 12 +# map: "ran-map" +# map: "import-map" +# +# commands: +# - vrf definition test1 +# - address-family ipv4 unicast +# - bgp next-hop loopback 40 +# - export map "testing-map" +# - export ipv4 multicast 345 map "single" +# - export ipv4 unicast 67 map "test-map" allow-evpn +# - import map "import-map" +# - import ipv4 multicast 89 map "import-map" +# - import ipv4 unicast 12 map "ran-map" allow-evpn +# +# after: +# - name: VRF1 +# address_families: +# - afi: "ipv4" +# safi: "unicast" +# bgp: +# next_hop: +# loopback: 23 +# export: +# ipv4: +# multicast: +# map: "single" +# prefix: 33 +# unicast: +# allow_evpn: true +# map: "test-map1" +# prefix: 7 +# map: "testing-map" +# import_config: +# ipv4: +# multicast: +# map: "import-map1" +# prefix: 89 +# unicast: +# allow_evpn: true +# limit: 12 +# map: "ran-map" +# map: "import-map" +# +# After state: +# ------------ +# +# RP/0/RP0/CPU0:ios(config)#show running-config vrf +# vrf definition VRF1 +# address-family ipv4 unicast +# bgp next-hop loopback 23 +# export map "testing-map" +# export ipv4 multicast 345 map "single" +# export ipv4 unicast 67 map "test-map1" allow-evpn +# import map "import-map" +# import ipv4 multicast 89 map "import-map1" +# import ipv4 unicast 12 map "ran-map" allow-evpn + +# Using overridden +# +# Before state: +# ------------- +# +# RP/0/RP0/CPU0:ios(config)#show running-config | section ^vrf +# vrf definition test1 +# address-family ipv4 unicast +# bgp next-hop loopback 40 +# export map "testing-map" +# export ipv4 multicast 345 map "single" +# export ipv4 unicast 67 map "test-map" allow-evpn +# import map "import-map" +# import ipv4 multicast 89 map "import-map" +# import ipv4 unicast 12 map "ran-map" allow-evpn + +- name: Override the provided configuration with the existing running configuration + cisco.ios.ios_vrf_address_family: + state: overridden + config: + - name: VRF7 + address_families: + - afi: "ipv4" + safi: "unicast" + bgp: + next_hop: + loopback: 89 + export: + ipv4: + multicast: + map: "single" + prefix: 345 + unicast: + allow_evpn: true + map: "test-map" + prefix: 67 + map: "testing-map" + import_config: + ipv4: + multicast: + map: "import-map" + prefix: 89 + unicast: + allow_evpn: true + limit: 12 + map: "ran-map" + map: "import-map" +# Task Output: +# ------------ +# +# before: +# - name: test1 +# address_families: +# - afi: "ipv4" +# safi: "unicast" +# bgp: +# next_hop: +# loopback: 40 +# export: +# ipv4: +# multicast: +# map: "single" +# prefix: 345 +# unicast: +# allow_evpn: true +# map: "test-map" +# prefix: 67 +# map: "testing-map" +# import_config: +# ipv4: +# multicast: +# map: "import-map" +# prefix: 89 +# unicast: +# allow_evpn: true +# limit: 12 +# map: "ran-map" +# map: "import-map" +# +# commands: +# - vrf definition VRF7 +# - address-family ipv4 unicast +# - bgp next-hop loopback 89 +# - export map "testing-map" +# - export ipv4 multicast 345 map "single" +# - export ipv4 unicast 67 map "test-map" allow-evpn +# - import map "import-map" +# - import ipv4 multicast 89 map "import-map" +# - import ipv4 unicast 12 map "ran-map" allow-evpn + +# +# After state: +# ------------- +# RP/0/RP0/CPU0:ios(config)#show running-config vrf +# vrf definition VRF4 +# vrf definition VRF7 +# address-family ipv4 unicast +# bgp next-hop loopback 89 +# export map "testing-map" +# export ipv4 multicast 345 map "single" +# export ipv4 unicast 67 map "test-map" allow-evpn +# import map "import-map" +# import ipv4 multicast 89 map "import-map1" +# import ipv4 unicast 12 map "ran-map" allow-evpn + +# Using deleted +# +# Before state: +# ------------- +# +# RP/0/RP0/CPU0:ios(config)#show running-config | section ^vrf +# vrf definition VRF4 +# vrf definition VRF6 +# address-family ipv4 unicast +# bgp next-hop loopback 40 +# import map "import-map" +# import ipv4 multicast 89 map "import-map" +# import ipv4 unicast 12 map "ran-map" allow-evpn +# export map "testing-map" +# export ipv4 multicast 345 map "single" +# export ipv4 unicast 67 map "test-map" allow-evpn +# vrf definition VRF7 + +- name: Delete the provided configuration + cisco.ios.ios_vrf_address_family: + config: + state: deleted + +# Task Output: +# ------------ +# +# before: +# - name: VRF4 +# - name: VRF6 +# address_families: +# - afi: "ipv4" +# safi: "unicast" +# bgp: +# next_hop: +# loopback: 23 +# import_config: +# ipv4: +# multicast: +# map: "import-map" +# prefix: 89 +# unicast: +# map: "ran-map" +# limit: 12 +# allow_evpn: true +# map: "import-map" +# export: +# ipv4: +# multicast: +# map: "single" +# prefix: 345 +# unicast: +# map: "test-map" +# prefix: 67 +# allow_evpn: true +# map: "testing-map" +# - name: VRF7 + +# commands: +# - vrf definition VRF4 +# - vrf definition VRF6 +# - no address-family ipv4 unicast +# - vrf definition VRF7 +# +# after: +# - name: VRF4 +# - name: VRF6 +# - name: VRF7 +# +# After state: +# ------------ +# +# RP/0/RP0/CPU0:ios(config)#show running-config | section ^vrf +# vrf definition VRF4 +# vrf definition VRF6 +# vrf definition VRF7 + +# Using rendered +# +- name: Render provided configuration with device configuration + cisco.ios.ios_vrf_address_family: + config: + - name: test + address_families: + - afi: "ipv4" + safi: "unicast" + bgp: + next_hop: + loopback: 23 + import_config: + ipv4: + multicast: + map: "import-map" + prefix: 89 + unicast: + map: "ran-map" + limit: 12 + allow_evpn: true + map: "import-map" + export: + ipv4: + multicast: + map: "single" + prefix: 345 + unicast: + map: "test-map" + prefix: 67 + allow_evpn: true + map: "testing-map" + state: rendered + +# Task Output: +# ------------ +# +# rendered: +# - vrf definition test +# - address-family ipv4 unicast +# - bgp next-hop loopback 23 +# - import map "import-map" +# - import ipv4 multicast 89 map "import-map" +# - import ipv4 unicast 12 map "ran-map" allow-evpn +# - export map "testing-map" +# - export ipv4 multicast 345 map "single" +# - export ipv4 unicast 67 map "test-map" allow-evpn + +# Using gathered +# +# Before state: +# ------------- +# +# RP/0/RP0/CPU0:ios(config)#show running-config | section ^vrf +# vrf definition test1 +# address-family ipv4 unicast +# bgp next-hop loopback 40 +# import map "import-map" +# import ipv4 multicast 89 map "import-map" +# import ipv4 unicast 12 map "ran-map" allow-evpn +# export map "testing-map" +# export ipv4 multicast 345 map "single" +# export ipv4 unicast 67 map "test-map" allow-evpn + +- name: Gather existing running configuration + cisco.ios.ios_vrf_address_family: + state: gathered + +# Task Output: +# ------------ +# +# gathered: +# - name: test1 +# address_families: +# - afi: "ipv4" +# safi: "unicast" +# bgp: +# next_hop: +# loopback: 40 +# export: +# ipv4: +# multicast: +# map: "single" +# prefix: 345 +# unicast: +# allow_evpn: true +# map: "test-map" +# prefix: 67 +# map: "testing-map" +# import_config: +# ipv4: +# multicast: +# map: "import-map" +# prefix: 89 +# unicast: +# allow_evpn: true +# limit: 12 +# map: "ran-map" +# map: "import-map" + +# Using parsed +# +# File: parsed.cfg +# ---------------- +# +# vrf definition test +# address-family ipv4 unicast +# bgp next-hop loopback 23 +# import map "import-map" +# import ipv4 multicast 89 map "import-map" +# import ipv4 unicast 12 map "ran-map" allow-evpn +# export map "testing-map" +# export ipv4 multicast 345 map "single" +# export ipv4 unicast 67 map "test-map" allow-evpn + +- name: Parse the provided configuration + cisco.ios.ios_vrf_address_family: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + +# Task Output: +# ------------ +# +# parsed: +# - address_families: +# - afi: ipv4 +# bgp: +# next_hop: +# loopback: 40 +# export: +# ipv4: +# multicast: +# map: "single" +# prefix: 345 +# unicast: +# allow_evpn: true +# map: "test-map" +# prefix: 67 +# map: "testing-map" +# import_config: +# ipv4: +# multicast: +# map: "import-map" +# prefix: 89 +# unicast: +# allow_evpn: true +# limit: 12 +# map: "ran-map" +# safi: unicast +# name: test +""" + +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: list + 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: list + 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) + type: list + sample: + - vrf definition test1 + - address-family ipv4 unicast + - bgp next-hop loopback 40 + - export map "testing-map" + - export ipv4 multicast 345 map "testmap" +rendered: + description: The provided configuration in the task rendered in device-native format (offline). + returned: when I(state) is C(rendered) + type: list + sample: + - vrf definition test1 + - address-family ipv4 unicast + - bgp next-hop loopback 40 + - import map "testing-map" + - export ipv4 multicast 345 map "testmap" +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.vrf_address_family.vrf_address_family import ( + Vrf_address_familyArgs, +) +from ansible_collections.cisco.ios.plugins.module_utils.network.ios.config.vrf_address_family.vrf_address_family import ( + Vrf_address_family, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=Vrf_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 = Vrf_address_family(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/tests/integration/targets/ios_vrf_address_family/defaults/main.yaml b/tests/integration/targets/ios_vrf_address_family/defaults/main.yaml new file mode 100644 index 000000000..164afead2 --- /dev/null +++ b/tests/integration/targets/ios_vrf_address_family/defaults/main.yaml @@ -0,0 +1,3 @@ +--- +testcase: "[^_].*" +test_items: [] diff --git a/tests/integration/targets/ios_vrf_address_family/meta/main.yaml b/tests/integration/targets/ios_vrf_address_family/meta/main.yaml new file mode 100644 index 000000000..23d65c7ef --- /dev/null +++ b/tests/integration/targets/ios_vrf_address_family/meta/main.yaml @@ -0,0 +1,2 @@ +--- +dependencies: [] diff --git a/tests/integration/targets/ios_vrf_address_family/tasks/cli.yaml b/tests/integration/targets/ios_vrf_address_family/tasks/cli.yaml new file mode 100644 index 000000000..86ca0d9cb --- /dev/null +++ b/tests/integration/targets/ios_vrf_address_family/tasks/cli.yaml @@ -0,0 +1,22 @@ +--- +- name: Collect all CLI test cases + ansible.builtin.find: + paths: "{{ role_path }}/tests/common" + patterns: "{{ testcase }}.yaml" + use_regex: true + register: test_cases + delegate_to: localhost + +- name: Set test_items + ansible.builtin.set_fact: + test_items: "{{ test_cases.files | map(attribute='path') | list }}" + +- name: Run test case (connection=ansible.netcommon.network_cli) + ansible.builtin.include_tasks: "{{ test_case_to_run }}" + vars: + ansible_connection: ansible.netcommon.network_cli + with_items: "{{ test_items }}" + loop_control: + loop_var: test_case_to_run + tags: + - network_cli diff --git a/tests/integration/targets/ios_vrf_address_family/tasks/main.yaml b/tests/integration/targets/ios_vrf_address_family/tasks/main.yaml new file mode 100644 index 000000000..f75f2f031 --- /dev/null +++ b/tests/integration/targets/ios_vrf_address_family/tasks/main.yaml @@ -0,0 +1,5 @@ +--- +- name: Include the CLI tasks + ansible.builtin.include_tasks: cli.yaml + tags: + - cli diff --git a/tests/integration/targets/ios_vrf_address_family/tests/common/_parsed.cfg b/tests/integration/targets/ios_vrf_address_family/tests/common/_parsed.cfg new file mode 100644 index 000000000..6156b768e --- /dev/null +++ b/tests/integration/targets/ios_vrf_address_family/tests/common/_parsed.cfg @@ -0,0 +1,11 @@ +vrf definition test + address-family ipv4 unicast + import ipv4 unicast 56 map import allow-evpn + export map testing-map2 + export ipv4 unicast 37 map test allow-evpn + mdt auto-discovery pim pim-tlv-announce mdt-hello-enable + mdt auto-discovery receiver-site + route-target export 10.12.0.1:20 + route-target import 10.0.0.1:30 + inter-as-hybrid next-hop 1.2.3.4 + bgp next-hop Loopback23 diff --git a/tests/integration/targets/ios_vrf_address_family/tests/common/_populate.yaml b/tests/integration/targets/ios_vrf_address_family/tests/common/_populate.yaml new file mode 100644 index 000000000..bf9888dd6 --- /dev/null +++ b/tests/integration/targets/ios_vrf_address_family/tests/common/_populate.yaml @@ -0,0 +1,39 @@ +--- +- name: Populate VRF configuration + register: result + cisco.ios.ios_vrf_address_family: + config: + - name: test1 + address_families: + - afi: "ipv4" + safi: "unicast" + export: + ipv4: + multicast: + map: "single" + prefix: 345 + unicast: + allow_evpn: true + map: "test-map" + prefix: 67 + map: "testing-map" + import_config: + ipv4: + multicast: + map: "import-map" + prefix: 89 + unicast: + allow_evpn: true + limit: 12 + map: "ran-map" + map: "import-map" + inter_as_hybrid: + csc: + next_hop: "1.2.3.4" + next_hop: "1.0.0.0" + mdt: + auto_discovery: + pim: + pim_tlv_announce: + mdt_hello_enable: true + state: merged diff --git a/tests/integration/targets/ios_vrf_address_family/tests/common/_remove_config.yaml b/tests/integration/targets/ios_vrf_address_family/tests/common/_remove_config.yaml new file mode 100644 index 000000000..b95d5216d --- /dev/null +++ b/tests/integration/targets/ios_vrf_address_family/tests/common/_remove_config.yaml @@ -0,0 +1,11 @@ +--- +- name: Remove VRF global configurations + cisco.ios.ios_config: + lines: + - no vrf definition VRF4 + - no vrf definition VRF6 + - no vrf definition VRF1 + - no vrf definition test + - no vrf definition test1 + - no vrf definition test2 + register: result diff --git a/tests/integration/targets/ios_vrf_address_family/tests/common/empty_config.yaml b/tests/integration/targets/ios_vrf_address_family/tests/common/empty_config.yaml new file mode 100644 index 000000000..3833dcc82 --- /dev/null +++ b/tests/integration/targets/ios_vrf_address_family/tests/common/empty_config.yaml @@ -0,0 +1,57 @@ +--- +- ansible.builtin.debug: + msg: START ios_vrf_address_family empty_config integration tests on connection={{ ansible_connection }} + +- name: Merged with empty configuration should give appropriate error message + register: result + ignore_errors: true + cisco.ios.ios_vrf_address_family: + config: + state: merged + +- ansible.builtin.assert: + that: + - result.msg == 'value of config parameter must not be empty for state merged' + +- name: Replaced with empty configuration should give appropriate error message + register: result + ignore_errors: true + cisco.ios.ios_vrf_address_family: + config: + state: replaced + +- ansible.builtin.assert: + that: + - result.msg == 'value of config parameter must not be empty for state replaced' + +- name: Overridden with empty configuration should give appropriate error message + register: result + ignore_errors: true + cisco.ios.ios_vrf_address_family: + config: + state: overridden + +- ansible.builtin.assert: + that: + - result.msg == 'value of config parameter must not be empty for state overridden' + +- name: Rendered with empty configuration should give appropriate error message + register: result + ignore_errors: true + cisco.ios.ios_vrf_address_family: + config: + state: rendered + +- ansible.builtin.assert: + that: + - result.msg == 'value of config parameter must not be empty for state rendered' + +- name: Parsed with empty configuration should give appropriate error message + register: result + ignore_errors: true + cisco.ios.ios_vrf_address_family: + config: + state: parsed + +- ansible.builtin.debug: + msg: END ios_vrf_address_family empty_config integration tests on connection={{ ansible_connection }} diff --git a/tests/integration/targets/ios_vrf_address_family/tests/common/gathered.yaml b/tests/integration/targets/ios_vrf_address_family/tests/common/gathered.yaml new file mode 100644 index 000000000..471af613a --- /dev/null +++ b/tests/integration/targets/ios_vrf_address_family/tests/common/gathered.yaml @@ -0,0 +1,23 @@ +--- +- ansible.builtin.debug: + msg: START ios_vrf_address_family gathered integration tests on connection={{ ansible_connection }} + +- ansible.builtin.include_tasks: _remove_config.yaml + +- ansible.builtin.include_tasks: _populate.yaml + +- block: + - name: Gather existing running configuration + register: result + cisco.ios.ios_vrf_address_family: + config: + state: gathered + + - name: Assert + ansible.builtin.assert: + that: + - result.changed == false + - gathered['after'] == result['gathered'] + + always: + - ansible.builtin.include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/ios_vrf_address_family/tests/common/merged.yaml b/tests/integration/targets/ios_vrf_address_family/tests/common/merged.yaml new file mode 100644 index 000000000..1134b0974 --- /dev/null +++ b/tests/integration/targets/ios_vrf_address_family/tests/common/merged.yaml @@ -0,0 +1,57 @@ +--- +- ansible.builtin.debug: + msg: Start ios_vrf_address_family merged integration tests connection={{ ansible_connection}} + +- ansible.builtin.include_tasks: _remove_config.yaml + +- block: + - name: Merge provided configuration with device configuration + cisco.ios.ios_vrf_address_family: &merged + config: + - name: test1 + address_families: + - afi: "ipv4" + safi: "unicast" + export: + map: "testing-map" + import_config: + map: "import-map" + - name: test2 + address_families: + - afi: "ipv4" + safi: "unicast" + export: + map: "testing-map1" + import_config: + map: "import-map1" + inter_as_hybrid: + csc: + next_hop: "1.2.3.4" + register: result + + - name: Assert that correct set of commands were generated + ansible.builtin.assert: + that: + - "{{ merged['commands'] | symmetric_difference(result['commands']) | length == 0 }}" + + - name: Assert that before dicts are correctly generated + ansible.builtin.assert: + that: + - merged['before'] == {} + + - name: Assert that after dict is correctly generated + ansible.builtin.assert: + that: + - merged['after'] == result['after'] + + - name: Merge the provided configuration with the existing running configuration (idempotent) + cisco.ios.ios_vrf_address_family: *merged + register: result + + - name: Assert that the previous task was idempotent + ansible.builtin.assert: + that: + - merged['after'] == result['after'] + + always: + - ansible.builtin.include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/ios_vrf_address_family/tests/common/overridden.yaml b/tests/integration/targets/ios_vrf_address_family/tests/common/overridden.yaml new file mode 100644 index 000000000..5560ec3f2 --- /dev/null +++ b/tests/integration/targets/ios_vrf_address_family/tests/common/overridden.yaml @@ -0,0 +1,59 @@ +--- +- ansible.builtin.debug: + msg: START ios_vrf_address_family overridden integration tests on connection={{ ansible_connection }} + +- ansible.builtin.include_tasks: _populate.yaml + +- ansible.builtin.include_tasks: _remove_config.yaml + +- block: + - name: Override the provided configuration with the existing running configuration + cisco.ios.ios_vrf_address_family: &overridden + config: + - name: VRF1 + address_families: + - afi: "ipv4" + safi: "unicast" + inter_as_hybrid: + csc: + next_hop: "2.3.4.5" + mdt: + auto_discovery: + pim: + pim_tlv_announce: + mdt_hello_enable: true + state: overridden + register: result + + - name: Assert that correct set of commands were generated + ansible.builtin.assert: + that: + - "{{ overridden['commands'] == result['commands'] }}" + + - name: Assert that before dicts are correctly generated + ansible.builtin.assert: + that: + - "{{ overridden['before'] == result['before'] }}" + + - name: Assert that after dict is correctly generated + ansible.builtin.assert: + that: + - "{{ overridden['after'] | symmetric_difference(result['after']) |length == 0 }}" + + - name: Idempotency check + cisco.ios.ios_vrf_address_family: *overridden + register: result + + - name: Assert that no changes were made + ansible.builtin.assert: + that: + - result['changed'] == false + - result.commands|length == 0 + + - name: Assert that before dict is correctly generated + ansible.builtin.assert: + that: + - "{{ overridden['after'] | symmetric_difference(result['before']) |length == 0 }}" + + always: + - ansible.builtin.include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/ios_vrf_address_family/tests/common/parsed.yaml b/tests/integration/targets/ios_vrf_address_family/tests/common/parsed.yaml new file mode 100644 index 000000000..b076d3695 --- /dev/null +++ b/tests/integration/targets/ios_vrf_address_family/tests/common/parsed.yaml @@ -0,0 +1,13 @@ +--- +- ansible.builtin.debug: + msg: START ios_vrf_address_family parsed integration tests on connection={{ ansible_connection }} + +- name: Parse externally provided VRF configuration + register: result + cisco.ios.ios_vrf_address_family: + running_config: "{{ lookup('file', './_parsed.cfg') }}" + state: parsed + +- ansible.builtin.assert: + that: + - result.changed == false diff --git a/tests/integration/targets/ios_vrf_address_family/tests/common/rendered.yaml b/tests/integration/targets/ios_vrf_address_family/tests/common/rendered.yaml new file mode 100644 index 000000000..95ca44940 --- /dev/null +++ b/tests/integration/targets/ios_vrf_address_family/tests/common/rendered.yaml @@ -0,0 +1,43 @@ +--- +- ansible.builtin.debug: + msg: START ios_vrf_address_family rendered integration tests on connection={{ ansible_connection }} + +- ansible.builtin.include_tasks: _remove_config.yaml + +- name: Render provided configuration with device configuration + cisco.ios.ios_vrf_address_family: + config: + - name: test1 + address_families: + - afi: "ipv4" + safi: "unicast" + bgp: + next_hop: + loopback: 40 + export: + ipv4: + multicast: + map: "single" + prefix: 345 + unicast: + allow_evpn: true + map: "test-map" + prefix: 67 + map: "testing-map" + import_config: + ipv4: + multicast: + map: "import-map" + prefix: 89 + unicast: + allow_evpn: true + limit: 12 + map: "ran-map" + map: "import-map" + state: rendered + register: result + +- name: Assert that correct set of commands were rendered + ansible.builtin.assert: + that: + - result.changed == false diff --git a/tests/integration/targets/ios_vrf_address_family/tests/common/replaced.yaml b/tests/integration/targets/ios_vrf_address_family/tests/common/replaced.yaml new file mode 100644 index 000000000..f95733af3 --- /dev/null +++ b/tests/integration/targets/ios_vrf_address_family/tests/common/replaced.yaml @@ -0,0 +1,54 @@ +--- +- ansible.builtin.debug: + msg: Start ios_vrf_address_family replaced integration tests connection={{ ansible_connection}} + +- ansible.builtin.include_tasks: _remove_config.yaml + +- ansible.builtin.include_tasks: _populate.yaml + +- block: + - name: Replace given vrf configuration with provided configurations + cisco.ios.ios_vrf_address_family: + config: + - name: test1 + address_families: + - afi: "ipv4" + safi: "unicast" + bgp: + next_hop: + loopback: 40 + export: + ipv4: + multicast: + map: "single" + prefix: 345 + unicast: + allow_evpn: true + map: "test-map" + prefix: 67 + map: "testing-map" + import_config: + ipv4: + multicast: + map: "import-map" + prefix: 89 + unicast: + allow_evpn: true + limit: 12 + map: "ran-map" + map: "import-map" + state: replaced + register: result + + - name: Assert that correct set of commands were generated + ansible.builtin.assert: + that: + - "{{ replaced['commands'] | symmetric_difference(result['commands']) | length == 0 }}" + + - name: Assert that before dict is correctly generated + ansible.builtin.assert: + that: + - "{{ replaced['before'] == result['before'] }}" + + always: + - ansible.builtin.include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/ios_vrf_address_family/vars/main.yaml b/tests/integration/targets/ios_vrf_address_family/vars/main.yaml new file mode 100644 index 000000000..a1f45d9a4 --- /dev/null +++ b/tests/integration/targets/ios_vrf_address_family/vars/main.yaml @@ -0,0 +1,157 @@ +--- +merged: + before: {} + commands: + - vrf definition test2 + - address-family ipv4 unicast + - export map testing-map1 + - import map import-map1 + - inter-as-hybrid csc next-hop 1.2.3.4 + - vrf definition test1 + - address-family ipv4 unicast + - export map testing-map + - import map import-map + after: + - name: test1 + address_families: + - afi: "ipv4" + safi: "unicast" + - name: test2 + address_families: + - afi: "ipv4" + safi: "unicast" + inter_as_hybrid: + csc: + next_hop: "1.2.3.4" + +replaced: + before: + - name: test1 + address_families: + - afi: "ipv4" + safi: "unicast" + inter_as_hybrid: + next_hop: "1.0.0.0" + mdt: + auto_discovery: + pim: + pim_tlv_announce: + mdt_hello_enable: true + + commands: + - vrf definition test1 + - address-family ipv4 unicast + - export map testing-map + - import map import-map + - no inter-as-hybrid next-hop 1.0.0.0 + - no mdt auto-discovery pim pim-tlv-announce mdt-hello-enable + + after: + - name: test1 + address_families: + - afi: "ipv4" + safi: "unicast" + +overridden: + before: {} + commands: + - vrf definition VRF1 + - address-family ipv4 unicast + - inter-as-hybrid csc next-hop 2.3.4.5 + - mdt auto-discovery pim pim-tlv-announce mdt-hello-enable + after: + - name: VRF1 + address_families: + - afi: "ipv4" + safi: "unicast" + inter_as_hybrid: + csc: + next_hop: "2.3.4.5" + mdt: + auto_discovery: + pim: + pim_tlv_announce: + mdt_hello_enable: true + +gathered: + after: + - name: test1 + address_families: + - afi: "ipv4" + safi: "unicast" + inter_as_hybrid: + next_hop: "1.0.0.0" + mdt: + auto_discovery: + pim: + pim_tlv_announce: + mdt_hello_enable: true + +parsed: + after: + - address_families: + - afi: "ipv4" + bgp: + next_hop: + loopback: 23 + export: + ipv4: + unicast: + allow_evpn: true + map: "test" + prefix: 37 + map: "testing-map2" + import_config: + ipv4: + unicast: + allow_evpn: true + limit: 56 + map: "import" + inter_as_hybrid: + next_hop: "1.2.3.4" + mdt: + auto_discovery: + pim: + pim_tlv_announce: + mdt_hello_enable: true + receiver_site: true + route_target: + export: "10.12.0.1:20" + import_config: "10.0.0.1:30" + safi: "unicast" + - name: test + +deleted: + before: + - name: test1 + address_families: + - afi: "ipv4" + safi: "unicast" + bgp: + next_hop: + loopback: 40 + export: + ipv4: + multicast: + map: "single" + prefix: 345 + unicast: + allow_evpn: true + map: "test-map" + prefix: 67 + map: "testing-map" + import_config: + ipv4: + multicast: + map: "import-map" + prefix: 89 + unicast: + allow_evpn: true + limit: 12 + map: "ran-map" + map: "import-map" + commands: + - vrf definition test1 + - no address-family ipv4 unicast + after: + - name: test1 diff --git a/tests/unit/modules/network/ios/test_ios_vrf_address_family.py b/tests/unit/modules/network/ios/test_ios_vrf_address_family.py new file mode 100644 index 000000000..8af6c81eb --- /dev/null +++ b/tests/unit/modules/network/ios/test_ios_vrf_address_family.py @@ -0,0 +1,407 @@ +# (c) 2021 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 . + +# Make coding more python3-ish + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +from textwrap import dedent +from unittest.mock import patch + +from ansible_collections.cisco.ios.plugins.modules import ios_vrf_address_family +from ansible_collections.cisco.ios.tests.unit.modules.utils import set_module_args + +from .ios_module import TestIosModule + + +class TestIosVrfAddressFamilyModule(TestIosModule): + """Tests the ios_vrf_address_family module.""" + + module = ios_vrf_address_family + + def setUp(self): + """Setup for ios_vrf_address_family module tests.""" + super(TestIosVrfAddressFamilyModule, self).setUp() + + self.mock_get_resource_connection = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module_base." + "get_resource_connection", + ) + self.get_resource_connection = self.mock_get_resource_connection.start() + + self.mock_get_config = patch( + "ansible_collections.cisco.ios.plugins.module_utils.network.ios.facts.vrf_address_family.vrf_address_family." + "Vrf_address_familyFacts.get_config", + ) + self.get_config = self.mock_get_config.start() + + def tearDown(self): + """Tear down for ios_vrf_address_family module tests.""" + super(TestIosVrfAddressFamilyModule, self).tearDown() + self.get_resource_connection.stop() + self.get_config.stop() + + def test_ios_vrf_address_family_merged_idempotent(self): + """Test the idempotent nature of the ios_vrf_address_family module in merged state.""" + run_cfg = dedent( + """\ + vrf definition test + address-family ipv4 unicast + import map "import-map" + export map "testing-map" + export ipv4 unicast 37 map test allow-evpn + inter-as-hybrid csc next-hop 1.2.3.4 + route-target export 10.12.0.1:20 + route-target import 10.0.0.1:30 + mdt auto-discovery ingress-replication inter-as mdt-hello-enable + """, + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=[ + dict( + name="test", + address_families=[ + dict( + afi="ipv4", + safi="unicast", + bgp=dict(next_hop=dict(loopback=23)), + export=dict( + map="testing-map", + ipv4=dict( + unicast=dict( + prefix=37, + map="test", + allow_evpn=True, + ), + ), + ), + import_config=dict( + map="import-map", + ), + inter_as_hybrid=dict( + csc=dict(next_hop="1.2.3.4"), + ), + route_target=dict( + export="10.12.0.1:20", + import_config="10.0.0.1:30", + ), + mdt=dict( + auto_discovery=dict( + ingress_replication=dict( + inter_as=dict(mdt_hello_enable=True), + ), + ), + ), + ), + ], + ), + ], + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_ios_vrf_address_family_merged(self): + """Test the merged state of the ios_vrf_address_family module.""" + set_module_args( + dict( + config=[ + dict( + name="VRF1", + address_families=[ + dict( + afi="ipv4", + safi="unicast", + export=dict( + map="testing-map", + ), + import_config=dict( + map="import-map", + ), + inter_as_hybrid=dict( + csc=dict(next_hop="1.2.3.4"), + ), + route_target=dict( + export="10.12.0.1:20", + import_config="10.0.0.1:10", + ), + ), + ], + ), + ], + state="merged", + ), + ) + commands = [ + "vrf definition VRF1", + "address-family ipv4 unicast", + "export map testing-map", + "import map import-map", + "inter-as-hybrid csc next-hop 1.2.3.4", + "route-target export 10.12.0.1:20", + "route-target import 10.0.0.1:10", + ] + result = self.execute_module(changed=True) + self.assertEqual((result["commands"]), (commands)) + + def test_ios_vrf_address_family_replaced(self): + """Test the replaced state of the ios_vrf_address_family module.""" + run_cfg = dedent( + """\ + vrf definition VRF1 + address-family ipv4 unicast + import map "import-map" + export map "testing-map" + inter-as-hybrid csc next-hop 1.2.3.4 + route-target export 10.12.0.1:20 + route-target import 10.0.0.1:10 + exit-address-family + """, + ) + self.get_config.return_value = run_cfg + + set_module_args( + dict( + config=[ + dict( + name="VRF2", + address_families=[ + dict( + afi="ipv4", + safi="unicast", + export=dict( + map="testing-map", + ), + import_config=dict( + map="import-map", + ), + inter_as_hybrid=dict( + csc=dict(next_hop="1.2.3.4"), + ), + route_target=dict( + export="10.12.0.1:20", + import_config="10.0.0.1:10", + ), + ), + ], + ), + ], + state="replaced", + ), + ) + commands = [ + "vrf definition VRF2", + "address-family ipv4 unicast", + "export map testing-map", + "import map import-map", + "inter-as-hybrid csc next-hop 1.2.3.4", + "route-target export 10.12.0.1:20", + "route-target import 10.0.0.1:10", + ] + result = self.execute_module(changed=True) + self.assertEqual((result["commands"]), (commands)) + + def test_ios_vrf_address_family_replaced_idempotent(self): + """Test the idempotent nature of the ios_vrf_address_family module in replaced state.""" + run_cfg = dedent( + """\ + vrf definition VRF2 + address-family ipv4 unicast + import map "import-map" + export map "testing-map" + inter-as-hybrid csc next-hop 1.2.3.4 + route-target export 10.12.0.1:20 + route-target import 10.0.0.1:10 + """, + ) + self.get_config.return_value = run_cfg + + set_module_args( + dict( + config=[ + dict( + name="VRF2", + address_families=[ + dict( + afi="ipv4", + safi="unicast", + export=dict( + map="testing-map", + ), + import_config=dict( + map="import-map", + ), + inter_as_hybrid=dict( + csc=dict(next_hop="1.2.3.4"), + ), + route_target=dict( + export="10.12.0.1:20", + import_config="10.0.0.1:10", + ), + ), + ], + ), + ], + state="replaced", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_ios_vrf_address_family_overridden_idempotent(self): + """Test the idempotent nature of the ios_vrf_address_family module in overridden state.""" + run_cfg = dedent( + """\ + vrf definition VRF7 + address-family ipv4 unicast + bgp next-hop loopback 40 + import map import-map1 + export map testing-map2 + inter-as-hybrid csc next-hop 1.2.3.4 + """, + ) + self.get_config.return_value = run_cfg + + set_module_args( + dict( + config=[ + dict( + name="VRF7", + address_families=[ + dict( + afi="ipv4", + safi="unicast", + bgp=dict(next_hop=dict(loopback=40)), + export=dict( + map="testing-map2", + ), + import_config=dict( + map="import-map1", + ), + inter_as_hybrid=dict( + csc=dict(next_hop="1.2.3.4"), + ), + ), + ], + ), + ], + state="overridden", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_ios_vrf_address_family_deleted_idempotent(self): + """Test the idempotent nature of the ios_vrf_address_family module in deleted state.""" + run_cfg = dedent( + """\ + """, + ) + self.get_config.return_value = run_cfg + set_module_args(dict(config=[], state="deleted")) + + result = self.execute_module(changed=False) + self.assertEqual(result["commands"], []) + + def test_ios_vrf_address_family_rendered(self): + """Test the rendered state of the ios_vrf_address_family module.""" + set_module_args( + dict( + config=[ + dict( + name="VRF1", + address_families=[ + dict( + afi="ipv4", + safi="unicast", + export=dict( + map="testing-map", + ), + import_config=dict( + map="import-map", + ), + inter_as_hybrid=dict( + csc=dict(next_hop="1.2.3.4"), + ), + ), + ], + ), + ], + state="rendered", + ), + ) + commands = [ + "vrf definition VRF1", + "address-family ipv4 unicast", + "export map testing-map", + "import map import-map", + "inter-as-hybrid csc next-hop 1.2.3.4", + ] + result = self.execute_module(changed=False) + self.assertEqual((result["rendered"]), (commands)) + + def test_ios_vrf_address_family_parsed(self): + """Test the parsed state of the ios_vrf_address_family module.""" + run_cfg = dedent( + """\ + vrf definition test + address-family ipv4 unicast + import map "import-map" + export map "testing-map" + inter-as-hybrid csc next-hop 1.2.3.4 + mdt auto-discovery ingress-replication inter-as mdt-hello-enable + exit-address-family + """, + ) + set_module_args(dict(running_config=run_cfg, state="parsed")) + result = self.execute_module(changed=False) + parsed_list = [ + { + "name": "test", + "address_families": [ + { + "afi": "ipv4", + "safi": "unicast", + "import_config": { + "map": "import-map", + }, + "export": { + "map": "testing-map", + }, + "inter_as_hybrid": { + "csc": { + "next_hop": "1.2.3.4", + }, + }, + "mdt": { + "auto_discovery": { + "ingress_replication": { + "inter_as": { + "mdt_hello_enable": True, + }, + }, + }, + }, + }, + ], + }, + ] + + self.assertEqual(parsed_list, result["parsed"])