diff --git a/changelogs/fragments/T6821_route_map_options.yml b/changelogs/fragments/T6821_route_map_options.yml new file mode 100644 index 00000000..6d1e974b --- /dev/null +++ b/changelogs/fragments/T6821_route_map_options.yml @@ -0,0 +1,3 @@ +--- +minor_changes: + - vyos_route_maps - add support for as-path-prepend policy option diff --git a/docs/vyos.vyos.vyos_route_maps_module.rst b/docs/vyos.vyos.vyos_route_maps_module.rst index 4e0c5322..f6a74d46 100644 --- a/docs/vyos.vyos.vyos_route_maps_module.rst +++ b/docs/vyos.vyos.vyos_route_maps_module.rst @@ -1,2158 +1,2248 @@ .. _vyos.vyos.vyos_route_maps_module: ************************* vyos.vyos.vyos_route_maps ************************* **Route Map resource module** Version added: 1.0.0 .. contents:: :local: :depth: 1 Synopsis -------- - This module manages route map configurations on devices running VYOS. Parameters ---------- .. raw:: html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Parameter Choices/Defaults Comments
config
list / elements=dictionary
A list of route-map configuration.
entries
list / elements=dictionary
Route Map rules.

aliases: rules
action
string
    Choices:
  • deny
  • permit
Action for matching routes
call
string
Route map name
continue_sequence
integer
Continue on a different entry within the route-map.
description
string
Description for the rule.
match
dictionary
Route parameters to match.
as_path
string
Set as-path.
community
dictionary
BGP community attribute.
community_list
string
BGP community-list to match
exact_match
boolean
    Choices:
  • no
  • yes
BGP community-list to match
extcommunity
string
Extended community name.
interface
string
First hop interface of a route to match.
ip
dictionary
IP prefix parameters to match.
address
dictionary
IP address of route to match.
list_type
string
    Choices:
  • access-list
  • prefix-list
type of list
value
string
value of access-list and prefix list
next_hop
dictionary
next hop prefix list.
list_type
string
    Choices:
  • access-list
  • prefix-list
type of list
value
string
value of access-list and prefix list
route_source
dictionary
IP route-source to match
list_type
string
    Choices:
  • access-list
  • prefix-list
type of list
value
string
value of access-list and prefix list
ipv6
dictionary
IPv6 prefix parameters to match.
address
dictionary
IPv6 address of route to match.
list_type
string
    Choices:
  • access-list
  • prefix-list
type of list
value
string
value of access-list and prefix list
next_hop
string
next-hop ipv6 address IPv6 <h:h:h:h:h:h:h:h>.
large_community_large_community_list
string
BGP large-community-list to match.
metric
integer
Route metric <1-65535>.
origin
string
    Choices:
  • ebgp
  • ibgp
  • incomplete
bgp origin.
peer
string
Peer IP address <x.x.x.x>.
+
+ protocol + +
+ string +
+
+
    Choices: +
  • babel
  • +
  • bgp
  • +
  • connected
  • +
  • isis
  • +
  • kernel
  • +
  • ospf
  • +
  • ospfv3
  • +
  • rip
  • +
  • ripng
  • +
  • static
  • +
  • table
  • +
  • vnc
  • +
+
+
Source protocol to match.
+
rpki
string
    Choices:
  • notfound
  • invalid
  • valid
RPKI validation value.
on_match
dictionary
Exit policy on matches.
goto
integer
Rule number to goto on match <1-65535>.
next
boolean
    Choices:
  • no
  • yes
Next sequence number to goto on match.
sequence
integer
Route map rule number <1-65535>.
set
dictionary
Route parameters.
aggregator
dictionary
Border Gateway Protocol (BGP) aggregator attribute.
as
string
AS number of an aggregation.
ip
string
IP address.
as_path_exclude
string
BGP AS path exclude string ex "456 64500 45001"
as_path_prepend
string
Prepend string for a Border Gateway Protocol (BGP) AS-path attribute.
atomic_aggregate
boolean
    Choices:
  • no
  • yes
Border Gateway Protocol (BGP) atomic aggregate attribute.
bgp_extcommunity_rt
string
ExtCommunity in format AS:value
comm_list
dictionary
Border Gateway Protocol (BGP) communities matching a community-list.
comm_list
string
BGP communities with a community-list.
delete
boolean
    Choices:
  • no
  • yes
Delete BGP communities matching the community-list.
community
dictionary
Border Gateway Protocol (BGP) community attribute.
value
string
Community in 4 octet AS:value format or it can be from local-AS, no-advertise,no-expert,internet,additive,none.
+
+ extcommunity_bandwidth + +
+ string +
+
+ +
Set Bandwidth of Origin value. 1-25600|cumulative|num-multipaths VPN extended community
+
+
+ extcommunity_bandwidth_non_transitive + +
+ boolean +
+
+
    Choices: +
  • no
  • +
  • yes
  • +
+
+
Set the bandwidth extended community encoded as non-transitive True/False VPN extended community
+
extcommunity_rt
string
Set route target value.ASN:nn_or_IP_address:nn VPN extended community.
extcommunity_soo
string
Set Site of Origin value. ASN:nn_or_IP_address:nn VPN extended community
ip_next_hop
string
IP address.
ipv6_next_hop
dictionary
Nexthop IPv6 address.
ip_type
string
    Choices:
  • global
  • local
Global or Local
value
string
ipv6 address
large_community
string
Set BGP large community value.
local_preference
string
Border Gateway Protocol (BGP) local preference attribute.Example <0-4294967295>.
metric
string
Destination routing protocol metric. Example <0-4294967295>.
metric_type
string
    Choices:
  • type-1
  • type-2
Open Shortest Path First (OSPF) external metric-type.
origin
string
    Choices:
  • egp
  • igp
  • incomplete
Set bgp origin.
originator_id
string
Border Gateway Protocol (BGP) originator ID attribute. Originator IP address.
src
string
Source address for route. Example <x.x.x.x> IP address.
+
+ table + +
+ string +
+
+ +
Set prefixes to table. Example <1-200>
+
tag
string
Tag value for routing protocol. Example <1-65535>
weight
string
Border Gateway Protocol (BGP) weight attribute. Example <0-4294967295>
route_map
string
Route map name.
running_config
string
This option is used only with state parsed.
The value of this option should be the output received from the VYOS device by executing the command show configuration commands | grep route-map.
The state parsed reads the configuration from show configuration commands | grep route-map 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:
  • deleted
  • merged ←
  • overridden
  • replaced
  • gathered
  • rendered
  • parsed
The state the configuration should be left in.

Notes ----- .. note:: - Tested against vyos 1.3.8 - This module works with connection ``network_cli``. Examples -------- .. code-block:: yaml # Using merged # Before state # vyos@vyos:~$ show configuration commands | match "set policy route-map" # vyos@vyos:~$ - name: Merge the provided configuration with the existing running configuration register: result vyos.vyos.vyos_route_maps: &id001 config: - route_map: test1 entries: - sequence: 1 description: "test" action: permit continue: 2 on_match: next: true - route_map: test3 entries: - sequence: 1 action: permit match: rpki: invalid metric: 1 peer: 192.0.2.32 set: local_preference: 4 metric: 5 metric_type: "type-1" origin: egp originator_id: 192.0.2.34 tag: 5 weight: 4 state: merged # After State # vyos@vyos:~$ show configuration commands | match "set policy route-maps" # set policy route-map test1 rule 1 description test # set policy route-map test1 rule 1 action permit # set policy route-map test1 rule 1 continue 2 # set policy route-map test1 rule 1 on-match next # set policy route-map test3 rule 1 action permit # set policy route-map test3 rule 1 set local-preference 4 # set policy route-map test3 rule 1 set metric 5 # set policy route-map test3 rule 1 set metric-type type-1 # set policy route-map test3 rule 1 set origin egp # set policy route-map test3 rule 1 set originator-id 192.0.2.34 # set policy route-map test3 rule 1 set tag 5 # set policy route-map test3 rule 1 set weight 4 # set policy route-map test3 rule 1 match metric 1 # set policy route-map test3 rule 1 match peer 192.0.2.32 # set policy route-map test3 rule 1 match rpki invalid # "after": [ # { # "entries": [ # { # "action": "permit", # "continue_sequence": 2, # "description": "test", # "on_match": { # "next": true # }, # "sequence": 1 # } # ], # "route_map": "test1" # }, # { # "entries": [ # { # "action": "permit", # "match": { # "metric": 1, # "peer": "192.0.2.32", # "rpki": "invalid" # }, # "sequence": 1, # "set": { # "local_preference": "4", # "metric": "5", # "metric_type": "type-1", # "origin": "egp", # "originator_id": "192.0.2.34", # "tag": "5", # "weight": "4" # } # } # ], # "route_map": "test3" # } # ], # "before": [], # "changed": true, # "commands": [ # "set policy route-map test1 rule 1 description test", # "set policy route-map test1 rule 1 action permit", # "set policy route-map test1 rule 1 continue 2", # "set policy route-map test1 rule 1 on-match next", # "set policy route-map test3 rule 1 action permit", # "set policy route-map test3 rule 1 set local-preference 4", # "set policy route-map test3 rule 1 set metric 5", # "set policy route-map test3 rule 1 set metric-type type-1", # "set policy route-map test3 rule 1 set origin egp", # "set policy route-map test3 rule 1 set originator-id 192.0.2.34", # "set policy route-map test3 rule 1 set tag 5", # "set policy route-map test3 rule 1 set weight 4", # "set policy route-map test3 rule 1 match metric 1", # "set policy route-map test3 rule 1 match peer 192.0.2.32", # "set policy route-map test3 rule 1 match rpki invalid" # ], # Using replaced: # -------------- # Before state: # vyos@vyos:~$ show configuration commands | match "set route-map policy" # set policy route-map test2 rule 1 action 'permit' # set policy route-map test2 rule 1 description 'test' # set policy route-map test2 rule 1 on-match next # set policy route-map test2 rule 2 action 'permit' # set policy route-map test2 rule 2 on-match goto '4' # set policy route-map test3 rule 1 action 'permit' # set policy route-map test3 rule 1 match metric '1' # set policy route-map test3 rule 1 match peer '192.0.2.32' # set policy route-map test3 rule 1 match rpki 'invalid' # set policy route-map test3 rule 1 set community 'internet' # set policy route-map test3 rule 1 set ip-next-hop '192.0.2.33' # set policy route-map test3 rule 1 set local-preference '4' # set policy route-map test3 rule 1 set metric '5' # set policy route-map test3 rule 1 set metric-type 'type-1' # set policy route-map test3 rule 1 set origin 'egp' # set policy route-map test3 rule 1 set originator-id '192.0.2.34' # set policy route-map test3 rule 1 set tag '5' # set policy route-map test3 rule 1 set weight '4' # # - name: Replace the provided configuration with the existing running configuration # register: result # vyos.vyos.vyos_route_maps: &id001 # config: # - route_map: test3 # entries: # - sequence: 1 # action: permit # match: # rpki: invalid # metric: 3 # peer: 192.0.2.35 # set: # local_preference: 6 # metric: 4 # metric_type: "type-1" # origin: egp # originator_id: 192.0.2.34 # tag: 4 # weight: 4 # state: replaced # After state: # vyos@vyos:~$ show configuration commands | match "set policy route-map" # set policy route-map test3 rule 1 set local-preference 6 # set policy route-map test3 rule 1 set metric 4 # set policy route-map test3 rule 1 set tag 4 # set policy route-map test3 rule 1 match metric 3 # set policy route-map test3 rule 1 match peer 192.0.2.35 # vyos@vyos:~$ # # # Module Execution: # # "after": [ # { # "entries": [ # { # "action": "permit", # "description": "test", # "on_match": { # "next": true # }, # "sequence": 1 # }, # { # "action": "permit", # "on_match": { # "goto": 4 # }, # "sequence": 2 # } # ], # "route_map": "test2" # }, # { # "entries": [ # { # "action": "permit", # "match": { # "metric": 3, # "peer": "192.0.2.35", # "rpki": "invalid" # }, # "sequence": 1, # "set": { # "local_preference": "6", # "metric": "4", # "metric_type": "type-1", # "origin": "egp", # "originator_id": "192.0.2.34", # "tag": "4", # "weight": "4" # } # } # ], # "route_map": "test3" # } # ], # "before": [ # { # "entries": [ # { # "action": "permit", # "description": "test", # "on_match": { # "next": true # }, # "sequence": 1 # }, # { # "action": "permit", # "on_match": { # "goto": 4 # }, # "sequence": 2 # } # ], # "route_map": "test2" # }, # { # "entries": [ # { # "action": "permit", # "match": { # "metric": 1, # "peer": "192.0.2.32", # "rpki": "invalid" # }, # "sequence": 1, # "set": { # "community": { # "value": "internet" # }, # "ip_next_hop": "192.0.2.33", # "local_preference": "4", # "metric": "5", # "metric_type": "type-1", # "origin": "egp", # "originator_id": "192.0.2.34", # "tag": "5", # "weight": "4" # } # } # ], # "route_map": "test3" # } # ], # "changed": true, # "commands": [ # "delete policy route-map test3 rule 1 set ip-next-hop 192.0.2.33", # "set policy route-map test3 rule 1 set local-preference 6", # "set policy route-map test3 rule 1 set metric 4", # "set policy route-map test3 rule 1 set tag 4", # "delete policy route-map test3 rule 1 set community internet", # "set policy route-map test3 rule 1 match metric 3", # "set policy route-map test3 rule 1 match peer 192.0.2.35" # ], # # Using deleted: # ------------- # Before state: # vyos@vyos:~$ show configuration commands | match "set policy route-map" # set policy route-map test3 rule 1 set local-preference 6 # set policy route-map test3 rule 1 set metric 4 # set policy route-map test3 rule 1 set tag 4 # set policy route-map test3 rule 1 match metric 3 # set policy route-map test3 rule 1 match peer 192.0.2.35 # vyos@vyos:~$ # # - name: Delete the provided configuration # register: result # vyos.vyos.vyos_route_maps: # config: # state: deleted # After state: # vyos@vyos:~$ show configuration commands | match "set policy route-map" # vyos@vyos:~$ # # # Module Execution: # # "after": [], # "before": [ # { # "entries": [ # { # "action": "permit", # "match": { # "metric": 3, # "peer": "192.0.2.35", # }, # "sequence": 1, # "set": { # "local_preference": "6", # "metric": "4", # "tag": "4", # } # } # ], # "route_map": "test3" # } # ], # "changed": true, # "commands": [ # "delete policy route-map test3" # ], # # using gathered: # -------------- # # Before state: # vyos@vyos:~$ show configuration commands | match "set policy route-maps" # set policy route-map test1 rule 1 description test # set policy route-map test1 rule 1 action permit # set policy route-map test1 rule 1 continue 2 # set policy route-map test1 rule 1 on-match next # set policy route-map test3 rule 1 action permit # set policy route-map test3 rule 1 set local-preference 4 # set policy route-map test3 rule 1 set metric 5 # set policy route-map test3 rule 1 set metric-type type-1 # set policy route-map test3 rule 1 set origin egp # set policy route-map test3 rule 1 set originator-id 192.0.2.34 # set policy route-map test3 rule 1 set tag 5 # set policy route-map test3 rule 1 set weight 4 # set policy route-map test3 rule 1 match metric 1 # set policy route-map test3 rule 1 match peer 192.0.2.32 # set policy route-map test3 rule 1 match rpki invalid # # - name: gather configs # vyos.vyos.vyos_route_maps: # state: gathered # "gathered": [ # { # "entries": [ # { # "action": "permit", # "continue_sequence": 2, # "description": "test", # "on_match": { # "next": true # }, # "sequence": 1 # } # ], # "route_map": "test1" # }, # { # "entries": [ # { # "action": "permit", # "match": { # "metric": 1, # "peer": "192.0.2.32", # "rpki": "invalid" # }, # "sequence": 1, # "set": { # "local_preference": "4", # "metric": "5", # "metric_type": "type-1", # "origin": "egp", # "originator_id": "192.0.2.34", # "tag": "5", # "weight": "4" # } # } # ], # "route_map": "test3" # } # ] # Using parsed: # ------------ # parsed.cfg # set policy route-map test1 rule 1 description test # set policy route-map test1 rule 1 action permit # set policy route-map test1 rule 1 continue 2 # set policy route-map test1 rule 1 on-match next # set policy route-map test3 rule 1 action permit # set policy route-map test3 rule 1 set local-preference 4 # set policy route-map test3 rule 1 set metric 5 # set policy route-map test3 rule 1 set metric-type type-1 # set policy route-map test3 rule 1 set origin egp # set policy route-map test3 rule 1 set originator-id 192.0.2.34 # set policy route-map test3 rule 1 set tag 5 # set policy route-map test3 rule 1 set weight 4 # set policy route-map test3 rule 1 match metric 1 # set policy route-map test3 rule 1 match peer 192.0.2.32 # set policy route-map test3 rule 1 match rpki invalid # # - name: parse configs # vyos.vyos.vyos_route_maps: # running_config: "{{ lookup('file', './parsed.cfg') }}" # state: parsed # tags: # - parsed # # Module execution: # "parsed": [ # { # "entries": [ # { # "action": "permit", # "continue_sequence": 2, # "description": "test", # "on_match": { # "next": true # }, # "sequence": 1 # } # ], # "route_map": "test1" # }, # { # "entries": [ # { # "action": "permit", # "match": { # "metric": 1, # "peer": "192.0.2.32", # "rpki": "invalid" # }, # "sequence": 1, # "set": { # "local_preference": "4", # "metric": "5", # "metric_type": "type-1", # "origin": "egp", # "originator_id": "192.0.2.34", # "tag": "5", # "weight": "4" # } # } # ], # "route_map": "test3" # } # ] # # # Using rendered: # -------------- # - name: Structure provided configuration into device specific commands # register: result # vyos.vyos.vyos_route_maps: &id001 # config: # - route_map: test1 # entries: # - sequence: 1 # description: "test" # action: permit # continue_sequence: 2 # on_match: # next: True # - route_map: test3 # entries: # - sequence: 1 # action: permit # match: # rpki: invalid # metric: 1 # peer: 192.0.2.32 # set: # local_preference: 4 # metric: 5 # metric_type: "type-1" # origin: egp # originator_id: 192.0.2.34 # tag: 5 # weight: 4 # state: rendered # Module Execution: # "rendered": [ # "set policy route-map test1 rule 1 description test", # "set policy route-map test1 rule 1 action permit", # "set policy route-map test1 rule 1 continue 2", # "set policy route-map test1 rule 1 on-match next", # "set policy route-map test3 rule 1 action permit", # "set policy route-map test3 rule 1 set local-preference 4", # "set policy route-map test3 rule 1 set metric 5", # "set policy route-map test3 rule 1 set metric-type type-1", # "set policy route-map test3 rule 1 set origin egp", # "set policy route-map test3 rule 1 set originator-id 192.0.2.34", # "set policy route-map test3 rule 1 set tag 5", # "set policy route-map test3 rule 1 set weight 4", # "set policy route-map test3 rule 1 match metric 1", # "set policy route-map test3 rule 1 match peer 192.0.2.32", # "set policy route-map test3 rule 1 match rpki invalid" # ] # # # Using overridden: # -------------- # Before state: # vyos@vyos:~$ show configuration commands | match "set policy route-map" # set policy route-map test2 rule 1 action 'permit' # set policy route-map test2 rule 1 description 'test' # set policy route-map test2 rule 1 on-match next # set policy route-map test2 rule 2 action 'permit' # set policy route-map test2 rule 2 on-match goto '4' # set policy route-map test3 rule 1 action 'permit' # set policy route-map test3 rule 1 match metric '1' # set policy route-map test3 rule 1 match peer '192.0.2.32' # set policy route-map test3 rule 1 match rpki 'invalid' # set policy route-map test3 rule 1 set community 'internet' # set policy route-map test3 rule 1 set ip-next-hop '192.0.2.33' # set policy route-map test3 rule 1 set local-preference '4' # set policy route-map test3 rule 1 set metric '5' # set policy route-map test3 rule 1 set metric-type 'type-1' # set policy route-map test3 rule 1 set origin 'egp' # set policy route-map test3 rule 1 set originator-id '192.0.2.34' # set policy route-map test3 rule 1 set tag '5' # set policy route-map test3 rule 1 set weight '4' # # - name: Override the existing configuration with the provided running configuration # register: result # vyos.vyos.vyos_route_maps: &id001 # config: # - route_map: test3 # entries: # - sequence: 1 # action: permit # match: # rpki: invalid # metric: 3 # peer: 192.0.2.35 # set: # local_preference: 6 # metric: 4 # metric_type: "type-1" # origin: egp # originator_id: 192.0.2.34 # tag: 4 # weight: 4 # state: overridden # After state: # vyos@vyos:~$ show configuration commands | match "set policy route-map" # set policy route-map test3 rule 1 set metric-type 'type-1' # set policy route-map test3 rule 1 set origin 'egp' # set policy route-map test3 rule 1 set originator-id '192.0.2.34' # set policy route-map test3 rule 1 set weight '4' # set policy route-map test3 rule 1 set local-preference 6 # set policy route-map test3 rule 1 set metric 4 # set policy route-map test3 rule 1 set tag 4 # set policy route-map test3 rule 1 match metric 3 # set policy route-map test3 rule 1 match peer 192.0.2.35 # set policy route-map test3 rule 1 match rpki 'invalid' # Module Execution: # "after": [ # { # "entries": [ # { # "action": "permit", # "match": { # "metric": 3, # "peer": "192.0.2.35", # "rpki": "invalid" # }, # "sequence": 1, # "set": { # "local_preference": "6", # "metric": "4", # "metric_type": "type-1", # "origin": "egp", # "originator_id": "192.0.2.34", # "tag": "4", # "weight": "4" # } # } # ], # "route_map": "test3" # } # ], # "before": [ # { # "entries": [ # { # "action": "permit", # "description": "test", # "on_match": { # "next": true # }, # "sequence": 1 # }, # { # "action": "permit", # "on_match": { # "goto": 4 # }, # "sequence": 2 # } # ], # "route_map": "test2" # }, # { # "entries": [ # { # "action": "permit", # "match": { # "metric": 1, # "peer": "192.0.2.32", # "rpki": "invalid" # }, # "sequence": 1, # "set": { # "community": { # "value": "internet" # }, # "ip_next_hop": "192.0.2.33", # "local_preference": "4", # "metric": "5", # "metric_type": "type-1", # "origin": "egp", # "originator_id": "192.0.2.34", # "tag": "5", # "weight": "4" # } # } # ], # "route_map": "test3" # } # ], # "changed": true, # "commands": [ # "delete policy route-map test2", # "delete policy route-map test3 rule 1 set ip-next-hop 192.0.2.33", # "set policy route-map test3 rule 1 set local-preference 6", # "set policy route-map test3 rule 1 set metric 4", # "set policy route-map test3 rule 1 set tag 4", # "delete policy route-map test3 rule 1 set community internet", # "set policy route-map test3 rule 1 match metric 3", # "set policy route-map test3 rule 1 match peer 192.0.2.35" # ], Return Values ------------- Common return values are documented `here `_, the following are the fields unique to this module: .. raw:: html
Key Returned Description
after
dictionary
when changed
The resulting configuration after module execution.

Sample:
This output will always be in the same format as the module argspec.
before
dictionary
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 or purged
The set of commands pushed to the remote device.

Sample:
['set policy route-map test3 rule 1 set local-preference 6', 'set policy route-map test3 rule 1 set metric 4', 'set policy route-map test3 rule 1 set tag 4']
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:
['set policy route-map test3 rule 1 set local-preference 6', 'set policy route-map test3 rule 1 set metric 4', 'set policy route-map test3 rule 1 set tag 4']


Status ------ Authors ~~~~~~~ - Ashwini Mhatre (@amhatre) diff --git a/plugins/module_utils/network/vyos/argspec/route_maps/route_maps.py b/plugins/module_utils/network/vyos/argspec/route_maps/route_maps.py index 196db0c7..5b6d404d 100644 --- a/plugins/module_utils/network/vyos/argspec/route_maps/route_maps.py +++ b/plugins/module_utils/network/vyos/argspec/route_maps/route_maps.py @@ -1,221 +1,241 @@ # -*- 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 # cli_rm_builder. # # Manually editing this file is not advised. # # To update the argspec make the desired changes # in the module docstring and re-run # cli_rm_builder. # ############################################# """ The arg spec for the vyos_route_maps module """ class Route_mapsArgs(object): # pylint: disable=R0903 """The arg spec for the vyos_route_maps module""" argument_spec = { "config": { "type": "list", "elements": "dict", "options": { "route_map": {"type": "str"}, "entries": { "aliases": ["rules"], "type": "list", "elements": "dict", "options": { "sequence": {"type": "int"}, "call": {"type": "str"}, "description": {"type": "str"}, "action": {"type": "str", "choices": ["deny", "permit"]}, "continue_sequence": {"type": "int"}, "set": { "type": "dict", "options": { "aggregator": { "type": "dict", "options": { "ip": {"type": "str"}, "as": {"type": "str"}, }, }, "as_path_exclude": {"type": "str"}, "as_path_prepend": {"type": "str"}, "atomic_aggregate": {"type": "bool"}, "bgp_extcommunity_rt": {"type": "str"}, "comm_list": { "type": "dict", "options": { "comm_list": {"type": "str"}, "delete": {"type": "bool"}, }, }, "community": { "type": "dict", "options": {"value": {"type": "str"}}, }, "extcommunity_rt": {"type": "str"}, "extcommunity_soo": {"type": "str"}, + "extcommunity_bandwidth": {"type": "str"}, + "extcommunity_bandwidth_non_transitive": {"type": "bool"}, "ip_next_hop": {"type": "str"}, "ipv6_next_hop": { "type": "dict", "options": { "ip_type": { "type": "str", "choices": ["global", "local"], }, "value": {"type": "str"}, }, }, "large_community": {"type": "str"}, "local_preference": {"type": "str"}, "metric": {"type": "str"}, "metric_type": { "type": "str", "choices": ["type-1", "type-2"], }, "origin": { "type": "str", "choices": ["egp", "igp", "incomplete"], }, "originator_id": {"type": "str"}, "src": {"type": "str"}, "tag": {"type": "str"}, "weight": {"type": "str"}, + "table": {"type": "str"}, }, }, "match": { "type": "dict", "options": { "as_path": {"type": "str"}, "community": { "type": "dict", "options": { "community_list": {"type": "str"}, "exact_match": {"type": "bool"}, }, }, "extcommunity": {"type": "str"}, "interface": {"type": "str"}, "ip": { "type": "dict", "options": { "address": { "type": "dict", "options": { "list_type": { "type": "str", "choices": [ "access-list", "prefix-list", ], }, "value": {"type": "str"}, }, }, "next_hop": { "type": "dict", "options": { "list_type": { "type": "str", "choices": [ "access-list", "prefix-list", ], }, "value": {"type": "str"}, }, }, "route_source": { "type": "dict", "options": { "list_type": { "type": "str", "choices": [ "access-list", "prefix-list", ], }, "value": {"type": "str"}, }, }, }, }, "ipv6": { "type": "dict", "options": { "address": { "type": "dict", "options": { "list_type": { "type": "str", "choices": [ "access-list", "prefix-list", ], }, "value": {"type": "str"}, }, }, "next_hop": {"type": "str"}, }, }, + "protocol": { + "type": "str", + "choices": [ + "babel", + "bgp", + "connected", + "isis", + "kernel", + "ospf", + "ospfv3", + "rip", + "ripng", + "static", + "table", + "vnc", + ], + }, "large_community_large_community_list": { "type": "str", }, "metric": {"type": "int"}, "origin": { "type": "str", "choices": ["ebgp", "ibgp", "incomplete"], }, "peer": {"type": "str"}, "rpki": { "type": "str", "choices": ["notfound", "invalid", "valid"], }, }, }, "on_match": { "type": "dict", "options": { "next": {"type": "bool"}, "goto": {"type": "int"}, }, }, }, }, }, }, "running_config": {"type": "str"}, "state": { "type": "str", "choices": [ "deleted", "merged", "overridden", "replaced", "gathered", "rendered", "parsed", ], "default": "merged", }, } # pylint: disable=C0301 diff --git a/plugins/module_utils/network/vyos/config/route_maps/route_maps.py b/plugins/module_utils/network/vyos/config/route_maps/route_maps.py index 9b6c3e9d..9692a253 100644 --- a/plugins/module_utils/network/vyos/config/route_maps/route_maps.py +++ b/plugins/module_utils/network/vyos/config/route_maps/route_maps.py @@ -1,155 +1,184 @@ # # -*- coding: utf-8 -*- # Copyright 2021 Red Hat # GNU General Public License v3.0+ # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # from __future__ import absolute_import, division, print_function __metaclass__ = type """ The vyos_route_maps config file. It is in this file where the current configuration (as dict) is compared to the provided configuration (as dict) and the command set necessary to bring the current configuration to its desired end-state is created. """ from ansible.module_utils.six import iteritems from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import ( ResourceModule, ) from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( dict_merge, ) from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.facts import Facts from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.rm_templates.route_maps import ( Route_mapsTemplate, ) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.rm_templates.route_maps_14 import ( + Route_mapsTemplate14, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.version import ( + LooseVersion, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import get_os_version class Route_maps(ResourceModule): """ The vyos_route_maps config class """ def __init__(self, module): super(Route_maps, self).__init__( empty_fact_val=[], facts_module=Facts(module), module=module, resource="route_maps", tmplt=Route_mapsTemplate(), ) self.parsers = [ "call", "description", "action", "continue_sequence", "set_aggregator_ip", "set_aggregator_as", "set_as_path_exclude", "set_as_path_prepend", "set_atomic_aggregate", "set_bgp_extcommunity_rt", "set_extcommunity_rt", "set_extcommunity_soo", + "set_extcommunity_bandwidth", + "set_extcommunity_bandwidth_non_transitive", "set_ip_next_hop", "set_ipv6_next_hop", "set_large_community", "set_local_preference", "set_metric", "set_metric_type", "set_origin", "set_originator_id", "set_src", "set_tag", "set_weight", + "set_table", "set_comm_list", "set_comm_list_delete", "set_community", "match_as_path", "match_community_community_list", "match_community_exact_match", "match_extcommunity", "match_interface", "match_large_community_large_community_list", "match_metric", "match_origin", "match_peer", "match_ip_address", "match_ip_next_hop", "match_ip_route_source", "on_match_goto", "on_match_next", "match_ipv6_address", "match_ipv6_nexthop", + "match_protocol", "match_rpki", ] + def _validate_template(self): + version = get_os_version(self._module) + if LooseVersion(version) >= LooseVersion("1.4"): + self._tmplt = Route_mapsTemplate14() + else: + self._tmplt = Route_mapsTemplate() + + def parse(self): + """override parse to check template""" + self._validate_template() + return super().parse() + + def get_parser(self, name): + """get_parsers""" + self._validate_template() + return super().get_parser(name) + def execute_module(self): """Execute the module :rtype: A dictionary :returns: The result from module execution """ + self._validate_template() 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._route_maps_list_to_dict(self.want) haved = self._route_maps_list_to_dict(self.have) # if state is merged, merge want onto have and then compare if self.state == "merged": wantd = dict_merge(haved, wantd) # if state is deleted, empty out wantd and set haved to wantd if self.state == "deleted": haved = {k: v for k, v in iteritems(haved) if k in wantd or not wantd} wantd = {} # remove superfluous config for overridden and deleted if self.state in ["overridden", "deleted"]: for k, have in iteritems(haved): if k not in wantd: self.commands.append(self._tmplt.render({"route_map": k}, "route_map", True)) for wk, want in iteritems(wantd): self._compare(want=want, have=haved.pop(wk, {})) def _compare(self, want, have): """Leverages the base class `compare()` method and populates the list of commands to be run by comparing the `want` and `have` data with the `parsers` defined for the Route_maps network resource. """ w_entries = want.get("entries", {}) h_entries = have.get("entries", {}) self._compare_entries(want=w_entries, have=h_entries) def _compare_entries(self, want, have): for wk, wentry in iteritems(want): hentry = have.pop(wk, {}) self.compare(parsers=self.parsers, want=wentry, have=hentry) def _route_maps_list_to_dict(self, entry): entry = {x["route_map"]: x for x in entry} for rmap, data in iteritems(entry): if "entries" in data: for x in data["entries"]: x.update({"route_map": rmap}) data["entries"] = { (rmap, entry.get("sequence")): entry for entry in data["entries"] } return entry diff --git a/plugins/module_utils/network/vyos/facts/route_maps/route_maps.py b/plugins/module_utils/network/vyos/facts/route_maps/route_maps.py index 2ad54e63..cfae26e3 100644 --- a/plugins/module_utils/network/vyos/facts/route_maps/route_maps.py +++ b/plugins/module_utils/network/vyos/facts/route_maps/route_maps.py @@ -1,82 +1,96 @@ # -*- coding: utf-8 -*- # Copyright 2021 Red Hat # GNU General Public License v3.0+ # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function __metaclass__ = type """ The vyos route_maps fact class It is in this file the configuration is collected from the device for a given resource, parsed, and the facts tree is populated based on the configuration. """ from copy import deepcopy from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.route_maps.route_maps import ( Route_mapsArgs, ) from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.rm_templates.route_maps import ( Route_mapsTemplate, ) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.rm_templates.route_maps_14 import ( + Route_mapsTemplate14, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.version import ( + LooseVersion, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import get_os_version class Route_mapsFacts(object): """The vyos route_maps facts class""" def __init__(self, module, subspec="config", options="options"): self._module = module self.argument_spec = Route_mapsArgs.argument_spec spec = deepcopy(self.argument_spec) if subspec: if options: facts_argument_spec = spec[subspec][options] else: facts_argument_spec = spec[subspec] else: facts_argument_spec = spec self.generated_spec = utils.generate_dict(facts_argument_spec) def get_config(self, connection): return connection.get("show configuration commands | grep route-map") def populate_facts(self, connection, ansible_facts, data=None): """Populate the facts for Route_maps network resource :param connection: the device connection :param ansible_facts: Facts dictionary :param data: previously collected conf :rtype: dictionary :returns: facts """ facts = {} objs = [] + + if LooseVersion(get_os_version(self._module)) >= LooseVersion("1.4"): + route_maps_class = Route_mapsTemplate14 + else: + route_maps_class = Route_mapsTemplate + if not data: data = self.get_config(connection) # parse native config using the Route_maps template - route_maps_parser = Route_mapsTemplate(lines=data.splitlines()) + route_maps_parser = route_maps_class(lines=data.splitlines()) + if route_maps_parser.parse().get("route_maps"): objs = list(route_maps_parser.parse().get("route_maps").values()) for item in objs: if item.get("entries"): item["entries"] = list(item["entries"].values()) ansible_facts["ansible_network_resources"].pop("route_maps", None) # import epdb;epdb.serve() params = utils.remove_empties(utils.validate_config(self.argument_spec, {"config": objs})) if params.get("config"): facts["route_maps"] = params["config"] ansible_facts["ansible_network_resources"].update(facts) return ansible_facts diff --git a/plugins/module_utils/network/vyos/rm_templates/route_maps.py b/plugins/module_utils/network/vyos/rm_templates/route_maps.py index 8f218a6b..c6b88f7b 100644 --- a/plugins/module_utils/network/vyos/rm_templates/route_maps.py +++ b/plugins/module_utils/network/vyos/rm_templates/route_maps.py @@ -1,1293 +1,1405 @@ # -*- coding: utf-8 -*- # Copyright 2021 Red Hat # GNU General Public License v3.0+ # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function __metaclass__ = type """ The Route_maps parser templates file. This contains a list of parser definitions and associated functions that facilitates both facts gathering and native command generation for the given network resource. """ import re from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( NetworkTemplate, ) class Route_mapsTemplate(NetworkTemplate): def __init__(self, lines=None): prefix = {"set": "set", "remove": "delete"} super(Route_mapsTemplate, self).__init__(lines=lines, tmplt=self, prefix=prefix) # fmt: off PARSERS = [ { "name": "route_map", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+) *$""", re.VERBOSE, ), "compval": "route_map", "setval": "policy route-map {{route_map}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', }, }, }, }, { "name": "sequence", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+) *$""", re.VERBOSE, ), "compval": "sequence", "setval": "policy route-map {{route_map}} rule {{sequence}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", }, }, }, }, }, }, { "name": "call", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\scall\s(?P\S+) *$""", re.VERBOSE, ), "setval": "policy route-map {{route_map}} rule {{sequence}} call {{call}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "call": "{{call}}", }, }, }, }, }, }, { "name": "description", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sdescription\s(?P\S+) *$""", re.VERBOSE, ), "setval": "policy route-map {{route_map}} rule {{sequence}} description {{description}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "description": "{{description}}", }, }, }, }, }, }, { "name": "action", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\saction\s(?P\S+) *$""", re.VERBOSE, ), "setval": "policy route-map {{route_map}} rule {{sequence}} action {{action}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "action": "{{action}}", }, }, }, }, }, }, { "name": "continue_sequence", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\scontinue\s(?P\S+) *$""", re.VERBOSE, ), "setval": "policy route-map {{route_map}} rule {{sequence}} continue {{continue_sequence}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "continue_sequence": "{{continue}}", }, }, }, }, }, }, { "name": "on_match_next", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\son-match\s(?Pnext) *$""", re.VERBOSE, ), "compval": "on_match.next", "setval": "policy route-map {{route_map}} rule {{sequence}} on-match next", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "on_match": { "next": "{{True if next is defined}}", }, }, }, }, }, }, }, { "name": "on_match_goto", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\son-match\sgoto\s(?P\S+) *$""", re.VERBOSE, ), "compval": "on_match.goto", "setval": "policy route-map {{route_map}} rule {{sequence}} on-match goto {{on_match.goto}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "on_match": { "goto": "{{goto}}", }, }, }, }, }, }, }, { "name": "set_aggregator_ip", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\saggregator\sip\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.aggregator.ip", "setval": "policy route-map {{route_map}} rule {{sequence}} set aggregator ip {{set.aggregator.ip}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "aggregator": { "ip": "{{ip}}", }, }, }, }, }, }, }, }, { "name": "set_aggregator_as", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\saggregator\sas\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.aggregator.as", "setval": "policy route-map {{route_map}} rule {{sequence}} set aggregator as {{set.aggregator.as}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "aggregator": { "as": "{{as}}", }, }, }, }, }, }, }, }, { "name": "set_as_path_exclude", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sas-path-exclude\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.as_path_exclude", "setval": "policy route-map {{route_map}} rule {{sequence}} set as-path-exclude {{set.as_path_exclude}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "as_path_exclude": "{{as}}", }, }, }, }, }, }, }, { "name": "set_as_path_prepend", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sas-path-prepend\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sas-path-prepend\s(?P.*) + $""", re.VERBOSE, ), "compval": "set.as_path_prepend", - "setval": "policy route-map {{route_map}} rule {{sequence}} set as-path-prepend {{set.as_path_prepend}}", + "setval": "policy route-map {{route_map}} rule {{sequence}} set as-path-prepend '{{set.as_path_prepend}}'", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "as_path_prepend": "{{as}}", }, }, }, }, }, }, }, { "name": "set_atomic_aggregate", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\satomic-aggregate(?P) + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\s(?Patomic-aggregate) *$""", re.VERBOSE, ), + "compval": "set.atomic_aggregate", "setval": "policy route-map {{route_map}} rule {{sequence}} set atomic-aggregate", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "atomic_aggregate": "{{True if as is defined}}", }, }, }, }, }, }, }, { "name": "set_bgp_extcommunity_rt", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sbgp-extcommunity-rt\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.bgp_extcommunity_rt", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set bgp-extcommunity-rt {{set.bgp_extcommunity_rt}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "bgp_extcommunity_rt": "{{bgp}}", }, }, }, }, }, }, }, { "name": "set_comm_list", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\scomm-list\scomm-list\s(?P\S+) + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\scommunity\scommunity-list\s(?P\S+) *$""", re.VERBOSE, ), - "compval": "set.comm_list.comm_list", + "compval": "match.community.community_list", "setval": "policy route-map {{route_map}} rule {{sequence}} " - "set comm-list comm-list {{set.comm_list.comm_list}}", + "match community community-list {{set.comm_list.comm_list}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", - "set": { - "comm_list": {"comm_list": "{{comm_list}}"}, + "match": { + "community": {"community_list": "{{comm_list}}"}, }, }, }, }, }, }, }, { "name": "set_comm_list_delete", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\scomm-list\sdelete(?P\S+) *$""", re.VERBOSE, ), "compval": "set.comm_list.comm_list", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set comm-list delete", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "comm_list": {"delete": "{{True if delete is defined}}"}, }, }, }, }, }, }, }, { "name": "set_extcommunity_rt", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity-rt\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.extcommunity_rt", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set extcommunity-rt {{set.extcommunity_rt}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "extcommunity_rt": "{{extcommunity_rt}}", }, }, }, }, }, }, }, { "name": "set_extcommunity_soo", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity-soo\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.extcommunity_soo", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set extcommunity-soo {{set.extcommunity_soo}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "extcommunity_soo": "{{set.extcommunity_soo}}", }, }, }, }, }, }, }, + { + "name": "set_extcommunity_bandwidth", + "getval": re.compile( + r""" + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity\sbandwidth\s(?P\S+) + *$""", + re.VERBOSE, + ), + "compval": "set.extcommunity_bandwidth", + "setval": "policy route-map {{route_map}} rule {{sequence}} " + "set extcommunity bandwidth {{set.extcommunity_bandwidth}}", + "result": { + "route_maps": { + "{{ route_map }}": { + "route_map": '{{ route_map }}', + "entries": { + "{{sequence}}": + { + "sequence": "{{sequence}}", + "set": { + "extcommunity_bandwidth": "{{extcommunity_bw}}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "set_extcommunity_bandwidth_non_transitive", + "getval": re.compile( + r""" + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity\s(?Pbandwidth-non-transitive) + *$""", + re.VERBOSE, + ), + "compval": "set.extcommunity_bandwidth_non_transitive", + "setval": "policy route-map {{route_map}} rule {{sequence}} " + "set extcommunity bandwidth-non-transitive", + "result": { + "route_maps": { + "{{ route_map }}": { + "route_map": '{{ route_map }}', + "entries": { + "{{sequence}}": + { + "sequence": "{{sequence}}", + "set": { + "extcommunity_bandwidth_non_transitive": "{{True if extcommunity_bw_nt is defined}}", + }, + }, + }, + }, + }, + }, + }, { "name": "set_ip_next_hop", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sip-next-hop\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.ip_next_hop", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set ip-next-hop {{set.ip_next_hop}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "ip_next_hop": "{{ip_next_hop}}", }, }, }, }, }, }, }, { "name": "set_ipv6_next_hop", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sipv6-next-hop \s(?Pglobal|local) \s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.ipv6_next_hop", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set ipv6-next-hop {{set.ipv6_next_hop.ip_type}} {{set.ipv6_next_hop.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "ipv6_next_hop": { "ip_type": "{{type}}", "value": "{{value}}", }, }, }, }, }, }, }, }, { "name": "set_large_community", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\slarge-community\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.large_community", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set large-community {{set.large_community}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "large_community": "{{large_community}}", }, }, }, }, }, }, }, { "name": "set_local_preference", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\slocal-preference\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.local_preference", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set local-preference {{set.local_preference}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "local_preference": "{{local_preference}}", }, }, }, }, }, }, }, { "name": "set_metric", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\smetric\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.metric", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set metric {{set.metric}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "metric": "{{metric}}", }, }, }, }, }, }, }, { "name": "set_metric_type", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\smetric-type\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.metric_type", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set metric-type {{set.metric_type}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "metric_type": "{{metric_type}}", }, }, }, }, }, }, }, { "name": "set_origin", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sorigin\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.origin", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set origin {{set.origin}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "origin": "{{origin}}", }, }, }, }, }, }, }, { "name": "set_originator_id", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\soriginator-id\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.originator_id", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set originator-id {{set.originator_id}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "originator_id": "{{originator_id}}", }, }, }, }, }, }, }, { "name": "set_src", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\ssrc\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.src", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set src {{set.src}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "src": "{{src}}", }, }, }, }, }, }, }, { "name": "set_tag", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\stag\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.tag", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set tag {{set.tag}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "tag": "{{tag}}", }, }, }, }, }, }, }, { "name": "set_weight", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sweight\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.weight", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set weight {{set.weight}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "weight": "{{weight}}", }, }, }, }, }, }, }, + { + "name": "set_table", + "getval": re.compile( + r""" + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\stable\s(?P\S+) + *$""", + re.VERBOSE, + ), + "compval": "set.weight", + "setval": "policy route-map {{route_map}} rule {{sequence}} " + "set table {{set.table}}", + "result": { + "route_maps": { + "{{ route_map }}": { + "route_map": '{{ route_map }}', + "entries": { + "{{sequence}}": + { + "sequence": "{{sequence}}", + "set": { + "table": "{{table}}", + }, + }, + }, + }, + }, + }, + }, { "name": "set_community", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\scommunity\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.community.value", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set community {{set.community.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "community": { "value": "{{value}}", }, }, }, }, }, }, }, }, { "name": "match_as_path", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sas-path\s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.as_path", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match as-path {{match.as_path}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "as_path": "{{as_path}}", }, }, }, }, }, }, }, { "name": "match_community_community_list", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\scommunity\scommunity-list\s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.community.community_list", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match community community-list {{match.community.community_list}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "community": {"community_list": "{{community_list}}"}, }, }, }, }, }, }, }, { "name": "match_community_exact_match", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\scommunity\sexact-match(?P) *$""", re.VERBOSE, ), "compval": "match.community.exact_match", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match community exact-match", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "community": {"exact_match": "{{True if exact_match is defined}}"}, }, }, }, }, }, }, }, { "name": "match_extcommunity", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sextcommunity\s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.extcommunity", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match extcommunity {{match.extcommunity}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "extcommunity": "{{extcommunity}}", }, }, }, }, }, }, }, { "name": "match_interface", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sinterface\s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.interface", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match interface {{match.interface}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "interface": "{{interface}}", }, }, }, }, }, }, }, { "name": "match_large_community_large_community_list", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\slarge-community\slarge-community-list\s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.large_community_large_community_list", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match large-community large-community-list {{match.large_community_large_community_list}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "large_community_large_community_list": "{{lc}}", }, }, }, }, }, }, }, { "name": "match_metric", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\smetric\s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.metric", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match metric {{match.metric}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "metric": "{{metric}}", }, }, }, }, }, }, }, { "name": "match_origin", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sorigin\s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.origin", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match origin {{match.origin}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "origin": "{{origin}}", }, }, }, }, }, }, }, { "name": "match_peer", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\speer\s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.peer", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match peer {{match.peer}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "peer": "{{peer}}", }, }, }, }, }, }, }, { "name": "match_ip_address", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sip\saddress \s(?Paccess-list|prefix-list) \s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.ip.address", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match ip address {{match.ip.address.list_type}} {{match.ip.address.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "ip": { "address": { "list_type": "{{list_type}}", "value": "{{value}}", }, }, }, }, }, }, }, }, }, { "name": "match_ip_next_hop", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sip\snexthop \s(?Paccess-list|prefix-list) \s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.ip.next_hop", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match ip nexthop {{match.ip.next_hop.list_type}} {{match.ip.next_hop.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "ip": { "next_hop": { "list_type": "{{list_type}}", "value": "{{value}}", }, }, }, }, }, }, }, }, }, { "name": "match_ip_route_source", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sip\sroute-source \s(?Paccess-list|prefix-list) \s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.ip.route_source", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match ip route-source {{match.ip.route_source.list_type}} {{match.ip.route_source.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "ip": { "route_source": { "list_type": "{{list_type}}", "value": "{{value}}", }, }, }, }, }, }, }, }, }, { "name": "match_ipv6_address", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sipv6\saddress \s(?Paccess-list|prefix-list) \s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.ipv6.address", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match ipv6 address {{match.ipv6.address.list_type}} {{match.ipv6.address.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "ipv6": { "address": { "list_type": "{{list_type}}", "value": "{{value}}", }, }, }, }, }, }, }, }, }, { "name": "match_ipv6_nexthop", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sipv6\snexthop \s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.ipv6.next_hop", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match ipv6 nexthop {{match.ipv6.next_hop}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "ipv6": { "next_hop": "{{value}}", }, }, }, }, }, }, }, }, + { + "name": "match_protocol", + "getval": re.compile( + r""" + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sprotocol\s(?P\S+) + *$""", + re.VERBOSE, + ), + "compval": "match.protocol", + "setval": "policy route-map {{route_map}} rule {{sequence}} " + "match protocol {{match.protocol}}", + "result": { + "route_maps": { + "{{ route_map }}": { + "route_map": '{{ route_map }}', + "entries": { + "{{sequence}}": { + "sequence": "{{sequence}}", + "match": { + "protocol": "{{value}}", + }, + }, + }, + }, + }, + }, + }, { "name": "match_rpki", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\srpki \s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.rpki", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match rpki {{match.rpki}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "rpki": "{{value}}", }, }, }, }, }, }, }, ] # fmt: on diff --git a/plugins/module_utils/network/vyos/rm_templates/route_maps.py b/plugins/module_utils/network/vyos/rm_templates/route_maps_14.py similarity index 88% copy from plugins/module_utils/network/vyos/rm_templates/route_maps.py copy to plugins/module_utils/network/vyos/rm_templates/route_maps_14.py index 8f218a6b..6564280d 100644 --- a/plugins/module_utils/network/vyos/rm_templates/route_maps.py +++ b/plugins/module_utils/network/vyos/rm_templates/route_maps_14.py @@ -1,1293 +1,1405 @@ # -*- coding: utf-8 -*- # Copyright 2021 Red Hat # GNU General Public License v3.0+ # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function __metaclass__ = type """ The Route_maps parser templates file. This contains a list of parser definitions and associated functions that facilitates both facts gathering and native command generation for the given network resource. """ import re from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( NetworkTemplate, ) -class Route_mapsTemplate(NetworkTemplate): +class Route_mapsTemplate14(NetworkTemplate): def __init__(self, lines=None): prefix = {"set": "set", "remove": "delete"} - super(Route_mapsTemplate, self).__init__(lines=lines, tmplt=self, prefix=prefix) + super(Route_mapsTemplate14, self).__init__(lines=lines, tmplt=self, prefix=prefix) # fmt: off PARSERS = [ { "name": "route_map", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+) *$""", re.VERBOSE, ), "compval": "route_map", "setval": "policy route-map {{route_map}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', }, }, }, }, { "name": "sequence", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+) *$""", re.VERBOSE, ), "compval": "sequence", "setval": "policy route-map {{route_map}} rule {{sequence}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", }, }, }, }, }, }, { "name": "call", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\scall\s(?P\S+) *$""", re.VERBOSE, ), "setval": "policy route-map {{route_map}} rule {{sequence}} call {{call}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "call": "{{call}}", }, }, }, }, }, }, { "name": "description", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sdescription\s(?P\S+) *$""", re.VERBOSE, ), "setval": "policy route-map {{route_map}} rule {{sequence}} description {{description}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "description": "{{description}}", }, }, }, }, }, }, { "name": "action", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\saction\s(?P\S+) *$""", re.VERBOSE, ), "setval": "policy route-map {{route_map}} rule {{sequence}} action {{action}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "action": "{{action}}", }, }, }, }, }, }, { "name": "continue_sequence", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\scontinue\s(?P\S+) *$""", re.VERBOSE, ), "setval": "policy route-map {{route_map}} rule {{sequence}} continue {{continue_sequence}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "continue_sequence": "{{continue}}", }, }, }, }, }, }, { "name": "on_match_next", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\son-match\s(?Pnext) *$""", re.VERBOSE, ), "compval": "on_match.next", "setval": "policy route-map {{route_map}} rule {{sequence}} on-match next", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "on_match": { "next": "{{True if next is defined}}", }, }, }, }, }, }, }, { "name": "on_match_goto", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\son-match\sgoto\s(?P\S+) *$""", re.VERBOSE, ), "compval": "on_match.goto", "setval": "policy route-map {{route_map}} rule {{sequence}} on-match goto {{on_match.goto}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "on_match": { "goto": "{{goto}}", }, }, }, }, }, }, }, { "name": "set_aggregator_ip", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\saggregator\sip\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.aggregator.ip", "setval": "policy route-map {{route_map}} rule {{sequence}} set aggregator ip {{set.aggregator.ip}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "aggregator": { "ip": "{{ip}}", }, }, }, }, }, }, }, }, { "name": "set_aggregator_as", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\saggregator\sas\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.aggregator.as", "setval": "policy route-map {{route_map}} rule {{sequence}} set aggregator as {{set.aggregator.as}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "aggregator": { "as": "{{as}}", }, }, }, }, }, }, }, }, { "name": "set_as_path_exclude", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sas-path-exclude\s(?P\S+) + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sas-path\sexclude\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.as_path_exclude", - "setval": "policy route-map {{route_map}} rule {{sequence}} set as-path-exclude {{set.as_path_exclude}}", + "setval": "policy route-map {{route_map}} rule {{sequence}} set as-path exclude {{set.as_path_exclude}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "as_path_exclude": "{{as}}", }, }, }, }, }, }, }, { "name": "set_as_path_prepend", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sas-path-prepend\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sas-path\sprepend\s(?P.*) + $""", re.VERBOSE, ), "compval": "set.as_path_prepend", - "setval": "policy route-map {{route_map}} rule {{sequence}} set as-path-prepend {{set.as_path_prepend}}", + "setval": "policy route-map {{route_map}} rule {{sequence}} set as-path prepend '{{set.as_path_prepend}}'", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "as_path_prepend": "{{as}}", }, }, }, }, }, }, }, { "name": "set_atomic_aggregate", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\satomic-aggregate(?P) + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\s(?Patomic-aggregate) *$""", re.VERBOSE, ), + "compval": "set.atomic_aggregate", "setval": "policy route-map {{route_map}} rule {{sequence}} set atomic-aggregate", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "atomic_aggregate": "{{True if as is defined}}", }, }, }, }, }, }, }, { "name": "set_bgp_extcommunity_rt", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sbgp-extcommunity-rt\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.bgp_extcommunity_rt", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set bgp-extcommunity-rt {{set.bgp_extcommunity_rt}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "bgp_extcommunity_rt": "{{bgp}}", }, }, }, }, }, }, }, { "name": "set_comm_list", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\scomm-list\scomm-list\s(?P\S+) + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\scommunity\scommunity-list\s(?P\S+) *$""", re.VERBOSE, ), - "compval": "set.comm_list.comm_list", + "compval": "match.community.community_list", "setval": "policy route-map {{route_map}} rule {{sequence}} " - "set comm-list comm-list {{set.comm_list.comm_list}}", + "match community community-list {{set.comm_list.comm_list}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", - "set": { - "comm_list": {"comm_list": "{{comm_list}}"}, + "match": { + "community": {"community_list": "{{comm_list}}"}, }, }, }, }, }, }, }, { "name": "set_comm_list_delete", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\scomm-list\sdelete(?P\S+) *$""", re.VERBOSE, ), "compval": "set.comm_list.comm_list", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set comm-list delete", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "comm_list": {"delete": "{{True if delete is defined}}"}, }, }, }, }, }, }, }, { "name": "set_extcommunity_rt", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity-rt\s(?P\S+) + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity\srt\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.extcommunity_rt", "setval": "policy route-map {{route_map}} rule {{sequence}} " - "set extcommunity-rt {{set.extcommunity_rt}}", + "set extcommunity rt {{set.extcommunity_rt}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "extcommunity_rt": "{{extcommunity_rt}}", }, }, }, }, }, }, }, { "name": "set_extcommunity_soo", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity-soo\s(?P\S+) + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity\ssoo\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.extcommunity_soo", "setval": "policy route-map {{route_map}} rule {{sequence}} " - "set extcommunity-soo {{set.extcommunity_soo}}", + "set extcommunity soo {{set.extcommunity_soo}}", + "result": { + "route_maps": { + "{{ route_map }}": { + "route_map": '{{ route_map }}', + "entries": { + "{{sequence}}": + { + "sequence": "{{sequence}}", + "set": { + "extcommunity_soo": "{{extcommunity_soo}}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "set_extcommunity_bandwidth", + "getval": re.compile( + r""" + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity\sbandwidth\s(?P\S+) + *$""", + re.VERBOSE, + ), + "compval": "set.extcommunity_bandwidth", + "setval": "policy route-map {{route_map}} rule {{sequence}} " + "set extcommunity bandwidth {{set.extcommunity_bandwidth}}", + "result": { + "route_maps": { + "{{ route_map }}": { + "route_map": '{{ route_map }}', + "entries": { + "{{sequence}}": + { + "sequence": "{{sequence}}", + "set": { + "extcommunity_bandwidth": "{{extcommunity_bw}}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "set_extcommunity_bandwidth_non_transitive", + "getval": re.compile( + r""" + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sextcommunity\s(?Pbandwidth-non-transitive) + *$""", + re.VERBOSE, + ), + "compval": "set.extcommunity_bandwidth_non_transitive", + "setval": "policy route-map {{route_map}} rule {{sequence}} " + "set extcommunity bandwidth-non-transitive", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { - "extcommunity_soo": "{{set.extcommunity_soo}}", + "extcommunity_bandwidth_non_transitive": "{{True if extcommunity_bw_nt is defined}}", }, }, }, }, }, }, }, { "name": "set_ip_next_hop", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sip-next-hop\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.ip_next_hop", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set ip-next-hop {{set.ip_next_hop}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "ip_next_hop": "{{ip_next_hop}}", }, }, }, }, }, }, }, { "name": "set_ipv6_next_hop", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sipv6-next-hop \s(?Pglobal|local) \s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.ipv6_next_hop", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set ipv6-next-hop {{set.ipv6_next_hop.ip_type}} {{set.ipv6_next_hop.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "ipv6_next_hop": { "ip_type": "{{type}}", "value": "{{value}}", }, }, }, }, }, }, }, }, { "name": "set_large_community", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\slarge-community\s(?P\S+) - *$""", + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\slarge-community\s(?Pnone|replace\s(?P\S+)) + $""", re.VERBOSE, ), "compval": "set.large_community", "setval": "policy route-map {{route_map}} rule {{sequence}} " - "set large-community {{set.large_community}}", + "set large-community {{set.large_community if set.large_community == 'none' else 'replace ' + set.large_community}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { - "large_community": "{{large_community}}", + "large_community": "{{op if op == 'none' else large_community}}", }, }, }, }, }, }, }, { "name": "set_local_preference", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\slocal-preference\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.local_preference", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set local-preference {{set.local_preference}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "local_preference": "{{local_preference}}", }, }, }, }, }, }, }, { "name": "set_metric", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\smetric\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.metric", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set metric {{set.metric}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "metric": "{{metric}}", }, }, }, }, }, }, }, { "name": "set_metric_type", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\smetric-type\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.metric_type", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set metric-type {{set.metric_type}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "metric_type": "{{metric_type}}", }, }, }, }, }, }, }, { "name": "set_origin", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sorigin\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.origin", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set origin {{set.origin}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "origin": "{{origin}}", }, }, }, }, }, }, }, { "name": "set_originator_id", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\soriginator-id\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.originator_id", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set originator-id {{set.originator_id}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "originator_id": "{{originator_id}}", }, }, }, }, }, }, }, { "name": "set_src", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\ssrc\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.src", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set src {{set.src}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "src": "{{src}}", }, }, }, }, }, }, }, { "name": "set_tag", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\stag\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.tag", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set tag {{set.tag}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "tag": "{{tag}}", }, }, }, }, }, }, }, { "name": "set_weight", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\sweight\s(?P\S+) *$""", re.VERBOSE, ), "compval": "set.weight", "setval": "policy route-map {{route_map}} rule {{sequence}} " "set weight {{set.weight}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "weight": "{{weight}}", }, }, }, }, }, }, }, { - "name": "set_community", + "name": "set_table", "getval": re.compile( r""" - ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\scommunity\s(?P\S+) + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\stable\s(?P
\S+) *$""", re.VERBOSE, ), + "compval": "set.weight", + "setval": "policy route-map {{route_map}} rule {{sequence}} " + "set table {{set.table}}", + "result": { + "route_maps": { + "{{ route_map }}": { + "route_map": '{{ route_map }}', + "entries": { + "{{sequence}}": + { + "sequence": "{{sequence}}", + "set": { + "table": "{{table}}", + }, + }, + }, + }, + }, + }, + }, + { + "name": "set_community", + "getval": re.compile( + r""" + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\sset\scommunity\s(?Pnone|replace\s(?P\S+)) + $""", + re.VERBOSE, + ), "compval": "set.community.value", "setval": "policy route-map {{route_map}} rule {{sequence}} " - "set community {{set.community.value}}", + "set community {{set.community.value if set.community.value == 'none' else 'replace ' + set.community.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "set": { "community": { - "value": "{{value}}", + "value": "{{op if op == 'none' else value}}", }, }, }, }, }, }, }, }, { "name": "match_as_path", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sas-path\s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.as_path", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match as-path {{match.as_path}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "as_path": "{{as_path}}", }, }, }, }, }, }, }, { "name": "match_community_community_list", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\scommunity\scommunity-list\s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.community.community_list", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match community community-list {{match.community.community_list}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "community": {"community_list": "{{community_list}}"}, }, }, }, }, }, }, }, { "name": "match_community_exact_match", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\scommunity\sexact-match(?P) *$""", re.VERBOSE, ), "compval": "match.community.exact_match", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match community exact-match", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "community": {"exact_match": "{{True if exact_match is defined}}"}, }, }, }, }, }, }, }, { "name": "match_extcommunity", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sextcommunity\s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.extcommunity", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match extcommunity {{match.extcommunity}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "extcommunity": "{{extcommunity}}", }, }, }, }, }, }, }, { "name": "match_interface", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sinterface\s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.interface", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match interface {{match.interface}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "interface": "{{interface}}", }, }, }, }, }, }, }, { "name": "match_large_community_large_community_list", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\slarge-community\slarge-community-list\s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.large_community_large_community_list", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match large-community large-community-list {{match.large_community_large_community_list}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "large_community_large_community_list": "{{lc}}", }, }, }, }, }, }, }, { "name": "match_metric", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\smetric\s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.metric", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match metric {{match.metric}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "metric": "{{metric}}", }, }, }, }, }, }, }, { "name": "match_origin", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sorigin\s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.origin", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match origin {{match.origin}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "origin": "{{origin}}", }, }, }, }, }, }, }, { "name": "match_peer", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\speer\s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.peer", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match peer {{match.peer}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "peer": "{{peer}}", }, }, }, }, }, }, }, { "name": "match_ip_address", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sip\saddress \s(?Paccess-list|prefix-list) \s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.ip.address", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match ip address {{match.ip.address.list_type}} {{match.ip.address.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "ip": { "address": { "list_type": "{{list_type}}", "value": "{{value}}", }, }, }, }, }, }, }, }, }, { "name": "match_ip_next_hop", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sip\snexthop \s(?Paccess-list|prefix-list) \s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.ip.next_hop", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match ip nexthop {{match.ip.next_hop.list_type}} {{match.ip.next_hop.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "ip": { "next_hop": { "list_type": "{{list_type}}", "value": "{{value}}", }, }, }, }, }, }, }, }, }, { "name": "match_ip_route_source", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sip\sroute-source \s(?Paccess-list|prefix-list) \s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.ip.route_source", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match ip route-source {{match.ip.route_source.list_type}} {{match.ip.route_source.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "ip": { "route_source": { "list_type": "{{list_type}}", "value": "{{value}}", }, }, }, }, }, }, }, }, }, { "name": "match_ipv6_address", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sipv6\saddress \s(?Paccess-list|prefix-list) \s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.ipv6.address", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match ipv6 address {{match.ipv6.address.list_type}} {{match.ipv6.address.value}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "ipv6": { "address": { "list_type": "{{list_type}}", "value": "{{value}}", }, }, }, }, }, }, }, }, }, { "name": "match_ipv6_nexthop", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sipv6\snexthop \s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.ipv6.next_hop", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match ipv6 nexthop {{match.ipv6.next_hop}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "ipv6": { "next_hop": "{{value}}", }, }, }, }, }, }, }, }, + { + "name": "match_protocol", + "getval": re.compile( + r""" + ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\sprotocol\s(?P\S+) + *$""", + re.VERBOSE, + ), + "compval": "match.protocol", + "setval": "policy route-map {{route_map}} rule {{sequence}} " + "match protocol {{match.protocol}}", + "result": { + "route_maps": { + "{{ route_map }}": { + "route_map": '{{ route_map }}', + "entries": { + "{{sequence}}": { + "sequence": "{{sequence}}", + "match": { + "protocol": "{{value}}", + }, + }, + }, + }, + }, + }, + }, { "name": "match_rpki", "getval": re.compile( r""" ^set\spolicy\sroute-map\s(?P\S+)\srule\s(?P\d+)\smatch\srpki \s(?P\S+) *$""", re.VERBOSE, ), "compval": "match.rpki", "setval": "policy route-map {{route_map}} rule {{sequence}} " "match rpki {{match.rpki}}", "result": { "route_maps": { "{{ route_map }}": { "route_map": '{{ route_map }}', "entries": { "{{sequence}}": { "sequence": "{{sequence}}", "match": { "rpki": "{{value}}", }, }, }, }, }, }, }, ] # fmt: on diff --git a/plugins/modules/vyos_route_maps.py b/plugins/modules/vyos_route_maps.py index 67d327a6..455bd3e6 100644 --- a/plugins/modules/vyos_route_maps.py +++ b/plugins/modules/vyos_route_maps.py @@ -1,1001 +1,1014 @@ #!/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 vyos_route_maps """ from __future__ import absolute_import, division, print_function __metaclass__ = type DOCUMENTATION = """ module: vyos_route_maps version_added: "1.0.0" short_description: Route Map resource module description: - This module manages route map configurations on devices running VYOS. author: Ashwini Mhatre (@amhatre) notes: - Tested against vyos 1.3.8 - This module works with connection C(network_cli). options: config: description: A list of route-map configuration. type: list elements: dict suboptions: route_map: description: Route map name. type: str entries: description: Route Map rules. aliases: ["rules"] type: list elements: dict suboptions: sequence: type: int description: Route map rule number <1-65535>. call: description: Route map name type: str description: description: Description for the rule. type: str action: description: Action for matching routes type: str choices: ["deny", "permit"] continue_sequence: description: Continue on a different entry within the route-map. type: int set: description: Route parameters. type: dict suboptions: aggregator: type: dict description: Border Gateway Protocol (BGP) aggregator attribute. suboptions: ip: type: str description: IP address. as: type: str description: AS number of an aggregation. as_path_exclude: type: str description: BGP AS path exclude string ex "456 64500 45001" as_path_prepend: type: str description: Prepend string for a Border Gateway Protocol (BGP) AS-path attribute. atomic_aggregate: type: bool description: Border Gateway Protocol (BGP) atomic aggregate attribute. bgp_extcommunity_rt: type: str description: ExtCommunity in format AS:value comm_list: type: dict description: Border Gateway Protocol (BGP) communities matching a community-list. suboptions: comm_list: type: str description: BGP communities with a community-list. delete: type: bool description: Delete BGP communities matching the community-list. community: type: dict description: Border Gateway Protocol (BGP) community attribute. suboptions: value: type: str description: Community in 4 octet AS:value format or it can be from local-AS, no-advertise,no-expert,internet,additive,none. extcommunity_rt: type: str description: Set route target value.ASN:nn_or_IP_address:nn VPN extended community. extcommunity_soo: type: str description: Set Site of Origin value. ASN:nn_or_IP_address:nn VPN extended community + extcommunity_bandwidth: + type: str + description: Set Bandwidth of Origin value. 1-25600|cumulative|num-multipaths VPN extended community + extcommunity_bandwidth_non_transitive: + type: bool + description: Set the bandwidth extended community encoded as non-transitive True/False VPN extended community ip_next_hop: type: str description: IP address. ipv6_next_hop: type: dict description: Nexthop IPv6 address. suboptions: ip_type: description: Global or Local type: str choices: ["global", "local"] value: description: ipv6 address type: str large_community: type: str description: Set BGP large community value. local_preference: type: str description: Border Gateway Protocol (BGP) local preference attribute.Example <0-4294967295>. metric: type: str description: Destination routing protocol metric. Example <0-4294967295>. metric_type: type: str choices: ['type-1', 'type-2'] description: Open Shortest Path First (OSPF) external metric-type. origin: description: Set bgp origin. type: str choices: [ "egp", "igp", "incomplete" ] originator_id: type: str description: Border Gateway Protocol (BGP) originator ID attribute. Originator IP address. src: type: str description: Source address for route. Example IP address. tag: type: str description: Tag value for routing protocol. Example <1-65535> weight: type: str description: Border Gateway Protocol (BGP) weight attribute. Example <0-4294967295> + table: + type: str + description: Set prefixes to table. Example <1-200> match: description: Route parameters to match. type: dict suboptions: as_path: description: Set as-path. type: str community: description: BGP community attribute. type: dict suboptions: community_list: description: BGP community-list to match type: str exact_match: description: BGP community-list to match type: bool extcommunity: description: Extended community name. type: str interface: description: First hop interface of a route to match. type: str ip: description: IP prefix parameters to match. type: dict suboptions: address: description: IP address of route to match. type: dict suboptions: list_type: &list_type description: type of list type: str choices: ['access-list', 'prefix-list'] value: &value type: str description: value of access-list and prefix list next_hop: description: next hop prefix list. type: dict suboptions: list_type: *list_type value: *value route_source: description: IP route-source to match type: dict suboptions: list_type: *list_type value: *value ipv6: description: IPv6 prefix parameters to match. type: dict suboptions: address: description: IPv6 address of route to match. type: dict suboptions: list_type: *list_type value: *value next_hop: description: next-hop ipv6 address IPv6 . type: str large_community_large_community_list: type: str description: BGP large-community-list to match. metric: description: Route metric <1-65535>. type: int origin: description: bgp origin. type: str choices: [ "ebgp", "ibgp", "incomplete" ] peer: type: str description: Peer IP address . rpki: type: str description: RPKI validation value. choices: [ "notfound", "invalid", "valid" ] + protocol: + type: str + description: Source protocol to match. + choices: [ "babel","bgp","connected","isis","kernel","ospf","ospfv3","rip","ripng","static","table","vnc" ] on_match: type: dict description: Exit policy on matches. suboptions: next: type: bool description: Next sequence number to goto on match. goto: type: int description: Rule number to goto on match <1-65535>. running_config: description: - This option is used only with state I(parsed). - The value of this option should be the output received from the VYOS device by executing the command B(show configuration commands | grep route-map). - The state I(parsed) reads the configuration from C(show configuration commands | grep route-map) option and transforms it into Ansible structured data as per the resource module's argspec and the value is then returned in the I(parsed) key within the result. type: str state: description: - The state the configuration should be left in. type: str choices: - deleted - merged - overridden - replaced - gathered - rendered - parsed default: merged """ EXAMPLES = """ # Using merged # Before state # vyos@vyos:~$ show configuration commands | match "set policy route-map" # vyos@vyos:~$ - name: Merge the provided configuration with the existing running configuration register: result vyos.vyos.vyos_route_maps: &id001 config: - route_map: test1 entries: - sequence: 1 description: "test" action: permit continue: 2 on_match: next: true - route_map: test3 entries: - sequence: 1 action: permit match: rpki: invalid metric: 1 peer: 192.0.2.32 set: local_preference: 4 metric: 5 metric_type: "type-1" origin: egp originator_id: 192.0.2.34 tag: 5 weight: 4 state: merged # After State # vyos@vyos:~$ show configuration commands | match "set policy route-maps" # set policy route-map test1 rule 1 description test # set policy route-map test1 rule 1 action permit # set policy route-map test1 rule 1 continue 2 # set policy route-map test1 rule 1 on-match next # set policy route-map test3 rule 1 action permit # set policy route-map test3 rule 1 set local-preference 4 # set policy route-map test3 rule 1 set metric 5 # set policy route-map test3 rule 1 set metric-type type-1 # set policy route-map test3 rule 1 set origin egp # set policy route-map test3 rule 1 set originator-id 192.0.2.34 # set policy route-map test3 rule 1 set tag 5 # set policy route-map test3 rule 1 set weight 4 # set policy route-map test3 rule 1 match metric 1 # set policy route-map test3 rule 1 match peer 192.0.2.32 # set policy route-map test3 rule 1 match rpki invalid # "after": [ # { # "entries": [ # { # "action": "permit", # "continue_sequence": 2, # "description": "test", # "on_match": { # "next": true # }, # "sequence": 1 # } # ], # "route_map": "test1" # }, # { # "entries": [ # { # "action": "permit", # "match": { # "metric": 1, # "peer": "192.0.2.32", # "rpki": "invalid" # }, # "sequence": 1, # "set": { # "local_preference": "4", # "metric": "5", # "metric_type": "type-1", # "origin": "egp", # "originator_id": "192.0.2.34", # "tag": "5", # "weight": "4" # } # } # ], # "route_map": "test3" # } # ], # "before": [], # "changed": true, # "commands": [ # "set policy route-map test1 rule 1 description test", # "set policy route-map test1 rule 1 action permit", # "set policy route-map test1 rule 1 continue 2", # "set policy route-map test1 rule 1 on-match next", # "set policy route-map test3 rule 1 action permit", # "set policy route-map test3 rule 1 set local-preference 4", # "set policy route-map test3 rule 1 set metric 5", # "set policy route-map test3 rule 1 set metric-type type-1", # "set policy route-map test3 rule 1 set origin egp", # "set policy route-map test3 rule 1 set originator-id 192.0.2.34", # "set policy route-map test3 rule 1 set tag 5", # "set policy route-map test3 rule 1 set weight 4", # "set policy route-map test3 rule 1 match metric 1", # "set policy route-map test3 rule 1 match peer 192.0.2.32", # "set policy route-map test3 rule 1 match rpki invalid" # ], # Using replaced: # -------------- # Before state: # vyos@vyos:~$ show configuration commands | match "set route-map policy" # set policy route-map test2 rule 1 action 'permit' # set policy route-map test2 rule 1 description 'test' # set policy route-map test2 rule 1 on-match next # set policy route-map test2 rule 2 action 'permit' # set policy route-map test2 rule 2 on-match goto '4' # set policy route-map test3 rule 1 action 'permit' # set policy route-map test3 rule 1 match metric '1' # set policy route-map test3 rule 1 match peer '192.0.2.32' # set policy route-map test3 rule 1 match rpki 'invalid' # set policy route-map test3 rule 1 set community 'internet' # set policy route-map test3 rule 1 set ip-next-hop '192.0.2.33' # set policy route-map test3 rule 1 set local-preference '4' # set policy route-map test3 rule 1 set metric '5' # set policy route-map test3 rule 1 set metric-type 'type-1' # set policy route-map test3 rule 1 set origin 'egp' # set policy route-map test3 rule 1 set originator-id '192.0.2.34' # set policy route-map test3 rule 1 set tag '5' # set policy route-map test3 rule 1 set weight '4' # # - name: Replace the provided configuration with the existing running configuration # register: result # vyos.vyos.vyos_route_maps: &id001 # config: # - route_map: test3 # entries: # - sequence: 1 # action: permit # match: # rpki: invalid # metric: 3 # peer: 192.0.2.35 # set: # local_preference: 6 # metric: 4 # metric_type: "type-1" # origin: egp # originator_id: 192.0.2.34 # tag: 4 # weight: 4 # state: replaced # After state: # vyos@vyos:~$ show configuration commands | match "set policy route-map" # set policy route-map test3 rule 1 set local-preference 6 # set policy route-map test3 rule 1 set metric 4 # set policy route-map test3 rule 1 set tag 4 # set policy route-map test3 rule 1 match metric 3 # set policy route-map test3 rule 1 match peer 192.0.2.35 # vyos@vyos:~$ # # # Module Execution: # # "after": [ # { # "entries": [ # { # "action": "permit", # "description": "test", # "on_match": { # "next": true # }, # "sequence": 1 # }, # { # "action": "permit", # "on_match": { # "goto": 4 # }, # "sequence": 2 # } # ], # "route_map": "test2" # }, # { # "entries": [ # { # "action": "permit", # "match": { # "metric": 3, # "peer": "192.0.2.35", # "rpki": "invalid" # }, # "sequence": 1, # "set": { # "local_preference": "6", # "metric": "4", # "metric_type": "type-1", # "origin": "egp", # "originator_id": "192.0.2.34", # "tag": "4", # "weight": "4" # } # } # ], # "route_map": "test3" # } # ], # "before": [ # { # "entries": [ # { # "action": "permit", # "description": "test", # "on_match": { # "next": true # }, # "sequence": 1 # }, # { # "action": "permit", # "on_match": { # "goto": 4 # }, # "sequence": 2 # } # ], # "route_map": "test2" # }, # { # "entries": [ # { # "action": "permit", # "match": { # "metric": 1, # "peer": "192.0.2.32", # "rpki": "invalid" # }, # "sequence": 1, # "set": { # "community": { # "value": "internet" # }, # "ip_next_hop": "192.0.2.33", # "local_preference": "4", # "metric": "5", # "metric_type": "type-1", # "origin": "egp", # "originator_id": "192.0.2.34", # "tag": "5", # "weight": "4" # } # } # ], # "route_map": "test3" # } # ], # "changed": true, # "commands": [ # "delete policy route-map test3 rule 1 set ip-next-hop 192.0.2.33", # "set policy route-map test3 rule 1 set local-preference 6", # "set policy route-map test3 rule 1 set metric 4", # "set policy route-map test3 rule 1 set tag 4", # "delete policy route-map test3 rule 1 set community internet", # "set policy route-map test3 rule 1 match metric 3", # "set policy route-map test3 rule 1 match peer 192.0.2.35" # ], # # Using deleted: # ------------- # Before state: # vyos@vyos:~$ show configuration commands | match "set policy route-map" # set policy route-map test3 rule 1 set local-preference 6 # set policy route-map test3 rule 1 set metric 4 # set policy route-map test3 rule 1 set tag 4 # set policy route-map test3 rule 1 match metric 3 # set policy route-map test3 rule 1 match peer 192.0.2.35 # vyos@vyos:~$ # # - name: Delete the provided configuration # register: result # vyos.vyos.vyos_route_maps: # config: # state: deleted # After state: # vyos@vyos:~$ show configuration commands | match "set policy route-map" # vyos@vyos:~$ # # # Module Execution: # # "after": [], # "before": [ # { # "entries": [ # { # "action": "permit", # "match": { # "metric": 3, # "peer": "192.0.2.35", # }, # "sequence": 1, # "set": { # "local_preference": "6", # "metric": "4", # "tag": "4", # } # } # ], # "route_map": "test3" # } # ], # "changed": true, # "commands": [ # "delete policy route-map test3" # ], # # using gathered: # -------------- # # Before state: # vyos@vyos:~$ show configuration commands | match "set policy route-maps" # set policy route-map test1 rule 1 description test # set policy route-map test1 rule 1 action permit # set policy route-map test1 rule 1 continue 2 # set policy route-map test1 rule 1 on-match next # set policy route-map test3 rule 1 action permit # set policy route-map test3 rule 1 set local-preference 4 # set policy route-map test3 rule 1 set metric 5 # set policy route-map test3 rule 1 set metric-type type-1 # set policy route-map test3 rule 1 set origin egp # set policy route-map test3 rule 1 set originator-id 192.0.2.34 # set policy route-map test3 rule 1 set tag 5 # set policy route-map test3 rule 1 set weight 4 # set policy route-map test3 rule 1 match metric 1 # set policy route-map test3 rule 1 match peer 192.0.2.32 # set policy route-map test3 rule 1 match rpki invalid # # - name: gather configs # vyos.vyos.vyos_route_maps: # state: gathered # "gathered": [ # { # "entries": [ # { # "action": "permit", # "continue_sequence": 2, # "description": "test", # "on_match": { # "next": true # }, # "sequence": 1 # } # ], # "route_map": "test1" # }, # { # "entries": [ # { # "action": "permit", # "match": { # "metric": 1, # "peer": "192.0.2.32", # "rpki": "invalid" # }, # "sequence": 1, # "set": { # "local_preference": "4", # "metric": "5", # "metric_type": "type-1", # "origin": "egp", # "originator_id": "192.0.2.34", # "tag": "5", # "weight": "4" # } # } # ], # "route_map": "test3" # } # ] # Using parsed: # ------------ # parsed.cfg # set policy route-map test1 rule 1 description test # set policy route-map test1 rule 1 action permit # set policy route-map test1 rule 1 continue 2 # set policy route-map test1 rule 1 on-match next # set policy route-map test3 rule 1 action permit # set policy route-map test3 rule 1 set local-preference 4 # set policy route-map test3 rule 1 set metric 5 # set policy route-map test3 rule 1 set metric-type type-1 # set policy route-map test3 rule 1 set origin egp # set policy route-map test3 rule 1 set originator-id 192.0.2.34 # set policy route-map test3 rule 1 set tag 5 # set policy route-map test3 rule 1 set weight 4 # set policy route-map test3 rule 1 match metric 1 # set policy route-map test3 rule 1 match peer 192.0.2.32 # set policy route-map test3 rule 1 match rpki invalid # # - name: parse configs # vyos.vyos.vyos_route_maps: # running_config: "{{ lookup('file', './parsed.cfg') }}" # state: parsed # tags: # - parsed # # Module execution: # "parsed": [ # { # "entries": [ # { # "action": "permit", # "continue_sequence": 2, # "description": "test", # "on_match": { # "next": true # }, # "sequence": 1 # } # ], # "route_map": "test1" # }, # { # "entries": [ # { # "action": "permit", # "match": { # "metric": 1, # "peer": "192.0.2.32", # "rpki": "invalid" # }, # "sequence": 1, # "set": { # "local_preference": "4", # "metric": "5", # "metric_type": "type-1", # "origin": "egp", # "originator_id": "192.0.2.34", # "tag": "5", # "weight": "4" # } # } # ], # "route_map": "test3" # } # ] # # # Using rendered: # -------------- # - name: Structure provided configuration into device specific commands # register: result # vyos.vyos.vyos_route_maps: &id001 # config: # - route_map: test1 # entries: # - sequence: 1 # description: "test" # action: permit # continue_sequence: 2 # on_match: # next: True # - route_map: test3 # entries: # - sequence: 1 # action: permit # match: # rpki: invalid # metric: 1 # peer: 192.0.2.32 # set: # local_preference: 4 # metric: 5 # metric_type: "type-1" # origin: egp # originator_id: 192.0.2.34 # tag: 5 # weight: 4 # state: rendered # Module Execution: # "rendered": [ # "set policy route-map test1 rule 1 description test", # "set policy route-map test1 rule 1 action permit", # "set policy route-map test1 rule 1 continue 2", # "set policy route-map test1 rule 1 on-match next", # "set policy route-map test3 rule 1 action permit", # "set policy route-map test3 rule 1 set local-preference 4", # "set policy route-map test3 rule 1 set metric 5", # "set policy route-map test3 rule 1 set metric-type type-1", # "set policy route-map test3 rule 1 set origin egp", # "set policy route-map test3 rule 1 set originator-id 192.0.2.34", # "set policy route-map test3 rule 1 set tag 5", # "set policy route-map test3 rule 1 set weight 4", # "set policy route-map test3 rule 1 match metric 1", # "set policy route-map test3 rule 1 match peer 192.0.2.32", # "set policy route-map test3 rule 1 match rpki invalid" # ] # # # Using overridden: # -------------- # Before state: # vyos@vyos:~$ show configuration commands | match "set policy route-map" # set policy route-map test2 rule 1 action 'permit' # set policy route-map test2 rule 1 description 'test' # set policy route-map test2 rule 1 on-match next # set policy route-map test2 rule 2 action 'permit' # set policy route-map test2 rule 2 on-match goto '4' # set policy route-map test3 rule 1 action 'permit' # set policy route-map test3 rule 1 match metric '1' # set policy route-map test3 rule 1 match peer '192.0.2.32' # set policy route-map test3 rule 1 match rpki 'invalid' # set policy route-map test3 rule 1 set community 'internet' # set policy route-map test3 rule 1 set ip-next-hop '192.0.2.33' # set policy route-map test3 rule 1 set local-preference '4' # set policy route-map test3 rule 1 set metric '5' # set policy route-map test3 rule 1 set metric-type 'type-1' # set policy route-map test3 rule 1 set origin 'egp' # set policy route-map test3 rule 1 set originator-id '192.0.2.34' # set policy route-map test3 rule 1 set tag '5' # set policy route-map test3 rule 1 set weight '4' # # - name: Override the existing configuration with the provided running configuration # register: result # vyos.vyos.vyos_route_maps: &id001 # config: # - route_map: test3 # entries: # - sequence: 1 # action: permit # match: # rpki: invalid # metric: 3 # peer: 192.0.2.35 # set: # local_preference: 6 # metric: 4 # metric_type: "type-1" # origin: egp # originator_id: 192.0.2.34 # tag: 4 # weight: 4 # state: overridden # After state: # vyos@vyos:~$ show configuration commands | match "set policy route-map" # set policy route-map test3 rule 1 set metric-type 'type-1' # set policy route-map test3 rule 1 set origin 'egp' # set policy route-map test3 rule 1 set originator-id '192.0.2.34' # set policy route-map test3 rule 1 set weight '4' # set policy route-map test3 rule 1 set local-preference 6 # set policy route-map test3 rule 1 set metric 4 # set policy route-map test3 rule 1 set tag 4 # set policy route-map test3 rule 1 match metric 3 # set policy route-map test3 rule 1 match peer 192.0.2.35 # set policy route-map test3 rule 1 match rpki 'invalid' # Module Execution: # "after": [ # { # "entries": [ # { # "action": "permit", # "match": { # "metric": 3, # "peer": "192.0.2.35", # "rpki": "invalid" # }, # "sequence": 1, # "set": { # "local_preference": "6", # "metric": "4", # "metric_type": "type-1", # "origin": "egp", # "originator_id": "192.0.2.34", # "tag": "4", # "weight": "4" # } # } # ], # "route_map": "test3" # } # ], # "before": [ # { # "entries": [ # { # "action": "permit", # "description": "test", # "on_match": { # "next": true # }, # "sequence": 1 # }, # { # "action": "permit", # "on_match": { # "goto": 4 # }, # "sequence": 2 # } # ], # "route_map": "test2" # }, # { # "entries": [ # { # "action": "permit", # "match": { # "metric": 1, # "peer": "192.0.2.32", # "rpki": "invalid" # }, # "sequence": 1, # "set": { # "community": { # "value": "internet" # }, # "ip_next_hop": "192.0.2.33", # "local_preference": "4", # "metric": "5", # "metric_type": "type-1", # "origin": "egp", # "originator_id": "192.0.2.34", # "tag": "5", # "weight": "4" # } # } # ], # "route_map": "test3" # } # ], # "changed": true, # "commands": [ # "delete policy route-map test2", # "delete policy route-map test3 rule 1 set ip-next-hop 192.0.2.33", # "set policy route-map test3 rule 1 set local-preference 6", # "set policy route-map test3 rule 1 set metric 4", # "set policy route-map test3 rule 1 set tag 4", # "delete policy route-map test3 rule 1 set community internet", # "set policy route-map test3 rule 1 match metric 3", # "set policy route-map test3 rule 1 match peer 192.0.2.35" # ], """ RETURN = """ before: description: The configuration prior to the module execution. returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) type: dict sample: > This output will always be in the same format as the module argspec. after: description: The resulting configuration after module execution. returned: when changed type: dict sample: > This output will always be in the same format as the module argspec. commands: description: The set of commands pushed to the remote device. returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) type: list sample: - "set policy route-map test3 rule 1 set local-preference 6" - "set policy route-map test3 rule 1 set metric 4" - "set policy route-map test3 rule 1 set tag 4" rendered: description: The provided configuration in the task rendered in device-native format (offline). returned: when I(state) is C(rendered) type: list sample: - "set policy route-map test3 rule 1 set local-preference 6" - "set policy route-map test3 rule 1 set metric 4" - "set policy route-map test3 rule 1 set tag 4" 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.vyos.vyos.plugins.module_utils.network.vyos.argspec.route_maps.route_maps import ( Route_mapsArgs, ) from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.route_maps.route_maps import ( Route_maps, ) def main(): """ Main entry point for module execution :returns: the result form module invocation """ module = AnsibleModule( argument_spec=Route_mapsArgs.argument_spec, mutually_exclusive=[["config", "running_config"]], required_if=[ ["state", "merged", ["config"]], ["state", "replaced", ["config"]], ["state", "overridden", ["config"]], ["state", "rendered", ["config"]], ["state", "parsed", ["running_config"]], ], supports_check_mode=True, ) result = Route_maps(module).execute_module() module.exit_json(**result) if __name__ == "__main__": main() diff --git a/tests/integration/targets/vyos_route_maps/tests/cli/replaced.yaml b/tests/integration/targets/vyos_route_maps/tests/cli/replaced.yaml index d7d05ec1..dce0cba9 100644 --- a/tests/integration/targets/vyos_route_maps/tests/cli/replaced.yaml +++ b/tests/integration/targets/vyos_route_maps/tests/cli/replaced.yaml @@ -1,49 +1,48 @@ --- - debug: msg: START vyos_route_maps replaced integration tests on connection={{ ansible_connection }} - include_tasks: _populate.yaml - block: - name: Replace the provided configuration with the existing running configuration register: result vyos.vyos.vyos_route_maps: &id001 config: - route_map: test3 entries: - sequence: 1 action: permit match: metric: 3 peer: 192.0.2.35 set: local_preference: 6 metric: 4 metric_type: type-1 origin: egp originator_id: 192.0.2.34 tag: 4 weight: 4 state: replaced - vyos.vyos.vyos_facts: gather_network_resources: route_maps - assert: that: - - result.commands|length == 7 - result.changed == true - result.commands|symmetric_difference(replaced.commands) == [] - result.after|symmetric_difference(ansible_facts['network_resources']['route_maps']) == [] - name: Replace the provided configuration with the existing running configuration (IDEMPOTENT) register: result vyos.vyos.vyos_route_maps: *id001 - name: Assert that the previous task was idempotent assert: that: - result['changed'] == false always: - include_tasks: _remove_config.yaml diff --git a/tests/unit/modules/network/vyos/fixtures/vyos_route_maps_config_v14.cfg b/tests/unit/modules/network/vyos/fixtures/vyos_route_maps_config_v14.cfg new file mode 100644 index 00000000..1e84e5eb --- /dev/null +++ b/tests/unit/modules/network/vyos/fixtures/vyos_route_maps_config_v14.cfg @@ -0,0 +1,18 @@ +set policy route-map test3 rule 1 action 'permit' +set policy route-map test3 rule 1 match interface 'eth2' +set policy route-map test3 rule 1 match ipv6 nexthop 'fdda:5cc1:23:4::1f' +set policy route-map test3 rule 1 match metric '1' +set policy route-map test3 rule 1 match peer '1.1.1.2' +set policy route-map test3 rule 1 match rpki 'invalid' +set policy route-map test3 rule 1 set bgp-extcommunity-rt '22:11' +set policy route-map test3 rule 1 set community replace 'internet' +set policy route-map test3 rule 1 set ipv6-next-hop global 'fdda:5cc1:23:4::1f' +set policy route-map test3 rule 1 set ip-next-hop '10.20.10.20' +set policy route-map test3 rule 1 set local-preference '4' +set policy route-map test3 rule 1 set metric '5' +set policy route-map test3 rule 1 set metric-type 'type-1' +set policy route-map test3 rule 1 set origin 'egp' +set policy route-map test3 rule 1 set originator-id '10.0.2.3' +set policy route-map test3 rule 1 set src '10.0.2.15' +set policy route-map test3 rule 1 set tag '5' +set policy route-map test3 rule 1 set weight '4' diff --git a/tests/unit/modules/network/vyos/test_vyos_route_maps.py b/tests/unit/modules/network/vyos/test_vyos_route_maps.py index ce13dcf2..db83ea40 100644 --- a/tests/unit/modules/network/vyos/test_vyos_route_maps.py +++ b/tests/unit/modules/network/vyos/test_vyos_route_maps.py @@ -1,584 +1,715 @@ # (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 unittest.mock import patch from ansible_collections.vyos.vyos.plugins.modules import vyos_route_maps from ansible_collections.vyos.vyos.tests.unit.modules.utils import set_module_args from .vyos_module import TestVyosModule, load_fixture class TestVyosRouteMapsModule(TestVyosModule): module = vyos_route_maps def setUp(self): super(TestVyosRouteMapsModule, self).setUp() self.mock_get_resource_connection_config = patch( "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module_base.get_resource_connection", ) self.get_resource_connection_config = self.mock_get_resource_connection_config.start() self.mock_get_resource_connection_facts = patch( "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection", ) self.get_resource_connection_facts = self.mock_get_resource_connection_facts.start() self.mock_execute_show_command = patch( "ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.route_maps.route_maps.Route_mapsFacts.get_config", ) self.execute_show_command = self.mock_execute_show_command.start() + self.mock_get_os_version = patch( + "ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.route_maps.route_maps.get_os_version", + ) + self.test_version = "1.2" + self.get_os_version = self.mock_get_os_version.start() + self.get_os_version.return_value = self.test_version + self.mock_facts_get_os_version = patch( + "ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.route_maps.route_maps.get_os_version", + ) + self.get_facts_os_version = self.mock_facts_get_os_version.start() + self.get_facts_os_version.return_value = self.test_version + self.maxDiff = None def tearDown(self): super(TestVyosRouteMapsModule, self).tearDown() self.mock_get_resource_connection_config.stop() self.mock_get_resource_connection_facts.stop() self.mock_execute_show_command.stop() def load_fixtures(self, commands=None, filename=None): if filename is None: filename = "vyos_route_maps_config.cfg" def load_from_file(*args, **kwargs): output = load_fixture(filename) return output self.execute_show_command.side_effect = load_from_file def test_vyos_route_maps_merged_idempotent(self): set_module_args( dict( config=[ dict( route_map="test3", entries=[ dict( sequence=1, action="permit", match=dict( rpki="invalid", interface="eth2", metric=1, peer="1.1.1.2", ipv6=dict(next_hop="fdda:5cc1:23:4::1f"), ), set=dict( ipv6_next_hop=dict( ip_type="global", value="fdda:5cc1:23:4::1f", ), community=dict(value="internet"), bgp_extcommunity_rt="22:11", ip_next_hop="10.20.10.20", local_preference=4, metric=5, metric_type="type-1", origin="egp", originator_id="10.0.2.3", src="10.0.2.15", tag=5, weight=4, ), ), ], ), ], state="merged", ), ) self.execute_module(changed=False, commands=[]) def test_route_maps_merged(self): set_module_args( dict( config=[ dict( route_map="test2", entries=[ dict( sequence=1, action="permit", match=dict( rpki="invalid", interface="eth2", metric=1, peer="1.1.1.3", ipv6=dict(next_hop="fdda:5cc1:23:4::1f"), ), set=dict( ipv6_next_hop=dict( ip_type="global", value="fdda:5cc1:23:4::1f", ), community=dict(value="internet"), bgp_extcommunity_rt="22:11", ip_next_hop="10.20.10.22", large_community="10:20:21", local_preference=4, metric=5, metric_type="type-2", origin="egp", originator_id="10.0.2.2", src="10.0.2.15", tag=4, weight=4, ), ), ], ), ], state="merged", ), ) commands = [ "set policy route-map test2 rule 1 action permit", "set policy route-map test2 rule 1 set bgp-extcommunity-rt 22:11", "set policy route-map test2 rule 1 set ip-next-hop 10.20.10.22", "set policy route-map test2 rule 1 set ipv6-next-hop global fdda:5cc1:23:4::1f", "set policy route-map test2 rule 1 set large-community 10:20:21", "set policy route-map test2 rule 1 set local-preference 4", "set policy route-map test2 rule 1 set metric 5", "set policy route-map test2 rule 1 set metric-type type-2", "set policy route-map test2 rule 1 set origin egp", "set policy route-map test2 rule 1 set originator-id 10.0.2.2", "set policy route-map test2 rule 1 set src 10.0.2.15", "set policy route-map test2 rule 1 set tag 4", "set policy route-map test2 rule 1 set weight 4", "set policy route-map test2 rule 1 set community internet", "set policy route-map test2 rule 1 match interface eth2", "set policy route-map test2 rule 1 match metric 1", "set policy route-map test2 rule 1 match peer 1.1.1.3", "set policy route-map test2 rule 1 match ipv6 nexthop fdda:5cc1:23:4::1f", "set policy route-map test2 rule 1 match rpki invalid", ] self.execute_module(changed=True, commands=commands) - def test_route_maps_replaced(self): + def test_route_maps_extras_merged(self): set_module_args( dict( config=[ dict( - route_map="test3", + route_map="test2", entries=[ dict( sequence=1, action="permit", + call="2", + continue_sequence=2, match=dict( rpki="invalid", + interface="eth2", metric=1, peer="1.1.1.3", ipv6=dict(next_hop="fdda:5cc1:23:4::1f"), + community=dict(community_list="235"), ), set=dict( ipv6_next_hop=dict( ip_type="global", value="fdda:5cc1:23:4::1f", ), community=dict(value="internet"), + extcommunity_rt="22:11", + extcommunity_soo="220:110", + extcommunity_bandwidth="100", + extcommunity_bandwidth_non_transitive=True, + atomic_aggregate=True, + aggregator={"ip": "10.20.11.22", "as": "245"}, bgp_extcommunity_rt="22:11", ip_next_hop="10.20.10.22", large_community="10:20:21", + as_path_prepend="100 200 350", + as_path_exclude="150", local_preference=4, metric=5, metric_type="type-2", origin="egp", originator_id="10.0.2.2", src="10.0.2.15", tag=4, weight=4, + table=7, + ), + ), + ], + ), + ], + state="merged", + ), + ) + commands = [ + "set policy route-map test2 rule 1 action permit", + "set policy route-map test2 rule 1 call 2", + "set policy route-map test2 rule 1 set bgp-extcommunity-rt 22:11", + "set policy route-map test2 rule 1 set ip-next-hop 10.20.10.22", + "set policy route-map test2 rule 1 set ipv6-next-hop global fdda:5cc1:23:4::1f", + "set policy route-map test2 rule 1 set large-community 10:20:21", + "set policy route-map test2 rule 1 set as-path-prepend '100 200 350'", + "set policy route-map test2 rule 1 set as-path-exclude 150", + "set policy route-map test2 rule 1 set local-preference 4", + "set policy route-map test2 rule 1 set metric 5", + "set policy route-map test2 rule 1 set metric-type type-2", + "set policy route-map test2 rule 1 set origin egp", + "set policy route-map test2 rule 1 set originator-id 10.0.2.2", + "set policy route-map test2 rule 1 set src 10.0.2.15", + "set policy route-map test2 rule 1 set tag 4", + "set policy route-map test2 rule 1 set weight 4", + "set policy route-map test2 rule 1 set table 7", + "set policy route-map test2 rule 1 set community internet", + "set policy route-map test2 rule 1 set extcommunity-rt 22:11", + "set policy route-map test2 rule 1 set extcommunity-soo 220:110", + "set policy route-map test2 rule 1 set extcommunity bandwidth 100", + "set policy route-map test2 rule 1 set extcommunity bandwidth-non-transitive", + "set policy route-map test2 rule 1 set atomic-aggregate", + "set policy route-map test2 rule 1 set aggregator as 245", + "set policy route-map test2 rule 1 set aggregator ip 10.20.11.22", + "set policy route-map test2 rule 1 match interface eth2", + "set policy route-map test2 rule 1 match metric 1", + "set policy route-map test2 rule 1 match peer 1.1.1.3", + "set policy route-map test2 rule 1 match ipv6 nexthop fdda:5cc1:23:4::1f", + "set policy route-map test2 rule 1 match rpki invalid", + "set policy route-map test2 rule 1 match community community-list 235", + "set policy route-map test2 rule 1 continue 2", + ] + + self.execute_module(changed=True, commands=commands) + + def test_route_maps_replaced(self): + set_module_args( + dict( + config=[ + dict( + route_map="test3", + entries=[ + dict( + sequence=1, + action="permit", + match=dict( + rpki="invalid", + metric=1, + peer="1.1.1.3", + ipv6=dict(next_hop="fdda:5cc1:23:4::1f"), + ), + set=dict( + ipv6_next_hop=dict( + ip_type="global", + value="fdda:5cc1:23:4::1f", + ), + community=dict(value="100:100"), + bgp_extcommunity_rt="22:11", + ip_next_hop="10.20.10.22", + large_community="10:20:21", + local_preference=4, + metric=5, + metric_type="type-2", + origin="egp", + originator_id="10.0.2.2", + src="fdda:5cc1:23:4::12", + tag=4, + weight=4, ), ), ], ), ], state="replaced", ), ) commands = [ "delete policy route-map test3 rule 1 match interface eth2", "set policy route-map test3 rule 1 set ip-next-hop 10.20.10.22", + "set policy route-map test3 rule 1 set community 100:100", "set policy route-map test3 rule 1 set large-community 10:20:21", "set policy route-map test3 rule 1 set metric-type type-2", "set policy route-map test3 rule 1 set originator-id 10.0.2.2", "set policy route-map test3 rule 1 set tag 4", + "set policy route-map test3 rule 1 set src fdda:5cc1:23:4::12", "set policy route-map test3 rule 1 match peer 1.1.1.3", ] self.execute_module(changed=True, commands=commands) def test_vyos_route_maps_replaced_idempotent(self): set_module_args( dict( config=[ dict( route_map="test3", entries=[ dict( sequence=1, action="permit", match=dict( rpki="invalid", interface="eth2", metric=1, peer="1.1.1.2", ipv6=dict(next_hop="fdda:5cc1:23:4::1f"), ), set=dict( ipv6_next_hop=dict( ip_type="global", value="fdda:5cc1:23:4::1f", ), community=dict(value="internet"), bgp_extcommunity_rt="22:11", ip_next_hop="10.20.10.20", local_preference=4, metric=5, metric_type="type-1", origin="egp", originator_id="10.0.2.3", src="10.0.2.15", tag=5, weight=4, ), ), ], ), ], state="replaced", ), ) self.execute_module(changed=False, commands=[]) def test_route_maps_overridden(self): set_module_args( dict( config=[ dict( route_map="test2", entries=[ dict( sequence=1, action="permit", match=dict(rpki="invalid", peer="1.1.1.3"), set=dict( ipv6_next_hop=dict( ip_type="global", value="fdda:5cc1:23:4::1f", ), community=dict(value="internet"), bgp_extcommunity_rt="22:11", ip_next_hop="10.20.10.22", large_community="10:20:21", local_preference=4, metric=5, metric_type="type-2", origin="egp", originator_id="10.0.2.2", src="10.0.2.15", tag=4, weight=4, ), ), ], ), ], state="overridden", ), ) commands = [ "delete policy route-map test3", "set policy route-map test2 rule 1 action permit", "set policy route-map test2 rule 1 set bgp-extcommunity-rt 22:11", "set policy route-map test2 rule 1 set ip-next-hop 10.20.10.22", "set policy route-map test2 rule 1 set ipv6-next-hop global fdda:5cc1:23:4::1f", "set policy route-map test2 rule 1 set large-community 10:20:21", "set policy route-map test2 rule 1 set local-preference 4", "set policy route-map test2 rule 1 set metric 5", "set policy route-map test2 rule 1 set metric-type type-2", "set policy route-map test2 rule 1 set origin egp", "set policy route-map test2 rule 1 set originator-id 10.0.2.2", "set policy route-map test2 rule 1 set src 10.0.2.15", "set policy route-map test2 rule 1 set tag 4", "set policy route-map test2 rule 1 set weight 4", "set policy route-map test2 rule 1 set community internet", "set policy route-map test2 rule 1 match peer 1.1.1.3", "set policy route-map test2 rule 1 match rpki invalid", ] self.execute_module(changed=True, commands=commands) + def test_route_maps__deny_overridden(self): + set_module_args( + dict( + config=[ + dict( + route_map="test2", + entries=[ + dict( + sequence=1, + action="deny", + match=dict(rpki="invalid", peer="1.1.1.5"), + ), + ], + ), + ], + state="overridden", + ), + ) + commands = [ + "delete policy route-map test3", + "set policy route-map test2 rule 1 action deny", + "set policy route-map test2 rule 1 match peer 1.1.1.5", + "set policy route-map test2 rule 1 match rpki invalid", + ] + self.execute_module(changed=True, commands=commands) + def test_vyos_route_maps_overridden_idempotent(self): set_module_args( dict( config=[ dict( route_map="test3", entries=[ dict( sequence=1, action="permit", match=dict( rpki="invalid", interface="eth2", metric=1, peer="1.1.1.2", ipv6=dict(next_hop="fdda:5cc1:23:4::1f"), ), set=dict( ipv6_next_hop=dict( ip_type="global", value="fdda:5cc1:23:4::1f", ), community=dict(value="internet"), bgp_extcommunity_rt="22:11", ip_next_hop="10.20.10.20", local_preference=4, metric=5, metric_type="type-1", origin="egp", originator_id="10.0.2.3", src="10.0.2.15", tag=5, weight=4, ), ), ], ), ], state="overridden", ), ) self.execute_module(changed=False, commands=[]) def test_vyos_route_maps_rendered(self): set_module_args( dict( config=[ dict( route_map="test3", entries=[ dict( sequence=1, action="permit", match=dict( rpki="invalid", interface="eth2", metric=1, peer="1.1.1.2", ipv6=dict(next_hop="fdda:5cc1:23:4::1f"), ), set=dict( ipv6_next_hop=dict( ip_type="global", value="fdda:5cc1:23:4::1f", ), community=dict(value="internet"), bgp_extcommunity_rt="22:11", ip_next_hop="10.20.10.20", local_preference=4, metric=5, metric_type="type-1", origin="egp", originator_id="10.0.2.3", src="10.0.2.15", tag=5, weight=4, ), ), ], ), dict( route_map="test1", entries=[ dict( sequence=1, action="permit", description="test", on_match=dict(next=True), ), dict( sequence=2, action="permit", on_match=dict(goto=4), ), ], ), ], state="rendered", ), ) rendered_cmds = [ "set policy route-map test3 rule 1 action permit", "set policy route-map test3 rule 1 set bgp-extcommunity-rt 22:11", "set policy route-map test3 rule 1 set ip-next-hop 10.20.10.20", "set policy route-map test3 rule 1 set ipv6-next-hop global fdda:5cc1:23:4::1f", "set policy route-map test3 rule 1 set local-preference 4", "set policy route-map test3 rule 1 set metric 5", "set policy route-map test3 rule 1 set metric-type type-1", "set policy route-map test3 rule 1 set origin egp", "set policy route-map test3 rule 1 set originator-id 10.0.2.3", "set policy route-map test3 rule 1 set src 10.0.2.15", "set policy route-map test3 rule 1 set tag 5", "set policy route-map test3 rule 1 set weight 4", "set policy route-map test3 rule 1 set community internet", "set policy route-map test3 rule 1 match interface eth2", "set policy route-map test3 rule 1 match metric 1", "set policy route-map test3 rule 1 match peer 1.1.1.2", "set policy route-map test3 rule 1 match ipv6 nexthop fdda:5cc1:23:4::1f", "set policy route-map test3 rule 1 match rpki invalid", "set policy route-map test1 rule 1 description test", "set policy route-map test1 rule 1 action permit", "set policy route-map test1 rule 1 on-match next", "set policy route-map test1 rule 2 action permit", "set policy route-map test1 rule 2 on-match goto 4", ] result = self.execute_module(changed=False) self.assertEqual( sorted(result["rendered"]), sorted(rendered_cmds), result["rendered"], ) def test_yos_route_maps_parsed(self): parsed_str = ( "set policy route-map test3 rule 1 action 'permit'" "\nset policy route-map test3 rule 1 match interface 'eth2'\nset policy route-map test3 rule 1 match ipv6 nexthop" " 'fdda:5cc1:23:4::1f'\nset policy route-map test3 rule 1 match metric '1'\nset policy route-map test3 rule 1 match peer " "'1.1.1.2'\nset policy route-map test3 rule 1 match rpki 'invalid'\nset policy route-map test3 rule 1 set bgp-extcommunity-rt " "'22:11'\nset policy route-map test3 rule 1 set community 'internet'\nset policy route-map test3 rule 1 set ipv6-next-hop global" " 'fdda:5cc1:23:4::1f'\nset policy route-map test3 rule 1 set ip-next-hop '10.20.10.20'\nset policy route-map " "test3 rule 1 set local-preference '4'\nset policy route-map test3 rule 1 set metric '5'\nset policy route-map test3 " "rule 1 set metric-type 'type-1'\nset policy route-map test3 rule 1 set origin 'egp'\nset policy route-map test3 rule 1 set originator-id " "'10.0.2.3'\nset policy route-map test3 rule 1 set src '10.0.2.15'" "\nset policy route-map test3 rule 1 set tag '5'\nset policy route-map test3 rule 1 set weight '4'" ) set_module_args(dict(running_config=parsed_str, state="parsed")) result = self.execute_module(changed=False) parsed_list = [ { "entries": [ { "action": "permit", "match": { "interface": "eth2", "ipv6": {"next_hop": "fdda:5cc1:23:4::1f"}, "metric": 1, "peer": "1.1.1.2", "rpki": "invalid", }, "sequence": 1, "set": { "bgp_extcommunity_rt": "22:11", "community": {"value": "internet"}, "ip_next_hop": "10.20.10.20", "ipv6_next_hop": { "ip_type": "global", "value": "fdda:5cc1:23:4::1f", }, "local_preference": "4", "metric": "5", "metric_type": "type-1", "origin": "egp", "originator_id": "10.0.2.3", "src": "10.0.2.15", "tag": "5", "weight": "4", }, }, ], "route_map": "test3", }, ] self.assertEqual(parsed_list, result["parsed"]) def test_vyos_route_maps_gathered(self): set_module_args(dict(state="gathered")) result = self.execute_module(changed=False) gathered_list = [ { "entries": [ { "action": "permit", "match": { "interface": "eth2", "ipv6": {"next_hop": "fdda:5cc1:23:4::1f"}, "metric": 1, "peer": "1.1.1.2", "rpki": "invalid", }, "sequence": 1, "set": { "bgp_extcommunity_rt": "22:11", "community": {"value": "internet"}, "ip_next_hop": "10.20.10.20", "ipv6_next_hop": { "ip_type": "global", "value": "fdda:5cc1:23:4::1f", }, "local_preference": "4", "metric": "5", "metric_type": "type-1", "origin": "egp", "originator_id": "10.0.2.3", "src": "10.0.2.15", "tag": "5", "weight": "4", }, }, ], "route_map": "test3", }, ] self.assertEqual(gathered_list, result["gathered"]) def test_vyos_route_maps_deleted(self): set_module_args( dict( config=[ dict( route_map="test3", entries=[ dict( sequence=1, action="permit", match=dict( rpki="invalid", interface="eth2", ), set=dict( origin="egp", originator_id="10.0.2.3", src="10.0.2.15", tag=5, weight=4, ), ), ], ), ], state="deleted", ), ) commands = ["delete policy route-map test3"] self.execute_module(changed=True, commands=commands) diff --git a/tests/unit/modules/network/vyos/test_vyos_route_maps.py b/tests/unit/modules/network/vyos/test_vyos_route_maps14.py similarity index 78% copy from tests/unit/modules/network/vyos/test_vyos_route_maps.py copy to tests/unit/modules/network/vyos/test_vyos_route_maps14.py index ce13dcf2..7bc5b74e 100644 --- a/tests/unit/modules/network/vyos/test_vyos_route_maps.py +++ b/tests/unit/modules/network/vyos/test_vyos_route_maps14.py @@ -1,584 +1,717 @@ # (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 unittest.mock import patch from ansible_collections.vyos.vyos.plugins.modules import vyos_route_maps from ansible_collections.vyos.vyos.tests.unit.modules.utils import set_module_args from .vyos_module import TestVyosModule, load_fixture class TestVyosRouteMapsModule(TestVyosModule): module = vyos_route_maps def setUp(self): super(TestVyosRouteMapsModule, self).setUp() self.mock_get_resource_connection_config = patch( "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module_base.get_resource_connection", ) self.get_resource_connection_config = self.mock_get_resource_connection_config.start() self.mock_get_resource_connection_facts = patch( "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection", ) self.get_resource_connection_facts = self.mock_get_resource_connection_facts.start() self.mock_execute_show_command = patch( "ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.route_maps.route_maps.Route_mapsFacts.get_config", ) self.execute_show_command = self.mock_execute_show_command.start() + self.mock_get_os_version = patch( + "ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.route_maps.route_maps.get_os_version", + ) + self.test_version = "1.4" + self.get_os_version = self.mock_get_os_version.start() + self.get_os_version.return_value = self.test_version + self.mock_facts_get_os_version = patch( + "ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.route_maps.route_maps.get_os_version", + ) + self.get_facts_os_version = self.mock_facts_get_os_version.start() + self.get_facts_os_version.return_value = self.test_version + self.maxDiff = None def tearDown(self): super(TestVyosRouteMapsModule, self).tearDown() self.mock_get_resource_connection_config.stop() self.mock_get_resource_connection_facts.stop() self.mock_execute_show_command.stop() def load_fixtures(self, commands=None, filename=None): if filename is None: - filename = "vyos_route_maps_config.cfg" + filename = "vyos_route_maps_config_v14.cfg" def load_from_file(*args, **kwargs): output = load_fixture(filename) return output self.execute_show_command.side_effect = load_from_file def test_vyos_route_maps_merged_idempotent(self): set_module_args( dict( config=[ dict( route_map="test3", entries=[ dict( sequence=1, action="permit", match=dict( rpki="invalid", interface="eth2", metric=1, peer="1.1.1.2", ipv6=dict(next_hop="fdda:5cc1:23:4::1f"), ), set=dict( ipv6_next_hop=dict( ip_type="global", value="fdda:5cc1:23:4::1f", ), community=dict(value="internet"), bgp_extcommunity_rt="22:11", ip_next_hop="10.20.10.20", local_preference=4, metric=5, metric_type="type-1", origin="egp", originator_id="10.0.2.3", src="10.0.2.15", tag=5, weight=4, ), ), ], ), ], state="merged", ), ) self.execute_module(changed=False, commands=[]) def test_route_maps_merged(self): set_module_args( dict( config=[ dict( route_map="test2", entries=[ dict( sequence=1, action="permit", match=dict( rpki="invalid", interface="eth2", metric=1, peer="1.1.1.3", ipv6=dict(next_hop="fdda:5cc1:23:4::1f"), ), set=dict( ipv6_next_hop=dict( ip_type="global", value="fdda:5cc1:23:4::1f", ), community=dict(value="internet"), bgp_extcommunity_rt="22:11", ip_next_hop="10.20.10.22", large_community="10:20:21", local_preference=4, metric=5, metric_type="type-2", origin="egp", originator_id="10.0.2.2", src="10.0.2.15", tag=4, weight=4, ), ), ], ), ], state="merged", ), ) commands = [ "set policy route-map test2 rule 1 action permit", "set policy route-map test2 rule 1 set bgp-extcommunity-rt 22:11", "set policy route-map test2 rule 1 set ip-next-hop 10.20.10.22", "set policy route-map test2 rule 1 set ipv6-next-hop global fdda:5cc1:23:4::1f", - "set policy route-map test2 rule 1 set large-community 10:20:21", + "set policy route-map test2 rule 1 set large-community replace 10:20:21", "set policy route-map test2 rule 1 set local-preference 4", "set policy route-map test2 rule 1 set metric 5", "set policy route-map test2 rule 1 set metric-type type-2", "set policy route-map test2 rule 1 set origin egp", "set policy route-map test2 rule 1 set originator-id 10.0.2.2", "set policy route-map test2 rule 1 set src 10.0.2.15", "set policy route-map test2 rule 1 set tag 4", "set policy route-map test2 rule 1 set weight 4", - "set policy route-map test2 rule 1 set community internet", + "set policy route-map test2 rule 1 set community replace internet", "set policy route-map test2 rule 1 match interface eth2", "set policy route-map test2 rule 1 match metric 1", "set policy route-map test2 rule 1 match peer 1.1.1.3", "set policy route-map test2 rule 1 match ipv6 nexthop fdda:5cc1:23:4::1f", "set policy route-map test2 rule 1 match rpki invalid", ] self.execute_module(changed=True, commands=commands) - def test_route_maps_replaced(self): + def test_route_maps_extras_merged(self): set_module_args( dict( config=[ dict( - route_map="test3", + route_map="test2", entries=[ dict( sequence=1, action="permit", + call="2", + continue_sequence=2, match=dict( rpki="invalid", + interface="eth2", metric=1, peer="1.1.1.3", ipv6=dict(next_hop="fdda:5cc1:23:4::1f"), + community=dict(community_list="235"), + protocol="bgp", ), set=dict( ipv6_next_hop=dict( ip_type="global", value="fdda:5cc1:23:4::1f", ), community=dict(value="internet"), + extcommunity_rt="22:11", + extcommunity_soo="220:110", + extcommunity_bandwidth="100", + extcommunity_bandwidth_non_transitive=True, + atomic_aggregate=True, + aggregator={"ip": "10.20.11.22", "as": "245"}, bgp_extcommunity_rt="22:11", ip_next_hop="10.20.10.22", large_community="10:20:21", + as_path_prepend="100 200 350", + as_path_exclude="150", local_preference=4, metric=5, metric_type="type-2", origin="egp", originator_id="10.0.2.2", src="10.0.2.15", tag=4, weight=4, + table=7, + ), + ), + ], + ), + ], + state="merged", + ), + ) + commands = [ + "set policy route-map test2 rule 1 action permit", + "set policy route-map test2 rule 1 call 2", + "set policy route-map test2 rule 1 set bgp-extcommunity-rt 22:11", + "set policy route-map test2 rule 1 set ip-next-hop 10.20.10.22", + "set policy route-map test2 rule 1 set ipv6-next-hop global fdda:5cc1:23:4::1f", + "set policy route-map test2 rule 1 set large-community replace 10:20:21", + "set policy route-map test2 rule 1 set as-path prepend '100 200 350'", + "set policy route-map test2 rule 1 set as-path exclude 150", + "set policy route-map test2 rule 1 set local-preference 4", + "set policy route-map test2 rule 1 set metric 5", + "set policy route-map test2 rule 1 set metric-type type-2", + "set policy route-map test2 rule 1 set origin egp", + "set policy route-map test2 rule 1 set originator-id 10.0.2.2", + "set policy route-map test2 rule 1 set src 10.0.2.15", + "set policy route-map test2 rule 1 set tag 4", + "set policy route-map test2 rule 1 set weight 4", + "set policy route-map test2 rule 1 set table 7", + "set policy route-map test2 rule 1 set community replace internet", + "set policy route-map test2 rule 1 set extcommunity rt 22:11", + "set policy route-map test2 rule 1 set extcommunity soo 220:110", + "set policy route-map test2 rule 1 set extcommunity bandwidth 100", + "set policy route-map test2 rule 1 set extcommunity bandwidth-non-transitive", + "set policy route-map test2 rule 1 set atomic-aggregate", + "set policy route-map test2 rule 1 set aggregator as 245", + "set policy route-map test2 rule 1 set aggregator ip 10.20.11.22", + "set policy route-map test2 rule 1 match interface eth2", + "set policy route-map test2 rule 1 match metric 1", + "set policy route-map test2 rule 1 match peer 1.1.1.3", + "set policy route-map test2 rule 1 match ipv6 nexthop fdda:5cc1:23:4::1f", + "set policy route-map test2 rule 1 match rpki invalid", + "set policy route-map test2 rule 1 match protocol bgp", + "set policy route-map test2 rule 1 match community community-list 235", + "set policy route-map test2 rule 1 continue 2", + ] + + self.execute_module(changed=True, commands=commands) + + def test_route_maps_replaced(self): + set_module_args( + dict( + config=[ + dict( + route_map="test3", + entries=[ + dict( + sequence=1, + action="permit", + match=dict( + rpki="invalid", + metric=1, + peer="1.1.1.3", + ipv6=dict(next_hop="fdda:5cc1:23:4::1f"), + ), + set=dict( + ipv6_next_hop=dict( + ip_type="global", + value="fdda:5cc1:23:4::1f", + ), + community=dict(value="100:100"), + bgp_extcommunity_rt="22:11", + ip_next_hop="10.20.10.22", + large_community="10:20:21", + local_preference=4, + metric=5, + metric_type="type-2", + origin="egp", + originator_id="10.0.2.2", + src="fdda:5cc1:23:4::12", + tag=4, + weight=4, ), ), ], ), ], state="replaced", ), ) commands = [ "delete policy route-map test3 rule 1 match interface eth2", "set policy route-map test3 rule 1 set ip-next-hop 10.20.10.22", - "set policy route-map test3 rule 1 set large-community 10:20:21", + "set policy route-map test3 rule 1 set community replace 100:100", + "set policy route-map test3 rule 1 set large-community replace 10:20:21", "set policy route-map test3 rule 1 set metric-type type-2", "set policy route-map test3 rule 1 set originator-id 10.0.2.2", "set policy route-map test3 rule 1 set tag 4", + "set policy route-map test3 rule 1 set src fdda:5cc1:23:4::12", "set policy route-map test3 rule 1 match peer 1.1.1.3", ] self.execute_module(changed=True, commands=commands) def test_vyos_route_maps_replaced_idempotent(self): set_module_args( dict( config=[ dict( route_map="test3", entries=[ dict( sequence=1, action="permit", match=dict( rpki="invalid", interface="eth2", metric=1, peer="1.1.1.2", ipv6=dict(next_hop="fdda:5cc1:23:4::1f"), ), set=dict( ipv6_next_hop=dict( ip_type="global", value="fdda:5cc1:23:4::1f", ), community=dict(value="internet"), bgp_extcommunity_rt="22:11", ip_next_hop="10.20.10.20", local_preference=4, metric=5, metric_type="type-1", origin="egp", originator_id="10.0.2.3", src="10.0.2.15", tag=5, weight=4, ), ), ], ), ], state="replaced", ), ) self.execute_module(changed=False, commands=[]) def test_route_maps_overridden(self): set_module_args( dict( config=[ dict( route_map="test2", entries=[ dict( sequence=1, action="permit", match=dict(rpki="invalid", peer="1.1.1.3"), set=dict( ipv6_next_hop=dict( ip_type="global", value="fdda:5cc1:23:4::1f", ), community=dict(value="internet"), bgp_extcommunity_rt="22:11", ip_next_hop="10.20.10.22", large_community="10:20:21", local_preference=4, metric=5, metric_type="type-2", origin="egp", originator_id="10.0.2.2", src="10.0.2.15", tag=4, weight=4, ), ), ], ), ], state="overridden", ), ) commands = [ "delete policy route-map test3", "set policy route-map test2 rule 1 action permit", "set policy route-map test2 rule 1 set bgp-extcommunity-rt 22:11", "set policy route-map test2 rule 1 set ip-next-hop 10.20.10.22", "set policy route-map test2 rule 1 set ipv6-next-hop global fdda:5cc1:23:4::1f", - "set policy route-map test2 rule 1 set large-community 10:20:21", + "set policy route-map test2 rule 1 set large-community replace 10:20:21", "set policy route-map test2 rule 1 set local-preference 4", "set policy route-map test2 rule 1 set metric 5", "set policy route-map test2 rule 1 set metric-type type-2", "set policy route-map test2 rule 1 set origin egp", "set policy route-map test2 rule 1 set originator-id 10.0.2.2", "set policy route-map test2 rule 1 set src 10.0.2.15", "set policy route-map test2 rule 1 set tag 4", "set policy route-map test2 rule 1 set weight 4", - "set policy route-map test2 rule 1 set community internet", + "set policy route-map test2 rule 1 set community replace internet", "set policy route-map test2 rule 1 match peer 1.1.1.3", "set policy route-map test2 rule 1 match rpki invalid", ] self.execute_module(changed=True, commands=commands) + def test_route_maps__deny_overridden(self): + set_module_args( + dict( + config=[ + dict( + route_map="test2", + entries=[ + dict( + sequence=1, + action="deny", + match=dict(rpki="invalid", peer="1.1.1.5"), + ), + ], + ), + ], + state="overridden", + ), + ) + commands = [ + "delete policy route-map test3", + "set policy route-map test2 rule 1 action deny", + "set policy route-map test2 rule 1 match peer 1.1.1.5", + "set policy route-map test2 rule 1 match rpki invalid", + ] + self.execute_module(changed=True, commands=commands) + def test_vyos_route_maps_overridden_idempotent(self): set_module_args( dict( config=[ dict( route_map="test3", entries=[ dict( sequence=1, action="permit", match=dict( rpki="invalid", interface="eth2", metric=1, peer="1.1.1.2", ipv6=dict(next_hop="fdda:5cc1:23:4::1f"), ), set=dict( ipv6_next_hop=dict( ip_type="global", value="fdda:5cc1:23:4::1f", ), community=dict(value="internet"), bgp_extcommunity_rt="22:11", ip_next_hop="10.20.10.20", local_preference=4, metric=5, metric_type="type-1", origin="egp", originator_id="10.0.2.3", src="10.0.2.15", tag=5, weight=4, ), ), ], ), ], state="overridden", ), ) self.execute_module(changed=False, commands=[]) def test_vyos_route_maps_rendered(self): set_module_args( dict( config=[ dict( route_map="test3", entries=[ dict( sequence=1, action="permit", match=dict( rpki="invalid", interface="eth2", metric=1, peer="1.1.1.2", ipv6=dict(next_hop="fdda:5cc1:23:4::1f"), ), set=dict( ipv6_next_hop=dict( ip_type="global", value="fdda:5cc1:23:4::1f", ), community=dict(value="internet"), bgp_extcommunity_rt="22:11", ip_next_hop="10.20.10.20", local_preference=4, metric=5, metric_type="type-1", origin="egp", originator_id="10.0.2.3", src="10.0.2.15", tag=5, weight=4, ), ), ], ), dict( route_map="test1", entries=[ dict( sequence=1, action="permit", description="test", on_match=dict(next=True), ), dict( sequence=2, action="permit", on_match=dict(goto=4), ), ], ), ], state="rendered", ), ) rendered_cmds = [ "set policy route-map test3 rule 1 action permit", "set policy route-map test3 rule 1 set bgp-extcommunity-rt 22:11", "set policy route-map test3 rule 1 set ip-next-hop 10.20.10.20", "set policy route-map test3 rule 1 set ipv6-next-hop global fdda:5cc1:23:4::1f", "set policy route-map test3 rule 1 set local-preference 4", "set policy route-map test3 rule 1 set metric 5", "set policy route-map test3 rule 1 set metric-type type-1", "set policy route-map test3 rule 1 set origin egp", "set policy route-map test3 rule 1 set originator-id 10.0.2.3", "set policy route-map test3 rule 1 set src 10.0.2.15", "set policy route-map test3 rule 1 set tag 5", "set policy route-map test3 rule 1 set weight 4", - "set policy route-map test3 rule 1 set community internet", + "set policy route-map test3 rule 1 set community replace internet", "set policy route-map test3 rule 1 match interface eth2", "set policy route-map test3 rule 1 match metric 1", "set policy route-map test3 rule 1 match peer 1.1.1.2", "set policy route-map test3 rule 1 match ipv6 nexthop fdda:5cc1:23:4::1f", "set policy route-map test3 rule 1 match rpki invalid", "set policy route-map test1 rule 1 description test", "set policy route-map test1 rule 1 action permit", "set policy route-map test1 rule 1 on-match next", "set policy route-map test1 rule 2 action permit", "set policy route-map test1 rule 2 on-match goto 4", ] result = self.execute_module(changed=False) self.assertEqual( sorted(result["rendered"]), sorted(rendered_cmds), result["rendered"], ) def test_yos_route_maps_parsed(self): parsed_str = ( "set policy route-map test3 rule 1 action 'permit'" "\nset policy route-map test3 rule 1 match interface 'eth2'\nset policy route-map test3 rule 1 match ipv6 nexthop" " 'fdda:5cc1:23:4::1f'\nset policy route-map test3 rule 1 match metric '1'\nset policy route-map test3 rule 1 match peer " "'1.1.1.2'\nset policy route-map test3 rule 1 match rpki 'invalid'\nset policy route-map test3 rule 1 set bgp-extcommunity-rt " - "'22:11'\nset policy route-map test3 rule 1 set community 'internet'\nset policy route-map test3 rule 1 set ipv6-next-hop global" + "'22:11'\nset policy route-map test3 rule 1 set community replace 'internet'\nset policy route-map test3 rule 1 set ipv6-next-hop global" " 'fdda:5cc1:23:4::1f'\nset policy route-map test3 rule 1 set ip-next-hop '10.20.10.20'\nset policy route-map " "test3 rule 1 set local-preference '4'\nset policy route-map test3 rule 1 set metric '5'\nset policy route-map test3 " "rule 1 set metric-type 'type-1'\nset policy route-map test3 rule 1 set origin 'egp'\nset policy route-map test3 rule 1 set originator-id " "'10.0.2.3'\nset policy route-map test3 rule 1 set src '10.0.2.15'" "\nset policy route-map test3 rule 1 set tag '5'\nset policy route-map test3 rule 1 set weight '4'" ) set_module_args(dict(running_config=parsed_str, state="parsed")) result = self.execute_module(changed=False) parsed_list = [ { "entries": [ { "action": "permit", "match": { "interface": "eth2", "ipv6": {"next_hop": "fdda:5cc1:23:4::1f"}, "metric": 1, "peer": "1.1.1.2", "rpki": "invalid", }, "sequence": 1, "set": { "bgp_extcommunity_rt": "22:11", "community": {"value": "internet"}, "ip_next_hop": "10.20.10.20", "ipv6_next_hop": { "ip_type": "global", "value": "fdda:5cc1:23:4::1f", }, "local_preference": "4", "metric": "5", "metric_type": "type-1", "origin": "egp", "originator_id": "10.0.2.3", "src": "10.0.2.15", "tag": "5", "weight": "4", }, }, ], "route_map": "test3", }, ] self.assertEqual(parsed_list, result["parsed"]) def test_vyos_route_maps_gathered(self): set_module_args(dict(state="gathered")) result = self.execute_module(changed=False) gathered_list = [ { "entries": [ { "action": "permit", "match": { "interface": "eth2", "ipv6": {"next_hop": "fdda:5cc1:23:4::1f"}, "metric": 1, "peer": "1.1.1.2", "rpki": "invalid", }, "sequence": 1, "set": { "bgp_extcommunity_rt": "22:11", "community": {"value": "internet"}, "ip_next_hop": "10.20.10.20", "ipv6_next_hop": { "ip_type": "global", "value": "fdda:5cc1:23:4::1f", }, "local_preference": "4", "metric": "5", "metric_type": "type-1", "origin": "egp", "originator_id": "10.0.2.3", "src": "10.0.2.15", "tag": "5", "weight": "4", }, }, ], "route_map": "test3", }, ] self.assertEqual(gathered_list, result["gathered"]) def test_vyos_route_maps_deleted(self): set_module_args( dict( config=[ dict( route_map="test3", entries=[ dict( sequence=1, action="permit", match=dict( rpki="invalid", interface="eth2", ), set=dict( origin="egp", originator_id="10.0.2.3", src="10.0.2.15", tag=5, weight=4, ), ), ], ), ], state="deleted", ), ) commands = ["delete policy route-map test3"] self.execute_module(changed=True, commands=commands)