From 8502431fc84346e3f3aa2e8fd557af88bf58b565 Mon Sep 17 00:00:00 2001
From: Shivani-gslab <145646625+Shivani-gslab@users.noreply.github.com>
Date: Thu, 7 Nov 2024 14:05:44 +0530
Subject: [PATCH 1/3] Feat(eos_cli_config_gen): Add support for LSP and CSNP
timers under router_isis (#4619)
---
.../documentation/devices/router-isis-2.md | 7 ++
.../documentation/devices/router-isis-new.md | 10 ++-
.../documentation/devices/router-isis.md | 21 +++++-
.../intended/configs/router-isis-2.cfg | 1 +
.../intended/configs/router-isis-new.cfg | 1 +
.../intended/configs/router-isis.cfg | 6 ++
.../inventory/host_vars/router-isis-2.yml | 4 ++
.../inventory/host_vars/router-isis-new.yml | 4 ++
.../inventory/host_vars/router-isis.yml | 12 ++++
.../documentation/devices/DC1-BL1A.md | 6 +-
.../documentation/devices/DC1-BL1B.md | 6 +-
.../documentation/devices/DC1-LEAF1A.md | 6 +-
.../documentation/devices/DC1-LEAF2A.md | 6 +-
.../documentation/devices/DC1-LEAF2B.md | 6 +-
.../documentation/devices/DC1-SPINE1.md | 6 +-
.../documentation/devices/DC1-SPINE2.md | 6 +-
.../documentation/devices/DC1-SPINE3.md | 6 +-
.../documentation/devices/DC1-SPINE4.md | 6 +-
.../documentation/devices/DC1-SVC3A.md | 6 +-
.../documentation/devices/DC1-SVC3B.md | 6 +-
.../documentation/devices/SITE1-LER1.md | 7 +-
.../documentation/devices/SITE1-LER2.md | 7 +-
.../documentation/devices/SITE1-LSR1.md | 7 +-
.../documentation/devices/SITE1-LSR2.md | 7 +-
.../documentation/devices/SITE1-RR1.md | 7 +-
.../documentation/devices/SITE2-LER1.md | 7 +-
.../documentation/devices/SITE2-LSR1.md | 7 +-
.../documentation/devices/SITE2-LSR2.md | 7 +-
.../documentation/devices/SITE2-RR1.md | 7 +-
.../documentation/devices/SITE3-LER1.md | 7 +-
.../docs/tables/router-isis.md | 44 ++++++++++++
.../j2templates/documentation/router-isis.j2 | 37 +++++++++-
.../j2templates/eos/router-isis.j2 | 25 +++++++
.../schema/eos_cli_config_gen.schema.yml | 70 +++++++++++++++++++
.../schema_fragments/router_isis.schema.yml | 67 ++++++++++++++++++
35 files changed, 397 insertions(+), 48 deletions(-)
diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/router-isis-2.md b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/router-isis-2.md
index 49dd5658bc0..07132005a4a 100644
--- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/router-isis-2.md
+++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/router-isis-2.md
@@ -45,6 +45,12 @@ interface Management1
| -------- | ----- |
| Instance | EVPN_UNDERLAY |
+#### ISIS Route Timers
+
+| Settings | Value |
+| -------- | ----- |
+| LSP Generation Maximum Interval | 30 seconds |
+
#### ISIS Interfaces Summary
| Interface | ISIS Instance | ISIS Metric | Interface Mode |
@@ -57,6 +63,7 @@ interface Management1
router isis EVPN_UNDERLAY
set-overload-bit
set-overload-bit on-startup 55
+ timers lsp generation 30
authentication mode sha key-id 4 rx-disabled
!
```
diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/router-isis-new.md b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/router-isis-new.md
index 7d277cfae7e..d0d681caa98 100644
--- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/router-isis-new.md
+++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/router-isis-new.md
@@ -194,7 +194,6 @@ interface Vlan4094
| Instance | EVPN_UNDERLAY |
| Log Adjacency Changes | False |
| MPLS LDP Sync Default | True |
-| Local Convergence Delay (ms) | 10000 |
| Advertise Passive-only | True |
| SR MPLS Enabled | True |
| SPF Interval | 250 seconds |
@@ -205,6 +204,14 @@ interface Vlan4094
| Graceful-restart t2 Level-2 | 20 |
| Graceful-restart Restart-hold-time | 10 |
+#### ISIS Route Timers
+
+| Settings | Value |
+| -------- | ----- |
+| Local Convergence Delay | 10000 milliseconds |
+| LSP Generation Maximum Interval | 30 seconds |
+| LSP Generation Initial Wait-time | 40 milliseconds |
+
#### ISIS Route Redistribution
| Route Type | Route-Map | Include Leaked |
@@ -282,6 +289,7 @@ router isis EVPN_UNDERLAY
set-overload-bit
advertise passive-only
spf-interval 250 seconds 10 milliseconds 20 milliseconds
+ timers lsp generation 30 40
authentication mode shared-secret profile test1 algorithm md5 level-1
authentication mode sha key-id 2 level-2
graceful-restart
diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/router-isis.md b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/router-isis.md
index fda57c11f04..1586cb655dd 100644
--- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/router-isis.md
+++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/router-isis.md
@@ -281,11 +281,24 @@ interface Vlan4094
| Type | level-2 |
| Router-ID | 192.168.255.3 |
| Log Adjacency Changes | True |
-| Local Convergence Delay (ms) | 15000 |
| Advertise Passive-only | True |
| SR MPLS Enabled | False |
| SPF Interval | 250 seconds |
+#### ISIS Route Timers
+
+| Settings | Value |
+| -------- | ----- |
+| Local Convergence Delay | 15000 milliseconds |
+| CSN Packet Transmission Interval | 10 seconds |
+| CSN Packet P2P Links Disabled | True |
+| LSP Generation Maximum Interval | 30 seconds |
+| LSP Generation Initial Wait-time | 40 milliseconds |
+| LSP Generation Wait-time | 50 milliseconds |
+| LSP Out-delay | 20 milliseconds |
+| LSP Refresh Interval | 56 seconds |
+| LSP Minimum Remaining Lifetime | 78 seconds |
+
#### ISIS Route Redistribution
| Route Type | Route-Map | Include Leaked |
@@ -352,6 +365,12 @@ router isis EVPN_UNDERLAY
set-overload-bit on-startup wait-for-bgp
advertise passive-only
spf-interval 250
+ timers csnp generation interval 10 seconds
+ timers csnp generation p2p disabled
+ timers lsp out-delay 20
+ timers lsp refresh 56
+ timers lsp generation 30 40 50
+ timers lsp min-remaining-lifetime 78
authentication mode sha key-id 5 rx-disabled level-1
authentication mode shared-secret profile test2 algorithm md5 rx-disabled level-2
authentication key 0 password
diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/router-isis-2.cfg b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/router-isis-2.cfg
index b45e1df447e..08adebcbf19 100644
--- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/router-isis-2.cfg
+++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/router-isis-2.cfg
@@ -7,5 +7,6 @@ interface Management1
router isis EVPN_UNDERLAY
set-overload-bit
set-overload-bit on-startup 55
+ timers lsp generation 30
authentication mode sha key-id 4 rx-disabled
!
diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/router-isis-new.cfg b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/router-isis-new.cfg
index f406824400d..c4edb58bcc6 100644
--- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/router-isis-new.cfg
+++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/router-isis-new.cfg
@@ -71,6 +71,7 @@ router isis EVPN_UNDERLAY
set-overload-bit
advertise passive-only
spf-interval 250 seconds 10 milliseconds 20 milliseconds
+ timers lsp generation 30 40
authentication mode shared-secret profile test1 algorithm md5 level-1
authentication mode sha key-id 2 level-2
graceful-restart
diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/router-isis.cfg b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/router-isis.cfg
index b92ac671374..61067928546 100644
--- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/router-isis.cfg
+++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/router-isis.cfg
@@ -108,6 +108,12 @@ router isis EVPN_UNDERLAY
set-overload-bit on-startup wait-for-bgp
advertise passive-only
spf-interval 250
+ timers csnp generation interval 10 seconds
+ timers csnp generation p2p disabled
+ timers lsp out-delay 20
+ timers lsp refresh 56
+ timers lsp generation 30 40 50
+ timers lsp min-remaining-lifetime 78
authentication mode sha key-id 5 rx-disabled level-1
authentication mode shared-secret profile test2 algorithm md5 rx-disabled level-2
authentication key 0 password
diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/router-isis-2.yml b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/router-isis-2.yml
index d009055aef4..1c9b45328f6 100644
--- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/router-isis-2.yml
+++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/router-isis-2.yml
@@ -4,6 +4,10 @@ router_isis:
enabled: true
on_startup:
delay: 55
+ timers:
+ lsp:
+ generation:
+ interval: 30
authentication:
both:
key_type: 0
diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/router-isis-new.yml b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/router-isis-new.yml
index 5ab2e962757..a289f5205de 100644
--- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/router-isis-new.yml
+++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/router-isis-new.yml
@@ -17,6 +17,10 @@ router_isis:
timers:
local_convergence:
protected_prefixes: true
+ lsp:
+ generation:
+ interval: 30
+ initial_wait_time: 40
advertise:
passive_only: true
redistribute_routes:
diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/router-isis.yml b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/router-isis.yml
index 0bab20e51f7..22aecdb4b7f 100644
--- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/router-isis.yml
+++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/router-isis.yml
@@ -14,6 +14,18 @@ router_isis:
local_convergence:
protected_prefixes: true
delay: 15000
+ csnp:
+ generation:
+ interval: 10
+ p2p_disabled: true
+ lsp:
+ out_delay: 20
+ refresh_interval: 56
+ generation:
+ interval: 30
+ initial_wait_time: 40
+ wait_time: 50
+ min_remaining_lifetime: 78
advertise:
passive_only: true
redistribute_routes:
diff --git a/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-BL1A.md b/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-BL1A.md
index 6feb69861ec..5f39892b7e3 100644
--- a/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-BL1A.md
+++ b/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-BL1A.md
@@ -690,9 +690,9 @@ ASN Notation: asplain
##### EVPN Peer Groups
-| Peer Group | Activate | Encapsulation |
-| ---------- | -------- | ------------- |
-| EVPN-OVERLAY-PEERS | True | default |
+| Peer Group | Activate | Route-map In | Route-map Out | Encapsulation |
+| ---------- | -------- | ------------ | ------------- | ------------- |
+| EVPN-OVERLAY-PEERS | True | - | - | default |
#### Router BGP VLAN Aware Bundles
diff --git a/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-BL1B.md b/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-BL1B.md
index 2563c18cfeb..8b1b3e76354 100644
--- a/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-BL1B.md
+++ b/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-BL1B.md
@@ -690,9 +690,9 @@ ASN Notation: asplain
##### EVPN Peer Groups
-| Peer Group | Activate | Encapsulation |
-| ---------- | -------- | ------------- |
-| EVPN-OVERLAY-PEERS | True | default |
+| Peer Group | Activate | Route-map In | Route-map Out | Encapsulation |
+| ---------- | -------- | ------------ | ------------- | ------------- |
+| EVPN-OVERLAY-PEERS | True | - | - | default |
#### Router BGP VLAN Aware Bundles
diff --git a/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-LEAF1A.md b/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-LEAF1A.md
index 31113b01356..98e7a334a77 100644
--- a/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-LEAF1A.md
+++ b/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-LEAF1A.md
@@ -566,9 +566,9 @@ ASN Notation: asplain
##### EVPN Peer Groups
-| Peer Group | Activate | Encapsulation |
-| ---------- | -------- | ------------- |
-| EVPN-OVERLAY-PEERS | True | default |
+| Peer Group | Activate | Route-map In | Route-map Out | Encapsulation |
+| ---------- | -------- | ------------ | ------------- | ------------- |
+| EVPN-OVERLAY-PEERS | True | - | - | default |
#### Router BGP VLAN Aware Bundles
diff --git a/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-LEAF2A.md b/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-LEAF2A.md
index a3846007d25..df8564f6cdc 100644
--- a/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-LEAF2A.md
+++ b/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-LEAF2A.md
@@ -920,9 +920,9 @@ ASN Notation: asplain
##### EVPN Peer Groups
-| Peer Group | Activate | Encapsulation |
-| ---------- | -------- | ------------- |
-| EVPN-OVERLAY-PEERS | True | default |
+| Peer Group | Activate | Route-map In | Route-map Out | Encapsulation |
+| ---------- | -------- | ------------ | ------------- | ------------- |
+| EVPN-OVERLAY-PEERS | True | - | - | default |
#### Router BGP VLAN Aware Bundles
diff --git a/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-LEAF2B.md b/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-LEAF2B.md
index a6643c3d023..660f78de080 100644
--- a/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-LEAF2B.md
+++ b/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-LEAF2B.md
@@ -920,9 +920,9 @@ ASN Notation: asplain
##### EVPN Peer Groups
-| Peer Group | Activate | Encapsulation |
-| ---------- | -------- | ------------- |
-| EVPN-OVERLAY-PEERS | True | default |
+| Peer Group | Activate | Route-map In | Route-map Out | Encapsulation |
+| ---------- | -------- | ------------ | ------------- | ------------- |
+| EVPN-OVERLAY-PEERS | True | - | - | default |
#### Router BGP VLAN Aware Bundles
diff --git a/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SPINE1.md b/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SPINE1.md
index d54b21e2659..e7e5b9ce234 100644
--- a/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SPINE1.md
+++ b/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SPINE1.md
@@ -420,9 +420,9 @@ ASN Notation: asplain
##### EVPN Peer Groups
-| Peer Group | Activate | Encapsulation |
-| ---------- | -------- | ------------- |
-| EVPN-OVERLAY-PEERS | True | default |
+| Peer Group | Activate | Route-map In | Route-map Out | Encapsulation |
+| ---------- | -------- | ------------ | ------------- | ------------- |
+| EVPN-OVERLAY-PEERS | True | - | - | default |
#### Router BGP Device Configuration
diff --git a/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SPINE2.md b/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SPINE2.md
index ba041364330..5dbde9614ed 100644
--- a/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SPINE2.md
+++ b/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SPINE2.md
@@ -420,9 +420,9 @@ ASN Notation: asplain
##### EVPN Peer Groups
-| Peer Group | Activate | Encapsulation |
-| ---------- | -------- | ------------- |
-| EVPN-OVERLAY-PEERS | True | default |
+| Peer Group | Activate | Route-map In | Route-map Out | Encapsulation |
+| ---------- | -------- | ------------ | ------------- | ------------- |
+| EVPN-OVERLAY-PEERS | True | - | - | default |
#### Router BGP Device Configuration
diff --git a/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SPINE3.md b/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SPINE3.md
index 118ce0a9605..bf9eea2d6bf 100644
--- a/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SPINE3.md
+++ b/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SPINE3.md
@@ -420,9 +420,9 @@ ASN Notation: asplain
##### EVPN Peer Groups
-| Peer Group | Activate | Encapsulation |
-| ---------- | -------- | ------------- |
-| EVPN-OVERLAY-PEERS | True | default |
+| Peer Group | Activate | Route-map In | Route-map Out | Encapsulation |
+| ---------- | -------- | ------------ | ------------- | ------------- |
+| EVPN-OVERLAY-PEERS | True | - | - | default |
#### Router BGP Device Configuration
diff --git a/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SPINE4.md b/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SPINE4.md
index ccfeed22327..8a45a95352b 100644
--- a/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SPINE4.md
+++ b/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SPINE4.md
@@ -420,9 +420,9 @@ ASN Notation: asplain
##### EVPN Peer Groups
-| Peer Group | Activate | Encapsulation |
-| ---------- | -------- | ------------- |
-| EVPN-OVERLAY-PEERS | True | default |
+| Peer Group | Activate | Route-map In | Route-map Out | Encapsulation |
+| ---------- | -------- | ------------ | ------------- | ------------- |
+| EVPN-OVERLAY-PEERS | True | - | - | default |
#### Router BGP Device Configuration
diff --git a/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SVC3A.md b/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SVC3A.md
index 9bda09b73b7..d168f4869bb 100644
--- a/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SVC3A.md
+++ b/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SVC3A.md
@@ -1040,9 +1040,9 @@ ASN Notation: asplain
##### EVPN Peer Groups
-| Peer Group | Activate | Encapsulation |
-| ---------- | -------- | ------------- |
-| EVPN-OVERLAY-PEERS | True | default |
+| Peer Group | Activate | Route-map In | Route-map Out | Encapsulation |
+| ---------- | -------- | ------------ | ------------- | ------------- |
+| EVPN-OVERLAY-PEERS | True | - | - | default |
#### Router BGP VLAN Aware Bundles
diff --git a/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SVC3B.md b/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SVC3B.md
index 1bd39e7e092..98b49bfff54 100644
--- a/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SVC3B.md
+++ b/ansible_collections/arista/avd/molecule/eos_config_deploy_cvp/documentation/devices/DC1-SVC3B.md
@@ -1013,9 +1013,9 @@ ASN Notation: asplain
##### EVPN Peer Groups
-| Peer Group | Activate | Encapsulation |
-| ---------- | -------- | ------------- |
-| EVPN-OVERLAY-PEERS | True | default |
+| Peer Group | Activate | Route-map In | Route-map Out | Encapsulation |
+| ---------- | -------- | ------------ | ------------- | ------------- |
+| EVPN-OVERLAY-PEERS | True | - | - | default |
#### Router BGP VLAN Aware Bundles
diff --git a/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE1-LER1.md b/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE1-LER1.md
index 93707bdabd2..0eb9f15d5f2 100644
--- a/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE1-LER1.md
+++ b/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE1-LER1.md
@@ -560,10 +560,15 @@ router ospf 19 vrf TENANT_B_INTRA
| Router-ID | 100.70.0.5 |
| Log Adjacency Changes | True |
| MPLS LDP Sync Default | True |
-| Local Convergence Delay (ms) | 15000 |
| Advertise Passive-only | True |
| SR MPLS Enabled | True |
+#### ISIS Route Timers
+
+| Settings | Value |
+| -------- | ----- |
+| Local Convergence Delay | 15000 milliseconds |
+
#### ISIS Interfaces Summary
| Interface | ISIS Instance | ISIS Metric | Interface Mode |
diff --git a/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE1-LER2.md b/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE1-LER2.md
index 8023886adb2..c6c71d4b749 100644
--- a/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE1-LER2.md
+++ b/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE1-LER2.md
@@ -525,10 +525,15 @@ ip route vrf MGMT 0.0.0.0/0 192.168.200.5
| Router-ID | 100.70.0.6 |
| Log Adjacency Changes | True |
| MPLS LDP Sync Default | True |
-| Local Convergence Delay (ms) | 15000 |
| Advertise Passive-only | True |
| SR MPLS Enabled | True |
+#### ISIS Route Timers
+
+| Settings | Value |
+| -------- | ----- |
+| Local Convergence Delay | 15000 milliseconds |
+
#### ISIS Interfaces Summary
| Interface | ISIS Instance | ISIS Metric | Interface Mode |
diff --git a/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE1-LSR1.md b/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE1-LSR1.md
index 00290755453..1657aa260a1 100644
--- a/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE1-LSR1.md
+++ b/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE1-LSR1.md
@@ -333,10 +333,15 @@ ip route vrf MGMT 0.0.0.0/0 192.168.200.5
| Router-ID | 100.70.0.1 |
| Log Adjacency Changes | True |
| MPLS LDP Sync Default | True |
-| Local Convergence Delay (ms) | 15000 |
| Advertise Passive-only | True |
| SR MPLS Enabled | True |
+#### ISIS Route Timers
+
+| Settings | Value |
+| -------- | ----- |
+| Local Convergence Delay | 15000 milliseconds |
+
#### ISIS Interfaces Summary
| Interface | ISIS Instance | ISIS Metric | Interface Mode |
diff --git a/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE1-LSR2.md b/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE1-LSR2.md
index 8807fca1dc2..1d6a909ec98 100644
--- a/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE1-LSR2.md
+++ b/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE1-LSR2.md
@@ -309,10 +309,15 @@ ip route vrf MGMT 0.0.0.0/0 192.168.200.5
| Router-ID | 100.70.0.2 |
| Log Adjacency Changes | True |
| MPLS LDP Sync Default | True |
-| Local Convergence Delay (ms) | 15000 |
| Advertise Passive-only | True |
| SR MPLS Enabled | True |
+#### ISIS Route Timers
+
+| Settings | Value |
+| -------- | ----- |
+| Local Convergence Delay | 15000 milliseconds |
+
#### ISIS Interfaces Summary
| Interface | ISIS Instance | ISIS Metric | Interface Mode |
diff --git a/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE1-RR1.md b/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE1-RR1.md
index ce63c726cf3..94352209b52 100644
--- a/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE1-RR1.md
+++ b/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE1-RR1.md
@@ -288,10 +288,15 @@ ip route vrf MGMT 0.0.0.0/0 192.168.200.5
| Router-ID | 100.70.0.8 |
| Log Adjacency Changes | True |
| MPLS LDP Sync Default | True |
-| Local Convergence Delay (ms) | 15000 |
| Advertise Passive-only | True |
| SR MPLS Enabled | True |
+#### ISIS Route Timers
+
+| Settings | Value |
+| -------- | ----- |
+| Local Convergence Delay | 15000 milliseconds |
+
#### ISIS Interfaces Summary
| Interface | ISIS Instance | ISIS Metric | Interface Mode |
diff --git a/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE2-LER1.md b/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE2-LER1.md
index fc7322f5ffc..f463525b357 100644
--- a/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE2-LER1.md
+++ b/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE2-LER1.md
@@ -628,10 +628,15 @@ router ospf 99 vrf TENANT_B_WAN
| Router-ID | 100.70.0.7 |
| Log Adjacency Changes | True |
| MPLS LDP Sync Default | True |
-| Local Convergence Delay (ms) | 15000 |
| Advertise Passive-only | True |
| SR MPLS Enabled | True |
+#### ISIS Route Timers
+
+| Settings | Value |
+| -------- | ----- |
+| Local Convergence Delay | 15000 milliseconds |
+
#### ISIS Interfaces Summary
| Interface | ISIS Instance | ISIS Metric | Interface Mode |
diff --git a/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE2-LSR1.md b/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE2-LSR1.md
index 77cbcc0f53e..774da3217fa 100644
--- a/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE2-LSR1.md
+++ b/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE2-LSR1.md
@@ -333,10 +333,15 @@ ip route vrf MGMT 0.0.0.0/0 192.168.200.5
| Router-ID | 100.70.0.3 |
| Log Adjacency Changes | True |
| MPLS LDP Sync Default | True |
-| Local Convergence Delay (ms) | 15000 |
| Advertise Passive-only | True |
| SR MPLS Enabled | True |
+#### ISIS Route Timers
+
+| Settings | Value |
+| -------- | ----- |
+| Local Convergence Delay | 15000 milliseconds |
+
#### ISIS Interfaces Summary
| Interface | ISIS Instance | ISIS Metric | Interface Mode |
diff --git a/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE2-LSR2.md b/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE2-LSR2.md
index 14c5750d42b..0420c63bbf6 100644
--- a/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE2-LSR2.md
+++ b/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE2-LSR2.md
@@ -396,10 +396,15 @@ ip route vrf MGMT 0.0.0.0/0 192.168.200.5
| Router-ID | 100.70.0.4 |
| Log Adjacency Changes | True |
| MPLS LDP Sync Default | True |
-| Local Convergence Delay (ms) | 15000 |
| Advertise Passive-only | True |
| SR MPLS Enabled | True |
+#### ISIS Route Timers
+
+| Settings | Value |
+| -------- | ----- |
+| Local Convergence Delay | 15000 milliseconds |
+
#### ISIS Interfaces Summary
| Interface | ISIS Instance | ISIS Metric | Interface Mode |
diff --git a/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE2-RR1.md b/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE2-RR1.md
index e2823cd95ad..112ebf34ba2 100644
--- a/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE2-RR1.md
+++ b/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE2-RR1.md
@@ -288,10 +288,15 @@ ip route vrf MGMT 0.0.0.0/0 192.168.200.5
| Router-ID | 100.70.0.9 |
| Log Adjacency Changes | True |
| MPLS LDP Sync Default | True |
-| Local Convergence Delay (ms) | 15000 |
| Advertise Passive-only | True |
| SR MPLS Enabled | True |
+#### ISIS Route Timers
+
+| Settings | Value |
+| -------- | ----- |
+| Local Convergence Delay | 15000 milliseconds |
+
#### ISIS Interfaces Summary
| Interface | ISIS Instance | ISIS Metric | Interface Mode |
diff --git a/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE3-LER1.md b/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE3-LER1.md
index 3d59fc72e88..380f046bbfc 100644
--- a/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE3-LER1.md
+++ b/ansible_collections/arista/avd/molecule/eos_designs-mpls-isis-sr-ldp/documentation/devices/SITE3-LER1.md
@@ -252,10 +252,15 @@ ip route vrf MGMT 0.0.0.0/0 192.168.200.5
| Router-ID | 100.70.0.10 |
| Log Adjacency Changes | True |
| MPLS LDP Sync Default | True |
-| Local Convergence Delay (ms) | 15000 |
| Advertise Passive-only | True |
| SR MPLS Enabled | True |
+#### ISIS Route Timers
+
+| Settings | Value |
+| -------- | ----- |
+| Local Convergence Delay | 15000 milliseconds |
+
#### ISIS Interfaces Summary
| Interface | ISIS Instance | ISIS Metric | Interface Mode |
diff --git a/ansible_collections/arista/avd/roles/eos_cli_config_gen/docs/tables/router-isis.md b/ansible_collections/arista/avd/roles/eos_cli_config_gen/docs/tables/router-isis.md
index 02a7c7bba0f..ad6b2ea856e 100644
--- a/ansible_collections/arista/avd/roles/eos_cli_config_gen/docs/tables/router-isis.md
+++ b/ansible_collections/arista/avd/roles/eos_cli_config_gen/docs/tables/router-isis.md
@@ -18,6 +18,18 @@
| [ local_convergence](## "router_isis.timers.local_convergence") | Dictionary | | | | |
| [ protected_prefixes](## "router_isis.timers.local_convergence.protected_prefixes") | Boolean | | | | |
| [ delay](## "router_isis.timers.local_convergence.delay") | Integer | | `10000` | | Delay in milliseconds. |
+ | [ lsp](## "router_isis.timers.lsp") | Dictionary | | | | Link State Packet timers. |
+ | [ generation](## "router_isis.timers.lsp.generation") | Dictionary | | | | |
+ | [ interval](## "router_isis.timers.lsp.generation.interval") | Integer | Required | | Min: 1
Max: 300 | Maximum interval (in seconds) between generating two LSPs. |
+ | [ initial_wait_time](## "router_isis.timers.lsp.generation.initial_wait_time") | Integer | | | Min: 1
Max: 300000 | Initial wait time (in milliseconds) before generating LSPs. |
+ | [ wait_time](## "router_isis.timers.lsp.generation.wait_time") | Integer | | | Min: 1
Max: 300000 | Wait time (in milliseconds) between generating the first and second LSPs. |
+ | [ out_delay](## "router_isis.timers.lsp.out_delay") | Integer | | | Min: 1
Max: 65000 | Transmit delay (in milliseconds) for link state packets. |
+ | [ refresh_interval](## "router_isis.timers.lsp.refresh_interval") | Integer | | | Min: 30
Max: 65535 | Interval (in seconds) between two LSP refreshes. |
+ | [ min_remaining_lifetime](## "router_isis.timers.lsp.min_remaining_lifetime") | Integer | | | Min: 60
Max: 65535 | Minimum remaining lifetime for LSPs (in seconds). |
+ | [ csnp](## "router_isis.timers.csnp") | Dictionary | | | | CSN Packet timers. |
+ | [ generation](## "router_isis.timers.csnp.generation") | Dictionary | | | | |
+ | [ interval](## "router_isis.timers.csnp.generation.interval") | Integer | | | Min: 1
Max: 300 | Transmit frequency (in seconds) for CSN packets. |
+ | [ p2p_disabled](## "router_isis.timers.csnp.generation.p2p_disabled") | Boolean | | | | Disable periodic CSN packets for P2P links. |
| [ set_overload_bit](## "router_isis.set_overload_bit") | Dictionary | | | | |
| [ enabled](## "router_isis.set_overload_bit.enabled") | Boolean | | | | |
| [ on_startup](## "router_isis.set_overload_bit.on_startup") | Dictionary | | | | |
@@ -147,6 +159,38 @@
# Delay in milliseconds.
delay:
+
+ # Link State Packet timers.
+ lsp:
+ generation:
+
+ # Maximum interval (in seconds) between generating two LSPs.
+ interval:
+
+ # Initial wait time (in milliseconds) before generating LSPs.
+ initial_wait_time:
+
+ # Wait time (in milliseconds) between generating the first and second LSPs.
+ wait_time:
+
+ # Transmit delay (in milliseconds) for link state packets.
+ out_delay:
+
+ # Interval (in seconds) between two LSP refreshes.
+ refresh_interval:
+
+ # Minimum remaining lifetime for LSPs (in seconds).
+ min_remaining_lifetime:
+
+ # CSN Packet timers.
+ csnp:
+ generation:
+
+ # Transmit frequency (in seconds) for CSN packets.
+ interval:
+
+ # Disable periodic CSN packets for P2P links.
+ p2p_disabled:
set_overload_bit:
enabled:
on_startup:
diff --git a/python-avd/pyavd/_eos_cli_config_gen/j2templates/documentation/router-isis.j2 b/python-avd/pyavd/_eos_cli_config_gen/j2templates/documentation/router-isis.j2
index 9acdfb4691a..f423620878b 100644
--- a/python-avd/pyavd/_eos_cli_config_gen/j2templates/documentation/router-isis.j2
+++ b/python-avd/pyavd/_eos_cli_config_gen/j2templates/documentation/router-isis.j2
@@ -30,9 +30,6 @@
{% if router_isis.mpls_ldp_sync_default is arista.avd.defined(true) %}
| MPLS LDP Sync Default | {{ router_isis.mpls_ldp_sync_default }} |
{% endif %}
-{% if router_isis.timers.local_convergence.protected_prefixes is arista.avd.defined(true) %}
-| Local Convergence Delay (ms) | {{ router_isis.timers.local_convergence.delay | arista.avd.default(10000) }} |
-{% endif %}
{% if router_isis.advertise.passive_only is arista.avd.defined(true) %}
| Advertise Passive-only | {{ router_isis.advertise.passive_only }} |
{% endif %}
@@ -62,6 +59,40 @@
| Graceful-restart Restart-hold-time | {{ router_isis.graceful_restart.restart_hold_time }} |
{% endif %}
{% endif %}
+{% if router_isis.timers is arista.avd.defined %}
+
+#### ISIS Route Timers
+
+| Settings | Value |
+| -------- | ----- |
+{% if router_isis.timers.local_convergence.protected_prefixes is arista.avd.defined(true) %}
+| Local Convergence Delay | {{ router_isis.timers.local_convergence.delay | arista.avd.default(10000) }} milliseconds |
+{% endif %}
+{% if router_isis.timers.csnp.generation.interval is arista.avd.defined %}
+| CSN Packet Transmission Interval | {{ router_isis.timers.csnp.generation.interval }} seconds |
+{% endif %}
+{% if router_isis.timers.csnp.generation.p2p_disabled is arista.avd.defined %}
+| CSN Packet P2P Links Disabled | {{ router_isis.timers.csnp.generation.p2p_disabled }} |
+{% endif %}
+{% if router_isis.timers.lsp.generation.interval is arista.avd.defined %}
+| LSP Generation Maximum Interval | {{ router_isis.timers.lsp.generation.interval }} seconds |
+{% endif %}
+{% if router_isis.timers.lsp.generation.initial_wait_time is arista.avd.defined %}
+| LSP Generation Initial Wait-time | {{ router_isis.timers.lsp.generation.initial_wait_time }} milliseconds |
+{% endif %}
+{% if router_isis.timers.lsp.generation.wait_time is arista.avd.defined %}
+| LSP Generation Wait-time | {{ router_isis.timers.lsp.generation.wait_time }} milliseconds |
+{% endif %}
+{% if router_isis.timers.lsp.out_delay is arista.avd.defined %}
+| LSP Out-delay | {{ router_isis.timers.lsp.out_delay }} milliseconds |
+{% endif %}
+{% if router_isis.timers.lsp.refresh_interval is arista.avd.defined %}
+| LSP Refresh Interval | {{ router_isis.timers.lsp.refresh_interval }} seconds |
+{% endif %}
+{% if router_isis.timers.lsp.min_remaining_lifetime is arista.avd.defined %}
+| LSP Minimum Remaining Lifetime | {{ router_isis.timers.lsp.min_remaining_lifetime }} seconds |
+{% endif %}
+{% endif %}
{% if router_isis.redistribute_routes is arista.avd.defined %}
#### ISIS Route Redistribution
diff --git a/python-avd/pyavd/_eos_cli_config_gen/j2templates/eos/router-isis.j2 b/python-avd/pyavd/_eos_cli_config_gen/j2templates/eos/router-isis.j2
index 36f3d6f7768..46b10c24c47 100644
--- a/python-avd/pyavd/_eos_cli_config_gen/j2templates/eos/router-isis.j2
+++ b/python-avd/pyavd/_eos_cli_config_gen/j2templates/eos/router-isis.j2
@@ -91,6 +91,31 @@ router isis {{ router_isis.instance }}
{% endif %}
{{ spf_interval_cli }}
{% endif %}
+{% if router_isis.timers.csnp.generation.interval is arista.avd.defined %}
+ timers csnp generation interval {{ router_isis.timers.csnp.generation.interval }} seconds
+{% endif %}
+{% if router_isis.timers.csnp.generation.p2p_disabled is arista.avd.defined(true) %}
+ timers csnp generation p2p disabled
+{% endif %}
+{% if router_isis.timers.lsp.out_delay is arista.avd.defined %}
+ timers lsp out-delay {{ router_isis.timers.lsp.out_delay }}
+{% endif %}
+{% if router_isis.timers.lsp.refresh_interval is arista.avd.defined %}
+ timers lsp refresh {{ router_isis.timers.lsp.refresh_interval }}
+{% endif %}
+{% if router_isis.timers.lsp.generation.interval is arista.avd.defined %}
+{% set timers_lsp_generation = "timers lsp generation " ~ router_isis.timers.lsp.generation.interval %}
+{% if router_isis.timers.lsp.generation.initial_wait_time is arista.avd.defined %}
+{% set timers_lsp_generation = timers_lsp_generation ~ " " ~ router_isis.timers.lsp.generation.initial_wait_time %}
+{% if router_isis.timers.lsp.generation.wait_time is arista.avd.defined %}
+{% set timers_lsp_generation = timers_lsp_generation ~ " " ~ router_isis.timers.lsp.generation.wait_time %}
+{% endif %}
+{% endif %}
+ {{ timers_lsp_generation }}
+{% endif %}
+{% if router_isis.timers.lsp.min_remaining_lifetime is arista.avd.defined %}
+ timers lsp min-remaining-lifetime {{ router_isis.timers.lsp.min_remaining_lifetime }}
+{% endif %}
{% if router_isis.authentication.both.mode is arista.avd.defined
and (router_isis.authentication.both.mode in ["md5", "text"]
or (router_isis.authentication.both.mode == "sha" and router_isis.authentication.both.sha.key_id is arista.avd.defined)
diff --git a/python-avd/pyavd/_eos_cli_config_gen/schema/eos_cli_config_gen.schema.yml b/python-avd/pyavd/_eos_cli_config_gen/schema/eos_cli_config_gen.schema.yml
index 888dbcde951..0f4a82a5e4d 100644
--- a/python-avd/pyavd/_eos_cli_config_gen/schema/eos_cli_config_gen.schema.yml
+++ b/python-avd/pyavd/_eos_cli_config_gen/schema/eos_cli_config_gen.schema.yml
@@ -17884,6 +17884,76 @@ keys:
- str
default: 10000
description: Delay in milliseconds.
+ lsp:
+ description: Link State Packet timers.
+ type: dict
+ keys:
+ generation:
+ type: dict
+ keys:
+ interval:
+ type: int
+ convert_types:
+ - str
+ min: 1
+ max: 300
+ required: true
+ description: Maximum interval (in seconds) between generating
+ two LSPs.
+ initial_wait_time:
+ type: int
+ convert_types:
+ - str
+ min: 1
+ max: 300000
+ description: Initial wait time (in milliseconds) before generating
+ LSPs.
+ wait_time:
+ type: int
+ convert_types:
+ - str
+ min: 1
+ max: 300000
+ description: Wait time (in milliseconds) between generating the
+ first and second LSPs.
+ out_delay:
+ type: int
+ convert_types:
+ - str
+ min: 1
+ max: 65000
+ description: Transmit delay (in milliseconds) for link state packets.
+ refresh_interval:
+ type: int
+ convert_types:
+ - str
+ min: 30
+ max: 65535
+ description: Interval (in seconds) between two LSP refreshes.
+ min_remaining_lifetime:
+ type: int
+ convert_types:
+ - str
+ min: 60
+ max: 65535
+ description: Minimum remaining lifetime for LSPs (in seconds).
+ csnp:
+ type: dict
+ description: CSN Packet timers.
+ keys:
+ generation:
+ type: dict
+ keys:
+ interval:
+ type: int
+ convert_types:
+ - str
+ min: 1
+ max: 300
+ description: Transmit frequency (in seconds) for CSN packets.
+ p2p_disabled:
+ type: bool
+ description: Disable periodic CSN packets for P2P links.
set_overload_bit:
type: dict
keys:
diff --git a/python-avd/pyavd/_eos_cli_config_gen/schema/schema_fragments/router_isis.schema.yml b/python-avd/pyavd/_eos_cli_config_gen/schema/schema_fragments/router_isis.schema.yml
index 2348a8dd713..b7837d870ca 100644
--- a/python-avd/pyavd/_eos_cli_config_gen/schema/schema_fragments/router_isis.schema.yml
+++ b/python-avd/pyavd/_eos_cli_config_gen/schema/schema_fragments/router_isis.schema.yml
@@ -44,6 +44,73 @@ keys:
- str
default: 10000
description: Delay in milliseconds.
+ lsp:
+ description: Link State Packet timers.
+ type: dict
+ keys:
+ generation:
+ type: dict
+ keys:
+ interval:
+ type: int
+ convert_types:
+ - str
+ min: 1
+ max: 300
+ required: true
+ description: Maximum interval (in seconds) between generating two LSPs.
+ initial_wait_time:
+ type: int
+ convert_types:
+ - str
+ min: 1
+ max: 300000
+ description: Initial wait time (in milliseconds) before generating LSPs.
+ wait_time:
+ type: int
+ convert_types:
+ - str
+ min: 1
+ max: 300000
+ description: Wait time (in milliseconds) between generating the first and second LSPs.
+ out_delay:
+ type: int
+ convert_types:
+ - str
+ min: 1
+ max: 65000
+ description: Transmit delay (in milliseconds) for link state packets.
+ refresh_interval:
+ type: int
+ convert_types:
+ - str
+ min: 30
+ max: 65535
+ description: Interval (in seconds) between two LSP refreshes.
+ min_remaining_lifetime:
+ type: int
+ convert_types:
+ - str
+ min: 60
+ max: 65535
+ description: Minimum remaining lifetime for LSPs (in seconds).
+ csnp:
+ type: dict
+ description: CSN Packet timers.
+ keys:
+ generation:
+ type: dict
+ keys:
+ interval:
+ type: int
+ convert_types:
+ - str
+ min: 1
+ max: 300
+ description: Transmit frequency (in seconds) for CSN packets.
+ p2p_disabled:
+ type: bool
+ description: Disable periodic CSN packets for P2P links.
set_overload_bit:
type: dict
keys:
From f22b00261384404e0d814451df7619473e820310 Mon Sep 17 00:00:00 2001
From: laxmikantchintakindi
<159624484+laxmikantchintakindi@users.noreply.github.com>
Date: Thu, 7 Nov 2024 14:22:16 +0530
Subject: [PATCH 2/3] Feat(eos_cli_config_gen): Add support for `mac timestamp
header` command (#4635)
---
.../documentation/devices/ethernet-interfaces.md | 3 +++
.../intended/configs/ethernet-interfaces.cfg | 3 +++
.../inventory/host_vars/ethernet-interfaces.yml | 3 +++
.../docs/tables/ethernet-interfaces.md | 6 ++++++
.../j2templates/eos/ethernet-interfaces.j2 | 3 +++
.../schema/eos_cli_config_gen.schema.yml | 13 +++++++++++++
.../schema_fragments/ethernet_interfaces.schema.yml | 7 +++++++
7 files changed, 38 insertions(+)
diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/ethernet-interfaces.md b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/ethernet-interfaces.md
index 63671daa4fe..cdd060acbb7 100644
--- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/ethernet-interfaces.md
+++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/ethernet-interfaces.md
@@ -1041,6 +1041,7 @@ interface Ethernet63
interface Ethernet64
description DHCP server interface
no switchport
+ mac timestamp replace-fcs
ip address 192.168.42.42/24
dhcp server ipv4
dhcp server ipv6
@@ -1049,6 +1050,7 @@ interface Ethernet65
description Multiple VRIDs
no shutdown
no switchport
+ mac timestamp header
ip address 192.0.2.2/25
ipv6 enable
ipv6 address 2001:db8::2/64
@@ -1085,6 +1087,7 @@ interface Ethernet67
description Custom_Transceiver_Frequency
no shutdown
switchport
+ mac timestamp before-fcs
transceiver frequency 190050.000
!
interface Ethernet67.1
diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/ethernet-interfaces.cfg b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/ethernet-interfaces.cfg
index d0fbafa4ba4..4ee49a35864 100644
--- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/ethernet-interfaces.cfg
+++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/ethernet-interfaces.cfg
@@ -656,6 +656,7 @@ interface Ethernet63
interface Ethernet64
description DHCP server interface
no switchport
+ mac timestamp replace-fcs
ip address 192.168.42.42/24
dhcp server ipv4
dhcp server ipv6
@@ -664,6 +665,7 @@ interface Ethernet65
description Multiple VRIDs
no shutdown
no switchport
+ mac timestamp header
ip address 192.0.2.2/25
ipv6 enable
ipv6 address 2001:db8::2/64
@@ -700,6 +702,7 @@ interface Ethernet67
description Custom_Transceiver_Frequency
no shutdown
switchport
+ mac timestamp before-fcs
transceiver frequency 190050.000
!
interface Ethernet67.1
diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/ethernet-interfaces.yml b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/ethernet-interfaces.yml
index 659bd5346da..22f0dd3e185 100644
--- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/ethernet-interfaces.yml
+++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/ethernet-interfaces.yml
@@ -1146,6 +1146,7 @@ ethernet_interfaces:
ip_address: 192.168.42.42/24
dhcp_server_ipv4: true
dhcp_server_ipv6: true
+ mac_timestamp: replace-fcs
- name: Ethernet69
switchport:
@@ -1163,6 +1164,7 @@ ethernet_interfaces:
ipv6_enable: true
ipv6_address: 2001:db8::2/64
ipv6_address_link_local: fe80::2/64
+ mac_timestamp: header
vrrp_ids:
- id: 1
priority_level: 105
@@ -1236,6 +1238,7 @@ ethernet_interfaces:
shutdown: false
transceiver:
frequency: 190050
+ mac_timestamp: before-fcs
- name: Ethernet67.1
description: Test_encapsulation_dot1q
diff --git a/ansible_collections/arista/avd/roles/eos_cli_config_gen/docs/tables/ethernet-interfaces.md b/ansible_collections/arista/avd/roles/eos_cli_config_gen/docs/tables/ethernet-interfaces.md
index 5b5032eb4b3..56ce6b6b34c 100644
--- a/ansible_collections/arista/avd/roles/eos_cli_config_gen/docs/tables/ethernet-interfaces.md
+++ b/ansible_collections/arista/avd/roles/eos_cli_config_gen/docs/tables/ethernet-interfaces.md
@@ -26,6 +26,7 @@
| [ l2_protocol](## "ethernet_interfaces.[].l2_protocol") | Dictionary | | | | |
| [ encapsulation_dot1q_vlan](## "ethernet_interfaces.[].l2_protocol.encapsulation_dot1q_vlan") | Integer | | | | Vlan tag to configure on sub-interface. |
| [ forwarding_profile](## "ethernet_interfaces.[].l2_protocol.forwarding_profile") | String | | | | L2 protocol forwarding profile. |
+ | [ mac_timestamp](## "ethernet_interfaces.[].mac_timestamp") | String | | | Valid Values:
- before-fcs
- replace-fcs
- header
| header: Insert timestamp in ethernet header. Supported on platforms like 7500E/R and 7280E/R.
before-fcs: Insert timestamp before fcs field. Supported on platforms like 7150.
replace-fcs: Replace fcs field with timestamp. |
| [ trunk_groups](## "ethernet_interfaces.[].trunk_groups") deprecated | List, items: String | | | | This key is deprecated. Support will be removed in AVD version 6.0.0. Use switchport.trunk.groups instead. |
| [ - <str>](## "ethernet_interfaces.[].trunk_groups.[]") | String | | | | |
| [ type](## "ethernet_interfaces.[].type") deprecated | String | | | Valid Values:
- routed
- switched
- l3dot1q
- l2dot1q
- port-channel-member
| l3dot1q and l2dot1q are used for sub-interfaces. The parent interface should be defined as routed.
The `type = switched/routed` should not be combined with `switchport`.
This key is deprecated. Support will be removed in AVD version 6.0.0. See [here](https://avd.arista.com/stable/docs/release-notes/5.x.x.html#removal-of-type-key-dependency-for-rendering-ethernetport-channel-interfaces-configuration-and-documentation) for details. |
@@ -550,6 +551,11 @@
# L2 protocol forwarding profile.
forwarding_profile:
+
+ # header: Insert timestamp in ethernet header. Supported on platforms like 7500E/R and 7280E/R.
+ # before-fcs: Insert timestamp before fcs field. Supported on platforms like 7150.
+ # replace-fcs: Replace fcs field with timestamp.
+ mac_timestamp:
# This key is deprecated.
# Support will be removed in AVD version 6.0.0.
# Use switchport.trunk.groups instead.
diff --git a/python-avd/pyavd/_eos_cli_config_gen/j2templates/eos/ethernet-interfaces.j2 b/python-avd/pyavd/_eos_cli_config_gen/j2templates/eos/ethernet-interfaces.j2
index 57986706be8..4da67bafade 100644
--- a/python-avd/pyavd/_eos_cli_config_gen/j2templates/eos/ethernet-interfaces.j2
+++ b/python-avd/pyavd/_eos_cli_config_gen/j2templates/eos/ethernet-interfaces.j2
@@ -302,6 +302,9 @@ interface {{ ethernet_interface.name }}
{% if ethernet_interface.l2_protocol.encapsulation_dot1q_vlan is arista.avd.defined %}
l2-protocol encapsulation dot1q vlan {{ ethernet_interface.l2_protocol.encapsulation_dot1q_vlan }}
{% endif %}
+{% if ethernet_interface.mac_timestamp is arista.avd.defined %}
+ mac timestamp {{ ethernet_interface.mac_timestamp }}
+{% endif %}
{% if ethernet_interface.evpn_ethernet_segment is arista.avd.defined %}
!
evpn ethernet-segment
diff --git a/python-avd/pyavd/_eos_cli_config_gen/schema/eos_cli_config_gen.schema.yml b/python-avd/pyavd/_eos_cli_config_gen/schema/eos_cli_config_gen.schema.yml
index 0f4a82a5e4d..be2ada40deb 100644
--- a/python-avd/pyavd/_eos_cli_config_gen/schema/eos_cli_config_gen.schema.yml
+++ b/python-avd/pyavd/_eos_cli_config_gen/schema/eos_cli_config_gen.schema.yml
@@ -2140,6 +2140,19 @@ keys:
forwarding_profile:
type: str
description: L2 protocol forwarding profile.
+ mac_timestamp:
+ type: str
+ valid_values:
+ - before-fcs
+ - replace-fcs
+ - header
+ description: 'header: Insert timestamp in ethernet header. Supported on
+ platforms like 7500E/R and 7280E/R.
+
+ before-fcs: Insert timestamp before fcs field. Supported on platforms
+ like 7150.
+
+ replace-fcs: Replace fcs field with timestamp.'
trunk_groups:
type: list
items:
diff --git a/python-avd/pyavd/_eos_cli_config_gen/schema/schema_fragments/ethernet_interfaces.schema.yml b/python-avd/pyavd/_eos_cli_config_gen/schema/schema_fragments/ethernet_interfaces.schema.yml
index f51b016ce7a..9602a0314ef 100644
--- a/python-avd/pyavd/_eos_cli_config_gen/schema/schema_fragments/ethernet_interfaces.schema.yml
+++ b/python-avd/pyavd/_eos_cli_config_gen/schema/schema_fragments/ethernet_interfaces.schema.yml
@@ -116,6 +116,13 @@ keys:
forwarding_profile:
type: str
description: L2 protocol forwarding profile.
+ mac_timestamp:
+ type: str
+ valid_values: ["before-fcs", "replace-fcs", "header"]
+ description: |-
+ header: Insert timestamp in ethernet header. Supported on platforms like 7500E/R and 7280E/R.
+ before-fcs: Insert timestamp before fcs field. Supported on platforms like 7150.
+ replace-fcs: Replace fcs field with timestamp.
trunk_groups:
type: list
items:
From 221cac03607cb2bc219fa692f5b9dca264af0afe Mon Sep 17 00:00:00 2001
From: Claus Holbech
Date: Thu, 7 Nov 2024 10:19:04 +0100
Subject: [PATCH 3/3] Test: Include more molecule scenarios in pytest (#4662)
---
.gitignore | 1 -
.../arista/avd/molecule/README.md | 2 +-
.../devices/host4_inline_jinja.md | 53 +++++
.../intended/configs/host4_inline_jinja.cfg | 7 +
.../host_vars/host1/tacacs-servers.yml | 3 +-
.../host4_inline_jinja/tacacs-servers.yml | 9 +
.../eos_cli_config_gen/inventory/hosts.ini | 185 -----------------
.../eos_cli_config_gen/inventory/hosts.yml | 192 ++++++++++++++++++
.../molecule/eos_cli_config_gen/molecule.yml | 2 +-
.../inventory/hosts.ini | 3 -
.../inventory/hosts.yml | 9 +
.../molecule.yml | 2 +-
.../inventory/hosts.yml | 3 +
.../inventory/hosts.yml | 8 +
python-avd/.gitignore | 1 -
python-avd/Makefile | 44 ----
python-avd/pyproject.toml | 19 ++
python-avd/scripts/export_test_vars.yml | 81 --------
python-avd/tests/models.py | 101 +++++++++
.../pyavd/cv/client/test_async_decorators.py | 8 +-
.../pyavd/eos_cli_config_gen/conftest.py | 86 --------
.../test_get_device_config.py | 23 ---
.../eos_cli_config_gen/test_get_device_doc.py | 22 --
.../test_validate_structured_config.py | 42 ----
.../tests/pyavd/eos_designs/__init__.py | 3 -
.../tests/pyavd/eos_designs/conftest.py | 93 ---------
.../pyavd/eos_designs/test_get_avd_facts.py | 18 --
.../test_get_device_structured_config.py | 19 --
.../pyavd/eos_designs/test_validate_inputs.py | 14 --
.../test_validate_structured_config.py | 42 ----
.../__init__.py | 0
.../pyavd/molecule_scenarios/conftest.py | 37 ++++
.../molecule_scenarios/test_get_avd_facts.py | 35 ++++
.../test_get_device_config.py | 31 ++-
.../molecule_scenarios/test_get_device_doc.py | 49 +++++
.../test_get_device_structured_config.py | 36 ++++
.../test_validate_inputs.py | 29 +++
.../test_validate_structured_config.py | 100 +++++++++
python-avd/tox.ini | 21 +-
39 files changed, 726 insertions(+), 707 deletions(-)
create mode 100644 ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/host4_inline_jinja.md
create mode 100644 ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/host4_inline_jinja.cfg
create mode 100644 ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/host4_inline_jinja/tacacs-servers.yml
delete mode 100644 ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/hosts.ini
create mode 100644 ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/hosts.yml
delete mode 100644 ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/inventory/hosts.ini
create mode 100644 ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/inventory/hosts.yml
delete mode 100644 python-avd/scripts/export_test_vars.yml
create mode 100644 python-avd/tests/models.py
delete mode 100644 python-avd/tests/pyavd/eos_cli_config_gen/conftest.py
delete mode 100644 python-avd/tests/pyavd/eos_cli_config_gen/test_get_device_config.py
delete mode 100644 python-avd/tests/pyavd/eos_cli_config_gen/test_get_device_doc.py
delete mode 100644 python-avd/tests/pyavd/eos_cli_config_gen/test_validate_structured_config.py
delete mode 100644 python-avd/tests/pyavd/eos_designs/__init__.py
delete mode 100644 python-avd/tests/pyavd/eos_designs/conftest.py
delete mode 100644 python-avd/tests/pyavd/eos_designs/test_get_avd_facts.py
delete mode 100644 python-avd/tests/pyavd/eos_designs/test_get_device_structured_config.py
delete mode 100644 python-avd/tests/pyavd/eos_designs/test_validate_inputs.py
delete mode 100644 python-avd/tests/pyavd/eos_designs/test_validate_structured_config.py
rename python-avd/tests/pyavd/{eos_cli_config_gen => molecule_scenarios}/__init__.py (100%)
create mode 100644 python-avd/tests/pyavd/molecule_scenarios/conftest.py
create mode 100644 python-avd/tests/pyavd/molecule_scenarios/test_get_avd_facts.py
rename python-avd/tests/pyavd/{eos_designs => molecule_scenarios}/test_get_device_config.py (50%)
create mode 100644 python-avd/tests/pyavd/molecule_scenarios/test_get_device_doc.py
create mode 100644 python-avd/tests/pyavd/molecule_scenarios/test_get_device_structured_config.py
create mode 100644 python-avd/tests/pyavd/molecule_scenarios/test_validate_inputs.py
create mode 100644 python-avd/tests/pyavd/molecule_scenarios/test_validate_structured_config.py
diff --git a/.gitignore b/.gitignore
index bd5e8f6192b..3303d9a97e8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,7 +11,6 @@ __pycache__/
/python-avd/build/
/python-avd/dist/
/python-avd/vendor/
-/python-avd/tests/pyavd/artifacts/
/python-avd/pyavd.egg-info/
/python-avd/.tox/
/python-avd/.coverage
diff --git a/ansible_collections/arista/avd/molecule/README.md b/ansible_collections/arista/avd/molecule/README.md
index 28fcf066812..ad2353236a8 100644
--- a/ansible_collections/arista/avd/molecule/README.md
+++ b/ansible_collections/arista/avd/molecule/README.md
@@ -76,7 +76,7 @@ When you update a template in `eos_cli_config_gen`, you should report a test cas
1. Create or update a file related to updated section under `inventory/host_vars`
-2. If the section is new, update the inventory file ([hosts.ini](eos_cli_config_gen/inventory/hosts.ini)) to add a new host. The host SHALL be the name of your section and also the `.yml` in your `host_vars`
+2. If the section is new, update the inventory file ([hosts.yml](eos_cli_config_gen/inventory/hosts.yml)) to add a new host. The host SHALL be the name of your section and also the `.yml` in your `host_vars`
3. Run molecule scenario to generate artifacts:
diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/host4_inline_jinja.md b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/host4_inline_jinja.md
new file mode 100644
index 00000000000..73a1ac0d771
--- /dev/null
+++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/documentation/devices/host4_inline_jinja.md
@@ -0,0 +1,53 @@
+# host4_inline_jinja
+
+## Table of Contents
+
+- [Management](#management)
+ - [Management Interfaces](#management-interfaces)
+- [Authentication](#authentication)
+ - [TACACS Servers](#tacacs-servers)
+
+## Management
+
+### Management Interfaces
+
+#### Management Interfaces Summary
+
+##### IPv4
+
+| Management Interface | Description | Type | VRF | IP Address | Gateway |
+| -------------------- | ----------- | ---- | --- | ---------- | ------- |
+| Management1 | OOB_MANAGEMENT | oob | MGMT | 10.73.255.122/24 | 10.73.255.2 |
+
+##### IPv6
+
+| Management Interface | Description | Type | VRF | IPv6 Address | IPv6 Gateway |
+| -------------------- | ----------- | ---- | --- | ------------ | ------------ |
+| Management1 | OOB_MANAGEMENT | oob | MGMT | - | - |
+
+#### Management Interfaces Device Configuration
+
+```eos
+!
+interface Management1
+ description OOB_MANAGEMENT
+ vrf MGMT
+ ip address 10.73.255.122/24
+```
+
+## Authentication
+
+### TACACS Servers
+
+#### TACACS Servers
+
+| VRF | TACACS Servers | Single-Connection | Timeout |
+| --- | -------------- | ----------------- | ------- |
+| default | 10.10.10.158 | False | - |
+
+#### TACACS Servers Device Configuration
+
+```eos
+!
+tacacs-server host 10.10.10.158 key 7
+```
diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/host4_inline_jinja.cfg b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/host4_inline_jinja.cfg
new file mode 100644
index 00000000000..d789bbd82db
--- /dev/null
+++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/intended/configs/host4_inline_jinja.cfg
@@ -0,0 +1,7 @@
+!
+tacacs-server host 10.10.10.158 key 7 071B245F5A
+!
+interface Management1
+ description OOB_MANAGEMENT
+ vrf MGMT
+ ip address 10.73.255.122/24
diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/host1/tacacs-servers.yml b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/host1/tacacs-servers.yml
index 3aafd2695a9..cfbbee549f5 100644
--- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/host1/tacacs-servers.yml
+++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/host1/tacacs-servers.yml
@@ -14,8 +14,7 @@ tacacs_servers:
single_connection: false
- host: 10.10.10.158
vrf: default
- # Testing of play_vars in eos_cli_config_gen
- key: "{{ tacacs_key_set_as_play_var }}"
+ key: 071B245F5A
key_type: 7
- host: 10.10.10.159
vrf: default
diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/host4_inline_jinja/tacacs-servers.yml b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/host4_inline_jinja/tacacs-servers.yml
new file mode 100644
index 00000000000..502415c86dc
--- /dev/null
+++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/host_vars/host4_inline_jinja/tacacs-servers.yml
@@ -0,0 +1,9 @@
+---
+## Tacacs+ Servers
+tacacs_servers:
+ hosts:
+ - host: 10.10.10.158
+ vrf: default
+ # Testing of play_vars in eos_cli_config_gen
+ key: "{{ tacacs_key_set_as_play_var }}"
+ key_type: 7
diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/hosts.ini b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/hosts.ini
deleted file mode 100644
index 14d027d2504..00000000000
--- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/hosts.ini
+++ /dev/null
@@ -1,185 +0,0 @@
-[test_hosts]
-; ls -l | gawk -F ' ' '{print $9}'| gawk -F '.' '{print $1}'
-host1
-host2
-acl
-address-locking
-base
-banners_without_eof
-custom-templates
-daemon_terminattr
-dns-ntp
-eos_cli_config_gen_configuration.enable
-eos_cli_config_gen_documentation.enable
-errdisable
-ethernet-interfaces
-event-handlers
-event-monitor
-flow-tracking
-flow-tracking-2
-groups
-hardware-counter
-hardware
-hide-passwords
-hostname
-igmp-snooping
-interface-defaults
-interface-profiles
-ip-access-lists
-ip-dhcp-relay
-ip-dhcp-snooping
-ip-community-lists
-ip-extended-community-lists
-ip-extended-community-lists-regexp
-ip-igmp-snooping-enable
-ip-nat
-ip-security
-ip-routing
-ip-routing-fib
-ip-radius-source-interface
-ip-tacacs-source-interface
-ip-client-source-interfaces
-ip-virtual-router-mac-address
-ipv6-access-lists
-ipv6-dhcp-relay
-ipv6-neighbors
-ipv6-static-routes
-l2-protocol-forwarding
-lacp
-link-tracking-groups
-lldp
-load-interval
-logging-match-list
-logging-minimal
-logging
-mcs-client
-loopbacks-interfaces
-mac-address-table
-maintenance
-management-accounts
-management-api-http
-management-cvx
-management-api-models
-management-gnmi
-management-gnmi-new-flags
-management-gnmi-grpc-tunnel
-management-console
-management-defaults
-management-interfaces
-management-security
-management-ssh
-management-ssh-custom-cipher
-management-tech-support
-mac-access-lists
-mac-security-eth-po-entropy
-match-lists
-mlag-configuration
-monitor-layer1
-monitor-connectivity
-monitor-connectivity-2
-monitor-sessions
-monitor-session-default-encapsulation-gre
-monitor-telemetry-influx
-monitor-telemetry-postcard-policy
-mpls
-mpls-2
-mpls-3
-none_configuration
-ntp
-object-tracking
-patch-panel
-peer-filters
-platform
-poe
-policy-maps
-policy-maps-pbr
-port-channel-interfaces
-prefix-lists
-prompt
-prompt-2
-ptp
-qos
-queue-monitor-length
-queue-monitor-length-notifying
-queue-monitor-streaming
-redundancy
-roles
-route-maps
-router-adaptive-virtual-topology
-router-adaptive-virtual-topology-2
-router-bfd-1
-router-bfd-2
-router-bgp-additional-paths
-router-bgp-base
-router-bgp-evpn
-router-bgp-evpn-vpn-import-pruning
-router-bgp-evpn-mpls
-router-bgp-ipv4-labeled-unicast
-router-bgp-link-state
-router-bgp-path-selection
-router-bgp-rtc
-router-bgp-v4-evpn
-router-bgp-v4-v6-evpn
-router-bgp-v4-v6-sr-te
-router-bgp-vpn-ipv4-vpn-ipv6
-router-bgp-vpws
-router-bgp-vrf-address-families
-router-bgp-vrf-lite
-router-general
-router-isis
-router-isis-new
-router-isis-1
-router-isis-2
-router-l2-vpn
-router-msdp
-router-multicast
-router-ospf
-router-path-selection
-router-pim-sparse-mode
-router-service-insertion
-router-igmp
-router-internet-exit
-service-routing-configuration-bgp
-service-routing-protocols-model
-service-routing-protocols-model-2
-router-general
-router-traffic-engineering
-router-segment-security
-sflow
-snmp
-snmp-server-traps
-spanning-tree
-spanning-tree-bpdu
-spanning-tree-rstp
-spanning-tree-rapid-pvst
-switchport-mode
-switchport-port-security
-stun
-sync-e
-tcam-profile
-static-routes
-system
-tap-aggregation
-terminal
-terminattr-cloud
-terminattr-extra-flags
-terminattr-multi-cluster-certs
-terminattr-multi-cluster
-terminattr-onprem-certs
-terminattr-onprem-token
-terminattr-prem
-terminattr-prem-no-ingestkey
-terminattr-prem-disableaaa
-traffic-policies
-traffic-policies-2
-traffic-policies-3
-transceiver_qsfp_default_mode_4x10_false
-tunnel-interfaces
-unsupported-transceiver
-vlan-interfaces
-virtual-source-nat
-vlan-internal-order
-vlans
-vmtracer-sessions
-vxlan-interface
-vxlan-interface-false
diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/hosts.yml b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/hosts.yml
new file mode 100644
index 00000000000..18fc19240c4
--- /dev/null
+++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/hosts.yml
@@ -0,0 +1,192 @@
+---
+test_hosts:
+ children:
+ IGNORE_IN_PYTEST:
+ hosts:
+ host4_inline_jinja:
+ custom-templates: # TODO: Remove inline jinja
+ tcam-profile: # TODO: Remove inline jinja
+ hosts:
+ host1:
+ host2:
+ host4_inline_jinja:
+ acl:
+ address-locking:
+ base:
+ banners_without_eof:
+ custom-templates:
+ daemon_terminattr:
+ dns-ntp:
+ eos_cli_config_gen_configuration.enable:
+ eos_cli_config_gen_documentation.enable:
+ errdisable:
+ ethernet-interfaces:
+ event-handlers:
+ event-monitor:
+ flow-tracking:
+ flow-tracking-2:
+ groups:
+ hardware-counter:
+ hardware:
+ hide-passwords:
+ hostname:
+ igmp-snooping:
+ interface-defaults:
+ interface-profiles:
+ ip-access-lists:
+ ip-dhcp-relay:
+ ip-dhcp-snooping:
+ ip-community-lists:
+ ip-extended-community-lists:
+ ip-extended-community-lists-regexp:
+ ip-igmp-snooping-enable:
+ ip-nat:
+ ip-security:
+ ip-routing:
+ ip-routing-fib:
+ ip-radius-source-interface:
+ ip-tacacs-source-interface:
+ ip-client-source-interfaces:
+ ip-virtual-router-mac-address:
+ ipv6-access-lists:
+ ipv6-dhcp-relay:
+ ipv6-neighbors:
+ ipv6-static-routes:
+ l2-protocol-forwarding:
+ lacp:
+ link-tracking-groups:
+ lldp:
+ load-interval:
+ logging-match-list:
+ logging-minimal:
+ logging:
+ mcs-client:
+ loopbacks-interfaces:
+ mac-address-table:
+ maintenance:
+ management-accounts:
+ management-api-http:
+ management-cvx:
+ management-api-models:
+ management-gnmi:
+ management-gnmi-new-flags:
+ management-gnmi-grpc-tunnel:
+ management-console:
+ management-defaults:
+ management-interfaces:
+ management-security:
+ management-ssh:
+ management-ssh-custom-cipher:
+ management-tech-support:
+ mac-access-lists:
+ mac-security-eth-po-entropy:
+ match-lists:
+ mlag-configuration:
+ monitor-layer1:
+ monitor-connectivity:
+ monitor-connectivity-2:
+ monitor-sessions:
+ monitor-session-default-encapsulation-gre:
+ monitor-telemetry-influx:
+ monitor-telemetry-postcard-policy:
+ mpls:
+ mpls-2:
+ mpls-3:
+ none_configuration:
+ ntp:
+ object-tracking:
+ patch-panel:
+ peer-filters:
+ platform:
+ poe:
+ policy-maps:
+ policy-maps-pbr:
+ port-channel-interfaces:
+ prefix-lists:
+ prompt:
+ prompt-2:
+ ptp:
+ qos:
+ queue-monitor-length:
+ queue-monitor-length-notifying:
+ queue-monitor-streaming:
+ redundancy:
+ roles:
+ route-maps:
+ router-adaptive-virtual-topology:
+ router-adaptive-virtual-topology-2:
+ router-bfd-1:
+ router-bfd-2:
+ router-bgp-additional-paths:
+ router-bgp-base:
+ router-bgp-evpn:
+ router-bgp-evpn-vpn-import-pruning:
+ router-bgp-evpn-mpls:
+ router-bgp-ipv4-labeled-unicast:
+ router-bgp-link-state:
+ router-bgp-path-selection:
+ router-bgp-rtc:
+ router-bgp-v4-evpn:
+ router-bgp-v4-v6-evpn:
+ router-bgp-v4-v6-sr-te:
+ router-bgp-vpn-ipv4-vpn-ipv6:
+ router-bgp-vpws:
+ router-bgp-vrf-address-families:
+ router-bgp-vrf-lite:
+ router-general:
+ router-isis:
+ router-isis-new:
+ router-isis-1:
+ router-isis-2:
+ router-l2-vpn:
+ router-msdp:
+ router-multicast:
+ router-ospf:
+ router-path-selection:
+ router-pim-sparse-mode:
+ router-service-insertion:
+ router-igmp:
+ router-internet-exit:
+ service-routing-configuration-bgp:
+ service-routing-protocols-model:
+ service-routing-protocols-model-2:
+ router-traffic-engineering:
+ router-segment-security:
+ sflow:
+ snmp:
+ snmp-server-traps:
+ spanning-tree:
+ spanning-tree-bpdu:
+ spanning-tree-rstp:
+ spanning-tree-rapid-pvst:
+ switchport-mode:
+ switchport-port-security:
+ stun:
+ sync-e:
+ tcam-profile:
+ static-routes:
+ system:
+ tap-aggregation:
+ terminal:
+ terminattr-cloud:
+ terminattr-extra-flags:
+ terminattr-multi-cluster-certs:
+ terminattr-multi-cluster:
+ terminattr-onprem-certs:
+ terminattr-onprem-token:
+ terminattr-prem:
+ terminattr-prem-no-ingestkey:
+ terminattr-prem-disableaaa:
+ traffic-policies:
+ traffic-policies-2:
+ traffic-policies-3:
+ transceiver_qsfp_default_mode_4x10_false:
+ tunnel-interfaces:
+ unsupported-transceiver:
+ vlan-interfaces:
+ virtual-source-nat:
+ vlan-internal-order:
+ vlans:
+ vmtracer-sessions:
+ vxlan-interface:
+ vxlan-interface-false:
diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/molecule.yml b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/molecule.yml
index 64a2cc5a203..2a54eb2580c 100644
--- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen/molecule.yml
+++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen/molecule.yml
@@ -28,7 +28,7 @@ provisioner:
inventory:
links:
- hosts: 'inventory/hosts.ini'
+ hosts: 'inventory/hosts.yml'
host_vars: 'inventory/host_vars/'
group_vars: 'inventory/group_vars/'
verifier:
diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/inventory/hosts.ini b/ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/inventory/hosts.ini
deleted file mode 100644
index 232d6940908..00000000000
--- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/inventory/hosts.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[test_hosts]
-host1
-host2
diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/inventory/hosts.yml b/ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/inventory/hosts.yml
new file mode 100644
index 00000000000..70f3887fd4f
--- /dev/null
+++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/inventory/hosts.yml
@@ -0,0 +1,9 @@
+---
+all:
+ groups:
+ IGNORE_IN_PYTEST:
+ hosts: # TODO: Remove inline jinja
+ host1:
+ hosts:
+ host1:
+ host2:
diff --git a/ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/molecule.yml b/ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/molecule.yml
index c5456334a28..16804cbcd18 100644
--- a/ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/molecule.yml
+++ b/ansible_collections/arista/avd/molecule/eos_cli_config_gen_deprecated_vars/molecule.yml
@@ -27,7 +27,7 @@ provisioner:
gathering: explicit
inventory:
links:
- hosts: 'inventory/hosts.ini'
+ hosts: 'inventory/hosts.yml'
host_vars: 'inventory/host_vars/'
group_vars: 'inventory/group_vars/'
verifier:
diff --git a/ansible_collections/arista/avd/molecule/eos_designs_deprecated_vars/inventory/hosts.yml b/ansible_collections/arista/avd/molecule/eos_designs_deprecated_vars/inventory/hosts.yml
index 6f894ed98ac..f4b55fa1a2d 100644
--- a/ansible_collections/arista/avd/molecule/eos_designs_deprecated_vars/inventory/hosts.yml
+++ b/ansible_collections/arista/avd/molecule/eos_designs_deprecated_vars/inventory/hosts.yml
@@ -1,6 +1,9 @@
---
all:
children:
+ IGNORE_IN_PYTEST:
+ hosts:
+ host1: # TODO: Remove inline jinja
EOS_DESIGNS_DEPRECATED_VARS:
hosts:
host1:
diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/hosts.yml b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/hosts.yml
index ff75d0ed0f6..3e2d17e6fbc 100644
--- a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/hosts.yml
+++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/hosts.yml
@@ -1,6 +1,14 @@
---
all:
children:
+ IGNORE_IN_PYTEST:
+ children:
+ CUSTOM_TEMPLATES_TESTS:
+ CUSTOM_PYTHON_MODULES_TESTS:
+ DC1_FABRIC: # TODO: Remove inline jinja
+ hosts:
+ RD-RT-ADMIN-SUBFIELD-L3LEAF6: # TODO: Remove inline jinja
+ connected_endpoints: # TODO: Remove inline jinja
EOS_DESIGNS_UNIT_TESTS:
children:
CLEAN_UNIT_TESTS: # Single Devices testing one specific case and only using hostvars
diff --git a/python-avd/.gitignore b/python-avd/.gitignore
index 84c9a373c18..1effd93b916 100644
--- a/python-avd/.gitignore
+++ b/python-avd/.gitignore
@@ -3,7 +3,6 @@
__pycache__/
/build/
/dist/
-/tests/artifacts/
/pyavd.egg-info/
/pyavd/eos_cli_config_gen.templates.zip
*.prof
diff --git a/python-avd/Makefile b/python-avd/Makefile
index 61c7a1c95ec..4dce12cdbb6 100644
--- a/python-avd/Makefile
+++ b/python-avd/Makefile
@@ -1,6 +1,5 @@
CURRENT_DIR = $(shell pwd)
ANSIBLE_AVD_DIR ?= ..
-TESTS_ARTIFACTS = $(CURRENT_DIR)/tests/pyavd/artifacts
SCRIPTS_DIR = $(CURRENT_DIR)/scripts
# export PYTHONPATH=$(CURRENT_DIR) # Uncomment to test from source
@@ -12,9 +11,6 @@ help: ## Display help message
.PHONY: dep
dep: compile-templates compile-schemas ## compile Jinja templates & AVD schemas
-.PHONY: test-dep
-test-dep: copy-test-data ## Copy and Fix Ansible AVD test files
-
.PHONY: build
build: ## Build pyavd package
pip3 install build
@@ -35,43 +31,3 @@ compile-schemas:
.PHONY: compile-templates
compile-templates:
$(SCRIPTS_DIR)/compile_templates.py
-
-.PHONY: copy-test-data
-copy-test-data: ## Copy inventory files from AVD collection Molecule scenario.
- rm -rf $(TESTS_ARTIFACTS)
-
-## EOS_CLI_CONFIG_GEN
-
-## Workaround to get the lookup plugin to resolve this TCAM profile before exporting vars
- mkdir -p $(SCRIPTS_DIR)/inventory
- cp $(ANSIBLE_AVD_DIR)/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/TCAM_TRAFFIC_POLICY.conf $(SCRIPTS_DIR)/inventory/
-
-## Excluding prompt because the unsafe marker is lost during the export of hostvars.
-## Excluding custom-templates since there is no jinja support in pyavd
- ANSIBLE_COLLECTIONS_PATH="..:/usr/share/ansible/collections" ansible-playbook \
- --limit 'all:!prompt:!custom-templates' \
- -i $(ANSIBLE_AVD_DIR)/ansible_collections/arista/avd/molecule/eos_cli_config_gen/inventory/hosts.ini \
- $(SCRIPTS_DIR)/export_test_vars.yml \
- -e testdir=eos_cli_config_gen \
- -f 10
-
- rm -rf $(SCRIPTS_DIR)/inventory/
-
-## Remove excluded tests
- rm $(TESTS_ARTIFACTS)/eos_cli_config_gen/configs/prompt.cfg
- rm $(TESTS_ARTIFACTS)/eos_cli_config_gen/configs/custom-templates.cfg
-
-## EOS_DESIGNS
-
- ANSIBLE_COLLECTIONS_PATH="..:/usr/share/ansible/collections" ansible-playbook \
- -i $(ANSIBLE_AVD_DIR)/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/hosts.yml $(SCRIPTS_DIR)/export_test_vars.yml \
- -e testdir=eos_designs_unit_tests \
- -f 10
-
-## Remove tests with custom templates
- rm $(TESTS_ARTIFACTS)/eos_designs_unit_tests/vars/CUSTOM-TEMPLATES*.json
- rm $(TESTS_ARTIFACTS)/eos_designs_unit_tests/structured_configs/CUSTOM-TEMPLATES*.yml
- rm $(TESTS_ARTIFACTS)/eos_designs_unit_tests/configs/CUSTOM-TEMPLATES*.cfg
- rm $(TESTS_ARTIFACTS)/eos_designs_unit_tests/vars/CUSTOM-PYTHON_MODULES*.json
- rm $(TESTS_ARTIFACTS)/eos_designs_unit_tests/structured_configs/CUSTOM-PYTHON_MODULES*.yml
- rm $(TESTS_ARTIFACTS)/eos_designs_unit_tests/configs/CUSTOM-PYTHON_MODULES*.cfg
diff --git a/python-avd/pyproject.toml b/python-avd/pyproject.toml
index 79f95e185dd..0d5dbe3f6dc 100644
--- a/python-avd/pyproject.toml
+++ b/python-avd/pyproject.toml
@@ -31,6 +31,19 @@ dependencies = [
homepage = "https://avd.arista.com"
repository = "https://github.com/aristanetworks/avd"
+[dependency-groups]
+pytest = [
+ "ansible-core<2.18",
+ "pytest",
+ "pytest-asyncio",
+ "PyYAML>=6.0.0",
+ "pydantic>=2.3.0",
+ "referencing>=0.35.0",
+]
+coverage = [
+ "coverage[toml]",
+]
+
[project.optional-dependencies]
ansible = [
"ansible-core>=2.15.0,<2.18.0",
@@ -140,3 +153,9 @@ exclude_also = [
# Extend the `pyproject.toml` file in the parent directory...
# Should not be needed, but the ruff vscode extension does not seem to respect the ruff behavior of ignoring files without tool.ruff
extend = "../pyproject.toml"
+
+[tool.pytest.ini_options]
+markers = [
+ "molecule_scenarios: Create test case fixtures 'molecule_host' or 'molecule_scenario' for the given molecule scenarios.",
+]
+asyncio_default_fixture_loop_scope = "function"
diff --git a/python-avd/scripts/export_test_vars.yml b/python-avd/scripts/export_test_vars.yml
deleted file mode 100644
index b39d13ddfca..00000000000
--- a/python-avd/scripts/export_test_vars.yml
+++ /dev/null
@@ -1,81 +0,0 @@
----
-
-# Ansible Playbook to export vars from AVD molecule scenarios
-# Must load inventory from file in source molecule scenario
-# Must give destination path as extra-var like "-e testdir=eos_designs_unit_tests"
-
-- name: Copy files from molecule scenario
- gather_facts: false
- connection: local
- hosts: all,!prompt ## Excluding prompt because the unsafe marker is lost during the export of hostvars.
- vars:
- scenario_dir: "{{ inventory_dir }}/.."
- pyavd_test_artifacts_dir: "{{ playbook_dir }}/../tests/pyavd/artifacts"
- tacacs_key_set_as_play_var: "071B245F5A" ## setting dummy value to avoid error for key set in molecule playbook
- string_set_as_play_var: "test of var set under play vars" ## setting dummy value to avoid error for key set in molecule playbook
- tasks:
- - name: Clear directory
- ansible.builtin.file:
- path: "{{ pyavd_test_artifacts_dir }}/{{ testdir }}"
- state: absent
- run_once: true
- delegate_to: localhost
-
- - name: Create directories
- ansible.builtin.file:
- path: "{{ pyavd_test_artifacts_dir }}/{{ testdir }}/{{ item }}"
- state: directory
- mode: "0o775"
- run_once: true
- loop:
- - vars
- - configs
- - structured_configs
- - documentation
- delegate_to: localhost
-
- - name: Copy structured_configs
- ansible.builtin.shell:
- cmd: "cp {{ scenario_dir }}/intended/structured_configs/*.yml {{ pyavd_test_artifacts_dir }}/{{ testdir }}/structured_configs/"
- run_once: true
- delegate_to: localhost
- when: lookup("ansible.builtin.fileglob", scenario_dir ~ "/intended/structured_configs/*.yml", skip=true)
-
- - name: Copy configs
- ansible.builtin.shell:
- cmd: "cp {{ scenario_dir }}/intended/configs/*.cfg {{ pyavd_test_artifacts_dir }}/{{ testdir }}/configs/"
- run_once: true
- delegate_to: localhost
- when: lookup("ansible.builtin.fileglob", scenario_dir ~ "/intended/configs/*.cfg", skip=true)
-
- - name: Copy documentation
- ansible.builtin.shell:
- cmd: "cp {{ scenario_dir }}/documentation/devices/*.md {{ pyavd_test_artifacts_dir }}/{{ testdir }}/documentation/"
- run_once: true
- delegate_to: localhost
- when: lookup("ansible.builtin.fileglob", scenario_dir ~ "/documentation/devices/*.md", skip=true)
-
- - name: Set fact with hostvars to force templating
- ansible.builtin.set_fact:
- templated_hostvars: "{{ hostvars[inventory_hostname] }}"
- delegate_to: localhost
- vars:
- # Variables required to run Molecule test data outside Ansible without getting "undefined" errors.
- playbook_dir: "playbook_dir"
- switch:
- mgmt_interface: Management99
- mgmt_vrf: MGMT
- id: 6
-
- - name: Export hostvars
- ansible.builtin.copy:
- content: "{{ templated_hostvars | to_json(sort_keys=false) }}"
- dest: "{{ pyavd_test_artifacts_dir }}/{{ testdir }}/vars/{{ inventory_hostname }}.json"
- delegate_to: localhost
- vars:
- # Variables required to run Molecule test data outside Ansible without getting "undefined" errors.
- playbook_dir: "playbook_dir"
- switch:
- mgmt_interface: Management99
- mgmt_vrf: MGMT
- id: 6
diff --git a/python-avd/tests/models.py b/python-avd/tests/models.py
new file mode 100644
index 00000000000..696c8d063a2
--- /dev/null
+++ b/python-avd/tests/models.py
@@ -0,0 +1,101 @@
+# Copyright (c) 2024 Arista Networks, Inc.
+# Use of this source code is governed by the Apache License 2.0
+# that can be found in the LICENSE file.
+from __future__ import annotations
+
+import json
+from copy import deepcopy
+from functools import cached_property
+from pathlib import Path
+from typing import TYPE_CHECKING
+
+from ansible.inventory.manager import InventoryManager
+from ansible.parsing.dataloader import DataLoader
+from ansible.vars.manager import VariableManager
+from yaml import CSafeLoader, load
+
+from pyavd import get_avd_facts
+
+if TYPE_CHECKING:
+ from ansible.inventory.host import Host as AnsibleHost
+
+REPO_ROOT = Path(__file__).parents[2]
+MOLECULE_PATH = REPO_ROOT / "ansible_collections/arista/avd/molecule"
+
+
+class MoleculeHost:
+ """Class representing one host defined in a Molecule scenario."""
+
+ name: str
+ ansible_host: AnsibleHost
+ scenario: MoleculeScenario
+
+ def __init__(self, name: str, ansible_host: AnsibleHost, scenario: MoleculeScenario) -> None:
+ self.name = name
+ self.ansible_host = ansible_host
+ self.scenario = scenario
+
+ @cached_property
+ def structured_config(self) -> dict:
+ """The intended structured config for the host, as read from the YAML file in the molecule scenario."""
+ structured_config_path = self.scenario.path / "intended/structured_configs" / f"{self.name}.yml"
+ if not structured_config_path.exists():
+ return {}
+
+ return load(structured_config_path.read_text(), CSafeLoader)
+
+ @cached_property
+ def config(self) -> str | None:
+ """The intended EOS config for the host, as read from the cfg file in the molecule scenario."""
+ config_path = self.scenario.path / "intended/configs" / f"{self.name}.cfg"
+ if not config_path.exists():
+ return None
+
+ return config_path.read_text()
+
+ @cached_property
+ def doc(self) -> str | None:
+ """The intended MarkDown documentation for the host, as read from the md file in the molecule scenario."""
+ doc_path = self.scenario.path / "documentation/devices" / f"{self.name}.md"
+ if not doc_path.exists():
+ return None
+
+ return doc_path.read_text()
+
+ @cached_property
+ def hostvars(self) -> dict:
+ """The input vars for the host, as read from the Ansible inventory in the molecule scenario."""
+ return json.loads(json.dumps(self.scenario._vars.get_vars(host=self.ansible_host)))
+
+
+class MoleculeScenario:
+ """Class representing one Molecule scenario."""
+
+ name: str
+ path: Path
+ hosts: list[MoleculeHost]
+
+ def __init__(self, name: str) -> None:
+ """
+ Class representing one Molecule scenario.
+
+ Args:
+ name: Molecule scenario name
+
+ The Ansible inventory of the Molecule scenario will be parsed and MoleculeHost instances will be inserted into the `hosts` property
+ for each host found in the inventory.
+ """
+ self.name = name
+ self.path = MOLECULE_PATH / name
+ self._inventory = InventoryManager(loader=DataLoader(), sources=[(self.path / "inventory/hosts.yml").as_posix()])
+ self._vars = VariableManager(loader=DataLoader(), inventory=self._inventory)
+ self.hosts = []
+ for host in self._inventory.get_hosts():
+ if "IGNORE_IN_PYTEST" in [group.name for group in host.groups]:
+ continue
+ self.hosts.append(MoleculeHost(name=host.name, ansible_host=host, scenario=self))
+
+ @cached_property
+ def avd_facts(self) -> dict:
+ """The AVD facts calculated from the full Ansible inventory in the molecule scenario."""
+ return get_avd_facts({host.name: deepcopy(host.hostvars) for host in self.hosts})
diff --git a/python-avd/tests/pyavd/cv/client/test_async_decorators.py b/python-avd/tests/pyavd/cv/client/test_async_decorators.py
index b0326bc82f3..f631c6f4a87 100644
--- a/python-avd/tests/pyavd/cv/client/test_async_decorators.py
+++ b/python-avd/tests/pyavd/cv/client/test_async_decorators.py
@@ -35,7 +35,7 @@
]
-class TestClass:
+class CvClass:
_cv_version: CvVersion
def __init__(self, version: CvVersion) -> None:
@@ -74,20 +74,20 @@ async def msgsize_limited_method(self, field: list, max_accepted_len: int) -> li
@pytest.mark.parametrize(("version", "expected_exception"), INVALID_VERSION_TESTS)
async def test_invalid_versions(version: str, expected_exception: Exception) -> None:
with pytest.raises(type(expected_exception), match=expected_exception.args[0]):
- await TestClass(CvVersion(version)).version_limited_method()
+ await CvClass(CvVersion(version)).version_limited_method()
@pytest.mark.asyncio
@pytest.mark.parametrize(("version", "expected_response"), VALID_VERSION_TESTS)
async def test_valid_versions(version: str, expected_response: tuple[str, str]) -> None:
- resp = await TestClass(CvVersion(version)).version_limited_method()
+ resp = await CvClass(CvVersion(version)).version_limited_method()
assert resp == expected_response
@pytest.mark.asyncio
@pytest.mark.parametrize(("data", "max_len", "expected_response"), MSG_SIZE_HANDLER_TESTS)
async def test_msg_size_handler(data: list, max_len: int, expected_response: list[int]) -> None:
- resp = await TestClass(CvVersion(CVAAS_VERSION_STRING)).msgsize_limited_method(field=data, max_accepted_len=max_len)
+ resp = await CvClass(CvVersion(CVAAS_VERSION_STRING)).msgsize_limited_method(field=data, max_accepted_len=max_len)
assert resp == expected_response
diff --git a/python-avd/tests/pyavd/eos_cli_config_gen/conftest.py b/python-avd/tests/pyavd/eos_cli_config_gen/conftest.py
deleted file mode 100644
index 79787a99201..00000000000
--- a/python-avd/tests/pyavd/eos_cli_config_gen/conftest.py
+++ /dev/null
@@ -1,86 +0,0 @@
-# Copyright (c) 2023-2024 Arista Networks, Inc.
-# Use of this source code is governed by the Apache License 2.0
-# that can be found in the LICENSE file.
-from pathlib import Path
-
-import pytest
-
-from tests.utils import read_file, read_vars
-
-VARS_PATH = Path(Path(__file__).parent, "../artifacts/eos_cli_config_gen/vars")
-CONFIGS_PATH = Path(Path(__file__).parent, "../artifacts/eos_cli_config_gen/configs")
-DOCS_PATH = Path(Path(__file__).parent, "../artifacts/eos_cli_config_gen/documentation")
-
-
-def get_hostnames() -> list:
- assert Path(VARS_PATH).is_dir()
-
- return [Path(device_var_file).name.removesuffix(".yaml").removesuffix(".yml").removesuffix(".json") for device_var_file in Path(VARS_PATH).glob("*")]
-
-
-@pytest.fixture(scope="module")
-def all_inputs() -> dict[str, dict]:
- """
- Return dict with all inputs.
-
- {
- "hostname1": dict
- "hostname2": dict
- }
- The inputs are read of test artifacts which are hostvars extracted from Ansible molecule scenarios.
- """
- assert Path(VARS_PATH).is_dir()
-
- inputs = {}
- for device_var_file in Path(VARS_PATH).glob("*"):
- hostname = Path(device_var_file).name.removesuffix(".yaml").removesuffix(".yml").removesuffix(".json")
- inputs[hostname] = read_vars(device_var_file)
-
- return inputs
-
-
-@pytest.fixture(scope="module", params=get_hostnames())
-def hostname(request: pytest.FixtureRequest) -> dict:
- return request.param
-
-
-@pytest.fixture(scope="module")
-def configs() -> dict:
- """
- Return dict with all configs.
-
- {
- "hostname1": str
- "hostname2": str
- }
- The contents are extracted from Ansible molecule scenarios.
- """
- assert Path(CONFIGS_PATH).is_dir()
-
- result = {}
- for filename in Path(CONFIGS_PATH).glob("*"):
- hostname = Path(filename).name.removesuffix(".cfg")
- result[hostname] = read_file(filename)
-
- return result
-
-
-@pytest.fixture(scope="module")
-def device_docs() -> dict:
- """
- Return dict with all docs.
-
- {
- "hostname1": str
- "hostname2": str
- }
- The contents are extracted from Ansible molecule scenarios.
- """
- assert Path(DOCS_PATH).is_dir()
-
- result = {}
- for filename in Path(DOCS_PATH).glob("*"):
- hostname = Path(filename).name.removesuffix(".md")
- result[hostname] = read_file(filename)
-
- return result
diff --git a/python-avd/tests/pyavd/eos_cli_config_gen/test_get_device_config.py b/python-avd/tests/pyavd/eos_cli_config_gen/test_get_device_config.py
deleted file mode 100644
index 3cdc9636034..00000000000
--- a/python-avd/tests/pyavd/eos_cli_config_gen/test_get_device_config.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright (c) 2023-2024 Arista Networks, Inc.
-# Use of this source code is governed by the Apache License 2.0
-# that can be found in the LICENSE file.
-from pyavd import get_device_config, validate_structured_config
-from pyavd._utils import get
-
-
-def test_get_device_config(hostname: str, all_inputs: dict, configs: dict) -> None:
- """Test get_device_config."""
- structured_config: dict = all_inputs[hostname]
- if not get(structured_config, "eos_cli_config_gen_configuration.enable", True):
- return
-
- expected_config: str = configs[hostname]
-
- # run validation on structured_config to ensure it is converted
- validate_structured_config(structured_config)
-
- device_config = get_device_config(structured_config)
-
- assert isinstance(device_config, str)
-
- assert device_config == expected_config
diff --git a/python-avd/tests/pyavd/eos_cli_config_gen/test_get_device_doc.py b/python-avd/tests/pyavd/eos_cli_config_gen/test_get_device_doc.py
deleted file mode 100644
index cec72efd4dd..00000000000
--- a/python-avd/tests/pyavd/eos_cli_config_gen/test_get_device_doc.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright (c) 2023-2024 Arista Networks, Inc.
-# Use of this source code is governed by the Apache License 2.0
-# that can be found in the LICENSE file.
-from pyavd import get_device_doc, validate_structured_config
-from pyavd._utils import get
-
-
-def test_get_device_doc(hostname: str, all_inputs: dict, device_docs: dict) -> None:
- """Test get_device_config."""
- structured_config: dict = all_inputs[hostname]
- if not get(structured_config, "eos_cli_config_gen_documentation.enable", True):
- return
-
- # run validation on structured_config to ensure it is covered
- validate_structured_config(structured_config)
-
- expected_doc: str = device_docs.get(hostname, "")
-
- device_doc = get_device_doc(structured_config, add_md_toc=True)
-
- assert isinstance(device_doc, str)
- assert device_doc == expected_doc
diff --git a/python-avd/tests/pyavd/eos_cli_config_gen/test_validate_structured_config.py b/python-avd/tests/pyavd/eos_cli_config_gen/test_validate_structured_config.py
deleted file mode 100644
index 47499a0a351..00000000000
--- a/python-avd/tests/pyavd/eos_cli_config_gen/test_validate_structured_config.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (c) 2023-2024 Arista Networks, Inc.
-# Use of this source code is governed by the Apache License 2.0
-# that can be found in the LICENSE file.
-from pyavd import validate_structured_config
-from pyavd._errors import AvdValidationError
-from pyavd.avd_schema_tools import AvdSchemaTools
-
-SCHEMA = AvdSchemaTools(schema_id="eos_cli_config_gen").avdschema._schema
-
-
-def test_validate_structured_config_with_valid_data(hostname: str, all_inputs: dict) -> None:
- """Test validate_structured_config."""
- structured_config = all_inputs[hostname]
- validation_result = validate_structured_config(structured_config)
- assert hostname
- assert validation_result.validation_errors == []
- assert hostname
- assert validation_result.failed is False
-
-
-def test_validate_structured_config_with_invalid_data(hostname: str, all_inputs: dict) -> None:
- """Test validate_structured_config."""
- structured_config: dict = all_inputs[hostname]
-
- updated = False
- # Insert a bad key in a random dict (making sure the dict is covered by the schema)
- for key, value in structured_config.items():
- if not isinstance(value, dict) or "structured_config" in key or key not in SCHEMA["keys"]:
- continue
- value.update({"invalid_key": "some_value"})
- updated = True
- break
-
- # No dict found, so we insert our own instead
- if not updated:
- structured_config.update({"ethernet_interfaces": [{"name": "dummy", "invalid_key": "some_value"}]})
-
- validation_result = validate_structured_config(structured_config)
- assert validation_result.failed is True
- assert len(validation_result.validation_errors) >= 1
- assert isinstance(validation_result.validation_errors[0], AvdValidationError)
- assert "invalid_key" in str(validation_result.validation_errors[0])
diff --git a/python-avd/tests/pyavd/eos_designs/__init__.py b/python-avd/tests/pyavd/eos_designs/__init__.py
deleted file mode 100644
index e772bee41fe..00000000000
--- a/python-avd/tests/pyavd/eos_designs/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# Copyright (c) 2023-2024 Arista Networks, Inc.
-# Use of this source code is governed by the Apache License 2.0
-# that can be found in the LICENSE file.
diff --git a/python-avd/tests/pyavd/eos_designs/conftest.py b/python-avd/tests/pyavd/eos_designs/conftest.py
deleted file mode 100644
index 6afc0fe5b6c..00000000000
--- a/python-avd/tests/pyavd/eos_designs/conftest.py
+++ /dev/null
@@ -1,93 +0,0 @@
-# Copyright (c) 2023-2024 Arista Networks, Inc.
-# Use of this source code is governed by the Apache License 2.0
-# that can be found in the LICENSE file.
-from pathlib import Path
-
-import pytest
-
-from pyavd import get_avd_facts
-from tests.utils import read_file, read_vars
-
-VARS_PATH = Path(Path(__file__).parent, "../artifacts/eos_designs_unit_tests/vars")
-STRUCTURED_CONFIGS_PATH = Path(Path(__file__).parent, "../artifacts/eos_designs_unit_tests/structured_configs")
-CONFIGS_PATH = Path(Path(__file__).parent, "../artifacts/eos_designs_unit_tests/configs")
-
-
-def get_hostnames() -> list:
- assert Path(VARS_PATH).is_dir()
-
- return [Path(device_var_file).name.removesuffix(".yaml").removesuffix(".yml").removesuffix(".json") for device_var_file in Path(VARS_PATH).glob("*")]
-
-
-@pytest.fixture(scope="module")
-def all_inputs() -> dict[str, dict]:
- """
- Return dict with all inputs.
-
- {
- "hostname1": dict
- "hostname2": dict
- }
- The inputs are read of test artifacts which are hostvars extracted from Ansible molecule scenarios.
- """
- assert Path(VARS_PATH).is_dir()
-
- inputs = {}
- for device_var_file in Path(VARS_PATH).glob("*"):
- hostname = Path(device_var_file).name.removesuffix(".yaml").removesuffix(".yml").removesuffix(".json")
- inputs[hostname] = read_vars(device_var_file)
-
- return inputs
-
-
-@pytest.fixture(scope="module")
-def avd_facts(all_inputs: dict) -> dict:
- """Test get_avd_facts."""
- return get_avd_facts(all_inputs)
-
-
-@pytest.fixture(scope="module", params=get_hostnames())
-def hostname(request: pytest.FixtureRequest) -> dict:
- return request.param
-
-
-@pytest.fixture(scope="module")
-def structured_configs() -> dict:
- """
- Return dict with all structured_configs.
-
- {
- "hostname1": dict
- "hostname2": dict
- }
- The contents are extracted from Ansible molecule scenarios.
- """
- assert Path(STRUCTURED_CONFIGS_PATH).is_dir()
-
- result = {}
- for filename in Path(STRUCTURED_CONFIGS_PATH).glob("*"):
- hostname = Path(filename).name.removesuffix(".yaml").removesuffix(".yml").removesuffix(".json")
- result[hostname] = read_vars(filename)
-
- return result
-
-
-@pytest.fixture(scope="module")
-def configs() -> dict:
- """
- Return dict with all configs.
-
- {
- "hostname1": str
- "hostname2": str
- }
- The contents are extracted from Ansible molecule scenarios.
- """
- assert Path(CONFIGS_PATH).is_dir()
-
- result = {}
- for filename in Path(CONFIGS_PATH).glob("*"):
- hostname = Path(filename).name.removesuffix(".cfg")
- result[hostname] = read_file(filename)
-
- return result
diff --git a/python-avd/tests/pyavd/eos_designs/test_get_avd_facts.py b/python-avd/tests/pyavd/eos_designs/test_get_avd_facts.py
deleted file mode 100644
index faf545c9c20..00000000000
--- a/python-avd/tests/pyavd/eos_designs/test_get_avd_facts.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright (c) 2023-2024 Arista Networks, Inc.
-# Use of this source code is governed by the Apache License 2.0
-# that can be found in the LICENSE file.
-from pyavd import get_avd_facts
-
-
-def test_get_avd_facts(all_inputs: dict) -> None:
- """Test get_avd_facts."""
- avd_facts = get_avd_facts(all_inputs)
-
- assert isinstance(avd_facts, dict)
- assert "avd_switch_facts" in avd_facts
- assert isinstance(avd_facts["avd_switch_facts"], dict)
- assert len(avd_facts["avd_switch_facts"]) == len(all_inputs)
- assert "avd_overlay_peers" in avd_facts
- assert isinstance(avd_facts["avd_overlay_peers"], dict)
- assert "avd_topology_peers" in avd_facts
- assert isinstance(avd_facts["avd_topology_peers"], dict)
diff --git a/python-avd/tests/pyavd/eos_designs/test_get_device_structured_config.py b/python-avd/tests/pyavd/eos_designs/test_get_device_structured_config.py
deleted file mode 100644
index 7d78598aaf4..00000000000
--- a/python-avd/tests/pyavd/eos_designs/test_get_device_structured_config.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright (c) 2023-2024 Arista Networks, Inc.
-# Use of this source code is governed by the Apache License 2.0
-# that can be found in the LICENSE file.
-from pyavd import get_device_structured_config, validate_inputs
-
-
-def test_get_device_structured_config(hostname: str, all_inputs: dict, avd_facts: dict, structured_configs: dict) -> None:
- """Test get_device_structured_config."""
- inputs = all_inputs[hostname]
-
- # run validation on inputs to ensure it is converted
- validate_inputs(inputs)
-
- expected_structured_config = structured_configs[hostname]
- structured_config = get_device_structured_config(hostname, inputs, avd_facts)
-
- assert isinstance(structured_config, dict)
- assert hostname == structured_config["hostname"]
- assert expected_structured_config == structured_config
diff --git a/python-avd/tests/pyavd/eos_designs/test_validate_inputs.py b/python-avd/tests/pyavd/eos_designs/test_validate_inputs.py
deleted file mode 100644
index 9d9578f2f12..00000000000
--- a/python-avd/tests/pyavd/eos_designs/test_validate_inputs.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright (c) 2023-2024 Arista Networks, Inc.
-# Use of this source code is governed by the Apache License 2.0
-# that can be found in the LICENSE file.
-from pyavd import validate_inputs
-
-
-def test_validate_inputs_with_valid_inputs(hostname: str, all_inputs: dict) -> None:
- """Test validate_inputs."""
- inputs = all_inputs[hostname]
- validation_result = validate_inputs(inputs)
- assert hostname
- assert validation_result.validation_errors == []
- assert hostname
- assert validation_result.failed is False
diff --git a/python-avd/tests/pyavd/eos_designs/test_validate_structured_config.py b/python-avd/tests/pyavd/eos_designs/test_validate_structured_config.py
deleted file mode 100644
index 790e8ab9925..00000000000
--- a/python-avd/tests/pyavd/eos_designs/test_validate_structured_config.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (c) 2023-2024 Arista Networks, Inc.
-# Use of this source code is governed by the Apache License 2.0
-# that can be found in the LICENSE file.
-from pyavd import validate_structured_config
-from pyavd._errors import AvdValidationError
-from pyavd.avd_schema_tools import AvdSchemaTools
-
-SCHEMA = AvdSchemaTools(schema_id="eos_cli_config_gen").avdschema._schema
-
-
-def test_validate_structured_config_with_valid_data(hostname: str, structured_configs: dict) -> None:
- """Test validate_structured_config."""
- structured_config = structured_configs[hostname]
- validation_result = validate_structured_config(structured_config)
- assert hostname
- assert validation_result.validation_errors == []
- assert hostname
- assert validation_result.failed is False
-
-
-def test_validate_structured_config_with_invalid_data(hostname: str, structured_configs: dict) -> None:
- """Test validate_structured_config."""
- structured_config = structured_configs[hostname]
-
- updated = False
- # Insert a bad key in a random dict (making sure the dict is covered by the schema)
- for key, value in structured_config.items():
- if not isinstance(value, dict) or "structured_config" in key or key not in SCHEMA["keys"]:
- continue
- value.update({"invalid_key": "some_value"})
- updated = True
- break
-
- # No dict found, so we insert our own instead
- if not updated:
- structured_config.update({"router_bgp": {"invalid_key": "some_value"}})
-
- validation_result = validate_structured_config(structured_config)
- assert validation_result.failed is True
- assert len(validation_result.validation_errors) >= 1
- assert isinstance(validation_result.validation_errors[0], AvdValidationError)
- assert "invalid_key" in str(validation_result.validation_errors[0])
diff --git a/python-avd/tests/pyavd/eos_cli_config_gen/__init__.py b/python-avd/tests/pyavd/molecule_scenarios/__init__.py
similarity index 100%
rename from python-avd/tests/pyavd/eos_cli_config_gen/__init__.py
rename to python-avd/tests/pyavd/molecule_scenarios/__init__.py
diff --git a/python-avd/tests/pyavd/molecule_scenarios/conftest.py b/python-avd/tests/pyavd/molecule_scenarios/conftest.py
new file mode 100644
index 00000000000..895b055ae08
--- /dev/null
+++ b/python-avd/tests/pyavd/molecule_scenarios/conftest.py
@@ -0,0 +1,37 @@
+# Copyright (c) 2023-2024 Arista Networks, Inc.
+# Use of this source code is governed by the Apache License 2.0
+# that can be found in the LICENSE file.
+from itertools import chain
+
+import pytest
+
+from tests.models import MoleculeHost, MoleculeScenario
+
+MOLECULE_SCENARIOS: dict[str, MoleculeScenario] = {}
+
+
+def get_test_id(host: MoleculeHost) -> str:
+ return f"{host.scenario.name}__{host.name}"
+
+
+def pytest_generate_tests(metafunc: pytest.Metafunc) -> None:
+ """
+ Generate MoleculeHost or MoleculeScenario instances for the scenarios given with pytest.mark.molecule_scenarios(, ).
+
+ The generated objects are inserted with parametrize to generate a test case for each.
+
+ Reads/updates MOLECULE_SCENARIOS for caching.
+ """
+ molecule_scenario_names = chain.from_iterable(list(mark.args) for mark in metafunc.definition.iter_markers(name="molecule_scenarios"))
+ molecule_scenarios: list[MoleculeScenario] = []
+ for molecule_scenario_name in molecule_scenario_names:
+ if molecule_scenario_name not in MOLECULE_SCENARIOS:
+ # Using this method since setdefault triggers init of the class which is expensive.
+ MOLECULE_SCENARIOS[molecule_scenario_name] = MoleculeScenario(molecule_scenario_name)
+ molecule_scenarios.append(MOLECULE_SCENARIOS[molecule_scenario_name])
+
+ if "molecule_host" in metafunc.fixturenames:
+ metafunc.parametrize("molecule_host", chain.from_iterable(scenario.hosts for scenario in molecule_scenarios), ids=get_test_id)
+
+ elif "molecule_scenario" in metafunc.fixturenames:
+ metafunc.parametrize("molecule_scenario", molecule_scenarios, ids=lambda scenario: scenario.name)
diff --git a/python-avd/tests/pyavd/molecule_scenarios/test_get_avd_facts.py b/python-avd/tests/pyavd/molecule_scenarios/test_get_avd_facts.py
new file mode 100644
index 00000000000..55f041c3fd6
--- /dev/null
+++ b/python-avd/tests/pyavd/molecule_scenarios/test_get_avd_facts.py
@@ -0,0 +1,35 @@
+# Copyright (c) 2023-2024 Arista Networks, Inc.
+# Use of this source code is governed by the Apache License 2.0
+# that can be found in the LICENSE file.
+from copy import deepcopy
+
+import pytest
+
+from pyavd import get_avd_facts
+from tests.models import MoleculeScenario
+
+
+@pytest.mark.molecule_scenarios(
+ "eos_designs_unit_tests",
+ "eos_designs_deprecated_vars",
+ "eos_designs_l2l2",
+ "eos_designs-mpls-isis-sr-ldp",
+ # TODO: "eos_designs-twodc-5stage-clos", # Remove inline jinja
+ "evpn_underlay_ebgp_overlay_ebgp",
+ "evpn_underlay_isis_overlay_ibgp",
+ "evpn_underlay_ospf_overlay_ebgp",
+ "evpn_underlay_rfc5549_overlay_ebgp",
+)
+def test_get_avd_facts(molecule_scenario: MoleculeScenario) -> None:
+ """Test get_avd_facts."""
+ molecule_inputs = {host.name: deepcopy(host.hostvars) for host in molecule_scenario.hosts}
+ avd_facts = get_avd_facts(molecule_inputs)
+
+ assert isinstance(avd_facts, dict)
+ assert "avd_switch_facts" in avd_facts
+ assert isinstance(avd_facts["avd_switch_facts"], dict)
+ assert len(avd_facts["avd_switch_facts"]) == len(molecule_inputs)
+ assert "avd_overlay_peers" in avd_facts
+ assert isinstance(avd_facts["avd_overlay_peers"], dict)
+ assert "avd_topology_peers" in avd_facts
+ assert isinstance(avd_facts["avd_topology_peers"], dict)
diff --git a/python-avd/tests/pyavd/eos_designs/test_get_device_config.py b/python-avd/tests/pyavd/molecule_scenarios/test_get_device_config.py
similarity index 50%
rename from python-avd/tests/pyavd/eos_designs/test_get_device_config.py
rename to python-avd/tests/pyavd/molecule_scenarios/test_get_device_config.py
index 5bbc5f18d97..233117ed1c3 100644
--- a/python-avd/tests/pyavd/eos_designs/test_get_device_config.py
+++ b/python-avd/tests/pyavd/molecule_scenarios/test_get_device_config.py
@@ -1,19 +1,41 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
+from copy import deepcopy
+
+import pytest
+
from pyavd import get_device_config, validate_structured_config
+from pyavd._utils import get
+from tests.models import MoleculeHost
-def test_get_device_config(hostname: str, all_inputs: dict, structured_configs: dict, configs: dict) -> None:
+@pytest.mark.molecule_scenarios(
+ "eos_designs_unit_tests",
+ "eos_designs_deprecated_vars",
+ "eos_cli_config_gen",
+ "eos_cli_config_gen_deprecated_vars",
+ "eos_designs_l2l2",
+ "eos_designs-mpls-isis-sr-ldp",
+ "eos_designs-twodc-5stage-clos",
+ "evpn_underlay_ebgp_overlay_ebgp",
+ "evpn_underlay_isis_overlay_ibgp",
+ "evpn_underlay_ospf_overlay_ebgp",
+ "evpn_underlay_rfc5549_overlay_ebgp",
+)
+def test_get_device_config(molecule_host: MoleculeHost) -> None:
"""Test get_device_config."""
# Loading inputs first and then updating structured config on top.
# This is how Ansible behaves, so we need this to generate the same configs.
# The underlying cause is eos_cli_config_gen inputs being set in eos_designs molecule vars,
# which are then _not_ included in the structured_config, hence lost unless we include the
# inputs as well.
- structured_config: dict = all_inputs[hostname]
- structured_config.update(structured_configs[hostname])
- expected_config: str = configs[hostname]
+ structured_config: dict = deepcopy(molecule_host.hostvars)
+ structured_config.update(deepcopy(molecule_host.structured_config))
+ expected_config = molecule_host.config
+
+ if not get(structured_config, "eos_cli_config_gen_configuration.enable", default=True):
+ return
# run validation on structured_config to ensure it is converted
validate_structured_config(structured_config)
@@ -21,5 +43,4 @@ def test_get_device_config(hostname: str, all_inputs: dict, structured_configs:
device_config = get_device_config(structured_config)
assert isinstance(device_config, str)
- assert f"hostname {hostname}\n" in device_config
assert device_config == expected_config
diff --git a/python-avd/tests/pyavd/molecule_scenarios/test_get_device_doc.py b/python-avd/tests/pyavd/molecule_scenarios/test_get_device_doc.py
new file mode 100644
index 00000000000..8abe7ecaa81
--- /dev/null
+++ b/python-avd/tests/pyavd/molecule_scenarios/test_get_device_doc.py
@@ -0,0 +1,49 @@
+# Copyright (c) 2023-2024 Arista Networks, Inc.
+# Use of this source code is governed by the Apache License 2.0
+# that can be found in the LICENSE file.
+from copy import deepcopy
+
+import pytest
+
+from pyavd import get_device_doc, validate_structured_config
+from pyavd._utils import get
+from tests.models import MoleculeHost
+
+
+@pytest.mark.molecule_scenarios(
+ "eos_cli_config_gen",
+ "eos_cli_config_gen_deprecated_vars",
+ "eos_designs_l2l2",
+ "eos_designs-mpls-isis-sr-ldp",
+ "eos_designs-twodc-5stage-clos",
+ "evpn_underlay_ebgp_overlay_ebgp",
+ "evpn_underlay_isis_overlay_ibgp",
+ "evpn_underlay_ospf_overlay_ebgp",
+ "evpn_underlay_rfc5549_overlay_ebgp",
+)
+def test_get_device_doc(molecule_host: MoleculeHost) -> None:
+ """Test get_device_config."""
+ # Loading inputs first and then updating structured config on top.
+ # This is how Ansible behaves, so we need this to generate the same configs.
+ # The underlying cause is eos_cli_config_gen inputs being set in eos_designs molecule vars,
+ # which are then _not_ included in the structured_config, hence lost unless we include the
+ # inputs as well.
+ structured_config: dict = deepcopy(molecule_host.hostvars)
+ structured_config.update(deepcopy(molecule_host.structured_config))
+
+ if not get(structured_config, "eos_cli_config_gen_documentation.enable", default=True):
+ return
+
+ # TODO: Deprecated, remove in 6.0.0
+ if not get(structured_config, "generate_device_documentation", default=True):
+ return
+
+ # run validation on structured_config to ensure it is covered
+ validate_structured_config(structured_config)
+
+ expected_doc = molecule_host.doc
+
+ device_doc = get_device_doc(structured_config, add_md_toc=True)
+
+ assert isinstance(device_doc, str)
+ assert device_doc == expected_doc
diff --git a/python-avd/tests/pyavd/molecule_scenarios/test_get_device_structured_config.py b/python-avd/tests/pyavd/molecule_scenarios/test_get_device_structured_config.py
new file mode 100644
index 00000000000..b91f3777bbc
--- /dev/null
+++ b/python-avd/tests/pyavd/molecule_scenarios/test_get_device_structured_config.py
@@ -0,0 +1,36 @@
+# Copyright (c) 2023-2024 Arista Networks, Inc.
+# Use of this source code is governed by the Apache License 2.0
+# that can be found in the LICENSE file.
+from copy import deepcopy
+
+import pytest
+
+from pyavd import get_device_structured_config, validate_inputs
+from tests.models import MoleculeHost
+
+
+@pytest.mark.molecule_scenarios(
+ "eos_designs_unit_tests",
+ "eos_designs_deprecated_vars",
+ "eos_designs_l2l2",
+ "eos_designs-mpls-isis-sr-ldp",
+ # TODO: "eos_designs-twodc-5stage-clos", # Remove inline jinja
+ # TODO: "evpn_underlay_ebgp_overlay_ebgp", # Remove inline jinja
+ "evpn_underlay_isis_overlay_ibgp",
+ "evpn_underlay_ospf_overlay_ebgp",
+ "evpn_underlay_rfc5549_overlay_ebgp",
+)
+def test_get_device_structured_config(molecule_host: MoleculeHost) -> None:
+ """Test get_device_structured_config."""
+ inputs = deepcopy(molecule_host.hostvars)
+
+ # run validation on inputs to ensure it is converted
+ validate_inputs(inputs)
+
+ expected_structured_config = molecule_host.structured_config
+ avd_facts = molecule_host.scenario.avd_facts
+ structured_config = get_device_structured_config(molecule_host.name, inputs, avd_facts)
+
+ assert isinstance(structured_config, dict)
+ assert molecule_host.name == structured_config["hostname"]
+ assert expected_structured_config == structured_config
diff --git a/python-avd/tests/pyavd/molecule_scenarios/test_validate_inputs.py b/python-avd/tests/pyavd/molecule_scenarios/test_validate_inputs.py
new file mode 100644
index 00000000000..d725f8efee0
--- /dev/null
+++ b/python-avd/tests/pyavd/molecule_scenarios/test_validate_inputs.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2023-2024 Arista Networks, Inc.
+# Use of this source code is governed by the Apache License 2.0
+# that can be found in the LICENSE file.
+from copy import deepcopy
+
+import pytest
+
+from pyavd import validate_inputs
+from tests.models import MoleculeHost
+
+
+# eos_cli_config_gen inputs are validated by `validate_structured_config` in another file.
+@pytest.mark.molecule_scenarios(
+ "eos_designs_unit_tests",
+ "eos_designs_deprecated_vars",
+ "eos_designs_l2l2",
+ "eos_designs-mpls-isis-sr-ldp",
+ "eos_designs-twodc-5stage-clos",
+ "evpn_underlay_ebgp_overlay_ebgp",
+ "evpn_underlay_isis_overlay_ibgp",
+ "evpn_underlay_ospf_overlay_ebgp",
+ "evpn_underlay_rfc5549_overlay_ebgp",
+)
+def test_validate_inputs_with_valid_inputs(molecule_host: MoleculeHost) -> None:
+ """Test validate_inputs."""
+ inputs = deepcopy(molecule_host.hostvars)
+ validation_result = validate_inputs(inputs)
+ assert validation_result.validation_errors == []
+ assert validation_result.failed is False
diff --git a/python-avd/tests/pyavd/molecule_scenarios/test_validate_structured_config.py b/python-avd/tests/pyavd/molecule_scenarios/test_validate_structured_config.py
new file mode 100644
index 00000000000..e47b07c50c6
--- /dev/null
+++ b/python-avd/tests/pyavd/molecule_scenarios/test_validate_structured_config.py
@@ -0,0 +1,100 @@
+# Copyright (c) 2023-2024 Arista Networks, Inc.
+# Use of this source code is governed by the Apache License 2.0
+# that can be found in the LICENSE file.
+from copy import deepcopy
+
+import pytest
+
+from pyavd import validate_structured_config
+from pyavd._errors import AvdValidationError
+from pyavd.avd_schema_tools import AvdSchemaTools
+from tests.models import MoleculeHost
+
+SCHEMA = AvdSchemaTools(schema_id="eos_cli_config_gen").avdschema._schema
+
+
+@pytest.mark.molecule_scenarios(
+ "eos_designs_unit_tests",
+ "eos_designs_deprecated_vars",
+ "eos_designs_l2l2",
+ "eos_designs-mpls-isis-sr-ldp",
+ # TODO: "eos_designs-twodc-5stage-clos", # Remove inline jinja
+ "evpn_underlay_ebgp_overlay_ebgp",
+ "evpn_underlay_isis_overlay_ibgp",
+ "evpn_underlay_ospf_overlay_ebgp",
+ "evpn_underlay_rfc5549_overlay_ebgp",
+)
+def test_validate_structured_config_with_valid_data(molecule_host: MoleculeHost) -> None:
+ """Test validate_structured_config."""
+ structured_config = deepcopy(molecule_host.structured_config)
+ validation_result = validate_structured_config(structured_config)
+ assert validation_result.validation_errors == []
+ assert validation_result.failed is False
+
+
+@pytest.mark.molecule_scenarios(
+ "eos_designs_unit_tests",
+ "eos_designs_deprecated_vars",
+)
+def test_validate_structured_config_with_invalid_data(molecule_host: MoleculeHost) -> None:
+ """Test validate_structured_config."""
+ structured_config = deepcopy(molecule_host.structured_config)
+
+ updated = False
+ # Insert a bad key in a random dict (making sure the dict is covered by the schema)
+ for key, value in structured_config.items():
+ if not isinstance(value, dict) or "structured_config" in key or key not in SCHEMA["keys"]:
+ continue
+ value.update({"invalid_key": "some_value"})
+ updated = True
+ break
+
+ # No dict found, so we insert our own instead
+ if not updated:
+ structured_config.update({"router_bgp": {"invalid_key": "some_value"}})
+
+ validation_result = validate_structured_config(structured_config)
+ assert validation_result.failed is True
+ assert len(validation_result.validation_errors) >= 1
+ assert isinstance(validation_result.validation_errors[0], AvdValidationError)
+ assert "invalid_key" in str(validation_result.validation_errors[0])
+
+
+@pytest.mark.molecule_scenarios(
+ "eos_cli_config_gen",
+ "eos_cli_config_gen_deprecated_vars",
+)
+def test_validate_cli_gen_inputs_with_valid_data(molecule_host: MoleculeHost) -> None:
+ """Test validate_structured_config."""
+ inputs = deepcopy(molecule_host.hostvars)
+ validation_result = validate_structured_config(inputs)
+ assert validation_result.validation_errors == []
+ assert validation_result.failed is False
+
+
+@pytest.mark.molecule_scenarios(
+ "eos_cli_config_gen",
+ "eos_cli_config_gen_deprecated_vars",
+)
+def test_validate_cli_gen_inputs_with_invalid_data(molecule_host: MoleculeHost) -> None:
+ """Test validate_structured_config."""
+ inputs = deepcopy(molecule_host.hostvars)
+
+ updated = False
+ # Insert a bad key in a random dict (making sure the dict is covered by the schema)
+ for key, value in inputs.items():
+ if not isinstance(value, dict) or key not in SCHEMA["keys"]:
+ continue
+ value.update({"invalid_key": "some_value"})
+ updated = True
+ break
+
+ # No dict found, so we insert our own instead
+ if not updated:
+ inputs.update({"router_bgp": {"invalid_key": "some_value"}})
+
+ validation_result = validate_structured_config(inputs)
+ assert validation_result.failed is True
+ assert len(validation_result.validation_errors) >= 1
+ assert isinstance(validation_result.validation_errors[0], AvdValidationError)
+ assert "invalid_key" in str(validation_result.validation_errors[0])
diff --git a/python-avd/tox.ini b/python-avd/tox.ini
index c42f1372adc..768f410200f 100644
--- a/python-avd/tox.ini
+++ b/python-avd/tox.ini
@@ -20,37 +20,26 @@ python =
description = run the tests with our own runner
package = wheel
wheel_build_env = .pkg
-allowlist_externals =
- make
-deps =
- ansible-core<2.17
+dependency_groups =
pytest
- PyYAML>=6.0.0
- pydantic>=2.3.0
- referencing>=0.35.0
commands =
- make test-dep
# posargs allows to run only a specific test using
# tox -e -- path/to/my/test::test
pytest {posargs}
[testenv:coverage]
-deps =
+dependency_groups =
pytest
- PyYAML>=6.0.0
- pydantic>=2.3.0
- coverage[toml]
- referencing>=0.35.0
+ coverage
commands =
coverage erase
- make test-dep
# posargs allows to run only a specific test using
# tox -e -- path/to/my/test::test
coverage run --rcfile=pyproject.toml -m pytest {posargs}
[testenv:report]
skip_install = true
-deps =
- coverage[toml]
+dependency_groups =
+ coverage
commands =
coverage report --rcfile=pyproject.toml