diff options
Diffstat (limited to '')
28 files changed, 11284 insertions, 0 deletions
diff --git a/tests/units/anta_tests/README.md b/tests/units/anta_tests/README.md new file mode 100644 index 0000000..6e4c5f0 --- /dev/null +++ b/tests/units/anta_tests/README.md @@ -0,0 +1,7 @@ +<!-- + ~ 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. + --> + +A guide explaining how to write the unit test can be found in the [contribution guide](../../../docs/contribution.md#unit-tests) diff --git a/tests/units/anta_tests/__init__.py b/tests/units/anta_tests/__init__.py new file mode 100644 index 0000000..e772bee --- /dev/null +++ b/tests/units/anta_tests/__init__.py @@ -0,0 +1,3 @@ +# 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/tests/units/anta_tests/routing/__init__.py b/tests/units/anta_tests/routing/__init__.py new file mode 100644 index 0000000..e772bee --- /dev/null +++ b/tests/units/anta_tests/routing/__init__.py @@ -0,0 +1,3 @@ +# 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/tests/units/anta_tests/routing/test_bgp.py b/tests/units/anta_tests/routing/test_bgp.py new file mode 100644 index 0000000..799f058 --- /dev/null +++ b/tests/units/anta_tests/routing/test_bgp.py @@ -0,0 +1,3385 @@ +# 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. +""" +Tests for anta.tests.routing.bgp.py +""" +# pylint: disable=C0302 +from __future__ import annotations + +from typing import Any + +# pylint: disable=C0413 +# because of the patch above +from anta.tests.routing.bgp import ( # noqa: E402 + VerifyBGPAdvCommunities, + VerifyBGPExchangedRoutes, + VerifyBGPPeerASNCap, + VerifyBGPPeerCount, + VerifyBGPPeerMD5Auth, + VerifyBGPPeerMPCaps, + VerifyBGPPeerRouteRefreshCap, + VerifyBGPPeersHealth, + VerifyBGPSpecificPeers, + VerifyBGPTimers, + VerifyEVPNType2Route, +) +from tests.lib.anta import test # noqa: F401; pylint: disable=W0611 + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifyBGPPeerCount, + "eos_data": [ + { + "vrfs": { + "default": { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.255.0": { + "description": "DC1-SPINE1_Ethernet1", + "version": 4, + "msgReceived": 0, + "msgSent": 0, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 0, + "prefixReceived": 0, + "upDownTime": 1694266295.098931, + "underMaintenance": False, + "peerState": "Established", + }, + "10.1.255.2": { + "description": "DC1-SPINE2_Ethernet1", + "version": 4, + "msgReceived": 3759, + "msgSent": 3757, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 14, + "prefixReceived": 14, + "upDownTime": 1694266296.367261, + "underMaintenance": False, + "peerState": "Established", + }, + }, + } + } + } + ], + "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "default", "num_peers": 2}]}, + "expected": {"result": "success"}, + }, + { + "name": "failure-wrong-count", + "test": VerifyBGPPeerCount, + "eos_data": [ + { + "vrfs": { + "default": { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.255.0": { + "description": "DC1-SPINE1_Ethernet1", + "version": 4, + "msgReceived": 0, + "msgSent": 0, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 0, + "prefixReceived": 0, + "upDownTime": 1694266295.098931, + "underMaintenance": False, + "peerState": "Established", + }, + "10.1.255.2": { + "description": "DC1-SPINE2_Ethernet1", + "version": 4, + "msgReceived": 3759, + "msgSent": 3757, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 14, + "prefixReceived": 14, + "upDownTime": 1694266296.367261, + "underMaintenance": False, + "peerState": "Established", + }, + }, + } + } + } + ], + "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "default", "num_peers": 3}]}, + "expected": {"result": "failure", "messages": ["Failures: [{'afi': 'ipv4', 'safi': 'unicast', 'vrfs': {'default': 'Expected: 3, Actual: 2'}}]"]}, + }, + { + "name": "failure-no-peers", + "test": VerifyBGPPeerCount, + "eos_data": [{"vrfs": {"default": {"vrf": "default", "routerId": "10.1.0.3", "asn": "65120", "peers": {}}}}], + "inputs": {"address_families": [{"afi": "ipv6", "safi": "unicast", "vrf": "default", "num_peers": 3}]}, + "expected": {"result": "failure", "messages": ["Failures: [{'afi': 'ipv6', 'safi': 'unicast', 'vrfs': {'default': 'Expected: 3, Actual: 0'}}]"]}, + }, + { + "name": "failure-not-configured", + "test": VerifyBGPPeerCount, + "eos_data": [{"vrfs": {}}], + "inputs": {"address_families": [{"afi": "ipv6", "safi": "multicast", "vrf": "DEV", "num_peers": 3}]}, + "expected": {"result": "failure", "messages": ["Failures: [{'afi': 'ipv6', 'safi': 'multicast', 'vrfs': {'DEV': 'Not Configured'}}]"]}, + }, + { + "name": "success-vrf-all", + "test": VerifyBGPPeerCount, + "eos_data": [ + { + "vrfs": { + "default": { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.255.0": { + "description": "DC1-SPINE1_Ethernet1", + "version": 4, + "msgReceived": 0, + "msgSent": 0, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 0, + "prefixReceived": 0, + "upDownTime": 1694266295.098931, + "underMaintenance": False, + "peerState": "Established", + }, + }, + }, + "PROD": { + "vrf": "PROD", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.254.1": { + "description": "DC1-LEAF1B", + "version": 4, + "msgReceived": 3777, + "msgSent": 3764, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65120", + "prefixAccepted": 2, + "prefixReceived": 2, + "upDownTime": 1694266296.659891, + "underMaintenance": False, + "peerState": "Established", + }, + "192.168.1.11": { + "description": "K8S-CLUSTER1", + "version": 4, + "msgReceived": 6417, + "msgSent": 7546, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65000", + "prefixAccepted": 1, + "prefixReceived": 1, + "upDownTime": 1694266329.978035, + "underMaintenance": False, + "peerState": "Established", + }, + }, + }, + } + } + ], + "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "all", "num_peers": 3}]}, + "expected": {"result": "success"}, + }, + { + "name": "failure-vrf-all", + "test": VerifyBGPPeerCount, + "eos_data": [ + { + "vrfs": { + "default": { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.255.0": { + "description": "DC1-SPINE1_Ethernet1", + "version": 4, + "msgReceived": 0, + "msgSent": 0, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 0, + "prefixReceived": 0, + "upDownTime": 1694266295.098931, + "underMaintenance": False, + "peerState": "Established", + }, + }, + }, + "PROD": { + "vrf": "PROD", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.254.1": { + "description": "DC1-LEAF1B", + "version": 4, + "msgReceived": 3777, + "msgSent": 3764, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65120", + "prefixAccepted": 2, + "prefixReceived": 2, + "upDownTime": 1694266296.659891, + "underMaintenance": False, + "peerState": "Established", + }, + "192.168.1.11": { + "description": "K8S-CLUSTER1", + "version": 4, + "msgReceived": 6417, + "msgSent": 7546, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65000", + "prefixAccepted": 1, + "prefixReceived": 1, + "upDownTime": 1694266329.978035, + "underMaintenance": False, + "peerState": "Established", + }, + }, + }, + } + } + ], + "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "all", "num_peers": 5}]}, + "expected": {"result": "failure", "messages": ["Failures: [{'afi': 'ipv4', 'safi': 'unicast', 'vrfs': {'all': 'Expected: 5, Actual: 3'}}]"]}, + }, + { + "name": "success-multiple-afi", + "test": VerifyBGPPeerCount, + "eos_data": [ + { + "vrfs": { + "PROD": { + "vrf": "PROD", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.254.1": { + "description": "DC1-LEAF1B", + "version": 4, + "msgReceived": 3777, + "msgSent": 3764, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65120", + "prefixAccepted": 2, + "prefixReceived": 2, + "upDownTime": 1694266296.659891, + "underMaintenance": False, + "peerState": "Established", + }, + "192.168.1.11": { + "description": "K8S-CLUSTER1", + "version": 4, + "msgReceived": 6417, + "msgSent": 7546, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65000", + "prefixAccepted": 1, + "prefixReceived": 1, + "upDownTime": 1694266329.978035, + "underMaintenance": False, + "peerState": "Established", + }, + }, + } + } + }, + { + "vrfs": { + "default": { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.0.1": { + "description": "DC1-SPINE1", + "version": 4, + "msgReceived": 3894, + "msgSent": 3897, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 0, + "prefixReceived": 0, + "upDownTime": 1694266296.584472, + "underMaintenance": False, + "peerState": "Established", + }, + "10.1.0.2": { + "description": "DC1-SPINE2", + "version": 4, + "msgReceived": 3893, + "msgSent": 3902, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 0, + "prefixReceived": 0, + "upDownTime": 1694266297.433896, + "underMaintenance": False, + "peerState": "Established", + }, + }, + } + } + }, + ], + "inputs": { + "address_families": [ + {"afi": "ipv4", "safi": "unicast", "vrf": "PROD", "num_peers": 2}, + {"afi": "evpn", "num_peers": 2}, + ] + }, + "expected": { + "result": "success", + }, + }, + { + "name": "failure-multiple-afi", + "test": VerifyBGPPeerCount, + "eos_data": [ + { + "vrfs": { + "PROD": { + "vrf": "PROD", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.254.1": { + "description": "DC1-LEAF1B", + "version": 4, + "msgReceived": 3777, + "msgSent": 3764, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65120", + "prefixAccepted": 2, + "prefixReceived": 2, + "upDownTime": 1694266296.659891, + "underMaintenance": False, + "peerState": "Established", + }, + "192.168.1.11": { + "description": "K8S-CLUSTER1", + "version": 4, + "msgReceived": 6417, + "msgSent": 7546, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65000", + "prefixAccepted": 1, + "prefixReceived": 1, + "upDownTime": 1694266329.978035, + "underMaintenance": False, + "peerState": "Established", + }, + }, + } + } + }, + {"vrfs": {}}, + { + "vrfs": { + "default": { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.0.1": { + "description": "DC1-SPINE1", + "version": 4, + "msgReceived": 3894, + "msgSent": 3897, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 0, + "prefixReceived": 0, + "upDownTime": 1694266296.584472, + "underMaintenance": False, + "peerState": "Established", + }, + "10.1.0.2": { + "description": "DC1-SPINE2", + "version": 4, + "msgReceived": 3893, + "msgSent": 3902, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 0, + "prefixReceived": 0, + "upDownTime": 1694266297.433896, + "underMaintenance": False, + "peerState": "Established", + }, + }, + } + } + }, + ], + "inputs": { + "address_families": [ + {"afi": "ipv4", "safi": "unicast", "vrf": "PROD", "num_peers": 3}, + {"afi": "evpn", "num_peers": 3}, + {"afi": "ipv6", "safi": "unicast", "vrf": "default", "num_peers": 3}, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Failures: [{'afi': 'ipv4', 'safi': 'unicast', 'vrfs': {'PROD': 'Expected: 3, Actual: 2'}}, " + "{'afi': 'ipv6', 'safi': 'unicast', 'vrfs': {'default': 'Not Configured'}}, " + "{'afi': 'evpn', 'vrfs': {'default': 'Expected: 3, Actual: 2'}}" + ], + }, + }, + { + "name": "success", + "test": VerifyBGPPeersHealth, + "eos_data": [ + { + "vrfs": { + "default": { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.255.0": { + "description": "DC1-SPINE1_Ethernet1", + "version": 4, + "msgReceived": 0, + "msgSent": 0, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 0, + "prefixReceived": 0, + "upDownTime": 1694266295.098931, + "underMaintenance": False, + "peerState": "Established", + }, + "10.1.255.2": { + "description": "DC1-SPINE2_Ethernet1", + "version": 4, + "msgReceived": 3759, + "msgSent": 3757, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 14, + "prefixReceived": 14, + "upDownTime": 1694266296.367261, + "underMaintenance": False, + "peerState": "Established", + }, + }, + } + } + } + ], + "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "default"}]}, + "expected": {"result": "success"}, + }, + { + "name": "failure-issues", + "test": VerifyBGPPeersHealth, + "eos_data": [ + { + "vrfs": { + "default": { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.255.0": { + "description": "DC1-SPINE1_Ethernet1", + "version": 4, + "msgReceived": 0, + "msgSent": 0, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 0, + "prefixReceived": 0, + "upDownTime": 1694266295.098931, + "underMaintenance": False, + "peerState": "Idle", + }, + "10.1.255.2": { + "description": "DC1-SPINE2_Ethernet1", + "version": 4, + "msgReceived": 3759, + "msgSent": 3757, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 14, + "prefixReceived": 14, + "upDownTime": 1694266296.367261, + "underMaintenance": False, + "peerState": "Established", + }, + }, + } + } + } + ], + "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "default"}]}, + "expected": { + "result": "failure", + "messages": [ + "Failures: [{'afi': 'ipv4', 'safi': 'unicast', 'vrfs': {'default': {'10.1.255.0': {'peerState': 'Idle', 'inMsgQueue': 0, 'outMsgQueue': 0}}}}]" + ], + }, + }, + { + "name": "success-vrf-all", + "test": VerifyBGPPeersHealth, + "eos_data": [ + { + "vrfs": { + "default": { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.255.0": { + "description": "DC1-SPINE1_Ethernet1", + "version": 4, + "msgReceived": 0, + "msgSent": 0, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 0, + "prefixReceived": 0, + "upDownTime": 1694266295.098931, + "underMaintenance": False, + "peerState": "Established", + }, + "10.1.255.2": { + "description": "DC1-SPINE2_Ethernet1", + "version": 4, + "msgReceived": 3759, + "msgSent": 3757, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 14, + "prefixReceived": 14, + "upDownTime": 1694266296.367261, + "underMaintenance": False, + "peerState": "Established", + }, + }, + }, + "PROD": { + "vrf": "PROD", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.254.1": { + "description": "DC1-LEAF1B", + "version": 4, + "msgReceived": 3777, + "msgSent": 3764, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65120", + "prefixAccepted": 2, + "prefixReceived": 2, + "upDownTime": 1694266296.659891, + "underMaintenance": False, + "peerState": "Established", + }, + "192.168.1.11": { + "description": "K8S-CLUSTER1", + "version": 4, + "msgReceived": 6417, + "msgSent": 7546, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65000", + "prefixAccepted": 1, + "prefixReceived": 1, + "upDownTime": 1694266329.978035, + "underMaintenance": False, + "peerState": "Established", + }, + }, + }, + } + } + ], + "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "all"}]}, + "expected": { + "result": "success", + }, + }, + { + "name": "failure-issues-vrf-all", + "test": VerifyBGPPeersHealth, + "eos_data": [ + { + "vrfs": { + "default": { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.255.0": { + "description": "DC1-SPINE1_Ethernet1", + "version": 4, + "msgReceived": 0, + "msgSent": 0, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 0, + "prefixReceived": 0, + "upDownTime": 1694266295.098931, + "underMaintenance": False, + "peerState": "Idle", + }, + "10.1.255.2": { + "description": "DC1-SPINE2_Ethernet1", + "version": 4, + "msgReceived": 3759, + "msgSent": 3757, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 14, + "prefixReceived": 14, + "upDownTime": 1694266296.367261, + "underMaintenance": False, + "peerState": "Established", + }, + }, + }, + "PROD": { + "vrf": "PROD", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.254.1": { + "description": "DC1-LEAF1B", + "version": 4, + "msgReceived": 3777, + "msgSent": 3764, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65120", + "prefixAccepted": 2, + "prefixReceived": 2, + "upDownTime": 1694266296.659891, + "underMaintenance": False, + "peerState": "Established", + }, + "192.168.1.11": { + "description": "K8S-CLUSTER1", + "version": 4, + "msgReceived": 6417, + "msgSent": 7546, + "inMsgQueue": 100, + "outMsgQueue": 200, + "asn": "65000", + "prefixAccepted": 1, + "prefixReceived": 1, + "upDownTime": 1694266329.978035, + "underMaintenance": False, + "peerState": "Established", + }, + }, + }, + } + } + ], + "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "all"}]}, + "expected": { + "result": "failure", + "messages": [ + "Failures: [{'afi': 'ipv4', 'safi': 'unicast', 'vrfs': {'default': {'10.1.255.0': {'peerState': 'Idle', 'inMsgQueue': 0, 'outMsgQueue': 0}}, " + "'PROD': {'192.168.1.11': {'peerState': 'Established', 'inMsgQueue': 100, 'outMsgQueue': 200}}}}]" + ], + }, + }, + { + "name": "failure-not-configured", + "test": VerifyBGPPeersHealth, + "eos_data": [{"vrfs": {}}], + "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "DEV"}]}, + "expected": {"result": "failure", "messages": ["Failures: [{'afi': 'ipv4', 'safi': 'unicast', 'vrfs': {'DEV': 'Not Configured'}}]"]}, + }, + { + "name": "failure-no-peers", + "test": VerifyBGPPeersHealth, + "eos_data": [{"vrfs": {"default": {"vrf": "default", "routerId": "10.1.0.3", "asn": "65120", "peers": {}}}}], + "inputs": {"address_families": [{"afi": "ipv4", "safi": "multicast"}]}, + "expected": {"result": "failure", "messages": ["Failures: [{'afi': 'ipv4', 'safi': 'multicast', 'vrfs': {'default': 'No Peers'}}]"]}, + }, + { + "name": "success-multiple-afi", + "test": VerifyBGPPeersHealth, + "eos_data": [ + { + "vrfs": { + "PROD": { + "vrf": "PROD", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.254.1": { + "description": "DC1-LEAF1B", + "version": 4, + "msgReceived": 3777, + "msgSent": 3764, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65120", + "prefixAccepted": 2, + "prefixReceived": 2, + "upDownTime": 1694266296.659891, + "underMaintenance": False, + "peerState": "Established", + }, + "192.168.1.11": { + "description": "K8S-CLUSTER1", + "version": 4, + "msgReceived": 6417, + "msgSent": 7546, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65000", + "prefixAccepted": 1, + "prefixReceived": 1, + "upDownTime": 1694266329.978035, + "underMaintenance": False, + "peerState": "Established", + }, + }, + } + } + }, + { + "vrfs": { + "default": { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.0.1": { + "description": "DC1-SPINE1", + "version": 4, + "msgReceived": 3894, + "msgSent": 3897, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 0, + "prefixReceived": 0, + "upDownTime": 1694266296.584472, + "underMaintenance": False, + "peerState": "Established", + }, + "10.1.0.2": { + "description": "DC1-SPINE2", + "version": 4, + "msgReceived": 3893, + "msgSent": 3902, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 0, + "prefixReceived": 0, + "upDownTime": 1694266297.433896, + "underMaintenance": False, + "peerState": "Established", + }, + }, + } + } + }, + ], + "inputs": { + "address_families": [ + {"afi": "ipv4", "safi": "unicast", "vrf": "PROD"}, + {"afi": "evpn"}, + ] + }, + "expected": { + "result": "success", + }, + }, + { + "name": "failure-multiple-afi", + "test": VerifyBGPPeersHealth, + "eos_data": [ + { + "vrfs": { + "PROD": { + "vrf": "PROD", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.254.1": { + "description": "DC1-LEAF1B", + "version": 4, + "msgReceived": 3777, + "msgSent": 3764, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65120", + "prefixAccepted": 2, + "prefixReceived": 2, + "upDownTime": 1694266296.659891, + "underMaintenance": False, + "peerState": "Established", + }, + "192.168.1.11": { + "description": "K8S-CLUSTER1", + "version": 4, + "msgReceived": 6417, + "msgSent": 7546, + "inMsgQueue": 10, + "outMsgQueue": 0, + "asn": "65000", + "prefixAccepted": 1, + "prefixReceived": 1, + "upDownTime": 1694266329.978035, + "underMaintenance": False, + "peerState": "Established", + }, + }, + } + } + }, + {"vrfs": {}}, + { + "vrfs": { + "default": { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.0.1": { + "description": "DC1-SPINE1", + "version": 4, + "msgReceived": 3894, + "msgSent": 3897, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 0, + "prefixReceived": 0, + "upDownTime": 1694266296.584472, + "underMaintenance": False, + "peerState": "Established", + }, + "10.1.0.2": { + "description": "DC1-SPINE2", + "version": 4, + "msgReceived": 3893, + "msgSent": 3902, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 0, + "prefixReceived": 0, + "upDownTime": 1694266297.433896, + "underMaintenance": False, + "peerState": "Idle", + }, + }, + } + } + }, + ], + "inputs": { + "address_families": [ + {"afi": "ipv4", "safi": "unicast", "vrf": "PROD"}, + {"afi": "evpn"}, + {"afi": "ipv6", "safi": "unicast", "vrf": "default"}, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Failures: [{'afi': 'ipv4', 'safi': 'unicast', 'vrfs': " + "{'PROD': {'192.168.1.11': {'peerState': 'Established', 'inMsgQueue': 10, 'outMsgQueue': 0}}}}, " + "{'afi': 'ipv6', 'safi': 'unicast', 'vrfs': {'default': 'Not Configured'}}, " + "{'afi': 'evpn', 'vrfs': {'default': {'10.1.0.2': {'peerState': 'Idle', 'inMsgQueue': 0, 'outMsgQueue': 0}}}" + ], + }, + }, + { + "name": "success", + "test": VerifyBGPSpecificPeers, + "eos_data": [ + { + "vrfs": { + "default": { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.255.0": { + "description": "DC1-SPINE1_Ethernet1", + "version": 4, + "msgReceived": 0, + "msgSent": 0, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 0, + "prefixReceived": 0, + "upDownTime": 1694266295.098931, + "underMaintenance": False, + "peerState": "Established", + }, + "10.1.255.2": { + "description": "DC1-SPINE2_Ethernet1", + "version": 4, + "msgReceived": 3759, + "msgSent": 3757, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 14, + "prefixReceived": 14, + "upDownTime": 1694266296.367261, + "underMaintenance": False, + "peerState": "Established", + }, + }, + } + } + } + ], + "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "default", "peers": ["10.1.255.0", "10.1.255.2"]}]}, + "expected": {"result": "success"}, + }, + { + "name": "failure-issues", + "test": VerifyBGPSpecificPeers, + "eos_data": [ + { + "vrfs": { + "default": { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.255.0": { + "description": "DC1-SPINE1_Ethernet1", + "version": 4, + "msgReceived": 0, + "msgSent": 0, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 0, + "prefixReceived": 0, + "upDownTime": 1694266295.098931, + "underMaintenance": False, + "peerState": "Idle", + }, + "10.1.255.2": { + "description": "DC1-SPINE2_Ethernet1", + "version": 4, + "msgReceived": 3759, + "msgSent": 3757, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 14, + "prefixReceived": 14, + "upDownTime": 1694266296.367261, + "underMaintenance": False, + "peerState": "Established", + }, + }, + } + } + } + ], + "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "default", "peers": ["10.1.255.0", "10.1.255.2"]}]}, + "expected": { + "result": "failure", + "messages": [ + "Failures: [{'afi': 'ipv4', 'safi': 'unicast', 'vrfs': {'default': {'10.1.255.0': {'peerState': 'Idle', 'inMsgQueue': 0, 'outMsgQueue': 0}}}}]" + ], + }, + }, + { + "name": "failure-not-configured", + "test": VerifyBGPSpecificPeers, + "eos_data": [{"vrfs": {}}], + "inputs": {"address_families": [{"afi": "ipv4", "safi": "unicast", "vrf": "DEV", "peers": ["10.1.255.0"]}]}, + "expected": {"result": "failure", "messages": ["Failures: [{'afi': 'ipv4', 'safi': 'unicast', 'vrfs': {'DEV': 'Not Configured'}}]"]}, + }, + { + "name": "failure-no-peers", + "test": VerifyBGPSpecificPeers, + "eos_data": [{"vrfs": {"default": {"vrf": "default", "routerId": "10.1.0.3", "asn": "65120", "peers": {}}}}], + "inputs": {"address_families": [{"afi": "ipv4", "safi": "multicast", "peers": ["10.1.255.0"]}]}, + "expected": { + "result": "failure", + "messages": ["Failures: [{'afi': 'ipv4', 'safi': 'multicast', 'vrfs': {'default': {'10.1.255.0': {'peerNotFound': True}}}}]"], + }, + }, + { + "name": "success-multiple-afi", + "test": VerifyBGPSpecificPeers, + "eos_data": [ + { + "vrfs": { + "PROD": { + "vrf": "PROD", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.254.1": { + "description": "DC1-LEAF1B", + "version": 4, + "msgReceived": 3777, + "msgSent": 3764, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65120", + "prefixAccepted": 2, + "prefixReceived": 2, + "upDownTime": 1694266296.659891, + "underMaintenance": False, + "peerState": "Established", + }, + "192.168.1.11": { + "description": "K8S-CLUSTER1", + "version": 4, + "msgReceived": 6417, + "msgSent": 7546, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65000", + "prefixAccepted": 1, + "prefixReceived": 1, + "upDownTime": 1694266329.978035, + "underMaintenance": False, + "peerState": "Established", + }, + }, + } + } + }, + { + "vrfs": { + "default": { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.0.1": { + "description": "DC1-SPINE1", + "version": 4, + "msgReceived": 3894, + "msgSent": 3897, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 0, + "prefixReceived": 0, + "upDownTime": 1694266296.584472, + "underMaintenance": False, + "peerState": "Established", + }, + "10.1.0.2": { + "description": "DC1-SPINE2", + "version": 4, + "msgReceived": 3893, + "msgSent": 3902, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 0, + "prefixReceived": 0, + "upDownTime": 1694266297.433896, + "underMaintenance": False, + "peerState": "Established", + }, + }, + } + } + }, + ], + "inputs": { + "address_families": [ + {"afi": "ipv4", "safi": "unicast", "vrf": "PROD", "peers": ["10.1.254.1", "192.168.1.11"]}, + {"afi": "evpn", "peers": ["10.1.0.1", "10.1.0.2"]}, + ] + }, + "expected": {"result": "success"}, + }, + { + "name": "failure-multiple-afi", + "test": VerifyBGPSpecificPeers, + "eos_data": [ + { + "vrfs": { + "PROD": { + "vrf": "PROD", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.254.1": { + "description": "DC1-LEAF1B", + "version": 4, + "msgReceived": 3777, + "msgSent": 3764, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65120", + "prefixAccepted": 2, + "prefixReceived": 2, + "upDownTime": 1694266296.659891, + "underMaintenance": False, + "peerState": "Established", + }, + "192.168.1.11": { + "description": "K8S-CLUSTER1", + "version": 4, + "msgReceived": 6417, + "msgSent": 7546, + "inMsgQueue": 10, + "outMsgQueue": 0, + "asn": "65000", + "prefixAccepted": 1, + "prefixReceived": 1, + "upDownTime": 1694266329.978035, + "underMaintenance": False, + "peerState": "Established", + }, + }, + } + } + }, + {"vrfs": {}}, + { + "vrfs": { + "default": { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": "65120", + "peers": { + "10.1.0.1": { + "description": "DC1-SPINE1", + "version": 4, + "msgReceived": 3894, + "msgSent": 3897, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 0, + "prefixReceived": 0, + "upDownTime": 1694266296.584472, + "underMaintenance": False, + "peerState": "Established", + }, + "10.1.0.2": { + "description": "DC1-SPINE2", + "version": 4, + "msgReceived": 3893, + "msgSent": 3902, + "inMsgQueue": 0, + "outMsgQueue": 0, + "asn": "65100", + "prefixAccepted": 0, + "prefixReceived": 0, + "upDownTime": 1694266297.433896, + "underMaintenance": False, + "peerState": "Idle", + }, + }, + } + } + }, + ], + "inputs": { + "address_families": [ + {"afi": "ipv4", "safi": "unicast", "vrf": "PROD", "peers": ["10.1.254.1", "192.168.1.11"]}, + {"afi": "evpn", "peers": ["10.1.0.1", "10.1.0.2"]}, + {"afi": "ipv6", "safi": "unicast", "vrf": "default", "peers": ["10.1.0.1", "10.1.0.2"]}, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Failures: [{'afi': 'ipv4', 'safi': 'unicast', 'vrfs': " + "{'PROD': {'192.168.1.11': {'peerState': 'Established', 'inMsgQueue': 10, 'outMsgQueue': 0}}}}, " + "{'afi': 'ipv6', 'safi': 'unicast', 'vrfs': {'default': 'Not Configured'}}, " + "{'afi': 'evpn', 'vrfs': {'default': {'10.1.0.2': {'peerState': 'Idle', 'inMsgQueue': 0, 'outMsgQueue': 0}}}" + ], + }, + }, + { + "name": "success", + "test": VerifyBGPExchangedRoutes, + "eos_data": [ + { + "vrfs": { + "default": { + "bgpRouteEntries": { + "192.0.254.3/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": True, + }, + } + ] + }, + "192.0.254.5/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": True, + }, + } + ] + }, + }, + } + } + }, + { + "vrfs": { + "default": { + "bgpRouteEntries": { + "192.0.254.3/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": True, + }, + } + ] + }, + "192.0.254.5/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": True, + }, + } + ] + }, + }, + } + } + }, + { + "vrfs": { + "default": { + "bgpRouteEntries": { + "192.0.254.3/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": True, + }, + } + ], + }, + "192.0.255.4/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": True, + }, + } + ], + }, + }, + } + } + }, + { + "vrfs": { + "default": { + "bgpRouteEntries": { + "192.0.254.3/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": True, + }, + } + ], + }, + "192.0.255.4/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": True, + }, + } + ], + }, + }, + } + } + }, + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.1", + "vrf": "default", + "advertised_routes": ["192.0.254.5/32", "192.0.254.3/32"], + "received_routes": ["192.0.254.3/32", "192.0.255.4/32"], + }, + { + "peer_address": "172.30.11.5", + "vrf": "default", + "advertised_routes": ["192.0.254.3/32", "192.0.254.5/32"], + "received_routes": ["192.0.254.3/32", "192.0.255.4/32"], + }, + ] + }, + "expected": {"result": "success"}, + }, + { + "name": "failure-no-routes", + "test": VerifyBGPExchangedRoutes, + "eos_data": [ + {"vrfs": {"default": {"vrf": "default", "routerId": "192.0.255.1", "asn": "65001", "bgpRouteEntries": {}}}}, + {"vrfs": {"default": {"vrf": "default", "routerId": "192.0.255.1", "asn": "65001", "bgpRouteEntries": {}}}}, + {"vrfs": {"default": {"vrf": "default", "routerId": "192.0.255.1", "asn": "65001", "bgpRouteEntries": {}}}}, + {"vrfs": {"default": {"vrf": "default", "routerId": "192.0.255.1", "asn": "65001", "bgpRouteEntries": {}}}}, + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.11", + "vrf": "default", + "advertised_routes": ["192.0.254.3/32"], + "received_routes": ["192.0.255.3/32"], + }, + { + "peer_address": "172.30.11.12", + "vrf": "default", + "advertised_routes": ["192.0.254.31/32"], + "received_routes": ["192.0.255.31/32"], + }, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peers are not found or routes are not exchanged properly:\n" + "{'bgp_peers': {'172.30.11.11': {'default': 'Not configured'}, '172.30.11.12': {'default': 'Not configured'}}}" + ], + }, + }, + { + "name": "failure-no-peer", + "test": VerifyBGPExchangedRoutes, + "eos_data": [ + {"vrfs": {}}, + { + "vrfs": { + "default": { + "bgpRouteEntries": { + "192.0.254.3/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": True, + }, + } + ] + }, + "192.0.254.5/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": True, + }, + } + ] + }, + }, + } + } + }, + {"vrfs": {}}, + { + "vrfs": { + "default": { + "bgpRouteEntries": { + "192.0.254.3/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": True, + }, + } + ], + }, + "192.0.255.4/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": True, + }, + } + ], + }, + }, + } + } + }, + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.11", + "vrf": "MGMT", + "advertised_routes": ["192.0.254.3/32"], + "received_routes": ["192.0.255.3/32"], + }, + { + "peer_address": "172.30.11.5", + "vrf": "default", + "advertised_routes": ["192.0.254.3/32", "192.0.254.5/32"], + "received_routes": ["192.0.254.3/32", "192.0.255.4/32"], + }, + ] + }, + "expected": { + "result": "failure", + "messages": ["Following BGP peers are not found or routes are not exchanged properly:\n{'bgp_peers': {'172.30.11.11': {'MGMT': 'Not configured'}}}"], + }, + }, + { + "name": "failure-missing-routes", + "test": VerifyBGPExchangedRoutes, + "eos_data": [ + { + "vrfs": { + "default": { + "bgpRouteEntries": { + "192.0.254.3/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": True, + }, + } + ] + }, + "192.0.254.5/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": True, + }, + } + ] + }, + }, + } + } + }, + { + "vrfs": { + "default": { + "bgpRouteEntries": { + "192.0.254.3/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": True, + }, + } + ] + }, + "192.0.254.5/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": True, + }, + } + ] + }, + }, + } + } + }, + { + "vrfs": { + "default": { + "bgpRouteEntries": { + "192.0.254.3/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": True, + }, + } + ], + }, + "192.0.255.4/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": True, + }, + } + ], + }, + }, + } + } + }, + { + "vrfs": { + "default": { + "bgpRouteEntries": { + "192.0.254.3/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": True, + }, + } + ], + }, + "192.0.255.4/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": True, + }, + } + ], + }, + }, + } + } + }, + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.1", + "vrf": "default", + "advertised_routes": ["192.0.254.3/32", "192.0.254.51/32"], + "received_routes": ["192.0.254.31/32", "192.0.255.4/32"], + }, + { + "peer_address": "172.30.11.5", + "vrf": "default", + "advertised_routes": ["192.0.254.31/32", "192.0.254.5/32"], + "received_routes": ["192.0.254.3/32", "192.0.255.41/32"], + }, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peers are not found or routes are not exchanged properly:\n{'bgp_peers': " + "{'172.30.11.1': {'default': {'advertised_routes': {'192.0.254.51/32': 'Not found'}, 'received_routes': {'192.0.254.31/32': 'Not found'}}}, " + "'172.30.11.5': {'default': {'advertised_routes': {'192.0.254.31/32': 'Not found'}, 'received_routes': {'192.0.255.41/32': 'Not found'}}}}}" + ], + }, + }, + { + "name": "failure-invalid-or-inactive-routes", + "test": VerifyBGPExchangedRoutes, + "eos_data": [ + { + "vrfs": { + "default": { + "bgpRouteEntries": { + "192.0.254.3/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": False, + "active": True, + }, + } + ] + }, + "192.0.254.5/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": False, + }, + } + ] + }, + }, + } + } + }, + { + "vrfs": { + "default": { + "bgpRouteEntries": { + "192.0.254.3/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": False, + "active": True, + }, + } + ] + }, + "192.0.254.5/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": False, + "active": True, + }, + } + ] + }, + }, + } + } + }, + { + "vrfs": { + "default": { + "bgpRouteEntries": { + "192.0.254.3/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": False, + "active": False, + }, + } + ], + }, + "192.0.255.4/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": False, + "active": False, + }, + } + ], + }, + }, + } + } + }, + { + "vrfs": { + "default": { + "bgpRouteEntries": { + "192.0.254.3/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": False, + }, + } + ], + }, + "192.0.255.4/32": { + "bgpRoutePaths": [ + { + "routeType": { + "valid": True, + "active": False, + }, + } + ], + }, + }, + } + } + }, + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.1", + "vrf": "default", + "advertised_routes": ["192.0.254.3/32", "192.0.254.51/32"], + "received_routes": ["192.0.254.31/32", "192.0.255.4/32"], + }, + { + "peer_address": "172.30.11.5", + "vrf": "default", + "advertised_routes": ["192.0.254.31/32", "192.0.254.5/32"], + "received_routes": ["192.0.254.3/32", "192.0.255.41/32"], + }, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peers are not found or routes are not exchanged properly:\n{'bgp_peers': " + "{'172.30.11.1': {'default': {'advertised_routes': {'192.0.254.3/32': {'valid': True, 'active': False}, '192.0.254.51/32': 'Not found'}, " + "'received_routes': {'192.0.254.31/32': 'Not found', '192.0.255.4/32': {'valid': False, 'active': False}}}}, " + "'172.30.11.5': {'default': {'advertised_routes': {'192.0.254.31/32': 'Not found', '192.0.254.5/32': {'valid': True, 'active': False}}, " + "'received_routes': {'192.0.254.3/32': {'valid': False, 'active': True}, '192.0.255.41/32': 'Not found'}}}}}" + ], + }, + }, + { + "name": "success", + "test": VerifyBGPPeerMPCaps, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "neighborCapabilities": { + "multiprotocolCaps": { + "ipv4Unicast": {"advertised": True, "received": True, "enabled": True}, + "ipv4MplsLabels": {"advertised": True, "received": True, "enabled": True}, + } + }, + } + ] + }, + "MGMT": { + "peerList": [ + { + "peerAddress": "172.30.11.10", + "neighborCapabilities": { + "multiprotocolCaps": { + "ipv4Unicast": {"advertised": True, "received": True, "enabled": True}, + "ipv4MplsVpn": {"advertised": True, "received": True, "enabled": True}, + } + }, + } + ] + }, + } + } + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.1", + "vrf": "default", + "capabilities": ["Ipv4 Unicast", "ipv4 Mpls labels"], + }, + { + "peer_address": "172.30.11.10", + "vrf": "MGMT", + "capabilities": ["ipv4 Unicast", "ipv4 MplsVpn"], + }, + ] + }, + "expected": {"result": "success"}, + }, + { + "name": "failure-no-vrf", + "test": VerifyBGPPeerMPCaps, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "neighborCapabilities": { + "multiprotocolCaps": { + "ipv4Unicast": {"advertised": True, "received": True, "enabled": True}, + "ipv4MplsVpn": {"advertised": True, "received": True, "enabled": True}, + } + }, + } + ] + } + } + } + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.1", + "vrf": "MGMT", + "capabilities": ["ipv4 Unicast", "ipv4mplslabels"], + } + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peer multiprotocol capabilities are not found or not ok:\n{'bgp_peers': {'172.30.11.1': {'MGMT': {'status': 'Not configured'}}}}" + ], + }, + }, + { + "name": "failure-no-peer", + "test": VerifyBGPPeerMPCaps, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "neighborCapabilities": { + "multiprotocolCaps": {"ipv4Unicast": {"advertised": True, "received": True, "enabled": True}}, + }, + } + ] + }, + "MGMT": { + "peerList": [ + { + "peerAddress": "172.30.11.10", + "neighborCapabilities": { + "multiprotocolCaps": {"ipv4Unicast": {"advertised": True, "received": True, "enabled": True}}, + }, + } + ] + }, + } + } + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.10", + "vrf": "default", + "capabilities": ["ipv4Unicast", "L2 Vpn EVPN"], + }, + { + "peer_address": "172.30.11.1", + "vrf": "MGMT", + "capabilities": ["ipv4Unicast", "L2 Vpn EVPN"], + }, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peer multiprotocol capabilities are not found or not ok:\n" + "{'bgp_peers': {'172.30.11.10': {'default': {'status': 'Not configured'}}, '172.30.11.1': {'MGMT': {'status': 'Not configured'}}}}" + ], + }, + }, + { + "name": "failure-missing-capabilities", + "test": VerifyBGPPeerMPCaps, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "neighborCapabilities": { + "multiprotocolCaps": {"ipv4Unicast": {"advertised": True, "received": True, "enabled": True}}, + }, + } + ] + } + } + } + ], + "inputs": {"bgp_peers": [{"peer_address": "172.30.11.1", "vrf": "default", "capabilities": ["ipv4 Unicast", "L2VpnEVPN"]}]}, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peer multiprotocol capabilities are not found or not ok:\n{'bgp_peers': {'172.30.11.1': {'default': {'l2VpnEvpn': 'not found'}}}}" + ], + }, + }, + { + "name": "failure-incorrect-capabilities", + "test": VerifyBGPPeerMPCaps, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "neighborCapabilities": { + "multiprotocolCaps": { + "ipv4Unicast": {"advertised": False, "received": False, "enabled": False}, + "ipv4MplsVpn": {"advertised": False, "received": True, "enabled": False}, + }, + }, + } + ] + }, + "MGMT": { + "peerList": [ + { + "peerAddress": "172.30.11.10", + "neighborCapabilities": { + "multiprotocolCaps": { + "l2VpnEvpn": {"advertised": True, "received": False, "enabled": False}, + "ipv4MplsVpn": {"advertised": False, "received": False, "enabled": True}, + }, + }, + }, + { + "peerAddress": "172.30.11.11", + "neighborCapabilities": { + "multiprotocolCaps": { + "ipv4Unicast": {"advertised": False, "received": False, "enabled": False}, + "ipv4MplsVpn": {"advertised": False, "received": False, "enabled": False}, + }, + }, + }, + ] + }, + } + } + ], + "inputs": { + "bgp_peers": [ + {"peer_address": "172.30.11.1", "vrf": "default", "capabilities": ["ipv4 unicast", "ipv4 mpls vpn", "L2 vpn EVPN"]}, + {"peer_address": "172.30.11.10", "vrf": "MGMT", "capabilities": ["ipv4unicast", "ipv4 mplsvpn", "L2vpnEVPN"]}, + {"peer_address": "172.30.11.11", "vrf": "MGMT", "capabilities": ["Ipv4 Unicast", "ipv4 MPLSVPN", "L2 vpnEVPN"]}, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peer multiprotocol capabilities are not found or not ok:\n" + "{'bgp_peers': {'172.30.11.1': {'default': {'ipv4Unicast': {'advertised': False, 'received': False, 'enabled': False}, " + "'ipv4MplsVpn': {'advertised': False, 'received': True, 'enabled': False}, 'l2VpnEvpn': 'not found'}}, " + "'172.30.11.10': {'MGMT': {'ipv4Unicast': 'not found', 'ipv4MplsVpn': {'advertised': False, 'received': False, 'enabled': True}, " + "'l2VpnEvpn': {'advertised': True, 'received': False, 'enabled': False}}}, " + "'172.30.11.11': {'MGMT': {'ipv4Unicast': {'advertised': False, 'received': False, 'enabled': False}, " + "'ipv4MplsVpn': {'advertised': False, 'received': False, 'enabled': False}, 'l2VpnEvpn': 'not found'}}}}" + ], + }, + }, + { + "name": "success", + "test": VerifyBGPPeerASNCap, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "neighborCapabilities": { + "fourOctetAsnCap": {"advertised": True, "received": True, "enabled": True}, + }, + } + ] + }, + "MGMT": { + "peerList": [ + { + "peerAddress": "172.30.11.10", + "neighborCapabilities": { + "fourOctetAsnCap": {"advertised": True, "received": True, "enabled": True}, + }, + } + ] + }, + } + } + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.1", + "vrf": "default", + }, + { + "peer_address": "172.30.11.10", + "vrf": "MGMT", + }, + ] + }, + "expected": {"result": "success"}, + }, + { + "name": "failure-no-vrf", + "test": VerifyBGPPeerASNCap, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "neighborCapabilities": { + "fourOctetAsnCap": {"advertised": True, "received": True, "enabled": True}, + }, + } + ] + } + }, + "MGMT": { + "peerList": [ + { + "peerAddress": "172.30.11.10", + "neighborCapabilities": { + "fourOctetAsnCap": {"advertised": True, "received": True, "enabled": True}, + }, + } + ] + }, + } + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.1", + "vrf": "MGMT", + }, + { + "peer_address": "172.30.11.10", + "vrf": "default", + }, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peer four octet asn capabilities are not found or not ok:\n" + "{'bgp_peers': {'172.30.11.1': {'MGMT': {'status': 'Not configured'}}, '172.30.11.10': {'default': {'status': 'Not configured'}}}}" + ], + }, + }, + { + "name": "failure-no-peer", + "test": VerifyBGPPeerASNCap, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "neighborCapabilities": { + "multiprotocolCaps": {"ipv4Unicast": {"advertised": True, "received": True, "enabled": True}}, + }, + }, + ] + } + } + } + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.10", + "vrf": "default", + } + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peer four octet asn capabilities are not found or not ok:\n{'bgp_peers': {'172.30.11.10': {'default': {'status': 'Not configured'}}}}" + ], + }, + }, + { + "name": "failure-missing-capabilities", + "test": VerifyBGPPeerASNCap, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "neighborCapabilities": { + "multiprotocolCaps": {"ipv4Unicast": {"advertised": True, "received": True, "enabled": True}}, + }, + } + ] + }, + "MGMT": { + "peerList": [ + { + "peerAddress": "172.30.11.10", + "neighborCapabilities": { + "multiprotocolCaps": {"ipv4MplsLabels": {"advertised": True, "received": True, "enabled": True}}, + }, + } + ] + }, + } + } + ], + "inputs": {"bgp_peers": [{"peer_address": "172.30.11.1", "vrf": "default"}, {"peer_address": "172.30.11.10", "vrf": "MGMT"}]}, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peer four octet asn capabilities are not found or not ok:\n" + "{'bgp_peers': {'172.30.11.1': {'default': {'fourOctetAsnCap': 'not found'}}, '172.30.11.10': {'MGMT': {'fourOctetAsnCap': 'not found'}}}}" + ], + }, + }, + { + "name": "failure-incorrect-capabilities", + "test": VerifyBGPPeerASNCap, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "neighborCapabilities": { + "fourOctetAsnCap": {"advertised": False, "received": False, "enabled": False}, + }, + } + ] + }, + "MGMT": { + "peerList": [ + { + "peerAddress": "172.30.11.10", + "neighborCapabilities": { + "fourOctetAsnCap": {"advertised": True, "received": False, "enabled": True}, + }, + } + ] + }, + } + } + ], + "inputs": {"bgp_peers": [{"peer_address": "172.30.11.1", "vrf": "default"}, {"peer_address": "172.30.11.10", "vrf": "MGMT"}]}, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peer four octet asn capabilities are not found or not ok:\n" + "{'bgp_peers': {'172.30.11.1': {'default': {'fourOctetAsnCap': {'advertised': False, 'received': False, 'enabled': False}}}, " + "'172.30.11.10': {'MGMT': {'fourOctetAsnCap': {'advertised': True, 'received': False, 'enabled': True}}}}}" + ], + }, + }, + { + "name": "success", + "test": VerifyBGPPeerRouteRefreshCap, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "neighborCapabilities": { + "routeRefreshCap": {"advertised": True, "received": True, "enabled": True}, + }, + } + ] + }, + "CS": { + "peerList": [ + { + "peerAddress": "172.30.11.11", + "neighborCapabilities": { + "routeRefreshCap": {"advertised": True, "received": True, "enabled": True}, + }, + } + ] + }, + } + } + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.1", + "vrf": "default", + }, + { + "peer_address": "172.30.11.11", + "vrf": "CS", + }, + ] + }, + "expected": {"result": "success"}, + }, + { + "name": "failure-no-vrf", + "test": VerifyBGPPeerRouteRefreshCap, + "eos_data": [{"vrfs": {}}], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.1", + "vrf": "MGMT", + } + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peer route refresh capabilities are not found or not ok:\n{'bgp_peers': {'172.30.11.1': {'MGMT': {'status': 'Not configured'}}}}" + ], + }, + }, + { + "name": "failure-no-peer", + "test": VerifyBGPPeerRouteRefreshCap, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "neighborCapabilities": { + "multiprotocolCaps": {"ip4Unicast": {"advertised": True, "received": True, "enabled": True}}, + }, + } + ] + }, + "CS": { + "peerList": [ + { + "peerAddress": "172.30.11.12", + "neighborCapabilities": { + "multiprotocolCaps": {"ip4Unicast": {"advertised": True, "received": True, "enabled": True}}, + }, + } + ] + }, + } + } + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.12", + "vrf": "default", + }, + { + "peer_address": "172.30.11.1", + "vrf": "CS", + }, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peer route refresh capabilities are not found or not ok:\n" + "{'bgp_peers': {'172.30.11.12': {'default': {'status': 'Not configured'}}, '172.30.11.1': {'CS': {'status': 'Not configured'}}}}" + ], + }, + }, + { + "name": "failure-missing-capabilities", + "test": VerifyBGPPeerRouteRefreshCap, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "neighborCapabilities": { + "multiprotocolCaps": {"ipv4Unicast": {"advertised": True, "received": True, "enabled": True}}, + }, + } + ] + }, + "CS": { + "peerList": [ + { + "peerAddress": "172.30.11.11", + "neighborCapabilities": { + "multiprotocolCaps": {"ipv4Unicast": {"advertised": True, "received": True, "enabled": True}}, + }, + } + ] + }, + } + } + ], + "inputs": {"bgp_peers": [{"peer_address": "172.30.11.1", "vrf": "default"}, {"peer_address": "172.30.11.11", "vrf": "CS"}]}, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peer route refresh capabilities are not found or not ok:\n" + "{'bgp_peers': {'172.30.11.1': {'default': {'routeRefreshCap': 'not found'}}, '172.30.11.11': {'CS': {'routeRefreshCap': 'not found'}}}}" + ], + }, + }, + { + "name": "failure-incorrect-capabilities", + "test": VerifyBGPPeerRouteRefreshCap, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "neighborCapabilities": { + "routeRefreshCap": {"advertised": False, "received": False, "enabled": False}, + }, + } + ] + }, + "CS": { + "peerList": [ + { + "peerAddress": "172.30.11.11", + "neighborCapabilities": { + "routeRefreshCap": {"advertised": True, "received": True, "enabled": True}, + }, + } + ] + }, + } + } + ], + "inputs": {"bgp_peers": [{"peer_address": "172.30.11.1", "vrf": "default"}, {"peer_address": "172.30.11.11", "vrf": "CS"}]}, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peer route refresh capabilities are not found or not ok:\n" + "{'bgp_peers': {'172.30.11.1': {'default': {'routeRefreshCap': {'advertised': False, 'received': False, 'enabled': False}}}}}" + ], + }, + }, + { + "name": "success", + "test": VerifyBGPPeerMD5Auth, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "state": "Established", + "md5AuthEnabled": True, + } + ] + }, + "CS": { + "peerList": [ + { + "peerAddress": "172.30.11.10", + "state": "Established", + "md5AuthEnabled": True, + } + ] + }, + } + } + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.1", + "vrf": "default", + }, + { + "peer_address": "172.30.11.10", + "vrf": "CS", + }, + ] + }, + "expected": {"result": "success"}, + }, + { + "name": "failure-no-vrf", + "test": VerifyBGPPeerMD5Auth, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.10", + "state": "Established", + "md5AuthEnabled": True, + } + ] + }, + } + } + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.1", + "vrf": "MGMT", + } + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peers are not configured, not established or MD5 authentication is not enabled:\n" + "{'bgp_peers': {'172.30.11.1': {'MGMT': {'status': 'Not configured'}}}}" + ], + }, + }, + { + "name": "failure-no-peer", + "test": VerifyBGPPeerMD5Auth, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "state": "Established", + "md5AuthEnabled": True, + } + ] + }, + "CS": { + "peerList": [ + { + "peerAddress": "172.30.11.11", + "state": "Established", + "md5AuthEnabled": True, + } + ] + }, + } + } + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.10", + "vrf": "default", + }, + { + "peer_address": "172.30.11.11", + "vrf": "default", + }, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peers are not configured, not established or MD5 authentication is not enabled:\n" + "{'bgp_peers': {'172.30.11.10': {'default': {'status': 'Not configured'}}, '172.30.11.11': {'default': {'status': 'Not configured'}}}}" + ], + }, + }, + { + "name": "failure-not-established-peer", + "test": VerifyBGPPeerMD5Auth, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "state": "Idle", + "md5AuthEnabled": True, + } + ] + }, + "MGMT": { + "peerList": [ + { + "peerAddress": "172.30.11.10", + "state": "Idle", + "md5AuthEnabled": False, + } + ] + }, + } + } + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.1", + "vrf": "default", + }, + { + "peer_address": "172.30.11.10", + "vrf": "MGMT", + }, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peers are not configured, not established or MD5 authentication is not enabled:\n" + "{'bgp_peers': {'172.30.11.1': {'default': {'state': 'Idle', 'md5_auth_enabled': True}}, " + "'172.30.11.10': {'MGMT': {'state': 'Idle', 'md5_auth_enabled': False}}}}" + ], + }, + }, + { + "name": "failure-not-md5-peer", + "test": VerifyBGPPeerMD5Auth, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "state": "Established", + }, + {"peerAddress": "172.30.11.10", "state": "Established", "md5AuthEnabled": False}, + ] + }, + "MGMT": {"peerList": [{"peerAddress": "172.30.11.11", "state": "Established", "md5AuthEnabled": False}]}, + } + } + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.1", + "vrf": "default", + }, + { + "peer_address": "172.30.11.11", + "vrf": "MGMT", + }, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peers are not configured, not established or MD5 authentication is not enabled:\n" + "{'bgp_peers': {'172.30.11.1': {'default': {'state': 'Established', 'md5_auth_enabled': None}}, " + "'172.30.11.11': {'MGMT': {'state': 'Established', 'md5_auth_enabled': False}}}}" + ], + }, + }, + { + "name": "success", + "test": VerifyEVPNType2Route, + "eos_data": [ + { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": 65120, + "evpnRoutes": { + "RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": { + "evpnRoutePaths": [ + { + "routeType": { + "active": True, + "valid": True, + }, + }, + ] + }, + }, + } + ], + "inputs": {"vxlan_endpoints": [{"address": "192.168.20.102", "vni": 10020}]}, + "expected": {"result": "success"}, + }, + { + "name": "success-multiple-endpoints", + "test": VerifyEVPNType2Route, + "eos_data": [ + { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": 65120, + "evpnRoutes": { + "RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": { + "evpnRoutePaths": [ + { + "routeType": { + "active": True, + "valid": True, + }, + }, + ] + }, + }, + }, + { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": 65120, + "evpnRoutes": { + "RD: 10.1.0.5:500 mac-ip 10010 aac1.ab5d.b41e": { + "evpnRoutePaths": [ + { + "routeType": { + "active": True, + "valid": True, + }, + }, + ] + }, + }, + }, + ], + "inputs": {"vxlan_endpoints": [{"address": "192.168.20.102", "vni": 10020}, {"address": "aac1.ab5d.b41e", "vni": 10010}]}, + "expected": {"result": "success"}, + }, + { + "name": "success-multiple-routes-ip", + "test": VerifyEVPNType2Route, + "eos_data": [ + { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": 65120, + "evpnRoutes": { + "RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": { + "evpnRoutePaths": [ + { + "routeType": { + "active": True, + "valid": True, + }, + }, + ] + }, + "RD: 10.1.0.6:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": { + "evpnRoutePaths": [ + { + "routeType": { + "active": True, + "valid": True, + }, + }, + ] + }, + }, + }, + ], + "inputs": {"vxlan_endpoints": [{"address": "192.168.20.102", "vni": 10020}]}, + "expected": {"result": "success"}, + }, + { + "name": "success-multiple-routes-mac", + "test": VerifyEVPNType2Route, + "eos_data": [ + { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": 65120, + "evpnRoutes": { + "RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2": { + "evpnRoutePaths": [ + { + "routeType": { + "active": True, + "valid": True, + }, + }, + ] + }, + "RD: 10.1.0.6:500 mac-ip 10020 aac1.ab4e.bec2": { + "evpnRoutePaths": [ + { + "routeType": { + "active": True, + "valid": True, + }, + }, + ] + }, + }, + }, + ], + "inputs": {"vxlan_endpoints": [{"address": "aac1.ab4e.bec2", "vni": 10020}]}, + "expected": {"result": "success"}, + }, + { + "name": "success-multiple-routes-multiple-paths-ip", + "test": VerifyEVPNType2Route, + "eos_data": [ + { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": 65120, + "evpnRoutes": { + "RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": { + "evpnRoutePaths": [ + { + "routeType": { + "active": True, + "valid": True, + "ecmp": True, + "ecmpContributor": True, + "ecmpHead": True, + }, + }, + { + "routeType": { + "active": False, + "valid": True, + "ecmp": True, + "ecmpContributor": True, + "ecmpHead": False, + }, + }, + ] + }, + "RD: 10.1.0.6:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": { + "evpnRoutePaths": [ + { + "routeType": { + "active": True, + "valid": True, + }, + }, + ] + }, + }, + }, + ], + "inputs": {"vxlan_endpoints": [{"address": "192.168.20.102", "vni": 10020}]}, + "expected": {"result": "success"}, + }, + { + "name": "success-multiple-routes-multiple-paths-mac", + "test": VerifyEVPNType2Route, + "eos_data": [ + { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": 65120, + "evpnRoutes": { + "RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2": { + "evpnRoutePaths": [ + { + "routeType": { + "active": True, + "valid": True, + "ecmp": True, + "ecmpContributor": True, + "ecmpHead": True, + }, + }, + { + "routeType": { + "active": False, + "valid": True, + "ecmp": True, + "ecmpContributor": True, + "ecmpHead": False, + }, + }, + ] + }, + "RD: 10.1.0.6:500 mac-ip 10020 aac1.ab4e.bec2": { + "evpnRoutePaths": [ + { + "routeType": { + "active": True, + "valid": True, + }, + }, + ] + }, + }, + }, + ], + "inputs": {"vxlan_endpoints": [{"address": "aac1.ab4e.bec2", "vni": 10020}]}, + "expected": {"result": "success"}, + }, + { + "name": "failure-no-routes", + "test": VerifyEVPNType2Route, + "eos_data": [{"vrf": "default", "routerId": "10.1.0.3", "asn": 65120, "evpnRoutes": {}}], + "inputs": {"vxlan_endpoints": [{"address": "192.168.20.102", "vni": 10020}]}, + "expected": { + "result": "failure", + "messages": ["The following VXLAN endpoint do not have any EVPN Type-2 route: [('192.168.20.102', 10020)]"], + }, + }, + { + "name": "failure-path-not-active", + "test": VerifyEVPNType2Route, + "eos_data": [ + { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": 65120, + "evpnRoutes": { + "RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": { + "evpnRoutePaths": [ + { + "routeType": { + "active": False, + "valid": True, + }, + }, + ] + }, + }, + }, + ], + "inputs": {"vxlan_endpoints": [{"address": "192.168.20.102", "vni": 10020}]}, + "expected": { + "result": "failure", + "messages": [ + "The following EVPN Type-2 routes do not have at least one valid and active path: ['RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102']" + ], + }, + }, + { + "name": "failure-multiple-routes-not-active", + "test": VerifyEVPNType2Route, + "eos_data": [ + { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": 65120, + "evpnRoutes": { + "RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": { + "evpnRoutePaths": [ + { + "routeType": { + "active": False, + "valid": True, + }, + }, + ] + }, + "RD: 10.1.0.6:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": { + "evpnRoutePaths": [ + { + "routeType": { + "active": False, + "valid": False, + }, + }, + ] + }, + }, + }, + ], + "inputs": {"vxlan_endpoints": [{"address": "192.168.20.102", "vni": 10020}]}, + "expected": { + "result": "failure", + "messages": [ + "The following EVPN Type-2 routes do not have at least one valid and active path: " + "['RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102', " + "'RD: 10.1.0.6:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102']" + ], + }, + }, + { + "name": "failure-multiple-routes-multiple-paths-not-active", + "test": VerifyEVPNType2Route, + "eos_data": [ + { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": 65120, + "evpnRoutes": { + "RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": { + "evpnRoutePaths": [ + { + "routeType": { + "active": True, + "valid": True, + }, + }, + { + "routeType": { + "active": False, + "valid": True, + }, + }, + ] + }, + "RD: 10.1.0.6:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": { + "evpnRoutePaths": [ + { + "routeType": { + "active": False, + "valid": False, + }, + }, + { + "routeType": { + "active": False, + "valid": False, + }, + }, + ] + }, + }, + }, + ], + "inputs": {"vxlan_endpoints": [{"address": "192.168.20.102", "vni": 10020}]}, + "expected": { + "result": "failure", + "messages": [ + "The following EVPN Type-2 routes do not have at least one valid and active path: ['RD: 10.1.0.6:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102']" + ], + }, + }, + { + "name": "failure-multiple-endpoints", + "test": VerifyEVPNType2Route, + "eos_data": [ + { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": 65120, + "evpnRoutes": { + "RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102": { + "evpnRoutePaths": [ + { + "routeType": { + "active": False, + "valid": False, + }, + }, + ] + }, + }, + }, + { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": 65120, + "evpnRoutes": { + "RD: 10.1.0.5:500 mac-ip 10010 aac1.ab5d.b41e": { + "evpnRoutePaths": [ + { + "routeType": { + "active": False, + "valid": False, + }, + }, + ] + }, + }, + }, + ], + "inputs": {"vxlan_endpoints": [{"address": "192.168.20.102", "vni": 10020}, {"address": "aac1.ab5d.b41e", "vni": 10010}]}, + "expected": { + "result": "failure", + "messages": [ + "The following EVPN Type-2 routes do not have at least one valid and active path: " + "['RD: 10.1.0.5:500 mac-ip 10020 aac1.ab4e.bec2 192.168.20.102', " + "'RD: 10.1.0.5:500 mac-ip 10010 aac1.ab5d.b41e']" + ], + }, + }, + { + "name": "failure-multiple-endpoints-one-no-routes", + "test": VerifyEVPNType2Route, + "eos_data": [ + {"vrf": "default", "routerId": "10.1.0.3", "asn": 65120, "evpnRoutes": {}}, + { + "vrf": "default", + "routerId": "10.1.0.3", + "asn": 65120, + "evpnRoutes": { + "RD: 10.1.0.5:500 mac-ip 10010 aac1.ab5d.b41e 192.168.10.101": { + "evpnRoutePaths": [ + { + "routeType": { + "active": False, + "valid": False, + }, + }, + ] + }, + }, + }, + ], + "inputs": {"vxlan_endpoints": [{"address": "aac1.ab4e.bec2", "vni": 10020}, {"address": "192.168.10.101", "vni": 10010}]}, + "expected": { + "result": "failure", + "messages": [ + "The following VXLAN endpoint do not have any EVPN Type-2 route: [('aa:c1:ab:4e:be:c2', 10020)]", + "The following EVPN Type-2 routes do not have at least one valid and active path: " + "['RD: 10.1.0.5:500 mac-ip 10010 aac1.ab5d.b41e 192.168.10.101']", + ], + }, + }, + { + "name": "failure-multiple-endpoints-no-routes", + "test": VerifyEVPNType2Route, + "eos_data": [ + {"vrf": "default", "routerId": "10.1.0.3", "asn": 65120, "evpnRoutes": {}}, + {"vrf": "default", "routerId": "10.1.0.3", "asn": 65120, "evpnRoutes": {}}, + ], + "inputs": {"vxlan_endpoints": [{"address": "aac1.ab4e.bec2", "vni": 10020}, {"address": "192.168.10.101", "vni": 10010}]}, + "expected": { + "result": "failure", + "messages": ["The following VXLAN endpoint do not have any EVPN Type-2 route: [('aa:c1:ab:4e:be:c2', 10020), ('192.168.10.101', 10010)]"], + }, + }, + { + "name": "success", + "test": VerifyBGPAdvCommunities, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "advertisedCommunities": {"standard": True, "extended": True, "large": True}, + } + ] + }, + "MGMT": { + "peerList": [ + { + "peerAddress": "172.30.11.10", + "advertisedCommunities": {"standard": True, "extended": True, "large": True}, + } + ] + }, + } + } + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.1", + }, + { + "peer_address": "172.30.11.10", + "vrf": "MGMT", + }, + ] + }, + "expected": {"result": "success"}, + }, + { + "name": "failure-no-vrf", + "test": VerifyBGPAdvCommunities, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "advertisedCommunities": {"standard": True, "extended": True, "large": True}, + } + ] + }, + } + } + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.17", + "vrf": "MGMT", + } + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peers are not configured or advertised communities are not standard, extended, and large:\n" + "{'bgp_peers': {'172.30.11.17': {'MGMT': {'status': 'Not configured'}}}}" + ], + }, + }, + { + "name": "failure-no-peer", + "test": VerifyBGPAdvCommunities, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "advertisedCommunities": {"standard": True, "extended": True, "large": True}, + } + ] + }, + "MGMT": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "advertisedCommunities": {"standard": True, "extended": True, "large": True}, + } + ] + }, + } + } + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.10", + "vrf": "default", + }, + { + "peer_address": "172.30.11.12", + "vrf": "MGMT", + }, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peers are not configured or advertised communities are not standard, extended, and large:\n" + "{'bgp_peers': {'172.30.11.10': {'default': {'status': 'Not configured'}}, '172.30.11.12': {'MGMT': {'status': 'Not configured'}}}}" + ], + }, + }, + { + "name": "failure-not-correct-communities", + "test": VerifyBGPAdvCommunities, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "advertisedCommunities": {"standard": False, "extended": False, "large": False}, + } + ] + }, + "CS": { + "peerList": [ + { + "peerAddress": "172.30.11.10", + "advertisedCommunities": {"standard": True, "extended": True, "large": False}, + } + ] + }, + } + } + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.1", + "vrf": "default", + }, + { + "peer_address": "172.30.11.10", + "vrf": "CS", + }, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peers are not configured or advertised communities are not standard, extended, and large:\n" + "{'bgp_peers': {'172.30.11.1': {'default': {'advertised_communities': {'standard': False, 'extended': False, 'large': False}}}, " + "'172.30.11.10': {'CS': {'advertised_communities': {'standard': True, 'extended': True, 'large': False}}}}}" + ], + }, + }, + { + "name": "success", + "test": VerifyBGPTimers, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "holdTime": 180, + "keepaliveTime": 60, + } + ] + }, + "MGMT": { + "peerList": [ + { + "peerAddress": "172.30.11.11", + "holdTime": 180, + "keepaliveTime": 60, + } + ] + }, + } + } + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.1", + "vrf": "default", + "hold_time": 180, + "keep_alive_time": 60, + }, + { + "peer_address": "172.30.11.11", + "vrf": "MGMT", + "hold_time": 180, + "keep_alive_time": 60, + }, + ] + }, + "expected": {"result": "success"}, + }, + { + "name": "failure-no-peer", + "test": VerifyBGPTimers, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "holdTime": 180, + "keepaliveTime": 60, + } + ] + }, + "MGMT": {"peerList": []}, + } + } + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.1", + "vrf": "MGMT", + "hold_time": 180, + "keep_alive_time": 60, + }, + { + "peer_address": "172.30.11.11", + "vrf": "MGMT", + "hold_time": 180, + "keep_alive_time": 60, + }, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peers are not configured or hold and keep-alive timers are not correct:\n" + "{'172.30.11.1': {'MGMT': 'Not configured'}, '172.30.11.11': {'MGMT': 'Not configured'}}" + ], + }, + }, + { + "name": "failure-not-correct-timers", + "test": VerifyBGPTimers, + "eos_data": [ + { + "vrfs": { + "default": { + "peerList": [ + { + "peerAddress": "172.30.11.1", + "holdTime": 160, + "keepaliveTime": 60, + } + ] + }, + "MGMT": { + "peerList": [ + { + "peerAddress": "172.30.11.11", + "holdTime": 120, + "keepaliveTime": 40, + } + ] + }, + } + } + ], + "inputs": { + "bgp_peers": [ + { + "peer_address": "172.30.11.1", + "vrf": "default", + "hold_time": 180, + "keep_alive_time": 60, + }, + { + "peer_address": "172.30.11.11", + "vrf": "MGMT", + "hold_time": 180, + "keep_alive_time": 60, + }, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Following BGP peers are not configured or hold and keep-alive timers are not correct:\n" + "{'172.30.11.1': {'default': {'hold_time': 160, 'keep_alive_time': 60}}, " + "'172.30.11.11': {'MGMT': {'hold_time': 120, 'keep_alive_time': 40}}}" + ], + }, + }, +] diff --git a/tests/units/anta_tests/routing/test_generic.py b/tests/units/anta_tests/routing/test_generic.py new file mode 100644 index 0000000..90e70f8 --- /dev/null +++ b/tests/units/anta_tests/routing/test_generic.py @@ -0,0 +1,230 @@ +# 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. +""" +Tests for anta.tests.routing.generic.py +""" +from __future__ import annotations + +from typing import Any + +from anta.tests.routing.generic import VerifyRoutingProtocolModel, VerifyRoutingTableEntry, VerifyRoutingTableSize +from tests.lib.anta import test # noqa: F401; pylint: disable=W0611 + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifyRoutingProtocolModel, + "eos_data": [{"vrfs": {"default": {}}, "protoModelStatus": {"configuredProtoModel": "multi-agent", "operatingProtoModel": "multi-agent"}}], + "inputs": {"model": "multi-agent"}, + "expected": {"result": "success"}, + }, + { + "name": "failure-wrong-configured-model", + "test": VerifyRoutingProtocolModel, + "eos_data": [{"vrfs": {"default": {}}, "protoModelStatus": {"configuredProtoModel": "ribd", "operatingProtoModel": "ribd"}}], + "inputs": {"model": "multi-agent"}, + "expected": {"result": "failure", "messages": ["routing model is misconfigured: configured: ribd - operating: ribd - expected: multi-agent"]}, + }, + { + "name": "failure-mismatch-operating-model", + "test": VerifyRoutingProtocolModel, + "eos_data": [{"vrfs": {"default": {}}, "protoModelStatus": {"configuredProtoModel": "multi-agent", "operatingProtoModel": "ribd"}}], + "inputs": {"model": "multi-agent"}, + "expected": {"result": "failure", "messages": ["routing model is misconfigured: configured: multi-agent - operating: ribd - expected: multi-agent"]}, + }, + { + "name": "success", + "test": VerifyRoutingTableSize, + "eos_data": [ + { + "vrfs": { + "default": { + # Output truncated + "maskLen": {"8": 2}, + "totalRoutes": 123, + } + }, + } + ], + "inputs": {"minimum": 42, "maximum": 666}, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyRoutingTableSize, + "eos_data": [ + { + "vrfs": { + "default": { + # Output truncated + "maskLen": {"8": 2}, + "totalRoutes": 1000, + } + }, + } + ], + "inputs": {"minimum": 42, "maximum": 666}, + "expected": {"result": "failure", "messages": ["routing-table has 1000 routes and not between min (42) and maximum (666)"]}, + }, + { + "name": "error-max-smaller-than-min", + "test": VerifyRoutingTableSize, + "eos_data": [{}], + "inputs": {"minimum": 666, "maximum": 42}, + "expected": { + "result": "error", + "messages": ["Minimum 666 is greater than maximum 42"], + }, + }, + { + "name": "success", + "test": VerifyRoutingTableEntry, + "eos_data": [ + { + "vrfs": { + "default": { + "routingDisabled": False, + "allRoutesProgrammedHardware": True, + "allRoutesProgrammedKernel": True, + "defaultRouteState": "notSet", + "routes": { + "10.1.0.1/32": { + "hardwareProgrammed": True, + "routeType": "eBGP", + "routeLeaked": False, + "kernelProgrammed": True, + "routeAction": "forward", + "directlyConnected": False, + "preference": 20, + "metric": 0, + "vias": [{"nexthopAddr": "10.1.255.4", "interface": "Ethernet1"}], + } + }, + } + } + }, + { + "vrfs": { + "default": { + "routingDisabled": False, + "allRoutesProgrammedHardware": True, + "allRoutesProgrammedKernel": True, + "defaultRouteState": "notSet", + "routes": { + "10.1.0.2/32": { + "hardwareProgrammed": True, + "routeType": "eBGP", + "routeLeaked": False, + "kernelProgrammed": True, + "routeAction": "forward", + "directlyConnected": False, + "preference": 20, + "metric": 0, + "vias": [{"nexthopAddr": "10.1.255.6", "interface": "Ethernet2"}], + } + }, + } + } + }, + ], + "inputs": {"vrf": "default", "routes": ["10.1.0.1", "10.1.0.2"]}, + "expected": {"result": "success"}, + }, + { + "name": "failure-missing-route", + "test": VerifyRoutingTableEntry, + "eos_data": [ + { + "vrfs": { + "default": { + "routingDisabled": False, + "allRoutesProgrammedHardware": True, + "allRoutesProgrammedKernel": True, + "defaultRouteState": "notSet", + "routes": {}, + } + } + }, + { + "vrfs": { + "default": { + "routingDisabled": False, + "allRoutesProgrammedHardware": True, + "allRoutesProgrammedKernel": True, + "defaultRouteState": "notSet", + "routes": { + "10.1.0.2/32": { + "hardwareProgrammed": True, + "routeType": "eBGP", + "routeLeaked": False, + "kernelProgrammed": True, + "routeAction": "forward", + "directlyConnected": False, + "preference": 20, + "metric": 0, + "vias": [{"nexthopAddr": "10.1.255.6", "interface": "Ethernet2"}], + } + }, + } + } + }, + ], + "inputs": {"vrf": "default", "routes": ["10.1.0.1", "10.1.0.2"]}, + "expected": {"result": "failure", "messages": ["The following route(s) are missing from the routing table of VRF default: ['10.1.0.1']"]}, + }, + { + "name": "failure-wrong-route", + "test": VerifyRoutingTableEntry, + "eos_data": [ + { + "vrfs": { + "default": { + "routingDisabled": False, + "allRoutesProgrammedHardware": True, + "allRoutesProgrammedKernel": True, + "defaultRouteState": "notSet", + "routes": { + "10.1.0.1/32": { + "hardwareProgrammed": True, + "routeType": "eBGP", + "routeLeaked": False, + "kernelProgrammed": True, + "routeAction": "forward", + "directlyConnected": False, + "preference": 20, + "metric": 0, + "vias": [{"nexthopAddr": "10.1.255.4", "interface": "Ethernet1"}], + } + }, + } + } + }, + { + "vrfs": { + "default": { + "routingDisabled": False, + "allRoutesProgrammedHardware": True, + "allRoutesProgrammedKernel": True, + "defaultRouteState": "notSet", + "routes": { + "10.1.0.55/32": { + "hardwareProgrammed": True, + "routeType": "eBGP", + "routeLeaked": False, + "kernelProgrammed": True, + "routeAction": "forward", + "directlyConnected": False, + "preference": 20, + "metric": 0, + "vias": [{"nexthopAddr": "10.1.255.6", "interface": "Ethernet2"}], + } + }, + } + } + }, + ], + "inputs": {"vrf": "default", "routes": ["10.1.0.1", "10.1.0.2"]}, + "expected": {"result": "failure", "messages": ["The following route(s) are missing from the routing table of VRF default: ['10.1.0.2']"]}, + }, +] diff --git a/tests/units/anta_tests/routing/test_ospf.py b/tests/units/anta_tests/routing/test_ospf.py new file mode 100644 index 0000000..fbabee9 --- /dev/null +++ b/tests/units/anta_tests/routing/test_ospf.py @@ -0,0 +1,298 @@ +# 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. +""" +Tests for anta.tests.routing.ospf.py +""" +from __future__ import annotations + +from typing import Any + +from anta.tests.routing.ospf import VerifyOSPFNeighborCount, VerifyOSPFNeighborState +from tests.lib.anta import test # noqa: F401; pylint: disable=W0611 + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifyOSPFNeighborState, + "eos_data": [ + { + "vrfs": { + "default": { + "instList": { + "666": { + "ospfNeighborEntries": [ + { + "routerId": "7.7.7.7", + "priority": 1, + "drState": "DR", + "interfaceName": "Ethernet1", + "adjacencyState": "full", + "inactivity": 1683298014.844345, + "interfaceAddress": "10.3.0.1", + }, + { + "routerId": "9.9.9.9", + "priority": 1, + "drState": "DR", + "interfaceName": "Ethernet1", + "adjacencyState": "full", + "inactivity": 1683298014.844345, + "interfaceAddress": "10.3.0.1", + }, + ] + } + } + }, + "BLAH": { + "instList": { + "777": { + "ospfNeighborEntries": [ + { + "routerId": "8.8.8.8", + "priority": 1, + "drState": "DR", + "interfaceName": "Ethernet1", + "adjacencyState": "full", + "inactivity": 1683298014.844345, + "interfaceAddress": "10.3.0.1", + } + ] + } + } + }, + } + } + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyOSPFNeighborState, + "eos_data": [ + { + "vrfs": { + "default": { + "instList": { + "666": { + "ospfNeighborEntries": [ + { + "routerId": "7.7.7.7", + "priority": 1, + "drState": "DR", + "interfaceName": "Ethernet1", + "adjacencyState": "2-way", + "inactivity": 1683298014.844345, + "interfaceAddress": "10.3.0.1", + }, + { + "routerId": "9.9.9.9", + "priority": 1, + "drState": "DR", + "interfaceName": "Ethernet1", + "adjacencyState": "full", + "inactivity": 1683298014.844345, + "interfaceAddress": "10.3.0.1", + }, + ] + } + } + }, + "BLAH": { + "instList": { + "777": { + "ospfNeighborEntries": [ + { + "routerId": "8.8.8.8", + "priority": 1, + "drState": "DR", + "interfaceName": "Ethernet1", + "adjacencyState": "down", + "inactivity": 1683298014.844345, + "interfaceAddress": "10.3.0.1", + } + ] + } + } + }, + } + } + ], + "inputs": None, + "expected": { + "result": "failure", + "messages": [ + "Some neighbors are not correctly configured: [{'vrf': 'default', 'instance': '666', 'neighbor': '7.7.7.7', 'state': '2-way'}," + " {'vrf': 'BLAH', 'instance': '777', 'neighbor': '8.8.8.8', 'state': 'down'}]." + ], + }, + }, + { + "name": "skipped", + "test": VerifyOSPFNeighborState, + "eos_data": [ + { + "vrfs": {}, + } + ], + "inputs": None, + "expected": {"result": "skipped", "messages": ["no OSPF neighbor found"]}, + }, + { + "name": "success", + "test": VerifyOSPFNeighborCount, + "eos_data": [ + { + "vrfs": { + "default": { + "instList": { + "666": { + "ospfNeighborEntries": [ + { + "routerId": "7.7.7.7", + "priority": 1, + "drState": "DR", + "interfaceName": "Ethernet1", + "adjacencyState": "full", + "inactivity": 1683298014.844345, + "interfaceAddress": "10.3.0.1", + }, + { + "routerId": "9.9.9.9", + "priority": 1, + "drState": "DR", + "interfaceName": "Ethernet1", + "adjacencyState": "full", + "inactivity": 1683298014.844345, + "interfaceAddress": "10.3.0.1", + }, + ] + } + } + }, + "BLAH": { + "instList": { + "777": { + "ospfNeighborEntries": [ + { + "routerId": "8.8.8.8", + "priority": 1, + "drState": "DR", + "interfaceName": "Ethernet1", + "adjacencyState": "full", + "inactivity": 1683298014.844345, + "interfaceAddress": "10.3.0.1", + } + ] + } + } + }, + } + } + ], + "inputs": {"number": 3}, + "expected": {"result": "success"}, + }, + { + "name": "failure-wrong-number", + "test": VerifyOSPFNeighborCount, + "eos_data": [ + { + "vrfs": { + "default": { + "instList": { + "666": { + "ospfNeighborEntries": [ + { + "routerId": "7.7.7.7", + "priority": 1, + "drState": "DR", + "interfaceName": "Ethernet1", + "adjacencyState": "full", + "inactivity": 1683298014.844345, + "interfaceAddress": "10.3.0.1", + }, + ] + } + } + } + } + } + ], + "inputs": {"number": 3}, + "expected": {"result": "failure", "messages": ["device has 1 neighbors (expected 3)"]}, + }, + { + "name": "failure-good-number-wrong-state", + "test": VerifyOSPFNeighborCount, + "eos_data": [ + { + "vrfs": { + "default": { + "instList": { + "666": { + "ospfNeighborEntries": [ + { + "routerId": "7.7.7.7", + "priority": 1, + "drState": "DR", + "interfaceName": "Ethernet1", + "adjacencyState": "2-way", + "inactivity": 1683298014.844345, + "interfaceAddress": "10.3.0.1", + }, + { + "routerId": "9.9.9.9", + "priority": 1, + "drState": "DR", + "interfaceName": "Ethernet1", + "adjacencyState": "full", + "inactivity": 1683298014.844345, + "interfaceAddress": "10.3.0.1", + }, + ] + } + } + }, + "BLAH": { + "instList": { + "777": { + "ospfNeighborEntries": [ + { + "routerId": "8.8.8.8", + "priority": 1, + "drState": "DR", + "interfaceName": "Ethernet1", + "adjacencyState": "down", + "inactivity": 1683298014.844345, + "interfaceAddress": "10.3.0.1", + } + ] + } + } + }, + } + } + ], + "inputs": {"number": 3}, + "expected": { + "result": "failure", + "messages": [ + "Some neighbors are not correctly configured: [{'vrf': 'default', 'instance': '666', 'neighbor': '7.7.7.7', 'state': '2-way'}," + " {'vrf': 'BLAH', 'instance': '777', 'neighbor': '8.8.8.8', 'state': 'down'}]." + ], + }, + }, + { + "name": "skipped", + "test": VerifyOSPFNeighborCount, + "eos_data": [ + { + "vrfs": {}, + } + ], + "inputs": {"number": 3}, + "expected": {"result": "skipped", "messages": ["no OSPF neighbor found"]}, + }, +] diff --git a/tests/units/anta_tests/test_aaa.py b/tests/units/anta_tests/test_aaa.py new file mode 100644 index 0000000..2992290 --- /dev/null +++ b/tests/units/anta_tests/test_aaa.py @@ -0,0 +1,516 @@ +# 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. +""" +Tests for anta.tests.aaa.py +""" +from __future__ import annotations + +from typing import Any + +from anta.tests.aaa import ( + VerifyAcctConsoleMethods, + VerifyAcctDefaultMethods, + VerifyAuthenMethods, + VerifyAuthzMethods, + VerifyTacacsServerGroups, + VerifyTacacsServers, + VerifyTacacsSourceIntf, +) +from tests.lib.anta import test # noqa: F401; pylint: disable=unused-import + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifyTacacsSourceIntf, + "eos_data": [ + { + "tacacsServers": [ + { + "serverInfo": {"hostname": "10.22.10.91", "authport": 49, "vrf": "MGMT"}, + } + ], + "groups": {"GROUP1": {"serverGroup": "TACACS+", "members": [{"hostname": "SERVER1", "authport": 49, "vrf": "MGMT"}]}}, + "srcIntf": {"MGMT": "Management0"}, + } + ], + "inputs": {"intf": "Management0", "vrf": "MGMT"}, + "expected": {"result": "success"}, + }, + { + "name": "failure-not-configured", + "test": VerifyTacacsSourceIntf, + "eos_data": [ + { + "tacacsServers": [], + "groups": {}, + "srcIntf": {}, + } + ], + "inputs": {"intf": "Management0", "vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["Source-interface Management0 is not configured in VRF MGMT"]}, + }, + { + "name": "failure-wrong-intf", + "test": VerifyTacacsSourceIntf, + "eos_data": [ + { + "tacacsServers": [ + { + "serverInfo": {"hostname": "10.22.10.91", "authport": 49, "vrf": "MGMT"}, + } + ], + "groups": {"GROUP1": {"serverGroup": "TACACS+", "members": [{"hostname": "SERVER1", "authport": 49, "vrf": "MGMT"}]}}, + "srcIntf": {"MGMT": "Management1"}, + } + ], + "inputs": {"intf": "Management0", "vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["Wrong source-interface configured in VRF MGMT"]}, + }, + { + "name": "failure-wrong-vrf", + "test": VerifyTacacsSourceIntf, + "eos_data": [ + { + "tacacsServers": [ + { + "serverInfo": {"hostname": "10.22.10.91", "authport": 49, "vrf": "MGMT"}, + } + ], + "groups": {"GROUP1": {"serverGroup": "TACACS+", "members": [{"hostname": "SERVER1", "authport": 49, "vrf": "MGMT"}]}}, + "srcIntf": {"PROD": "Management0"}, + } + ], + "inputs": {"intf": "Management0", "vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["Source-interface Management0 is not configured in VRF MGMT"]}, + }, + { + "name": "success", + "test": VerifyTacacsServers, + "eos_data": [ + { + "tacacsServers": [ + { + "serverInfo": {"hostname": "10.22.10.91", "authport": 49, "vrf": "MGMT"}, + } + ], + "groups": {"GROUP1": {"serverGroup": "TACACS+", "members": [{"hostname": "SERVER1", "authport": 49, "vrf": "MGMT"}]}}, + "srcIntf": {"MGMT": "Management0"}, + } + ], + "inputs": {"servers": ["10.22.10.91"], "vrf": "MGMT"}, + "expected": {"result": "success"}, + }, + { + "name": "failure-no-servers", + "test": VerifyTacacsServers, + "eos_data": [ + { + "tacacsServers": [], + "groups": {}, + "srcIntf": {}, + } + ], + "inputs": {"servers": ["10.22.10.91"], "vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["No TACACS servers are configured"]}, + }, + { + "name": "failure-not-configured", + "test": VerifyTacacsServers, + "eos_data": [ + { + "tacacsServers": [ + { + "serverInfo": {"hostname": "10.22.10.91", "authport": 49, "vrf": "MGMT"}, + } + ], + "groups": {"GROUP1": {"serverGroup": "TACACS+", "members": [{"hostname": "SERVER1", "authport": 49, "vrf": "MGMT"}]}}, + "srcIntf": {"MGMT": "Management0"}, + } + ], + "inputs": {"servers": ["10.22.10.91", "10.22.10.92"], "vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["TACACS servers ['10.22.10.92'] are not configured in VRF MGMT"]}, + }, + { + "name": "failure-wrong-vrf", + "test": VerifyTacacsServers, + "eos_data": [ + { + "tacacsServers": [ + { + "serverInfo": {"hostname": "10.22.10.91", "authport": 49, "vrf": "PROD"}, + } + ], + "groups": {"GROUP1": {"serverGroup": "TACACS+", "members": [{"hostname": "SERVER1", "authport": 49, "vrf": "MGMT"}]}}, + "srcIntf": {"MGMT": "Management0"}, + } + ], + "inputs": {"servers": ["10.22.10.91"], "vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["TACACS servers ['10.22.10.91'] are not configured in VRF MGMT"]}, + }, + { + "name": "success", + "test": VerifyTacacsServerGroups, + "eos_data": [ + { + "tacacsServers": [ + { + "serverInfo": {"hostname": "10.22.10.91", "authport": 49, "vrf": "MGMT"}, + } + ], + "groups": {"GROUP1": {"serverGroup": "TACACS+", "members": [{"hostname": "SERVER1", "authport": 49, "vrf": "MGMT"}]}}, + "srcIntf": {"MGMT": "Management0"}, + } + ], + "inputs": {"groups": ["GROUP1"]}, + "expected": {"result": "success"}, + }, + { + "name": "failure-no-server-groups", + "test": VerifyTacacsServerGroups, + "eos_data": [ + { + "tacacsServers": [], + "groups": {}, + "srcIntf": {}, + } + ], + "inputs": {"groups": ["GROUP1"]}, + "expected": {"result": "failure", "messages": ["No TACACS server group(s) are configured"]}, + }, + { + "name": "failure-not-configured", + "test": VerifyTacacsServerGroups, + "eos_data": [ + { + "tacacsServers": [ + { + "serverInfo": {"hostname": "10.22.10.91", "authport": 49, "vrf": "MGMT"}, + } + ], + "groups": {"GROUP2": {"serverGroup": "TACACS+", "members": [{"hostname": "SERVER1", "authport": 49, "vrf": "MGMT"}]}}, + "srcIntf": {"MGMT": "Management0"}, + } + ], + "inputs": {"groups": ["GROUP1"]}, + "expected": {"result": "failure", "messages": ["TACACS server group(s) ['GROUP1'] are not configured"]}, + }, + { + "name": "success-login-enable", + "test": VerifyAuthenMethods, + "eos_data": [ + { + "loginAuthenMethods": {"default": {"methods": ["group tacacs+", "local"]}, "login": {"methods": ["group tacacs+", "local"]}}, + "enableAuthenMethods": {"default": {"methods": ["group tacacs+", "local"]}}, + "dot1xAuthenMethods": {"default": {"methods": ["group radius"]}}, + } + ], + "inputs": {"methods": ["tacacs+", "local"], "types": ["login", "enable"]}, + "expected": {"result": "success"}, + }, + { + "name": "success-dot1x", + "test": VerifyAuthenMethods, + "eos_data": [ + { + "loginAuthenMethods": {"default": {"methods": ["group tacacs+", "local"]}, "login": {"methods": ["group tacacs+", "local"]}}, + "enableAuthenMethods": {"default": {"methods": ["group tacacs+", "local"]}}, + "dot1xAuthenMethods": {"default": {"methods": ["group radius"]}}, + } + ], + "inputs": {"methods": ["radius"], "types": ["dot1x"]}, + "expected": {"result": "success"}, + }, + { + "name": "failure-no-login-console", + "test": VerifyAuthenMethods, + "eos_data": [ + { + "loginAuthenMethods": {"default": {"methods": ["group tacacs+", "local"]}}, + "enableAuthenMethods": {"default": {"methods": ["group tacacs+", "local"]}}, + "dot1xAuthenMethods": {"default": {"methods": ["group radius"]}}, + } + ], + "inputs": {"methods": ["tacacs+", "local"], "types": ["login", "enable"]}, + "expected": {"result": "failure", "messages": ["AAA authentication methods are not configured for login console"]}, + }, + { + "name": "failure-login-console", + "test": VerifyAuthenMethods, + "eos_data": [ + { + "loginAuthenMethods": {"default": {"methods": ["group tacacs+", "local"]}, "login": {"methods": ["group radius", "local"]}}, + "enableAuthenMethods": {"default": {"methods": ["group tacacs+", "local"]}}, + "dot1xAuthenMethods": {"default": {"methods": ["group radius"]}}, + } + ], + "inputs": {"methods": ["tacacs+", "local"], "types": ["login", "enable"]}, + "expected": {"result": "failure", "messages": ["AAA authentication methods ['group tacacs+', 'local'] are not matching for login console"]}, + }, + { + "name": "failure-login-default", + "test": VerifyAuthenMethods, + "eos_data": [ + { + "loginAuthenMethods": {"default": {"methods": ["group radius", "local"]}, "login": {"methods": ["group tacacs+", "local"]}}, + "enableAuthenMethods": {"default": {"methods": ["group tacacs+", "local"]}}, + "dot1xAuthenMethods": {"default": {"methods": ["group radius"]}}, + } + ], + "inputs": {"methods": ["tacacs+", "local"], "types": ["login", "enable"]}, + "expected": {"result": "failure", "messages": ["AAA authentication methods ['group tacacs+', 'local'] are not matching for ['login']"]}, + }, + { + "name": "success", + "test": VerifyAuthzMethods, + "eos_data": [ + { + "commandsAuthzMethods": {"privilege0-15": {"methods": ["group tacacs+", "local"]}}, + "execAuthzMethods": {"exec": {"methods": ["group tacacs+", "local"]}}, + } + ], + "inputs": {"methods": ["tacacs+", "local"], "types": ["commands", "exec"]}, + "expected": {"result": "success"}, + }, + { + "name": "failure-commands", + "test": VerifyAuthzMethods, + "eos_data": [ + { + "commandsAuthzMethods": {"privilege0-15": {"methods": ["group radius", "local"]}}, + "execAuthzMethods": {"exec": {"methods": ["group tacacs+", "local"]}}, + } + ], + "inputs": {"methods": ["tacacs+", "local"], "types": ["commands", "exec"]}, + "expected": {"result": "failure", "messages": ["AAA authorization methods ['group tacacs+', 'local'] are not matching for ['commands']"]}, + }, + { + "name": "failure-exec", + "test": VerifyAuthzMethods, + "eos_data": [ + { + "commandsAuthzMethods": {"privilege0-15": {"methods": ["group tacacs+", "local"]}}, + "execAuthzMethods": {"exec": {"methods": ["group radius", "local"]}}, + } + ], + "inputs": {"methods": ["tacacs+", "local"], "types": ["commands", "exec"]}, + "expected": {"result": "failure", "messages": ["AAA authorization methods ['group tacacs+', 'local'] are not matching for ['exec']"]}, + }, + { + "name": "success-commands-exec-system", + "test": VerifyAcctDefaultMethods, + "eos_data": [ + { + "commandsAcctMethods": {"privilege0-15": {"defaultAction": "startStop", "defaultMethods": ["group tacacs+", "logging"], "consoleMethods": []}}, + "execAcctMethods": {"exec": {"defaultAction": "startStop", "defaultMethods": ["group tacacs+", "logging"], "consoleMethods": []}}, + "systemAcctMethods": {"system": {"defaultAction": "startStop", "defaultMethods": ["group tacacs+", "logging"], "consoleMethods": []}}, + "dot1xAcctMethods": {"dot1x": {"defaultMethods": [], "consoleMethods": []}}, + } + ], + "inputs": {"methods": ["tacacs+", "logging"], "types": ["commands", "exec", "system"]}, + "expected": {"result": "success"}, + }, + { + "name": "success-dot1x", + "test": VerifyAcctDefaultMethods, + "eos_data": [ + { + "commandsAcctMethods": {"privilege0-15": {"defaultAction": "startStop", "defaultMethods": ["group tacacs+", "logging"], "consoleMethods": []}}, + "execAcctMethods": {"exec": {"defaultAction": "startStop", "defaultMethods": ["group tacacs+", "logging"], "consoleMethods": []}}, + "systemAcctMethods": {"system": {"defaultAction": "startStop", "defaultMethods": ["group tacacs+", "logging"], "consoleMethods": []}}, + "dot1xAcctMethods": {"dot1x": {"defaultAction": "startStop", "defaultMethods": ["group radius", "logging"], "consoleMethods": []}}, + } + ], + "inputs": {"methods": ["radius", "logging"], "types": ["dot1x"]}, + "expected": {"result": "success"}, + }, + { + "name": "failure-not-configured", + "test": VerifyAcctDefaultMethods, + "eos_data": [ + { + "commandsAcctMethods": {"privilege0-15": {"defaultMethods": [], "consoleMethods": []}}, + "execAcctMethods": {"exec": {"defaultAction": "startStop", "defaultMethods": ["group tacacs+", "logging"], "consoleMethods": []}}, + "systemAcctMethods": {"system": {"defaultAction": "startStop", "defaultMethods": ["group tacacs+", "logging"], "consoleMethods": []}}, + "dot1xAcctMethods": {"dot1x": {"defaultMethods": [], "consoleMethods": []}}, + } + ], + "inputs": {"methods": ["tacacs+", "logging"], "types": ["commands", "exec", "system"]}, + "expected": {"result": "failure", "messages": ["AAA default accounting is not configured for ['commands']"]}, + }, + { + "name": "failure-not-configured-empty", + "test": VerifyAcctDefaultMethods, + "eos_data": [ + { + "systemAcctMethods": {"system": {"defaultMethods": [], "consoleMethods": []}}, + "execAcctMethods": {"exec": {"defaultMethods": [], "consoleMethods": []}}, + "commandsAcctMethods": {"privilege0-15": {"defaultMethods": [], "consoleMethods": []}}, + "dot1xAcctMethods": {"dot1x": {"defaultMethods": [], "consoleMethods": []}}, + } + ], + "inputs": {"methods": ["tacacs+", "logging"], "types": ["commands", "exec", "system"]}, + "expected": {"result": "failure", "messages": ["AAA default accounting is not configured for ['system', 'exec', 'commands']"]}, + }, + { + "name": "failure-not-matching", + "test": VerifyAcctDefaultMethods, + "eos_data": [ + { + "commandsAcctMethods": {"privilege0-15": {"defaultAction": "startStop", "defaultMethods": ["group radius", "logging"], "consoleMethods": []}}, + "execAcctMethods": {"exec": {"defaultAction": "startStop", "defaultMethods": ["group tacacs+", "logging"], "consoleMethods": []}}, + "systemAcctMethods": {"system": {"defaultAction": "startStop", "defaultMethods": ["group tacacs+", "logging"], "consoleMethods": []}}, + "dot1xAcctMethods": {"dot1x": {"defaultMethods": [], "consoleMethods": []}}, + } + ], + "inputs": {"methods": ["tacacs+", "logging"], "types": ["commands", "exec", "system"]}, + "expected": {"result": "failure", "messages": ["AAA accounting default methods ['group tacacs+', 'logging'] are not matching for ['commands']"]}, + }, + { + "name": "success-commands-exec-system", + "test": VerifyAcctConsoleMethods, + "eos_data": [ + { + "commandsAcctMethods": { + "privilege0-15": { + "defaultMethods": [], + "consoleAction": "startStop", + "consoleMethods": ["group tacacs+", "logging"], + } + }, + "execAcctMethods": { + "exec": { + "defaultMethods": [], + "consoleAction": "startStop", + "consoleMethods": ["group tacacs+", "logging"], + } + }, + "systemAcctMethods": { + "system": { + "defaultMethods": [], + "consoleAction": "startStop", + "consoleMethods": ["group tacacs+", "logging"], + } + }, + "dot1xAcctMethods": {"dot1x": {"defaultMethods": [], "consoleMethods": []}}, + } + ], + "inputs": {"methods": ["tacacs+", "logging"], "types": ["commands", "exec", "system"]}, + "expected": {"result": "success"}, + }, + { + "name": "success-dot1x", + "test": VerifyAcctConsoleMethods, + "eos_data": [ + { + "commandsAcctMethods": { + "privilege0-15": { + "defaultMethods": [], + "consoleAction": "startStop", + "consoleMethods": ["group tacacs+", "logging"], + } + }, + "execAcctMethods": { + "exec": { + "defaultMethods": [], + "consoleAction": "startStop", + "consoleMethods": ["group tacacs+", "logging"], + } + }, + "systemAcctMethods": { + "system": { + "defaultMethods": [], + "consoleAction": "startStop", + "consoleMethods": ["group tacacs+", "logging"], + } + }, + "dot1xAcctMethods": { + "dot1x": { + "defaultMethods": [], + "consoleAction": "startStop", + "consoleMethods": ["group tacacs+", "logging"], + } + }, + } + ], + "inputs": {"methods": ["tacacs+", "logging"], "types": ["dot1x"]}, + "expected": {"result": "success"}, + }, + { + "name": "failure-not-configured", + "test": VerifyAcctConsoleMethods, + "eos_data": [ + { + "commandsAcctMethods": { + "privilege0-15": { + "defaultMethods": [], + "consoleMethods": [], + } + }, + "execAcctMethods": { + "exec": { + "defaultMethods": [], + "consoleAction": "startStop", + "consoleMethods": ["group tacacs+", "logging"], + } + }, + "systemAcctMethods": { + "system": { + "defaultMethods": [], + "consoleAction": "startStop", + "consoleMethods": ["group tacacs+", "logging"], + } + }, + "dot1xAcctMethods": {"dot1x": {"defaultMethods": [], "consoleMethods": []}}, + } + ], + "inputs": {"methods": ["tacacs+", "logging"], "types": ["commands", "exec", "system"]}, + "expected": {"result": "failure", "messages": ["AAA console accounting is not configured for ['commands']"]}, + }, + { + "name": "failure-not-configured-empty", + "test": VerifyAcctConsoleMethods, + "eos_data": [ + { + "systemAcctMethods": {"system": {"defaultMethods": [], "consoleMethods": []}}, + "execAcctMethods": {"exec": {"defaultMethods": [], "consoleMethods": []}}, + "commandsAcctMethods": {"privilege0-15": {"defaultMethods": [], "consoleMethods": []}}, + "dot1xAcctMethods": {"dot1x": {"defaultMethods": [], "consoleMethods": []}}, + } + ], + "inputs": {"methods": ["tacacs+", "logging"], "types": ["commands", "exec", "system"]}, + "expected": {"result": "failure", "messages": ["AAA console accounting is not configured for ['system', 'exec', 'commands']"]}, + }, + { + "name": "failure-not-matching", + "test": VerifyAcctConsoleMethods, + "eos_data": [ + { + "commandsAcctMethods": { + "privilege0-15": { + "defaultMethods": [], + "consoleAction": "startStop", + "consoleMethods": ["group radius", "logging"], + } + }, + "execAcctMethods": { + "exec": { + "defaultMethods": [], + "consoleAction": "startStop", + "consoleMethods": ["group tacacs+", "logging"], + } + }, + "systemAcctMethods": { + "system": { + "defaultMethods": [], + "consoleAction": "startStop", + "consoleMethods": ["group tacacs+", "logging"], + } + }, + "dot1xAcctMethods": {"dot1x": {"defaultMethods": [], "consoleMethods": []}}, + } + ], + "inputs": {"methods": ["tacacs+", "logging"], "types": ["commands", "exec", "system"]}, + "expected": {"result": "failure", "messages": ["AAA accounting console methods ['group tacacs+', 'logging'] are not matching for ['commands']"]}, + }, +] diff --git a/tests/units/anta_tests/test_bfd.py b/tests/units/anta_tests/test_bfd.py new file mode 100644 index 0000000..67bb0b4 --- /dev/null +++ b/tests/units/anta_tests/test_bfd.py @@ -0,0 +1,523 @@ +# 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. +""" +Tests for anta.tests.bfd.py +""" +# pylint: disable=C0302 +from __future__ import annotations + +from typing import Any + +# pylint: disable=C0413 +# because of the patch above +from anta.tests.bfd import VerifyBFDPeersHealth, VerifyBFDPeersIntervals, VerifyBFDSpecificPeers # noqa: E402 +from tests.lib.anta import test # noqa: F401; pylint: disable=W0611 + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifyBFDPeersIntervals, + "eos_data": [ + { + "vrfs": { + "default": { + "ipv4Neighbors": { + "192.0.255.7": { + "peerStats": { + "": { + "peerStatsDetail": { + "operTxInterval": 1200000, + "operRxInterval": 1200000, + "detectMult": 3, + } + } + } + } + } + }, + "MGMT": { + "ipv4Neighbors": { + "192.0.255.70": { + "peerStats": { + "": { + "peerStatsDetail": { + "operTxInterval": 1200000, + "operRxInterval": 1200000, + "detectMult": 3, + } + } + } + } + } + }, + } + } + ], + "inputs": { + "bfd_peers": [ + {"peer_address": "192.0.255.7", "vrf": "default", "tx_interval": 1200, "rx_interval": 1200, "multiplier": 3}, + {"peer_address": "192.0.255.70", "vrf": "MGMT", "tx_interval": 1200, "rx_interval": 1200, "multiplier": 3}, + ] + }, + "expected": {"result": "success"}, + }, + { + "name": "failure-no-peer", + "test": VerifyBFDPeersIntervals, + "eos_data": [ + { + "vrfs": { + "default": { + "ipv4Neighbors": { + "192.0.255.7": { + "peerStats": { + "": { + "peerStatsDetail": { + "operTxInterval": 1200000, + "operRxInterval": 1200000, + "detectMult": 3, + } + } + } + } + } + }, + "MGMT": { + "ipv4Neighbors": { + "192.0.255.71": { + "peerStats": { + "": { + "peerStatsDetail": { + "operTxInterval": 1200000, + "operRxInterval": 1200000, + "detectMult": 3, + } + } + } + } + } + }, + } + } + ], + "inputs": { + "bfd_peers": [ + {"peer_address": "192.0.255.7", "vrf": "CS", "tx_interval": 1200, "rx_interval": 1200, "multiplier": 3}, + {"peer_address": "192.0.255.70", "vrf": "MGMT", "tx_interval": 1200, "rx_interval": 1200, "multiplier": 3}, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Following BFD peers are not configured or timers are not correct:\n" + "{'192.0.255.7': {'CS': 'Not Configured'}, '192.0.255.70': {'MGMT': 'Not Configured'}}" + ], + }, + }, + { + "name": "failure-incorrect-timers", + "test": VerifyBFDPeersIntervals, + "eos_data": [ + { + "vrfs": { + "default": { + "ipv4Neighbors": { + "192.0.255.7": { + "peerStats": { + "": { + "peerStatsDetail": { + "operTxInterval": 1300000, + "operRxInterval": 1200000, + "detectMult": 4, + } + } + } + } + } + }, + "MGMT": { + "ipv4Neighbors": { + "192.0.255.70": { + "peerStats": { + "": { + "peerStatsDetail": { + "operTxInterval": 120000, + "operRxInterval": 120000, + "detectMult": 5, + } + } + } + } + } + }, + } + } + ], + "inputs": { + "bfd_peers": [ + {"peer_address": "192.0.255.7", "vrf": "default", "tx_interval": 1200, "rx_interval": 1200, "multiplier": 3}, + {"peer_address": "192.0.255.70", "vrf": "MGMT", "tx_interval": 1200, "rx_interval": 1200, "multiplier": 3}, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "Following BFD peers are not configured or timers are not correct:\n" + "{'192.0.255.7': {'default': {'tx_interval': 1300000, 'rx_interval': 1200000, 'multiplier': 4}}, " + "'192.0.255.70': {'MGMT': {'tx_interval': 120000, 'rx_interval': 120000, 'multiplier': 5}}}" + ], + }, + }, + { + "name": "success", + "test": VerifyBFDSpecificPeers, + "eos_data": [ + { + "vrfs": { + "default": { + "ipv4Neighbors": { + "192.0.255.7": { + "peerStats": { + "": { + "status": "up", + "remoteDisc": 108328132, + } + } + } + } + }, + "MGMT": { + "ipv4Neighbors": { + "192.0.255.70": { + "peerStats": { + "": { + "status": "up", + "remoteDisc": 108328132, + } + } + } + } + }, + } + } + ], + "inputs": {"bfd_peers": [{"peer_address": "192.0.255.7", "vrf": "default"}, {"peer_address": "192.0.255.70", "vrf": "MGMT"}]}, + "expected": {"result": "success"}, + }, + { + "name": "failure-no-peer", + "test": VerifyBFDSpecificPeers, + "eos_data": [ + { + "vrfs": { + "default": { + "ipv4Neighbors": { + "192.0.255.7": { + "peerStats": { + "": { + "status": "up", + "remoteDisc": 108328132, + } + } + } + } + }, + "MGMT": { + "ipv4Neighbors": { + "192.0.255.71": { + "peerStats": { + "": { + "status": "up", + "remoteDisc": 108328132, + } + } + } + } + }, + } + } + ], + "inputs": {"bfd_peers": [{"peer_address": "192.0.255.7", "vrf": "CS"}, {"peer_address": "192.0.255.70", "vrf": "MGMT"}]}, + "expected": { + "result": "failure", + "messages": [ + "Following BFD peers are not configured, status is not up or remote disc is zero:\n" + "{'192.0.255.7': {'CS': 'Not Configured'}, '192.0.255.70': {'MGMT': 'Not Configured'}}" + ], + }, + }, + { + "name": "failure-session-down", + "test": VerifyBFDSpecificPeers, + "eos_data": [ + { + "vrfs": { + "default": { + "ipv4Neighbors": { + "192.0.255.7": { + "peerStats": { + "": { + "status": "Down", + "remoteDisc": 108328132, + } + } + } + } + }, + "MGMT": { + "ipv4Neighbors": { + "192.0.255.70": { + "peerStats": { + "": { + "status": "Down", + "remoteDisc": 0, + } + } + } + } + }, + } + } + ], + "inputs": {"bfd_peers": [{"peer_address": "192.0.255.7", "vrf": "default"}, {"peer_address": "192.0.255.70", "vrf": "MGMT"}]}, + "expected": { + "result": "failure", + "messages": [ + "Following BFD peers are not configured, status is not up or remote disc is zero:\n" + "{'192.0.255.7': {'default': {'status': 'Down', 'remote_disc': 108328132}}, " + "'192.0.255.70': {'MGMT': {'status': 'Down', 'remote_disc': 0}}}" + ], + }, + }, + { + "name": "success", + "test": VerifyBFDPeersHealth, + "eos_data": [ + { + "vrfs": { + "default": { + "ipv4Neighbors": { + "192.0.255.7": { + "peerStats": { + "": { + "status": "up", + "remoteDisc": 3940685114, + "lastDown": 1703657258.652725, + "l3intf": "", + } + } + }, + }, + "ipv6Neighbors": {}, + }, + "MGMT": { + "ipv4Neighbors": { + "192.0.255.71": { + "peerStats": { + "": { + "status": "up", + "remoteDisc": 3940685114, + "lastDown": 1703657258.652725, + "l3intf": "", + } + } + }, + }, + "ipv6Neighbors": {}, + }, + } + }, + { + "utcTime": 1703667348.111288, + }, + ], + "inputs": {"down_threshold": 2}, + "expected": {"result": "success"}, + }, + { + "name": "failure-no-peer", + "test": VerifyBFDPeersHealth, + "eos_data": [ + { + "vrfs": { + "MGMT": { + "ipv6Neighbors": {}, + "ipv4Neighbors": {}, + }, + "default": { + "ipv6Neighbors": {}, + "ipv4Neighbors": {}, + }, + } + }, + { + "utcTime": 1703658481.8778424, + }, + ], + "inputs": None, + "expected": { + "result": "failure", + "messages": ["No IPv4 BFD peers are configured for any VRF."], + }, + }, + { + "name": "failure-session-down", + "test": VerifyBFDPeersHealth, + "eos_data": [ + { + "vrfs": { + "default": { + "ipv4Neighbors": { + "192.0.255.7": { + "peerStats": { + "": { + "status": "down", + "remoteDisc": 0, + "lastDown": 1703657258.652725, + "l3intf": "", + } + } + }, + "192.0.255.70": { + "peerStats": { + "": { + "status": "up", + "remoteDisc": 3940685114, + "lastDown": 1703657258.652725, + "l3intf": "", + } + } + }, + }, + "ipv6Neighbors": {}, + }, + "MGMT": { + "ipv4Neighbors": { + "192.0.255.71": { + "peerStats": { + "": { + "status": "down", + "remoteDisc": 0, + "lastDown": 1703657258.652725, + "l3intf": "", + } + } + }, + }, + "ipv6Neighbors": {}, + }, + } + }, + { + "utcTime": 1703658481.8778424, + }, + ], + "inputs": {}, + "expected": { + "result": "failure", + "messages": [ + "Following BFD peers are not up:\n192.0.255.7 is down in default VRF with remote disc 0.\n192.0.255.71 is down in MGMT VRF with remote disc 0." + ], + }, + }, + { + "name": "failure-session-up-disc", + "test": VerifyBFDPeersHealth, + "eos_data": [ + { + "vrfs": { + "default": { + "ipv4Neighbors": { + "192.0.255.7": { + "peerStats": { + "": { + "status": "up", + "remoteDisc": 0, + "lastDown": 1703657258.652725, + "l3intf": "Ethernet2", + } + } + }, + "192.0.255.71": { + "peerStats": { + "": { + "status": "up", + "remoteDisc": 0, + "lastDown": 1703657258.652725, + "l3intf": "Ethernet2", + } + } + }, + }, + "ipv6Neighbors": {}, + } + } + }, + { + "utcTime": 1703658481.8778424, + }, + ], + "inputs": {}, + "expected": { + "result": "failure", + "messages": ["Following BFD peers were down:\n192.0.255.7 in default VRF has remote disc 0.\n192.0.255.71 in default VRF has remote disc 0."], + }, + }, + { + "name": "failure-last-down", + "test": VerifyBFDPeersHealth, + "eos_data": [ + { + "vrfs": { + "default": { + "ipv4Neighbors": { + "192.0.255.7": { + "peerStats": { + "": { + "status": "up", + "remoteDisc": 3940685114, + "lastDown": 1703657258.652725, + "l3intf": "", + } + } + }, + "192.0.255.71": { + "peerStats": { + "": { + "status": "up", + "remoteDisc": 3940685114, + "lastDown": 1703657258.652725, + "l3intf": "", + } + } + }, + "192.0.255.17": { + "peerStats": { + "": { + "status": "up", + "remoteDisc": 3940685114, + "lastDown": 1703657258.652725, + "l3intf": "", + } + } + }, + }, + "ipv6Neighbors": {}, + } + } + }, + { + "utcTime": 1703667348.111288, + }, + ], + "inputs": {"down_threshold": 4}, + "expected": { + "result": "failure", + "messages": [ + "Following BFD peers were down:\n192.0.255.7 in default VRF was down 3 hours ago.\n" + "192.0.255.71 in default VRF was down 3 hours ago.\n192.0.255.17 in default VRF was down 3 hours ago." + ], + }, + }, +] diff --git a/tests/units/anta_tests/test_configuration.py b/tests/units/anta_tests/test_configuration.py new file mode 100644 index 0000000..a2ab673 --- /dev/null +++ b/tests/units/anta_tests/test_configuration.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. +"""Data for testing anta.tests.configuration""" +from __future__ import annotations + +from typing import Any + +from anta.tests.configuration import VerifyRunningConfigDiffs, VerifyZeroTouch +from tests.lib.anta import test # noqa: F401; pylint: disable=W0611 + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifyZeroTouch, + "eos_data": [{"mode": "disabled"}], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyZeroTouch, + "eos_data": [{"mode": "enabled"}], + "inputs": None, + "expected": {"result": "failure", "messages": ["ZTP is NOT disabled"]}, + }, + { + "name": "success", + "test": VerifyRunningConfigDiffs, + "eos_data": [""], + "inputs": None, + "expected": {"result": "success"}, + }, + {"name": "failure", "test": VerifyRunningConfigDiffs, "eos_data": ["blah blah"], "inputs": None, "expected": {"result": "failure", "messages": ["blah blah"]}}, +] diff --git a/tests/units/anta_tests/test_connectivity.py b/tests/units/anta_tests/test_connectivity.py new file mode 100644 index 0000000..f79ce24 --- /dev/null +++ b/tests/units/anta_tests/test_connectivity.py @@ -0,0 +1,369 @@ +# 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. +""" +Tests for anta.tests.connectivity.py +""" +from __future__ import annotations + +from typing import Any + +from anta.tests.connectivity import VerifyLLDPNeighbors, VerifyReachability +from tests.lib.anta import test # noqa: F401; pylint: disable=W0611 + +DATA: list[dict[str, Any]] = [ + { + "name": "success-ip", + "test": VerifyReachability, + "inputs": {"hosts": [{"destination": "10.0.0.1", "source": "10.0.0.5"}, {"destination": "10.0.0.2", "source": "10.0.0.5"}]}, + "eos_data": [ + { + "messages": [ + """PING 10.0.0.1 (10.0.0.1) from 10.0.0.5 : 72(100) bytes of data. + 80 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.247 ms + 80 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.072 ms + + --- 10.0.0.1 ping statistics --- + 2 packets transmitted, 2 received, 0% packet loss, time 0ms + rtt min/avg/max/mdev = 0.072/0.159/0.247/0.088 ms, ipg/ewma 0.370/0.225 ms + + """ + ] + }, + { + "messages": [ + """PING 10.0.0.2 (10.0.0.2) from 10.0.0.5 : 72(100) bytes of data. + 80 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.247 ms + 80 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.072 ms + + --- 10.0.0.2 ping statistics --- + 2 packets transmitted, 2 received, 0% packet loss, time 0ms + rtt min/avg/max/mdev = 0.072/0.159/0.247/0.088 ms, ipg/ewma 0.370/0.225 ms + + """ + ] + }, + ], + "expected": {"result": "success"}, + }, + { + "name": "success-interface", + "test": VerifyReachability, + "inputs": {"hosts": [{"destination": "10.0.0.1", "source": "Management0"}, {"destination": "10.0.0.2", "source": "Management0"}]}, + "eos_data": [ + { + "messages": [ + """PING 10.0.0.1 (10.0.0.1) from 10.0.0.5 : 72(100) bytes of data. + 80 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.247 ms + 80 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.072 ms + + --- 10.0.0.1 ping statistics --- + 2 packets transmitted, 2 received, 0% packet loss, time 0ms + rtt min/avg/max/mdev = 0.072/0.159/0.247/0.088 ms, ipg/ewma 0.370/0.225 ms + + """ + ] + }, + { + "messages": [ + """PING 10.0.0.2 (10.0.0.2) from 10.0.0.5 : 72(100) bytes of data. + 80 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.247 ms + 80 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.072 ms + + --- 10.0.0.2 ping statistics --- + 2 packets transmitted, 2 received, 0% packet loss, time 0ms + rtt min/avg/max/mdev = 0.072/0.159/0.247/0.088 ms, ipg/ewma 0.370/0.225 ms + + """ + ] + }, + ], + "expected": {"result": "success"}, + }, + { + "name": "success-repeat", + "test": VerifyReachability, + "inputs": {"hosts": [{"destination": "10.0.0.1", "source": "Management0", "repeat": 1}]}, + "eos_data": [ + { + "messages": [ + """PING 10.0.0.1 (10.0.0.1) from 10.0.0.5 : 72(100) bytes of data. + 80 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.247 ms + + --- 10.0.0.1 ping statistics --- + 1 packets transmitted, 1 received, 0% packet loss, time 0ms + rtt min/avg/max/mdev = 0.072/0.159/0.247/0.088 ms, ipg/ewma 0.370/0.225 ms + + """ + ] + }, + ], + "expected": {"result": "success"}, + }, + { + "name": "failure-ip", + "test": VerifyReachability, + "inputs": {"hosts": [{"destination": "10.0.0.11", "source": "10.0.0.5"}, {"destination": "10.0.0.2", "source": "10.0.0.5"}]}, + "eos_data": [ + { + "messages": [ + """ping: sendmsg: Network is unreachable + ping: sendmsg: Network is unreachable + PING 10.0.0.11 (10.0.0.11) from 10.0.0.5 : 72(100) bytes of data. + + --- 10.0.0.11 ping statistics --- + 2 packets transmitted, 0 received, 100% packet loss, time 10ms + + + """ + ] + }, + { + "messages": [ + """PING 10.0.0.2 (10.0.0.2) from 10.0.0.5 : 72(100) bytes of data. + 80 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.247 ms + 80 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.072 ms + + --- 10.0.0.2 ping statistics --- + 2 packets transmitted, 2 received, 0% packet loss, time 0ms + rtt min/avg/max/mdev = 0.072/0.159/0.247/0.088 ms, ipg/ewma 0.370/0.225 ms + + """ + ] + }, + ], + "expected": {"result": "failure", "messages": ["Connectivity test failed for the following source-destination pairs: [('10.0.0.5', '10.0.0.11')]"]}, + }, + { + "name": "failure-interface", + "test": VerifyReachability, + "inputs": {"hosts": [{"destination": "10.0.0.11", "source": "Management0"}, {"destination": "10.0.0.2", "source": "Management0"}]}, + "eos_data": [ + { + "messages": [ + """ping: sendmsg: Network is unreachable + ping: sendmsg: Network is unreachable + PING 10.0.0.11 (10.0.0.11) from 10.0.0.5 : 72(100) bytes of data. + + --- 10.0.0.11 ping statistics --- + 2 packets transmitted, 0 received, 100% packet loss, time 10ms + + + """ + ] + }, + { + "messages": [ + """PING 10.0.0.2 (10.0.0.2) from 10.0.0.5 : 72(100) bytes of data. + 80 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.247 ms + 80 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.072 ms + + --- 10.0.0.2 ping statistics --- + 2 packets transmitted, 2 received, 0% packet loss, time 0ms + rtt min/avg/max/mdev = 0.072/0.159/0.247/0.088 ms, ipg/ewma 0.370/0.225 ms + + """ + ] + }, + ], + "expected": {"result": "failure", "messages": ["Connectivity test failed for the following source-destination pairs: [('Management0', '10.0.0.11')]"]}, + }, + { + "name": "success", + "test": VerifyLLDPNeighbors, + "inputs": { + "neighbors": [ + {"port": "Ethernet1", "neighbor_device": "DC1-SPINE1", "neighbor_port": "Ethernet1"}, + {"port": "Ethernet2", "neighbor_device": "DC1-SPINE2", "neighbor_port": "Ethernet1"}, + ] + }, + "eos_data": [ + { + "lldpNeighbors": { + "Ethernet1": { + "lldpNeighborInfo": [ + { + "chassisIdType": "macAddress", + "chassisId": "001c.73a0.fc18", + "systemName": "DC1-SPINE1", + "neighborInterfaceInfo": { + "interfaceIdType": "interfaceName", + "interfaceId": '"Ethernet1"', + "interfaceId_v2": "Ethernet1", + "interfaceDescription": "P2P_LINK_TO_DC1-LEAF1A_Ethernet1", + }, + } + ] + }, + "Ethernet2": { + "lldpNeighborInfo": [ + { + "chassisIdType": "macAddress", + "chassisId": "001c.73f7.d138", + "systemName": "DC1-SPINE2", + "neighborInterfaceInfo": { + "interfaceIdType": "interfaceName", + "interfaceId": '"Ethernet1"', + "interfaceId_v2": "Ethernet1", + "interfaceDescription": "P2P_LINK_TO_DC1-LEAF1A_Ethernet2", + }, + } + ] + }, + } + } + ], + "expected": {"result": "success"}, + }, + { + "name": "failure-port-not-configured", + "test": VerifyLLDPNeighbors, + "inputs": { + "neighbors": [ + {"port": "Ethernet1", "neighbor_device": "DC1-SPINE1", "neighbor_port": "Ethernet1"}, + {"port": "Ethernet2", "neighbor_device": "DC1-SPINE2", "neighbor_port": "Ethernet1"}, + ] + }, + "eos_data": [ + { + "lldpNeighbors": { + "Ethernet1": { + "lldpNeighborInfo": [ + { + "chassisIdType": "macAddress", + "chassisId": "001c.73a0.fc18", + "systemName": "DC1-SPINE1", + "neighborInterfaceInfo": { + "interfaceIdType": "interfaceName", + "interfaceId": '"Ethernet1"', + "interfaceId_v2": "Ethernet1", + "interfaceDescription": "P2P_LINK_TO_DC1-LEAF1A_Ethernet1", + }, + } + ] + }, + } + } + ], + "expected": {"result": "failure", "messages": ["The following port(s) have issues: {'port_not_configured': ['Ethernet2']}"]}, + }, + { + "name": "failure-no-neighbor", + "test": VerifyLLDPNeighbors, + "inputs": { + "neighbors": [ + {"port": "Ethernet1", "neighbor_device": "DC1-SPINE1", "neighbor_port": "Ethernet1"}, + {"port": "Ethernet2", "neighbor_device": "DC1-SPINE2", "neighbor_port": "Ethernet1"}, + ] + }, + "eos_data": [ + { + "lldpNeighbors": { + "Ethernet1": { + "lldpNeighborInfo": [ + { + "chassisIdType": "macAddress", + "chassisId": "001c.73a0.fc18", + "systemName": "DC1-SPINE1", + "neighborInterfaceInfo": { + "interfaceIdType": "interfaceName", + "interfaceId": '"Ethernet1"', + "interfaceId_v2": "Ethernet1", + "interfaceDescription": "P2P_LINK_TO_DC1-LEAF1A_Ethernet1", + }, + } + ] + }, + "Ethernet2": {"lldpNeighborInfo": []}, + } + } + ], + "expected": {"result": "failure", "messages": ["The following port(s) have issues: {'no_lldp_neighbor': ['Ethernet2']}"]}, + }, + { + "name": "failure-wrong-neighbor", + "test": VerifyLLDPNeighbors, + "inputs": { + "neighbors": [ + {"port": "Ethernet1", "neighbor_device": "DC1-SPINE1", "neighbor_port": "Ethernet1"}, + {"port": "Ethernet2", "neighbor_device": "DC1-SPINE2", "neighbor_port": "Ethernet1"}, + ] + }, + "eos_data": [ + { + "lldpNeighbors": { + "Ethernet1": { + "lldpNeighborInfo": [ + { + "chassisIdType": "macAddress", + "chassisId": "001c.73a0.fc18", + "systemName": "DC1-SPINE1", + "neighborInterfaceInfo": { + "interfaceIdType": "interfaceName", + "interfaceId": '"Ethernet1"', + "interfaceId_v2": "Ethernet1", + "interfaceDescription": "P2P_LINK_TO_DC1-LEAF1A_Ethernet1", + }, + } + ] + }, + "Ethernet2": { + "lldpNeighborInfo": [ + { + "chassisIdType": "macAddress", + "chassisId": "001c.73f7.d138", + "systemName": "DC1-SPINE2", + "neighborInterfaceInfo": { + "interfaceIdType": "interfaceName", + "interfaceId": '"Ethernet2"', + "interfaceId_v2": "Ethernet2", + "interfaceDescription": "P2P_LINK_TO_DC1-LEAF1A_Ethernet2", + }, + } + ] + }, + } + } + ], + "expected": {"result": "failure", "messages": ["The following port(s) have issues: {'wrong_lldp_neighbor': ['Ethernet2']}"]}, + }, + { + "name": "failure-multiple", + "test": VerifyLLDPNeighbors, + "inputs": { + "neighbors": [ + {"port": "Ethernet1", "neighbor_device": "DC1-SPINE1", "neighbor_port": "Ethernet1"}, + {"port": "Ethernet2", "neighbor_device": "DC1-SPINE2", "neighbor_port": "Ethernet1"}, + {"port": "Ethernet3", "neighbor_device": "DC1-SPINE3", "neighbor_port": "Ethernet1"}, + ] + }, + "eos_data": [ + { + "lldpNeighbors": { + "Ethernet1": { + "lldpNeighborInfo": [ + { + "chassisIdType": "macAddress", + "chassisId": "001c.73a0.fc18", + "systemName": "DC1-SPINE1", + "neighborInterfaceInfo": { + "interfaceIdType": "interfaceName", + "interfaceId": '"Ethernet2"', + "interfaceId_v2": "Ethernet2", + "interfaceDescription": "P2P_LINK_TO_DC1-LEAF1A_Ethernet1", + }, + } + ] + }, + "Ethernet2": {"lldpNeighborInfo": []}, + } + } + ], + "expected": { + "result": "failure", + "messages": [ + "The following port(s) have issues: {'wrong_lldp_neighbor': ['Ethernet1'], 'no_lldp_neighbor': ['Ethernet2'], 'port_not_configured': ['Ethernet3']}" + ], + }, + }, +] diff --git a/tests/units/anta_tests/test_field_notices.py b/tests/units/anta_tests/test_field_notices.py new file mode 100644 index 0000000..7c17f22 --- /dev/null +++ b/tests/units/anta_tests/test_field_notices.py @@ -0,0 +1,291 @@ +# 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. +"""Test inputs for anta.tests.field_notices""" +from __future__ import annotations + +from typing import Any + +from anta.tests.field_notices import VerifyFieldNotice44Resolution, VerifyFieldNotice72Resolution +from tests.lib.anta import test # noqa: F401; pylint: disable=W0611 + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifyFieldNotice44Resolution, + "eos_data": [ + { + "imageFormatVersion": "1.0", + "uptime": 1109144.35, + "modelName": "DCS-7280QRA-C36S", + "details": { + "deviations": [], + "components": [{"name": "Aboot", "version": "Aboot-veos-8.0.0-3255441"}], + }, + } + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure-4.0", + "test": VerifyFieldNotice44Resolution, + "eos_data": [ + { + "imageFormatVersion": "1.0", + "uptime": 1109144.35, + "modelName": "DCS-7280QRA-C36S", + "details": { + "deviations": [], + "components": [{"name": "Aboot", "version": "Aboot-veos-4.0.1-3255441"}], + }, + } + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["device is running incorrect version of aboot (4.0.1)"]}, + }, + { + "name": "failure-4.1", + "test": VerifyFieldNotice44Resolution, + "eos_data": [ + { + "imageFormatVersion": "1.0", + "uptime": 1109144.35, + "modelName": "DCS-7280QRA-C36S", + "details": { + "deviations": [], + "components": [{"name": "Aboot", "version": "Aboot-veos-4.1.0-3255441"}], + }, + } + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["device is running incorrect version of aboot (4.1.0)"]}, + }, + { + "name": "failure-6.0", + "test": VerifyFieldNotice44Resolution, + "eos_data": [ + { + "imageFormatVersion": "1.0", + "uptime": 1109144.35, + "modelName": "DCS-7280QRA-C36S", + "details": { + "deviations": [], + "components": [{"name": "Aboot", "version": "Aboot-veos-6.0.1-3255441"}], + }, + } + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["device is running incorrect version of aboot (6.0.1)"]}, + }, + { + "name": "failure-6.1", + "test": VerifyFieldNotice44Resolution, + "eos_data": [ + { + "imageFormatVersion": "1.0", + "uptime": 1109144.35, + "modelName": "DCS-7280QRA-C36S", + "details": { + "deviations": [], + "components": [{"name": "Aboot", "version": "Aboot-veos-6.1.1-3255441"}], + }, + } + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["device is running incorrect version of aboot (6.1.1)"]}, + }, + { + "name": "skipped-model", + "test": VerifyFieldNotice44Resolution, + "eos_data": [ + { + "imageFormatVersion": "1.0", + "uptime": 1109144.35, + "modelName": "vEOS-lab", + "details": { + "deviations": [], + "components": [{"name": "Aboot", "version": "Aboot-veos-8.0.0-3255441"}], + }, + } + ], + "inputs": None, + "expected": {"result": "skipped", "messages": ["device is not impacted by FN044"]}, + }, + { + "name": "success-JPE", + "test": VerifyFieldNotice72Resolution, + "eos_data": [ + { + "modelName": "DCS-7280SR3-48YC8", + "serialNumber": "JPE2130000", + "details": { + "deviations": [], + "components": [{"name": "FixedSystemvrm1", "version": "7"}], + }, + } + ], + "inputs": None, + "expected": {"result": "success", "messages": ["FN72 is mitigated"]}, + }, + { + "name": "success-JAS", + "test": VerifyFieldNotice72Resolution, + "eos_data": [ + { + "modelName": "DCS-7280SR3-48YC8", + "serialNumber": "JAS2040000", + "details": { + "deviations": [], + "components": [{"name": "FixedSystemvrm1", "version": "7"}], + }, + } + ], + "inputs": None, + "expected": {"result": "success", "messages": ["FN72 is mitigated"]}, + }, + { + "name": "success-K-JPE", + "test": VerifyFieldNotice72Resolution, + "eos_data": [ + { + "modelName": "DCS-7280SR3K-48YC8", + "serialNumber": "JPE2133000", + "details": { + "deviations": [], + "components": [{"name": "FixedSystemvrm1", "version": "7"}], + }, + } + ], + "inputs": None, + "expected": {"result": "success", "messages": ["FN72 is mitigated"]}, + }, + { + "name": "success-K-JAS", + "test": VerifyFieldNotice72Resolution, + "eos_data": [ + { + "modelName": "DCS-7280SR3K-48YC8", + "serialNumber": "JAS2040000", + "details": { + "deviations": [], + "components": [{"name": "FixedSystemvrm1", "version": "7"}], + }, + } + ], + "inputs": None, + "expected": {"result": "success", "messages": ["FN72 is mitigated"]}, + }, + { + "name": "skipped-Serial", + "test": VerifyFieldNotice72Resolution, + "eos_data": [ + { + "modelName": "DCS-7280SR3K-48YC8", + "serialNumber": "BAN2040000", + "details": { + "deviations": [], + "components": [{"name": "FixedSystemvrm1", "version": "7"}], + }, + } + ], + "inputs": None, + "expected": {"result": "skipped", "messages": ["Device not exposed"]}, + }, + { + "name": "skipped-Platform", + "test": VerifyFieldNotice72Resolution, + "eos_data": [ + { + "modelName": "DCS-7150-52-CL", + "serialNumber": "JAS0040000", + "details": { + "deviations": [], + "components": [{"name": "FixedSystemvrm1", "version": "5"}], + }, + } + ], + "inputs": None, + "expected": {"result": "skipped", "messages": ["Platform is not impacted by FN072"]}, + }, + { + "name": "skipped-range-JPE", + "test": VerifyFieldNotice72Resolution, + "eos_data": [ + { + "modelName": "DCS-7280SR3-48YC8", + "serialNumber": "JPE2131000", + "details": { + "deviations": [], + "components": [{"name": "FixedSystemvrm1", "version": "5"}], + }, + } + ], + "inputs": None, + "expected": {"result": "skipped", "messages": ["Device not exposed"]}, + }, + { + "name": "skipped-range-K-JAS", + "test": VerifyFieldNotice72Resolution, + "eos_data": [ + { + "modelName": "DCS-7280SR3K-48YC8", + "serialNumber": "JAS2041000", + "details": { + "deviations": [], + "components": [{"name": "FixedSystemvrm1", "version": "5"}], + }, + } + ], + "inputs": None, + "expected": {"result": "skipped", "messages": ["Device not exposed"]}, + }, + { + "name": "failed-JPE", + "test": VerifyFieldNotice72Resolution, + "eos_data": [ + { + "modelName": "DCS-7280SR3K-48YC8", + "serialNumber": "JPE2133000", + "details": { + "deviations": [], + "components": [{"name": "FixedSystemvrm1", "version": "5"}], + }, + } + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["Device is exposed to FN72"]}, + }, + { + "name": "failed-JAS", + "test": VerifyFieldNotice72Resolution, + "eos_data": [ + { + "modelName": "DCS-7280SR3-48YC8", + "serialNumber": "JAS2040000", + "details": { + "deviations": [], + "components": [{"name": "FixedSystemvrm1", "version": "5"}], + }, + } + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["Device is exposed to FN72"]}, + }, + { + "name": "error", + "test": VerifyFieldNotice72Resolution, + "eos_data": [ + { + "modelName": "DCS-7280SR3-48YC8", + "serialNumber": "JAS2040000", + "details": { + "deviations": [], + "components": [{"name": "FixedSystemvrm2", "version": "5"}], + }, + } + ], + "inputs": None, + "expected": {"result": "error", "messages": ["Error in running test - FixedSystemvrm1 not found"]}, + }, +] diff --git a/tests/units/anta_tests/test_greent.py b/tests/units/anta_tests/test_greent.py new file mode 100644 index 0000000..65789a2 --- /dev/null +++ b/tests/units/anta_tests/test_greent.py @@ -0,0 +1,47 @@ +# 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. +"""Data for testing anta.tests.configuration""" +from __future__ import annotations + +from typing import Any + +from anta.tests.greent import VerifyGreenT, VerifyGreenTCounters + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifyGreenTCounters, + "eos_data": [{"sampleRcvd": 0, "sampleDiscarded": 0, "multiDstSampleRcvd": 0, "grePktSent": 1, "sampleSent": 0}], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyGreenTCounters, + "eos_data": [{"sampleRcvd": 0, "sampleDiscarded": 0, "multiDstSampleRcvd": 0, "grePktSent": 0, "sampleSent": 0}], + "inputs": None, + "expected": {"result": "failure"}, + }, + { + "name": "success", + "test": VerifyGreenT, + "eos_data": [{"sampleRcvd": 0, "sampleDiscarded": 0, "multiDstSampleRcvd": 0, "grePktSent": 1, "sampleSent": 0}], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyGreenT, + "eos_data": [ + { + "profiles": { + "default": {"interfaces": [], "appliedInterfaces": [], "samplePolicy": "default", "failures": {}, "appliedInterfaces6": [], "failures6": {}}, + "testProfile": {"interfaces": [], "appliedInterfaces": [], "samplePolicy": "default", "failures": {}, "appliedInterfaces6": [], "failures6": {}}, + } + } + ], + "inputs": None, + "expected": {"result": "failure"}, + }, +] diff --git a/tests/units/anta_tests/test_hardware.py b/tests/units/anta_tests/test_hardware.py new file mode 100644 index 0000000..5279d89 --- /dev/null +++ b/tests/units/anta_tests/test_hardware.py @@ -0,0 +1,918 @@ +# 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. +"""Test inputs for anta.tests.hardware""" +from __future__ import annotations + +from typing import Any + +from anta.tests.hardware import ( + VerifyAdverseDrops, + VerifyEnvironmentCooling, + VerifyEnvironmentPower, + VerifyEnvironmentSystemCooling, + VerifyTemperature, + VerifyTransceiversManufacturers, + VerifyTransceiversTemperature, +) +from tests.lib.anta import test # noqa: F401; pylint: disable=W0611 + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifyTransceiversManufacturers, + "eos_data": [ + { + "xcvrSlots": { + "1": {"mfgName": "Arista Networks", "modelName": "QSFP-100G-DR", "serialNum": "XKT203501340", "hardwareRev": "21"}, + "2": {"mfgName": "Arista Networks", "modelName": "QSFP-100G-DR", "serialNum": "XKT203501337", "hardwareRev": "21"}, + } + } + ], + "inputs": {"manufacturers": ["Arista Networks"]}, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyTransceiversManufacturers, + "eos_data": [ + { + "xcvrSlots": { + "1": {"mfgName": "Arista Networks", "modelName": "QSFP-100G-DR", "serialNum": "XKT203501340", "hardwareRev": "21"}, + "2": {"mfgName": "Arista Networks", "modelName": "QSFP-100G-DR", "serialNum": "XKT203501337", "hardwareRev": "21"}, + } + } + ], + "inputs": {"manufacturers": ["Arista"]}, + "expected": {"result": "failure", "messages": ["Some transceivers are from unapproved manufacturers: {'1': 'Arista Networks', '2': 'Arista Networks'}"]}, + }, + { + "name": "success", + "test": VerifyTemperature, + "eos_data": [ + { + "powercycleOnOverheat": "False", + "ambientThreshold": 45, + "cardSlots": [], + "shutdownOnOverheat": "True", + "systemStatus": "temperatureOk", + "recoveryModeOnOverheat": "recoveryModeNA", + } + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyTemperature, + "eos_data": [ + { + "powercycleOnOverheat": "False", + "ambientThreshold": 45, + "cardSlots": [], + "shutdownOnOverheat": "True", + "systemStatus": "temperatureKO", + "recoveryModeOnOverheat": "recoveryModeNA", + } + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["Device temperature exceeds acceptable limits. Current system status: 'temperatureKO'"]}, + }, + { + "name": "success", + "test": VerifyTransceiversTemperature, + "eos_data": [ + { + "tempSensors": [ + { + "maxTemperature": 25.03125, + "maxTemperatureLastChange": 1682509618.2227979, + "hwStatus": "ok", + "alertCount": 0, + "description": "Xcvr54 temp sensor", + "overheatThreshold": 70.0, + "criticalThreshold": 70.0, + "inAlertState": False, + "targetTemperature": 62.0, + "relPos": "54", + "currentTemperature": 24.171875, + "setPointTemperature": 61.8, + "pidDriverCount": 0, + "isPidDriver": False, + "name": "DomTemperatureSensor54", + } + ], + "cardSlots": [], + } + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure-hwStatus", + "test": VerifyTransceiversTemperature, + "eos_data": [ + { + "tempSensors": [ + { + "maxTemperature": 25.03125, + "maxTemperatureLastChange": 1682509618.2227979, + "hwStatus": "ko", + "alertCount": 0, + "description": "Xcvr54 temp sensor", + "overheatThreshold": 70.0, + "criticalThreshold": 70.0, + "inAlertState": False, + "targetTemperature": 62.0, + "relPos": "54", + "currentTemperature": 24.171875, + "setPointTemperature": 61.8, + "pidDriverCount": 0, + "isPidDriver": False, + "name": "DomTemperatureSensor54", + } + ], + "cardSlots": [], + } + ], + "inputs": None, + "expected": { + "result": "failure", + "messages": [ + "The following sensors are operating outside the acceptable temperature range or have raised alerts: " + "{'DomTemperatureSensor54': " + "{'hwStatus': 'ko', 'alertCount': 0}}" + ], + }, + }, + { + "name": "failure-alertCount", + "test": VerifyTransceiversTemperature, + "eos_data": [ + { + "tempSensors": [ + { + "maxTemperature": 25.03125, + "maxTemperatureLastChange": 1682509618.2227979, + "hwStatus": "ok", + "alertCount": 1, + "description": "Xcvr54 temp sensor", + "overheatThreshold": 70.0, + "criticalThreshold": 70.0, + "inAlertState": False, + "targetTemperature": 62.0, + "relPos": "54", + "currentTemperature": 24.171875, + "setPointTemperature": 61.8, + "pidDriverCount": 0, + "isPidDriver": False, + "name": "DomTemperatureSensor54", + } + ], + "cardSlots": [], + } + ], + "inputs": None, + "expected": { + "result": "failure", + "messages": [ + "The following sensors are operating outside the acceptable temperature range or have raised alerts: " + "{'DomTemperatureSensor54': " + "{'hwStatus': 'ok', 'alertCount': 1}}" + ], + }, + }, + { + "name": "success", + "test": VerifyEnvironmentSystemCooling, + "eos_data": [ + { + "defaultZones": False, + "numCoolingZones": [], + "coolingMode": "automatic", + "ambientTemperature": 24.5, + "shutdownOnInsufficientFans": True, + "airflowDirection": "frontToBackAirflow", + "overrideFanSpeed": 0, + "powerSupplySlots": [], + "fanTraySlots": [], + "minFanSpeed": 0, + "currentZones": 1, + "configuredZones": 0, + "systemStatus": "coolingOk", + } + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyEnvironmentSystemCooling, + "eos_data": [ + { + "defaultZones": False, + "numCoolingZones": [], + "coolingMode": "automatic", + "ambientTemperature": 24.5, + "shutdownOnInsufficientFans": True, + "airflowDirection": "frontToBackAirflow", + "overrideFanSpeed": 0, + "powerSupplySlots": [], + "fanTraySlots": [], + "minFanSpeed": 0, + "currentZones": 1, + "configuredZones": 0, + "systemStatus": "coolingKo", + } + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["Device system cooling is not OK: 'coolingKo'"]}, + }, + { + "name": "success", + "test": VerifyEnvironmentCooling, + "eos_data": [ + { + "defaultZones": False, + "numCoolingZones": [], + "coolingMode": "automatic", + "ambientTemperature": 24.5, + "shutdownOnInsufficientFans": True, + "airflowDirection": "frontToBackAirflow", + "overrideFanSpeed": 0, + "powerSupplySlots": [ + { + "status": "ok", + "fans": [ + { + "status": "ok", + "uptime": 1682498937.0240965, + "maxSpeed": 23000, + "lastSpeedStableChangeTime": 1682499033.0403435, + "configuredSpeed": 30, + "actualSpeed": 33, + "speedHwOverride": True, + "speedStable": True, + "label": "PowerSupply1/1", + } + ], + "speed": 30, + "label": "PowerSupply1", + }, + { + "status": "ok", + "fans": [ + { + "status": "ok", + "uptime": 1682498935.9121106, + "maxSpeed": 23000, + "lastSpeedStableChangeTime": 1682499092.4665174, + "configuredSpeed": 30, + "actualSpeed": 33, + "speedHwOverride": True, + "speedStable": True, + "label": "PowerSupply2/1", + } + ], + "speed": 30, + "label": "PowerSupply2", + }, + ], + "fanTraySlots": [ + { + "status": "ok", + "fans": [ + { + "status": "ok", + "uptime": 1682498923.9303148, + "maxSpeed": 17500, + "lastSpeedStableChangeTime": 1682498975.0139885, + "configuredSpeed": 30, + "actualSpeed": 29, + "speedHwOverride": False, + "speedStable": True, + "label": "1/1", + } + ], + "speed": 30, + "label": "1", + }, + { + "status": "ok", + "fans": [ + { + "status": "ok", + "uptime": 1682498923.9304729, + "maxSpeed": 17500, + "lastSpeedStableChangeTime": 1682498939.9329433, + "configuredSpeed": 30, + "actualSpeed": 30, + "speedHwOverride": False, + "speedStable": True, + "label": "2/1", + } + ], + "speed": 30, + "label": "2", + }, + { + "status": "ok", + "fans": [ + { + "status": "ok", + "uptime": 1682498923.9383528, + "maxSpeed": 17500, + "lastSpeedStableChangeTime": 1682498975.0140095, + "configuredSpeed": 30, + "actualSpeed": 30, + "speedHwOverride": False, + "speedStable": True, + "label": "3/1", + } + ], + "speed": 30, + "label": "3", + }, + { + "status": "ok", + "fans": [ + { + "status": "ok", + "uptime": 1682498923.9303904, + "maxSpeed": 17500, + "lastSpeedStableChangeTime": 1682498975.0140295, + "configuredSpeed": 30, + "actualSpeed": 30, + "speedHwOverride": False, + "speedStable": True, + "label": "4/1", + } + ], + "speed": 30, + "label": "4", + }, + ], + "minFanSpeed": 0, + "currentZones": 1, + "configuredZones": 0, + "systemStatus": "coolingOk", + } + ], + "inputs": {"states": ["ok"]}, + "expected": {"result": "success"}, + }, + { + "name": "success-additional-states", + "test": VerifyEnvironmentCooling, + "eos_data": [ + { + "defaultZones": False, + "numCoolingZones": [], + "coolingMode": "automatic", + "ambientTemperature": 24.5, + "shutdownOnInsufficientFans": True, + "airflowDirection": "frontToBackAirflow", + "overrideFanSpeed": 0, + "powerSupplySlots": [ + { + "status": "ok", + "fans": [ + { + "status": "ok", + "uptime": 1682498937.0240965, + "maxSpeed": 23000, + "lastSpeedStableChangeTime": 1682499033.0403435, + "configuredSpeed": 30, + "actualSpeed": 33, + "speedHwOverride": True, + "speedStable": True, + "label": "PowerSupply1/1", + } + ], + "speed": 30, + "label": "PowerSupply1", + }, + { + "status": "ok", + "fans": [ + { + "status": "Not Inserted", + "uptime": 1682498935.9121106, + "maxSpeed": 23000, + "lastSpeedStableChangeTime": 1682499092.4665174, + "configuredSpeed": 30, + "actualSpeed": 33, + "speedHwOverride": True, + "speedStable": True, + "label": "PowerSupply2/1", + } + ], + "speed": 30, + "label": "PowerSupply2", + }, + ], + "fanTraySlots": [ + { + "status": "ok", + "fans": [ + { + "status": "ok", + "uptime": 1682498923.9303148, + "maxSpeed": 17500, + "lastSpeedStableChangeTime": 1682498975.0139885, + "configuredSpeed": 30, + "actualSpeed": 29, + "speedHwOverride": False, + "speedStable": True, + "label": "1/1", + } + ], + "speed": 30, + "label": "1", + }, + { + "status": "ok", + "fans": [ + { + "status": "ok", + "uptime": 1682498923.9304729, + "maxSpeed": 17500, + "lastSpeedStableChangeTime": 1682498939.9329433, + "configuredSpeed": 30, + "actualSpeed": 30, + "speedHwOverride": False, + "speedStable": True, + "label": "2/1", + } + ], + "speed": 30, + "label": "2", + }, + { + "status": "ok", + "fans": [ + { + "status": "ok", + "uptime": 1682498923.9383528, + "maxSpeed": 17500, + "lastSpeedStableChangeTime": 1682498975.0140095, + "configuredSpeed": 30, + "actualSpeed": 30, + "speedHwOverride": False, + "speedStable": True, + "label": "3/1", + } + ], + "speed": 30, + "label": "3", + }, + { + "status": "ok", + "fans": [ + { + "status": "ok", + "uptime": 1682498923.9303904, + "maxSpeed": 17500, + "lastSpeedStableChangeTime": 1682498975.0140295, + "configuredSpeed": 30, + "actualSpeed": 30, + "speedHwOverride": False, + "speedStable": True, + "label": "4/1", + } + ], + "speed": 30, + "label": "4", + }, + ], + "minFanSpeed": 0, + "currentZones": 1, + "configuredZones": 0, + "systemStatus": "coolingOk", + } + ], + "inputs": {"states": ["ok", "Not Inserted"]}, + "expected": {"result": "success"}, + }, + { + "name": "failure-fan-tray", + "test": VerifyEnvironmentCooling, + "eos_data": [ + { + "defaultZones": False, + "numCoolingZones": [], + "coolingMode": "automatic", + "ambientTemperature": 24.5, + "shutdownOnInsufficientFans": True, + "airflowDirection": "frontToBackAirflow", + "overrideFanSpeed": 0, + "powerSupplySlots": [ + { + "status": "ok", + "fans": [ + { + "status": "ok", + "uptime": 1682498937.0240965, + "maxSpeed": 23000, + "lastSpeedStableChangeTime": 1682499033.0403435, + "configuredSpeed": 30, + "actualSpeed": 33, + "speedHwOverride": True, + "speedStable": True, + "label": "PowerSupply1/1", + } + ], + "speed": 30, + "label": "PowerSupply1", + }, + { + "status": "ok", + "fans": [ + { + "status": "ok", + "uptime": 1682498935.9121106, + "maxSpeed": 23000, + "lastSpeedStableChangeTime": 1682499092.4665174, + "configuredSpeed": 30, + "actualSpeed": 33, + "speedHwOverride": True, + "speedStable": True, + "label": "PowerSupply2/1", + } + ], + "speed": 30, + "label": "PowerSupply2", + }, + ], + "fanTraySlots": [ + { + "status": "ok", + "fans": [ + { + "status": "down", + "uptime": 1682498923.9303148, + "maxSpeed": 17500, + "lastSpeedStableChangeTime": 1682498975.0139885, + "configuredSpeed": 30, + "actualSpeed": 29, + "speedHwOverride": False, + "speedStable": True, + "label": "1/1", + } + ], + "speed": 30, + "label": "1", + }, + { + "status": "ok", + "fans": [ + { + "status": "ok", + "uptime": 1682498923.9304729, + "maxSpeed": 17500, + "lastSpeedStableChangeTime": 1682498939.9329433, + "configuredSpeed": 30, + "actualSpeed": 30, + "speedHwOverride": False, + "speedStable": True, + "label": "2/1", + } + ], + "speed": 30, + "label": "2", + }, + { + "status": "ok", + "fans": [ + { + "status": "Not Inserted", + "uptime": 1682498923.9383528, + "maxSpeed": 17500, + "lastSpeedStableChangeTime": 1682498975.0140095, + "configuredSpeed": 30, + "actualSpeed": 30, + "speedHwOverride": False, + "speedStable": True, + "label": "3/1", + } + ], + "speed": 30, + "label": "3", + }, + { + "status": "ok", + "fans": [ + { + "status": "ok", + "uptime": 1682498923.9303904, + "maxSpeed": 17500, + "lastSpeedStableChangeTime": 1682498975.0140295, + "configuredSpeed": 30, + "actualSpeed": 30, + "speedHwOverride": False, + "speedStable": True, + "label": "4/1", + } + ], + "speed": 30, + "label": "4", + }, + ], + "minFanSpeed": 0, + "currentZones": 1, + "configuredZones": 0, + "systemStatus": "CoolingKo", + } + ], + "inputs": {"states": ["ok", "Not Inserted"]}, + "expected": {"result": "failure", "messages": ["Fan 1/1 on Fan Tray 1 is: 'down'"]}, + }, + { + "name": "failure-power-supply", + "test": VerifyEnvironmentCooling, + "eos_data": [ + { + "defaultZones": False, + "numCoolingZones": [], + "coolingMode": "automatic", + "ambientTemperature": 24.5, + "shutdownOnInsufficientFans": True, + "airflowDirection": "frontToBackAirflow", + "overrideFanSpeed": 0, + "powerSupplySlots": [ + { + "status": "ok", + "fans": [ + { + "status": "down", + "uptime": 1682498937.0240965, + "maxSpeed": 23000, + "lastSpeedStableChangeTime": 1682499033.0403435, + "configuredSpeed": 30, + "actualSpeed": 33, + "speedHwOverride": True, + "speedStable": True, + "label": "PowerSupply1/1", + } + ], + "speed": 30, + "label": "PowerSupply1", + }, + { + "status": "ok", + "fans": [ + { + "status": "ok", + "uptime": 1682498935.9121106, + "maxSpeed": 23000, + "lastSpeedStableChangeTime": 1682499092.4665174, + "configuredSpeed": 30, + "actualSpeed": 33, + "speedHwOverride": True, + "speedStable": True, + "label": "PowerSupply2/1", + } + ], + "speed": 30, + "label": "PowerSupply2", + }, + ], + "fanTraySlots": [ + { + "status": "ok", + "fans": [ + { + "status": "ok", + "uptime": 1682498923.9303148, + "maxSpeed": 17500, + "lastSpeedStableChangeTime": 1682498975.0139885, + "configuredSpeed": 30, + "actualSpeed": 29, + "speedHwOverride": False, + "speedStable": True, + "label": "1/1", + } + ], + "speed": 30, + "label": "1", + }, + { + "status": "ok", + "fans": [ + { + "status": "ok", + "uptime": 1682498923.9304729, + "maxSpeed": 17500, + "lastSpeedStableChangeTime": 1682498939.9329433, + "configuredSpeed": 30, + "actualSpeed": 30, + "speedHwOverride": False, + "speedStable": True, + "label": "2/1", + } + ], + "speed": 30, + "label": "2", + }, + { + "status": "ok", + "fans": [ + { + "status": "Not Inserted", + "uptime": 1682498923.9383528, + "maxSpeed": 17500, + "lastSpeedStableChangeTime": 1682498975.0140095, + "configuredSpeed": 30, + "actualSpeed": 30, + "speedHwOverride": False, + "speedStable": True, + "label": "3/1", + } + ], + "speed": 30, + "label": "3", + }, + { + "status": "ok", + "fans": [ + { + "status": "ok", + "uptime": 1682498923.9303904, + "maxSpeed": 17500, + "lastSpeedStableChangeTime": 1682498975.0140295, + "configuredSpeed": 30, + "actualSpeed": 30, + "speedHwOverride": False, + "speedStable": True, + "label": "4/1", + } + ], + "speed": 30, + "label": "4", + }, + ], + "minFanSpeed": 0, + "currentZones": 1, + "configuredZones": 0, + "systemStatus": "CoolingKo", + } + ], + "inputs": {"states": ["ok", "Not Inserted"]}, + "expected": {"result": "failure", "messages": ["Fan PowerSupply1/1 on PowerSupply PowerSupply1 is: 'down'"]}, + }, + { + "name": "success", + "test": VerifyEnvironmentPower, + "eos_data": [ + { + "powerSupplies": { + "1": { + "outputPower": 0.0, + "modelName": "PWR-500AC-F", + "capacity": 500.0, + "tempSensors": { + "TempSensorP1/2": {"status": "ok", "temperature": 0.0}, + "TempSensorP1/3": {"status": "ok", "temperature": 0.0}, + "TempSensorP1/1": {"status": "ok", "temperature": 0.0}, + }, + "fans": {"FanP1/1": {"status": "ok", "speed": 33}}, + "state": "ok", + "inputCurrent": 0.0, + "dominant": False, + "inputVoltage": 0.0, + "outputCurrent": 0.0, + "managed": True, + }, + "2": { + "outputPower": 117.375, + "uptime": 1682498935.9121966, + "modelName": "PWR-500AC-F", + "capacity": 500.0, + "tempSensors": { + "TempSensorP2/1": {"status": "ok", "temperature": 39.0}, + "TempSensorP2/3": {"status": "ok", "temperature": 43.0}, + "TempSensorP2/2": {"status": "ok", "temperature": 31.0}, + }, + "fans": {"FanP2/1": {"status": "ok", "speed": 33}}, + "state": "ok", + "inputCurrent": 0.572265625, + "dominant": False, + "inputVoltage": 232.5, + "outputCurrent": 9.828125, + "managed": True, + }, + } + } + ], + "inputs": {"states": ["ok"]}, + "expected": {"result": "success"}, + }, + { + "name": "success-additional-states", + "test": VerifyEnvironmentPower, + "eos_data": [ + { + "powerSupplies": { + "1": { + "outputPower": 0.0, + "modelName": "PWR-500AC-F", + "capacity": 500.0, + "tempSensors": { + "TempSensorP1/2": {"status": "ok", "temperature": 0.0}, + "TempSensorP1/3": {"status": "ok", "temperature": 0.0}, + "TempSensorP1/1": {"status": "ok", "temperature": 0.0}, + }, + "fans": {"FanP1/1": {"status": "ok", "speed": 33}}, + "state": "Not Inserted", + "inputCurrent": 0.0, + "dominant": False, + "inputVoltage": 0.0, + "outputCurrent": 0.0, + "managed": True, + }, + "2": { + "outputPower": 117.375, + "uptime": 1682498935.9121966, + "modelName": "PWR-500AC-F", + "capacity": 500.0, + "tempSensors": { + "TempSensorP2/1": {"status": "ok", "temperature": 39.0}, + "TempSensorP2/3": {"status": "ok", "temperature": 43.0}, + "TempSensorP2/2": {"status": "ok", "temperature": 31.0}, + }, + "fans": {"FanP2/1": {"status": "ok", "speed": 33}}, + "state": "ok", + "inputCurrent": 0.572265625, + "dominant": False, + "inputVoltage": 232.5, + "outputCurrent": 9.828125, + "managed": True, + }, + } + } + ], + "inputs": {"states": ["ok", "Not Inserted"]}, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyEnvironmentPower, + "eos_data": [ + { + "powerSupplies": { + "1": { + "outputPower": 0.0, + "modelName": "PWR-500AC-F", + "capacity": 500.0, + "tempSensors": { + "TempSensorP1/2": {"status": "ok", "temperature": 0.0}, + "TempSensorP1/3": {"status": "ok", "temperature": 0.0}, + "TempSensorP1/1": {"status": "ok", "temperature": 0.0}, + }, + "fans": {"FanP1/1": {"status": "ok", "speed": 33}}, + "state": "powerLoss", + "inputCurrent": 0.0, + "dominant": False, + "inputVoltage": 0.0, + "outputCurrent": 0.0, + "managed": True, + }, + "2": { + "outputPower": 117.375, + "uptime": 1682498935.9121966, + "modelName": "PWR-500AC-F", + "capacity": 500.0, + "tempSensors": { + "TempSensorP2/1": {"status": "ok", "temperature": 39.0}, + "TempSensorP2/3": {"status": "ok", "temperature": 43.0}, + "TempSensorP2/2": {"status": "ok", "temperature": 31.0}, + }, + "fans": {"FanP2/1": {"status": "ok", "speed": 33}}, + "state": "ok", + "inputCurrent": 0.572265625, + "dominant": False, + "inputVoltage": 232.5, + "outputCurrent": 9.828125, + "managed": True, + }, + } + } + ], + "inputs": {"states": ["ok"]}, + "expected": {"result": "failure", "messages": ["The following power supplies status are not in the accepted states list: {'1': {'state': 'powerLoss'}}"]}, + }, + { + "name": "success", + "test": VerifyAdverseDrops, + "eos_data": [{"totalAdverseDrops": 0}], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyAdverseDrops, + "eos_data": [{"totalAdverseDrops": 10}], + "inputs": None, + "expected": {"result": "failure", "messages": ["Device totalAdverseDrops counter is: '10'"]}, + }, +] diff --git a/tests/units/anta_tests/test_interfaces.py b/tests/units/anta_tests/test_interfaces.py new file mode 100644 index 0000000..5b0d845 --- /dev/null +++ b/tests/units/anta_tests/test_interfaces.py @@ -0,0 +1,1411 @@ +# 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. +"""Test inputs for anta.tests.hardware""" +from __future__ import annotations + +from typing import Any + +from anta.tests.interfaces import ( + VerifyIllegalLACP, + VerifyInterfaceDiscards, + VerifyInterfaceErrDisabled, + VerifyInterfaceErrors, + VerifyInterfaceIPv4, + VerifyInterfacesStatus, + VerifyInterfaceUtilization, + VerifyIPProxyARP, + VerifyIpVirtualRouterMac, + VerifyL2MTU, + VerifyL3MTU, + VerifyLoopbackCount, + VerifyPortChannels, + VerifyStormControlDrops, + VerifySVI, +) +from tests.lib.anta import test # noqa: F401; pylint: disable=W0611 + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifyInterfaceUtilization, + "eos_data": [ + """Port Name Intvl In Mbps % In Kpps Out Mbps % Out Kpps +Et1 5:00 0.0 0.0% 0 0.0 0.0% 0 +Et4 5:00 0.0 0.0% 0 0.0 0.0% 0 +""" + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyInterfaceUtilization, + "eos_data": [ + """Port Name Intvl In Mbps % In Kpps Out Mbps % Out Kpps +Et1 5:00 0.0 0.0% 0 0.0 80.0% 0 +Et4 5:00 0.0 99.9% 0 0.0 0.0% 0 +""" + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["The following interfaces have a usage > 75%: {'Et1': '80.0%', 'Et4': '99.9%'}"]}, + }, + { + "name": "success", + "test": VerifyInterfaceErrors, + "eos_data": [ + { + "interfaceErrorCounters": { + "Ethernet1": {"inErrors": 0, "frameTooLongs": 0, "outErrors": 0, "frameTooShorts": 0, "fcsErrors": 0, "alignmentErrors": 0, "symbolErrors": 0}, + "Ethernet6": {"inErrors": 0, "frameTooLongs": 0, "outErrors": 0, "frameTooShorts": 0, "fcsErrors": 0, "alignmentErrors": 0, "symbolErrors": 0}, + } + } + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure-multiple-intfs", + "test": VerifyInterfaceErrors, + "eos_data": [ + { + "interfaceErrorCounters": { + "Ethernet1": {"inErrors": 42, "frameTooLongs": 0, "outErrors": 0, "frameTooShorts": 0, "fcsErrors": 0, "alignmentErrors": 0, "symbolErrors": 0}, + "Ethernet6": {"inErrors": 0, "frameTooLongs": 0, "outErrors": 0, "frameTooShorts": 0, "fcsErrors": 0, "alignmentErrors": 666, "symbolErrors": 0}, + } + } + ], + "inputs": None, + "expected": { + "result": "failure", + "messages": [ + "The following interface(s) have non-zero error counters: [{'Ethernet1': {'inErrors': 42, 'frameTooLongs': 0, 'outErrors': 0, 'frameTooShorts': 0," + " 'fcsErrors': 0, 'alignmentErrors': 0, 'symbolErrors': 0}}, {'Ethernet6': {'inErrors': 0, 'frameTooLongs': 0, 'outErrors': 0, 'frameTooShorts':" + " 0, 'fcsErrors': 0, 'alignmentErrors': 666, 'symbolErrors': 0}}]" + ], + }, + }, + { + "name": "failure-multiple-intfs-multiple-errors", + "test": VerifyInterfaceErrors, + "eos_data": [ + { + "interfaceErrorCounters": { + "Ethernet1": {"inErrors": 42, "frameTooLongs": 0, "outErrors": 10, "frameTooShorts": 0, "fcsErrors": 0, "alignmentErrors": 0, "symbolErrors": 0}, + "Ethernet6": {"inErrors": 0, "frameTooLongs": 0, "outErrors": 0, "frameTooShorts": 0, "fcsErrors": 0, "alignmentErrors": 6, "symbolErrors": 10}, + } + } + ], + "inputs": None, + "expected": { + "result": "failure", + "messages": [ + "The following interface(s) have non-zero error counters: [{'Ethernet1': {'inErrors': 42, 'frameTooLongs': 0, 'outErrors': 10, 'frameTooShorts': 0," + " 'fcsErrors': 0, 'alignmentErrors': 0, 'symbolErrors': 0}}, {'Ethernet6': {'inErrors': 0, 'frameTooLongs': 0, 'outErrors': 0, 'frameTooShorts':" + " 0, 'fcsErrors': 0, 'alignmentErrors': 6, 'symbolErrors': 10}}]" + ], + }, + }, + { + "name": "failure-single-intf-multiple-errors", + "test": VerifyInterfaceErrors, + "eos_data": [ + { + "interfaceErrorCounters": { + "Ethernet1": {"inErrors": 42, "frameTooLongs": 0, "outErrors": 2, "frameTooShorts": 0, "fcsErrors": 0, "alignmentErrors": 0, "symbolErrors": 0}, + } + } + ], + "inputs": None, + "expected": { + "result": "failure", + "messages": [ + "The following interface(s) have non-zero error counters: [{'Ethernet1': {'inErrors': 42, 'frameTooLongs': 0, 'outErrors': 2, 'frameTooShorts': 0," + " 'fcsErrors': 0, 'alignmentErrors': 0, 'symbolErrors': 0}}]" + ], + }, + }, + { + "name": "success", + "test": VerifyInterfaceDiscards, + "eos_data": [ + { + "inDiscardsTotal": 0, + "interfaces": { + "Ethernet2": {"outDiscards": 0, "inDiscards": 0}, + "Ethernet1": {"outDiscards": 0, "inDiscards": 0}, + }, + "outDiscardsTotal": 0, + } + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyInterfaceDiscards, + "eos_data": [ + { + "inDiscardsTotal": 0, + "interfaces": { + "Ethernet2": {"outDiscards": 42, "inDiscards": 0}, + "Ethernet1": {"outDiscards": 0, "inDiscards": 42}, + }, + "outDiscardsTotal": 0, + } + ], + "inputs": None, + "expected": { + "result": "failure", + "messages": [ + "The following interfaces have non 0 discard counter(s): [{'Ethernet2': {'outDiscards': 42, 'inDiscards': 0}}," + " {'Ethernet1': {'outDiscards': 0, 'inDiscards': 42}}]" + ], + }, + }, + { + "name": "success", + "test": VerifyInterfaceErrDisabled, + "eos_data": [ + { + "interfaceStatuses": { + "Management1": { + "linkStatus": "connected", + }, + "Ethernet8": { + "linkStatus": "connected", + }, + } + } + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyInterfaceErrDisabled, + "eos_data": [ + { + "interfaceStatuses": { + "Management1": { + "linkStatus": "errdisabled", + }, + "Ethernet8": { + "linkStatus": "errdisabled", + }, + } + } + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["The following interfaces are in error disabled state: ['Management1', 'Ethernet8']"]}, + }, + { + "name": "success", + "test": VerifyInterfacesStatus, + "eos_data": [ + { + "interfaceDescriptions": { + "Ethernet8": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"}, + "Ethernet2": {"interfaceStatus": "adminDown", "description": "", "lineProtocolStatus": "down"}, + "Ethernet3": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"}, + } + } + ], + "inputs": {"interfaces": [{"name": "Ethernet2", "status": "adminDown"}, {"name": "Ethernet8", "status": "up"}, {"name": "Ethernet3", "status": "up"}]}, + "expected": {"result": "success"}, + }, + { + "name": "success-up-with-line-protocol-status", + "test": VerifyInterfacesStatus, + "eos_data": [ + { + "interfaceDescriptions": { + "Ethernet8": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "down"}, + } + } + ], + "inputs": {"interfaces": [{"name": "Ethernet8", "status": "up", "line_protocol_status": "down"}]}, + "expected": {"result": "success"}, + }, + { + "name": "success-with-line-protocol-status", + "test": VerifyInterfacesStatus, + "eos_data": [ + { + "interfaceDescriptions": { + "Ethernet8": {"interfaceStatus": "adminDown", "description": "", "lineProtocolStatus": "testing"}, + "Ethernet2": {"interfaceStatus": "adminDown", "description": "", "lineProtocolStatus": "down"}, + "Ethernet3.10": {"interfaceStatus": "down", "description": "", "lineProtocolStatus": "dormant"}, + } + } + ], + "inputs": { + "interfaces": [ + {"name": "Ethernet2", "status": "adminDown", "line_protocol_status": "down"}, + {"name": "Ethernet8", "status": "adminDown", "line_protocol_status": "testing"}, + {"name": "Ethernet3.10", "status": "down", "line_protocol_status": "dormant"}, + ] + }, + "expected": {"result": "success"}, + }, + { + "name": "success-lower", + "test": VerifyInterfacesStatus, + "eos_data": [ + { + "interfaceDescriptions": { + "Ethernet8": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"}, + "Ethernet2": {"interfaceStatus": "adminDown", "description": "", "lineProtocolStatus": "down"}, + "Ethernet3": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"}, + } + } + ], + "inputs": {"interfaces": [{"name": "ethernet2", "status": "adminDown"}, {"name": "ethernet8", "status": "up"}, {"name": "ethernet3", "status": "up"}]}, + "expected": {"result": "success"}, + }, + { + "name": "success-eth-name", + "test": VerifyInterfacesStatus, + "eos_data": [ + { + "interfaceDescriptions": { + "Ethernet8": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"}, + "Ethernet2": {"interfaceStatus": "adminDown", "description": "", "lineProtocolStatus": "down"}, + "Ethernet3": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"}, + } + } + ], + "inputs": {"interfaces": [{"name": "eth2", "status": "adminDown"}, {"name": "et8", "status": "up"}, {"name": "et3", "status": "up"}]}, + "expected": {"result": "success"}, + }, + { + "name": "success-po-name", + "test": VerifyInterfacesStatus, + "eos_data": [ + { + "interfaceDescriptions": { + "Port-Channel100": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"}, + } + } + ], + "inputs": {"interfaces": [{"name": "po100", "status": "up"}]}, + "expected": {"result": "success"}, + }, + { + "name": "success-sub-interfaces", + "test": VerifyInterfacesStatus, + "eos_data": [ + { + "interfaceDescriptions": { + "Ethernet52/1.1963": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"}, + } + } + ], + "inputs": {"interfaces": [{"name": "Ethernet52/1.1963", "status": "up"}]}, + "expected": {"result": "success"}, + }, + { + "name": "success-transceiver-down", + "test": VerifyInterfacesStatus, + "eos_data": [ + { + "interfaceDescriptions": { + "Ethernet49/1": {"interfaceStatus": "adminDown", "description": "", "lineProtocolStatus": "notPresent"}, + } + } + ], + "inputs": {"interfaces": [{"name": "Ethernet49/1", "status": "adminDown"}]}, + "expected": {"result": "success"}, + }, + { + "name": "success-po-down", + "test": VerifyInterfacesStatus, + "eos_data": [ + { + "interfaceDescriptions": { + "Port-Channel100": {"interfaceStatus": "adminDown", "description": "", "lineProtocolStatus": "lowerLayerDown"}, + } + } + ], + "inputs": {"interfaces": [{"name": "PortChannel100", "status": "adminDown"}]}, + "expected": {"result": "success"}, + }, + { + "name": "success-po-lowerlayerdown", + "test": VerifyInterfacesStatus, + "eos_data": [ + { + "interfaceDescriptions": { + "Port-Channel100": {"interfaceStatus": "adminDown", "description": "", "lineProtocolStatus": "lowerLayerDown"}, + } + } + ], + "inputs": {"interfaces": [{"name": "Port-Channel100", "status": "adminDown", "line_protocol_status": "lowerLayerDown"}]}, + "expected": {"result": "success"}, + }, + { + "name": "failure-not-configured", + "test": VerifyInterfacesStatus, + "eos_data": [ + { + "interfaceDescriptions": { + "Ethernet2": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"}, + "Ethernet3": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"}, + } + } + ], + "inputs": {"interfaces": [{"name": "Ethernet2", "status": "up"}, {"name": "Ethernet8", "status": "up"}, {"name": "Ethernet3", "status": "up"}]}, + "expected": { + "result": "failure", + "messages": ["The following interface(s) are not configured: ['Ethernet8']"], + }, + }, + { + "name": "failure-status-down", + "test": VerifyInterfacesStatus, + "eos_data": [ + { + "interfaceDescriptions": { + "Ethernet8": {"interfaceStatus": "down", "description": "", "lineProtocolStatus": "down"}, + "Ethernet2": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"}, + "Ethernet3": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"}, + } + } + ], + "inputs": {"interfaces": [{"name": "Ethernet2", "status": "up"}, {"name": "Ethernet8", "status": "up"}, {"name": "Ethernet3", "status": "up"}]}, + "expected": { + "result": "failure", + "messages": ["The following interface(s) are not in the expected state: ['Ethernet8 is down/down'"], + }, + }, + { + "name": "failure-proto-down", + "test": VerifyInterfacesStatus, + "eos_data": [ + { + "interfaceDescriptions": { + "Ethernet8": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "down"}, + "Ethernet2": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"}, + "Ethernet3": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"}, + } + } + ], + "inputs": { + "interfaces": [ + {"name": "Ethernet2", "status": "up"}, + {"name": "Ethernet8", "status": "up"}, + {"name": "Ethernet3", "status": "up"}, + ] + }, + "expected": { + "result": "failure", + "messages": ["The following interface(s) are not in the expected state: ['Ethernet8 is up/down'"], + }, + }, + { + "name": "failure-po-status-down", + "test": VerifyInterfacesStatus, + "eos_data": [ + { + "interfaceDescriptions": { + "Port-Channel100": {"interfaceStatus": "down", "description": "", "lineProtocolStatus": "lowerLayerDown"}, + } + } + ], + "inputs": {"interfaces": [{"name": "PortChannel100", "status": "up"}]}, + "expected": { + "result": "failure", + "messages": ["The following interface(s) are not in the expected state: ['Port-Channel100 is down/lowerLayerDown'"], + }, + }, + { + "name": "failure-proto-unknown", + "test": VerifyInterfacesStatus, + "eos_data": [ + { + "interfaceDescriptions": { + "Ethernet8": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "down"}, + "Ethernet2": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "unknown"}, + "Ethernet3": {"interfaceStatus": "up", "description": "", "lineProtocolStatus": "up"}, + } + } + ], + "inputs": { + "interfaces": [ + {"name": "Ethernet2", "status": "up", "line_protocol_status": "down"}, + {"name": "Ethernet8", "status": "up"}, + {"name": "Ethernet3", "status": "up"}, + ] + }, + "expected": { + "result": "failure", + "messages": ["The following interface(s) are not in the expected state: ['Ethernet2 is up/unknown'"], + }, + }, + { + "name": "success", + "test": VerifyStormControlDrops, + "eos_data": [ + { + "aggregateTrafficClasses": {}, + "interfaces": { + "Ethernet1": { + "trafficTypes": {"broadcast": {"level": 100, "thresholdType": "packetsPerSecond", "rate": 0, "drop": 0, "dormant": False}}, + "active": True, + "reason": "", + "errdisabled": False, + } + }, + } + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyStormControlDrops, + "eos_data": [ + { + "aggregateTrafficClasses": {}, + "interfaces": { + "Ethernet1": { + "trafficTypes": {"broadcast": {"level": 100, "thresholdType": "packetsPerSecond", "rate": 0, "drop": 666, "dormant": False}}, + "active": True, + "reason": "", + "errdisabled": False, + } + }, + } + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["The following interfaces have none 0 storm-control drop counters {'Ethernet1': {'broadcast': 666}}"]}, + }, + { + "name": "success", + "test": VerifyPortChannels, + "eos_data": [ + { + "portChannels": { + "Port-Channel42": { + "recircFeature": [], + "maxWeight": 16, + "minSpeed": "0 gbps", + "rxPorts": {}, + "currWeight": 0, + "minLinks": 0, + "inactivePorts": {}, + "activePorts": {}, + "inactiveLag": False, + } + } + } + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyPortChannels, + "eos_data": [ + { + "portChannels": { + "Port-Channel42": { + "recircFeature": [], + "maxWeight": 16, + "minSpeed": "0 gbps", + "rxPorts": {}, + "currWeight": 0, + "minLinks": 0, + "inactivePorts": {"Ethernet8": {"reasonUnconfigured": "waiting for LACP response"}}, + "activePorts": {}, + "inactiveLag": False, + } + } + } + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["The following port-channels have inactive port(s): ['Port-Channel42']"]}, + }, + { + "name": "success", + "test": VerifyIllegalLACP, + "eos_data": [ + { + "portChannels": { + "Port-Channel42": { + "interfaces": { + "Ethernet8": { + "actorPortStatus": "noAgg", + "illegalRxCount": 0, + "markerResponseTxCount": 0, + "markerResponseRxCount": 0, + "lacpdusRxCount": 0, + "lacpdusTxCount": 454, + "markersTxCount": 0, + "markersRxCount": 0, + } + } + } + }, + "orphanPorts": {}, + } + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyIllegalLACP, + "eos_data": [ + { + "portChannels": { + "Port-Channel42": { + "interfaces": { + "Ethernet8": { + "actorPortStatus": "noAgg", + "illegalRxCount": 666, + "markerResponseTxCount": 0, + "markerResponseRxCount": 0, + "lacpdusRxCount": 0, + "lacpdusTxCount": 454, + "markersTxCount": 0, + "markersRxCount": 0, + } + } + } + }, + "orphanPorts": {}, + } + ], + "inputs": None, + "expected": { + "result": "failure", + "messages": ["The following port-channels have recieved illegal lacp packets on the following ports: [{'Port-Channel42': 'Ethernet8'}]"], + }, + }, + { + "name": "success", + "test": VerifyLoopbackCount, + "eos_data": [ + { + "interfaces": { + "Loopback42": { + "name": "Loopback42", + "interfaceStatus": "connected", + "interfaceAddress": {"ipAddr": {"maskLen": 0, "address": "0.0.0.0"}, "unnumberedIntf": "Vlan42"}, + "ipv4Routable240": False, + "lineProtocolStatus": "up", + "mtu": 65535, + }, + "Loopback666": { + "name": "Loopback666", + "interfaceStatus": "connected", + "interfaceAddress": {"ipAddr": {"maskLen": 32, "address": "6.6.6.6"}}, + "ipv4Routable240": False, + "lineProtocolStatus": "up", + "mtu": 65535, + }, + } + } + ], + "inputs": {"number": 2}, + "expected": {"result": "success"}, + }, + { + "name": "failure-loopback-down", + "test": VerifyLoopbackCount, + "eos_data": [ + { + "interfaces": { + "Loopback42": { + "name": "Loopback42", + "interfaceStatus": "connected", + "interfaceAddress": {"ipAddr": {"maskLen": 0, "address": "0.0.0.0"}, "unnumberedIntf": "Vlan42"}, + "ipv4Routable240": False, + "lineProtocolStatus": "up", + "mtu": 65535, + }, + "Loopback666": { + "name": "Loopback666", + "interfaceStatus": "connected", + "interfaceAddress": {"ipAddr": {"maskLen": 32, "address": "6.6.6.6"}}, + "ipv4Routable240": False, + "lineProtocolStatus": "down", + "mtu": 65535, + }, + } + } + ], + "inputs": {"number": 2}, + "expected": {"result": "failure", "messages": ["The following Loopbacks are not up: ['Loopback666']"]}, + }, + { + "name": "failure-count-loopback", + "test": VerifyLoopbackCount, + "eos_data": [ + { + "interfaces": { + "Loopback42": { + "name": "Loopback42", + "interfaceStatus": "connected", + "interfaceAddress": {"ipAddr": {"maskLen": 0, "address": "0.0.0.0"}, "unnumberedIntf": "Vlan42"}, + "ipv4Routable240": False, + "lineProtocolStatus": "up", + "mtu": 65535, + }, + } + } + ], + "inputs": {"number": 2}, + "expected": {"result": "failure", "messages": ["Found 1 Loopbacks when expecting 2"]}, + }, + { + "name": "success", + "test": VerifySVI, + "eos_data": [ + { + "interfaces": { + "Vlan42": { + "name": "Vlan42", + "interfaceStatus": "connected", + "interfaceAddress": {"ipAddr": {"maskLen": 24, "address": "11.11.11.11"}}, + "ipv4Routable240": False, + "lineProtocolStatus": "up", + "mtu": 1500, + } + } + } + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifySVI, + "eos_data": [ + { + "interfaces": { + "Vlan42": { + "name": "Vlan42", + "interfaceStatus": "notconnect", + "interfaceAddress": {"ipAddr": {"maskLen": 24, "address": "11.11.11.11"}}, + "ipv4Routable240": False, + "lineProtocolStatus": "lowerLayerDown", + "mtu": 1500, + } + } + } + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["The following SVIs are not up: ['Vlan42']"]}, + }, + { + "name": "success", + "test": VerifyL3MTU, + "eos_data": [ + { + "interfaces": { + "Ethernet2": { + "name": "Ethernet2", + "forwardingModel": "routed", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "hardware": "ethernet", + "mtu": 1500, + "l3MtuConfigured": True, + "l2Mru": 0, + }, + "Ethernet10": { + "name": "Ethernet10", + "forwardingModel": "bridged", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "hardware": "ethernet", + "mtu": 1500, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + "Management1/1": { + "name": "Management0", + "forwardingModel": "routed", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "hardware": "ethernet", + "mtu": 1500, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + "Port-Channel2": { + "name": "Port-Channel2", + "forwardingModel": "bridged", + "lineProtocolStatus": "lowerLayerDown", + "interfaceStatus": "notconnect", + "hardware": "portChannel", + "mtu": 1500, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + "Loopback0": { + "name": "Loopback0", + "forwardingModel": "routed", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "hardware": "loopback", + "mtu": 65535, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + "Vxlan1": { + "name": "Vxlan1", + "forwardingModel": "bridged", + "lineProtocolStatus": "down", + "interfaceStatus": "notconnect", + "hardware": "vxlan", + "mtu": 0, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + }, + } + ], + "inputs": {"mtu": 1500}, + "expected": {"result": "success"}, + }, + { + "name": "success", + "test": VerifyL3MTU, + "eos_data": [ + { + "interfaces": { + "Ethernet2": { + "name": "Ethernet2", + "forwardingModel": "routed", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "hardware": "ethernet", + "mtu": 1500, + "l3MtuConfigured": True, + "l2Mru": 0, + }, + "Ethernet10": { + "name": "Ethernet10", + "forwardingModel": "routed", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "hardware": "ethernet", + "mtu": 1501, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + "Management0": { + "name": "Management0", + "forwardingModel": "routed", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "hardware": "ethernet", + "mtu": 1500, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + "Port-Channel2": { + "name": "Port-Channel2", + "forwardingModel": "bridged", + "lineProtocolStatus": "lowerLayerDown", + "interfaceStatus": "notconnect", + "hardware": "portChannel", + "mtu": 1500, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + "Loopback0": { + "name": "Loopback0", + "forwardingModel": "routed", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "hardware": "loopback", + "mtu": 65535, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + "Vxlan1": { + "name": "Vxlan1", + "forwardingModel": "bridged", + "lineProtocolStatus": "down", + "interfaceStatus": "notconnect", + "hardware": "vxlan", + "mtu": 0, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + }, + } + ], + "inputs": {"mtu": 1500, "ignored_interfaces": ["Loopback", "Port-Channel", "Management", "Vxlan"], "specific_mtu": [{"Ethernet10": 1501}]}, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyL3MTU, + "eos_data": [ + { + "interfaces": { + "Ethernet2": { + "name": "Ethernet2", + "forwardingModel": "routed", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "hardware": "ethernet", + "mtu": 1600, + "l3MtuConfigured": True, + "l2Mru": 0, + }, + "Ethernet10": { + "name": "Ethernet10", + "forwardingModel": "routed", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "hardware": "ethernet", + "mtu": 1500, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + "Management0": { + "name": "Management0", + "forwardingModel": "routed", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "hardware": "ethernet", + "mtu": 1500, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + "Port-Channel2": { + "name": "Port-Channel2", + "forwardingModel": "bridged", + "lineProtocolStatus": "lowerLayerDown", + "interfaceStatus": "notconnect", + "hardware": "portChannel", + "mtu": 1500, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + "Loopback0": { + "name": "Loopback0", + "forwardingModel": "routed", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "hardware": "loopback", + "mtu": 65535, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + "Vxlan1": { + "name": "Vxlan1", + "forwardingModel": "bridged", + "lineProtocolStatus": "down", + "interfaceStatus": "notconnect", + "hardware": "vxlan", + "mtu": 0, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + }, + } + ], + "inputs": {"mtu": 1500}, + "expected": {"result": "failure", "messages": ["Some interfaces do not have correct MTU configured:\n[{'Ethernet2': 1600}]"]}, + }, + { + "name": "success", + "test": VerifyL2MTU, + "eos_data": [ + { + "interfaces": { + "Ethernet2": { + "name": "Ethernet2", + "forwardingModel": "routed", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "hardware": "ethernet", + "mtu": 1500, + "l3MtuConfigured": True, + "l2Mru": 0, + }, + "Ethernet10": { + "name": "Ethernet10", + "forwardingModel": "bridged", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "hardware": "ethernet", + "mtu": 9214, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + "Management0": { + "name": "Management0", + "forwardingModel": "routed", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "hardware": "ethernet", + "mtu": 1500, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + "Port-Channel2": { + "name": "Port-Channel2", + "forwardingModel": "bridged", + "lineProtocolStatus": "lowerLayerDown", + "interfaceStatus": "notconnect", + "hardware": "portChannel", + "mtu": 9214, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + "Loopback0": { + "name": "Loopback0", + "forwardingModel": "routed", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "hardware": "loopback", + "mtu": 65535, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + "Vxlan1": { + "name": "Vxlan1", + "forwardingModel": "bridged", + "lineProtocolStatus": "down", + "interfaceStatus": "notconnect", + "hardware": "vxlan", + "mtu": 0, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + }, + } + ], + "inputs": {"mtu": 9214}, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyL2MTU, + "eos_data": [ + { + "interfaces": { + "Ethernet2": { + "name": "Ethernet2", + "forwardingModel": "routed", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "hardware": "ethernet", + "mtu": 1600, + "l3MtuConfigured": True, + "l2Mru": 0, + }, + "Ethernet10": { + "name": "Ethernet10", + "forwardingModel": "bridged", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "hardware": "ethernet", + "mtu": 9214, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + "Management0": { + "name": "Management0", + "forwardingModel": "routed", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "hardware": "ethernet", + "mtu": 1500, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + "Port-Channel2": { + "name": "Port-Channel2", + "forwardingModel": "bridged", + "lineProtocolStatus": "lowerLayerDown", + "interfaceStatus": "notconnect", + "hardware": "portChannel", + "mtu": 9214, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + "Loopback0": { + "name": "Loopback0", + "forwardingModel": "routed", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "hardware": "loopback", + "mtu": 65535, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + "Vxlan1": { + "name": "Vxlan1", + "forwardingModel": "bridged", + "lineProtocolStatus": "down", + "interfaceStatus": "notconnect", + "hardware": "vxlan", + "mtu": 0, + "l3MtuConfigured": False, + "l2Mru": 0, + }, + }, + } + ], + "inputs": {"mtu": 1500}, + "expected": {"result": "failure", "messages": ["Some L2 interfaces do not have correct MTU configured:\n[{'Ethernet10': 9214}, {'Port-Channel2': 9214}]"]}, + }, + { + "name": "success", + "test": VerifyIPProxyARP, + "eos_data": [ + { + "interfaces": { + "Ethernet1": { + "name": "Ethernet1", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "mtu": 1500, + "interfaceAddressBrief": {"ipAddr": {"address": "10.1.0.0", "maskLen": 31}}, + "ipv4Routable240": False, + "ipv4Routable0": False, + "enabled": True, + "description": "P2P_LINK_TO_NW-CORE_Ethernet1", + "proxyArp": True, + "localProxyArp": False, + "gratuitousArp": False, + "vrf": "default", + "urpf": "disable", + "addresslessForwarding": "isInvalid", + "directedBroadcastEnabled": False, + "maxMssIngress": 0, + "maxMssEgress": 0, + } + } + }, + { + "interfaces": { + "Ethernet2": { + "name": "Ethernet2", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "mtu": 1500, + "interfaceAddressBrief": {"ipAddr": {"address": "10.1.0.2", "maskLen": 31}}, + "ipv4Routable240": False, + "ipv4Routable0": False, + "enabled": True, + "description": "P2P_LINK_TO_SW-CORE_Ethernet1", + "proxyArp": True, + "localProxyArp": False, + "gratuitousArp": False, + "vrf": "default", + "urpf": "disable", + "addresslessForwarding": "isInvalid", + "directedBroadcastEnabled": False, + "maxMssIngress": 0, + "maxMssEgress": 0, + } + } + }, + ], + "inputs": {"interfaces": ["Ethernet1", "Ethernet2"]}, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyIPProxyARP, + "eos_data": [ + { + "interfaces": { + "Ethernet1": { + "name": "Ethernet1", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "mtu": 1500, + "interfaceAddressBrief": {"ipAddr": {"address": "10.1.0.0", "maskLen": 31}}, + "ipv4Routable240": False, + "ipv4Routable0": False, + "enabled": True, + "description": "P2P_LINK_TO_NW-CORE_Ethernet1", + "proxyArp": True, + "localProxyArp": False, + "gratuitousArp": False, + "vrf": "default", + "urpf": "disable", + "addresslessForwarding": "isInvalid", + "directedBroadcastEnabled": False, + "maxMssIngress": 0, + "maxMssEgress": 0, + } + } + }, + { + "interfaces": { + "Ethernet2": { + "name": "Ethernet2", + "lineProtocolStatus": "up", + "interfaceStatus": "connected", + "mtu": 1500, + "interfaceAddressBrief": {"ipAddr": {"address": "10.1.0.2", "maskLen": 31}}, + "ipv4Routable240": False, + "ipv4Routable0": False, + "enabled": True, + "description": "P2P_LINK_TO_SW-CORE_Ethernet1", + "proxyArp": False, + "localProxyArp": False, + "gratuitousArp": False, + "vrf": "default", + "urpf": "disable", + "addresslessForwarding": "isInvalid", + "directedBroadcastEnabled": False, + "maxMssIngress": 0, + "maxMssEgress": 0, + } + } + }, + ], + "inputs": {"interfaces": ["Ethernet1", "Ethernet2"]}, + "expected": {"result": "failure", "messages": ["The following interface(s) have Proxy-ARP disabled: ['Ethernet2']"]}, + }, + { + "name": "success", + "test": VerifyInterfaceIPv4, + "eos_data": [ + { + "interfaces": { + "Ethernet2": { + "interfaceAddress": { + "primaryIp": {"address": "172.30.11.0", "maskLen": 31}, + "secondaryIpsOrderedList": [{"address": "10.10.10.0", "maskLen": 31}, {"address": "10.10.10.10", "maskLen": 31}], + } + } + } + }, + { + "interfaces": { + "Ethernet12": { + "interfaceAddress": { + "primaryIp": {"address": "172.30.11.10", "maskLen": 31}, + "secondaryIpsOrderedList": [{"address": "10.10.10.10", "maskLen": 31}, {"address": "10.10.10.20", "maskLen": 31}], + } + } + } + }, + ], + "inputs": { + "interfaces": [ + {"name": "Ethernet2", "primary_ip": "172.30.11.0/31", "secondary_ips": ["10.10.10.0/31", "10.10.10.10/31"]}, + {"name": "Ethernet12", "primary_ip": "172.30.11.10/31", "secondary_ips": ["10.10.10.10/31", "10.10.10.20/31"]}, + ] + }, + "expected": {"result": "success"}, + }, + { + "name": "success-without-secondary-ip", + "test": VerifyInterfaceIPv4, + "eos_data": [ + { + "interfaces": { + "Ethernet2": { + "interfaceAddress": { + "primaryIp": {"address": "172.30.11.0", "maskLen": 31}, + "secondaryIpsOrderedList": [], + } + } + } + }, + { + "interfaces": { + "Ethernet12": { + "interfaceAddress": { + "primaryIp": {"address": "172.30.11.10", "maskLen": 31}, + "secondaryIpsOrderedList": [], + } + } + } + }, + ], + "inputs": { + "interfaces": [ + {"name": "Ethernet2", "primary_ip": "172.30.11.0/31"}, + {"name": "Ethernet12", "primary_ip": "172.30.11.10/31"}, + ] + }, + "expected": {"result": "success"}, + }, + { + "name": "failure-not-l3-interface", + "test": VerifyInterfaceIPv4, + "eos_data": [{"interfaces": {"Ethernet2": {"interfaceAddress": {}}}}, {"interfaces": {"Ethernet12": {"interfaceAddress": {}}}}], + "inputs": { + "interfaces": [ + {"name": "Ethernet2", "primary_ip": "172.30.11.0/31", "secondary_ips": ["10.10.10.0/31", "10.10.10.10/31"]}, + {"name": "Ethernet12", "primary_ip": "172.30.11.20/31", "secondary_ips": ["10.10.11.0/31", "10.10.11.10/31"]}, + ] + }, + "expected": { + "result": "failure", + "messages": ["For interface `Ethernet2`, IP address is not configured.", "For interface `Ethernet12`, IP address is not configured."], + }, + }, + { + "name": "failure-ip-address-not-configured", + "test": VerifyInterfaceIPv4, + "eos_data": [ + { + "interfaces": { + "Ethernet2": { + "interfaceAddress": { + "primaryIp": {"address": "0.0.0.0", "maskLen": 0}, + "secondaryIpsOrderedList": [], + } + } + } + }, + { + "interfaces": { + "Ethernet12": { + "interfaceAddress": { + "primaryIp": {"address": "0.0.0.0", "maskLen": 0}, + "secondaryIpsOrderedList": [], + } + } + } + }, + ], + "inputs": { + "interfaces": [ + {"name": "Ethernet2", "primary_ip": "172.30.11.0/31", "secondary_ips": ["10.10.10.0/31", "10.10.10.10/31"]}, + {"name": "Ethernet12", "primary_ip": "172.30.11.10/31", "secondary_ips": ["10.10.11.0/31", "10.10.11.10/31"]}, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "For interface `Ethernet2`, The expected primary IP address is `172.30.11.0/31`, but the actual primary IP address is `0.0.0.0/0`. " + "The expected secondary IP addresses are `['10.10.10.0/31', '10.10.10.10/31']`, but the actual secondary IP address is not configured.", + "For interface `Ethernet12`, The expected primary IP address is `172.30.11.10/31`, but the actual primary IP address is `0.0.0.0/0`. " + "The expected secondary IP addresses are `['10.10.11.0/31', '10.10.11.10/31']`, but the actual secondary IP address is not configured.", + ], + }, + }, + { + "name": "failure-ip-address-missmatch", + "test": VerifyInterfaceIPv4, + "eos_data": [ + { + "interfaces": { + "Ethernet2": { + "interfaceAddress": { + "primaryIp": {"address": "172.30.11.0", "maskLen": 31}, + "secondaryIpsOrderedList": [{"address": "10.10.10.0", "maskLen": 31}, {"address": "10.10.10.10", "maskLen": 31}], + } + } + } + }, + { + "interfaces": { + "Ethernet3": { + "interfaceAddress": { + "primaryIp": {"address": "172.30.10.10", "maskLen": 31}, + "secondaryIpsOrderedList": [{"address": "10.10.11.0", "maskLen": 31}, {"address": "10.11.11.10", "maskLen": 31}], + } + } + } + }, + ], + "inputs": { + "interfaces": [ + {"name": "Ethernet2", "primary_ip": "172.30.11.2/31", "secondary_ips": ["10.10.10.20/31", "10.10.10.30/31"]}, + {"name": "Ethernet3", "primary_ip": "172.30.10.2/31", "secondary_ips": ["10.10.11.0/31", "10.10.11.10/31"]}, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "For interface `Ethernet2`, The expected primary IP address is `172.30.11.2/31`, but the actual primary IP address is `172.30.11.0/31`. " + "The expected secondary IP addresses are `['10.10.10.20/31', '10.10.10.30/31']`, but the actual secondary IP addresses are " + "`['10.10.10.0/31', '10.10.10.10/31']`.", + "For interface `Ethernet3`, The expected primary IP address is `172.30.10.2/31`, but the actual primary IP address is `172.30.10.10/31`. " + "The expected secondary IP addresses are `['10.10.11.0/31', '10.10.11.10/31']`, but the actual secondary IP addresses are " + "`['10.10.11.0/31', '10.11.11.10/31']`.", + ], + }, + }, + { + "name": "failure-secondary-ip-address", + "test": VerifyInterfaceIPv4, + "eos_data": [ + { + "interfaces": { + "Ethernet2": { + "interfaceAddress": { + "primaryIp": {"address": "172.30.11.0", "maskLen": 31}, + "secondaryIpsOrderedList": [], + } + } + } + }, + { + "interfaces": { + "Ethernet3": { + "interfaceAddress": { + "primaryIp": {"address": "172.30.10.10", "maskLen": 31}, + "secondaryIpsOrderedList": [{"address": "10.10.11.0", "maskLen": 31}, {"address": "10.11.11.10", "maskLen": 31}], + } + } + } + }, + ], + "inputs": { + "interfaces": [ + {"name": "Ethernet2", "primary_ip": "172.30.11.2/31", "secondary_ips": ["10.10.10.20/31", "10.10.10.30/31"]}, + {"name": "Ethernet3", "primary_ip": "172.30.10.2/31", "secondary_ips": ["10.10.11.0/31", "10.10.11.10/31"]}, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "For interface `Ethernet2`, The expected primary IP address is `172.30.11.2/31`, but the actual primary IP address is `172.30.11.0/31`. " + "The expected secondary IP addresses are `['10.10.10.20/31', '10.10.10.30/31']`, but the actual secondary IP address is not configured.", + "For interface `Ethernet3`, The expected primary IP address is `172.30.10.2/31`, but the actual primary IP address is `172.30.10.10/31`. " + "The expected secondary IP addresses are `['10.10.11.0/31', '10.10.11.10/31']`, but the actual secondary IP addresses are " + "`['10.10.11.0/31', '10.11.11.10/31']`.", + ], + }, + }, + { + "name": "success", + "test": VerifyIpVirtualRouterMac, + "eos_data": [ + { + "virtualMacs": [ + { + "macAddress": "00:1c:73:00:dc:01", + } + ], + } + ], + "inputs": {"mac_address": "00:1c:73:00:dc:01"}, + "expected": {"result": "success"}, + }, + { + "name": "faliure-incorrect-mac-address", + "test": VerifyIpVirtualRouterMac, + "eos_data": [ + { + "virtualMacs": [ + { + "macAddress": "00:00:00:00:00:00", + } + ], + } + ], + "inputs": {"mac_address": "00:1c:73:00:dc:01"}, + "expected": {"result": "failure", "messages": ["IP virtual router MAC address `00:1c:73:00:dc:01` is not configured."]}, + }, +] diff --git a/tests/units/anta_tests/test_lanz.py b/tests/units/anta_tests/test_lanz.py new file mode 100644 index 0000000..932d1ac --- /dev/null +++ b/tests/units/anta_tests/test_lanz.py @@ -0,0 +1,27 @@ +# 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. +"""Data for testing anta.tests.configuration""" +from __future__ import annotations + +from typing import Any + +from anta.tests.lanz import VerifyLANZ +from tests.lib.anta import test # noqa: F401; pylint: disable=W0611 + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifyLANZ, + "eos_data": [{"lanzEnabled": True}], + "inputs": None, + "expected": {"result": "success", "messages": ["LANZ is enabled"]}, + }, + { + "name": "failure", + "test": VerifyLANZ, + "eos_data": [{"lanzEnabled": False}], + "inputs": None, + "expected": {"result": "failure", "messages": ["LANZ is not enabled"]}, + }, +] diff --git a/tests/units/anta_tests/test_logging.py b/tests/units/anta_tests/test_logging.py new file mode 100644 index 0000000..8ac2323 --- /dev/null +++ b/tests/units/anta_tests/test_logging.py @@ -0,0 +1,254 @@ +# 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. +"""Data for testing anta.tests.logging""" +from __future__ import annotations + +from typing import Any + +from anta.tests.logging import ( + VerifyLoggingAccounting, + VerifyLoggingErrors, + VerifyLoggingHostname, + VerifyLoggingHosts, + VerifyLoggingLogsGeneration, + VerifyLoggingPersistent, + VerifyLoggingSourceIntf, + VerifyLoggingTimestamp, +) +from tests.lib.anta import test # noqa: F401; pylint: disable=W0611 + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifyLoggingPersistent, + "eos_data": [ + "Persistent logging: level debugging\n", + """Directory of flash:/persist/messages + + -rw- 9948 May 10 13:54 messages + + 33214693376 bytes total (10081136640 bytes free) + + """, + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure-disabled", + "test": VerifyLoggingPersistent, + "eos_data": [ + "Persistent logging: disabled\n", + """Directory of flash:/persist/messages + + -rw- 0 Apr 13 16:29 messages + + 33214693376 bytes total (10082168832 bytes free) + + """, + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["Persistent logging is disabled"]}, + }, + { + "name": "failure-not-saved", + "test": VerifyLoggingPersistent, + "eos_data": [ + "Persistent logging: level debugging\n", + """Directory of flash:/persist/messages + + -rw- 0 Apr 13 16:29 messages + + 33214693376 bytes total (10082168832 bytes free) + + """, + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["No persistent logs are saved in flash"]}, + }, + { + "name": "success", + "test": VerifyLoggingSourceIntf, + "eos_data": [ + """Trap logging: level informational + Logging source-interface 'Management0', IP Address 172.20.20.12 in VRF MGMT + Logging to '10.22.10.92' port 514 in VRF MGMT via udp + Logging to '10.22.10.93' port 514 in VRF MGMT via tcp + Logging to '10.22.10.94' port 911 in VRF MGMT via udp + + """ + ], + "inputs": {"interface": "Management0", "vrf": "MGMT"}, + "expected": {"result": "success"}, + }, + { + "name": "failure-intf", + "test": VerifyLoggingSourceIntf, + "eos_data": [ + """Trap logging: level informational + Logging source-interface 'Management1', IP Address 172.20.20.12 in VRF MGMT + Logging to '10.22.10.92' port 514 in VRF MGMT via udp + Logging to '10.22.10.93' port 514 in VRF MGMT via tcp + Logging to '10.22.10.94' port 911 in VRF MGMT via udp + + """ + ], + "inputs": {"interface": "Management0", "vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["Source-interface 'Management0' is not configured in VRF MGMT"]}, + }, + { + "name": "failure-vrf", + "test": VerifyLoggingSourceIntf, + "eos_data": [ + """Trap logging: level informational + Logging source-interface 'Management0', IP Address 172.20.20.12 in VRF default + Logging to '10.22.10.92' port 514 in VRF MGMT via udp + Logging to '10.22.10.93' port 514 in VRF MGMT via tcp + Logging to '10.22.10.94' port 911 in VRF MGMT via udp + + """ + ], + "inputs": {"interface": "Management0", "vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["Source-interface 'Management0' is not configured in VRF MGMT"]}, + }, + { + "name": "success", + "test": VerifyLoggingHosts, + "eos_data": [ + """Trap logging: level informational + Logging source-interface 'Management0', IP Address 172.20.20.12 in VRF MGMT + Logging to '10.22.10.92' port 514 in VRF MGMT via udp + Logging to '10.22.10.93' port 514 in VRF MGMT via tcp + Logging to '10.22.10.94' port 911 in VRF MGMT via udp + + """ + ], + "inputs": {"hosts": ["10.22.10.92", "10.22.10.93", "10.22.10.94"], "vrf": "MGMT"}, + "expected": {"result": "success"}, + }, + { + "name": "failure-hosts", + "test": VerifyLoggingHosts, + "eos_data": [ + """Trap logging: level informational + Logging source-interface 'Management1', IP Address 172.20.20.12 in VRF MGMT + Logging to '10.22.10.92' port 514 in VRF MGMT via udp + Logging to '10.22.10.103' port 514 in VRF MGMT via tcp + Logging to '10.22.10.104' port 911 in VRF MGMT via udp + + """ + ], + "inputs": {"hosts": ["10.22.10.92", "10.22.10.93", "10.22.10.94"], "vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["Syslog servers ['10.22.10.93', '10.22.10.94'] are not configured in VRF MGMT"]}, + }, + { + "name": "failure-vrf", + "test": VerifyLoggingHosts, + "eos_data": [ + """Trap logging: level informational + Logging source-interface 'Management0', IP Address 172.20.20.12 in VRF MGMT + Logging to '10.22.10.92' port 514 in VRF MGMT via udp + Logging to '10.22.10.93' port 514 in VRF default via tcp + Logging to '10.22.10.94' port 911 in VRF default via udp + + """ + ], + "inputs": {"hosts": ["10.22.10.92", "10.22.10.93", "10.22.10.94"], "vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["Syslog servers ['10.22.10.93', '10.22.10.94'] are not configured in VRF MGMT"]}, + }, + { + "name": "success", + "test": VerifyLoggingLogsGeneration, + "eos_data": [ + "", + "2023-05-10T13:54:21.463497-05:00 NW-CORE.example.org ConfigAgent: %SYS-6-LOGMSG_INFO: " + "Message from arista on command-api (10.22.1.107): ANTA VerifyLoggingLogsGeneration validation\n", + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyLoggingLogsGeneration, + "eos_data": ["", "Log Buffer:\n"], + "inputs": None, + "expected": {"result": "failure", "messages": ["Logs are not generated"]}, + }, + { + "name": "success", + "test": VerifyLoggingHostname, + "eos_data": [ + {"hostname": "NW-CORE", "fqdn": "NW-CORE.example.org"}, + "", + "2023-05-10T15:41:44.701810-05:00 NW-CORE.example.org ConfigAgent: %SYS-6-LOGMSG_INFO: " + "Message from arista on command-api (10.22.1.107): ANTA VerifyLoggingHostname validation\n", + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyLoggingHostname, + "eos_data": [ + {"hostname": "NW-CORE", "fqdn": "NW-CORE.example.org"}, + "", + "2023-05-10T13:54:21.463497-05:00 NW-CORE ConfigAgent: %SYS-6-LOGMSG_INFO: " + "Message from arista on command-api (10.22.1.107): ANTA VerifyLoggingLogsHostname validation\n", + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["Logs are not generated with the device FQDN"]}, + }, + { + "name": "success", + "test": VerifyLoggingTimestamp, + "eos_data": [ + "", + "2023-05-10T15:41:44.680813-05:00 NW-CORE.example.org ConfigAgent: %SYS-6-LOGMSG_INFO: " + "Message from arista on command-api (10.22.1.107): ANTA VerifyLoggingTimestamp validation\n", + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyLoggingTimestamp, + "eos_data": [ + "", + "May 10 13:54:22 NE-CORE.example.org ConfigAgent: %SYS-6-LOGMSG_INFO: " + "Message from arista on command-api (10.22.1.107): ANTA VerifyLoggingTimestamp validation\n", + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["Logs are not generated with the appropriate timestamp format"]}, + }, + { + "name": "success", + "test": VerifyLoggingAccounting, + "eos_data": ["2023 May 10 15:50:31 arista command-api 10.22.1.107 stop service=shell priv-lvl=15 cmd=show aaa accounting logs | tail\n"], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyLoggingAccounting, + "eos_data": ["2023 May 10 15:52:26 arista vty14 10.22.1.107 stop service=shell priv-lvl=15 cmd=show bgp summary\n"], + "inputs": None, + "expected": {"result": "failure", "messages": ["AAA accounting logs are not generated"]}, + }, + { + "name": "success", + "test": VerifyLoggingErrors, + "eos_data": [""], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyLoggingErrors, + "eos_data": [ + "Aug 2 19:57:42 DC1-LEAF1A Mlag: %FWK-3-SOCKET_CLOSE_REMOTE: Connection to Mlag (pid:27200) at tbt://192.168.0.1:4432/+n closed by peer (EOF)" + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["Device has reported syslog messages with a severity of ERRORS or higher"]}, + }, +] diff --git a/tests/units/anta_tests/test_mlag.py b/tests/units/anta_tests/test_mlag.py new file mode 100644 index 0000000..90f3c7a --- /dev/null +++ b/tests/units/anta_tests/test_mlag.py @@ -0,0 +1,343 @@ +# 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. +""" +Tests for anta.tests.mlag.py +""" +from __future__ import annotations + +from typing import Any + +from anta.tests.mlag import VerifyMlagConfigSanity, VerifyMlagDualPrimary, VerifyMlagInterfaces, VerifyMlagPrimaryPriority, VerifyMlagReloadDelay, VerifyMlagStatus +from tests.lib.anta import test # noqa: F401; pylint: disable=W0611 + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifyMlagStatus, + "eos_data": [{"state": "active", "negStatus": "connected", "peerLinkStatus": "up", "localIntfStatus": "up"}], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "skipped", + "test": VerifyMlagStatus, + "eos_data": [ + { + "state": "disabled", + } + ], + "inputs": None, + "expected": {"result": "skipped", "messages": ["MLAG is disabled"]}, + }, + { + "name": "failure", + "test": VerifyMlagStatus, + "eos_data": [{"state": "active", "negStatus": "connected", "peerLinkStatus": "down", "localIntfStatus": "up"}], + "inputs": None, + "expected": { + "result": "failure", + "messages": ["MLAG status is not OK: {'state': 'active', 'negStatus': 'connected', 'localIntfStatus': 'up', 'peerLinkStatus': 'down'}"], + }, + }, + { + "name": "success", + "test": VerifyMlagInterfaces, + "eos_data": [ + { + "state": "active", + "mlagPorts": {"Disabled": 0, "Configured": 0, "Inactive": 0, "Active-partial": 0, "Active-full": 1}, + } + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "skipped", + "test": VerifyMlagInterfaces, + "eos_data": [ + { + "state": "disabled", + } + ], + "inputs": None, + "expected": {"result": "skipped", "messages": ["MLAG is disabled"]}, + }, + { + "name": "failure-active-partial", + "test": VerifyMlagInterfaces, + "eos_data": [ + { + "state": "active", + "mlagPorts": {"Disabled": 0, "Configured": 0, "Inactive": 0, "Active-partial": 1, "Active-full": 1}, + } + ], + "inputs": None, + "expected": { + "result": "failure", + "messages": ["MLAG status is not OK: {'Disabled': 0, 'Configured': 0, 'Inactive': 0, 'Active-partial': 1, 'Active-full': 1}"], + }, + }, + { + "name": "failure-inactive", + "test": VerifyMlagInterfaces, + "eos_data": [ + { + "state": "active", + "mlagPorts": {"Disabled": 0, "Configured": 0, "Inactive": 1, "Active-partial": 1, "Active-full": 1}, + } + ], + "inputs": None, + "expected": { + "result": "failure", + "messages": ["MLAG status is not OK: {'Disabled': 0, 'Configured': 0, 'Inactive': 1, 'Active-partial': 1, 'Active-full': 1}"], + }, + }, + { + "name": "success", + "test": VerifyMlagConfigSanity, + "eos_data": [{"globalConfiguration": {}, "interfaceConfiguration": {}, "mlagActive": True, "mlagConnected": True}], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "skipped", + "test": VerifyMlagConfigSanity, + "eos_data": [ + { + "mlagActive": False, + } + ], + "inputs": None, + "expected": {"result": "skipped", "messages": ["MLAG is disabled"]}, + }, + { + "name": "error", + "test": VerifyMlagConfigSanity, + "eos_data": [ + { + "dummy": False, + } + ], + "inputs": None, + "expected": {"result": "error", "messages": ["Incorrect JSON response - 'mlagActive' state was not found"]}, + }, + { + "name": "failure-global", + "test": VerifyMlagConfigSanity, + "eos_data": [ + { + "globalConfiguration": {"mlag": {"globalParameters": {"dual-primary-detection-delay": {"localValue": "0", "peerValue": "200"}}}}, + "interfaceConfiguration": {}, + "mlagActive": True, + "mlagConnected": True, + } + ], + "inputs": None, + "expected": { + "result": "failure", + "messages": [ + "MLAG config-sanity returned inconsistencies: " + "{'globalConfiguration': {'mlag': {'globalParameters': " + "{'dual-primary-detection-delay': {'localValue': '0', 'peerValue': '200'}}}}, " + "'interfaceConfiguration': {}}" + ], + }, + }, + { + "name": "failure-interface", + "test": VerifyMlagConfigSanity, + "eos_data": [ + { + "globalConfiguration": {}, + "interfaceConfiguration": {"trunk-native-vlan mlag30": {"interface": {"Port-Channel30": {"localValue": "123", "peerValue": "3700"}}}}, + "mlagActive": True, + "mlagConnected": True, + } + ], + "inputs": None, + "expected": { + "result": "failure", + "messages": [ + "MLAG config-sanity returned inconsistencies: " + "{'globalConfiguration': {}, " + "'interfaceConfiguration': {'trunk-native-vlan mlag30': " + "{'interface': {'Port-Channel30': {'localValue': '123', 'peerValue': '3700'}}}}}" + ], + }, + }, + { + "name": "success", + "test": VerifyMlagReloadDelay, + "eos_data": [{"state": "active", "reloadDelay": 300, "reloadDelayNonMlag": 330}], + "inputs": {"reload_delay": 300, "reload_delay_non_mlag": 330}, + "expected": {"result": "success"}, + }, + { + "name": "skipped-disabled", + "test": VerifyMlagReloadDelay, + "eos_data": [ + { + "state": "disabled", + } + ], + "inputs": {"reload_delay": 300, "reload_delay_non_mlag": 330}, + "expected": {"result": "skipped", "messages": ["MLAG is disabled"]}, + }, + { + "name": "failure", + "test": VerifyMlagReloadDelay, + "eos_data": [{"state": "active", "reloadDelay": 400, "reloadDelayNonMlag": 430}], + "inputs": {"reload_delay": 300, "reload_delay_non_mlag": 330}, + "expected": {"result": "failure", "messages": ["The reload-delay parameters are not configured properly: {'reloadDelay': 400, 'reloadDelayNonMlag': 430}"]}, + }, + { + "name": "success", + "test": VerifyMlagDualPrimary, + "eos_data": [ + { + "state": "active", + "dualPrimaryDetectionState": "configured", + "dualPrimaryPortsErrdisabled": False, + "dualPrimaryMlagRecoveryDelay": 60, + "dualPrimaryNonMlagRecoveryDelay": 0, + "detail": {"dualPrimaryDetectionDelay": 200, "dualPrimaryAction": "none"}, + } + ], + "inputs": {"detection_delay": 200, "errdisabled": False, "recovery_delay": 60, "recovery_delay_non_mlag": 0}, + "expected": {"result": "success"}, + }, + { + "name": "skipped-disabled", + "test": VerifyMlagDualPrimary, + "eos_data": [ + { + "state": "disabled", + } + ], + "inputs": {"detection_delay": 200, "errdisabled": False, "recovery_delay": 60, "recovery_delay_non_mlag": 0}, + "expected": {"result": "skipped", "messages": ["MLAG is disabled"]}, + }, + { + "name": "failure-disabled", + "test": VerifyMlagDualPrimary, + "eos_data": [ + { + "state": "active", + "dualPrimaryDetectionState": "disabled", + "dualPrimaryPortsErrdisabled": False, + } + ], + "inputs": {"detection_delay": 200, "errdisabled": False, "recovery_delay": 60, "recovery_delay_non_mlag": 0}, + "expected": {"result": "failure", "messages": ["Dual-primary detection is disabled"]}, + }, + { + "name": "failure-wrong-timers", + "test": VerifyMlagDualPrimary, + "eos_data": [ + { + "state": "active", + "dualPrimaryDetectionState": "configured", + "dualPrimaryPortsErrdisabled": False, + "dualPrimaryMlagRecoveryDelay": 160, + "dualPrimaryNonMlagRecoveryDelay": 0, + "detail": {"dualPrimaryDetectionDelay": 300, "dualPrimaryAction": "none"}, + } + ], + "inputs": {"detection_delay": 200, "errdisabled": False, "recovery_delay": 60, "recovery_delay_non_mlag": 0}, + "expected": { + "result": "failure", + "messages": [ + ( + "The dual-primary parameters are not configured properly: " + "{'detail.dualPrimaryDetectionDelay': 300, " + "'detail.dualPrimaryAction': 'none', " + "'dualPrimaryMlagRecoveryDelay': 160, " + "'dualPrimaryNonMlagRecoveryDelay': 0}" + ) + ], + }, + }, + { + "name": "failure-wrong-action", + "test": VerifyMlagDualPrimary, + "eos_data": [ + { + "state": "active", + "dualPrimaryDetectionState": "configured", + "dualPrimaryPortsErrdisabled": False, + "dualPrimaryMlagRecoveryDelay": 60, + "dualPrimaryNonMlagRecoveryDelay": 0, + "detail": {"dualPrimaryDetectionDelay": 200, "dualPrimaryAction": "none"}, + } + ], + "inputs": {"detection_delay": 200, "errdisabled": True, "recovery_delay": 60, "recovery_delay_non_mlag": 0}, + "expected": { + "result": "failure", + "messages": [ + ( + "The dual-primary parameters are not configured properly: " + "{'detail.dualPrimaryDetectionDelay': 200, " + "'detail.dualPrimaryAction': 'none', " + "'dualPrimaryMlagRecoveryDelay': 60, " + "'dualPrimaryNonMlagRecoveryDelay': 0}" + ) + ], + }, + }, + { + "name": "success", + "test": VerifyMlagPrimaryPriority, + "eos_data": [ + { + "state": "active", + "detail": {"mlagState": "primary", "primaryPriority": 32767}, + } + ], + "inputs": { + "primary_priority": 32767, + }, + "expected": {"result": "success"}, + }, + { + "name": "skipped-disabled", + "test": VerifyMlagPrimaryPriority, + "eos_data": [ + { + "state": "disabled", + } + ], + "inputs": {"primary_priority": 32767}, + "expected": {"result": "skipped", "messages": ["MLAG is disabled"]}, + }, + { + "name": "failure-not-primary", + "test": VerifyMlagPrimaryPriority, + "eos_data": [ + { + "state": "active", + "detail": {"mlagState": "secondary", "primaryPriority": 32767}, + } + ], + "inputs": {"primary_priority": 32767}, + "expected": { + "result": "failure", + "messages": ["The device is not set as MLAG primary."], + }, + }, + { + "name": "failure-incorrect-priority", + "test": VerifyMlagPrimaryPriority, + "eos_data": [ + { + "state": "active", + "detail": {"mlagState": "secondary", "primaryPriority": 32767}, + } + ], + "inputs": {"primary_priority": 1}, + "expected": { + "result": "failure", + "messages": ["The device is not set as MLAG primary.", "The primary priority does not match expected. Expected `1`, but found `32767` instead."], + }, + }, +] diff --git a/tests/units/anta_tests/test_multicast.py b/tests/units/anta_tests/test_multicast.py new file mode 100644 index 0000000..9276a9f --- /dev/null +++ b/tests/units/anta_tests/test_multicast.py @@ -0,0 +1,175 @@ +# 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. +"""Test inputs for anta.tests.multicast""" +from __future__ import annotations + +from typing import Any + +from anta.tests.multicast import VerifyIGMPSnoopingGlobal, VerifyIGMPSnoopingVlans +from tests.lib.anta import test # noqa: F401; pylint: disable=unused-import + +DATA: list[dict[str, Any]] = [ + { + "name": "success-enabled", + "test": VerifyIGMPSnoopingVlans, + "eos_data": [ + { + "reportFlooding": "disabled", + "igmpSnoopingState": "enabled", + "vlans": { + "1": { + "reportFlooding": "disabled", + "proxyActive": False, + "groupsOverrun": False, + "multicastRouterLearningMode": "pim-dvmrp", + "igmpSnoopingState": "enabled", + "pruningActive": False, + "maxGroups": 65534, + "immediateLeave": "default", + "floodingTraffic": True, + }, + "42": { + "reportFlooding": "disabled", + "proxyActive": False, + "groupsOverrun": False, + "multicastRouterLearningMode": "pim-dvmrp", + "igmpSnoopingState": "enabled", + "pruningActive": False, + "maxGroups": 65534, + "immediateLeave": "default", + "floodingTraffic": True, + }, + }, + "robustness": 2, + "immediateLeave": "enabled", + "reportFloodingSwitchPorts": [], + } + ], + "inputs": {"vlans": {1: True, 42: True}}, + "expected": {"result": "success"}, + }, + { + "name": "success-disabled", + "test": VerifyIGMPSnoopingVlans, + "eos_data": [ + { + "reportFlooding": "disabled", + "igmpSnoopingState": "enabled", + "vlans": { + "42": { + "reportFlooding": "disabled", + "proxyActive": False, + "groupsOverrun": False, + "multicastRouterLearningMode": "pim-dvmrp", + "igmpSnoopingState": "disabled", + "pruningActive": False, + "maxGroups": 65534, + "immediateLeave": "default", + "floodingTraffic": True, + } + }, + "robustness": 2, + "immediateLeave": "enabled", + "reportFloodingSwitchPorts": [], + } + ], + "inputs": {"vlans": {42: False}}, + "expected": {"result": "success"}, + }, + { + "name": "failure-missing-vlan", + "test": VerifyIGMPSnoopingVlans, + "eos_data": [ + { + "reportFlooding": "disabled", + "igmpSnoopingState": "enabled", + "vlans": { + "1": { + "reportFlooding": "disabled", + "proxyActive": False, + "groupsOverrun": False, + "multicastRouterLearningMode": "pim-dvmrp", + "igmpSnoopingState": "enabled", + "pruningActive": False, + "maxGroups": 65534, + "immediateLeave": "default", + "floodingTraffic": True, + }, + }, + "robustness": 2, + "immediateLeave": "enabled", + "reportFloodingSwitchPorts": [], + } + ], + "inputs": {"vlans": {1: False, 42: False}}, + "expected": {"result": "failure", "messages": ["IGMP state for vlan 1 is enabled", "Supplied vlan 42 is not present on the device."]}, + }, + { + "name": "failure-wrong-state", + "test": VerifyIGMPSnoopingVlans, + "eos_data": [ + { + "reportFlooding": "disabled", + "igmpSnoopingState": "enabled", + "vlans": { + "1": { + "reportFlooding": "disabled", + "proxyActive": False, + "groupsOverrun": False, + "multicastRouterLearningMode": "pim-dvmrp", + "igmpSnoopingState": "disabled", + "pruningActive": False, + "maxGroups": 65534, + "immediateLeave": "default", + "floodingTraffic": True, + }, + }, + "robustness": 2, + "immediateLeave": "enabled", + "reportFloodingSwitchPorts": [], + } + ], + "inputs": {"vlans": {1: True}}, + "expected": {"result": "failure", "messages": ["IGMP state for vlan 1 is disabled"]}, + }, + { + "name": "success-enabled", + "test": VerifyIGMPSnoopingGlobal, + "eos_data": [ + { + "reportFlooding": "disabled", + "igmpSnoopingState": "enabled", + "robustness": 2, + "immediateLeave": "enabled", + "reportFloodingSwitchPorts": [], + } + ], + "inputs": {"enabled": True}, + "expected": {"result": "success"}, + }, + { + "name": "success-disabled", + "test": VerifyIGMPSnoopingGlobal, + "eos_data": [ + { + "reportFlooding": "disabled", + "igmpSnoopingState": "disabled", + } + ], + "inputs": {"enabled": False}, + "expected": {"result": "success"}, + }, + { + "name": "failure-wrong-state", + "test": VerifyIGMPSnoopingGlobal, + "eos_data": [ + { + "reportFlooding": "disabled", + "igmpSnoopingState": "disabled", + } + ], + "inputs": {"enabled": True}, + "expected": {"result": "failure", "messages": ["IGMP state is not valid: disabled"]}, + }, +] diff --git a/tests/units/anta_tests/test_profiles.py b/tests/units/anta_tests/test_profiles.py new file mode 100644 index 0000000..c0ebb57 --- /dev/null +++ b/tests/units/anta_tests/test_profiles.py @@ -0,0 +1,47 @@ +# 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. +""" +Tests for anta.tests.profiles.py +""" +from __future__ import annotations + +from typing import Any + +from anta.tests.profiles import VerifyTcamProfile, VerifyUnifiedForwardingTableMode +from tests.lib.anta import test # noqa: F401; pylint: disable=W0611 + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifyUnifiedForwardingTableMode, + "eos_data": [{"uftMode": "2", "urpfEnabled": False, "chipModel": "bcm56870", "l2TableSize": 163840, "l3TableSize": 147456, "lpmTableSize": 32768}], + "inputs": {"mode": 2}, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyUnifiedForwardingTableMode, + "eos_data": [{"uftMode": "2", "urpfEnabled": False, "chipModel": "bcm56870", "l2TableSize": 163840, "l3TableSize": 147456, "lpmTableSize": 32768}], + "inputs": {"mode": 3}, + "expected": {"result": "failure", "messages": ["Device is not running correct UFT mode (expected: 3 / running: 2)"]}, + }, + { + "name": "success", + "test": VerifyTcamProfile, + "eos_data": [ + {"pmfProfiles": {"FixedSystem": {"config": "test", "configType": "System Profile", "status": "test", "mode": "tcam"}}, "lastProgrammingStatus": {}} + ], + "inputs": {"profile": "test"}, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyTcamProfile, + "eos_data": [ + {"pmfProfiles": {"FixedSystem": {"config": "test", "configType": "System Profile", "status": "default", "mode": "tcam"}}, "lastProgrammingStatus": {}} + ], + "inputs": {"profile": "test"}, + "expected": {"result": "failure", "messages": ["Incorrect profile running on device: default"]}, + }, +] diff --git a/tests/units/anta_tests/test_ptp.py b/tests/units/anta_tests/test_ptp.py new file mode 100644 index 0000000..3969c97 --- /dev/null +++ b/tests/units/anta_tests/test_ptp.py @@ -0,0 +1,42 @@ +# 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. +"""Data for testing anta.tests.configuration""" +from __future__ import annotations + +from typing import Any + +from anta.tests.ptp import VerifyPtpStatus + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifyPtpStatus, + "eos_data": [ + { + "ptpMode": "ptpBoundaryClock", + "ptpProfile": "ptpDefaultProfile", + "ptpClockSummary": { + "clockIdentity": "0xcc:1a:a3:ff:ff:c3:bf:eb", + "gmClockIdentity": "0x00:00:00:00:00:00:00:00", + "numberOfSlavePorts": 0, + "numberOfMasterPorts": 0, + "offsetFromMaster": 0, + "meanPathDelay": 0, + "stepsRemoved": 0, + "skew": 1.0, + }, + "ptpIntfSummaries": {}, + } + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyPtpStatus, + "eos_data": [{"ptpIntfSummaries": {}}], + "inputs": None, + "expected": {"result": "failure"}, + }, +] diff --git a/tests/units/anta_tests/test_security.py b/tests/units/anta_tests/test_security.py new file mode 100644 index 0000000..17fa04e --- /dev/null +++ b/tests/units/anta_tests/test_security.py @@ -0,0 +1,900 @@ +# 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. +""" +Tests for anta.tests.security.py +""" +from __future__ import annotations + +from typing import Any + +from anta.tests.security import ( + VerifyAPIHttpsSSL, + VerifyAPIHttpStatus, + VerifyAPIIPv4Acl, + VerifyAPIIPv6Acl, + VerifyAPISSLCertificate, + VerifyBannerLogin, + VerifyBannerMotd, + VerifyIPv4ACL, + VerifySSHIPv4Acl, + VerifySSHIPv6Acl, + VerifySSHStatus, + VerifyTelnetStatus, +) +from tests.lib.anta import test # noqa: F401; pylint: disable=W0611 + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifySSHStatus, + "eos_data": ["SSHD status for Default VRF is disabled\nSSH connection limit is 50\nSSH per host connection limit is 20\nFIPS status: disabled\n\n"], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifySSHStatus, + "eos_data": ["SSHD status for Default VRF is enabled\nSSH connection limit is 50\nSSH per host connection limit is 20\nFIPS status: disabled\n\n"], + "inputs": None, + "expected": {"result": "failure", "messages": ["SSHD status for Default VRF is enabled"]}, + }, + { + "name": "success", + "test": VerifySSHIPv4Acl, + "eos_data": [{"ipAclList": {"aclList": [{"type": "Ip4Acl", "name": "ACL_IPV4_SSH", "configuredVrfs": ["MGMT"], "activeVrfs": ["MGMT"]}]}}], + "inputs": {"number": 1, "vrf": "MGMT"}, + "expected": {"result": "success"}, + }, + { + "name": "failure-wrong-number", + "test": VerifySSHIPv4Acl, + "eos_data": [{"ipAclList": {"aclList": []}}], + "inputs": {"number": 1, "vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["Expected 1 SSH IPv4 ACL(s) in vrf MGMT but got 0"]}, + }, + { + "name": "failure-wrong-vrf", + "test": VerifySSHIPv4Acl, + "eos_data": [{"ipAclList": {"aclList": [{"type": "Ip4Acl", "name": "ACL_IPV4_SSH", "configuredVrfs": ["default"], "activeVrfs": ["default"]}]}}], + "inputs": {"number": 1, "vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["SSH IPv4 ACL(s) not configured or active in vrf MGMT: ['ACL_IPV4_SSH']"]}, + }, + { + "name": "success", + "test": VerifySSHIPv6Acl, + "eos_data": [{"ipv6AclList": {"aclList": [{"type": "Ip6Acl", "name": "ACL_IPV6_SSH", "configuredVrfs": ["MGMT"], "activeVrfs": ["MGMT"]}]}}], + "inputs": {"number": 1, "vrf": "MGMT"}, + "expected": {"result": "success"}, + }, + { + "name": "failure-wrong-number", + "test": VerifySSHIPv6Acl, + "eos_data": [{"ipv6AclList": {"aclList": []}}], + "inputs": {"number": 1, "vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["Expected 1 SSH IPv6 ACL(s) in vrf MGMT but got 0"]}, + }, + { + "name": "failure-wrong-vrf", + "test": VerifySSHIPv6Acl, + "eos_data": [{"ipv6AclList": {"aclList": [{"type": "Ip6Acl", "name": "ACL_IPV6_SSH", "configuredVrfs": ["default"], "activeVrfs": ["default"]}]}}], + "inputs": {"number": 1, "vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["SSH IPv6 ACL(s) not configured or active in vrf MGMT: ['ACL_IPV6_SSH']"]}, + }, + { + "name": "success", + "test": VerifyTelnetStatus, + "eos_data": [{"serverState": "disabled", "vrfName": "default", "maxTelnetSessions": 20, "maxTelnetSessionsPerHost": 20}], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyTelnetStatus, + "eos_data": [{"serverState": "enabled", "vrfName": "default", "maxTelnetSessions": 20, "maxTelnetSessionsPerHost": 20}], + "inputs": None, + "expected": {"result": "failure", "messages": ["Telnet status for Default VRF is enabled"]}, + }, + { + "name": "success", + "test": VerifyAPIHttpStatus, + "eos_data": [ + { + "enabled": True, + "httpServer": {"configured": False, "running": False, "port": 80}, + "localHttpServer": {"configured": False, "running": False, "port": 8080}, + "httpsServer": {"configured": True, "running": True, "port": 443}, + "unixSocketServer": {"configured": False, "running": False}, + "sslProfile": {"name": "API_SSL_Profile", "configured": True, "state": "valid"}, + "tlsProtocol": ["1.2"], + } + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyAPIHttpStatus, + "eos_data": [ + { + "enabled": True, + "httpServer": {"configured": True, "running": True, "port": 80}, + "localHttpServer": {"configured": False, "running": False, "port": 8080}, + "httpsServer": {"configured": True, "running": True, "port": 443}, + "unixSocketServer": {"configured": False, "running": False}, + "sslProfile": {"name": "API_SSL_Profile", "configured": True, "state": "valid"}, + "tlsProtocol": ["1.2"], + } + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["eAPI HTTP server is enabled globally"]}, + }, + { + "name": "success", + "test": VerifyAPIHttpsSSL, + "eos_data": [ + { + "enabled": True, + "httpServer": {"configured": False, "running": False, "port": 80}, + "localHttpServer": {"configured": False, "running": False, "port": 8080}, + "httpsServer": {"configured": True, "running": True, "port": 443}, + "unixSocketServer": {"configured": False, "running": False}, + "sslProfile": {"name": "API_SSL_Profile", "configured": True, "state": "valid"}, + "tlsProtocol": ["1.2"], + } + ], + "inputs": {"profile": "API_SSL_Profile"}, + "expected": {"result": "success"}, + }, + { + "name": "failure-not-configured", + "test": VerifyAPIHttpsSSL, + "eos_data": [ + { + "enabled": True, + "httpServer": {"configured": True, "running": True, "port": 80}, + "localHttpServer": {"configured": False, "running": False, "port": 8080}, + "httpsServer": {"configured": True, "running": True, "port": 443}, + "unixSocketServer": {"configured": False, "running": False}, + "tlsProtocol": ["1.2"], + } + ], + "inputs": {"profile": "API_SSL_Profile"}, + "expected": {"result": "failure", "messages": ["eAPI HTTPS server SSL profile (API_SSL_Profile) is not configured"]}, + }, + { + "name": "failure-misconfigured-invalid", + "test": VerifyAPIHttpsSSL, + "eos_data": [ + { + "enabled": True, + "httpServer": {"configured": True, "running": True, "port": 80}, + "localHttpServer": {"configured": False, "running": False, "port": 8080}, + "httpsServer": {"configured": True, "running": True, "port": 443}, + "unixSocketServer": {"configured": False, "running": False}, + "sslProfile": {"name": "Wrong_SSL_Profile", "configured": True, "state": "valid"}, + "tlsProtocol": ["1.2"], + } + ], + "inputs": {"profile": "API_SSL_Profile"}, + "expected": {"result": "failure", "messages": ["eAPI HTTPS server SSL profile (API_SSL_Profile) is misconfigured or invalid"]}, + }, + { + "name": "success", + "test": VerifyAPIIPv4Acl, + "eos_data": [{"ipAclList": {"aclList": [{"type": "Ip4Acl", "name": "ACL_IPV4_API", "configuredVrfs": ["MGMT"], "activeVrfs": ["MGMT"]}]}}], + "inputs": {"number": 1, "vrf": "MGMT"}, + "expected": {"result": "success"}, + }, + { + "name": "failure-wrong-number", + "test": VerifyAPIIPv4Acl, + "eos_data": [{"ipAclList": {"aclList": []}}], + "inputs": {"number": 1, "vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["Expected 1 eAPI IPv4 ACL(s) in vrf MGMT but got 0"]}, + }, + { + "name": "failure-wrong-vrf", + "test": VerifyAPIIPv4Acl, + "eos_data": [{"ipAclList": {"aclList": [{"type": "Ip4Acl", "name": "ACL_IPV4_API", "configuredVrfs": ["default"], "activeVrfs": ["default"]}]}}], + "inputs": {"number": 1, "vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["eAPI IPv4 ACL(s) not configured or active in vrf MGMT: ['ACL_IPV4_API']"]}, + }, + { + "name": "success", + "test": VerifyAPIIPv6Acl, + "eos_data": [{"ipv6AclList": {"aclList": [{"type": "Ip6Acl", "name": "ACL_IPV6_API", "configuredVrfs": ["MGMT"], "activeVrfs": ["MGMT"]}]}}], + "inputs": {"number": 1, "vrf": "MGMT"}, + "expected": {"result": "success"}, + }, + { + "name": "failure-wrong-number", + "test": VerifyAPIIPv6Acl, + "eos_data": [{"ipv6AclList": {"aclList": []}}], + "inputs": {"number": 1, "vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["Expected 1 eAPI IPv6 ACL(s) in vrf MGMT but got 0"]}, + }, + { + "name": "failure-wrong-vrf", + "test": VerifyAPIIPv6Acl, + "eos_data": [{"ipv6AclList": {"aclList": [{"type": "Ip6Acl", "name": "ACL_IPV6_API", "configuredVrfs": ["default"], "activeVrfs": ["default"]}]}}], + "inputs": {"number": 1, "vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["eAPI IPv6 ACL(s) not configured or active in vrf MGMT: ['ACL_IPV6_API']"]}, + }, + { + "name": "success", + "test": VerifyAPISSLCertificate, + "eos_data": [ + { + "certificates": { + "ARISTA_ROOT_CA.crt": { + "subject": {"commonName": "Arista Networks Internal IT Root Cert Authority"}, + "notAfter": 2127420899, + "publicKey": { + "encryptionAlgorithm": "RSA", + "size": 4096, + }, + }, + "ARISTA_SIGNING_CA.crt": { + "subject": {"commonName": "AristaIT-ICA ECDSA Issuing Cert Authority"}, + "notAfter": 2127420899, + "publicKey": { + "encryptionAlgorithm": "ECDSA", + "size": 256, + }, + }, + } + }, + { + "utcTime": 1702288467.6736515, + }, + ], + "inputs": { + "certificates": [ + { + "certificate_name": "ARISTA_SIGNING_CA.crt", + "expiry_threshold": 30, + "common_name": "AristaIT-ICA ECDSA Issuing Cert Authority", + "encryption_algorithm": "ECDSA", + "key_size": 256, + }, + { + "certificate_name": "ARISTA_ROOT_CA.crt", + "expiry_threshold": 30, + "common_name": "Arista Networks Internal IT Root Cert Authority", + "encryption_algorithm": "RSA", + "key_size": 4096, + }, + ] + }, + "expected": {"result": "success"}, + }, + { + "name": "failure-certificate-not-configured", + "test": VerifyAPISSLCertificate, + "eos_data": [ + { + "certificates": { + "ARISTA_SIGNING_CA.crt": { + "subject": {"commonName": "AristaIT-ICA ECDSA Issuing Cert Authority"}, + "notAfter": 2127420899, + "publicKey": { + "encryptionAlgorithm": "ECDSA", + "size": 256, + }, + }, + } + }, + { + "utcTime": 1702288467.6736515, + }, + ], + "inputs": { + "certificates": [ + { + "certificate_name": "ARISTA_SIGNING_CA.crt", + "expiry_threshold": 30, + "common_name": "AristaIT-ICA ECDSA Issuing Cert Authority", + "encryption_algorithm": "ECDSA", + "key_size": 256, + }, + { + "certificate_name": "ARISTA_ROOT_CA.crt", + "expiry_threshold": 30, + "common_name": "Arista Networks Internal IT Root Cert Authority", + "encryption_algorithm": "RSA", + "key_size": 4096, + }, + ] + }, + "expected": { + "result": "failure", + "messages": ["SSL certificate 'ARISTA_ROOT_CA.crt', is not configured.\n"], + }, + }, + { + "name": "failure-certificate-expired", + "test": VerifyAPISSLCertificate, + "eos_data": [ + { + "certificates": { + "ARISTA_ROOT_CA.crt": { + "subject": {"commonName": "Arista Networks Internal IT Root Cert Authority"}, + "notAfter": 1702533518, + "publicKey": { + "encryptionAlgorithm": "RSA", + "size": 4096, + }, + }, + } + }, + { + "utcTime": 1702622372.2240553, + }, + ], + "inputs": { + "certificates": [ + { + "certificate_name": "ARISTA_SIGNING_CA.crt", + "expiry_threshold": 30, + "common_name": "AristaIT-ICA ECDSA Issuing Cert Authority", + "encryption_algorithm": "ECDSA", + "key_size": 256, + }, + { + "certificate_name": "ARISTA_ROOT_CA.crt", + "expiry_threshold": 30, + "common_name": "Arista Networks Internal IT Root Cert Authority", + "encryption_algorithm": "RSA", + "key_size": 4096, + }, + ] + }, + "expected": { + "result": "failure", + "messages": ["SSL certificate 'ARISTA_SIGNING_CA.crt', is not configured.\n", "SSL certificate `ARISTA_ROOT_CA.crt` is expired.\n"], + }, + }, + { + "name": "failure-certificate-about-to-expire", + "test": VerifyAPISSLCertificate, + "eos_data": [ + { + "certificates": { + "ARISTA_ROOT_CA.crt": { + "subject": {"commonName": "Arista Networks Internal IT Root Cert Authority"}, + "notAfter": 1704782709, + "publicKey": { + "encryptionAlgorithm": "RSA", + "size": 4096, + }, + }, + "ARISTA_SIGNING_CA.crt": { + "subject": {"commonName": "AristaIT-ICA ECDSA Issuing Cert Authority"}, + "notAfter": 1702533518, + "publicKey": { + "encryptionAlgorithm": "ECDSA", + "size": 256, + }, + }, + } + }, + { + "utcTime": 1702622372.2240553, + }, + ], + "inputs": { + "certificates": [ + { + "certificate_name": "ARISTA_SIGNING_CA.crt", + "expiry_threshold": 30, + "common_name": "AristaIT-ICA ECDSA Issuing Cert Authority", + "encryption_algorithm": "ECDSA", + "key_size": 256, + }, + { + "certificate_name": "ARISTA_ROOT_CA.crt", + "expiry_threshold": 30, + "common_name": "Arista Networks Internal IT Root Cert Authority", + "encryption_algorithm": "RSA", + "key_size": 4096, + }, + ] + }, + "expected": { + "result": "failure", + "messages": ["SSL certificate `ARISTA_SIGNING_CA.crt` is expired.\n", "SSL certificate `ARISTA_ROOT_CA.crt` is about to expire in 25 days."], + }, + }, + { + "name": "failure-wrong-subject-name", + "test": VerifyAPISSLCertificate, + "eos_data": [ + { + "certificates": { + "ARISTA_ROOT_CA.crt": { + "subject": {"commonName": "AristaIT-ICA Networks Internal IT Root Cert Authority"}, + "notAfter": 2127420899, + "publicKey": { + "encryptionAlgorithm": "RSA", + "size": 4096, + }, + }, + "ARISTA_SIGNING_CA.crt": { + "subject": {"commonName": "Arista ECDSA Issuing Cert Authority"}, + "notAfter": 2127420899, + "publicKey": { + "encryptionAlgorithm": "ECDSA", + "size": 256, + }, + }, + } + }, + { + "utcTime": 1702288467.6736515, + }, + ], + "inputs": { + "certificates": [ + { + "certificate_name": "ARISTA_SIGNING_CA.crt", + "expiry_threshold": 30, + "common_name": "AristaIT-ICA ECDSA Issuing Cert Authority", + "encryption_algorithm": "ECDSA", + "key_size": 256, + }, + { + "certificate_name": "ARISTA_ROOT_CA.crt", + "expiry_threshold": 30, + "common_name": "Arista Networks Internal IT Root Cert Authority", + "encryption_algorithm": "RSA", + "key_size": 4096, + }, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "SSL certificate `ARISTA_SIGNING_CA.crt` is not configured properly:\n" + "Expected `AristaIT-ICA ECDSA Issuing Cert Authority` as the subject.commonName, but found " + "`Arista ECDSA Issuing Cert Authority` instead.\n", + "SSL certificate `ARISTA_ROOT_CA.crt` is not configured properly:\n" + "Expected `Arista Networks Internal IT Root Cert Authority` as the subject.commonName, " + "but found `AristaIT-ICA Networks Internal IT Root Cert Authority` instead.\n", + ], + }, + }, + { + "name": "failure-wrong-encryption-type-and-size", + "test": VerifyAPISSLCertificate, + "eos_data": [ + { + "certificates": { + "ARISTA_ROOT_CA.crt": { + "subject": {"commonName": "Arista Networks Internal IT Root Cert Authority"}, + "notAfter": 2127420899, + "publicKey": { + "encryptionAlgorithm": "ECDSA", + "size": 256, + }, + }, + "ARISTA_SIGNING_CA.crt": { + "subject": {"commonName": "AristaIT-ICA ECDSA Issuing Cert Authority"}, + "notAfter": 2127420899, + "publicKey": { + "encryptionAlgorithm": "RSA", + "size": 4096, + }, + }, + } + }, + { + "utcTime": 1702288467.6736515, + }, + ], + "inputs": { + "certificates": [ + { + "certificate_name": "ARISTA_SIGNING_CA.crt", + "expiry_threshold": 30, + "common_name": "AristaIT-ICA ECDSA Issuing Cert Authority", + "encryption_algorithm": "ECDSA", + "key_size": 256, + }, + { + "certificate_name": "ARISTA_ROOT_CA.crt", + "expiry_threshold": 30, + "common_name": "Arista Networks Internal IT Root Cert Authority", + "encryption_algorithm": "RSA", + "key_size": 4096, + }, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "SSL certificate `ARISTA_SIGNING_CA.crt` is not configured properly:\n" + "Expected `ECDSA` as the publicKey.encryptionAlgorithm, but found `RSA` instead.\n" + "Expected `256` as the publicKey.size, but found `4096` instead.\n", + "SSL certificate `ARISTA_ROOT_CA.crt` is not configured properly:\n" + "Expected `RSA` as the publicKey.encryptionAlgorithm, but found `ECDSA` instead.\n" + "Expected `4096` as the publicKey.size, but found `256` instead.\n", + ], + }, + }, + { + "name": "failure-missing-actual-output", + "test": VerifyAPISSLCertificate, + "eos_data": [ + { + "certificates": { + "ARISTA_ROOT_CA.crt": { + "subject": {"commonName": "Arista Networks Internal IT Root Cert Authority"}, + "notAfter": 2127420899, + }, + "ARISTA_SIGNING_CA.crt": { + "subject": {"commonName": "AristaIT-ICA ECDSA Issuing Cert Authority"}, + "notAfter": 2127420899, + }, + } + }, + { + "utcTime": 1702288467.6736515, + }, + ], + "inputs": { + "certificates": [ + { + "certificate_name": "ARISTA_SIGNING_CA.crt", + "expiry_threshold": 30, + "common_name": "AristaIT-ICA ECDSA Issuing Cert Authority", + "encryption_algorithm": "ECDSA", + "key_size": 256, + }, + { + "certificate_name": "ARISTA_ROOT_CA.crt", + "expiry_threshold": 30, + "common_name": "Arista Networks Internal IT Root Cert Authority", + "encryption_algorithm": "RSA", + "key_size": 4096, + }, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "SSL certificate `ARISTA_SIGNING_CA.crt` is not configured properly:\n" + "Expected `ECDSA` as the publicKey.encryptionAlgorithm, but it was not found in the actual output.\n" + "Expected `256` as the publicKey.size, but it was not found in the actual output.\n", + "SSL certificate `ARISTA_ROOT_CA.crt` is not configured properly:\n" + "Expected `RSA` as the publicKey.encryptionAlgorithm, but it was not found in the actual output.\n" + "Expected `4096` as the publicKey.size, but it was not found in the actual output.\n", + ], + }, + }, + { + "name": "success", + "test": VerifyBannerLogin, + "eos_data": [ + { + "loginBanner": "Copyright (c) 2023-2024 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n" + "that can be found in the LICENSE file." + } + ], + "inputs": { + "login_banner": "Copyright (c) 2023-2024 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n" + "that can be found in the LICENSE file." + }, + "expected": {"result": "success"}, + }, + { + "name": "success-multiline", + "test": VerifyBannerLogin, + "eos_data": [ + { + "loginBanner": "Copyright (c) 2023-2024 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n" + "that can be found in the LICENSE file." + } + ], + "inputs": { + "login_banner": """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.""" + }, + "expected": {"result": "success"}, + }, + { + "name": "failure-incorrect-login-banner", + "test": VerifyBannerLogin, + "eos_data": [ + { + "loginBanner": "Copyright (c) 2023 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n" + "that can be found in the LICENSE file." + } + ], + "inputs": { + "login_banner": "Copyright (c) 2023-2024 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n" + "that can be found in the LICENSE file." + }, + "expected": { + "result": "failure", + "messages": [ + "Expected `Copyright (c) 2023-2024 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n" + "that can be found in the LICENSE file.` as the login banner, but found `Copyright (c) 2023 Arista Networks, Inc.\nUse of this source code is " + "governed by the Apache License 2.0\nthat can be found in the LICENSE file.` instead." + ], + }, + }, + { + "name": "success", + "test": VerifyBannerMotd, + "eos_data": [ + { + "motd": "Copyright (c) 2023-2024 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n" + "that can be found in the LICENSE file." + } + ], + "inputs": { + "motd_banner": "Copyright (c) 2023-2024 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n" + "that can be found in the LICENSE file." + }, + "expected": {"result": "success"}, + }, + { + "name": "success-multiline", + "test": VerifyBannerMotd, + "eos_data": [ + { + "motd": "Copyright (c) 2023-2024 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n" + "that can be found in the LICENSE file." + } + ], + "inputs": { + "motd_banner": """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.""" + }, + "expected": {"result": "success"}, + }, + { + "name": "failure-incorrect-motd-banner", + "test": VerifyBannerMotd, + "eos_data": [ + { + "motd": "Copyright (c) 2023 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n" + "that can be found in the LICENSE file." + } + ], + "inputs": { + "motd_banner": "Copyright (c) 2023-2024 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n" + "that can be found in the LICENSE file." + }, + "expected": { + "result": "failure", + "messages": [ + "Expected `Copyright (c) 2023-2024 Arista Networks, Inc.\nUse of this source code is governed by the Apache License 2.0\n" + "that can be found in the LICENSE file.` as the motd banner, but found `Copyright (c) 2023 Arista Networks, Inc.\nUse of this source code is " + "governed by the Apache License 2.0\nthat can be found in the LICENSE file.` instead." + ], + }, + }, + { + "name": "success", + "test": VerifyIPv4ACL, + "eos_data": [ + { + "aclList": [ + { + "sequence": [ + {"text": "permit icmp any any", "sequenceNumber": 10}, + {"text": "permit ip any any tracked", "sequenceNumber": 20}, + {"text": "permit udp any any eq bfd ttl eq 255", "sequenceNumber": 30}, + ], + } + ] + }, + { + "aclList": [ + { + "sequence": [ + {"text": "permit icmp any any", "sequenceNumber": 10}, + {"text": "permit tcp any any range 5900 5910", "sequenceNumber": 20}, + ], + } + ] + }, + ], + "inputs": { + "ipv4_access_lists": [ + { + "name": "default-control-plane-acl", + "entries": [ + {"sequence": 10, "action": "permit icmp any any"}, + {"sequence": 20, "action": "permit ip any any tracked"}, + {"sequence": 30, "action": "permit udp any any eq bfd ttl eq 255"}, + ], + }, + { + "name": "LabTest", + "entries": [{"sequence": 10, "action": "permit icmp any any"}, {"sequence": 20, "action": "permit tcp any any range 5900 5910"}], + }, + ] + }, + "expected": {"result": "success"}, + }, + { + "name": "failure-acl-not-found", + "test": VerifyIPv4ACL, + "eos_data": [ + { + "aclList": [ + { + "sequence": [ + {"text": "permit icmp any any", "sequenceNumber": 10}, + {"text": "permit ip any any tracked", "sequenceNumber": 20}, + {"text": "permit udp any any eq bfd ttl eq 255", "sequenceNumber": 30}, + ], + } + ] + }, + {"aclList": []}, + ], + "inputs": { + "ipv4_access_lists": [ + { + "name": "default-control-plane-acl", + "entries": [ + {"sequence": 10, "action": "permit icmp any any"}, + {"sequence": 20, "action": "permit ip any any tracked"}, + {"sequence": 30, "action": "permit udp any any eq bfd ttl eq 255"}, + ], + }, + { + "name": "LabTest", + "entries": [{"sequence": 10, "action": "permit icmp any any"}, {"sequence": 20, "action": "permit tcp any any range 5900 5910"}], + }, + ] + }, + "expected": {"result": "failure", "messages": ["LabTest: Not found"]}, + }, + { + "name": "failure-sequence-not-found", + "test": VerifyIPv4ACL, + "eos_data": [ + { + "aclList": [ + { + "sequence": [ + {"text": "permit icmp any any", "sequenceNumber": 10}, + {"text": "permit ip any any tracked", "sequenceNumber": 20}, + {"text": "permit udp any any eq bfd ttl eq 255", "sequenceNumber": 40}, + ], + } + ] + }, + { + "aclList": [ + { + "sequence": [ + {"text": "permit icmp any any", "sequenceNumber": 10}, + {"text": "permit tcp any any range 5900 5910", "sequenceNumber": 30}, + ], + } + ] + }, + ], + "inputs": { + "ipv4_access_lists": [ + { + "name": "default-control-plane-acl", + "entries": [ + {"sequence": 10, "action": "permit icmp any any"}, + {"sequence": 20, "action": "permit ip any any tracked"}, + {"sequence": 30, "action": "permit udp any any eq bfd ttl eq 255"}, + ], + }, + { + "name": "LabTest", + "entries": [{"sequence": 10, "action": "permit icmp any any"}, {"sequence": 20, "action": "permit tcp any any range 5900 5910"}], + }, + ] + }, + "expected": { + "result": "failure", + "messages": ["default-control-plane-acl:\nSequence number `30` is not found.\n", "LabTest:\nSequence number `20` is not found.\n"], + }, + }, + { + "name": "failure-action-not-match", + "test": VerifyIPv4ACL, + "eos_data": [ + { + "aclList": [ + { + "sequence": [ + {"text": "permit icmp any any", "sequenceNumber": 10}, + {"text": "permit ip any any tracked", "sequenceNumber": 20}, + {"text": "permit tcp any any range 5900 5910", "sequenceNumber": 30}, + ], + } + ] + }, + { + "aclList": [ + { + "sequence": [ + {"text": "permit icmp any any", "sequenceNumber": 10}, + {"text": "permit udp any any eq bfd ttl eq 255", "sequenceNumber": 20}, + ], + } + ] + }, + ], + "inputs": { + "ipv4_access_lists": [ + { + "name": "default-control-plane-acl", + "entries": [ + {"sequence": 10, "action": "permit icmp any any"}, + {"sequence": 20, "action": "permit ip any any tracked"}, + {"sequence": 30, "action": "permit udp any any eq bfd ttl eq 255"}, + ], + }, + { + "name": "LabTest", + "entries": [{"sequence": 10, "action": "permit icmp any any"}, {"sequence": 20, "action": "permit tcp any any range 5900 5910"}], + }, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "default-control-plane-acl:\n" + "Expected `permit udp any any eq bfd ttl eq 255` as sequence number 30 action but found `permit tcp any any range 5900 5910` instead.\n", + "LabTest:\nExpected `permit tcp any any range 5900 5910` as sequence number 20 action but found `permit udp any any eq bfd ttl eq 255` instead.\n", + ], + }, + }, + { + "name": "failure-all-type", + "test": VerifyIPv4ACL, + "eos_data": [ + { + "aclList": [ + { + "sequence": [ + {"text": "permit icmp any any", "sequenceNumber": 10}, + {"text": "permit ip any any tracked", "sequenceNumber": 40}, + {"text": "permit tcp any any range 5900 5910", "sequenceNumber": 30}, + ], + } + ] + }, + {"aclList": []}, + ], + "inputs": { + "ipv4_access_lists": [ + { + "name": "default-control-plane-acl", + "entries": [ + {"sequence": 10, "action": "permit icmp any any"}, + {"sequence": 20, "action": "permit ip any any tracked"}, + {"sequence": 30, "action": "permit udp any any eq bfd ttl eq 255"}, + ], + }, + { + "name": "LabTest", + "entries": [{"sequence": 10, "action": "permit icmp any any"}, {"sequence": 20, "action": "permit tcp any any range 5900 5910"}], + }, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "default-control-plane-acl:\nSequence number `20` is not found.\n" + "Expected `permit udp any any eq bfd ttl eq 255` as sequence number 30 action but found `permit tcp any any range 5900 5910` instead.\n", + "LabTest: Not found", + ], + }, + }, +] diff --git a/tests/units/anta_tests/test_services.py b/tests/units/anta_tests/test_services.py new file mode 100644 index 0000000..dcd1ee2 --- /dev/null +++ b/tests/units/anta_tests/test_services.py @@ -0,0 +1,218 @@ +# 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. +""" +Tests for anta.tests.services.py +""" +from __future__ import annotations + +from typing import Any + +from anta.tests.services import VerifyDNSLookup, VerifyDNSServers, VerifyErrdisableRecovery, VerifyHostname +from tests.lib.anta import test # noqa: F401; pylint: disable=W0611 + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifyHostname, + "eos_data": [{"hostname": "s1-spine1", "fqdn": "s1-spine1.fun.aristanetworks.com"}], + "inputs": {"hostname": "s1-spine1"}, + "expected": {"result": "success"}, + }, + { + "name": "failure-incorrect-hostname", + "test": VerifyHostname, + "eos_data": [{"hostname": "s1-spine2", "fqdn": "s1-spine1.fun.aristanetworks.com"}], + "inputs": {"hostname": "s1-spine1"}, + "expected": { + "result": "failure", + "messages": ["Expected `s1-spine1` as the hostname, but found `s1-spine2` instead."], + }, + }, + { + "name": "success", + "test": VerifyDNSLookup, + "eos_data": [ + { + "messages": [ + "Server:\t\t127.0.0.1\nAddress:\t127.0.0.1#53\n\nNon-authoritative answer:\nName:\tarista.com\nAddress: 151.101.130.132\nName:\tarista.com\n" + "Address: 151.101.2.132\nName:\tarista.com\nAddress: 151.101.194.132\nName:\tarista.com\nAddress: 151.101.66.132\n\n" + ] + }, + {"messages": ["Server:\t\t127.0.0.1\nAddress:\t127.0.0.1#53\n\nNon-authoritative answer:\nName:\twww.google.com\nAddress: 172.217.12.100\n\n"]}, + ], + "inputs": {"domain_names": ["arista.com", "www.google.com"]}, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyDNSLookup, + "eos_data": [ + {"messages": ["Server:\t\t127.0.0.1\nAddress:\t127.0.0.1#53\n\nNon-authoritative answer:\n*** Can't find arista.ca: No answer\n\n"]}, + {"messages": ["Server:\t\t127.0.0.1\nAddress:\t127.0.0.1#53\n\nNon-authoritative answer:\nName:\twww.google.com\nAddress: 172.217.12.100\n\n"]}, + {"messages": ["Server:\t\t127.0.0.1\nAddress:\t127.0.0.1#53\n\nNon-authoritative answer:\n*** Can't find google.ca: No answer\n\n"]}, + ], + "inputs": {"domain_names": ["arista.ca", "www.google.com", "google.ca"]}, + "expected": {"result": "failure", "messages": ["The following domain(s) are not resolved to an IP address: arista.ca, google.ca"]}, + }, + { + "name": "success", + "test": VerifyDNSServers, + "eos_data": [ + { + "nameServerConfigs": [{"ipAddr": "10.14.0.1", "vrf": "default", "priority": 0}, {"ipAddr": "10.14.0.11", "vrf": "MGMT", "priority": 1}], + } + ], + "inputs": { + "dns_servers": [{"server_address": "10.14.0.1", "vrf": "default", "priority": 0}, {"server_address": "10.14.0.11", "vrf": "MGMT", "priority": 1}] + }, + "expected": {"result": "success"}, + }, + { + "name": "failure-dns-missing", + "test": VerifyDNSServers, + "eos_data": [ + { + "nameServerConfigs": [{"ipAddr": "10.14.0.1", "vrf": "default", "priority": 0}, {"ipAddr": "10.14.0.11", "vrf": "MGMT", "priority": 1}], + } + ], + "inputs": { + "dns_servers": [{"server_address": "10.14.0.10", "vrf": "default", "priority": 0}, {"server_address": "10.14.0.21", "vrf": "MGMT", "priority": 1}] + }, + "expected": { + "result": "failure", + "messages": ["DNS server `10.14.0.10` is not configured with any VRF.", "DNS server `10.14.0.21` is not configured with any VRF."], + }, + }, + { + "name": "failure-no-dns-found", + "test": VerifyDNSServers, + "eos_data": [ + { + "nameServerConfigs": [], + } + ], + "inputs": { + "dns_servers": [{"server_address": "10.14.0.10", "vrf": "default", "priority": 0}, {"server_address": "10.14.0.21", "vrf": "MGMT", "priority": 1}] + }, + "expected": { + "result": "failure", + "messages": ["DNS server `10.14.0.10` is not configured with any VRF.", "DNS server `10.14.0.21` is not configured with any VRF."], + }, + }, + { + "name": "failure-incorrect-dns-details", + "test": VerifyDNSServers, + "eos_data": [ + { + "nameServerConfigs": [{"ipAddr": "10.14.0.1", "vrf": "CS", "priority": 1}, {"ipAddr": "10.14.0.11", "vrf": "MGMT", "priority": 1}], + } + ], + "inputs": { + "dns_servers": [ + {"server_address": "10.14.0.1", "vrf": "CS", "priority": 0}, + {"server_address": "10.14.0.11", "vrf": "default", "priority": 0}, + {"server_address": "10.14.0.110", "vrf": "MGMT", "priority": 0}, + ] + }, + "expected": { + "result": "failure", + "messages": [ + "For DNS server `10.14.0.1`, the expected priority is `0`, but `1` was found instead.", + "DNS server `10.14.0.11` is not configured with VRF `default`.", + "DNS server `10.14.0.110` is not configured with any VRF.", + ], + }, + }, + { + "name": "success", + "test": VerifyErrdisableRecovery, + "eos_data": [ + """ + Errdisable Reason Timer Status Timer Interval + ------------------------------ ----------------- -------------- + acl Enabled 300 + bpduguard Enabled 300 + arp-inspection Enabled 30 + """ + ], + "inputs": {"reasons": [{"reason": "acl", "interval": 300}, {"reason": "bpduguard", "interval": 300}]}, + "expected": {"result": "success"}, + }, + { + "name": "failure-reason-missing", + "test": VerifyErrdisableRecovery, + "eos_data": [ + """ + Errdisable Reason Timer Status Timer Interval + ------------------------------ ----------------- -------------- + acl Enabled 300 + bpduguard Enabled 300 + arp-inspection Enabled 30 + """ + ], + "inputs": {"reasons": [{"reason": "acl", "interval": 300}, {"reason": "arp-inspection", "interval": 30}, {"reason": "tapagg", "interval": 30}]}, + "expected": { + "result": "failure", + "messages": ["`tapagg`: Not found."], + }, + }, + { + "name": "failure-reason-disabled", + "test": VerifyErrdisableRecovery, + "eos_data": [ + """ + Errdisable Reason Timer Status Timer Interval + ------------------------------ ----------------- -------------- + acl Disabled 300 + bpduguard Enabled 300 + arp-inspection Enabled 30 + """ + ], + "inputs": {"reasons": [{"reason": "acl", "interval": 300}, {"reason": "arp-inspection", "interval": 30}]}, + "expected": { + "result": "failure", + "messages": ["`acl`:\nExpected `Enabled` as the status, but found `Disabled` instead."], + }, + }, + { + "name": "failure-interval-not-ok", + "test": VerifyErrdisableRecovery, + "eos_data": [ + """ + Errdisable Reason Timer Status Timer Interval + ------------------------------ ----------------- -------------- + acl Enabled 300 + bpduguard Enabled 300 + arp-inspection Enabled 30 + """ + ], + "inputs": {"reasons": [{"reason": "acl", "interval": 30}, {"reason": "arp-inspection", "interval": 30}]}, + "expected": { + "result": "failure", + "messages": ["`acl`:\nExpected `30` as the interval, but found `300` instead."], + }, + }, + { + "name": "failure-all-type", + "test": VerifyErrdisableRecovery, + "eos_data": [ + """ + Errdisable Reason Timer Status Timer Interval + ------------------------------ ----------------- -------------- + acl Disabled 300 + bpduguard Enabled 300 + arp-inspection Enabled 30 + """ + ], + "inputs": {"reasons": [{"reason": "acl", "interval": 30}, {"reason": "arp-inspection", "interval": 300}, {"reason": "tapagg", "interval": 30}]}, + "expected": { + "result": "failure", + "messages": [ + "`acl`:\nExpected `30` as the interval, but found `300` instead.\nExpected `Enabled` as the status, but found `Disabled` instead.", + "`arp-inspection`:\nExpected `300` as the interval, but found `30` instead.", + "`tapagg`: Not found.", + ], + }, + }, +] diff --git a/tests/units/anta_tests/test_snmp.py b/tests/units/anta_tests/test_snmp.py new file mode 100644 index 0000000..7009689 --- /dev/null +++ b/tests/units/anta_tests/test_snmp.py @@ -0,0 +1,128 @@ +# 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. +""" +Tests for anta.tests.snmp.py +""" +from __future__ import annotations + +from typing import Any + +from anta.tests.snmp import VerifySnmpContact, VerifySnmpIPv4Acl, VerifySnmpIPv6Acl, VerifySnmpLocation, VerifySnmpStatus +from tests.lib.anta import test # noqa: F401; pylint: disable=W0611 + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifySnmpStatus, + "eos_data": [{"vrfs": {"snmpVrfs": ["MGMT", "default"]}, "enabled": True}], + "inputs": {"vrf": "MGMT"}, + "expected": {"result": "success"}, + }, + { + "name": "failure-wrong-vrf", + "test": VerifySnmpStatus, + "eos_data": [{"vrfs": {"snmpVrfs": ["default"]}, "enabled": True}], + "inputs": {"vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["SNMP agent disabled in vrf MGMT"]}, + }, + { + "name": "failure-disabled", + "test": VerifySnmpStatus, + "eos_data": [{"vrfs": {"snmpVrfs": ["default"]}, "enabled": False}], + "inputs": {"vrf": "default"}, + "expected": {"result": "failure", "messages": ["SNMP agent disabled in vrf default"]}, + }, + { + "name": "success", + "test": VerifySnmpIPv4Acl, + "eos_data": [{"ipAclList": {"aclList": [{"type": "Ip4Acl", "name": "ACL_IPV4_SNMP", "configuredVrfs": ["MGMT"], "activeVrfs": ["MGMT"]}]}}], + "inputs": {"number": 1, "vrf": "MGMT"}, + "expected": {"result": "success"}, + }, + { + "name": "failure-wrong-number", + "test": VerifySnmpIPv4Acl, + "eos_data": [{"ipAclList": {"aclList": []}}], + "inputs": {"number": 1, "vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["Expected 1 SNMP IPv4 ACL(s) in vrf MGMT but got 0"]}, + }, + { + "name": "failure-wrong-vrf", + "test": VerifySnmpIPv4Acl, + "eos_data": [{"ipAclList": {"aclList": [{"type": "Ip4Acl", "name": "ACL_IPV4_SNMP", "configuredVrfs": ["default"], "activeVrfs": ["default"]}]}}], + "inputs": {"number": 1, "vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["SNMP IPv4 ACL(s) not configured or active in vrf MGMT: ['ACL_IPV4_SNMP']"]}, + }, + { + "name": "success", + "test": VerifySnmpIPv6Acl, + "eos_data": [{"ipv6AclList": {"aclList": [{"type": "Ip6Acl", "name": "ACL_IPV6_SNMP", "configuredVrfs": ["MGMT"], "activeVrfs": ["MGMT"]}]}}], + "inputs": {"number": 1, "vrf": "MGMT"}, + "expected": {"result": "success"}, + }, + { + "name": "failure-wrong-number", + "test": VerifySnmpIPv6Acl, + "eos_data": [{"ipv6AclList": {"aclList": []}}], + "inputs": {"number": 1, "vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["Expected 1 SNMP IPv6 ACL(s) in vrf MGMT but got 0"]}, + }, + { + "name": "failure-wrong-vrf", + "test": VerifySnmpIPv6Acl, + "eos_data": [{"ipv6AclList": {"aclList": [{"type": "Ip6Acl", "name": "ACL_IPV6_SNMP", "configuredVrfs": ["default"], "activeVrfs": ["default"]}]}}], + "inputs": {"number": 1, "vrf": "MGMT"}, + "expected": {"result": "failure", "messages": ["SNMP IPv6 ACL(s) not configured or active in vrf MGMT: ['ACL_IPV6_SNMP']"]}, + }, + { + "name": "success", + "test": VerifySnmpLocation, + "eos_data": [ + { + "location": {"location": "New York"}, + } + ], + "inputs": {"location": "New York"}, + "expected": {"result": "success"}, + }, + { + "name": "failure-incorrect-location", + "test": VerifySnmpLocation, + "eos_data": [ + { + "location": {"location": "Europe"}, + } + ], + "inputs": {"location": "New York"}, + "expected": { + "result": "failure", + "messages": ["Expected `New York` as the location, but found `Europe` instead."], + }, + }, + { + "name": "success", + "test": VerifySnmpContact, + "eos_data": [ + { + "contact": {"contact": "Jon@example.com"}, + } + ], + "inputs": {"contact": "Jon@example.com"}, + "expected": {"result": "success"}, + }, + { + "name": "failure-incorrect-contact", + "test": VerifySnmpContact, + "eos_data": [ + { + "contact": {"contact": "Jon@example.com"}, + } + ], + "inputs": {"contact": "Bob@example.com"}, + "expected": { + "result": "failure", + "messages": ["Expected `Bob@example.com` as the contact, but found `Jon@example.com` instead."], + }, + }, +] diff --git a/tests/units/anta_tests/test_software.py b/tests/units/anta_tests/test_software.py new file mode 100644 index 0000000..6d39c04 --- /dev/null +++ b/tests/units/anta_tests/test_software.py @@ -0,0 +1,101 @@ +# 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. +"""Test inputs for anta.tests.hardware""" +from __future__ import annotations + +from typing import Any + +from anta.tests.software import VerifyEOSExtensions, VerifyEOSVersion, VerifyTerminAttrVersion +from tests.lib.anta import test # noqa: F401; pylint: disable=W0611 + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifyEOSVersion, + "eos_data": [ + { + "modelName": "vEOS-lab", + "internalVersion": "4.27.0F-24305004.4270F", + "version": "4.27.0F", + } + ], + "inputs": {"versions": ["4.27.0F", "4.28.0F"]}, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyEOSVersion, + "eos_data": [ + { + "modelName": "vEOS-lab", + "internalVersion": "4.27.0F-24305004.4270F", + "version": "4.27.0F", + } + ], + "inputs": {"versions": ["4.27.1F"]}, + "expected": {"result": "failure", "messages": ["device is running version \"4.27.0F\" not in expected versions: ['4.27.1F']"]}, + }, + { + "name": "success", + "test": VerifyTerminAttrVersion, + "eos_data": [ + { + "imageFormatVersion": "1.0", + "uptime": 1107543.52, + "modelName": "vEOS-lab", + "details": { + "deviations": [], + "components": [{"name": "Aboot", "version": "Aboot-veos-8.0.0-3255441"}], + "switchType": "fixedSystem", + "packages": { + "TerminAttr-core": {"release": "1", "version": "v1.17.0"}, + }, + }, + } + ], + "inputs": {"versions": ["v1.17.0", "v1.18.1"]}, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyTerminAttrVersion, + "eos_data": [ + { + "imageFormatVersion": "1.0", + "uptime": 1107543.52, + "modelName": "vEOS-lab", + "details": { + "deviations": [], + "components": [{"name": "Aboot", "version": "Aboot-veos-8.0.0-3255441"}], + "switchType": "fixedSystem", + "packages": { + "TerminAttr-core": {"release": "1", "version": "v1.17.0"}, + }, + }, + } + ], + "inputs": {"versions": ["v1.17.1", "v1.18.1"]}, + "expected": {"result": "failure", "messages": ["device is running TerminAttr version v1.17.0 and is not in the allowed list: ['v1.17.1', 'v1.18.1']"]}, + }, + { + "name": "success-no-extensions", + "test": VerifyEOSExtensions, + "eos_data": [ + {"extensions": {}, "extensionStoredDir": "flash:", "warnings": ["No extensions are available"]}, + {"extensions": []}, + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyEOSExtensions, + "eos_data": [ + {"extensions": {}, "extensionStoredDir": "flash:", "warnings": ["No extensions are available"]}, + {"extensions": ["dummy"]}, + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["Missing EOS extensions: installed [] / configured: ['dummy']"]}, + }, +] diff --git a/tests/units/anta_tests/test_stp.py b/tests/units/anta_tests/test_stp.py new file mode 100644 index 0000000..26f0b90 --- /dev/null +++ b/tests/units/anta_tests/test_stp.py @@ -0,0 +1,328 @@ +# 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. +""" +Tests for anta.tests.stp.py +""" +from __future__ import annotations + +from typing import Any + +from anta.tests.stp import VerifySTPBlockedPorts, VerifySTPCounters, VerifySTPForwardingPorts, VerifySTPMode, VerifySTPRootPriority +from tests.lib.anta import test # noqa: F401; pylint: disable=W0611 + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifySTPMode, + "eos_data": [ + {"spanningTreeVlanInstances": {"10": {"spanningTreeVlanInstance": {"protocol": "rstp"}}}}, + {"spanningTreeVlanInstances": {"20": {"spanningTreeVlanInstance": {"protocol": "rstp"}}}}, + ], + "inputs": {"mode": "rstp", "vlans": [10, 20]}, + "expected": {"result": "success"}, + }, + { + "name": "failure-no-instances", + "test": VerifySTPMode, + "eos_data": [ + {"spanningTreeVlanInstances": {}}, + {"spanningTreeVlanInstances": {}}, + ], + "inputs": {"mode": "rstp", "vlans": [10, 20]}, + "expected": {"result": "failure", "messages": ["STP mode 'rstp' not configured for the following VLAN(s): [10, 20]"]}, + }, + { + "name": "failure-wrong-mode", + "test": VerifySTPMode, + "eos_data": [ + {"spanningTreeVlanInstances": {"10": {"spanningTreeVlanInstance": {"protocol": "mstp"}}}}, + {"spanningTreeVlanInstances": {"20": {"spanningTreeVlanInstance": {"protocol": "mstp"}}}}, + ], + "inputs": {"mode": "rstp", "vlans": [10, 20]}, + "expected": {"result": "failure", "messages": ["Wrong STP mode configured for the following VLAN(s): [10, 20]"]}, + }, + { + "name": "failure-both", + "test": VerifySTPMode, + "eos_data": [ + {"spanningTreeVlanInstances": {}}, + {"spanningTreeVlanInstances": {"20": {"spanningTreeVlanInstance": {"protocol": "mstp"}}}}, + ], + "inputs": {"mode": "rstp", "vlans": [10, 20]}, + "expected": { + "result": "failure", + "messages": ["STP mode 'rstp' not configured for the following VLAN(s): [10]", "Wrong STP mode configured for the following VLAN(s): [20]"], + }, + }, + { + "name": "success", + "test": VerifySTPBlockedPorts, + "eos_data": [{"spanningTreeInstances": {}}], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifySTPBlockedPorts, + "eos_data": [{"spanningTreeInstances": {"MST0": {"spanningTreeBlockedPorts": ["Ethernet10"]}, "MST10": {"spanningTreeBlockedPorts": ["Ethernet10"]}}}], + "inputs": None, + "expected": {"result": "failure", "messages": ["The following ports are blocked by STP: {'MST0': ['Ethernet10'], 'MST10': ['Ethernet10']}"]}, + }, + { + "name": "success", + "test": VerifySTPCounters, + "eos_data": [{"interfaces": {"Ethernet10": {"bpduSent": 99, "bpduReceived": 0, "bpduTaggedError": 0, "bpduOtherError": 0, "bpduRateLimitCount": 0}}}], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifySTPCounters, + "eos_data": [ + { + "interfaces": { + "Ethernet10": {"bpduSent": 201, "bpduReceived": 0, "bpduTaggedError": 3, "bpduOtherError": 0, "bpduRateLimitCount": 0}, + "Ethernet11": {"bpduSent": 99, "bpduReceived": 0, "bpduTaggedError": 0, "bpduOtherError": 6, "bpduRateLimitCount": 0}, + } + } + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["The following interfaces have STP BPDU packet errors: ['Ethernet10', 'Ethernet11']"]}, + }, + { + "name": "success", + "test": VerifySTPForwardingPorts, + "eos_data": [ + { + "unmappedVlans": [], + "topologies": {"Mst10": {"vlans": [10], "interfaces": {"Ethernet10": {"state": "forwarding"}, "MplsTrunk1": {"state": "forwarding"}}}}, + }, + { + "unmappedVlans": [], + "topologies": {"Mst20": {"vlans": [20], "interfaces": {"Ethernet10": {"state": "forwarding"}, "MplsTrunk1": {"state": "forwarding"}}}}, + }, + ], + "inputs": {"vlans": [10, 20]}, + "expected": {"result": "success"}, + }, + { + "name": "success-vlan-not-in-topology", # Should it succeed really ? TODO - this output should be impossible + "test": VerifySTPForwardingPorts, + "eos_data": [ + { + "unmappedVlans": [], + "topologies": {"Mst10": {"vlans": [10], "interfaces": {"Ethernet10": {"state": "forwarding"}, "MplsTrunk1": {"state": "forwarding"}}}}, + }, + { + "unmappedVlans": [], + "topologies": {"Mst10": {"vlans": [10], "interfaces": {"Ethernet10": {"state": "forwarding"}, "MplsTrunk1": {"state": "forwarding"}}}}, + }, + ], + "inputs": {"vlans": [10, 20]}, + "expected": {"result": "success"}, + }, + { + "name": "failure-no-instances", + "test": VerifySTPForwardingPorts, + "eos_data": [{"unmappedVlans": [], "topologies": {}}, {"unmappedVlans": [], "topologies": {}}], + "inputs": {"vlans": [10, 20]}, + "expected": {"result": "failure", "messages": ["STP instance is not configured for the following VLAN(s): [10, 20]"]}, + }, + { + "name": "failure", + "test": VerifySTPForwardingPorts, + "eos_data": [ + { + "unmappedVlans": [], + "topologies": {"Vl10": {"vlans": [10], "interfaces": {"Ethernet10": {"state": "discarding"}, "MplsTrunk1": {"state": "forwarding"}}}}, + }, + { + "unmappedVlans": [], + "topologies": {"Vl20": {"vlans": [20], "interfaces": {"Ethernet10": {"state": "discarding"}, "MplsTrunk1": {"state": "forwarding"}}}}, + }, + ], + "inputs": {"vlans": [10, 20]}, + "expected": { + "result": "failure", + "messages": ["The following VLAN(s) have interface(s) that are not in a fowarding state: [{'VLAN 10': ['Ethernet10']}, {'VLAN 20': ['Ethernet10']}]"], + }, + }, + { + "name": "success-specific-instances", + "test": VerifySTPRootPriority, + "eos_data": [ + { + "instances": { + "VL10": { + "rootBridge": { + "priority": 32768, + "systemIdExtension": 10, + "macAddress": "00:1c:73:27:95:a2", + "helloTime": 2.0, + "maxAge": 20, + "forwardDelay": 15, + } + }, + "VL20": { + "rootBridge": { + "priority": 32768, + "systemIdExtension": 20, + "macAddress": "00:1c:73:27:95:a2", + "helloTime": 2.0, + "maxAge": 20, + "forwardDelay": 15, + } + }, + "VL30": { + "rootBridge": { + "priority": 32768, + "systemIdExtension": 30, + "macAddress": "00:1c:73:27:95:a2", + "helloTime": 2.0, + "maxAge": 20, + "forwardDelay": 15, + } + }, + } + } + ], + "inputs": {"priority": 32768, "instances": [10, 20]}, + "expected": {"result": "success"}, + }, + { + "name": "success-all-instances", + "test": VerifySTPRootPriority, + "eos_data": [ + { + "instances": { + "VL10": { + "rootBridge": { + "priority": 32768, + "systemIdExtension": 10, + "macAddress": "00:1c:73:27:95:a2", + "helloTime": 2.0, + "maxAge": 20, + "forwardDelay": 15, + } + }, + "VL20": { + "rootBridge": { + "priority": 32768, + "systemIdExtension": 20, + "macAddress": "00:1c:73:27:95:a2", + "helloTime": 2.0, + "maxAge": 20, + "forwardDelay": 15, + } + }, + "VL30": { + "rootBridge": { + "priority": 32768, + "systemIdExtension": 30, + "macAddress": "00:1c:73:27:95:a2", + "helloTime": 2.0, + "maxAge": 20, + "forwardDelay": 15, + } + }, + } + } + ], + "inputs": {"priority": 32768}, + "expected": {"result": "success"}, + }, + { + "name": "success-MST", + "test": VerifySTPRootPriority, + "eos_data": [ + { + "instances": { + "MST0": { + "rootBridge": { + "priority": 16384, + "systemIdExtension": 0, + "macAddress": "02:1c:73:8b:93:ac", + "helloTime": 2.0, + "maxAge": 20, + "forwardDelay": 15, + } + } + } + } + ], + "inputs": {"priority": 16384, "instances": [0]}, + "expected": {"result": "success"}, + }, + { + "name": "failure-no-instances", + "test": VerifySTPRootPriority, + "eos_data": [ + { + "instances": { + "WRONG0": { + "rootBridge": { + "priority": 16384, + "systemIdExtension": 0, + "macAddress": "02:1c:73:8b:93:ac", + "helloTime": 2.0, + "maxAge": 20, + "forwardDelay": 15, + } + } + } + } + ], + "inputs": {"priority": 32768, "instances": [0]}, + "expected": {"result": "failure", "messages": ["Unsupported STP instance type: WRONG0"]}, + }, + { + "name": "failure-wrong-instance-type", + "test": VerifySTPRootPriority, + "eos_data": [{"instances": {}}], + "inputs": {"priority": 32768, "instances": [10, 20]}, + "expected": {"result": "failure", "messages": ["No STP instances configured"]}, + }, + { + "name": "failure-wrong-priority", + "test": VerifySTPRootPriority, + "eos_data": [ + { + "instances": { + "VL10": { + "rootBridge": { + "priority": 32768, + "systemIdExtension": 10, + "macAddress": "00:1c:73:27:95:a2", + "helloTime": 2.0, + "maxAge": 20, + "forwardDelay": 15, + } + }, + "VL20": { + "rootBridge": { + "priority": 8196, + "systemIdExtension": 20, + "macAddress": "00:1c:73:27:95:a2", + "helloTime": 2.0, + "maxAge": 20, + "forwardDelay": 15, + } + }, + "VL30": { + "rootBridge": { + "priority": 8196, + "systemIdExtension": 30, + "macAddress": "00:1c:73:27:95:a2", + "helloTime": 2.0, + "maxAge": 20, + "forwardDelay": 15, + } + }, + } + } + ], + "inputs": {"priority": 32768, "instances": [10, 20, 30]}, + "expected": {"result": "failure", "messages": ["The following instance(s) have the wrong STP root priority configured: ['VL20', 'VL30']"]}, + }, +] diff --git a/tests/units/anta_tests/test_system.py b/tests/units/anta_tests/test_system.py new file mode 100644 index 0000000..62260fa --- /dev/null +++ b/tests/units/anta_tests/test_system.py @@ -0,0 +1,283 @@ +# 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. +"""Test inputs for anta.tests.system""" +from __future__ import annotations + +from typing import Any + +from anta.tests.system import ( + VerifyAgentLogs, + VerifyCoredump, + VerifyCPUUtilization, + VerifyFileSystemUtilization, + VerifyMemoryUtilization, + VerifyNTP, + VerifyReloadCause, + VerifyUptime, +) +from tests.lib.anta import test # noqa: F401; pylint: disable=W0611 + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifyUptime, + "eos_data": [{"upTime": 1186689.15, "loadAvg": [0.13, 0.12, 0.09], "users": 1, "currentTime": 1683186659.139859}], + "inputs": {"minimum": 666}, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyUptime, + "eos_data": [{"upTime": 665.15, "loadAvg": [0.13, 0.12, 0.09], "users": 1, "currentTime": 1683186659.139859}], + "inputs": {"minimum": 666}, + "expected": {"result": "failure", "messages": ["Device uptime is 665.15 seconds"]}, + }, + { + "name": "success-no-reload", + "test": VerifyReloadCause, + "eos_data": [{"kernelCrashData": [], "resetCauses": [], "full": False}], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "success-valid-cause", + "test": VerifyReloadCause, + "eos_data": [ + { + "resetCauses": [ + {"recommendedAction": "No action necessary.", "description": "Reload requested by the user.", "timestamp": 1683186892.0, "debugInfoIsDir": False} + ], + "full": False, + } + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyReloadCause, + # The failure cause is made up + "eos_data": [ + { + "resetCauses": [ + {"recommendedAction": "No action necessary.", "description": "Reload after crash.", "timestamp": 1683186892.0, "debugInfoIsDir": False} + ], + "full": False, + } + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["Reload cause is: 'Reload after crash.'"]}, + }, + { + "name": "error", + "test": VerifyReloadCause, + "eos_data": [{}], + "inputs": None, + "expected": {"result": "error", "messages": ["No reload causes available"]}, + }, + { + "name": "success-without-minidump", + "test": VerifyCoredump, + "eos_data": [{"mode": "compressedDeferred", "coreFiles": []}], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "success-with-minidump", + "test": VerifyCoredump, + "eos_data": [{"mode": "compressedDeferred", "coreFiles": ["minidump"]}], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure-without-minidump", + "test": VerifyCoredump, + "eos_data": [{"mode": "compressedDeferred", "coreFiles": ["core.2344.1584483862.Mlag.gz", "core.23101.1584483867.Mlag.gz"]}], + "inputs": None, + "expected": {"result": "failure", "messages": ["Core dump(s) have been found: ['core.2344.1584483862.Mlag.gz', 'core.23101.1584483867.Mlag.gz']"]}, + }, + { + "name": "failure-with-minidump", + "test": VerifyCoredump, + "eos_data": [{"mode": "compressedDeferred", "coreFiles": ["minidump", "core.2344.1584483862.Mlag.gz", "core.23101.1584483867.Mlag.gz"]}], + "inputs": None, + "expected": {"result": "failure", "messages": ["Core dump(s) have been found: ['core.2344.1584483862.Mlag.gz', 'core.23101.1584483867.Mlag.gz']"]}, + }, + { + "name": "success", + "test": VerifyAgentLogs, + "eos_data": [""], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyAgentLogs, + "eos_data": [ + """===> /var/log/agents/Test-666 Thu May 4 09:57:02 2023 <=== +CLI Exception: Exception +CLI Exception: Backtrace +===> /var/log/agents/Aaa-855 Fri Jul 7 15:07:00 2023 <=== +===== Output from /usr/bin/Aaa [] (PID=855) started Jul 7 15:06:11.606414 === +EntityManager::doBackoff waiting for remote sysdb version ....ok + +===> /var/log/agents/Acl-830 Fri Jul 7 15:07:00 2023 <=== +===== Output from /usr/bin/Acl [] (PID=830) started Jul 7 15:06:10.871700 === +EntityManager::doBackoff waiting for remote sysdb version ...................ok +""" + ], + "inputs": None, + "expected": { + "result": "failure", + "messages": [ + "Device has reported agent crashes:\n" + " * /var/log/agents/Test-666 Thu May 4 09:57:02 2023\n" + " * /var/log/agents/Aaa-855 Fri Jul 7 15:07:00 2023\n" + " * /var/log/agents/Acl-830 Fri Jul 7 15:07:00 2023", + ], + }, + }, + { + "name": "success", + "test": VerifyCPUUtilization, + "eos_data": [ + { + "cpuInfo": {"%Cpu(s)": {"idle": 88.2, "stolen": 0.0, "user": 5.9, "swIrq": 0.0, "ioWait": 0.0, "system": 0.0, "hwIrq": 5.9, "nice": 0.0}}, + "processes": { + "1": { + "userName": "root", + "status": "S", + "memPct": 0.3, + "niceValue": 0, + "cpuPct": 0.0, + "cpuPctType": "{:.1f}", + "cmd": "systemd", + "residentMem": "5096", + "priority": "20", + "activeTime": 360, + "virtMem": "6644", + "sharedMem": "3996", + } + }, + } + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyCPUUtilization, + "eos_data": [ + { + "cpuInfo": {"%Cpu(s)": {"idle": 24.8, "stolen": 0.0, "user": 5.9, "swIrq": 0.0, "ioWait": 0.0, "system": 0.0, "hwIrq": 5.9, "nice": 0.0}}, + "processes": { + "1": { + "userName": "root", + "status": "S", + "memPct": 0.3, + "niceValue": 0, + "cpuPct": 0.0, + "cpuPctType": "{:.1f}", + "cmd": "systemd", + "residentMem": "5096", + "priority": "20", + "activeTime": 360, + "virtMem": "6644", + "sharedMem": "3996", + } + }, + } + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["Device has reported a high CPU utilization: 75.2%"]}, + }, + { + "name": "success", + "test": VerifyMemoryUtilization, + "eos_data": [ + { + "uptime": 1994.67, + "modelName": "vEOS-lab", + "internalVersion": "4.27.3F-26379303.4273F", + "memTotal": 2004568, + "memFree": 879004, + "version": "4.27.3F", + } + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyMemoryUtilization, + "eos_data": [ + { + "uptime": 1994.67, + "modelName": "vEOS-lab", + "internalVersion": "4.27.3F-26379303.4273F", + "memTotal": 2004568, + "memFree": 89004, + "version": "4.27.3F", + } + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["Device has reported a high memory usage: 95.56%"]}, + }, + { + "name": "success", + "test": VerifyFileSystemUtilization, + "eos_data": [ + """Filesystem Size Used Avail Use% Mounted on +/dev/sda2 3.9G 988M 2.9G 26% /mnt/flash +none 294M 78M 217M 27% / +none 294M 78M 217M 27% /.overlay +/dev/loop0 461M 461M 0 100% /rootfs-i386 +""" + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyFileSystemUtilization, + "eos_data": [ + """Filesystem Size Used Avail Use% Mounted on +/dev/sda2 3.9G 988M 2.9G 84% /mnt/flash +none 294M 78M 217M 27% / +none 294M 78M 217M 84% /.overlay +/dev/loop0 461M 461M 0 100% /rootfs-i386 +""" + ], + "inputs": None, + "expected": { + "result": "failure", + "messages": [ + "Mount point /dev/sda2 3.9G 988M 2.9G 84% /mnt/flash is higher than 75%: reported 84%", + "Mount point none 294M 78M 217M 84% /.overlay is higher than 75%: reported 84%", + ], + }, + }, + { + "name": "success", + "test": VerifyNTP, + "eos_data": [ + """synchronised +poll interval unknown +""" + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyNTP, + "eos_data": [ + """unsynchronised +poll interval unknown +""" + ], + "inputs": None, + "expected": {"result": "failure", "messages": ["The device is not synchronized with the configured NTP server(s): 'unsynchronised'"]}, + }, +] diff --git a/tests/units/anta_tests/test_vlan.py b/tests/units/anta_tests/test_vlan.py new file mode 100644 index 0000000..93398f6 --- /dev/null +++ b/tests/units/anta_tests/test_vlan.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. +""" +Tests for anta.tests.vlan.py +""" +from __future__ import annotations + +from typing import Any + +from anta.tests.vlan import VerifyVlanInternalPolicy +from tests.lib.anta import test # noqa: F401; pylint: disable=W0611 + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifyVlanInternalPolicy, + "eos_data": [{"policy": "ascending", "startVlanId": 1006, "endVlanId": 4094}], + "inputs": {"policy": "ascending", "start_vlan_id": 1006, "end_vlan_id": 4094}, + "expected": {"result": "success"}, + }, + { + "name": "failure-incorrect-policy", + "test": VerifyVlanInternalPolicy, + "eos_data": [{"policy": "descending", "startVlanId": 4094, "endVlanId": 1006}], + "inputs": {"policy": "ascending", "start_vlan_id": 1006, "end_vlan_id": 4094}, + "expected": { + "result": "failure", + "messages": [ + "The VLAN internal allocation policy is not configured properly:\n" + "Expected `ascending` as the policy, but found `descending` instead.\n" + "Expected `1006` as the startVlanId, but found `4094` instead.\n" + "Expected `4094` as the endVlanId, but found `1006` instead." + ], + }, + }, +] diff --git a/tests/units/anta_tests/test_vxlan.py b/tests/units/anta_tests/test_vxlan.py new file mode 100644 index 0000000..2a9a875 --- /dev/null +++ b/tests/units/anta_tests/test_vxlan.py @@ -0,0 +1,365 @@ +# 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. +""" +Tests for anta.tests.vxlan.py +""" +from __future__ import annotations + +from typing import Any + +from anta.tests.vxlan import VerifyVxlan1ConnSettings, VerifyVxlan1Interface, VerifyVxlanConfigSanity, VerifyVxlanVniBinding, VerifyVxlanVtep +from tests.lib.anta import test # noqa: F401; pylint: disable=W0611 + +DATA: list[dict[str, Any]] = [ + { + "name": "success", + "test": VerifyVxlan1Interface, + "eos_data": [{"interfaceDescriptions": {"Vxlan1": {"lineProtocolStatus": "up", "interfaceStatus": "up"}}}], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "skipped", + "test": VerifyVxlan1Interface, + "eos_data": [{"interfaceDescriptions": {"Loopback0": {"lineProtocolStatus": "up", "interfaceStatus": "up"}}}], + "inputs": None, + "expected": {"result": "skipped", "messages": ["Vxlan1 interface is not configured"]}, + }, + { + "name": "failure", + "test": VerifyVxlan1Interface, + "eos_data": [{"interfaceDescriptions": {"Vxlan1": {"lineProtocolStatus": "down", "interfaceStatus": "up"}}}], + "inputs": None, + "expected": {"result": "failure", "messages": ["Vxlan1 interface is down/up"]}, + }, + { + "name": "failure", + "test": VerifyVxlan1Interface, + "eos_data": [{"interfaceDescriptions": {"Vxlan1": {"lineProtocolStatus": "up", "interfaceStatus": "down"}}}], + "inputs": None, + "expected": {"result": "failure", "messages": ["Vxlan1 interface is up/down"]}, + }, + { + "name": "failure", + "test": VerifyVxlan1Interface, + "eos_data": [{"interfaceDescriptions": {"Vxlan1": {"lineProtocolStatus": "down", "interfaceStatus": "down"}}}], + "inputs": None, + "expected": {"result": "failure", "messages": ["Vxlan1 interface is down/down"]}, + }, + { + "name": "success", + "test": VerifyVxlanConfigSanity, + "eos_data": [ + { + "categories": { + "localVtep": { + "description": "Local VTEP Configuration Check", + "allCheckPass": True, + "detail": "", + "hasWarning": False, + "items": [ + {"name": "Loopback IP Address", "checkPass": True, "hasWarning": False, "detail": ""}, + {"name": "VLAN-VNI Map", "checkPass": True, "hasWarning": False, "detail": ""}, + {"name": "Flood List", "checkPass": True, "hasWarning": False, "detail": ""}, + {"name": "Routing", "checkPass": True, "hasWarning": False, "detail": ""}, + {"name": "VNI VRF ACL", "checkPass": True, "hasWarning": False, "detail": ""}, + {"name": "VRF-VNI Dynamic VLAN", "checkPass": True, "hasWarning": False, "detail": ""}, + {"name": "Decap VRF-VNI Map", "checkPass": True, "hasWarning": False, "detail": ""}, + ], + }, + "remoteVtep": { + "description": "Remote VTEP Configuration Check", + "allCheckPass": True, + "detail": "", + "hasWarning": False, + "items": [{"name": "Remote VTEP", "checkPass": True, "hasWarning": False, "detail": ""}], + }, + "pd": { + "description": "Platform Dependent Check", + "allCheckPass": True, + "detail": "", + "hasWarning": False, + "items": [ + {"name": "VXLAN Bridging", "checkPass": True, "hasWarning": False, "detail": ""}, + {"name": "VXLAN Routing", "checkPass": True, "hasWarning": False, "detail": "VXLAN Routing not enabled"}, + ], + }, + "cvx": { + "description": "CVX Configuration Check", + "allCheckPass": True, + "detail": "", + "hasWarning": False, + "items": [{"name": "CVX Server", "checkPass": True, "hasWarning": False, "detail": "Not in controller client mode"}], + }, + "mlag": { + "description": "MLAG Configuration Check", + "allCheckPass": True, + "detail": "Run 'show mlag config-sanity' to verify MLAG config", + "hasWarning": False, + "items": [ + {"name": "Peer VTEP IP", "checkPass": True, "hasWarning": False, "detail": ""}, + {"name": "MLAG VTEP IP", "checkPass": True, "hasWarning": False, "detail": ""}, + {"name": "Virtual VTEP IP", "checkPass": True, "hasWarning": False, "detail": ""}, + {"name": "Peer VLAN-VNI", "checkPass": True, "hasWarning": False, "detail": ""}, + {"name": "MLAG Inactive State", "checkPass": True, "hasWarning": False, "detail": ""}, + ], + }, + }, + "warnings": [], + } + ], + "inputs": None, + "expected": {"result": "success"}, + }, + { + "name": "failure", + "test": VerifyVxlanConfigSanity, + "eos_data": [ + { + "categories": { + "localVtep": { + "description": "Local VTEP Configuration Check", + "allCheckPass": False, + "detail": "", + "hasWarning": True, + "items": [ + {"name": "Loopback IP Address", "checkPass": True, "hasWarning": False, "detail": ""}, + {"name": "VLAN-VNI Map", "checkPass": False, "hasWarning": False, "detail": "No VLAN-VNI mapping in Vxlan1"}, + {"name": "Flood List", "checkPass": False, "hasWarning": True, "detail": "No VXLAN VLANs in Vxlan1"}, + {"name": "Routing", "checkPass": True, "hasWarning": False, "detail": ""}, + {"name": "VNI VRF ACL", "checkPass": True, "hasWarning": False, "detail": ""}, + {"name": "VRF-VNI Dynamic VLAN", "checkPass": True, "hasWarning": False, "detail": ""}, + {"name": "Decap VRF-VNI Map", "checkPass": True, "hasWarning": False, "detail": ""}, + ], + }, + "remoteVtep": { + "description": "Remote VTEP Configuration Check", + "allCheckPass": True, + "detail": "", + "hasWarning": False, + "items": [{"name": "Remote VTEP", "checkPass": True, "hasWarning": False, "detail": ""}], + }, + "pd": { + "description": "Platform Dependent Check", + "allCheckPass": True, + "detail": "", + "hasWarning": False, + "items": [ + {"name": "VXLAN Bridging", "checkPass": True, "hasWarning": False, "detail": ""}, + {"name": "VXLAN Routing", "checkPass": True, "hasWarning": False, "detail": "VXLAN Routing not enabled"}, + ], + }, + "cvx": { + "description": "CVX Configuration Check", + "allCheckPass": True, + "detail": "", + "hasWarning": False, + "items": [{"name": "CVX Server", "checkPass": True, "hasWarning": False, "detail": "Not in controller client mode"}], + }, + "mlag": { + "description": "MLAG Configuration Check", + "allCheckPass": True, + "detail": "Run 'show mlag config-sanity' to verify MLAG config", + "hasWarning": False, + "items": [ + {"name": "Peer VTEP IP", "checkPass": True, "hasWarning": False, "detail": ""}, + {"name": "MLAG VTEP IP", "checkPass": True, "hasWarning": False, "detail": ""}, + {"name": "Virtual VTEP IP", "checkPass": True, "hasWarning": False, "detail": ""}, + {"name": "Peer VLAN-VNI", "checkPass": True, "hasWarning": False, "detail": ""}, + {"name": "MLAG Inactive State", "checkPass": True, "hasWarning": False, "detail": ""}, + ], + }, + }, + "warnings": ["Your configuration contains warnings. This does not mean misconfigurations. But you may wish to re-check your configurations."], + } + ], + "inputs": None, + "expected": { + "result": "failure", + "messages": [ + "VXLAN config sanity check is not passing: {'localVtep': {'description': 'Local VTEP Configuration Check', " + "'allCheckPass': False, 'detail': '', 'hasWarning': True, 'items': [{'name': 'Loopback IP Address', 'checkPass': True, " + "'hasWarning': False, 'detail': ''}, {'name': 'VLAN-VNI Map', 'checkPass': False, 'hasWarning': False, 'detail': " + "'No VLAN-VNI mapping in Vxlan1'}, {'name': 'Flood List', 'checkPass': False, 'hasWarning': True, 'detail': " + "'No VXLAN VLANs in Vxlan1'}, {'name': 'Routing', 'checkPass': True, 'hasWarning': False, 'detail': ''}, {'name': " + "'VNI VRF ACL', 'checkPass': True, 'hasWarning': False, 'detail': ''}, {'name': 'VRF-VNI Dynamic VLAN', 'checkPass': True, " + "'hasWarning': False, 'detail': ''}, {'name': 'Decap VRF-VNI Map', 'checkPass': True, 'hasWarning': False, 'detail': ''}]}}" + ], + }, + }, + { + "name": "skipped", + "test": VerifyVxlanConfigSanity, + "eos_data": [{"categories": {}}], + "inputs": None, + "expected": {"result": "skipped", "messages": ["VXLAN is not configured"]}, + }, + { + "name": "success", + "test": VerifyVxlanVniBinding, + "eos_data": [ + { + "vxlanIntfs": { + "Vxlan1": { + "vniBindings": { + "10020": {"vlan": 20, "dynamicVlan": False, "source": "static", "interfaces": {"Ethernet31": {"dot1q": 0}, "Vxlan1": {"dot1q": 20}}} + }, + "vniBindingsToVrf": {"500": {"vrfName": "PROD", "vlan": 1199, "source": "evpn"}}, + } + } + } + ], + "inputs": {"bindings": {10020: 20, 500: 1199}}, + "expected": {"result": "success"}, + }, + { + "name": "failure-no-binding", + "test": VerifyVxlanVniBinding, + "eos_data": [ + { + "vxlanIntfs": { + "Vxlan1": { + "vniBindings": { + "10020": {"vlan": 20, "dynamicVlan": False, "source": "static", "interfaces": {"Ethernet31": {"dot1q": 0}, "Vxlan1": {"dot1q": 20}}} + }, + "vniBindingsToVrf": {"500": {"vrfName": "PROD", "vlan": 1199, "source": "evpn"}}, + } + } + } + ], + "inputs": {"bindings": {10010: 10, 10020: 20, 500: 1199}}, + "expected": {"result": "failure", "messages": ["The following VNI(s) have no binding: ['10010']"]}, + }, + { + "name": "failure-wrong-binding", + "test": VerifyVxlanVniBinding, + "eos_data": [ + { + "vxlanIntfs": { + "Vxlan1": { + "vniBindings": { + "10020": {"vlan": 30, "dynamicVlan": False, "source": "static", "interfaces": {"Ethernet31": {"dot1q": 0}, "Vxlan1": {"dot1q": 20}}} + }, + "vniBindingsToVrf": {"500": {"vrfName": "PROD", "vlan": 1199, "source": "evpn"}}, + } + } + } + ], + "inputs": {"bindings": {10020: 20, 500: 1199}}, + "expected": {"result": "failure", "messages": ["The following VNI(s) have the wrong VLAN binding: [{'10020': 30}]"]}, + }, + { + "name": "failure-no-and-wrong-binding", + "test": VerifyVxlanVniBinding, + "eos_data": [ + { + "vxlanIntfs": { + "Vxlan1": { + "vniBindings": { + "10020": {"vlan": 30, "dynamicVlan": False, "source": "static", "interfaces": {"Ethernet31": {"dot1q": 0}, "Vxlan1": {"dot1q": 20}}} + }, + "vniBindingsToVrf": {"500": {"vrfName": "PROD", "vlan": 1199, "source": "evpn"}}, + } + } + } + ], + "inputs": {"bindings": {10010: 10, 10020: 20, 500: 1199}}, + "expected": { + "result": "failure", + "messages": ["The following VNI(s) have no binding: ['10010']", "The following VNI(s) have the wrong VLAN binding: [{'10020': 30}]"], + }, + }, + { + "name": "skipped", + "test": VerifyVxlanVniBinding, + "eos_data": [{"vxlanIntfs": {}}], + "inputs": {"bindings": {10020: 20, 500: 1199}}, + "expected": {"result": "skipped", "messages": ["Vxlan1 interface is not configured"]}, + }, + { + "name": "success", + "test": VerifyVxlanVtep, + "eos_data": [{"vteps": {}, "interfaces": {"Vxlan1": {"vteps": ["10.1.1.5", "10.1.1.6"]}}}], + "inputs": {"vteps": ["10.1.1.5", "10.1.1.6"]}, + "expected": {"result": "success"}, + }, + { + "name": "failure-missing-vtep", + "test": VerifyVxlanVtep, + "eos_data": [{"vteps": {}, "interfaces": {"Vxlan1": {"vteps": ["10.1.1.5", "10.1.1.6"]}}}], + "inputs": {"vteps": ["10.1.1.5", "10.1.1.6", "10.1.1.7"]}, + "expected": {"result": "failure", "messages": ["The following VTEP peer(s) are missing from the Vxlan1 interface: ['10.1.1.7']"]}, + }, + { + "name": "failure-no-vtep", + "test": VerifyVxlanVtep, + "eos_data": [{"vteps": {}, "interfaces": {"Vxlan1": {"vteps": []}}}], + "inputs": {"vteps": ["10.1.1.5", "10.1.1.6"]}, + "expected": {"result": "failure", "messages": ["The following VTEP peer(s) are missing from the Vxlan1 interface: ['10.1.1.5', '10.1.1.6']"]}, + }, + { + "name": "failure-no-input-vtep", + "test": VerifyVxlanVtep, + "eos_data": [{"vteps": {}, "interfaces": {"Vxlan1": {"vteps": ["10.1.1.5"]}}}], + "inputs": {"vteps": []}, + "expected": {"result": "failure", "messages": ["Unexpected VTEP peer(s) on Vxlan1 interface: ['10.1.1.5']"]}, + }, + { + "name": "failure-missmatch", + "test": VerifyVxlanVtep, + "eos_data": [{"vteps": {}, "interfaces": {"Vxlan1": {"vteps": ["10.1.1.6", "10.1.1.7", "10.1.1.8"]}}}], + "inputs": {"vteps": ["10.1.1.5", "10.1.1.6"]}, + "expected": { + "result": "failure", + "messages": [ + "The following VTEP peer(s) are missing from the Vxlan1 interface: ['10.1.1.5']", + "Unexpected VTEP peer(s) on Vxlan1 interface: ['10.1.1.7', '10.1.1.8']", + ], + }, + }, + { + "name": "skipped", + "test": VerifyVxlanVtep, + "eos_data": [{"vteps": {}, "interfaces": {}}], + "inputs": {"vteps": ["10.1.1.5", "10.1.1.6", "10.1.1.7"]}, + "expected": {"result": "skipped", "messages": ["Vxlan1 interface is not configured"]}, + }, + { + "name": "success", + "test": VerifyVxlan1ConnSettings, + "eos_data": [{"interfaces": {"Vxlan1": {"srcIpIntf": "Loopback1", "udpPort": 4789}}}], + "inputs": {"source_interface": "Loopback1", "udp_port": 4789}, + "expected": {"result": "success"}, + }, + { + "name": "skipped", + "test": VerifyVxlan1ConnSettings, + "eos_data": [{"interfaces": {}}], + "inputs": {"source_interface": "Loopback1", "udp_port": 4789}, + "expected": {"result": "skipped", "messages": ["Vxlan1 interface is not configured."]}, + }, + { + "name": "failure-wrong-interface", + "test": VerifyVxlan1ConnSettings, + "eos_data": [{"interfaces": {"Vxlan1": {"srcIpIntf": "Loopback10", "udpPort": 4789}}}], + "inputs": {"source_interface": "lo1", "udp_port": 4789}, + "expected": { + "result": "failure", + "messages": ["Source interface is not correct. Expected `Loopback1` as source interface but found `Loopback10` instead."], + }, + }, + { + "name": "failure-wrong-port", + "test": VerifyVxlan1ConnSettings, + "eos_data": [{"interfaces": {"Vxlan1": {"srcIpIntf": "Loopback10", "udpPort": 4789}}}], + "inputs": {"source_interface": "Lo1", "udp_port": 4780}, + "expected": { + "result": "failure", + "messages": [ + "Source interface is not correct. Expected `Loopback1` as source interface but found `Loopback10` instead.", + "UDP port is not correct. Expected `4780` as UDP port but found `4789` instead.", + ], + }, + }, +] |