From a8e5dac21090e9b0ddf876214a9a1522079ecde1 Mon Sep 17 00:00:00 2001
From: omnom62 <75066712+omnom62@users.noreply.github.com>
Date: Wed, 4 Mar 2026 19:51:16 +1000
Subject: T6836 VRF module (#408)
* t6836 vfr module init
* argspec facts module for VRF
* T6834 static_route module to support interface_route (#398)
* t6834 init
* facts fixes, WIP
* T6834 - facts updates
* static_routes 1.3- config, facts, args and sanit and unit tests
* changelog
* changelog updates
* static_routes 1.4+
* static_routes v1.4 unit tests
* comment removed
* T6829 (area interfaces in OSPFv3 1.3-1.5) re-init (#399)
* T6829 re-init
* re-init T6829 ospfv3 area interface for 1.3-
* changelog
* changelog fix
* Doc is updated
* adding 1.4+ support
* ospfv3 area interfaces for 1.4+
* fixed ospfv3 facts and added area interface unit test for 1.4
* ospfv3 clean-up
* doc updates
* Resolve merge conflicts
* vrf parsers set_table
* more vrf paresers added
* vrf facts main code
* vrf data structures
* simple vrf config push
* simple vrf config push
* some work on vrf
* basic facts done
* vrf instance parsers wif
* ongoing parser testing
* vrf dev work
* testing with paresers
* all basic settings
* merged for vrf
* more states for VRF
* vrf deleted, overriden
* overriden
* sanity
* rst for vrf
* changelog
* fix changelog
* doc fix
* vrf delete idempotent
* deleted and overridden for VFR
* overriden
* overriden vrf idempotency
* asdvanced vrf settings
* afi for VRF facts
* VRF AFI config
* VRF AFI tests
* vrf dev work
* afi dev work
* afi and deep_merge fixes for VRF
* afi basic provisioning
* changelog
* vrf sanity fixes
* VRF AFI protocols and route-maps
* vrf parsed, gathered, rendered fixes
* docstrings VRF
* docstrings VRF
* docstring VRF
* module doc update
* vrf module examples
* VRF doc examples
* linter
* VRF unit tests init
* VRF unit tests init
* VRF unit tests updates
* fixed VRF overridden and deleted unit test cases
* VRF integration tests init
* VRF int tests rtt, merged, replaced
* VRF int testt gathered, rendered
* VRF int tests deleted, rendered, overridden and empty_config
* linter
* VRF int test misc fixes
* VRF global idepmotency
* fixing py3.13 runner deps
* fixing lint
* fixing sanity
* reverting previous fixes
* VRF protocols load_module and provisioning flow
* fixes to bgp VRF protocol methods
* VRF protocol facts init
* VRF protocol load_module works
* reworked VRF load_module routine
* vrf protocl static fixed
* Fixed static and ospf VRF protocol provisioning
* Fixed static and ospf VRF protocol provisioning
* VRF doc update
* VRF docs update
* VRF doc updates
* unit tests for VRF protocols
* VRF BGP protcol sanity check
* VRF protocol fixed sanity checks (DOCUMENTATION)
* sanity and doc for VRF fixed
* VRF unit tests mock
* VRF protocol integration parsed, rtt and merged init
* VRF protocols - rendered, overridden
* VRF protocols replaced
* fix accidental changes to test_vyos_config.py
* PR description
* fix image
* README fix
* Fixing linter
* Mid-result UAT overriden VRF
* Mid-result for VRF UAT
* VRF uat
* VRF obsolete features removed
---
PR408_README.md | 163 +
README.md | 1 +
changelogs/fragments/t6838_vrf.yml | 3 +
docs/vyos.vyos.vyos_config_module.rst | 41 +
docs/vyos.vyos.vyos_vrf_module.rst | 5087 ++++++++++++++++++++
meta/runtime.yml | 2 +
plugins/action/vrf.py | 1 +
.../network/vyos/argspec/vrf/__init__.py | 0
.../module_utils/network/vyos/argspec/vrf/vrf.py | 131 +
.../network/vyos/config/vrf/__init__.py | 0
.../module_utils/network/vyos/config/vrf/vrf.old | 313 ++
.../module_utils/network/vyos/config/vrf/vrf.py | 308 ++
plugins/module_utils/network/vyos/facts/facts.py | 2 +
.../network/vyos/facts/vrf/__init__.py | 0
plugins/module_utils/network/vyos/facts/vrf/vrf.py | 227 +
.../module_utils/network/vyos/rm_templates/vrf.py | 249 +
plugins/module_utils/network/vyos/utils/utils.py | 22 +
plugins/modules/vyos_vrf.py | 1545 ++++++
pr408-diagram.png | Bin 0 -> 161529 bytes
.../targets/vyos_vrf/defaults/main.yaml | 3 +
tests/integration/targets/vyos_vrf/tasks/cli.yaml | 20 +
tests/integration/targets/vyos_vrf/tasks/main.yaml | 5 +
.../targets/vyos_vrf/tests/cli/_add_rm.yaml | 12 +
.../targets/vyos_vrf/tests/cli/_parsed.cfg | 34 +
.../targets/vyos_vrf/tests/cli/_populate.yaml | 10 +
.../targets/vyos_vrf/tests/cli/_remove_config.yaml | 9 +
.../targets/vyos_vrf/tests/cli/_remove_rm.yaml | 0
.../targets/vyos_vrf/tests/cli/deleted.yaml | 34 +
.../targets/vyos_vrf/tests/cli/empty_config.yaml | 60 +
.../targets/vyos_vrf/tests/cli/gathered.yaml | 22 +
.../targets/vyos_vrf/tests/cli/merged.yaml | 54 +
.../targets/vyos_vrf/tests/cli/overridden.yaml | 49 +
.../targets/vyos_vrf/tests/cli/parsed.yaml | 16 +
.../targets/vyos_vrf/tests/cli/rendered.yaml | 133 +
.../targets/vyos_vrf/tests/cli/replaced.yaml | 56 +
.../targets/vyos_vrf/tests/cli/rtt.yaml | 69 +
tests/integration/targets/vyos_vrf/vars/main.yaml | 278 ++
.../network/vyos/fixtures/vyos_vrf_config.cfg | 15 +
tests/unit/modules/network/vyos/test_vyos_vrf.py | 689 +++
39 files changed, 9663 insertions(+)
create mode 100644 PR408_README.md
create mode 100644 changelogs/fragments/t6838_vrf.yml
create mode 100644 docs/vyos.vyos.vyos_vrf_module.rst
create mode 120000 plugins/action/vrf.py
create mode 100644 plugins/module_utils/network/vyos/argspec/vrf/__init__.py
create mode 100644 plugins/module_utils/network/vyos/argspec/vrf/vrf.py
create mode 100644 plugins/module_utils/network/vyos/config/vrf/__init__.py
create mode 100644 plugins/module_utils/network/vyos/config/vrf/vrf.old
create mode 100644 plugins/module_utils/network/vyos/config/vrf/vrf.py
create mode 100644 plugins/module_utils/network/vyos/facts/vrf/__init__.py
create mode 100644 plugins/module_utils/network/vyos/facts/vrf/vrf.py
create mode 100644 plugins/module_utils/network/vyos/rm_templates/vrf.py
create mode 100644 plugins/modules/vyos_vrf.py
create mode 100644 pr408-diagram.png
create mode 100644 tests/integration/targets/vyos_vrf/defaults/main.yaml
create mode 100644 tests/integration/targets/vyos_vrf/tasks/cli.yaml
create mode 100644 tests/integration/targets/vyos_vrf/tasks/main.yaml
create mode 100644 tests/integration/targets/vyos_vrf/tests/cli/_add_rm.yaml
create mode 100644 tests/integration/targets/vyos_vrf/tests/cli/_parsed.cfg
create mode 100644 tests/integration/targets/vyos_vrf/tests/cli/_populate.yaml
create mode 100644 tests/integration/targets/vyos_vrf/tests/cli/_remove_config.yaml
create mode 100644 tests/integration/targets/vyos_vrf/tests/cli/_remove_rm.yaml
create mode 100644 tests/integration/targets/vyos_vrf/tests/cli/deleted.yaml
create mode 100644 tests/integration/targets/vyos_vrf/tests/cli/empty_config.yaml
create mode 100644 tests/integration/targets/vyos_vrf/tests/cli/gathered.yaml
create mode 100644 tests/integration/targets/vyos_vrf/tests/cli/merged.yaml
create mode 100644 tests/integration/targets/vyos_vrf/tests/cli/overridden.yaml
create mode 100644 tests/integration/targets/vyos_vrf/tests/cli/parsed.yaml
create mode 100644 tests/integration/targets/vyos_vrf/tests/cli/rendered.yaml
create mode 100644 tests/integration/targets/vyos_vrf/tests/cli/replaced.yaml
create mode 100644 tests/integration/targets/vyos_vrf/tests/cli/rtt.yaml
create mode 100644 tests/integration/targets/vyos_vrf/vars/main.yaml
create mode 100644 tests/unit/modules/network/vyos/fixtures/vyos_vrf_config.cfg
create mode 100644 tests/unit/modules/network/vyos/test_vyos_vrf.py
diff --git a/PR408_README.md b/PR408_README.md
new file mode 100644
index 00000000..0423b56f
--- /dev/null
+++ b/PR408_README.md
@@ -0,0 +1,163 @@
+# ๐ฆ Pull Request Documentation
+
+## ๐งพ Summary
+
+
+
+This is a new Ansible module to manage VyOS VRF configuration as requested by https://vyos.dev/T6836
+
+---
+
+## ๐ Implementation
+
+
+
+The module implements a set of VyOS 1.4.2 and 1.5.x commands related to VRF configuration, described in https://docs.vyos.io/en/1.4/configuration/vrf/index.html
+The module allows to configure a global attribute (bind-all), as well as, VRF instance configuration.
+
+The structure of the parameters is depicted below
+
+
+The module supports the following states:
+
+- "deleted"
+- "merged"
+- "replaced"
+- "overridden"
+- "gathered"
+- "rendered"
+- "parsed"
+
+---
+
+## ๐ Examples
+
+### Replaced (to demo individual attribute processing)
+
+Initial coonfiguration
+
+```
+ - set vrf bind-to-all
+ - set vrf name vrf-blue description 'blue-vrf'
+ - set vrf name vrf-blue table '100'
+ - set vrf name vrf-blue vni '1000'
+ - set vrf name vrf-red description 'red-vrf'
+ - set vrf name vrf-red disable
+ - set vrf name vrf-red ip disable-forwarding
+ - set vrf name vrf-red ip protocol kernel route-map 'rm1'
+ - set vrf name vrf-red ip protocol rip route-map 'rm1'
+ - set vrf name vrf-red ipv6 nht no-resolve-via-default
+ - set vrf name vrf-red table '101'
+ - set vrf name vrf-red vni '1001'
+ - set vrf name vrf-pink table 111
+ - set vrf name vrf-pink vni 1111
+ - set vrf name vrf-pink description pink-vrf
+ - set vrf name vrf-pink protocols bgp system-as 65000
+ - set vrf name vrf-pink protocols bgp neighbor 192.0.2.1 remote-as 65002
+ - set vrf name vrf-pink protocols bgp neighbor 1.1.1.3 passive
+ - set vrf name vrf-pink protocols bgp neighbor 1.1.1.3 remote-as 400
+ - set vrf name vrf-pink protocols ospf log-adjacency-changes 'detail'
+ - set vrf name vrf-pink protocols ospf max-metric router-lsa administrative
+ - set vrf name vrf-pink protocols ospf max-metric router-lsa on-shutdown 10
+ - set vrf name vrf-pink protocols ospf max-metric router-lsa on-startup 10
+ - set vrf name vrf-pink protocols ospf default-information originate always
+ - set vrf name vrf-pink protocols ospf default-information originate metric 10
+ - set vrf name vrf-pink protocols ospf default-information originate metric-type 2
+ - set vrf name vrf-pink protocols ospf mpls-te router-address '192.0.11.12'
+ - set vrf name vrf-pink protocols ospf auto-cost reference-bandwidth '2'
+ - set vrf name vrf-pink protocols ospf neighbor 192.0.11.12
+ - set vrf name vrf-pink protocols ospf neighbor 192.0.11.12 poll-interval 10
+ - set vrf name vrf-pink protocols ospf neighbor 192.0.11.12 priority 2
+ - set vrf name vrf-pink protocols ospf redistribute bgp
+ - set vrf name vrf-pink protocols ospf redistribute bgp metric 10
+ - set vrf name vrf-pink protocols ospf redistribute bgp metric-type 2
+ - set vrf name vrf-pink protocols ospf parameters router-id '192.0.1.1'
+ - set vrf name vrf-pink protocols ospf parameters rfc1583-compatibility
+ - set vrf name vrf-pink protocols ospf parameters abr-type 'cisco'
+ - set vrf name vrf-pink protocols ospf area '2'
+ - set vrf name vrf-pink protocols ospf area 2 area-type normal
+ - set vrf name vrf-pink protocols ospf area 2 authentication plaintext-password
+ - set vrf name vrf-pink protocols ospf area 2 shortcut enable
+ - set vrf name vrf-pink protocols ospf area '3'
+ - set vrf name vrf-pink protocols ospf area 3 area-type nssa
+ - set vrf name vrf-pink protocols ospf area '4'
+ - set vrf name vrf-pink protocols ospf area 4 area-type stub default-cost 20
+ - set vrf name vrf-pink protocols ospf area 4 network 192.0.2.0/24
+ - set vrf name vrf-pink protocols ospf area 4 range 192.0.3.0/24
+ - set vrf name vrf-pink protocols ospf area 4 range 192.0.3.0/24 cost 10
+ - set vrf name vrf-pink protocols ospf area 4 range 192.0.4.0/24
+ - set vrf name vrf-pink protocols ospf area 4 range 192.0.4.0/24 cost 12
+ - set vrf name vrf-pink protocols ospfv3 area '2'
+ - set vrf name vrf-pink protocols ospfv3 area 2 export-list export1
+ - set vrf name vrf-pink protocols ospfv3 area 2 import-list import1
+ - set vrf name vrf-pink protocols ospfv3 area 2 range 2001:db10::/32
+ - set vrf name vrf-pink protocols ospfv3 area 2 range 2001:db20::/32
+ - set vrf name vrf-pink protocols ospfv3 area 2 range 2001:db30::/32
+ - set vrf name vrf-pink protocols ospfv3 area '3'
+ - set vrf name vrf-pink protocols ospfv3 area 3 range 2001:db40::/32
+ - set vrf name vrf-pink protocols ospfv3 parameters router-id '192.0.2.10'
+ - set vrf name vrf-pink protocols ospfv3 redistribute bgp
+ - set vrf name vrf-pink protocols static route 192.0.2.0/24
+ - set vrf name vrf-pink protocols static route 192.0.2.0/24 blackhole distance '10'
+ - set vrf name vrf-pink protocols static route 192.0.2.0/24 next-hop '203.0.113.1'
+ - set vrf name vrf-pink protocols static route 192.0.2.0/24 next-hop '203.0.113.2'
+ - set vrf name vrf-pink protocols static route6 2001:db8::/32
+ - set vrf name vrf-pink protocols static route6 2001:db8::/32 blackhole distance '20'
+ - set vrf name vrf-pink protocols static route6 2001:db8::/32 next-hop '2001:db8::1'
+```
+
+Module configuration
+
+```yaml
+vyos.vyos.vyos_vrf:
+ config:
+ instances:
+ - name: "vrf-blue"
+ description: "blue-vrf"
+ disable: true
+ table_id: 100
+ vni: 1000
+ - name: "vrf-red"
+ description: "Vermillion_VRF"
+ disable: false
+ table_id: 101
+ vni: 1011
+ address_family:
+ - afi: "ipv6"
+ nht_no_resolve_via_default: false
+ - name: "vrf-pink"
+ table_id: 111
+ protocols:
+ ospf:
+ default_information:
+ originate:
+ always: true
+ metric: 20
+ metric_type: 1
+ state: replaced
+```
+
+Will result in
+
+````
+- delete vrf bind-to-all
+- set vrf name vrf-blue disable
+- set vrf name vrf-red vni 1011
+- set vrf name vrf-red description Vermillion_VRF
+- delete vrf name vrf-red disable
+- delete vrf name vrf-red ipv6 nht no-resolve-via-default
+- delete vrf name vrf-pink vni 1111
+- delete vrf name vrf-pink description pink-vrf
+- delete vrf name vrf-pink protocols ospf log-adjacency-changes 'detail'
+- delete vrf name vrf-pink protocols ospf auto-cost
+- delete vrf name vrf-pink protocols ospf max-metric
+- delete vrf name vrf-pink protocols ospf mpls-te
+- delete vrf name vrf-pink protocols ospf area
+- delete vrf name vrf-pink protocols ospf parameters
+- delete vrf name vrf-pink protocols ospf neighbor
+- delete vrf name vrf-pink protocols ospf redistribute
+- set vrf name vrf-pink protocols ospf default-information originate metric 20
+- set vrf name vrf-pink protocols ospf default-information originate metric-type 1
+```
+---
+````
diff --git a/README.md b/README.md
index df9d916e..c453038b 100644
--- a/README.md
+++ b/README.md
@@ -70,6 +70,7 @@ Name | Description
[vyos.vyos.vyos_system](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_system_module.rst)|Run `set system` commands on VyOS devices
[vyos.vyos.vyos_user](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_user_module.rst)|Manage the collection of local users on VyOS device
[vyos.vyos.vyos_vlan](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_vlan_module.rst)|Manage VLANs on VyOS network devices
+[vyos.vyos.vyos_vrf](https://github.com/vyos/vyos.vyos/blob/main/docs/vyos.vyos.vyos_vrf_module.rst)|VRF resource module
diff --git a/changelogs/fragments/t6838_vrf.yml b/changelogs/fragments/t6838_vrf.yml
new file mode 100644
index 00000000..9483e466
--- /dev/null
+++ b/changelogs/fragments/t6838_vrf.yml
@@ -0,0 +1,3 @@
+---
+minor_changes:
+ - vyos_vrf - Add VRF support
diff --git a/docs/vyos.vyos.vyos_config_module.rst b/docs/vyos.vyos.vyos_config_module.rst
index 1efbd38f..e2be25b9 100644
--- a/docs/vyos.vyos.vyos_config_module.rst
+++ b/docs/vyos.vyos.vyos_config_module.rst
@@ -131,6 +131,42 @@ Parameters
@@ -236,6 +272,11 @@ Examples
vyos.vyos.vyos_config:
src: vyos_template.j2
+ - name: revert after ten minutes, if connection is lost
+ vyos.vyos.vyos_config:
+ src: vyos_template.j2
+ confirm: automatic
+
- name: for idempotency, use full-form commands
vyos.vyos.vyos_config:
lines:
diff --git a/docs/vyos.vyos.vyos_vrf_module.rst b/docs/vyos.vyos.vyos_vrf_module.rst
new file mode 100644
index 00000000..a3fad8a3
--- /dev/null
+++ b/docs/vyos.vyos.vyos_vrf_module.rst
@@ -0,0 +1,5087 @@
+.. _vyos.vyos.vyos_vrf_module:
+
+
+******************
+vyos.vyos.vyos_vrf
+******************
+
+**VRF resource module**
+
+
+Version added: 1.0.0
+
+.. contents::
+ :local:
+ :depth: 1
+
+
+Synopsis
+--------
+- This module manages vrf configuration on devices running Vyos
+
+
+
+
+Parameters
+----------
+
+.. raw:: html
+
+
+
+ | Parameter |
+ Choices/Defaults |
+ Comments |
+
+
+ |
+
+ config
+
+
+ dictionary
+
+ |
+
+ |
+
+ List of vrf configuration.
+ |
+
+
+ |
+
+
+ bind_to_all
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Enable binding services to all VRFs
+ |
+
+
+ |
+
+
+ instances
+
+
+ list
+ / elements=dictionary
+
+ |
+
+ |
+
+ Virtual Routing and Forwarding instance
+ |
+
+
+ |
+ |
+
+
+ address_family
+
+
+ list
+ / elements=dictionary
+
+ |
+
+ |
+
+ Address family configuration
+ |
+
+
+ |
+ |
+ |
+
+
+ afi
+
+
+ string
+
+ |
+
+
+ |
+
+ Address family identifier
+ |
+
+
+ |
+ |
+ |
+
+
+ disable_forwarding
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Disable forwarding for this address family
+ |
+
+
+ |
+ |
+ |
+
+
+ nht_no_resolve_via_default
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Disable next-hop resolution via default route
+ |
+
+
+ |
+ |
+ |
+
+
+ route_maps
+
+
+ list
+ / elements=dictionary
+
+ |
+
+ |
+
+ List of route maps for this address family
+ |
+
+
+ |
+ |
+ |
+ |
+
+
+ protocol
+
+
+ string
+
+ |
+
+ Choices:
+ - any
+ - babel
+ - bgp
+ - eigrp
+ - isis
+ - ospf
+ - rip
+ - static
+
+ |
+
+ Protocol to which the route map applies
+ |
+
+
+ |
+ |
+ |
+ |
+
+
+ rm_name
+
+
+ string
+ / required
+
+ |
+
+ |
+
+ Route map name
+ |
+
+
+
+
+ |
+ |
+
+
+ description
+
+
+ string
+
+ |
+
+ |
+
+ Description
+ |
+
+
+ |
+ |
+
+
+ disable
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Administratively disable interface
+ aliases: disabled
+ |
+
+
+ |
+ |
+
+
+ name
+
+
+ string
+ / required
+
+ |
+
+ |
+
+ VRF instance name
+ |
+
+
+ |
+ |
+
+
+ protocols
+
+
+ dictionary
+
+ |
+
+ |
+
+ Protocol configuration
+ |
+
+
+ |
+ |
+ |
+
+
+ bgp
+
+
+ dictionary
+
+ |
+
+ |
+
+ BGP configuration
+ |
+
+
+ |
+ |
+ |
+ |
+
+
+ as_number
+
+
+ integer
+
+ |
+
+ |
+
+ AS number.
+ |
+
+
+ |
+ |
+ |
+ |
+
+
+ bgp_params
+
+
+ dictionary
+
+ |
+
+ |
+
+ BGP parameters
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ always_compare_med
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Always compare MEDs from different neighbors
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ bestpath
+
+
+ dictionary
+
+ |
+
+ |
+
+ Default bestpath selection mechanism
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ as_path
+
+
+ string
+
+ |
+
+ Choices:
+ - confed
+ - ignore
+
+ |
+
+ AS-path attribute comparison parameters
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ compare_routerid
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Compare the router-id for identical EBGP paths
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ med
+
+
+ string
+
+ |
+
+ Choices:
+ - confed
+ - missing-as-worst
+
+ |
+
+ MED attribute comparison parameters
+ |
+
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ cluster_id
+
+
+ string
+
+ |
+
+ |
+
+ Route-reflector cluster-id
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ confederation
+
+
+ list
+ / elements=dictionary
+
+ |
+
+ |
+
+ AS confederation parameters
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ identifier
+
+
+ integer
+
+ |
+
+ |
+
+ Confederation AS identifier
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ peers
+
+
+ integer
+
+ |
+
+ |
+
+ Peer ASs in the BGP confederation
+ |
+
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ dampening
+
+
+ dictionary
+
+ |
+
+ |
+
+ Enable route-flap dampening
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ half_life
+
+
+ integer
+
+ |
+
+ |
+
+ Half-life penalty in seconds
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ max_suppress_time
+
+
+ integer
+
+ |
+
+ |
+
+ Maximum duration to suppress a stable route
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ re_use
+
+
+ integer
+
+ |
+
+ |
+
+ Time to start reusing a route
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ start_suppress_time
+
+
+ integer
+
+ |
+
+ |
+
+ When to start suppressing a route
+ |
+
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ default
+
+
+ dictionary
+
+ |
+
+ |
+
+ BGP defaults
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ local_pref
+
+
+ integer
+
+ |
+
+ |
+
+ Default local preference
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ no_ipv4_unicast
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Deactivate IPv4 unicast for a peer by default
+ Deprecated: Unavailable after 1.4
+ |
+
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ deterministic_med
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Compare MEDs between different peers in the same AS
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ disable_network_import_check
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Disable IGP route check for network statements
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ distance
+
+
+ list
+ / elements=dictionary
+
+ |
+
+ |
+
+ Administrative distances for BGP routes
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ prefix
+
+
+ integer
+
+ |
+
+ |
+
+ Administrative distance for a specific BGP prefix
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ type
+
+
+ string
+
+ |
+
+ Choices:
+ - external
+ - internal
+ - local
+
+ |
+
+ Type of route
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ value
+
+
+ integer
+
+ |
+
+ |
+
+ distance
+ |
+
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ enforce_first_as
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Require first AS in the path to match peer's AS
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ graceful_restart
+
+
+ integer
+
+ |
+
+ |
+
+ Maximum time to hold onto restarting peer's stale paths
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ log_neighbor_changes
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Log neighbor up/down changes and reset reason
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ no_client_to_client_reflection
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Disable client to client route reflection
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ no_fast_external_failover
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Disable immediate session reset if peer's connected link goes down
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ router_id
+
+
+ string
+
+ |
+
+ |
+
+ BGP router-id
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ scan_time
+
+
+ integer
+
+ |
+
+ |
+
+ BGP route scanner interval
+ |
+
+
+
+ |
+ |
+ |
+ |
+
+
+ neighbor
+
+
+ list
+ / elements=dictionary
+
+ |
+
+ |
+
+ BGP neighbor
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ address
+
+
+ string
+
+ |
+
+ |
+
+ BGP neighbor address (v4/v6).
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ advertisement_interval
+
+
+ integer
+
+ |
+
+ |
+
+ Minimum interval for sending routing updates.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ capability
+
+
+ dictionary
+
+ |
+
+ |
+
+ Advertise capabilities to this neighbor.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ dynamic
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Advertise dynamic capability to this neighbor.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ extended_nexthop
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Advertise extended nexthop capability to this neighbor.
+ |
+
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ default_originate
+
+
+ string
+
+ |
+
+ |
+
+ Send default route to this neighbor
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ description
+
+
+ string
+
+ |
+
+ |
+
+ Description of the neighbor
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ disable_capability_negotiation
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Disbale capability negotiation with the neighbor
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ disable_connected_check
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Disable check to see if EBGP peer's address is a connected route.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ disable_send_community
+
+
+ string
+
+ |
+
+ Choices:
+ - extended
+ - standard
+
+ |
+
+ Disable sending community attributes to this neighbor.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ ebgp_multihop
+
+
+ integer
+
+ |
+
+ |
+
+ Allow this EBGP neighbor to not be on a directly connected network. Specify the number hops.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ local_as
+
+
+ integer
+
+ |
+
+ |
+
+ local as number not to be prepended to updates from EBGP peers
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ override_capability
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Ignore capability negotiation with specified neighbor.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ passive
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Do not initiate a session with this neighbor
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ password
+
+
+ string
+
+ |
+
+ |
+
+ BGP MD5 password
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ peer_group
+
+
+ boolean
+
+ |
+
+
+ |
+
+ True if all the configs under this neighbor key is for peer group template.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ peer_group_name
+
+
+ string
+
+ |
+
+ |
+
+ IPv4 peer group for this peer
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ port
+
+
+ integer
+
+ |
+
+ |
+
+ Neighbor's BGP port
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ remote_as
+
+
+ integer
+
+ |
+
+ |
+
+ Neighbor BGP AS number
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ shutdown
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Administratively shut down neighbor
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ solo
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Do not send back prefixes learned from the neighbor
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ strict_capability_match
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Enable strict capability negotiation
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ timers
+
+
+ dictionary
+
+ |
+
+ |
+
+ Neighbor timers
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ connect
+
+
+ integer
+
+ |
+
+ |
+
+ BGP connect timer for this neighbor.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ holdtime
+
+
+ integer
+
+ |
+
+ |
+
+ BGP hold timer for this neighbor
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ keepalive
+
+
+ integer
+
+ |
+
+ |
+
+ BGP keepalive interval for this neighbor
+ |
+
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ ttl_security
+
+
+ integer
+
+ |
+
+ |
+
+ Number of the maximum number of hops to the BGP peer
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ update_source
+
+
+ string
+
+ |
+
+ |
+
+ Source IP of routing updates
+ |
+
+
+
+ |
+ |
+ |
+ |
+
+
+ timers
+
+
+ dictionary
+
+ |
+
+ |
+
+ BGP protocol timers
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ holdtime
+
+
+ integer
+
+ |
+
+ |
+
+ Hold time interval
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ keepalive
+
+
+ integer
+
+ |
+
+ |
+
+ Keepalive interval
+ |
+
+
+
+
+ |
+ |
+ |
+
+
+ ospf
+
+
+ dictionary
+
+ |
+
+ |
+
+ OSPFv2 configuration
+ |
+
+
+ |
+ |
+ |
+ |
+
+
+ areas
+
+
+ list
+ / elements=dictionary
+
+ |
+
+ |
+
+ OSPFv2 area.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ area_id
+
+
+ string
+
+ |
+
+ |
+
+ OSPFv2 area identity.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ area_type
+
+
+ dictionary
+
+ |
+
+ |
+
+ Area type.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ normal
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Normal OSPFv2 area.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ nssa
+
+
+ dictionary
+
+ |
+
+ |
+
+ NSSA OSPFv2 area.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ default_cost
+
+
+ integer
+
+ |
+
+ |
+
+ Summary-default cost of NSSA area.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ no_summary
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Do not inject inter-area routes into stub.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ set
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Enabling NSSA.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ translate
+
+
+ string
+
+ |
+
+ Choices:
+ - always
+ - candidate
+ - never
+
+ |
+
+ NSSA-ABR.
+ |
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ stub
+
+
+ dictionary
+
+ |
+
+ |
+
+ Stub OSPFv2 area.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ default_cost
+
+
+ integer
+
+ |
+
+ |
+
+ Summary-default cost of stub area.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ no_summary
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Do not inject inter-area routes into stub.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ set
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Enabling stub.
+ |
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ authentication
+
+
+ string
+
+ |
+
+ Choices:
+ - plaintext-password
+ - md5
+
+ |
+
+ OSPFv2 area authentication type.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ network
+
+
+ list
+ / elements=dictionary
+
+ |
+
+ |
+
+ OSPFv2 network.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ address
+
+
+ string
+ / required
+
+ |
+
+ |
+
+ OSPFv2 IPv4 network address.
+ |
+
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ range
+
+
+ list
+ / elements=dictionary
+
+ |
+
+ |
+
+ Summarize routes matching prefix (border routers only).
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ address
+
+
+ string
+
+ |
+
+ |
+
+ border router IPv4 address.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ cost
+
+
+ integer
+
+ |
+
+ |
+
+ Metric for this range.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ not_advertise
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Don't advertise this range.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ substitute
+
+
+ string
+
+ |
+
+ |
+
+ Announce area range (IPv4 address) as another prefix.
+ |
+
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ shortcut
+
+
+ string
+
+ |
+
+ Choices:
+ - default
+ - disable
+ - enable
+
+ |
+
+ Area's shortcut mode.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ virtual_link
+
+
+ list
+ / elements=dictionary
+
+ |
+
+ |
+
+ Virtual link address.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ address
+
+
+ string
+
+ |
+
+ |
+
+ virtual link address.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ authentication
+
+
+ dictionary
+
+ |
+
+ |
+
+ OSPFv2 area authentication type.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ md5
+
+
+ list
+ / elements=dictionary
+
+ |
+
+ |
+
+ MD5 key id based authentication.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ key_id
+
+
+ integer
+
+ |
+
+ |
+
+ MD5 key id.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ md5_key
+
+
+ string
+
+ |
+
+ |
+
+ MD5 key.
+ |
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ plaintext_password
+
+
+ string
+
+ |
+
+ |
+
+ Plain text password.
+ |
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ dead_interval
+
+
+ integer
+
+ |
+
+ |
+
+ Interval after which a neighbor is declared dead.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ hello_interval
+
+
+ integer
+
+ |
+
+ |
+
+ Interval between hello packets.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ retransmit_interval
+
+
+ integer
+
+ |
+
+ |
+
+ Interval between retransmitting lost link state advertisements.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ transmit_delay
+
+
+ integer
+
+ |
+
+ |
+
+ Link state transmit delay.
+ |
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+ auto_cost
+
+
+ dictionary
+
+ |
+
+ |
+
+ Calculate OSPFv2 interface cost according to bandwidth.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ reference_bandwidth
+
+
+ integer
+
+ |
+
+ |
+
+ Reference bandwidth cost in Mbits/sec.
+ |
+
+
+
+ |
+ |
+ |
+ |
+
+
+ default_information
+
+
+ dictionary
+
+ |
+
+ |
+
+ Control distribution of default information.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ originate
+
+
+ dictionary
+
+ |
+
+ |
+
+ Distribute a default route.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ always
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Always advertise default route.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ metric
+
+
+ integer
+
+ |
+
+ |
+
+ OSPFv2 default metric.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ metric_type
+
+
+ integer
+
+ |
+
+ |
+
+ OSPFv2 Metric types for default routes.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ route_map
+
+
+ string
+
+ |
+
+ |
+
+ Route map references.
+ |
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+ default_metric
+
+
+ integer
+
+ |
+
+ |
+
+ Metric of redistributed routes
+ |
+
+
+ |
+ |
+ |
+ |
+
+
+ distance
+
+
+ dictionary
+
+ |
+
+ |
+
+ Administrative distance.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ global
+
+
+ integer
+
+ |
+
+ |
+
+ Global OSPFv2 administrative distance.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ ospf
+
+
+ dictionary
+
+ |
+
+ |
+
+ OSPFv2 administrative distance.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ external
+
+
+ integer
+
+ |
+
+ |
+
+ Distance for external routes.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ inter_area
+
+
+ integer
+
+ |
+
+ |
+
+ Distance for inter-area routes.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ intra_area
+
+
+ integer
+
+ |
+
+ |
+
+ Distance for intra-area routes.
+ |
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+ log_adjacency_changes
+
+
+ string
+
+ |
+
+
+ |
+
+ Log changes in adjacency state.
+ |
+
+
+ |
+ |
+ |
+ |
+
+
+ max_metric
+
+
+ dictionary
+
+ |
+
+ |
+
+ OSPFv2 maximum/infinite-distance metric.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ router_lsa
+
+
+ dictionary
+
+ |
+
+ |
+
+ Advertise own Router-LSA with infinite distance (stub router).
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ administrative
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Administratively apply, for an indefinite period.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ on_shutdown
+
+
+ integer
+
+ |
+
+ |
+
+ Time to advertise self as stub-router.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ on_startup
+
+
+ integer
+
+ |
+
+ |
+
+ Time to advertise self as stub-router
+ |
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+ mpls_te
+
+
+ dictionary
+
+ |
+
+ |
+
+ MultiProtocol Label Switching-Traffic Engineering (MPLS-TE) parameters.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ enabled
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Enable MPLS-TE functionality.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ router_address
+
+
+ string
+
+ |
+
+ |
+
+ Stable IP address of the advertising router.
+ |
+
+
+
+ |
+ |
+ |
+ |
+
+
+ neighbor
+
+
+ list
+ / elements=dictionary
+
+ |
+
+ |
+
+ Neighbor IP address.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ neighbor_id
+
+
+ string
+
+ |
+
+ |
+
+ Identity (number/IP address) of neighbor.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ poll_interval
+
+
+ integer
+
+ |
+
+ |
+
+ Seconds between dead neighbor polling interval.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ priority
+
+
+ integer
+
+ |
+
+ |
+
+ Neighbor priority.
+ |
+
+
+
+ |
+ |
+ |
+ |
+
+
+ parameters
+
+
+ dictionary
+
+ |
+
+ |
+
+ OSPFv2 specific parameters.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ abr_type
+
+
+ string
+
+ |
+
+ Choices:
+ - cisco
+ - ibm
+ - shortcut
+ - standard
+
+ |
+
+ OSPFv2 ABR Type.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ opaque_lsa
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Enable the Opaque-LSA capability (rfc2370).
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ rfc1583_compatibility
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Enable rfc1583 criteria for handling AS external routes.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ router_id
+
+
+ string
+
+ |
+
+ |
+
+ Override the default router identifier.
+ |
+
+
+
+ |
+ |
+ |
+ |
+
+
+ passive_interface
+
+
+ list
+ / elements=string
+
+ |
+
+ |
+
+ Suppress routing updates on an interface.
+ |
+
+
+ |
+ |
+ |
+ |
+
+
+ passive_interface_exclude
+
+
+ list
+ / elements=string
+
+ |
+
+ |
+
+ Interface to exclude when using passive-interface default.
+ |
+
+
+ |
+ |
+ |
+ |
+
+
+ redistribute
+
+
+ list
+ / elements=dictionary
+
+ |
+
+ |
+
+ Redistribute information from another routing protocol.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ metric
+
+
+ integer
+
+ |
+
+ |
+
+ Metric for redistribution routes.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ metric_type
+
+
+ integer
+
+ |
+
+ |
+
+ OSPFv2 Metric types.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ route_map
+
+
+ string
+
+ |
+
+ |
+
+ Route map references.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ route_type
+
+
+ string
+
+ |
+
+ Choices:
+ - bgp
+ - connected
+ - kernel
+ - rip
+ - static
+
+ |
+
+ Route type to redistribute.
+ |
+
+
+
+ |
+ |
+ |
+ |
+
+
+ route_map
+
+
+ list
+ / elements=string
+
+ |
+
+ |
+
+ Filter routes installed in local route map.
+ |
+
+
+ |
+ |
+ |
+ |
+
+
+ timers
+
+
+ dictionary
+
+ |
+
+ |
+
+ Adjust routing timers.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ refresh
+
+
+ dictionary
+
+ |
+
+ |
+
+ Adjust refresh parameters.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ timers
+
+
+ integer
+
+ |
+
+ |
+
+ refresh timer.
+ |
+
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ throttle
+
+
+ dictionary
+
+ |
+
+ |
+
+ Throttling adaptive timers.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ spf
+
+
+ dictionary
+
+ |
+
+ |
+
+ OSPFv2 SPF timers.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ delay
+
+
+ integer
+
+ |
+
+ |
+
+ Delay (msec) from first change received till SPF calculation.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ initial_holdtime
+
+
+ integer
+
+ |
+
+ |
+
+ Initial hold time(msec) between consecutive SPF calculations.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ max_holdtime
+
+
+ integer
+
+ |
+
+ |
+
+ maximum hold time (sec).
+ |
+
+
+
+
+
+
+ |
+ |
+ |
+
+
+ ospfv3
+
+
+ dictionary
+
+ |
+
+ |
+
+ OSPFv3 configuration
+ |
+
+
+ |
+ |
+ |
+ |
+
+
+ areas
+
+
+ list
+ / elements=dictionary
+
+ |
+
+ |
+
+ OSPFv3 area.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ area_id
+
+
+ string
+
+ |
+
+ |
+
+ OSPFv3 Area name/identity.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ export_list
+
+
+ string
+
+ |
+
+ |
+
+ Name of export-list.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ import_list
+
+
+ string
+
+ |
+
+ |
+
+ Name of import-list.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ interface
+
+
+ list
+ / elements=dictionary
+
+ |
+
+ |
+
+ Enable OSPVv3 on an interface for this area.
+ aliases: interfaces
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ name
+
+
+ string
+
+ |
+
+ |
+
+ Interface name.
+ |
+
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ range
+
+
+ list
+ / elements=dictionary
+
+ |
+
+ |
+
+ Summarize routes matching prefix (border routers only).
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ address
+
+
+ string
+
+ |
+
+ |
+
+ border router IPv4 address.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ advertise
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Advertise this range.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ not_advertise
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Don't advertise this range.
+ |
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+ parameters
+
+
+ dictionary
+
+ |
+
+ |
+
+ OSPFv3 specific parameters.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ router_id
+
+
+ string
+
+ |
+
+ |
+
+ Override the default router identifier.
+ |
+
+
+
+ |
+ |
+ |
+ |
+
+
+ redistribute
+
+
+ list
+ / elements=dictionary
+
+ |
+
+ |
+
+ Redistribute information from another routing protocol.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ route_map
+
+
+ string
+
+ |
+
+ |
+
+ Route map references.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ route_type
+
+
+ string
+
+ |
+
+ Choices:
+ - bgp
+ - connected
+ - kernel
+ - ripng
+ - static
+
+ |
+
+ Route type to redistribute.
+ |
+
+
+
+
+ |
+ |
+ |
+
+
+ static
+
+
+ list
+ / elements=dictionary
+
+ |
+
+ |
+
+ Static routes configuration
+ |
+
+
+ |
+ |
+ |
+ |
+
+
+ address_families
+
+
+ list
+ / elements=dictionary
+
+ |
+
+ |
+
+ A dictionary specifying the address family to which the static route(s) belong.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ afi
+
+
+ string
+ / required
+
+ |
+
+
+ |
+
+ Specifies the type of route.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+ routes
+
+
+ list
+ / elements=dictionary
+
+ |
+
+ |
+
+ A dictionary that specify the static route configurations.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ blackhole_config
+
+
+ dictionary
+
+ |
+
+ |
+
+ Configured to silently discard packets.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ distance
+
+
+ integer
+
+ |
+
+ |
+
+ Distance for the route.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ type
+
+
+ string
+
+ |
+
+ |
+
+ This is to configure only blackhole.
+ |
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ dest
+
+
+ string
+ / required
+
+ |
+
+ |
+
+ An IPv4/v6 address in CIDR notation that specifies the destination network for the static route.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ next_hops
+
+
+ list
+ / elements=dictionary
+
+ |
+
+ |
+
+ Next hops to the specified destination.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ admin_distance
+
+
+ integer
+
+ |
+
+ |
+
+ Distance value for the route.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ enabled
+
+
+ boolean
+
+ |
+
+
+ |
+
+ Disable IPv4/v6 next-hop static route.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ forward_router_address
+
+
+ string
+
+ |
+
+ |
+
+ The IP address of the next hop that can be used to reach the destination network.
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ interface
+
+
+ string
+
+ |
+
+ |
+
+ Name of the outgoing interface.
+ |
+
+
+
+
+
+
+
+ |
+ |
+
+
+ table_id
+
+
+ integer
+
+ |
+
+ |
+
+ Routing table associated with this instance
+ |
+
+
+ |
+ |
+
+
+ vni
+
+
+ integer
+
+ |
+
+ |
+
+ Virtual Network Identifier
+ |
+
+
+
+
+ |
+
+ 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 | match "set vrf".
+ The states replaced and overridden have identical behaviour for this module.
+ The state parsed reads the configuration from show configuration commands | match "set vrf" 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.4.2 and 1.5-stream-2025-Q1
+ - This module works with connection ``network_cli``.
+
+
+
+Examples
+--------
+
+.. code-block:: yaml
+
+ # # -------------------
+ # # 1. Using merged
+ # # -------------------
+
+ # # Before state:
+ # # -------------
+ # vyos@vyos:~$ show configuration commands | match 'set vrf'
+ # set vrf name vrf-blue description 'blue-vrf'
+ # set vrf name vrf-blue disable
+ # set vrf name vrf-blue table '100'
+ # set vrf name vrf-blue vni '1000'
+ # vyos@vyos:~$
+
+ # # Task
+ # # -------------
+ # - name: Merge provided configuration with device configuration
+ # vyos.vyos.vyos_vrf:
+ # config:
+ # instances:
+ # - name: "vrf-green"
+ # description: "green-vrf"
+ # table_id: 110
+ # vni: 1010
+
+ # Task output:
+ # -------------
+ # "after": {
+ # "bind_to_all": false,
+ # "instances": [
+ # {
+ # "description": "blue-vrf",
+ # "disable": true,
+ # "name": "vrf-blue",
+ # "table_id": 100,
+ # "vni": 1000
+ # },
+ # {
+ # "description": "green-vrf",
+ # "disable": false,
+ # "name": "vrf-green",
+ # "table_id": 110,
+ # "vni": 1010
+ # }
+ # ]
+ # },
+ # "before": {
+ # "bind_to_all": false,
+ # "instances": [
+ # {
+ # "description": "blue-vrf",
+ # "disable": true,
+ # "name": "vrf-blue",
+ # "table_id": 100,
+ # "vni": 1000
+ # }
+ # ]
+ # },
+ # "changed": true,
+ # "commands": [
+ # "set vrf name vrf-green table 110",
+ # "set vrf name vrf-green vni 1010",
+ # "set vrf name vrf-green description green-vrf"
+ # ]
+
+ # After state:
+ # # -------------
+ # vyos@vyos:~$ show configuration commands | match 'set vrf'
+ # set vrf name vrf-blue description 'blue-vrf'
+ # set vrf name vrf-blue disable
+ # set vrf name vrf-blue table '100'
+ # set vrf name vrf-blue vni '1000'
+ # set vrf name vrf-green description 'green-vrf'
+ # set vrf name vrf-green table '110'
+ # set vrf name vrf-green vni '1010'
+ # vyos@vyos:~$
+
+ # # -------------------
+ # # 2. Using replaced
+ # # -------------------
+
+ # # Before state:
+ # # -------------
+ # vyos@vyos:~$ show configuration commands | match 'set vrf'
+ # set vrf bind-to-all
+ # set vrf name vrf-blue description 'blue-vrf'
+ # set vrf name vrf-blue table '100'
+ # set vrf name vrf-blue vni '1000'
+ # set vrf name vrf-red description 'red-vrf'
+ # set vrf name vrf-red disable
+ # set vrf name vrf-red ip disable-forwarding
+ # set vrf name vrf-red ip protocol rip route-map 'rm1'
+ # set vrf name vrf-red table '101'
+ # set vrf name vrf-red vni '1001'
+ # vyos@vyos:~$
+
+
+ # # Task
+ # # -------------
+ # - name: Merge provided configuration with device configuration
+ # vyos.vyos.vyos_vrf:
+ # config:
+ # bind_to_all: true
+ # instances:
+ # - name: "vrf-blue"
+ # description: "blue-vrf"
+ # disable: false
+ # table_id: 100
+ # vni: 1002
+ # - name: "vrf-red"
+ # description: "red-vrf"
+ # disable: false
+ # table_id: 101
+ # vni: 1001
+ # address_family:
+ # - afi: "ipv4"
+ # disable_forwarding: false
+ # route_maps:
+ # - rm_name: "rm1"
+ # protocol: "ospf"
+ # - afi: "ipv6"
+ # nht_no_resolve_via_default: true
+ # state: replaced
+
+ # # Task output:
+ # # -------------
+ # "after": {
+ # "bind_to_all": true,
+ # "instances": [
+ # {
+ # "description": "blue-vrf",
+ # "disable": false,
+ # "name": "vrf-blue",
+ # "table_id": 100,
+ # "vni": 1002
+ # },
+ # {
+ # "address_family": [
+ # {
+ # "afi": "ipv4",
+ # "disable_forwarding": false,
+ # "nht_no_resolve_via_default": false,
+ # "route_maps": [
+ # {
+ # "protocol": "ospf",
+ # "rm_name": "rm1"
+ # },
+ # {
+ # "protocol": "rip",
+ # "rm_name": "rm1"
+ # }
+ # ]
+ # },
+ # {
+ # "afi": "ipv6",
+ # "disable_forwarding": false,
+ # "nht_no_resolve_via_default": true
+ # }
+ # ],
+ # "description": "red-vrf",
+ # "disable": false,
+ # "name": "vrf-red",
+ # "table_id": 101,
+ # "vni": 1001
+ # }
+ # ]
+ # },
+ # "before": {
+ # "bind_to_all": true,
+ # "instances": [
+ # {
+ # "description": "blue-vrf",
+ # "disable": false,
+ # "name": "vrf-blue",
+ # "table_id": 100,
+ # "vni": 1000
+ # },
+ # {
+ # "address_family": [
+ # {
+ # "afi": "ipv4",
+ # "disable_forwarding": true,
+ # "nht_no_resolve_via_default": false,
+ # "route_maps": [
+ # {
+ # "protocol": "rip",
+ # "rm_name": "rm1"
+ # }
+ # ]
+ # }
+ # ],
+ # "description": "red-vrf",
+ # "disable": true,
+ # "name": "vrf-red",
+ # "table_id": 101,
+ # "vni": 1001
+ # }
+ # ]
+ # },
+ # "changed": true,
+ # "commands": [
+ # "set vrf name vrf-blue vni 1002",
+ # "delete vrf name vrf-red disable",
+ # "set vrf name vrf-red ip protocol ospf route-map rm1",
+ # "delete vrf name vrf-red ip disable-forwarding",
+ # "set vrf name vrf-red ipv6 nht no-resolve-via-default"
+ # ]
+
+ # After state:
+ # # -------------
+ # vyos@vyos:~$
+ # set vrf bind-to-all
+ # set vrf name vrf-blue description 'blue-vrf'
+ # set vrf name vrf-blue table '100'
+ # set vrf name vrf-blue vni '1002'
+ # set vrf name vrf-red description 'red-vrf'
+ # set vrf name vrf-red ip protocol ospf route-map 'rm1'
+ # set vrf name vrf-red ip protocol rip route-map 'rm1'
+ # set vrf name vrf-red ipv6 nht no-resolve-via-default
+ # set vrf name vrf-red table '101'
+ # set vrf name vrf-red vni '1001'
+ # vyos@vyos:~$
+
+
+ # # -------------------
+ # # 3. Using overridden
+ # # -------------------
+
+ # # Before state:
+ # # -------------
+ # vyos@vyos:~$ show configuration commands | match 'set vrf'
+ # set vrf bind-to-all
+ # set vrf name vrf-blue description 'blue-vrf'
+ # set vrf name vrf-blue table '100'
+ # set vrf name vrf-blue vni '1000'
+ # set vrf name vrf-red description 'red-vrf'
+ # set vrf name vrf-red disable
+ # set vrf name vrf-red ip disable-forwarding
+ # set vrf name vrf-red ip protocol rip route-map 'rm1'
+ # set vrf name vrf-red table '101'
+ # set vrf name vrf-red vni '1001'
+ # vyos@vyos:~$
+
+ # Task
+ # -------------
+ # - name: Overridden provided configuration with device configuration
+ # vyos.vyos.vyos_vrf:
+ # config:
+ # bind_to_all: true
+ # instances:
+ # - name: "vrf-blue"
+ # description: "blue-vrf"
+ # disable: true
+ # table_id: 100
+ # vni: 1000
+ # - name: "vrf-red"
+ # description: "red-vrf"
+ # disable: true
+ # table_id: 101
+ # vni: 1001
+ # address_family:
+ # - afi: "ipv4"
+ # disable_forwarding: false
+ # route_maps:
+ # - rm_name: "rm1"
+ # protocol: "rip"
+ # - afi: "ipv6"
+ # nht_no_resolve_via_default: false
+ # state: overridden
+
+ # # Task output:
+ # # -------------
+ # "after": {
+ # "bind_to_all": true,
+ # "instances": [
+ # {
+ # "description": "blue-vrf",
+ # "disable": true,
+ # "name": "vrf-blue",
+ # "table_id": 100,
+ # "vni": 1000
+ # },
+ # {
+ # "address_family": [
+ # {
+ # "afi": "ipv4",
+ # "disable_forwarding": false,
+ # "nht_no_resolve_via_default": false,
+ # "route_maps": [
+ # {
+ # "protocol": "rip",
+ # "rm_name": "rm1"
+ # }
+ # ]
+ # }
+ # ],
+ # "description": "red-vrf",
+ # "disable": true,
+ # "name": "vrf-red",
+ # "table_id": 101,
+ # "vni": 1001
+ # }
+ # ]
+ # },
+ # "before": {
+ # "bind_to_all": true,
+ # "instances": [
+ # {
+ # "description": "blue-vrf",
+ # "disable": false,
+ # "name": "vrf-blue",
+ # "table_id": 100,
+ # "vni": 1000
+ # },
+ # {
+ # "address_family": [
+ # {
+ # "afi": "ipv4",
+ # "disable_forwarding": true,
+ # "nht_no_resolve_via_default": false,
+ # "route_maps": [
+ # {
+ # "protocol": "rip",
+ # "rm_name": "rm1"
+ # }
+ # ]
+ # }
+ # ],
+ # "description": "red-vrf",
+ # "disable": true,
+ # "name": "vrf-red",
+ # "table_id": 101,
+ # "vni": 1001
+ # }
+ # ]
+ # },
+ # "changed": true,
+ # "commands": [
+ # "delete vrf name vrf-blue",
+ # "commit",
+ # "delete vrf name vrf-red",
+ # "commit",
+ # "set vrf name vrf-blue table 100",
+ # "set vrf name vrf-blue vni 1000",
+ # "set vrf name vrf-blue description blue-vrf",
+ # "set vrf name vrf-blue disable",
+ # "set vrf name vrf-red table 101",
+ # "set vrf name vrf-red vni 1001",
+ # "set vrf name vrf-red description red-vrf",
+ # "set vrf name vrf-red disable",
+ # "set vrf name vrf-red ip protocol rip route-map rm1"
+ # ]
+
+ # After state:
+ # # -------------
+ # vyos@vyos:~$ show configuration commands | match 'set vrf'
+ # set vrf bind-to-all
+ # set vrf name vrf-blue description 'blue-vrf'
+ # set vrf name vrf-blue disable
+ # set vrf name vrf-blue table '100'
+ # set vrf name vrf-blue vni '1000'
+ # set vrf name vrf-red description 'red-vrf'
+ # set vrf name vrf-red disable
+ # set vrf name vrf-red ip protocol rip route-map 'rm1'
+ # set vrf name vrf-red table '101'
+ # set vrf name vrf-red vni '1001'
+ # vyos@vyos:~$
+
+ # 4. Using gathered
+ # -------------------
+
+ # # Before state:
+ # # -------------
+ # vyos@vyos:~$ show configuration commands | match 'set vrf'
+ # set vrf bind-to-all
+ # set vrf name vrf-blue description 'blue-vrf'
+ # set vrf name vrf-blue table '100'
+ # set vrf name vrf-blue vni '1000'
+ # set vrf name vrf-red description 'red-vrf'
+ # set vrf name vrf-red disable
+ # set vrf name vrf-red ip disable-forwarding
+ # set vrf name vrf-red ip protocol rip route-map 'rm1'
+ # set vrf name vrf-red table '101'
+ # set vrf name vrf-red vni '1001'
+ # vyos@vyos:~$
+
+ # Task
+ # -------------
+ # - name: Gather provided configuration with device configuration
+ # vyos.vyos.vyos_vrf:
+ # config:
+ # state: gathered
+
+ # # Task output:
+ # # -------------
+ # "gathered": {
+ # "bind_to_all": true,
+ # "instances": [
+ # {
+ # "description": "blue-vrf",
+ # "disable": false,
+ # "name": "vrf-blue",
+ # "table_id": 100,
+ # "vni": 1000
+ # },
+ # {
+ # "address_family": [
+ # {
+ # "afi": "ipv4",
+ # "disable_forwarding": true,
+ # "nht_no_resolve_via_default": false,
+ # "route_maps": [
+ # {
+ # "protocol": "rip",
+ # "rm_name": "rm1"
+ # }
+ # ]
+ # }
+ # ],
+ # "description": "red-vrf",
+ # "disable": true,
+ # "name": "vrf-red",
+ # "table_id": 101,
+ # "vni": 1001
+ # }
+ # ]
+ # }
+
+ # After state:
+ # # -------------
+ # vyos@vyos:~$ show configuration commands | match 'set vrf'
+ # set vrf bind-to-all
+ # set vrf name vrf-blue description 'blue-vrf'
+ # set vrf name vrf-blue table '100'
+ # set vrf name vrf-blue vni '1000'
+ # set vrf name vrf-red description 'red-vrf'
+ # set vrf name vrf-red disable
+ # set vrf name vrf-red ip disable-forwarding
+ # set vrf name vrf-red ip protocol rip route-map 'rm1'
+ # set vrf name vrf-red table '101'
+ # set vrf name vrf-red vni '1001'
+ # vyos@vyos:~$
+
+
+ # # -------------------
+ # # 5. Using deleted
+ # # -------------------
+
+ # # Before state:
+ # # -------------
+ # vyos@vyos:~$ show configuration commands | match 'set vrf'
+ # set vrf bind-to-all
+ # set vrf name vrf-blue description 'blue-vrf'
+ # set vrf name vrf-blue table '100'
+ # set vrf name vrf-blue vni '1000'
+ # set vrf name vrf-red description 'red-vrf'
+ # set vrf name vrf-red disable
+ # set vrf name vrf-red ip disable-forwarding
+ # set vrf name vrf-red ip protocol rip route-map 'rm1'
+ # set vrf name vrf-red table '101'
+ # set vrf name vrf-red vni '1001'
+ # vyos@vyos:~$
+
+ # # Task
+ # # -------------
+ # - name: Replace provided configuration with device configuration
+ # vyos.vyos.vyos_vrf:
+ # config:
+ # bind_to_all: false
+ # instances:
+ # - name: "vrf-blue"
+ # state: deleted
+
+
+ # # Task output:
+ # # -------------
+ # "after": {
+ # "bind_to_all": false,
+ # "instances": [
+ # {
+ # "address_family": [
+ # {
+ # "afi": "ipv4",
+ # "disable_forwarding": true,
+ # "nht_no_resolve_via_default": false,
+ # "route_maps": [
+ # {
+ # "protocol": "rip",
+ # "rm_name": "rm1"
+ # }
+ # ]
+ # }
+ # ],
+ # "description": "red-vrf",
+ # "disable": true,
+ # "name": "vrf-red",
+ # "table_id": 101,
+ # "vni": 1001
+ # }
+ # ]
+ # },
+ # "before": {
+ # "bind_to_all": true,
+ # "instances": [
+ # {
+ # "description": "blue-vrf",
+ # "disable": false,
+ # "name": "vrf-blue",
+ # "table_id": 100,
+ # "vni": 1000
+ # },
+ # {
+ # "address_family": [
+ # {
+ # "afi": "ipv4",
+ # "disable_forwarding": true,
+ # "nht_no_resolve_via_default": false,
+ # "route_maps": [
+ # {
+ # "protocol": "rip",
+ # "rm_name": "rm1"
+ # }
+ # ]
+ # }
+ # ],
+ # "description": "red-vrf",
+ # "disable": true,
+ # "name": "vrf-red",
+ # "table_id": 101,
+ # "vni": 1001
+ # }
+ # ]
+ # },
+ # "changed": true,
+ # "commands": [
+ # "delete vrf bind-to-all",
+ # "delete vrf name vrf-blue"
+ # ]
+
+ # After state:
+ # # -------------
+ # vyos@vyos:~$ show configuration commands | match 'set vrf'
+ # set vrf name vrf-red description 'red-vrf'
+ # set vrf name vrf-red disable
+ # set vrf name vrf-red ip disable-forwarding
+ # set vrf name vrf-red ip protocol rip route-map 'rm1'
+ # set vrf name vrf-red table '101'
+ # set vrf name vrf-red vni '1001'
+ # vyos@vyos:~$
+
+ # # -------------------
+ # # 6. Using rendered
+ # # -------------------
+
+ # # Before state:
+ # # -------------
+ # vyos@vyos:~$ show configuration commands | match 'set vrf'
+ # set vrf name vrf-red description 'red-vrf'
+ # set vrf name vrf-red disable
+ # set vrf name vrf-red ip disable-forwarding
+ # set vrf name vrf-red ip protocol rip route-map 'rm1'
+ # set vrf name vrf-red table '101'
+ # set vrf name vrf-red vni '1001'
+ # vyos@vyos:~$
+
+ # Task
+ # -------------
+ # - name: Render provided configuration with device configuration
+ # vyos.vyos.vyos_vrf:
+ # config:
+ # bind_to_all: true
+ # instances:
+ # - name: "vrf-green"
+ # description: "green-vrf"
+ # disabled: true
+ # table_id: 105
+ # vni: 1000
+ # - name: "vrf-amber"
+ # description: "amber-vrf"
+ # disable: false
+ # table_id: 111
+ # vni: 1001
+ # address_family:
+ # - afi: "ipv4"
+ # disable_forwarding: true
+ # route_maps:
+ # - rm_name: "rm1"
+ # protocol: "ospf"
+ # - afi: "ipv6"
+ # nht_no_resolve_via_default: false
+ # state: rendered
+
+ # # Task output:
+ # # -------------
+ # "rendered": [
+ # "set vrf bind-to-all",
+ # "set vrf name vrf-green table 105",
+ # "set vrf name vrf-green vni 1000",
+ # "set vrf name vrf-green description green-vrf",
+ # "set vrf name vrf-green disable",
+ # "set vrf name vrf-amber table 111",
+ # "set vrf name vrf-amber vni 1001",
+ # "set vrf name vrf-amber description amber-vrf",
+ # "set vrf name vrf-amber ip protocol ospf route-map rm1",
+ # "set vrf name vrf-amber ip disable-forwarding"
+ # ]
+
+ # # -------------------
+ # # 7. Using parsed
+ # # -------------------
+
+ # # vrf_parsed.cfg:
+ # # -------------
+ # set vrf bind-to-all
+ # set vrf name vrf1 description 'red'
+ # set vrf name vrf1 disable
+ # set vrf name vrf1 table 101
+ # set vrf name vrf1 vni 501
+ # set vrf name vrf2 description 'blah2'
+ # set vrf name vrf2 disable
+ # set vrf name vrf2 table 102
+ # set vrf name vrf2 vni 102
+ # set vrf name vrf1 ip disable-forwarding
+ # set vrf name vrf1 ip nht no-resolve-via-default
+ # set vrf name vrf-red ip protocol ospf route-map 'rm1'
+ # set vrf name vrf-red ipv6 nht no-resolve-via-default
+
+ # Task:
+ # -------------
+ # - name: Parse provided configuration with device configuration
+ # vyos.vyos.vyos_vrf:
+ # running_config: "{{ lookup('file', './vrf_parsed.cfg') }}"
+ # state: parsed
+
+
+ # # Task output:
+ # # -------------
+ # "parsed": {
+ # "bind_to_all": true,
+ # "instances": [
+ # {
+ # "address_family": [
+ # {
+ # "afi": "ipv4",
+ # "disable_forwarding": true,
+ # "nht_no_resolve_via_default": true
+ # }
+ # ],
+ # "description": "red",
+ # "disable": true,
+ # "name": "vrf1"
+ # },
+ # {
+ # "description": "blah2",
+ # "disable": true,
+ # "name": "vrf2"
+ # },
+ # {
+ # "address_family": [
+ # {
+ # "afi": "ipv4",
+ # "disable_forwarding": false,
+ # "nht_no_resolve_via_default": false,
+ # "route_maps": [
+ # {
+ # "protocol": "ospf",
+ # "rm_name": "rm1"
+ # }
+ # ]
+ # },
+ # {
+ # "afi": "ipv6",
+ # "disable_forwarding": false,
+ # "nht_no_resolve_via_default": true
+ # }
+ # ],
+ # "disable": false,
+ # "name": "vrf-red"
+ # }
+ # ]
+ # }
+
+
+
+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 system ntp server server1 dynamic', 'set system ntp server server1 prefer', 'set system ntp server server2 noselect', 'set system ntp server server2 preempt', 'set system ntp server server_add preempt']
+ |
+
+
+ |
+
+ 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 system ntp server server1 dynamic', 'set system ntp server server1 prefer', 'set system ntp server server2 noselect', 'set system ntp server server2 preempt', 'set system ntp server server_add preempt']
+ |
+
+
+
+
+
+Status
+------
+
+
+Authors
+~~~~~~~
+
+- Evgeny Molotkov (@omnom62)
diff --git a/meta/runtime.yml b/meta/runtime.yml
index 58899674..36579e05 100644
--- a/meta/runtime.yml
+++ b/meta/runtime.yml
@@ -64,3 +64,5 @@ plugin_routing:
redirect: vyos.vyos.vyos_user
vlan:
redirect: vyos.vyos.vyos_vlan
+ vrf:
+ redirect: vyos.vyos.vyos_vrf
diff --git a/plugins/action/vrf.py b/plugins/action/vrf.py
new file mode 120000
index 00000000..331a791f
--- /dev/null
+++ b/plugins/action/vrf.py
@@ -0,0 +1 @@
+vyos.py
\ No newline at end of file
diff --git a/plugins/module_utils/network/vyos/argspec/vrf/__init__.py b/plugins/module_utils/network/vyos/argspec/vrf/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/plugins/module_utils/network/vyos/argspec/vrf/vrf.py b/plugins/module_utils/network/vyos/argspec/vrf/vrf.py
new file mode 100644
index 00000000..e24fd537
--- /dev/null
+++ b/plugins/module_utils/network/vyos/argspec/vrf/vrf.py
@@ -0,0 +1,131 @@
+# -*- 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_vrf module
+"""
+
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.bgp_global.bgp_global import (
+ Bgp_globalArgs,
+)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.ospfv2.ospfv2 import (
+ Ospfv2Args,
+)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.ospfv3.ospfv3 import (
+ Ospfv3Args,
+)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.static_routes.static_routes import (
+ Static_routesArgs,
+)
+
+
+class VrfArgs(object): # pylint: disable=R0903
+ """The arg spec for the vyos_vrf module"""
+
+ bgp_argument_spec = Bgp_globalArgs.argument_spec["config"]
+ static_routes_argument_spec = Static_routesArgs.argument_spec["config"]
+ ospfv2_argument_spec = Ospfv2Args.argument_spec["config"]
+ ospfv3_argument_spec = Ospfv3Args.argument_spec["config"]
+
+ argument_spec = {
+ "config": {
+ "type": "dict",
+ "options": {
+ "bind_to_all": {"type": "bool", "default": False},
+ "instances": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "name": {"required": True, "type": "str"},
+ "description": {"type": "str"},
+ "disable": {
+ "aliases": ["disabled"],
+ "default": False,
+ "type": "bool",
+ },
+ "table_id": {"type": "int"},
+ "vni": {"type": "int"},
+ "address_family": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "afi": {
+ "type": "str",
+ "choices": ["ipv4", "ipv6"],
+ },
+ "disable_forwarding": {"type": "bool", "default": False},
+ "nht_no_resolve_via_default": {"type": "bool", "default": False},
+ "route_maps": {
+ "type": "list",
+ "elements": "dict",
+ "options": {
+ "rm_name": {"type": "str", "required": True},
+ "protocol": {
+ "type": "str",
+ "choices": [
+ "any",
+ "babel",
+ "bgp",
+ "eigrp",
+ "isis",
+ "ospf",
+ "rip",
+ "static",
+ ],
+ },
+ },
+ },
+ },
+ },
+ "protocols": {
+ # "type": "list", # sanity
+ # "elements": "dict",
+ "type": "dict",
+ "options": {
+ "bgp": bgp_argument_spec,
+ "ospf": ospfv2_argument_spec,
+ "ospfv3": ospfv3_argument_spec,
+ "static": static_routes_argument_spec,
+ },
+ },
+ },
+ },
+ },
+ },
+ "state": {
+ "type": "str",
+ "choices": [
+ "deleted",
+ "merged",
+ "replaced",
+ "overridden",
+ "gathered",
+ "rendered",
+ "parsed",
+ ],
+ "default": "merged",
+ },
+ "running_config": {"type": "str"},
+ } # pylint: disable=C0301
diff --git a/plugins/module_utils/network/vyos/config/vrf/__init__.py b/plugins/module_utils/network/vyos/config/vrf/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/plugins/module_utils/network/vyos/config/vrf/vrf.old b/plugins/module_utils/network/vyos/config/vrf/vrf.old
new file mode 100644
index 00000000..b9f56cc6
--- /dev/null
+++ b/plugins/module_utils/network/vyos/config/vrf/vrf.old
@@ -0,0 +1,313 @@
+#
+# -*- 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_vrf 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.
+"""
+
+import importlib
+
+from copy import deepcopy
+
+from ansible.module_utils.six import iteritems
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import (
+ ResourceModule,
+)
+
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.bgp_global.bgp_global import (
+ Bgp_global,
+)
+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.vrf import (
+ VrfTemplate,
+)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.utils import combine
+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
+
+
+# from ansible.plugins.filter.core import combine
+
+
+class Vrf(ResourceModule):
+ """
+ The vyos_vrf config class
+ """
+
+ def __init__(self, module):
+ super(Vrf, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="vrf",
+ tmplt=VrfTemplate(),
+ )
+ self.parsers = [
+ "bind_to_all",
+ ]
+ self.bgp = Bgp_global(module)
+
+ def _validate_template(self):
+ version = get_os_version(self._module)
+ if LooseVersion(version) >= LooseVersion("1.4"):
+ self._tmplt = VrfTemplate()
+ else:
+ self._module.fail_json(msg="VRF is not supported in this version of VyOS")
+
+ 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
+ """
+ if self.state not in ["parsed", "gathered"]:
+ self.generate_commands()
+ self.run_commands()
+
+ return self.result
+
+ def generate_commands(self):
+ """Generate configuration commands to send based on
+ want, have and desired state.
+ """
+ wantd = {}
+ haved = {}
+ wantd = deepcopy(self.want)
+ haved = deepcopy(self.have)
+
+ # self._module.fail_json(msg="WanT: " + str(self.want) + "**** H: " + str(self.have))
+
+ # if state is merged, merge want onto have and then compare
+ if self.state in ["merged", "replaced"]:
+ # wantd = dict_merge(wantd, haved)
+ # wantd = haved | combine(wantd, recursive=True)
+ wantd = combine(haved, wantd, recursive=True)
+ # self._module.fail_json(msg="Want: " + str(wantd) + "**** H: " + str(haved))
+
+ # if state is deleted, delete and empty out wantd
+ if self.state == "deleted":
+ w = deepcopy(wantd)
+ if w == {} and haved != {}:
+ self.commands = ["delete vrf"]
+ return
+ for k, want in iteritems(w):
+ if not (k in haved and haved[k]):
+ del wantd[k]
+ else:
+ if isinstance(want, list):
+ for entry in want:
+ wname = entry.get("name")
+ haved["instances"] = [
+ i for i in haved.get("instances", []) if i.get("name") != wname
+ ]
+ self.commands.append("delete vrf name {}".format(wname))
+ else:
+ self.commands.append("delete vrf {}".format(k.replace("_", "-")))
+ del wantd[k]
+
+ if self.state == "overridden":
+ w = deepcopy(wantd)
+ h = deepcopy(haved)
+ for k, want in iteritems(w):
+ if k in haved and haved[k] != want:
+ if isinstance(want, list):
+ for entry in want:
+ wname = entry.get("name")
+ hdict = next(
+ (inst for inst in haved["instances"] if inst["name"] == wname),
+ None,
+ )
+ if entry != hdict:
+ # self._module.fail_json(msg="Want: " + str(entry) + "**** H: " + str(hdict))
+ haved["instances"] = [
+ i for i in haved.get("instances", []) if i.get("name") != wname
+ ]
+ self.commands.append("delete vrf name {}".format(wname))
+ self.commands.append("commit")
+
+ for k, want in iteritems(wantd):
+ if isinstance(want, list):
+ self._compare_instances(want=want, have=haved.pop(k, {}))
+ self.compare(
+ parsers=self.parsers,
+ want={k: want},
+ have={k: haved.pop(k, {})},
+ )
+ self._module.fail_json(msg=self.commands)
+
+ def _compare_instances(self, want, have):
+ """Compare the instances of the VRF"""
+ parsers = [
+ "table_id",
+ "vni",
+ "description",
+ "disable_vrf",
+ ]
+ # self._module.fail_json(msg="want: " + str(want) + "**** have: " + str(have))
+
+ for entry in want:
+ h = {}
+ wname = entry.get("name")
+ # h = next((vrf for vrf in have if vrf["name"] == wname), {})
+ h = {
+ k: v
+ for vrf in have
+ if vrf.get("name") == wname
+ for k, v in vrf.items()
+ if k != "address_family"
+ }
+ self.compare(parsers=parsers, want=entry, have=h)
+
+ if "address_family" in entry:
+ wafi = {"name": wname, "address_family": entry.get("address_family", [])}
+ # hdict = next((item for item in have if item["name"] == wname), None)
+ hdict = next((d for d in have if d.get("name") == wname), None)
+
+ hafi = {
+ "name": (hdict or {"name": wname})["name"],
+ "address_family": hdict.get("address_family", []) if hdict else [],
+ }
+
+ # self._module.fail_json(msg="wafi: " + str(wafi) + "**** hafi: " + str(hafi))
+
+ self._compare_addr_family(wafi, hafi)
+
+ if "protocols" in entry:
+ for protocol_name in entry["protocols"]:
+ protocol_module = self._load_protocol_module(protocol_name)
+ w_p_dict = entry["protocols"][protocol_name]
+ h_p_dict = next(
+ (
+ v.get("protocols", {}).get(protocol_name)
+ for v in have
+ if v.get("name") == wname
+ ),
+ {},
+ )
+ if protocol_name == "bgp":
+ protocol_module._validate_template()
+ protocol_module.want = w_p_dict
+ protocol_module.have = h_p_dict
+ protocol_module.generate_commands()
+ elif protocol_name in [
+ # "ospf",
+ # "ospfv3",
+ "static",
+ ]:
+ self._module.fail_json(msg=str(protocol_module))
+ protocol_module._module.params["config"] = w_p_dict
+ protocol_module.state = self.state
+ self._module.fail_json(msg=str(protocol_module.set_config(h_p_dict)))
+
+ protocol_module.commands = protocol_module.set_config(h_p_dict)
+ self.commands.extend(
+ [
+ cmd.replace("protocols", "vrf name " + wname + " protocols", 1)
+ for cmd in protocol_module.commands
+ ],
+ )
+ protocol_module = None # Clear the module to free resources
+
+ def _compare_addr_family(self, want, have):
+ """Compare the address families of the VRF"""
+ afi_parsers = [
+ # "address_family",
+ "disable_forwarding",
+ "disable_nht",
+ ]
+ # self._module.fail_json(msg="wAfi: " + str(want) + "**** hAfi: " + str(have))
+
+ wafi = self.afi_to_list(want)
+ hafi = self.afi_to_list(have)
+
+ lookup = {(d["name"], d["afi"]): d for d in hafi}
+ pairs = [(d1, lookup.get((d1["name"], d1["afi"]), {})) for d1 in wafi]
+
+ for wafd, hafd in pairs:
+ # self._module.fail_json(msg="wAfd: " + str(wafd) + "**** hAfd: " + str(hafd))
+ if "route_maps" in wafd:
+ self._compare_route_maps(wafd, hafd)
+ self.compare(parsers=afi_parsers, want=wafd, have=hafd)
+ # self.compare(parsers=afi_parsers, want=wafi, have=hafi)
+
+ def afi_to_list(self, data):
+ """Convert address family dict to list"""
+
+ return [
+ {"name": data["name"], **{**af, "afi": "ip" if af["afi"] == "ipv4" else af["afi"]}}
+ for af in data["address_family"]
+ ]
+
+ def _compare_route_maps(self, wafd, hafd):
+ want_rms = wafd.get("route_maps", [])
+ have_rms = hafd.get("route_maps", [])
+
+ for want in want_rms:
+ match = next(
+ (
+ h
+ for h in have_rms
+ if h["rm_name"] == want["rm_name"] and h["protocol"] == want["protocol"]
+ ),
+ {},
+ )
+ base = {"name": wafd["name"], "afi": wafd["afi"]}
+
+ self.compare(
+ parsers="route_maps",
+ want={**base, "route_maps": want},
+ have={**base, "route_maps": match},
+ )
+
+ def _load_protocol_module(self, protocol_name):
+ if protocol_name == "bgp":
+ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.bgp_global.bgp_global import (
+ Bgp_global,
+ )
+
+ return Bgp_global(self._module)
+ elif protocol_name == "ospf":
+ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.ospfv2.ospfv2 import (
+ Ospfv2,
+ )
+
+ return Ospfv2(self._module)
+ elif protocol_name == "ospfv3":
+ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.ospfv3.ospfv3 import (
+ Ospfv3,
+ )
+
+ return Ospfv3(self._module)
+ elif protocol_name == "static":
+ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.static_routes.static_routes import (
+ Static_routes,
+ )
+
+ return Static_routes(self._module)
+ else:
+ self._module.fail_json(msg="The protocol is not supported")
diff --git a/plugins/module_utils/network/vyos/config/vrf/vrf.py b/plugins/module_utils/network/vyos/config/vrf/vrf.py
new file mode 100644
index 00000000..aa4329d9
--- /dev/null
+++ b/plugins/module_utils/network/vyos/config/vrf/vrf.py
@@ -0,0 +1,308 @@
+#
+# -*- 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_vrf config file.
+It is in this file where the current configuration (as dict)
+is compared to the provided configuration (as dict) and the command set
+necessary to bring the current configuration to its desired end-state is
+created.
+"""
+
+from copy import deepcopy
+
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import (
+ ResourceModule,
+)
+
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.bgp_global.bgp_global import (
+ Bgp_global,
+)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.ospfv2.ospfv2 import (
+ Ospfv2,
+)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.ospfv3.ospfv3 import (
+ Ospfv3,
+)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.static_routes.static_routes import (
+ Static_routes,
+)
+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.vrf import (
+ VrfTemplate,
+)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.utils import combine
+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 Vrf(ResourceModule):
+ """
+ The vyos_vrf config class
+ """
+
+ def __init__(self, module):
+ super(Vrf, self).__init__(
+ empty_fact_val={},
+ facts_module=Facts(module),
+ module=module,
+ resource="vrf",
+ tmplt=VrfTemplate(),
+ )
+ self.parsers = [
+ "bind_to_all",
+ ]
+
+ def _validate_template(self):
+ version = get_os_version(self._module)
+ if LooseVersion(version) >= LooseVersion("1.4"):
+ self._tmplt = VrfTemplate()
+ else:
+ self._module.fail_json(msg="VRF is not supported in this version of VyOS")
+
+ 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
+ """
+ if self.state not in ["parsed", "gathered"]:
+ self.generate_commands()
+ self.run_commands()
+
+ return self.result
+
+ def generate_commands(self):
+ """Generate configuration commands to send based on
+ want, have and desired state.
+ """
+ wantd = {}
+ haved = {}
+ wantd = deepcopy(self.want)
+ haved = deepcopy(self.have)
+
+ # if state is merged, merge want onto have and then compare
+ if self.state in ["merged", "replaced"]:
+
+ wantd = combine(haved, wantd, recursive=True)
+
+ # if state is deleted, delete and empty out wantd
+ if self.state == "deleted":
+ w = deepcopy(wantd)
+ if w == {} and haved != {}:
+ self.commands = ["delete vrf"]
+ return
+ for k, want in w.items():
+ if not (k in haved and haved[k]):
+ del wantd[k]
+ else:
+ if isinstance(want, list):
+ for entry in want:
+ wname = entry.get("name")
+ haved["instances"] = [
+ i for i in haved.get("instances", []) if i.get("name") != wname
+ ]
+ self.commands.append("delete vrf name {}".format(wname))
+ else:
+ self.commands.append("delete vrf {}".format(k.replace("_", "-")))
+ del wantd[k]
+
+ if self.state == "overridden":
+ w = deepcopy(wantd)
+ h = deepcopy(haved)
+ for k, want in w.items():
+ if k in haved and haved[k] != want:
+ if isinstance(want, list):
+ for entry in want:
+ wname = entry.get("name")
+ hdict = next(
+ (inst for inst in haved["instances"] if inst["name"] == wname),
+ None,
+ )
+ wantc = self._canonicalise(entry)
+ havec = self._canonicalise(hdict or {})
+
+ if wantc != havec:
+ haved["instances"] = [
+ i for i in haved.get("instances", []) if i.get("name") != wname
+ ]
+ self.commands.append("delete vrf name {}".format(wname))
+ self.commands.append("commit")
+
+ for k, want in wantd.items():
+ if isinstance(want, list):
+ self._compare_instances(want=want, have=haved.pop(k, {}))
+ self.compare(
+ parsers=self.parsers,
+ want={k: want},
+ have={k: haved.pop(k, {})},
+ )
+
+ def _compare_instances(self, want, have):
+ """Compare the instances of the VRF"""
+ parsers = [
+ "table_id",
+ "vni",
+ "description",
+ "disable_vrf",
+ ]
+
+ for entry in want:
+ h = {}
+ wname = entry.get("name")
+ h = {
+ k: v
+ for vrf in have
+ if vrf.get("name") == wname
+ for k, v in vrf.items()
+ if k != "address_family"
+ }
+ self.compare(parsers=parsers, want=entry, have=h)
+
+ if "address_family" in entry:
+ wafi = {"name": wname, "address_family": entry.get("address_family", [])}
+ hdict = next((d for d in have if d.get("name") == wname), None)
+
+ hafi = {
+ "name": (hdict or {"name": wname})["name"],
+ "address_family": hdict.get("address_family", []) if hdict else [],
+ }
+
+ self._compare_addr_family(wafi, hafi)
+
+ if "protocols" in entry:
+ for protocol_name in entry["protocols"]:
+
+ w_p_dict = entry["protocols"][protocol_name]
+
+ h_p_dict = next(
+ (
+ v.get("protocols", {}).get(protocol_name, {})
+ for v in have
+ if v.get("name") == wname
+ ),
+ {},
+ )
+ if protocol_name == "bgp":
+ bgp_module = Bgp_global(self._module)
+ bgp_module._validate_template()
+ bgp_module.want = w_p_dict
+ bgp_module.have = h_p_dict
+ bgp_module.generate_commands()
+ protocol_commands = bgp_module.commands
+ elif protocol_name == "ospf":
+ ospfv2_module = Ospfv2(self._module)
+ ospfv2_module._module.params["config"] = w_p_dict
+ ospfv2_module.state = self.state
+ protocol_commands = ospfv2_module.set_config(h_p_dict)
+ elif protocol_name == "ospfv3":
+ ospfv3_module = Ospfv3(self._module)
+ ospfv3_module._module.params["config"] = w_p_dict
+ ospfv3_module.state = self.state
+ protocol_commands = ospfv3_module.set_config(h_p_dict)
+ elif protocol_name == "static":
+ static_routes_module = Static_routes(self._module)
+ static_routes_module._module.params["config"] = w_p_dict
+ static_routes_module.state = self.state
+ protocol_commands = static_routes_module.set_config(h_p_dict)
+ else:
+ self._module.fail_json(
+ msg="The protocol {} is not supported".format(protocol_name),
+ )
+ self.commands.extend(
+ [
+ cmd.replace("protocols", "vrf name " + wname + " protocols", 1)
+ for cmd in protocol_commands
+ ],
+ )
+
+ def _compare_addr_family(self, want, have):
+ """Compare the address families of the VRF"""
+ afi_parsers = [
+ "disable_forwarding",
+ "disable_nht",
+ ]
+
+ wafi = self.afi_to_list(want)
+ hafi = self.afi_to_list(have)
+
+ lookup = {(d["name"], d["afi"]): d for d in hafi}
+ pairs = [(d1, lookup.get((d1["name"], d1["afi"]), {})) for d1 in wafi]
+
+ for wafd, hafd in pairs:
+ if "route_maps" in wafd:
+ self._compare_route_maps(wafd, hafd)
+ self.compare(parsers=afi_parsers, want=wafd, have=hafd)
+
+ def afi_to_list(self, data):
+ """Convert address family dict to list"""
+
+ return [
+ {"name": data["name"], **{**af, "afi": "ip" if af["afi"] == "ipv4" else af["afi"]}}
+ for af in data["address_family"]
+ ]
+
+ def _compare_route_maps(self, wafd, hafd):
+ want_rms = wafd.get("route_maps", [])
+ have_rms = hafd.get("route_maps", [])
+
+ for want in want_rms:
+ match = next(
+ (
+ h
+ for h in have_rms
+ if h["rm_name"] == want["rm_name"] and h["protocol"] == want["protocol"]
+ ),
+ {},
+ )
+ base = {"name": wafd["name"], "afi": wafd["afi"]}
+
+ self.compare(
+ parsers="route_maps",
+ want={**base, "route_maps": want},
+ have={**base, "route_maps": match},
+ )
+
+ def _canonicalise(self, obj):
+ if isinstance(obj, dict):
+ return {k: self._canonicalise(v) for k, v in obj.items()}
+
+ if isinstance(obj, list):
+ if not obj:
+ return obj
+
+ if not isinstance(obj[0], dict):
+ return sorted(obj)
+
+ canon = [self._canonicalise(i) for i in obj]
+
+ def sort_key(d):
+ for k in ("name", "address", "afi", "area_id", "neighbor_id", "dest"):
+ if k in d:
+ return d[k]
+ return tuple(sorted(d.items()))
+
+ return sorted(canon, key=sort_key)
+
+ return obj
diff --git a/plugins/module_utils/network/vyos/facts/facts.py b/plugins/module_utils/network/vyos/facts/facts.py
index 74bbda74..24c444dd 100644
--- a/plugins/module_utils/network/vyos/facts/facts.py
+++ b/plugins/module_utils/network/vyos/facts/facts.py
@@ -80,6 +80,7 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.snmp_
from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.static_routes.static_routes import (
Static_routesFacts,
)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.vrf.vrf import VrfFacts
FACT_LEGACY_SUBSETS = dict(default=Default, neighbors=Neighbors, config=Config)
@@ -104,6 +105,7 @@ FACT_RESOURCE_SUBSETS = dict(
ntp_global=Ntp_globalFacts,
snmp_server=Snmp_serverFacts,
hostname=HostnameFacts,
+ vrf=VrfFacts,
)
diff --git a/plugins/module_utils/network/vyos/facts/vrf/__init__.py b/plugins/module_utils/network/vyos/facts/vrf/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/plugins/module_utils/network/vyos/facts/vrf/vrf.py b/plugins/module_utils/network/vyos/facts/vrf/vrf.py
new file mode 100644
index 00000000..6c7b8918
--- /dev/null
+++ b/plugins/module_utils/network/vyos/facts/vrf/vrf.py
@@ -0,0 +1,227 @@
+# -*- 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 vrf 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.
+"""
+
+import re
+
+from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import utils
+
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.vrf.vrf import VrfArgs
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.bgp_global.bgp_global import (
+ Bgp_globalFacts,
+)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.ospfv2.ospfv2 import (
+ Ospfv2Facts,
+)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.ospfv3.ospfv3 import (
+ Ospfv3Facts,
+)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.static_routes.static_routes import (
+ Static_routesFacts,
+)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.rm_templates.vrf import (
+ VrfTemplate,
+)
+
+
+class VrfFacts(object):
+ """The vyos vrf facts class"""
+
+ def __init__(self, module, subspec="config", options="options"):
+ self._module = module
+ self.argument_spec = VrfArgs.argument_spec
+
+ def get_config(self, connection):
+ return connection.get("show configuration commands | match 'set vrf'")
+
+ def get_config_set(self, data, connection):
+ """To classify the configurations beased on vrf"""
+ config_dict = {}
+ for config_line in data.splitlines():
+ vrf_inst = re.search(r"set vrf name (\S+).*", config_line)
+ vrf_bta = re.search(r"set vrf bind-to-all", config_line)
+ if vrf_bta:
+ config_dict["bind_to_all"] = config_dict.get("bind_to_all", "") + config_line + "\n"
+ if vrf_inst:
+ config_dict[vrf_inst.group(1)] = (
+ config_dict.get(vrf_inst.group(1), "") + config_line + "\n"
+ )
+ return list(config_dict.values())
+
+ def populate_facts(self, connection, ansible_facts, data=None):
+ """Populate the facts for Vrf network resource
+
+ :param connection: the device connection
+ :param ansible_facts: Facts dictionary
+ :param data: previously collected conf
+
+ :rtype: dictionary
+ :returns: facts
+ """
+ facts = {}
+ objs = []
+
+ if not data:
+ data = self.get_config(connection)
+
+ vrf_facts = {}
+ instances = []
+ vrf_parser = VrfTemplate(lines=[], module=self._module)
+ resources = self.get_config_set(data, connection)
+
+ for resource in resources:
+ vrf_parser = VrfTemplate(
+ lines=resource.split("\n"),
+ module=self._module,
+ )
+ objs = vrf_parser.parse()
+
+ if objs and "protocols" in resource:
+
+ protocol_lines = []
+ for line in resource.strip().split("\n"):
+ if "protocols" in line:
+ idx = line.index("protocols")
+ protocol_lines.append("set " + line[idx:])
+ objs["protocols"] = self._parse_protocols("\n".join(protocol_lines))
+
+ if objs:
+ if "bind_to_all" in objs:
+ vrf_facts.update(objs)
+ if "name" in objs:
+ instances.append(self._normalise_instance(objs))
+
+ if instances:
+ vrf_facts.update({"instances": instances})
+
+ ansible_facts["ansible_network_resources"].pop("vrf_facts", None)
+ facts = {"vrf": []}
+
+ params = utils.remove_empties(
+ vrf_parser.validate_config(
+ self.argument_spec,
+ {"config": vrf_facts},
+ redact=True,
+ ),
+ )
+
+ if not resources:
+ params["config"].pop("bind_to_all", None)
+
+ if params.get("config"):
+ facts["vrf"] = params["config"]
+ ansible_facts["ansible_network_resources"].update(facts)
+ return ansible_facts
+
+ def _normalise_instance(self, instance):
+ n_inst = instance.copy()
+ af_map = {}
+
+ for af in instance.get("address_family", []):
+ afi = af.get("afi")
+ if not afi:
+ continue
+
+ if afi not in af_map:
+ af_map[afi] = {"afi": afi}
+
+ for k, v in af.items():
+ if k == "afi":
+ continue
+ elif k == "route_maps":
+ if "route_maps" not in af_map[afi]:
+ af_map[afi]["route_maps"] = []
+ af_map[afi]["route_maps"].extend(v)
+ else:
+ af_map[afi][k] = v
+
+ for afi_data in af_map.values():
+ if "route_maps" in afi_data:
+ seen = []
+ deduped = []
+ for item in afi_data["route_maps"]:
+ if item not in seen:
+ seen.append(item)
+ deduped.append(item)
+ afi_data["route_maps"] = deduped
+
+ n_inst["address_family"] = list(af_map.values())
+ return n_inst
+
+ def _parse_protocols(self, protocols):
+ """Parse protocols and return a dictionary"""
+
+ protocol_chunks = {}
+ parsed_protocols = {}
+
+ for line in protocols.split("\n"):
+ parts = line.split()
+ if len(parts) > 2 and parts[0] == "set" and parts[1] == "protocols":
+ protocol = parts[2]
+ protocol_chunks.setdefault(protocol, []).append(line)
+
+ protocol_strings = {proto: "\n".join(lines) for proto, lines in protocol_chunks.items()}
+
+ for protocol_name, protocol_string in protocol_strings.items():
+ protocol_dict = {}
+
+ if protocol_name == "bgp":
+ bgp_module = Bgp_globalFacts(self._module)
+ protocol_dict = bgp_module.populate_facts(
+ connection=self._module._connection,
+ ansible_facts={"ansible_network_resources": {}},
+ data=protocol_string,
+ )
+ parsed_protocols[protocol_name] = list(
+ protocol_dict.get("ansible_network_resources").values(),
+ )[0]
+
+ elif protocol_name == "ospf":
+ ospf_module = Ospfv2Facts(self._module)
+ protocol_dict = ospf_module.populate_facts(
+ connection=self._module._connection,
+ ansible_facts={"ansible_network_resources": {}},
+ data=protocol_string,
+ )
+ parsed_protocols[protocol_name] = list(
+ protocol_dict.get("ansible_network_resources").values(),
+ )[0]
+
+ elif protocol_name == "ospfv3":
+ ospfv3_module = Ospfv3Facts(self._module)
+ protocol_dict = ospfv3_module.populate_facts(
+ connection=self._module._connection,
+ ansible_facts={"ansible_network_resources": {}},
+ data=protocol_string,
+ )
+ parsed_protocols[protocol_name] = list(
+ protocol_dict.get("ansible_network_resources").values(),
+ )[0]
+
+ elif protocol_name == "static":
+ static_routes_module = Static_routesFacts(self._module)
+ protocol_dict = static_routes_module.populate_facts(
+ connection=self._module._connection,
+ ansible_facts={"ansible_network_resources": {}},
+ data=protocol_string,
+ )
+ parsed_protocols[protocol_name] = list(
+ protocol_dict.get("ansible_network_resources").values(),
+ )[0]
+ else:
+ self._module.fail_json(msg="The protocol is not supported" + protocol_name)
+
+ return parsed_protocols
diff --git a/plugins/module_utils/network/vyos/rm_templates/vrf.py b/plugins/module_utils/network/vyos/rm_templates/vrf.py
new file mode 100644
index 00000000..5171404e
--- /dev/null
+++ b/plugins/module_utils/network/vyos/rm_templates/vrf.py
@@ -0,0 +1,249 @@
+# -*- 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 VRF 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 VrfTemplate(NetworkTemplate):
+ def __init__(self, lines=None, module=None):
+ prefix = {"set": "set", "remove": "delete"}
+ super(VrfTemplate, self).__init__(lines=lines, tmplt=self, prefix=prefix, module=module)
+
+ # fmt: off
+ PARSERS = [
+ {
+ "name": "table_id",
+ "getval": re.compile(
+ r"""
+ ^set
+ \s+vrf
+ \s+name
+ \s+(?P\S+)
+ \s+table
+ \s+'(?P\S+)'
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "vrf name {{ name }} table {{ table_id }}",
+ "result": {
+ "name": "{{ name }}",
+ "table_id": "{{ tid }}",
+ },
+ },
+ {
+ "name": "bind_to_all",
+ "getval": re.compile(
+ r"""
+ ^set
+ \svrf
+ \s(?Pbind-to-all)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "vrf bind-to-all",
+ "result": {
+ "bind_to_all": "{{ True if bta is defined }}",
+ },
+ },
+ {
+ "name": "vni",
+ "getval": re.compile(
+ r"""
+ ^set
+ \s+vrf
+ \s+name
+ \s+(?P\S+)
+ \s+vni
+ \s'(?P\S+)'
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "vrf name {{name}} vni {{vni}}",
+ "result": {
+ "name": "{{ name }}",
+ "vni": "{{ vni }}",
+ },
+ },
+ {
+ "name": "description",
+ "getval": re.compile(
+ r"""
+ ^set
+ \svrf
+ \sname
+ \s(?P\S+)
+ \sdescription
+ \s(?P\S+)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "vrf name {{name}} description {{description}}",
+ "result": {
+ "name": "{{ name }}",
+ "description": "{{ desc }}",
+ },
+ },
+ {
+ "name": "disable_vrf",
+ "getval": re.compile(
+ r"""
+ ^set
+ \svrf
+ \sname
+ \s(?P\S+)
+ \s(?Pdisable)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "vrf name {{name}} disable",
+ "compval": "disable",
+ "result": {
+ "name": "{{ name }}",
+ "disable": "{{ True if disable is defined }}",
+ },
+ },
+ # {
+ # "name": "address_family",
+ # "getval": re.compile(
+ # r"""
+ # ^set
+ # \svrf
+ # \sname
+ # \s(?P\S+)
+ # \s(?Pip|ipv6)
+ # $""",
+ # re.VERBOSE,
+ # ),
+ # "setval": "vrf name {{name}} {{ af }}",
+ # 'compval': "address_family",
+ # "result": {
+ # "name": "{{ name }}",
+ # "address_family": {
+ # '{{ "ipv4" if af == "ip" else "ipv6" }}': {
+ # "afi": '{{ "ipv4" if af == "ip" else "ipv6" }}',
+ # },
+ # },
+ # },
+ # },
+ # {
+ # "name": "address_family.disable_forwarding",
+ # "getval": re.compile(
+ # r"""
+ # ^set
+ # \svrf
+ # \sname
+ # \s(?P\S+)
+ # \s(?Pip|ipv6)
+ # \s(?Pdisable-forwarding)
+ # $""",
+ # re.VERBOSE,
+ # ),
+ # "setval": "vrf name {{name}} {{ afi }} disable-forwarding",
+ # # "compval": "address_family.ipv6.disable_forwarding",
+ # "result": {
+ # "name": "{{ name }}",
+ # "address_family": {
+ # '{{ "ipv4" if af == "ip" else "ipv6" }}': {
+ # "afi": '{{ "ipv4" if af == "ip" else "ipv6" }}',
+ # "disable_forwarding": "{{ True if df is defined }}",
+ # },
+ # },
+ # },
+ # },
+ {
+ "name": "disable_forwarding",
+ "getval": re.compile(
+ r"""
+ ^set
+ \svrf
+ \sname
+ \s(?P\S+)
+ \s(?Pip|ipv6)
+ \s(?Pdisable-forwarding)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "vrf name {{name}} {{ afi }} disable-forwarding",
+ "compval": "disable_forwarding",
+ "result": {
+ "name": "{{ name }}",
+ 'address_family': [{
+ "afi": '{{ "ipv4" if af == "ip" else "ipv6" }}',
+ "disable_forwarding": "{{ True if df is defined }}",
+ }],
+ },
+ },
+ {
+ "name": "disable_nht",
+ "getval": re.compile(
+ r"""
+ ^set
+ \svrf
+ \sname
+ \s(?P\S+)
+ \s(?Pip|ipv6)
+ \snht
+ \s(?Pno-resolve-via-default)
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "vrf name {{name}} {{ afi }} nht no-resolve-via-default",
+ "compval": "nht_no_resolve_via_default",
+ "result": {
+ "name": "{{ name }}",
+ "address_family": [{
+ "afi": '{{ "ipv4" if af == "ip" else "ipv6" }}',
+ "nht_no_resolve_via_default": "{{ True if nht is defined }}",
+ }],
+ },
+ },
+ {
+ "name": "route_maps",
+ "getval": re.compile(
+ r"""
+ ^set
+ \svrf
+ \sname
+ \s(?P\S+)
+ \s(?Pip|ipv6)
+ \sprotocol
+ \s(?P\S+)
+ \sroute-map
+ \s'(?P\S+)'
+ $""",
+ re.VERBOSE,
+ ),
+ "setval": "vrf name {{name}} {{ afi }} protocol {{ route_maps.protocol }} route-map {{ route_maps.rm_name }}",
+ "compval": "route_maps",
+ "remval": "vrf name {{name}} {{ afi }} protocol {{ route_maps.protocol }}",
+ "result": {
+ "name": "{{ name }}",
+ "address_family": [{
+ "afi": '{{ "ipv4" if af == "ip" else "ipv6" }}',
+ "route_maps": [{
+ "rm_name": "{{ rm }}",
+ "protocol": "{{ proto }}",
+ }],
+ }],
+ },
+ },
+ ]
+ # fmt: on
diff --git a/plugins/module_utils/network/vyos/utils/utils.py b/plugins/module_utils/network/vyos/utils/utils.py
index 6957f6cb..78445c02 100644
--- a/plugins/module_utils/network/vyos/utils/utils.py
+++ b/plugins/module_utils/network/vyos/utils/utils.py
@@ -285,3 +285,25 @@ def in_target_not_none(h, key):
:return: True/False.
"""
return True if h and key in h and h[key] is not None else False
+
+
+def combine(a, b, recursive=False, list_merge="replace"):
+ """
+ Merge two dictionaries (shallow or deep).
+ :param a: dict
+ :param b: dict
+ :param recursive: bool, deep merge
+ :param list_merge: str, only 'replace' is supported (default Ansible behavior)
+ """
+ if not isinstance(a, dict) or not isinstance(b, dict):
+ raise ValueError("combine expects two dictionaries")
+
+ result = a.copy()
+
+ for k, v in b.items():
+ if recursive and k in result and isinstance(result[k], dict) and isinstance(v, dict):
+ result[k] = combine(result[k], v, recursive=True, list_merge=list_merge)
+ else:
+ result[k] = v
+
+ return result
diff --git a/plugins/modules/vyos_vrf.py b/plugins/modules/vyos_vrf.py
new file mode 100644
index 00000000..395a152b
--- /dev/null
+++ b/plugins/modules/vyos_vrf.py
@@ -0,0 +1,1545 @@
+#!/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_vrf
+"""
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+DOCUMENTATION = """
+module: vyos_vrf
+version_added: 1.0.0
+short_description: VRF resource module
+description:
+- This module manages vrf configuration on devices running Vyos
+author:
+- Evgeny Molotkov (@omnom62)
+notes:
+- Tested against vyos 1.4.2 and 1.5-stream-2025-Q1
+- This module works with connection C(network_cli).
+options:
+ config:
+ description: List of vrf configuration.
+ type: dict
+ suboptions:
+ bind_to_all:
+ default: false
+ description: Enable binding services to all VRFs
+ type: bool
+ instances:
+ description: Virtual Routing and Forwarding instance
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: VRF instance name
+ required: true
+ type: str
+ description:
+ description: Description
+ type: str
+ disable:
+ default: false
+ description: Administratively disable interface
+ type: bool
+ aliases: ['disabled']
+ table_id:
+ description: Routing table associated with this instance
+ type: int
+ vni:
+ description: Virtual Network Identifier
+ type: int
+ address_family:
+ type: list
+ elements: dict
+ description: Address family configuration
+ suboptions:
+ afi:
+ description: Address family identifier
+ type: str
+ choices: ['ipv4', 'ipv6']
+ disable_forwarding:
+ default: False
+ description: Disable forwarding for this address family
+ type: bool
+ nht_no_resolve_via_default:
+ default: False
+ description: Disable next-hop resolution via default route
+ type: bool
+ route_maps:
+ description: List of route maps for this address family
+ type: list
+ elements: dict
+ suboptions:
+ rm_name:
+ description: Route map name
+ type: str
+ required: true
+ protocol:
+ description: Protocol to which the route map applies
+ type: str
+ choices:
+ - any
+ - babel
+ - bgp
+ - eigrp
+ - isis
+ - ospf
+ - rip
+ - static
+ protocols:
+ # type: list # sanity
+ # elements: dict
+ type: dict
+ description: Protocol configuration
+ suboptions:
+ bgp:
+ type: dict
+ description: BGP configuration
+ suboptions:
+ as_number:
+ description:
+ - AS number.
+ type: int
+ #maximum_paths: --> moved to address-family before 1.3
+ neighbor:
+ description: BGP neighbor
+ type: list
+ elements: dict
+ suboptions:
+ address:
+ description:
+ - BGP neighbor address (v4/v6).
+ type: str
+ advertisement_interval:
+ description:
+ - Minimum interval for sending routing updates.
+ type: int
+ capability:
+ description:
+ - Advertise capabilities to this neighbor.
+ type: dict
+ suboptions:
+ dynamic:
+ description:
+ - Advertise dynamic capability to this neighbor.
+ type: bool
+ extended_nexthop:
+ description:
+ - Advertise extended nexthop capability to this neighbor.
+ type: bool
+ default_originate:
+ description:
+ - Send default route to this neighbor
+ type: str
+ description:
+ description:
+ - Description of the neighbor
+ type: str
+ disable_capability_negotiation:
+ description:
+ - Disbale capability negotiation with the neighbor
+ type: bool
+ disable_connected_check:
+ description:
+ - Disable check to see if EBGP peer's address is a connected route.
+ type: bool
+ disable_send_community:
+ description:
+ - Disable sending community attributes to this neighbor.
+ type: str
+ choices: ['extended', 'standard']
+ ebgp_multihop:
+ description:
+ - Allow this EBGP neighbor to not be on a directly connected network. Specify
+ the number hops.
+ type: int
+ local_as:
+ description: local as number not to be prepended to updates from EBGP peers
+ type: int
+ override_capability:
+ description: Ignore capability negotiation with specified neighbor.
+ type: bool
+ passive:
+ description: Do not initiate a session with this neighbor
+ type: bool
+ password:
+ description: BGP MD5 password
+ type: str
+ peer_group_name:
+ description: IPv4 peer group for this peer
+ type: str
+ peer_group:
+ description: True if all the configs under this neighbor key is for peer group template.
+ type: bool
+ port:
+ description: Neighbor's BGP port
+ type: int
+ remote_as:
+ description: Neighbor BGP AS number
+ type: int
+ shutdown:
+ description: Administratively shut down neighbor
+ type: bool
+ solo: # <-- added in 1.3
+ description: Do not send back prefixes learned from the neighbor
+ type: bool
+ strict_capability_match:
+ description: Enable strict capability negotiation
+ type: bool
+ timers:
+ description: Neighbor timers
+ type: dict
+ suboptions:
+ connect:
+ description: BGP connect timer for this neighbor.
+ type: int
+ holdtime:
+ description: BGP hold timer for this neighbor
+ type: int
+ keepalive:
+ description: BGP keepalive interval for this neighbor
+ type: int
+ ttl_security:
+ description: Number of the maximum number of hops to the BGP peer
+ type: int
+ update_source:
+ description: Source IP of routing updates
+ type: str
+ timers:
+ description: BGP protocol timers
+ type: dict
+ suboptions:
+ keepalive:
+ description: Keepalive interval
+ type: int
+ holdtime:
+ description: Hold time interval
+ type: int
+ bgp_params:
+ description: BGP parameters
+ type: dict
+ suboptions:
+ always_compare_med:
+ description: Always compare MEDs from different neighbors
+ type: bool
+ bestpath:
+ description: Default bestpath selection mechanism
+ type: dict
+ suboptions:
+ as_path:
+ description: AS-path attribute comparison parameters
+ type: str
+ choices: ['confed', 'ignore']
+ compare_routerid:
+ description: Compare the router-id for identical EBGP paths
+ type: bool
+ med:
+ description: MED attribute comparison parameters
+ type: str
+ choices: ['confed', 'missing-as-worst']
+ cluster_id:
+ description: Route-reflector cluster-id
+ type: str
+ confederation:
+ description: AS confederation parameters
+ type: list
+ elements: dict
+ suboptions:
+ identifier:
+ description: Confederation AS identifier
+ type: int
+ peers:
+ description: Peer ASs in the BGP confederation
+ type: int
+ dampening:
+ description: Enable route-flap dampening
+ type: dict
+ suboptions:
+ half_life:
+ description: Half-life penalty in seconds
+ type: int
+ max_suppress_time:
+ description: Maximum duration to suppress a stable route
+ type: int
+ re_use:
+ description: Time to start reusing a route
+ type: int
+ start_suppress_time:
+ description: When to start suppressing a route
+ type: int
+ default:
+ description: BGP defaults
+ type: dict
+ suboptions:
+ local_pref:
+ description: Default local preference
+ type: int
+ no_ipv4_unicast:
+ description: |
+ Deactivate IPv4 unicast for a peer by default
+ Deprecated: Unavailable after 1.4
+ type: bool
+ deterministic_med:
+ description: Compare MEDs between different peers in the same AS
+ type: bool
+ disable_network_import_check:
+ description: Disable IGP route check for network statements
+ type: bool
+ distance:
+ description: Administrative distances for BGP routes
+ type: list
+ elements: dict
+ suboptions:
+ type:
+ description: Type of route
+ type: str
+ choices: ['external', 'internal', 'local']
+ value:
+ description: distance
+ type: int
+ prefix:
+ description: Administrative distance for a specific BGP prefix
+ type: int
+ enforce_first_as:
+ description: Require first AS in the path to match peer's AS
+ type: bool
+ graceful_restart:
+ description: Maximum time to hold onto restarting peer's stale paths
+ type: int
+ log_neighbor_changes:
+ description: Log neighbor up/down changes and reset reason
+ type: bool
+ no_client_to_client_reflection:
+ description: Disable client to client route reflection
+ type: bool
+ no_fast_external_failover:
+ description: Disable immediate session reset if peer's connected link goes down
+ type: bool
+ router_id:
+ description: BGP router-id
+ type: str
+ scan_time:
+ description: BGP route scanner interval
+ type: int
+ ospf:
+ type: dict
+ description: OSPFv2 configuration
+ suboptions:
+ areas:
+ description: OSPFv2 area.
+ type: list
+ elements: dict
+ suboptions:
+ area_id:
+ description: OSPFv2 area identity.
+ type: str
+ area_type:
+ description: Area type.
+ type: dict
+ suboptions:
+ normal:
+ description: Normal OSPFv2 area.
+ type: bool
+ nssa:
+ description: NSSA OSPFv2 area.
+ type: dict
+ suboptions:
+ set:
+ description: Enabling NSSA.
+ type: bool
+ default_cost:
+ description: Summary-default cost of NSSA area.
+ type: int
+ no_summary:
+ description: Do not inject inter-area routes into stub.
+ type: bool
+ translate:
+ description: NSSA-ABR.
+ type: str
+ choices: [always, candidate, never]
+ stub:
+ description: Stub OSPFv2 area.
+ type: dict
+ suboptions:
+ set:
+ description: Enabling stub.
+ type: bool
+ default_cost:
+ description: Summary-default cost of stub area.
+ type: int
+ no_summary:
+ description: Do not inject inter-area routes into stub.
+ type: bool
+ authentication:
+ description: OSPFv2 area authentication type.
+ type: str
+ choices: [plaintext-password, md5]
+ network:
+ description: OSPFv2 network.
+ type: list
+ elements: dict
+ suboptions:
+ address:
+ required: true
+ description: OSPFv2 IPv4 network address.
+ type: str
+ range:
+ description: Summarize routes matching prefix (border routers only).
+ type: list
+ elements: dict
+ suboptions:
+ address:
+ description: border router IPv4 address.
+ type: str
+ cost:
+ description: Metric for this range.
+ type: int
+ not_advertise:
+ description: Don't advertise this range.
+ type: bool
+ substitute:
+ description: Announce area range (IPv4 address) as another prefix.
+ type: str
+ shortcut:
+ description: Area's shortcut mode.
+ type: str
+ choices: [default, disable, enable]
+ virtual_link:
+ description: Virtual link address.
+ type: list
+ elements: dict
+ suboptions:
+ address:
+ description: virtual link address.
+ type: str
+ authentication:
+ description: OSPFv2 area authentication type.
+ type: dict
+ suboptions:
+ md5:
+ description: MD5 key id based authentication.
+ type: list
+ elements: dict
+ suboptions:
+ key_id:
+ description: MD5 key id.
+ type: int
+ md5_key:
+ description: MD5 key.
+ type: str
+ plaintext_password:
+ description: Plain text password.
+ type: str
+ dead_interval:
+ description: Interval after which a neighbor is declared dead.
+ type: int
+ hello_interval:
+ description: Interval between hello packets.
+ type: int
+ retransmit_interval:
+ description: Interval between retransmitting lost link state advertisements.
+ type: int
+ transmit_delay:
+ description: Link state transmit delay.
+ type: int
+ log_adjacency_changes:
+ description: Log changes in adjacency state.
+ type: str
+ choices: [detail]
+ max_metric:
+ description: OSPFv2 maximum/infinite-distance metric.
+ type: dict
+ suboptions:
+ router_lsa:
+ description: Advertise own Router-LSA with infinite distance (stub router).
+ type: dict
+ suboptions:
+ administrative:
+ description: Administratively apply, for an indefinite period.
+ type: bool
+ on_shutdown:
+ description: Time to advertise self as stub-router.
+ type: int
+ on_startup:
+ description: Time to advertise self as stub-router
+ type: int
+ auto_cost:
+ description: Calculate OSPFv2 interface cost according to bandwidth.
+ type: dict
+ suboptions:
+ reference_bandwidth:
+ description: Reference bandwidth cost in Mbits/sec.
+ type: int
+ default_information:
+ description: Control distribution of default information.
+ type: dict
+ suboptions:
+ originate:
+ description: Distribute a default route.
+ type: dict
+ suboptions:
+ always:
+ description: Always advertise default route.
+ type: bool
+ metric:
+ description: OSPFv2 default metric.
+ type: int
+ metric_type:
+ description: OSPFv2 Metric types for default routes.
+ type: int
+ route_map:
+ description: Route map references.
+ type: str
+ default_metric:
+ description: Metric of redistributed routes
+ type: int
+ distance:
+ description: Administrative distance.
+ type: dict
+ suboptions:
+ global:
+ description: Global OSPFv2 administrative distance.
+ type: int
+ ospf:
+ description: OSPFv2 administrative distance.
+ type: dict
+ suboptions:
+ external:
+ description: Distance for external routes.
+ type: int
+ inter_area:
+ description: Distance for inter-area routes.
+ type: int
+ intra_area:
+ description: Distance for intra-area routes.
+ type: int
+ mpls_te:
+ description: MultiProtocol Label Switching-Traffic Engineering (MPLS-TE) parameters.
+ type: dict
+ suboptions:
+ enabled:
+ description: Enable MPLS-TE functionality.
+ type: bool
+ router_address:
+ description: Stable IP address of the advertising router.
+ type: str
+ neighbor:
+ description: Neighbor IP address.
+ type: list
+ elements: dict
+ suboptions:
+ neighbor_id:
+ description: Identity (number/IP address) of neighbor.
+ type: str
+ poll_interval:
+ description: Seconds between dead neighbor polling interval.
+ type: int
+ priority:
+ description: Neighbor priority.
+ type: int
+ parameters:
+ description: OSPFv2 specific parameters.
+ type: dict
+ suboptions:
+ abr_type:
+ description: OSPFv2 ABR Type.
+ type: str
+ choices: [cisco, ibm, shortcut, standard]
+ opaque_lsa:
+ description: Enable the Opaque-LSA capability (rfc2370).
+ type: bool
+ rfc1583_compatibility:
+ description: Enable rfc1583 criteria for handling AS external routes.
+ type: bool
+ router_id:
+ description: Override the default router identifier.
+ type: str
+ passive_interface:
+ description: Suppress routing updates on an interface.
+ type: list
+ elements: str
+ passive_interface_exclude:
+ description: Interface to exclude when using passive-interface default.
+ type: list
+ elements: str
+ redistribute:
+ description: Redistribute information from another routing protocol.
+ type: list
+ elements: dict
+ suboptions:
+ route_type:
+ description: Route type to redistribute.
+ type: str
+ choices: [bgp, connected, kernel, rip, static]
+ metric:
+ description: Metric for redistribution routes.
+ type: int
+ metric_type:
+ description: OSPFv2 Metric types.
+ type: int
+ route_map:
+ description: Route map references.
+ type: str
+ route_map:
+ description: Filter routes installed in local route map.
+ type: list
+ elements: str
+ timers:
+ description: Adjust routing timers.
+ type: dict
+ suboptions:
+ refresh:
+ description: Adjust refresh parameters.
+ type: dict
+ suboptions:
+ timers:
+ description: refresh timer.
+ type: int
+ throttle:
+ description: Throttling adaptive timers.
+ type: dict
+ suboptions:
+ spf:
+ description: OSPFv2 SPF timers.
+ type: dict
+ suboptions:
+ delay:
+ description: Delay (msec) from first change received till SPF
+ calculation.
+ type: int
+ initial_holdtime:
+ description: Initial hold time(msec) between consecutive SPF calculations.
+ type: int
+ max_holdtime:
+ description: maximum hold time (sec).
+ type: int
+ ospfv3:
+ type: dict
+ description: OSPFv3 configuration
+ suboptions:
+ areas:
+ description: OSPFv3 area.
+ type: list
+ elements: dict
+ suboptions:
+ area_id:
+ description: OSPFv3 Area name/identity.
+ type: str
+ export_list:
+ description: Name of export-list.
+ type: str
+ import_list:
+ description: Name of import-list.
+ type: str
+ interface:
+ description: Enable OSPVv3 on an interface for this area.
+ aliases: ['interfaces']
+ type: list
+ elements: dict
+ suboptions:
+ name:
+ description: Interface name.
+ type: str
+ range:
+ description: Summarize routes matching prefix (border routers only).
+ type: list
+ elements: dict
+ suboptions:
+ address:
+ description: border router IPv4 address.
+ type: str
+ advertise:
+ description: Advertise this range.
+ type: bool
+ not_advertise:
+ description: Don't advertise this range.
+ type: bool
+ parameters:
+ description: OSPFv3 specific parameters.
+ type: dict
+ suboptions:
+ router_id:
+ description: Override the default router identifier.
+ type: str
+ redistribute:
+ description: Redistribute information from another routing protocol.
+ type: list
+ elements: dict
+ suboptions:
+ route_type:
+ description: Route type to redistribute.
+ type: str
+ choices:
+ - bgp
+ - connected
+ - kernel
+ - ripng
+ - static
+ route_map:
+ description: Route map references.
+ type: str
+ static:
+ type: list
+ description: Static routes configuration
+ elements: dict
+ suboptions:
+ address_families:
+ description: A dictionary specifying the address family to which the static
+ route(s) belong.
+ type: list
+ elements: dict
+ suboptions:
+ afi:
+ description:
+ - Specifies the type of route.
+ type: str
+ choices:
+ - ipv4
+ - ipv6
+ required: true
+ routes:
+ description: A dictionary that specify the static route configurations.
+ type: list
+ elements: dict
+ suboptions:
+ dest:
+ description:
+ - An IPv4/v6 address in CIDR notation that specifies the destination
+ network for the static route.
+ type: str
+ required: true
+ blackhole_config:
+ description:
+ - Configured to silently discard packets.
+ type: dict
+ suboptions:
+ type:
+ description:
+ - This is to configure only blackhole.
+ type: str
+ distance:
+ description:
+ - Distance for the route.
+ type: int
+ next_hops:
+ description:
+ - Next hops to the specified destination.
+ type: list
+ elements: dict
+ suboptions:
+ forward_router_address:
+ description:
+ - The IP address of the next hop that can be used to reach the
+ destination network.
+ type: str
+ enabled:
+ description:
+ - Disable IPv4/v6 next-hop static route.
+ type: bool
+ admin_distance:
+ description:
+ - Distance value for the route.
+ type: int
+ interface:
+ description:
+ - Name of the outgoing interface.
+ type: str
+ running_config:
+ description:
+ - This option is used only with state I(parsed).
+ - The value of this option should be the output received from the VYOS device by
+ executing the command B(show configuration commands | match "set vrf").
+ - The states I(replaced) and I(overridden) have identical
+ behaviour for this module.
+ - The state I(parsed) reads the configuration from C(show configuration commands | match "set vrf") 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 = """
+# # -------------------
+# # 1. Using merged
+# # -------------------
+
+# # Before state:
+# # -------------
+# vyos@vyos:~$ show configuration commands | match 'set vrf'
+# set vrf name vrf-blue description 'blue-vrf'
+# set vrf name vrf-blue disable
+# set vrf name vrf-blue table '100'
+# set vrf name vrf-blue vni '1000'
+# vyos@vyos:~$
+
+# # Task
+# # -------------
+ # - name: Merge provided configuration with device configuration
+ # vyos.vyos.vyos_vrf:
+ # config:
+ # instances:
+ # - name: "vrf-green"
+ # description: "green-vrf"
+ # table_id: 110
+ # vni: 1010
+
+# Task output:
+# -------------
+ # "after": {
+ # "bind_to_all": false,
+ # "instances": [
+ # {
+ # "description": "blue-vrf",
+ # "disable": true,
+ # "name": "vrf-blue",
+ # "table_id": 100,
+ # "vni": 1000
+ # },
+ # {
+ # "description": "green-vrf",
+ # "disable": false,
+ # "name": "vrf-green",
+ # "table_id": 110,
+ # "vni": 1010
+ # }
+ # ]
+ # },
+ # "before": {
+ # "bind_to_all": false,
+ # "instances": [
+ # {
+ # "description": "blue-vrf",
+ # "disable": true,
+ # "name": "vrf-blue",
+ # "table_id": 100,
+ # "vni": 1000
+ # }
+ # ]
+ # },
+ # "changed": true,
+ # "commands": [
+ # "set vrf name vrf-green table 110",
+ # "set vrf name vrf-green vni 1010",
+ # "set vrf name vrf-green description green-vrf"
+ # ]
+
+# After state:
+# # -------------
+# vyos@vyos:~$ show configuration commands | match 'set vrf'
+# set vrf name vrf-blue description 'blue-vrf'
+# set vrf name vrf-blue disable
+# set vrf name vrf-blue table '100'
+# set vrf name vrf-blue vni '1000'
+# set vrf name vrf-green description 'green-vrf'
+# set vrf name vrf-green table '110'
+# set vrf name vrf-green vni '1010'
+# vyos@vyos:~$
+
+# # -------------------
+# # 2. Using replaced
+# # -------------------
+
+# # Before state:
+# # -------------
+ # vyos@vyos:~$ show configuration commands | match 'set vrf'
+ # set vrf bind-to-all
+ # set vrf name vrf-blue description 'blue-vrf'
+ # set vrf name vrf-blue table '100'
+ # set vrf name vrf-blue vni '1000'
+ # set vrf name vrf-red description 'red-vrf'
+ # set vrf name vrf-red disable
+ # set vrf name vrf-red ip disable-forwarding
+ # set vrf name vrf-red ip protocol rip route-map 'rm1'
+ # set vrf name vrf-red table '101'
+ # set vrf name vrf-red vni '1001'
+ # vyos@vyos:~$
+
+
+# # Task
+# # -------------
+ # - name: Merge provided configuration with device configuration
+ # vyos.vyos.vyos_vrf:
+ # config:
+ # bind_to_all: true
+ # instances:
+ # - name: "vrf-blue"
+ # description: "blue-vrf"
+ # disable: false
+ # table_id: 100
+ # vni: 1002
+ # - name: "vrf-red"
+ # description: "red-vrf"
+ # disable: false
+ # table_id: 101
+ # vni: 1001
+ # address_family:
+ # - afi: "ipv4"
+ # disable_forwarding: false
+ # route_maps:
+ # - rm_name: "rm1"
+ # protocol: "ospf"
+ # - afi: "ipv6"
+ # nht_no_resolve_via_default: true
+ # state: replaced
+
+# # Task output:
+# # -------------
+ # "after": {
+ # "bind_to_all": true,
+ # "instances": [
+ # {
+ # "description": "blue-vrf",
+ # "disable": false,
+ # "name": "vrf-blue",
+ # "table_id": 100,
+ # "vni": 1002
+ # },
+ # {
+ # "address_family": [
+ # {
+ # "afi": "ipv4",
+ # "disable_forwarding": false,
+ # "nht_no_resolve_via_default": false,
+ # "route_maps": [
+ # {
+ # "protocol": "ospf",
+ # "rm_name": "rm1"
+ # },
+ # {
+ # "protocol": "rip",
+ # "rm_name": "rm1"
+ # }
+ # ]
+ # },
+ # {
+ # "afi": "ipv6",
+ # "disable_forwarding": false,
+ # "nht_no_resolve_via_default": true
+ # }
+ # ],
+ # "description": "red-vrf",
+ # "disable": false,
+ # "name": "vrf-red",
+ # "table_id": 101,
+ # "vni": 1001
+ # }
+ # ]
+ # },
+ # "before": {
+ # "bind_to_all": true,
+ # "instances": [
+ # {
+ # "description": "blue-vrf",
+ # "disable": false,
+ # "name": "vrf-blue",
+ # "table_id": 100,
+ # "vni": 1000
+ # },
+ # {
+ # "address_family": [
+ # {
+ # "afi": "ipv4",
+ # "disable_forwarding": true,
+ # "nht_no_resolve_via_default": false,
+ # "route_maps": [
+ # {
+ # "protocol": "rip",
+ # "rm_name": "rm1"
+ # }
+ # ]
+ # }
+ # ],
+ # "description": "red-vrf",
+ # "disable": true,
+ # "name": "vrf-red",
+ # "table_id": 101,
+ # "vni": 1001
+ # }
+ # ]
+ # },
+ # "changed": true,
+ # "commands": [
+ # "set vrf name vrf-blue vni 1002",
+ # "delete vrf name vrf-red disable",
+ # "set vrf name vrf-red ip protocol ospf route-map rm1",
+ # "delete vrf name vrf-red ip disable-forwarding",
+ # "set vrf name vrf-red ipv6 nht no-resolve-via-default"
+ # ]
+
+# After state:
+# # -------------
+ # vyos@vyos:~$
+ # set vrf bind-to-all
+ # set vrf name vrf-blue description 'blue-vrf'
+ # set vrf name vrf-blue table '100'
+ # set vrf name vrf-blue vni '1002'
+ # set vrf name vrf-red description 'red-vrf'
+ # set vrf name vrf-red ip protocol ospf route-map 'rm1'
+ # set vrf name vrf-red ip protocol rip route-map 'rm1'
+ # set vrf name vrf-red ipv6 nht no-resolve-via-default
+ # set vrf name vrf-red table '101'
+ # set vrf name vrf-red vni '1001'
+ # vyos@vyos:~$
+
+
+# # -------------------
+# # 3. Using overridden
+# # -------------------
+
+# # Before state:
+# # -------------
+ # vyos@vyos:~$ show configuration commands | match 'set vrf'
+ # set vrf bind-to-all
+ # set vrf name vrf-blue description 'blue-vrf'
+ # set vrf name vrf-blue table '100'
+ # set vrf name vrf-blue vni '1000'
+ # set vrf name vrf-red description 'red-vrf'
+ # set vrf name vrf-red disable
+ # set vrf name vrf-red ip disable-forwarding
+ # set vrf name vrf-red ip protocol rip route-map 'rm1'
+ # set vrf name vrf-red table '101'
+ # set vrf name vrf-red vni '1001'
+ # vyos@vyos:~$
+
+# Task
+# -------------
+ # - name: Overridden provided configuration with device configuration
+ # vyos.vyos.vyos_vrf:
+ # config:
+ # bind_to_all: true
+ # instances:
+ # - name: "vrf-blue"
+ # description: "blue-vrf"
+ # disable: true
+ # table_id: 100
+ # vni: 1000
+ # - name: "vrf-red"
+ # description: "red-vrf"
+ # disable: true
+ # table_id: 101
+ # vni: 1001
+ # address_family:
+ # - afi: "ipv4"
+ # disable_forwarding: false
+ # route_maps:
+ # - rm_name: "rm1"
+ # protocol: "rip"
+ # - afi: "ipv6"
+ # nht_no_resolve_via_default: false
+ # state: overridden
+
+# # Task output:
+# # -------------
+ # "after": {
+ # "bind_to_all": true,
+ # "instances": [
+ # {
+ # "description": "blue-vrf",
+ # "disable": true,
+ # "name": "vrf-blue",
+ # "table_id": 100,
+ # "vni": 1000
+ # },
+ # {
+ # "address_family": [
+ # {
+ # "afi": "ipv4",
+ # "disable_forwarding": false,
+ # "nht_no_resolve_via_default": false,
+ # "route_maps": [
+ # {
+ # "protocol": "rip",
+ # "rm_name": "rm1"
+ # }
+ # ]
+ # }
+ # ],
+ # "description": "red-vrf",
+ # "disable": true,
+ # "name": "vrf-red",
+ # "table_id": 101,
+ # "vni": 1001
+ # }
+ # ]
+ # },
+ # "before": {
+ # "bind_to_all": true,
+ # "instances": [
+ # {
+ # "description": "blue-vrf",
+ # "disable": false,
+ # "name": "vrf-blue",
+ # "table_id": 100,
+ # "vni": 1000
+ # },
+ # {
+ # "address_family": [
+ # {
+ # "afi": "ipv4",
+ # "disable_forwarding": true,
+ # "nht_no_resolve_via_default": false,
+ # "route_maps": [
+ # {
+ # "protocol": "rip",
+ # "rm_name": "rm1"
+ # }
+ # ]
+ # }
+ # ],
+ # "description": "red-vrf",
+ # "disable": true,
+ # "name": "vrf-red",
+ # "table_id": 101,
+ # "vni": 1001
+ # }
+ # ]
+ # },
+ # "changed": true,
+ # "commands": [
+ # "delete vrf name vrf-blue",
+ # "commit",
+ # "delete vrf name vrf-red",
+ # "commit",
+ # "set vrf name vrf-blue table 100",
+ # "set vrf name vrf-blue vni 1000",
+ # "set vrf name vrf-blue description blue-vrf",
+ # "set vrf name vrf-blue disable",
+ # "set vrf name vrf-red table 101",
+ # "set vrf name vrf-red vni 1001",
+ # "set vrf name vrf-red description red-vrf",
+ # "set vrf name vrf-red disable",
+ # "set vrf name vrf-red ip protocol rip route-map rm1"
+ # ]
+
+# After state:
+# # -------------
+ # vyos@vyos:~$ show configuration commands | match 'set vrf'
+ # set vrf bind-to-all
+ # set vrf name vrf-blue description 'blue-vrf'
+ # set vrf name vrf-blue disable
+ # set vrf name vrf-blue table '100'
+ # set vrf name vrf-blue vni '1000'
+ # set vrf name vrf-red description 'red-vrf'
+ # set vrf name vrf-red disable
+ # set vrf name vrf-red ip protocol rip route-map 'rm1'
+ # set vrf name vrf-red table '101'
+ # set vrf name vrf-red vni '1001'
+ # vyos@vyos:~$
+
+# 4. Using gathered
+# -------------------
+
+# # Before state:
+# # -------------
+ # vyos@vyos:~$ show configuration commands | match 'set vrf'
+ # set vrf bind-to-all
+ # set vrf name vrf-blue description 'blue-vrf'
+ # set vrf name vrf-blue table '100'
+ # set vrf name vrf-blue vni '1000'
+ # set vrf name vrf-red description 'red-vrf'
+ # set vrf name vrf-red disable
+ # set vrf name vrf-red ip disable-forwarding
+ # set vrf name vrf-red ip protocol rip route-map 'rm1'
+ # set vrf name vrf-red table '101'
+ # set vrf name vrf-red vni '1001'
+ # vyos@vyos:~$
+
+# Task
+# -------------
+# - name: Gather provided configuration with device configuration
+# vyos.vyos.vyos_vrf:
+# config:
+# state: gathered
+
+# # Task output:
+# # -------------
+ # "gathered": {
+ # "bind_to_all": true,
+ # "instances": [
+ # {
+ # "description": "blue-vrf",
+ # "disable": false,
+ # "name": "vrf-blue",
+ # "table_id": 100,
+ # "vni": 1000
+ # },
+ # {
+ # "address_family": [
+ # {
+ # "afi": "ipv4",
+ # "disable_forwarding": true,
+ # "nht_no_resolve_via_default": false,
+ # "route_maps": [
+ # {
+ # "protocol": "rip",
+ # "rm_name": "rm1"
+ # }
+ # ]
+ # }
+ # ],
+ # "description": "red-vrf",
+ # "disable": true,
+ # "name": "vrf-red",
+ # "table_id": 101,
+ # "vni": 1001
+ # }
+ # ]
+ # }
+
+# After state:
+# # -------------
+ # vyos@vyos:~$ show configuration commands | match 'set vrf'
+ # set vrf bind-to-all
+ # set vrf name vrf-blue description 'blue-vrf'
+ # set vrf name vrf-blue table '100'
+ # set vrf name vrf-blue vni '1000'
+ # set vrf name vrf-red description 'red-vrf'
+ # set vrf name vrf-red disable
+ # set vrf name vrf-red ip disable-forwarding
+ # set vrf name vrf-red ip protocol rip route-map 'rm1'
+ # set vrf name vrf-red table '101'
+ # set vrf name vrf-red vni '1001'
+ # vyos@vyos:~$
+
+
+# # -------------------
+# # 5. Using deleted
+# # -------------------
+
+# # Before state:
+# # -------------
+ # vyos@vyos:~$ show configuration commands | match 'set vrf'
+ # set vrf bind-to-all
+ # set vrf name vrf-blue description 'blue-vrf'
+ # set vrf name vrf-blue table '100'
+ # set vrf name vrf-blue vni '1000'
+ # set vrf name vrf-red description 'red-vrf'
+ # set vrf name vrf-red disable
+ # set vrf name vrf-red ip disable-forwarding
+ # set vrf name vrf-red ip protocol rip route-map 'rm1'
+ # set vrf name vrf-red table '101'
+ # set vrf name vrf-red vni '1001'
+ # vyos@vyos:~$
+
+# # Task
+# # -------------
+# - name: Replace provided configuration with device configuration
+# vyos.vyos.vyos_vrf:
+# config:
+# bind_to_all: false
+# instances:
+# - name: "vrf-blue"
+# state: deleted
+
+
+# # Task output:
+# # -------------
+ # "after": {
+ # "bind_to_all": false,
+ # "instances": [
+ # {
+ # "address_family": [
+ # {
+ # "afi": "ipv4",
+ # "disable_forwarding": true,
+ # "nht_no_resolve_via_default": false,
+ # "route_maps": [
+ # {
+ # "protocol": "rip",
+ # "rm_name": "rm1"
+ # }
+ # ]
+ # }
+ # ],
+ # "description": "red-vrf",
+ # "disable": true,
+ # "name": "vrf-red",
+ # "table_id": 101,
+ # "vni": 1001
+ # }
+ # ]
+ # },
+ # "before": {
+ # "bind_to_all": true,
+ # "instances": [
+ # {
+ # "description": "blue-vrf",
+ # "disable": false,
+ # "name": "vrf-blue",
+ # "table_id": 100,
+ # "vni": 1000
+ # },
+ # {
+ # "address_family": [
+ # {
+ # "afi": "ipv4",
+ # "disable_forwarding": true,
+ # "nht_no_resolve_via_default": false,
+ # "route_maps": [
+ # {
+ # "protocol": "rip",
+ # "rm_name": "rm1"
+ # }
+ # ]
+ # }
+ # ],
+ # "description": "red-vrf",
+ # "disable": true,
+ # "name": "vrf-red",
+ # "table_id": 101,
+ # "vni": 1001
+ # }
+ # ]
+ # },
+ # "changed": true,
+ # "commands": [
+ # "delete vrf bind-to-all",
+ # "delete vrf name vrf-blue"
+ # ]
+
+# After state:
+# # -------------
+ # vyos@vyos:~$ show configuration commands | match 'set vrf'
+ # set vrf name vrf-red description 'red-vrf'
+ # set vrf name vrf-red disable
+ # set vrf name vrf-red ip disable-forwarding
+ # set vrf name vrf-red ip protocol rip route-map 'rm1'
+ # set vrf name vrf-red table '101'
+ # set vrf name vrf-red vni '1001'
+ # vyos@vyos:~$
+
+# # -------------------
+# # 6. Using rendered
+# # -------------------
+
+# # Before state:
+# # -------------
+ # vyos@vyos:~$ show configuration commands | match 'set vrf'
+ # set vrf name vrf-red description 'red-vrf'
+ # set vrf name vrf-red disable
+ # set vrf name vrf-red ip disable-forwarding
+ # set vrf name vrf-red ip protocol rip route-map 'rm1'
+ # set vrf name vrf-red table '101'
+ # set vrf name vrf-red vni '1001'
+ # vyos@vyos:~$
+
+# Task
+# -------------
+ # - name: Render provided configuration with device configuration
+ # vyos.vyos.vyos_vrf:
+ # config:
+ # bind_to_all: true
+ # instances:
+ # - name: "vrf-green"
+ # description: "green-vrf"
+ # disabled: true
+ # table_id: 105
+ # vni: 1000
+ # - name: "vrf-amber"
+ # description: "amber-vrf"
+ # disable: false
+ # table_id: 111
+ # vni: 1001
+ # address_family:
+ # - afi: "ipv4"
+ # disable_forwarding: true
+ # route_maps:
+ # - rm_name: "rm1"
+ # protocol: "ospf"
+ # - afi: "ipv6"
+ # nht_no_resolve_via_default: false
+ # state: rendered
+
+# # Task output:
+# # -------------
+ # "rendered": [
+ # "set vrf bind-to-all",
+ # "set vrf name vrf-green table 105",
+ # "set vrf name vrf-green vni 1000",
+ # "set vrf name vrf-green description green-vrf",
+ # "set vrf name vrf-green disable",
+ # "set vrf name vrf-amber table 111",
+ # "set vrf name vrf-amber vni 1001",
+ # "set vrf name vrf-amber description amber-vrf",
+ # "set vrf name vrf-amber ip protocol ospf route-map rm1",
+ # "set vrf name vrf-amber ip disable-forwarding"
+ # ]
+
+# # -------------------
+# # 7. Using parsed
+# # -------------------
+
+# # vrf_parsed.cfg:
+# # -------------
+# set vrf bind-to-all
+# set vrf name vrf1 description 'red'
+# set vrf name vrf1 disable
+# set vrf name vrf1 table 101
+# set vrf name vrf1 vni 501
+# set vrf name vrf2 description 'blah2'
+# set vrf name vrf2 disable
+# set vrf name vrf2 table 102
+# set vrf name vrf2 vni 102
+# set vrf name vrf1 ip disable-forwarding
+# set vrf name vrf1 ip nht no-resolve-via-default
+# set vrf name vrf-red ip protocol ospf route-map 'rm1'
+# set vrf name vrf-red ipv6 nht no-resolve-via-default
+
+# Task:
+# -------------
+# - name: Parse provided configuration with device configuration
+# vyos.vyos.vyos_vrf:
+# running_config: "{{ lookup('file', './vrf_parsed.cfg') }}"
+# state: parsed
+
+
+# # Task output:
+# # -------------
+# "parsed": {
+# "bind_to_all": true,
+# "instances": [
+# {
+# "address_family": [
+# {
+# "afi": "ipv4",
+# "disable_forwarding": true,
+# "nht_no_resolve_via_default": true
+# }
+# ],
+# "description": "red",
+# "disable": true,
+# "name": "vrf1"
+# },
+# {
+# "description": "blah2",
+# "disable": true,
+# "name": "vrf2"
+# },
+# {
+# "address_family": [
+# {
+# "afi": "ipv4",
+# "disable_forwarding": false,
+# "nht_no_resolve_via_default": false,
+# "route_maps": [
+# {
+# "protocol": "ospf",
+# "rm_name": "rm1"
+# }
+# ]
+# },
+# {
+# "afi": "ipv6",
+# "disable_forwarding": false,
+# "nht_no_resolve_via_default": true
+# }
+# ],
+# "disable": false,
+# "name": "vrf-red"
+# }
+# ]
+# }
+"""
+
+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 system ntp server server1 dynamic
+ - set system ntp server server1 prefer
+ - set system ntp server server2 noselect
+ - set system ntp server server2 preempt
+ - set system ntp server server_add preempt
+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 system ntp server server1 dynamic
+ - set system ntp server server1 prefer
+ - set system ntp server server2 noselect
+ - set system ntp server server2 preempt
+ - set system ntp server server_add preempt
+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.vrf.vrf import VrfArgs
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.vrf.vrf import Vrf
+
+
+def main():
+ """
+ Main entry point for module execution
+
+ :returns: the result form module invocation
+ """
+ module = AnsibleModule(
+ argument_spec=VrfArgs.argument_spec,
+ mutually_exclusive=[["config", "running_config"]],
+ required_if=[
+ ["state", "merged", ["config"]],
+ ["state", "replaced", ["config"]],
+ ["state", "overridden", ["config"]],
+ ["state", "rendered", ["config"]],
+ ["state", "parsed", ["running_config"]],
+ ],
+ supports_check_mode=True,
+ )
+
+ result = Vrf(module).execute_module()
+ module.exit_json(**result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/pr408-diagram.png b/pr408-diagram.png
new file mode 100644
index 00000000..029208e0
Binary files /dev/null and b/pr408-diagram.png differ
diff --git a/tests/integration/targets/vyos_vrf/defaults/main.yaml b/tests/integration/targets/vyos_vrf/defaults/main.yaml
new file mode 100644
index 00000000..164afead
--- /dev/null
+++ b/tests/integration/targets/vyos_vrf/defaults/main.yaml
@@ -0,0 +1,3 @@
+---
+testcase: "[^_].*"
+test_items: []
diff --git a/tests/integration/targets/vyos_vrf/tasks/cli.yaml b/tests/integration/targets/vyos_vrf/tasks/cli.yaml
new file mode 100644
index 00000000..daccf720
--- /dev/null
+++ b/tests/integration/targets/vyos_vrf/tasks/cli.yaml
@@ -0,0 +1,20 @@
+---
+- name: Collect all cli test cases
+ ansible.builtin.find:
+ paths: "{{ role_path }}/tests/cli"
+ patterns: "{{ testcase }}.yaml"
+ use_regex: true
+ register: test_cases
+ delegate_to: localhost
+
+- name: Set test_items
+ ansible.builtin.set_fact:
+ test_items: "{{ test_cases.files | map(attribute='path') | list }}"
+
+- name: Run test case (connection=ansible.netcommon.network_cli)
+ ansible.builtin.include_tasks: "{{ test_case_to_run }}"
+ vars:
+ ansible_connection: ansible.netcommon.network_cli
+ with_items: "{{ test_items }}"
+ loop_control:
+ loop_var: test_case_to_run
diff --git a/tests/integration/targets/vyos_vrf/tasks/main.yaml b/tests/integration/targets/vyos_vrf/tasks/main.yaml
new file mode 100644
index 00000000..e6378581
--- /dev/null
+++ b/tests/integration/targets/vyos_vrf/tasks/main.yaml
@@ -0,0 +1,5 @@
+---
+- name: Run CLI tests
+ ansible.builtin.include_tasks: cli.yaml
+ tags:
+ - network_cli
diff --git a/tests/integration/targets/vyos_vrf/tests/cli/_add_rm.yaml b/tests/integration/targets/vyos_vrf/tests/cli/_add_rm.yaml
new file mode 100644
index 00000000..ddbed78e
--- /dev/null
+++ b/tests/integration/targets/vyos_vrf/tests/cli/_add_rm.yaml
@@ -0,0 +1,12 @@
+---
+- ansible.builtin.include_tasks: _remove_rm.yaml
+
+- name: Add Route Map
+ ansible.netcommon.cli_config:
+ config: |-
+ set policy route-map rm1 rule 10 action 'permit'
+ set policy route-map rm1 rule 10 match peer '192.0.2.32'
+ set policy route-map rm1 rule 10 set aggregator as '100'
+ set policy route-map rm1 rule 10 set as-path exclude '111'
+ set policy route-map rm1 rule 10 set large-community none
+ set policy route-map rm1 rule 10 set metric '5'
diff --git a/tests/integration/targets/vyos_vrf/tests/cli/_parsed.cfg b/tests/integration/targets/vyos_vrf/tests/cli/_parsed.cfg
new file mode 100644
index 00000000..5fb7c6da
--- /dev/null
+++ b/tests/integration/targets/vyos_vrf/tests/cli/_parsed.cfg
@@ -0,0 +1,34 @@
+set vrf bind-to-all
+set vrf name vrf1 description 'Parser Test VRF 1'
+set vrf name vrf1 disable
+set vrf name vrf1 table 101
+set vrf name vrf1 vni 501
+set vrf name vrf2 description 'Parser Test VRF 2'
+set vrf name vrf2 disable
+set vrf name vrf2 table 102
+set vrf name vrf2 vni 102
+set vrf name vrf1 ip disable-forwarding
+set vrf name vrf1 ip nht no-resolve-via-default
+# set vrf name vrf-red ip protocol kernel route-map 'rm1'
+set vrf name vrf-red ip protocol ospf route-map 'rm1'
+set vrf name vrf-red ipv6 nht no-resolve-via-default
+set vrf name vrf-green protocols ospf area '4'
+set vrf name vrf-green protocols ospf area 4 area-type stub default-cost 20
+set vrf name vrf-green protocols ospf area 4 network 192.0.2.0/24
+set vrf name vrf-green protocols ospf area 4 range 192.0.3.0/24
+set vrf name vrf-green protocols ospf area 4 range 192.0.3.0/24 cost 10
+set vrf name vrf-green protocols ospf area 4 range 192.0.4.0/24
+set vrf name vrf-green protocols ospf area 4 range 192.0.4.0/24 cost 12
+set vrf name vrf-green protocols ospfv3 area '2'
+set vrf name vrf-green protocols ospfv3 area 2 export-list export1
+set vrf name vrf-green protocols ospfv3 area 2 import-list import1
+set vrf name vrf-green protocols ospfv3 area 2 range 2001:db10::/32
+set vrf name vrf-green protocols ospfv3 area 2 range 2001:db20::/32
+set vrf name vrf-green protocols ospfv3 area 2 range 2001:db30::/32
+set vrf name vrf-green protocols static route 192.0.2.0/24
+set vrf name vrf-green protocols static route 192.0.2.0/24 blackhole distance '10'
+set vrf name vrf-green protocols static route 192.0.2.0/24 next-hop '203.0.113.1'
+set vrf name vrf-green protocols static route 192.0.2.0/24 next-hop '203.0.113.2'
+set vrf name vrf-green protocols static route6 2001:db8::/32
+set vrf name vrf-green protocols static route6 2001:db8::/32 blackhole distance '20'
+set vrf name vrf-green protocols static route6 2001:db8::/32 next-hop '2001:db8::1'"
diff --git a/tests/integration/targets/vyos_vrf/tests/cli/_populate.yaml b/tests/integration/targets/vyos_vrf/tests/cli/_populate.yaml
new file mode 100644
index 00000000..9e6253ee
--- /dev/null
+++ b/tests/integration/targets/vyos_vrf/tests/cli/_populate.yaml
@@ -0,0 +1,10 @@
+---
+- ansible.builtin.include_tasks: _remove_config.yaml
+
+- ansible.builtin.include_tasks: _add_rm.yaml
+
+- name: Setup
+ vyos.vyos.vyos_config:
+ lines: "{{ populate_config }}"
+ vars:
+ ansible_connection: ansible.netcommon.network_cli
diff --git a/tests/integration/targets/vyos_vrf/tests/cli/_remove_config.yaml b/tests/integration/targets/vyos_vrf/tests/cli/_remove_config.yaml
new file mode 100644
index 00000000..d909adfd
--- /dev/null
+++ b/tests/integration/targets/vyos_vrf/tests/cli/_remove_config.yaml
@@ -0,0 +1,9 @@
+---
+- name: Remove route-maps and VRF configuration
+ vyos.vyos.vyos_config:
+ lines:
+ - delete policy route-map rm1
+ - delete vrf
+ ignore_errors: true
+ vars:
+ ansible_connection: ansible.netcommon.network_cli
diff --git a/tests/integration/targets/vyos_vrf/tests/cli/_remove_rm.yaml b/tests/integration/targets/vyos_vrf/tests/cli/_remove_rm.yaml
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/integration/targets/vyos_vrf/tests/cli/deleted.yaml b/tests/integration/targets/vyos_vrf/tests/cli/deleted.yaml
new file mode 100644
index 00000000..b6a28d0a
--- /dev/null
+++ b/tests/integration/targets/vyos_vrf/tests/cli/deleted.yaml
@@ -0,0 +1,34 @@
+---
+- debug:
+ msg: START vyos_vrf deleted integration tests on connection={{ ansible_connection }}
+
+- include_tasks: _populate.yaml
+
+- block:
+ - name: Delete the provided configuration
+ register: result
+ vyos.vyos.vyos_vrf: &id001
+ config:
+ state: deleted
+
+ - assert:
+ that:
+ - result.changed == true
+ - result.commands|symmetric_difference(deleted.commands) == []
+
+ - name: Assert that the after dicts were correctly generated
+ assert:
+ that:
+ - result.after|symmetric_difference(deleted.after) == []
+
+ - name: Delete the existing configuration with the provided running configuration (IDEMPOTENT)
+ register: result
+ vyos.vyos.vyos_vrf: *id001
+
+ - name: Assert that the previous task was idempotent
+ assert:
+ that:
+ - result['changed'] == false
+
+ always:
+ - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_vrf/tests/cli/empty_config.yaml b/tests/integration/targets/vyos_vrf/tests/cli/empty_config.yaml
new file mode 100644
index 00000000..ba1dab0d
--- /dev/null
+++ b/tests/integration/targets/vyos_vrf/tests/cli/empty_config.yaml
@@ -0,0 +1,60 @@
+---
+- debug:
+ msg: START vyos_vrf empty_config integration tests on connection={{ ansible_connection }}
+
+- name: Merged with empty config should give appropriate error message
+ register: result
+ ignore_errors: true
+ vyos.vyos.vyos_vrf:
+ config:
+ state: merged
+
+- assert:
+ that:
+ - result.msg == 'value of config parameter must not be empty for state merged'
+
+- name: Replaced with empty config should give appropriate error message
+ register: result
+ ignore_errors: true
+ vyos.vyos.vyos_vrf:
+ config:
+ state: replaced
+
+- assert:
+ that:
+ - result.msg == 'value of config parameter must not be empty for state replaced'
+
+- name: Overridden with empty config should give appropriate error message
+ register: result
+ ignore_errors: true
+ vyos.vyos.vyos_vrf:
+ config:
+ state: overridden
+
+- assert:
+ that:
+ - result.msg == 'value of config parameter must not be empty for state overridden'
+
+- name: Parsed with empty running_config should give appropriate error message
+ register: result
+ ignore_errors: true
+ vyos.vyos.vyos_vrf:
+ running_config:
+ state: parsed
+
+- assert:
+ that:
+ - result.msg == 'value of running_config parameter must not be empty for state parsed'
+
+- name: Rendered with empty config should give appropriate error message
+ register: result
+ ignore_errors: true
+ vyos.vyos.vyos_vrf:
+ config:
+ state: rendered
+
+- assert:
+ that:
+ - result.msg == 'value of config parameter must not be empty for state rendered'
+
+- include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_vrf/tests/cli/gathered.yaml b/tests/integration/targets/vyos_vrf/tests/cli/gathered.yaml
new file mode 100644
index 00000000..7ea7b286
--- /dev/null
+++ b/tests/integration/targets/vyos_vrf/tests/cli/gathered.yaml
@@ -0,0 +1,22 @@
+---
+- debug:
+ msg: START vyos_vrf gathered integration tests on connection={{ ansible_connection }}
+
+- include_tasks: _populate.yaml
+
+- block:
+ - name: Gather config from the device in structured format.
+ register: result
+ vyos.vyos.vyos_vrf:
+ state: gathered
+
+ - vyos.vyos.vyos_facts:
+ gather_network_resources: vrf
+
+ - assert:
+ that:
+ - result.changed == false
+ - result.gathered|symmetric_difference(ansible_facts['network_resources']['vrf']) == []
+
+ always:
+ - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_vrf/tests/cli/merged.yaml b/tests/integration/targets/vyos_vrf/tests/cli/merged.yaml
new file mode 100644
index 00000000..0a93ae02
--- /dev/null
+++ b/tests/integration/targets/vyos_vrf/tests/cli/merged.yaml
@@ -0,0 +1,54 @@
+---
+- debug:
+ msg: START vyos_vrf merged integration tests on connection={{ ansible_connection }}
+
+- include_tasks: _populate.yaml
+
+- block:
+ - name: Merge the provided configuration with the existing running configuration
+ register: result
+ vyos.vyos.vyos_vrf: &id001
+ config:
+ bind_to_all: true
+ instances:
+ - name: "vrf-green"
+ description: "green-vrf"
+ table_id: 110
+ vni: 1010
+ - name: "vrf-pink"
+ description: "pink-vrf"
+ table_id: 111
+ vni: 1111
+ protocols:
+ bgp:
+ as_number: 65005
+ neighbor:
+ - address: 192.0.5.1
+ remote_as: 65012
+ state: merged
+
+ - vyos.vyos.vyos_facts:
+ gather_network_resources: vrf
+
+ - assert:
+ that:
+ - result.changed == true
+ - result.commands|symmetric_difference(merged.commands) == []
+ - result.after|symmetric_difference(ansible_facts['network_resources']['vrf']) == []
+
+ - name: Assert that before dicts were correctly generated
+ assert:
+ that:
+ - "{{ merged['before'] | symmetric_difference(result['before']) |length == 0 }}"
+
+ - name: Merge the provided configuration with the existing running configuration (IDEMPOTENT)
+ register: result
+ vyos.vyos.vyos_vrf: *id001
+
+ - name: Assert that the previous task was idempotent
+ assert:
+ that:
+ - result['changed'] == false
+
+ always:
+ - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_vrf/tests/cli/overridden.yaml b/tests/integration/targets/vyos_vrf/tests/cli/overridden.yaml
new file mode 100644
index 00000000..e21ae185
--- /dev/null
+++ b/tests/integration/targets/vyos_vrf/tests/cli/overridden.yaml
@@ -0,0 +1,49 @@
+---
+- debug:
+ msg: START vyos_vrf overridden integration tests on connection={{ ansible_connection }}
+
+- include_tasks: _populate.yaml
+
+- block:
+ - name: Override the existing configuration with the provided running configuration
+ register: result
+ vyos.vyos.vyos_vrf: &id001
+ config:
+ instances:
+ - name: "vrf-blue"
+ description: "blue-vrf"
+ disable: true
+ table_id: 103
+ vni: 1002
+ - name: "vrf-pink"
+ description: "pink-vrf"
+ table_id: 111
+ vni: 1111
+ protocols:
+ bgp:
+ as_number: 65005
+ neighbor:
+ - address: 192.0.2.1
+ remote_as: 65002
+ state: overridden
+
+ - vyos.vyos.vyos_facts:
+ gather_network_resources: vrf
+
+ - assert:
+ that:
+ - result.changed == true
+ - result.commands|symmetric_difference(overridden.commands) == []
+ - result.after|symmetric_difference(ansible_facts['network_resources']['vrf']) == []
+
+ - name: Override the existing configuration with the provided running configuration (IDEMPOTENT)
+ register: result
+ vyos.vyos.vyos_vrf: *id001
+
+ - name: Assert that the previous task was idempotent
+ assert:
+ that:
+ - result['changed'] == false
+
+ always:
+ - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_vrf/tests/cli/parsed.yaml b/tests/integration/targets/vyos_vrf/tests/cli/parsed.yaml
new file mode 100644
index 00000000..7f6a4b3d
--- /dev/null
+++ b/tests/integration/targets/vyos_vrf/tests/cli/parsed.yaml
@@ -0,0 +1,16 @@
+---
+- debug:
+ msg: START vyos_vrf parsed integration tests on connection={{ ansible_connection }}
+
+- name: Provide the running configuration for parsing (config to be parsed)
+ register: result
+ vyos.vyos.vyos_vrf:
+ running_config: "{{ lookup('file', '_parsed.cfg') }}"
+ state: parsed
+
+- assert:
+ that:
+ - result.changed == false
+ - result.parsed|symmetric_difference(merged.before) == []
+
+- include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_vrf/tests/cli/rendered.yaml b/tests/integration/targets/vyos_vrf/tests/cli/rendered.yaml
new file mode 100644
index 00000000..b8b26d12
--- /dev/null
+++ b/tests/integration/targets/vyos_vrf/tests/cli/rendered.yaml
@@ -0,0 +1,133 @@
+---
+- debug:
+ msg: START vyos_route_maps rendered integration tests on connection={{ ansible_connection }}
+
+- include_tasks: _remove_config.yaml
+
+- block:
+ - name: Structure provided configuration into device specific commands
+ register: result
+ vyos.vyos.vyos_vrf:
+ config:
+ bind_to_all: true
+ instances:
+ - name: vrf-green
+ description: green-vrf
+ disabled: true
+ table_id: 105
+ vni: 1000
+ protocols:
+ bgp:
+ as_number: 65000
+ neighbor:
+ - address: 192.0.2.1
+ remote_as: 65002
+ - address: "1.1.1.3"
+ passive: true
+ remote_as: 400
+ ospf:
+ log_adjacency_changes: detail
+ max_metric:
+ router_lsa:
+ administrative: true
+ on_shutdown: 10
+ on_startup: 10
+ default_information:
+ originate:
+ always: true
+ metric: 10
+ metric_type: 2
+ mpls_te:
+ router_address: 192.0.11.12
+ auto_cost:
+ reference_bandwidth: 2
+ neighbor:
+ - neighbor_id: 192.0.11.12
+ poll_interval: 10
+ priority: 2
+ redistribute:
+ - route_type: bgp
+ metric: 10
+ metric_type: 2
+ parameters:
+ router_id: 192.0.1.1
+ rfc1583_compatibility: true
+ abr_type: cisco
+ areas:
+ - area_id: "2"
+ area_type:
+ normal: true
+ authentication: plaintext-password
+ shortcut: enable
+ - area_id: "3"
+ area_type:
+ nssa:
+ set: true
+ - area_id: "4"
+ area_type:
+ stub:
+ default_cost: 20
+ network:
+ - address: 192.0.2.0/24
+ range:
+ - address: 192.0.3.0/24
+ cost: 10
+ - address: 192.0.4.0/24
+ cost: 12
+ ospfv3:
+ areas:
+ - area_id: "2"
+ export_list: export1
+ import_list: import1
+ range:
+ - address: 2001:db10::/32
+ - address: 2001:db20::/32
+ - address: 2001:db30::/32
+ - area_id: "3"
+ range:
+ - address: 2001:db40::/32
+ parameters:
+ router_id: 192.0.2.10
+ redistribute:
+ - route_type: bgp
+ static:
+ - address_families:
+ - afi: ipv4
+ routes:
+ - dest: "192.0.2.0/24"
+ blackhole_config:
+ distance: 10
+ next_hops:
+ - forward_router_address: "203.0.113.1"
+ - forward_router_address: "203.0.113.2"
+ - afi: ipv6
+ routes:
+ - dest: "2001:db8::/32"
+ blackhole_config:
+ distance: 20
+ next_hops:
+ - forward_router_address: "2001:db8::1"
+ - name: vrf-amber
+ description: amber-vrf
+ disable: false
+ table_id: 111
+ vni: 1001
+ address_family:
+ - afi: ipv4
+ disable_forwarding: true
+ route_maps:
+ # - rm_name: rm1
+ # protocol: kernel
+ - rm_name: rm1
+ protocol: ospf
+ - afi: ipv6
+ nht_no_resolve_via_default: false
+ state: rendered
+
+ - assert:
+ that:
+ - result.changed == false
+ - result.rendered|symmetric_difference(rendered.commands) == []
+
+ always:
+ - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_vrf/tests/cli/replaced.yaml b/tests/integration/targets/vyos_vrf/tests/cli/replaced.yaml
new file mode 100644
index 00000000..68d3e450
--- /dev/null
+++ b/tests/integration/targets/vyos_vrf/tests/cli/replaced.yaml
@@ -0,0 +1,56 @@
+---
+- debug:
+ msg: START vyos_vrf 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_vrf: &id001
+ config:
+ instances:
+ - name: "vrf-blue"
+ description: "blue-vrf"
+ disable: true
+ table_id: 100
+ vni: 1000
+ - name: "vrf-red"
+ description: "Vermillion_VRF"
+ disable: false
+ table_id: 101
+ vni: 1011
+ address_family:
+ - afi: "ipv6"
+ nht_no_resolve_via_default: false
+ - name: "vrf-pink"
+ table_id: 111
+ protocols:
+ ospf:
+ default_information:
+ originate:
+ always: true
+ metric: 20
+ metric_type: 1
+ state: replaced
+
+ - vyos.vyos.vyos_facts:
+ gather_network_resources: vrf
+
+ - assert:
+ that:
+ - result.changed == true
+ - result.commands|symmetric_difference(replaced.commands) == []
+ - result.after|symmetric_difference(ansible_facts['network_resources']['vrf']) == []
+
+ - name: Replace the provided configuration with the existing running configuration (IDEMPOTENT)
+ register: result
+ vyos.vyos.vyos_vrf: *id001
+
+ - name: Assert that the previous task was idempotent
+ assert:
+ that:
+ - result['changed'] == false
+
+ always:
+ - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_vrf/tests/cli/rtt.yaml b/tests/integration/targets/vyos_vrf/tests/cli/rtt.yaml
new file mode 100644
index 00000000..e8e9ea2c
--- /dev/null
+++ b/tests/integration/targets/vyos_vrf/tests/cli/rtt.yaml
@@ -0,0 +1,69 @@
+---
+- debug:
+ msg: START vyos_vrf merged integration tests on connection={{ ansible_connection }}
+
+- include_tasks: _populate.yaml
+
+- block:
+ - name: Merge the provided configuration with the existing running configuration
+ register: baseconfig
+ vyos.vyos.vyos_vrf:
+ config:
+ bind_to_all: true
+ instances:
+ - name: "vrf-green"
+ description: "green-vrf"
+ table_id: 110
+ vni: 1010
+ - name: "vrf-pink"
+ description: "pink-vrf"
+ table_id: 111
+ vni: 1111
+ protocols:
+ bgp:
+ as_number: 65005
+ neighbor:
+ - address: 192.0.5.1
+ remote_as: 65012
+ state: merged
+
+ - vyos.vyos.vyos_facts:
+ gather_network_resources: vrf
+
+ - assert:
+ that:
+ - baseconfig.changed == true
+ - baseconfig.commands|symmetric_difference(merged.commands) == []
+ - baseconfig.after|symmetric_difference(ansible_facts['network_resources']['vrf']) == []
+
+ - name: Merge the existing configuration with the provided running configuration
+ register: result
+ vyos.vyos.vyos_vrf:
+ config:
+ instances:
+ - name: "vrf-blue"
+ description: "blue-vrf"
+ disable: true
+ table_id: 100
+ vni: 1000
+ - name: "vrf-green"
+ description: "green-vrf"
+ table_id: 110
+ vni: 1010
+ address_family:
+ - afi: "ipv4"
+ disable_forwarding: true
+ state: merged
+
+ - name: Revert back to base config using facts round trip
+ register: revert
+ vyos.vyos.vyos_vrf:
+ config: "{{ ansible_facts['network_resources']['vrf'] }}"
+ state: overridden
+
+ - name: Assert that config was reverted
+ assert:
+ that: baseconfig.after == revert.after
+
+ always:
+ - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_vrf/vars/main.yaml b/tests/integration/targets/vyos_vrf/vars/main.yaml
new file mode 100644
index 00000000..9620cf32
--- /dev/null
+++ b/tests/integration/targets/vyos_vrf/vars/main.yaml
@@ -0,0 +1,278 @@
+---
+merged:
+ before:
+ bind_to_all: true
+ instances:
+ - name: "vrf-blue"
+ description: "blue-vrf"
+ disable: false
+ table_id: 100
+ vni: 1000
+ - name: "vrf-red"
+ description: "red-vrf"
+ disable: true
+ table_id: 101
+ vni: 1001
+ address_family:
+ - afi: "ipv4"
+ disable_forwarding: true
+ route_maps:
+ - rm_name: "rm1"
+ protocol: "rip"
+ - afi: "ipv6"
+ nht_no_resolve_via_default: true
+ - name: "vrf-green"
+ description: "green-vrf"
+ table_id: 110
+ vni: 1010
+ protocols:
+ ospf:
+ areas:
+ - area_id: "4"
+ area_type:
+ stub:
+ default_cost: 20
+ network:
+ - address: 192.0.2.0/24
+ range:
+ - address: 192.0.3.0/24
+ cost: 10
+ - address: 192.0.4.0/24
+ cost: 12
+ ospfv3:
+ areas:
+ - area_id: "2"
+ export_list: export1
+ import_list: import1
+ range:
+ - address: 2001:db10::/32
+ - address: 2001:db20::/32
+ - address: 2001:db30::/32
+ static:
+ - address_families:
+ - afi: ipv4
+ routes:
+ - dest: "192.0.2.0/24"
+ blackhole_config:
+ distance: 10
+ next_hops:
+ - forward_router_address: "203.0.113.1"
+ - forward_router_address: "203.0.113.2"
+ - afi: ipv6
+ routes:
+ - dest: "2001:db8::/32"
+ blackhole_config:
+ distance: 20
+ next_hops:
+ - forward_router_address: "2001:db8::1"
+ commands:
+ - set vrf name vrf-green table 110
+ - set vrf name vrf-green vni 1010
+ - set vrf name vrf-green description green-vrf
+ - set vrf name vrf-pink protocols bgp system-as 65005
+ - set vrf name vrf-pink protocols bgp neighbor 192.0.5.1 remote-as 65012
+ after:
+ bind_to_all: true
+ instances:
+ - name: "vrf-blue"
+ description: "blue-vrf"
+ disable: false
+ table_id: 100
+ vni: 1000
+ - name: "vrf-red"
+ description: "red-vrf"
+ disable: true
+ table_id: 101
+ vni: 1001
+ address_family:
+ - afi: "ipv4"
+ disable_forwarding: true
+ route_maps:
+ - rm_name: "rm1"
+ protocol: "rip"
+ - afi: "ipv6"
+ nht_no_resolve_via_default: true
+ - name: "vrf-green"
+ description: "green-vrf"
+ table_id: 110
+ vni: 1010
+
+replaced:
+ commands:
+ - delete vrf bind-to-all
+ - set vrf name vrf-blue disable
+ - set vrf name vrf-red vni 1011
+ - set vrf name vrf-red description Vermillion_VRF
+ - delete vrf name vrf-red disable
+ - delete vrf name vrf-red ipv6 nht no-resolve-via-default
+ - delete vrf name vrf-pink vni 1111
+ - delete vrf name vrf-pink description pink-vrf
+ - delete vrf name vrf-pink protocols ospf log-adjacency-changes 'detail'
+ - delete vrf name vrf-pink protocols ospf auto-cost
+ - delete vrf name vrf-pink protocols ospf max-metric
+ - delete vrf name vrf-pink protocols ospf mpls-te
+ - delete vrf name vrf-pink protocols ospf area
+ - delete vrf name vrf-pink protocols ospf parameters
+ - delete vrf name vrf-pink protocols ospf neighbor
+ - delete vrf name vrf-pink protocols ospf redistribute
+ - set vrf name vrf-pink protocols ospf default-information originate metric 20
+ - set vrf name vrf-pink protocols ospf default-information originate metric-type 1
+ after: []
+
+overridden:
+ commands:
+ - delete vrf name vrf-blue
+ - commit
+ - delete vrf name vrf-pink
+ - commit
+ - set vrf name vrf-blue table 103
+ - set vrf name vrf-blue vni 1002
+ - set vrf name vrf-blue description blue-vrf
+ - set vrf name vrf-blue disable
+ - set vrf name vrf-pink table 111
+ - set vrf name vrf-pink vni 1111
+ - set vrf name vrf-pink description pink-vrf
+ - set vrf name vrf-pink protocols bgp system-as 65005
+ - set vrf name vrf-pink protocols bgp neighbor 192.0.2.1 remote-as 65002
+ - delete vrf bind-to-all
+ after: []
+
+deleted:
+ commands:
+ - delete vrf
+ after: []
+
+rendered:
+ commands:
+ - set vrf bind-to-all
+ - set vrf name vrf-green table 105
+ - set vrf name vrf-green vni 1000
+ - set vrf name vrf-green description green-vrf
+ - set vrf name vrf-green disable
+ - set vrf name vrf-green protocols bgp system-as 65000
+ - set vrf name vrf-green protocols bgp neighbor 192.0.2.1 remote-as 65002
+ - set vrf name vrf-green protocols bgp neighbor 1.1.1.3 passive
+ - set vrf name vrf-green protocols bgp neighbor 1.1.1.3 remote-as 400
+ - set vrf name vrf-green protocols ospf log-adjacency-changes 'detail'
+ - set vrf name vrf-green protocols ospf max-metric router-lsa administrative
+ - set vrf name vrf-green protocols ospf max-metric router-lsa on-shutdown 10
+ - set vrf name vrf-green protocols ospf max-metric router-lsa on-startup 10
+ - set vrf name vrf-green protocols ospf default-information originate always
+ - set vrf name vrf-green protocols ospf default-information originate metric 10
+ - set vrf name vrf-green protocols ospf default-information originate metric-type 2
+ - set vrf name vrf-green protocols ospf mpls-te router-address '192.0.11.12'
+ - set vrf name vrf-green protocols ospf auto-cost reference-bandwidth '2'
+ - set vrf name vrf-green protocols ospf neighbor 192.0.11.12
+ - set vrf name vrf-green protocols ospf neighbor 192.0.11.12 poll-interval 10
+ - set vrf name vrf-green protocols ospf neighbor 192.0.11.12 priority 2
+ - set vrf name vrf-green protocols ospf redistribute bgp
+ - set vrf name vrf-green protocols ospf redistribute bgp metric 10
+ - set vrf name vrf-green protocols ospf redistribute bgp metric-type 2
+ - set vrf name vrf-green protocols ospf parameters router-id '192.0.1.1'
+ - set vrf name vrf-green protocols ospf parameters rfc1583-compatibility
+ - set vrf name vrf-green protocols ospf parameters abr-type 'cisco'
+ - set vrf name vrf-green protocols ospf area '2'
+ - set vrf name vrf-green protocols ospf area 2 area-type normal
+ - set vrf name vrf-green protocols ospf area 2 authentication plaintext-password
+ - set vrf name vrf-green protocols ospf area 2 shortcut enable
+ - set vrf name vrf-green protocols ospf area '3'
+ - set vrf name vrf-green protocols ospf area 3 area-type nssa
+ - set vrf name vrf-green protocols ospf area '4'
+ - set vrf name vrf-green protocols ospf area 4 area-type stub default-cost 20
+ - set vrf name vrf-green protocols ospf area 4 network 192.0.2.0/24
+ - set vrf name vrf-green protocols ospf area 4 range 192.0.3.0/24
+ - set vrf name vrf-green protocols ospf area 4 range 192.0.3.0/24 cost 10
+ - set vrf name vrf-green protocols ospf area 4 range 192.0.4.0/24
+ - set vrf name vrf-green protocols ospf area 4 range 192.0.4.0/24 cost 12
+ - set vrf name vrf-green protocols ospfv3 area '2'
+ - set vrf name vrf-green protocols ospfv3 area 2 export-list export1
+ - set vrf name vrf-green protocols ospfv3 area 2 import-list import1
+ - set vrf name vrf-green protocols ospfv3 area 2 range 2001:db10::/32
+ - set vrf name vrf-green protocols ospfv3 area 2 range 2001:db20::/32
+ - set vrf name vrf-green protocols ospfv3 area 2 range 2001:db30::/32
+ - set vrf name vrf-green protocols ospfv3 area '3'
+ - set vrf name vrf-green protocols ospfv3 area 3 range 2001:db40::/32
+ - set vrf name vrf-green protocols ospfv3 parameters router-id '192.0.2.10'
+ - set vrf name vrf-green protocols ospfv3 redistribute bgp
+ - set vrf name vrf-green protocols static route 192.0.2.0/24
+ - set vrf name vrf-green protocols static route 192.0.2.0/24 blackhole distance '10'
+ - set vrf name vrf-green protocols static route 192.0.2.0/24 next-hop '203.0.113.1'
+ - set vrf name vrf-green protocols static route 192.0.2.0/24 next-hop '203.0.113.2'
+ - set vrf name vrf-green protocols static route6 2001:db8::/32
+ - set vrf name vrf-green protocols static route6 2001:db8::/32 blackhole distance '20'
+ - set vrf name vrf-green protocols static route6 2001:db8::/32 next-hop '2001:db8::1'
+ - set vrf name vrf-amber table 111
+ - set vrf name vrf-amber vni 1001
+ - set vrf name vrf-amber description amber-vrf
+ # - set vrf name vrf-amber ip protocol kernel route-map rm1
+ - set vrf name vrf-amber ip protocol ospf route-map rm1
+ - set vrf name vrf-amber ip disable-forwarding
+
+populate_config:
+ - set vrf bind-to-all
+ - set vrf name vrf-blue description 'blue-vrf'
+ - set vrf name vrf-blue table '100'
+ - set vrf name vrf-blue vni '1000'
+ - set vrf name vrf-red description 'red-vrf'
+ - set vrf name vrf-red disable
+ - set vrf name vrf-red ip disable-forwarding
+ # - set vrf name vrf-red ip protocol kernel route-map 'rm1'
+ - set vrf name vrf-red ip protocol rip route-map 'rm1'
+ - set vrf name vrf-red ipv6 nht no-resolve-via-default
+ - set vrf name vrf-red table '101'
+ - set vrf name vrf-red vni '1001'
+ - set vrf name vrf-pink table 111
+ - set vrf name vrf-pink vni 1111
+ - set vrf name vrf-pink description pink-vrf
+ - set vrf name vrf-pink protocols bgp system-as 65000
+ - set vrf name vrf-pink protocols bgp neighbor 192.0.2.1 remote-as 65002
+ - set vrf name vrf-pink protocols bgp neighbor 1.1.1.3 passive
+ - set vrf name vrf-pink protocols bgp neighbor 1.1.1.3 remote-as 400
+ - set vrf name vrf-pink protocols ospf log-adjacency-changes 'detail'
+ - set vrf name vrf-pink protocols ospf max-metric router-lsa administrative
+ - set vrf name vrf-pink protocols ospf max-metric router-lsa on-shutdown 10
+ - set vrf name vrf-pink protocols ospf max-metric router-lsa on-startup 10
+ - set vrf name vrf-pink protocols ospf default-information originate always
+ - set vrf name vrf-pink protocols ospf default-information originate metric 10
+ - set vrf name vrf-pink protocols ospf default-information originate metric-type 2
+ - set vrf name vrf-pink protocols ospf mpls-te router-address '192.0.11.12'
+ - set vrf name vrf-pink protocols ospf auto-cost reference-bandwidth '2'
+ - set vrf name vrf-pink protocols ospf neighbor 192.0.11.12
+ - set vrf name vrf-pink protocols ospf neighbor 192.0.11.12 poll-interval 10
+ - set vrf name vrf-pink protocols ospf neighbor 192.0.11.12 priority 2
+ - set vrf name vrf-pink protocols ospf redistribute bgp
+ - set vrf name vrf-pink protocols ospf redistribute bgp metric 10
+ - set vrf name vrf-pink protocols ospf redistribute bgp metric-type 2
+ - set vrf name vrf-pink protocols ospf parameters router-id '192.0.1.1'
+ - set vrf name vrf-pink protocols ospf parameters rfc1583-compatibility
+ - set vrf name vrf-pink protocols ospf parameters abr-type 'cisco'
+ - set vrf name vrf-pink protocols ospf area '2'
+ - set vrf name vrf-pink protocols ospf area 2 area-type normal
+ - set vrf name vrf-pink protocols ospf area 2 authentication plaintext-password
+ - set vrf name vrf-pink protocols ospf area 2 shortcut enable
+ - set vrf name vrf-pink protocols ospf area '3'
+ - set vrf name vrf-pink protocols ospf area 3 area-type nssa
+ - set vrf name vrf-pink protocols ospf area '4'
+ - set vrf name vrf-pink protocols ospf area 4 area-type stub default-cost 20
+ - set vrf name vrf-pink protocols ospf area 4 network 192.0.2.0/24
+ - set vrf name vrf-pink protocols ospf area 4 range 192.0.3.0/24
+ - set vrf name vrf-pink protocols ospf area 4 range 192.0.3.0/24 cost 10
+ - set vrf name vrf-pink protocols ospf area 4 range 192.0.4.0/24
+ - set vrf name vrf-pink protocols ospf area 4 range 192.0.4.0/24 cost 12
+ - set vrf name vrf-pink protocols ospfv3 area '2'
+ - set vrf name vrf-pink protocols ospfv3 area 2 export-list export1
+ - set vrf name vrf-pink protocols ospfv3 area 2 import-list import1
+ - set vrf name vrf-pink protocols ospfv3 area 2 range 2001:db10::/32
+ - set vrf name vrf-pink protocols ospfv3 area 2 range 2001:db20::/32
+ - set vrf name vrf-pink protocols ospfv3 area 2 range 2001:db30::/32
+ - set vrf name vrf-pink protocols ospfv3 area '3'
+ - set vrf name vrf-pink protocols ospfv3 area 3 range 2001:db40::/32
+ - set vrf name vrf-pink protocols ospfv3 parameters router-id '192.0.2.10'
+ - set vrf name vrf-pink protocols ospfv3 redistribute bgp
+ - set vrf name vrf-pink protocols static route 192.0.2.0/24
+ - set vrf name vrf-pink protocols static route 192.0.2.0/24 blackhole distance '10'
+ - set vrf name vrf-pink protocols static route 192.0.2.0/24 next-hop '203.0.113.1'
+ - set vrf name vrf-pink protocols static route 192.0.2.0/24 next-hop '203.0.113.2'
+ - set vrf name vrf-pink protocols static route6 2001:db8::/32
+ - set vrf name vrf-pink protocols static route6 2001:db8::/32 blackhole distance '20'
+ - set vrf name vrf-pink protocols static route6 2001:db8::/32 next-hop '2001:db8::1'
diff --git a/tests/unit/modules/network/vyos/fixtures/vyos_vrf_config.cfg b/tests/unit/modules/network/vyos/fixtures/vyos_vrf_config.cfg
new file mode 100644
index 00000000..094b7cf3
--- /dev/null
+++ b/tests/unit/modules/network/vyos/fixtures/vyos_vrf_config.cfg
@@ -0,0 +1,15 @@
+set vrf bind-to-all
+set vrf name vrf-blue description 'blue-vrf'
+set vrf name vrf-blue table '100'
+set vrf name vrf-blue vni '1000'
+set vrf name vrf-red description 'red-vrf'
+set vrf name vrf-red disable
+set vrf name vrf-red ip disable-forwarding
+set vrf name vrf-red ip protocol rip route-map 'rm1'
+set vrf name vrf-red ipv6 nht no-resolve-via-default
+set vrf name vrf-red table '101'
+set vrf name vrf-red vni '1001'
+set vrf name vrf-red protocols bgp system-as 65000
+set vrf name vrf-red protocols bgp neighbor 192.0.2.1 remote-as 65002
+set vrf name vrf-red protocols bgp neighbor 1.1.1.3 passive
+set vrf name vrf-red protocols bgp neighbor 1.1.1.3 remote-as 400
diff --git a/tests/unit/modules/network/vyos/test_vyos_vrf.py b/tests/unit/modules/network/vyos/test_vyos_vrf.py
new file mode 100644
index 00000000..e86227a9
--- /dev/null
+++ b/tests/unit/modules/network/vyos/test_vyos_vrf.py
@@ -0,0 +1,689 @@
+# (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 .
+
+
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+from unittest.mock import MagicMock, patch
+
+from ansible_collections.vyos.vyos.plugins.modules import vyos_vrf
+from ansible_collections.vyos.vyos.tests.unit.modules.utils import set_module_args
+
+from .vyos_module import TestVyosModule, load_fixture
+
+
+class TestVyosVrfModule(TestVyosModule):
+ module = vyos_vrf
+
+ def setUp(self):
+ super(TestVyosVrfModule, self).setUp()
+
+ self.fake_connection = MagicMock()
+ self.fake_connection.get.return_value = "{}"
+
+ self.fake_connection.get_device_info.return_value = {
+ "version": "1.5",
+ }
+
+ self.fake_connection.get_device_info.return_value = {
+ "network_os_major_version": "1.5",
+ }
+ patch(
+ "ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos.get_connection",
+ return_value=self.fake_connection,
+ ).start()
+
+ def _get_resource_connection_side_effect(module, *args, **kwargs):
+ module._connection = self.fake_connection
+ return self.fake_connection
+
+ patch(
+ "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module_base.get_resource_connection",
+ side_effect=_get_resource_connection_side_effect,
+ ).start()
+
+ patch(
+ "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection",
+ side_effect=_get_resource_connection_side_effect,
+ ).start()
+
+ self.mock_execute_show_command = patch(
+ "ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.vrf.vrf.VrfFacts.get_config",
+ ).start()
+
+ patch(
+ "ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.vrf.vrf.get_os_version",
+ return_value="1.5",
+ ).start()
+
+ patch(
+ "ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.bgp_global.bgp_global.get_os_version",
+ return_value="1.5",
+ ).start()
+
+ self.maxDiff = None
+
+ def tearDown(self):
+ super(TestVyosVrfModule, self).tearDown()
+ patch.stopall()
+
+ def load_fixtures(self, commands=None, filename=None):
+ if filename is None:
+ filename = "vyos_vrf_config.cfg"
+
+ def load_from_file(*args, **kwargs):
+ return load_fixture(filename)
+
+ self.mock_execute_show_command.side_effect = load_from_file
+
+ def test_vrf_merged_idempotent(self):
+ set_module_args(
+ dict(
+ config=dict(
+ bind_to_all=True,
+ instances=[
+ dict(
+ name="vrf-blue",
+ description="blue-vrf",
+ disable=False,
+ table_id=100,
+ vni=1000,
+ ),
+ dict(
+ name="vrf-red",
+ description="red-vrf",
+ disable=True,
+ table_id=101,
+ vni=1001,
+ address_family=[
+ dict(
+ afi="ipv4",
+ disable_forwarding=True,
+ route_maps=[
+ dict(rm_name="rm1", protocol="rip"),
+ ],
+ ),
+ dict(
+ afi="ipv6",
+ nht_no_resolve_via_default=True,
+ ),
+ ],
+ protocols=dict(
+ bgp=dict(
+ as_number=65000,
+ neighbor=[
+ dict(
+ address="192.0.2.1",
+ remote_as=65002,
+ ),
+ dict(
+ address="1.1.1.3",
+ remote_as=400,
+ passive=True,
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ state="merged",
+ ),
+ )
+
+ self.execute_module(changed=False, commands=[])
+
+ def test_vrf_merged(self):
+ set_module_args(
+ dict(
+ config=dict(
+ bind_to_all=False,
+ instances=[
+ dict(
+ name="vrf-green",
+ description="green-vrf",
+ table_id=110,
+ vni=1010,
+ protocols=dict(
+ ospf=dict(
+ log_adjacency_changes="detail",
+ max_metric=dict(
+ router_lsa=dict(
+ administrative=True,
+ on_shutdown=10,
+ on_startup=10,
+ ),
+ ),
+ default_information=dict(
+ originate=dict(
+ always=True,
+ metric=10,
+ metric_type=2,
+ ),
+ ),
+ auto_cost=dict(
+ reference_bandwidth=2,
+ ),
+ neighbor=[
+ dict(
+ neighbor_id="192.0.11.12",
+ poll_interval=10,
+ priority=2,
+ ),
+ ],
+ redistribute=[
+ dict(
+ route_type="bgp",
+ metric=10,
+ metric_type=2,
+ ),
+ ],
+ parameters=dict(
+ router_id="192.0.1.1",
+ rfc1583_compatibility=True,
+ abr_type="cisco",
+ ),
+ areas=[
+ dict(
+ area_id="2",
+ area_type=dict(
+ normal=True,
+ ),
+ authentication="plaintext-password",
+ shortcut="enable",
+ ),
+ dict(
+ area_id="3",
+ area_type=dict(
+ nssa=dict(
+ set=True,
+ ),
+ ),
+ ),
+ dict(
+ area_id="4",
+ area_type=dict(
+ stub=dict(
+ default_cost=20,
+ ),
+ ),
+ network=[
+ dict(
+ address="192.0.2.0/24",
+ ),
+ ],
+ range=[
+ dict(
+ address="192.0.3.0/24",
+ cost=10,
+ ),
+ dict(
+ address="192.0.4.0/24",
+ cost=12,
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ state="merged",
+ ),
+ )
+
+ commands = [
+ "delete vrf bind-to-all",
+ "set vrf name vrf-green table 110",
+ "set vrf name vrf-green vni 1010",
+ "set vrf name vrf-green description green-vrf",
+ "set vrf name vrf-green protocols ospf log-adjacency-changes 'detail'",
+ "set vrf name vrf-green protocols ospf max-metric router-lsa administrative",
+ "set vrf name vrf-green protocols ospf max-metric router-lsa on-shutdown 10",
+ "set vrf name vrf-green protocols ospf max-metric router-lsa on-startup 10",
+ "set vrf name vrf-green protocols ospf default-information originate always",
+ "set vrf name vrf-green protocols ospf default-information originate metric 10",
+ "set vrf name vrf-green protocols ospf default-information originate metric-type 2",
+ "set vrf name vrf-green protocols ospf auto-cost reference-bandwidth '2'",
+ "set vrf name vrf-green protocols ospf neighbor 192.0.11.12",
+ "set vrf name vrf-green protocols ospf neighbor 192.0.11.12 poll-interval 10",
+ "set vrf name vrf-green protocols ospf neighbor 192.0.11.12 priority 2",
+ "set vrf name vrf-green protocols ospf redistribute bgp",
+ "set vrf name vrf-green protocols ospf redistribute bgp metric 10",
+ "set vrf name vrf-green protocols ospf redistribute bgp metric-type 2",
+ "set vrf name vrf-green protocols ospf parameters router-id '192.0.1.1'",
+ "set vrf name vrf-green protocols ospf parameters rfc1583-compatibility",
+ "set vrf name vrf-green protocols ospf parameters abr-type 'cisco'",
+ "set vrf name vrf-green protocols ospf area '2'",
+ "set vrf name vrf-green protocols ospf area 2 area-type normal",
+ "set vrf name vrf-green protocols ospf area 2 authentication plaintext-password",
+ "set vrf name vrf-green protocols ospf area 2 shortcut enable",
+ "set vrf name vrf-green protocols ospf area '3'",
+ "set vrf name vrf-green protocols ospf area 3 area-type nssa",
+ "set vrf name vrf-green protocols ospf area '4'",
+ "set vrf name vrf-green protocols ospf area 4 area-type stub default-cost 20",
+ "set vrf name vrf-green protocols ospf area 4 network 192.0.2.0/24",
+ "set vrf name vrf-green protocols ospf area 4 range 192.0.3.0/24",
+ "set vrf name vrf-green protocols ospf area 4 range 192.0.3.0/24 cost 10",
+ "set vrf name vrf-green protocols ospf area 4 range 192.0.4.0/24",
+ "set vrf name vrf-green protocols ospf area 4 range 192.0.4.0/24 cost 12",
+ ]
+
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vrf_replaced(self):
+ set_module_args(
+ dict(
+ config=dict(
+ bind_to_all=True,
+ instances=[
+ dict(
+ name="vrf-blue",
+ description="blue-vrf-replaced",
+ disable=True,
+ table_id=100,
+ vni=1000,
+ ),
+ dict(
+ name="vrf-red",
+ description="red-vrf",
+ disable=True,
+ table_id=101,
+ vni=1001,
+ address_family=[
+ dict(
+ afi="ipv4",
+ disable_forwarding=False,
+ route_maps=[
+ dict(rm_name="rm1", protocol="rip"),
+ ],
+ ),
+ dict(
+ afi="ipv6",
+ nht_no_resolve_via_default=False,
+ ),
+ ],
+ ),
+ ],
+ ),
+ state="replaced",
+ ),
+ )
+ commands = [
+ "set vrf name vrf-blue description blue-vrf-replaced",
+ "set vrf name vrf-blue disable",
+ "delete vrf name vrf-red ip disable-forwarding",
+ "delete vrf name vrf-red ipv6 nht no-resolve-via-default",
+ ]
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vrf_replaced_idempotent(self):
+ set_module_args(
+ dict(
+ config=dict(
+ bind_to_all=True,
+ instances=[
+ dict(
+ name="vrf-blue",
+ description="blue-vrf",
+ disable=False,
+ table_id=100,
+ vni=1000,
+ ),
+ dict(
+ name="vrf-red",
+ description="red-vrf",
+ disable=True,
+ table_id=101,
+ vni=1001,
+ address_family=[
+ dict(
+ afi="ipv4",
+ disable_forwarding=True,
+ route_maps=[
+ dict(rm_name="rm1", protocol="rip"),
+ ],
+ ),
+ dict(
+ afi="ipv6",
+ nht_no_resolve_via_default=True,
+ ),
+ ],
+ ),
+ ],
+ ),
+ state="replaced",
+ ),
+ )
+ self.execute_module(changed=False, commands=[])
+
+ def test_vrf_overridden(self):
+ set_module_args(
+ dict(
+ config=dict(
+ instances=[
+ dict(
+ name="vrf-blue",
+ description="blue-vrf",
+ disable=True,
+ table_id=103,
+ vni=1002,
+ ),
+ dict(
+ name="vrf-red",
+ description="red-vrf",
+ disable=True,
+ table_id=101,
+ vni=1001,
+ protocols=dict(
+ bgp=dict(
+ as_number=65000,
+ neighbor=[
+ dict(
+ address="192.0.2.1",
+ remote_as=65003,
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ state="overridden",
+ ),
+ )
+ commands = [
+ "delete vrf name vrf-blue",
+ "commit",
+ "delete vrf name vrf-red",
+ "commit",
+ "set vrf name vrf-blue table 103",
+ "set vrf name vrf-blue vni 1002",
+ "set vrf name vrf-blue description blue-vrf",
+ "set vrf name vrf-blue disable",
+ "set vrf name vrf-red table 101",
+ "set vrf name vrf-red vni 1001",
+ "set vrf name vrf-red description red-vrf",
+ "set vrf name vrf-red disable",
+ "set vrf name vrf-red protocols bgp system-as 65000",
+ "set vrf name vrf-red protocols bgp neighbor 192.0.2.1 remote-as 65003",
+ "delete vrf bind-to-all",
+ ]
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vrf_overridden_idempotent(self):
+ set_module_args(
+ dict(
+ config=dict(
+ bind_to_all=True,
+ instances=[
+ dict(
+ name="vrf-blue",
+ description="blue-vrf",
+ disable=False,
+ table_id=100,
+ vni=1000,
+ ),
+ dict(
+ name="vrf-red",
+ description="red-vrf",
+ disable=True,
+ table_id=101,
+ vni=1001,
+ address_family=[
+ dict(
+ afi="ipv4",
+ disable_forwarding=True,
+ nht_no_resolve_via_default=False,
+ route_maps=[
+ dict(rm_name="rm1", protocol="rip"),
+ ],
+ ),
+ dict(
+ afi="ipv6",
+ disable_forwarding=False,
+ nht_no_resolve_via_default=True,
+ ),
+ ],
+ protocols=dict(
+ bgp=dict(
+ as_number=65000,
+ neighbor=[
+ dict(
+ address="192.0.2.1",
+ remote_as=65002,
+ ),
+ dict(
+ address="1.1.1.3",
+ remote_as=400,
+ passive=True,
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ state="overridden",
+ ),
+ )
+ self.execute_module(changed=False, commands=[])
+
+ def test_vrf_rendered(self):
+ set_module_args(
+ dict(
+ config=dict(
+ bind_to_all=True,
+ instances=[
+ dict(
+ name="vrf-green",
+ description="green-vrf",
+ disabled=True,
+ table_id=105,
+ vni=1000,
+ ),
+ dict(
+ name="vrf-amber",
+ description="amber-vrf",
+ disable=False,
+ table_id=111,
+ vni=1001,
+ address_family=[
+ dict(
+ afi="ipv4",
+ disable_forwarding=True,
+ route_maps=[
+ dict(rm_name="rm1", protocol="ospf"),
+ ],
+ ),
+ dict(
+ afi="ipv6",
+ nht_no_resolve_via_default=False,
+ ),
+ ],
+ ),
+ ],
+ ),
+ state="rendered",
+ ),
+ )
+ rendered_commands = [
+ "set vrf bind-to-all",
+ "set vrf name vrf-green table 105",
+ "set vrf name vrf-green vni 1000",
+ "set vrf name vrf-green description green-vrf",
+ "set vrf name vrf-green disable",
+ "set vrf name vrf-amber table 111",
+ "set vrf name vrf-amber vni 1001",
+ "set vrf name vrf-amber description amber-vrf",
+ "set vrf name vrf-amber ip protocol ospf route-map rm1",
+ "set vrf name vrf-amber ip disable-forwarding",
+ ]
+ result = self.execute_module(changed=False)
+ self.assertEqual(
+ sorted(result["rendered"]),
+ sorted(rendered_commands),
+ result["rendered"],
+ )
+
+ def test_vrf_parsed(self):
+ commands = (
+ "set vrf bind-to-all",
+ "set vrf name vrf1 description 'red'",
+ "set vrf name vrf1 disable",
+ "set vrf name vrf1 table 101",
+ "set vrf name vrf1 vni 501",
+ "set vrf name vrf2 description 'green'",
+ "set vrf name vrf2 disable",
+ "set vrf name vrf2 table 102",
+ "set vrf name vrf2 vni 102",
+ "set vrf name vrf1 ip disable-forwarding",
+ "set vrf name vrf1 ip nht no-resolve-via-default",
+ "set vrf name vrf-red ip protocol ospf route-map 'rm1'",
+ "set vrf name vrf-red ipv6 nht no-resolve-via-default",
+ )
+ parsed_str = "\n".join(commands)
+ set_module_args(dict(running_config=parsed_str, state="parsed"))
+ result = self.execute_module(changed=False)
+ parsed_list = {
+ "bind_to_all": True,
+ "instances": [
+ {
+ "address_family": [
+ {
+ "afi": "ipv4",
+ "disable_forwarding": True,
+ "nht_no_resolve_via_default": True,
+ },
+ ],
+ "description": "red",
+ "disable": True,
+ "name": "vrf1",
+ },
+ {
+ "description": "green",
+ "disable": True,
+ "name": "vrf2",
+ },
+ {
+ "address_family": [
+ {
+ "afi": "ipv4",
+ "disable_forwarding": False,
+ "nht_no_resolve_via_default": False,
+ "route_maps": [
+ {
+ "protocol": "ospf",
+ "rm_name": "rm1",
+ },
+ ],
+ },
+ {
+ "afi": "ipv6",
+ "disable_forwarding": False,
+ "nht_no_resolve_via_default": True,
+ },
+ ],
+ "disable": False,
+ "name": "vrf-red",
+ },
+ ],
+ }
+ self.assertEqual(parsed_list, result["parsed"])
+
+ def test_vrf_gathered(self):
+ set_module_args(dict(state="gathered"))
+ result = self.execute_module(changed=False)
+ gathered_list = {
+ "bind_to_all": True,
+ "instances": [
+ {
+ "description": "blue-vrf",
+ "disable": False,
+ "name": "vrf-blue",
+ "table_id": 100,
+ "vni": 1000,
+ },
+ {
+ "address_family": [
+ {
+ "afi": "ipv4",
+ "disable_forwarding": True,
+ "nht_no_resolve_via_default": False,
+ "route_maps": [
+ {"protocol": "rip", "rm_name": "rm1"},
+ ],
+ },
+ {
+ "afi": "ipv6",
+ "disable_forwarding": False,
+ "nht_no_resolve_via_default": True,
+ },
+ ],
+ "description": "red-vrf",
+ "disable": True,
+ "name": "vrf-red",
+ "protocols": {
+ "bgp": {
+ "as_number": 65000,
+ "neighbor": [
+ {"address": "1.1.1.3", "passive": True, "remote_as": 400},
+ {"address": "192.0.2.1", "remote_as": 65002},
+ ],
+ },
+ },
+ "table_id": 101,
+ "vni": 1001,
+ },
+ ],
+ }
+ self.assertEqual(gathered_list, result["gathered"])
+
+ def test_vrf_deleted(self):
+ set_module_args(
+ dict(
+ config=dict(
+ bind_to_all=True,
+ instances=[
+ dict(
+ name="vrf-blue",
+ ),
+ ],
+ ),
+ state="deleted",
+ ),
+ )
+ commands = [
+ "delete vrf bind-to-all",
+ "delete vrf name vrf-blue",
+ ]
+ self.execute_module(changed=True, commands=commands)
+
+ def test_vrf_all_deleted(self):
+ set_module_args(
+ dict(
+ state="deleted",
+ ),
+ )
+ commands = [
+ "delete vrf",
+ ]
+ self.execute_module(changed=True, commands=commands)
--
cgit v1.2.3
|