summaryrefslogtreecommitdiffstats
path: root/anta/tests/routing/bgp.py
diff options
context:
space:
mode:
Diffstat (limited to 'anta/tests/routing/bgp.py')
-rw-r--r--anta/tests/routing/bgp.py857
1 files changed, 541 insertions, 316 deletions
diff --git a/anta/tests/routing/bgp.py b/anta/tests/routing/bgp.py
index 334ac3b..3b99a02 100644
--- a/anta/tests/routing/bgp.py
+++ b/anta/tests/routing/bgp.py
@@ -1,41 +1,40 @@
# 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.
-"""
-BGP test functions
-"""
+"""Module related to BGP tests."""
+
# Mypy does not understand AntaTest.Input typing
# mypy: disable-error-code=attr-defined
from __future__ import annotations
from ipaddress import IPv4Address, IPv4Network, IPv6Address
-from typing import Any, List, Optional, Union, cast
+from typing import Any, ClassVar
-from pydantic import BaseModel, Field, PositiveInt, model_validator, utils
+from pydantic import BaseModel, Field, PositiveInt, model_validator
+from pydantic.v1.utils import deep_update
from pydantic_extra_types.mac_address import MacAddress
from anta.custom_types import Afi, MultiProtocolCaps, Safi, Vni
from anta.models import AntaCommand, AntaTemplate, AntaTest
-from anta.tools.get_item import get_item
-from anta.tools.get_value import get_value
-
-# Need to keep List for pydantic in python 3.8
+from anta.tools import get_item, get_value
-def _add_bgp_failures(failures: dict[tuple[str, Union[str, None]], dict[str, Any]], afi: Afi, safi: Optional[Safi], vrf: str, issue: Any) -> None:
- """
- Add a BGP failure entry to the given `failures` dictionary.
+def _add_bgp_failures(failures: dict[tuple[str, str | None], dict[str, Any]], afi: Afi, safi: Safi | None, vrf: str, issue: str | dict[str, Any]) -> None:
+ """Add a BGP failure entry to the given `failures` dictionary.
Note: This function modifies `failures` in-place.
- Parameters:
- failures (dict): The dictionary to which the failure will be added.
- afi (Afi): The address family identifier.
- vrf (str): The VRF name.
- safi (Safi, optional): The subsequent address family identifier.
- issue (Any): A description of the issue. Can be of any type.
+ Args:
+ ----
+ failures: The dictionary to which the failure will be added.
+ afi: The address family identifier.
+ vrf: The VRF name.
+ safi: The subsequent address family identifier.
+ issue: A description of the issue. Can be of any type.
- The `failures` dictionnary will have the following structure:
+ Example:
+ -------
+ The `failures` dictionary will have the following structure:
{
('afi1', 'safi1'): {
'afi': 'afi1',
@@ -52,40 +51,43 @@ def _add_bgp_failures(failures: dict[tuple[str, Union[str, None]], dict[str, Any
}
}
}
+
"""
key = (afi, safi)
- if safi:
- failure_entry = failures.setdefault(key, {"afi": afi, "safi": safi, "vrfs": {}})
- else:
- failure_entry = failures.setdefault(key, {"afi": afi, "vrfs": {}})
+ failure_entry = failures.setdefault(key, {"afi": afi, "safi": safi, "vrfs": {}}) if safi else failures.setdefault(key, {"afi": afi, "vrfs": {}})
failure_entry["vrfs"][vrf] = issue
-def _check_peer_issues(peer_data: Optional[dict[str, Any]]) -> dict[str, Any]:
- """
- Check for issues in BGP peer data.
+def _check_peer_issues(peer_data: dict[str, Any] | None) -> dict[str, Any]:
+ """Check for issues in BGP peer data.
- Parameters:
- peer_data (dict, optional): The BGP peer data dictionary nested in the `show bgp <afi> <safi> summary` command.
+ Args:
+ ----
+ peer_data: The BGP peer data dictionary nested in the `show bgp <afi> <safi> summary` command.
- Returns:
+ Returns
+ -------
dict: Dictionary with keys indicating issues or an empty dictionary if no issues.
+ Raises
+ ------
+ ValueError: If any of the required keys ("peerState", "inMsgQueue", "outMsgQueue") are missing in `peer_data`, i.e. invalid BGP peer data.
+
Example:
+ -------
{"peerNotFound": True}
{"peerState": "Idle", "inMsgQueue": 2, "outMsgQueue": 0}
{}
- Raises:
- ValueError: If any of the required keys ("peerState", "inMsgQueue", "outMsgQueue") are missing in `peer_data`, i.e. invalid BGP peer data.
"""
if peer_data is None:
return {"peerNotFound": True}
if any(key not in peer_data for key in ["peerState", "inMsgQueue", "outMsgQueue"]):
- raise ValueError("Provided BGP peer data is invalid.")
+ msg = "Provided BGP peer data is invalid."
+ raise ValueError(msg)
if peer_data["peerState"] != "Established" or peer_data["inMsgQueue"] != 0 or peer_data["outMsgQueue"] != 0:
return {"peerState": peer_data["peerState"], "inMsgQueue": peer_data["inMsgQueue"], "outMsgQueue": peer_data["outMsgQueue"]}
@@ -96,80 +98,110 @@ def _check_peer_issues(peer_data: Optional[dict[str, Any]]) -> dict[str, Any]:
def _add_bgp_routes_failure(
bgp_routes: list[str], bgp_output: dict[str, Any], peer: str, vrf: str, route_type: str = "advertised_routes"
) -> dict[str, dict[str, dict[str, dict[str, list[str]]]]]:
- """
- Identifies missing BGP routes and invalid or inactive route entries.
+ """Identify missing BGP routes and invalid or inactive route entries.
This function checks the BGP output from the device against the expected routes.
+
It identifies any missing routes as well as any routes that are invalid or inactive. The results are returned in a dictionary.
- Parameters:
- bgp_routes (list[str]): The list of expected routes.
- bgp_output (dict[str, Any]): The BGP output from the device.
- peer (str): The IP address of the BGP peer.
- vrf (str): The name of the VRF for which the routes need to be verified.
- route_type (str, optional): The type of BGP routes. Defaults to 'advertised_routes'.
+ Args:
+ ----
+ bgp_routes: The list of expected routes.
+ bgp_output: The BGP output from the device.
+ peer: The IP address of the BGP peer.
+ vrf: The name of the VRF for which the routes need to be verified.
+ route_type: The type of BGP routes. Defaults to 'advertised_routes'.
- Returns:
+ Returns
+ -------
dict[str, dict[str, dict[str, dict[str, list[str]]]]]: A dictionary containing the missing routes and invalid or inactive routes.
- """
+ """
# Prepare the failure routes dictionary
failure_routes: dict[str, dict[str, Any]] = {}
# Iterate over the expected BGP routes
for route in bgp_routes:
- route = str(route)
- failure = {"bgp_peers": {peer: {vrf: {route_type: {route: Any}}}}}
+ str_route = str(route)
+ failure = {"bgp_peers": {peer: {vrf: {route_type: {str_route: Any}}}}}
# Check if the route is missing in the BGP output
- if route not in bgp_output:
+ if str_route not in bgp_output:
# If missing, add it to the failure routes dictionary
- failure["bgp_peers"][peer][vrf][route_type][route] = "Not found"
- failure_routes = utils.deep_update(failure_routes, failure)
+ failure["bgp_peers"][peer][vrf][route_type][str_route] = "Not found"
+ failure_routes = deep_update(failure_routes, failure)
continue
# Check if the route is active and valid
- is_active = bgp_output[route]["bgpRoutePaths"][0]["routeType"]["valid"]
- is_valid = bgp_output[route]["bgpRoutePaths"][0]["routeType"]["active"]
+ is_active = bgp_output[str_route]["bgpRoutePaths"][0]["routeType"]["valid"]
+ is_valid = bgp_output[str_route]["bgpRoutePaths"][0]["routeType"]["active"]
# If the route is either inactive or invalid, add it to the failure routes dictionary
if not is_active or not is_valid:
- failure["bgp_peers"][peer][vrf][route_type][route] = {"valid": is_valid, "active": is_active}
- failure_routes = utils.deep_update(failure_routes, failure)
+ failure["bgp_peers"][peer][vrf][route_type][str_route] = {"valid": is_valid, "active": is_active}
+ failure_routes = deep_update(failure_routes, failure)
return failure_routes
class VerifyBGPPeerCount(AntaTest):
- """
- This test verifies the count of BGP peers for a given address family.
+ """Verifies the count of BGP peers for a given address family.
+
+ It supports multiple types of Address Families Identifiers (AFI) and Subsequent Address Family Identifiers (SAFI).
+
+ For SR-TE SAFI, the EOS command supports sr-te first then ipv4/ipv6 (AFI) which is handled automatically in this test.
- It supports multiple types of address families (AFI) and subsequent service families (SAFI).
Please refer to the Input class attributes below for details.
- Expected Results:
- * success: If the count of BGP peers matches the expected count for each address family and VRF.
- * failure: If the count of BGP peers does not match the expected count, or if BGP is not configured for an expected VRF or address family.
+ Expected Results
+ ----------------
+ * Success: If the count of BGP peers matches the expected count for each address family and VRF.
+ * Failure: If the count of BGP peers does not match the expected count, or if BGP is not configured for an expected VRF or address family.
+
+ Examples
+ --------
+ ```yaml
+ anta.tests.routing:
+ bgp:
+ - VerifyBGPPeerCount:
+ address_families:
+ - afi: "evpn"
+ num_peers: 2
+ - afi: "ipv4"
+ safi: "unicast"
+ vrf: "PROD"
+ num_peers: 2
+ - afi: "ipv4"
+ safi: "unicast"
+ vrf: "default"
+ num_peers: 3
+ - afi: "ipv4"
+ safi: "multicast"
+ vrf: "DEV"
+ num_peers: 3
+ ```
"""
name = "VerifyBGPPeerCount"
description = "Verifies the count of BGP peers."
- categories = ["bgp"]
- commands = [
- AntaTemplate(template="show bgp {afi} {safi} summary vrf {vrf}"),
- AntaTemplate(template="show bgp {afi} summary"),
+ categories: ClassVar[list[str]] = ["bgp"]
+ commands: ClassVar[list[AntaCommand | AntaTemplate]] = [
+ AntaTemplate(template="show bgp {afi} {safi} summary vrf {vrf}", revision=3),
+ AntaTemplate(template="show bgp {afi} summary", revision=3),
]
- class Input(AntaTest.Input): # pylint: disable=missing-class-docstring
- address_families: List[BgpAfi]
- """
- List of BGP address families (BgpAfi)
- """
+ class Input(AntaTest.Input):
+ """Input model for the VerifyBGPPeerCount test."""
+
+ address_families: list[BgpAfi]
+ """List of BGP address families (BgpAfi)."""
+
+ class BgpAfi(BaseModel):
+ """Model for a BGP address family (AFI) and subsequent address family (SAFI)."""
- class BgpAfi(BaseModel): # pylint: disable=missing-class-docstring
afi: Afi
- """BGP address family (AFI)"""
- safi: Optional[Safi] = None
+ """BGP address family (AFI)."""
+ safi: Safi | None = None
"""Optional BGP subsequent service family (SAFI).
If the input `afi` is `ipv4` or `ipv6`, a valid `safi` must be provided.
@@ -181,12 +213,11 @@ class VerifyBGPPeerCount(AntaTest):
If the input `afi` is not `ipv4` or `ipv6`, e.g. `evpn`, `vrf` must be `default`.
"""
num_peers: PositiveInt
- """Number of expected BGP peer(s)"""
+ """Number of expected BGP peer(s)."""
@model_validator(mode="after")
def validate_inputs(self: BaseModel) -> BaseModel:
- """
- Validate the inputs provided to the BgpAfi class.
+ """Validate the inputs provided to the BgpAfi class.
If afi is either ipv4 or ipv6, safi must be provided.
@@ -194,36 +225,54 @@ class VerifyBGPPeerCount(AntaTest):
"""
if self.afi in ["ipv4", "ipv6"]:
if self.safi is None:
- raise ValueError("'safi' must be provided when afi is ipv4 or ipv6")
+ msg = "'safi' must be provided when afi is ipv4 or ipv6"
+ raise ValueError(msg)
elif self.safi is not None:
- raise ValueError("'safi' must not be provided when afi is not ipv4 or ipv6")
+ msg = "'safi' must not be provided when afi is not ipv4 or ipv6"
+ raise ValueError(msg)
elif self.vrf != "default":
- raise ValueError("'vrf' must be default when afi is not ipv4 or ipv6")
+ msg = "'vrf' must be default when afi is not ipv4 or ipv6"
+ raise ValueError(msg)
return self
def render(self, template: AntaTemplate) -> list[AntaCommand]:
+ """Render the template for each BGP address family in the input list."""
commands = []
for afi in self.inputs.address_families:
- if template == VerifyBGPPeerCount.commands[0] and afi.afi in ["ipv4", "ipv6"]:
- commands.append(template.render(afi=afi.afi, safi=afi.safi, vrf=afi.vrf, num_peers=afi.num_peers))
+ if template == VerifyBGPPeerCount.commands[0] and afi.afi in ["ipv4", "ipv6"] and afi.safi != "sr-te":
+ commands.append(template.render(afi=afi.afi, safi=afi.safi, vrf=afi.vrf))
+
+ # For SR-TE SAFI, the EOS command supports sr-te first then ipv4/ipv6
+ elif template == VerifyBGPPeerCount.commands[0] and afi.afi in ["ipv4", "ipv6"] and afi.safi == "sr-te":
+ commands.append(template.render(afi=afi.safi, safi=afi.afi, vrf=afi.vrf))
elif template == VerifyBGPPeerCount.commands[1] and afi.afi not in ["ipv4", "ipv6"]:
- commands.append(template.render(afi=afi.afi, vrf=afi.vrf, num_peers=afi.num_peers))
+ commands.append(template.render(afi=afi.afi))
return commands
@AntaTest.anta_test
def test(self) -> None:
+ """Main test function for VerifyBGPPeerCount."""
self.result.is_success()
failures: dict[tuple[str, Any], dict[str, Any]] = {}
for command in self.instance_commands:
+ num_peers = None
peer_count = 0
command_output = command.json_output
- afi = cast(Afi, command.params.get("afi"))
- safi = cast(Optional[Safi], command.params.get("safi"))
- afi_vrf = cast(str, command.params.get("vrf"))
- num_peers = cast(PositiveInt, command.params.get("num_peers"))
+ afi = command.params.afi
+ safi = command.params.safi
+ afi_vrf = command.params.vrf or "default"
+
+ # Swapping AFI and SAFI in case of SR-TE
+ if afi == "sr-te":
+ afi, safi = safi, afi
+
+ for input_entry in self.inputs.address_families:
+ if input_entry.afi == afi and input_entry.safi == safi and input_entry.vrf == afi_vrf:
+ num_peers = input_entry.num_peers
+ break
if not (vrfs := command_output.get("vrfs")):
_add_bgp_failures(failures=failures, afi=afi, safi=safi, vrf=afi_vrf, issue="Not Configured")
@@ -243,37 +292,58 @@ class VerifyBGPPeerCount(AntaTest):
class VerifyBGPPeersHealth(AntaTest):
- """
- This test verifies the health of BGP peers.
+ """Verifies the health of BGP peers.
It will validate that all BGP sessions are established and all message queues for these BGP sessions are empty for a given address family.
- It supports multiple types of address families (AFI) and subsequent service families (SAFI).
+ It supports multiple types of Address Families Identifiers (AFI) and Subsequent Address Family Identifiers (SAFI).
+
+ For SR-TE SAFI, the EOS command supports sr-te first then ipv4/ipv6 (AFI) which is handled automatically in this test.
+
Please refer to the Input class attributes below for details.
- Expected Results:
- * success: If all BGP sessions are established and all messages queues are empty for each address family and VRF.
- * failure: If there are issues with any of the BGP sessions, or if BGP is not configured for an expected VRF or address family.
+ Expected Results
+ ----------------
+ * Success: If all BGP sessions are established and all messages queues are empty for each address family and VRF.
+ * Failure: If there are issues with any of the BGP sessions, or if BGP is not configured for an expected VRF or address family.
+
+ Examples
+ --------
+ ```yaml
+ anta.tests.routing:
+ bgp:
+ - VerifyBGPPeersHealth:
+ address_families:
+ - afi: "evpn"
+ - afi: "ipv4"
+ safi: "unicast"
+ vrf: "default"
+ - afi: "ipv6"
+ safi: "unicast"
+ vrf: "DEV"
+ ```
"""
name = "VerifyBGPPeersHealth"
description = "Verifies the health of BGP peers"
- categories = ["bgp"]
- commands = [
- AntaTemplate(template="show bgp {afi} {safi} summary vrf {vrf}"),
- AntaTemplate(template="show bgp {afi} summary"),
+ categories: ClassVar[list[str]] = ["bgp"]
+ commands: ClassVar[list[AntaCommand | AntaTemplate]] = [
+ AntaTemplate(template="show bgp {afi} {safi} summary vrf {vrf}", revision=3),
+ AntaTemplate(template="show bgp {afi} summary", revision=3),
]
- class Input(AntaTest.Input): # pylint: disable=missing-class-docstring
- address_families: List[BgpAfi]
- """
- List of BGP address families (BgpAfi)
- """
+ class Input(AntaTest.Input):
+ """Input model for the VerifyBGPPeersHealth test."""
+
+ address_families: list[BgpAfi]
+ """List of BGP address families (BgpAfi)."""
+
+ class BgpAfi(BaseModel):
+ """Model for a BGP address family (AFI) and subsequent address family (SAFI)."""
- class BgpAfi(BaseModel): # pylint: disable=missing-class-docstring
afi: Afi
- """BGP address family (AFI)"""
- safi: Optional[Safi] = None
+ """BGP address family (AFI)."""
+ safi: Safi | None = None
"""Optional BGP subsequent service family (SAFI).
If the input `afi` is `ipv4` or `ipv6`, a valid `safi` must be provided.
@@ -287,8 +357,7 @@ class VerifyBGPPeersHealth(AntaTest):
@model_validator(mode="after")
def validate_inputs(self: BaseModel) -> BaseModel:
- """
- Validate the inputs provided to the BgpAfi class.
+ """Validate the inputs provided to the BgpAfi class.
If afi is either ipv4 or ipv6, safi must be provided.
@@ -296,24 +365,33 @@ class VerifyBGPPeersHealth(AntaTest):
"""
if self.afi in ["ipv4", "ipv6"]:
if self.safi is None:
- raise ValueError("'safi' must be provided when afi is ipv4 or ipv6")
+ msg = "'safi' must be provided when afi is ipv4 or ipv6"
+ raise ValueError(msg)
elif self.safi is not None:
- raise ValueError("'safi' must not be provided when afi is not ipv4 or ipv6")
+ msg = "'safi' must not be provided when afi is not ipv4 or ipv6"
+ raise ValueError(msg)
elif self.vrf != "default":
- raise ValueError("'vrf' must be default when afi is not ipv4 or ipv6")
+ msg = "'vrf' must be default when afi is not ipv4 or ipv6"
+ raise ValueError(msg)
return self
def render(self, template: AntaTemplate) -> list[AntaCommand]:
+ """Render the template for each BGP address family in the input list."""
commands = []
for afi in self.inputs.address_families:
- if template == VerifyBGPPeersHealth.commands[0] and afi.afi in ["ipv4", "ipv6"]:
+ if template == VerifyBGPPeersHealth.commands[0] and afi.afi in ["ipv4", "ipv6"] and afi.safi != "sr-te":
commands.append(template.render(afi=afi.afi, safi=afi.safi, vrf=afi.vrf))
+
+ # For SR-TE SAFI, the EOS command supports sr-te first then ipv4/ipv6
+ elif template == VerifyBGPPeersHealth.commands[0] and afi.afi in ["ipv4", "ipv6"] and afi.safi == "sr-te":
+ commands.append(template.render(afi=afi.safi, safi=afi.afi, vrf=afi.vrf))
elif template == VerifyBGPPeersHealth.commands[1] and afi.afi not in ["ipv4", "ipv6"]:
- commands.append(template.render(afi=afi.afi, vrf=afi.vrf))
+ commands.append(template.render(afi=afi.afi))
return commands
@AntaTest.anta_test
def test(self) -> None:
+ """Main test function for VerifyBGPPeersHealth."""
self.result.is_success()
failures: dict[tuple[str, Any], dict[str, Any]] = {}
@@ -321,9 +399,13 @@ class VerifyBGPPeersHealth(AntaTest):
for command in self.instance_commands:
command_output = command.json_output
- afi = cast(Afi, command.params.get("afi"))
- safi = cast(Optional[Safi], command.params.get("safi"))
- afi_vrf = cast(str, command.params.get("vrf"))
+ afi = command.params.afi
+ safi = command.params.safi
+
+ # Swapping AFI and SAFI in case of SR-TE
+ if afi == "sr-te":
+ afi, safi = safi, afi
+ afi_vrf = command.params.vrf or "default"
if not (vrfs := command_output.get("vrfs")):
_add_bgp_failures(failures=failures, afi=afi, safi=safi, vrf=afi_vrf, issue="Not Configured")
@@ -349,37 +431,62 @@ class VerifyBGPPeersHealth(AntaTest):
class VerifyBGPSpecificPeers(AntaTest):
- """
- This test verifies the health of specific BGP peer(s).
+ """Verifies the health of specific BGP peer(s).
It will validate that the BGP session is established and all message queues for this BGP session are empty for the given peer(s).
- It supports multiple types of address families (AFI) and subsequent service families (SAFI).
+ It supports multiple types of Address Families Identifiers (AFI) and Subsequent Address Family Identifiers (SAFI).
+
+ For SR-TE SAFI, the EOS command supports sr-te first then ipv4/ipv6 (AFI) which is handled automatically in this test.
+
Please refer to the Input class attributes below for details.
- Expected Results:
- * success: If the BGP session is established and all messages queues are empty for each given peer.
- * failure: If the BGP session has issues or is not configured, or if BGP is not configured for an expected VRF or address family.
+ Expected Results
+ ----------------
+ * Success: If the BGP session is established and all messages queues are empty for each given peer.
+ * Failure: If the BGP session has issues or is not configured, or if BGP is not configured for an expected VRF or address family.
+
+ Examples
+ --------
+ ```yaml
+ anta.tests.routing:
+ bgp:
+ - VerifyBGPSpecificPeers:
+ address_families:
+ - afi: "evpn"
+ peers:
+ - 10.1.0.1
+ - 10.1.0.2
+ - afi: "ipv4"
+ safi: "unicast"
+ peers:
+ - 10.1.254.1
+ - 10.1.255.0
+ - 10.1.255.2
+ - 10.1.255.4
+ ```
"""
name = "VerifyBGPSpecificPeers"
description = "Verifies the health of specific BGP peer(s)."
- categories = ["bgp"]
- commands = [
- AntaTemplate(template="show bgp {afi} {safi} summary vrf {vrf}"),
- AntaTemplate(template="show bgp {afi} summary"),
+ categories: ClassVar[list[str]] = ["bgp"]
+ commands: ClassVar[list[AntaCommand | AntaTemplate]] = [
+ AntaTemplate(template="show bgp {afi} {safi} summary vrf {vrf}", revision=3),
+ AntaTemplate(template="show bgp {afi} summary", revision=3),
]
- class Input(AntaTest.Input): # pylint: disable=missing-class-docstring
- address_families: List[BgpAfi]
- """
- List of BGP address families (BgpAfi)
- """
+ class Input(AntaTest.Input):
+ """Input model for the VerifyBGPSpecificPeers test."""
+
+ address_families: list[BgpAfi]
+ """List of BGP address families (BgpAfi)."""
+
+ class BgpAfi(BaseModel):
+ """Model for a BGP address family (AFI) and subsequent address family (SAFI)."""
- class BgpAfi(BaseModel): # pylint: disable=missing-class-docstring
afi: Afi
- """BGP address family (AFI)"""
- safi: Optional[Safi] = None
+ """BGP address family (AFI)."""
+ safi: Safi | None = None
"""Optional BGP subsequent service family (SAFI).
If the input `afi` is `ipv4` or `ipv6`, a valid `safi` must be provided.
@@ -392,13 +499,12 @@ class VerifyBGPSpecificPeers(AntaTest):
If the input `afi` is not `ipv4` or `ipv6`, e.g. `evpn`, `vrf` must be `default`.
"""
- peers: List[Union[IPv4Address, IPv6Address]]
- """List of BGP IPv4 or IPv6 peer"""
+ peers: list[IPv4Address | IPv6Address]
+ """List of BGP IPv4 or IPv6 peer."""
@model_validator(mode="after")
def validate_inputs(self: BaseModel) -> BaseModel:
- """
- Validate the inputs provided to the BgpAfi class.
+ """Validate the inputs provided to the BgpAfi class.
If afi is either ipv4 or ipv6, safi must be provided and vrf must NOT be all.
@@ -406,26 +512,37 @@ class VerifyBGPSpecificPeers(AntaTest):
"""
if self.afi in ["ipv4", "ipv6"]:
if self.safi is None:
- raise ValueError("'safi' must be provided when afi is ipv4 or ipv6")
+ msg = "'safi' must be provided when afi is ipv4 or ipv6"
+ raise ValueError(msg)
if self.vrf == "all":
- raise ValueError("'all' is not supported in this test. Use VerifyBGPPeersHealth test instead.")
+ msg = "'all' is not supported in this test. Use VerifyBGPPeersHealth test instead."
+ raise ValueError(msg)
elif self.safi is not None:
- raise ValueError("'safi' must not be provided when afi is not ipv4 or ipv6")
+ msg = "'safi' must not be provided when afi is not ipv4 or ipv6"
+ raise ValueError(msg)
elif self.vrf != "default":
- raise ValueError("'vrf' must be default when afi is not ipv4 or ipv6")
+ msg = "'vrf' must be default when afi is not ipv4 or ipv6"
+ raise ValueError(msg)
return self
def render(self, template: AntaTemplate) -> list[AntaCommand]:
+ """Render the template for each BGP address family in the input list."""
commands = []
+
for afi in self.inputs.address_families:
- if template == VerifyBGPSpecificPeers.commands[0] and afi.afi in ["ipv4", "ipv6"]:
- commands.append(template.render(afi=afi.afi, safi=afi.safi, vrf=afi.vrf, peers=afi.peers))
+ if template == VerifyBGPSpecificPeers.commands[0] and afi.afi in ["ipv4", "ipv6"] and afi.safi != "sr-te":
+ commands.append(template.render(afi=afi.afi, safi=afi.safi, vrf=afi.vrf))
+
+ # For SR-TE SAFI, the EOS command supports sr-te first then ipv4/ipv6
+ elif template == VerifyBGPSpecificPeers.commands[0] and afi.afi in ["ipv4", "ipv6"] and afi.safi == "sr-te":
+ commands.append(template.render(afi=afi.safi, safi=afi.afi, vrf=afi.vrf))
elif template == VerifyBGPSpecificPeers.commands[1] and afi.afi not in ["ipv4", "ipv6"]:
- commands.append(template.render(afi=afi.afi, vrf=afi.vrf, peers=afi.peers))
+ commands.append(template.render(afi=afi.afi))
return commands
@AntaTest.anta_test
def test(self) -> None:
+ """Main test function for VerifyBGPSpecificPeers."""
self.result.is_success()
failures: dict[tuple[str, Any], dict[str, Any]] = {}
@@ -433,10 +550,18 @@ class VerifyBGPSpecificPeers(AntaTest):
for command in self.instance_commands:
command_output = command.json_output
- afi = cast(Afi, command.params.get("afi"))
- safi = cast(Optional[Safi], command.params.get("safi"))
- afi_vrf = cast(str, command.params.get("vrf"))
- afi_peers = cast(List[Union[IPv4Address, IPv6Address]], command.params.get("peers", []))
+ afi = command.params.afi
+ safi = command.params.safi
+ afi_vrf = command.params.vrf or "default"
+
+ # Swapping AFI and SAFI in case of SR-TE
+ if afi == "sr-te":
+ afi, safi = safi, afi
+
+ for input_entry in self.inputs.address_families:
+ if input_entry.afi == afi and input_entry.safi == safi and input_entry.vrf == afi_vrf:
+ afi_peers = input_entry.peers
+ break
if not (vrfs := command_output.get("vrfs")):
_add_bgp_failures(failures=failures, afi=afi, safi=safi, vrf=afi_vrf, issue="Not Configured")
@@ -458,63 +583,82 @@ class VerifyBGPSpecificPeers(AntaTest):
class VerifyBGPExchangedRoutes(AntaTest):
- """
- Verifies if the BGP peers have correctly advertised and received routes.
+ """Verifies if the BGP peers have correctly advertised and received routes.
+
The route type should be 'valid' and 'active' for a specified VRF.
- Expected results:
- * success: If the BGP peers have correctly advertised and received routes of type 'valid' and 'active' for a specified VRF.
- * failure: If a BGP peer is not found, the expected advertised/received routes are not found, or the routes are not 'valid' or 'active'.
+ Expected Results
+ ----------------
+ * Success: If the BGP peers have correctly advertised and received routes of type 'valid' and 'active' for a specified VRF.
+ * Failure: If a BGP peer is not found, the expected advertised/received routes are not found, or the routes are not 'valid' or 'active'.
+
+ Examples
+ --------
+ ```yaml
+ anta.tests.routing:
+ bgp:
+ - VerifyBGPExchangedRoutes:
+ bgp_peers:
+ - peer_address: 172.30.255.5
+ vrf: default
+ advertised_routes:
+ - 192.0.254.5/32
+ received_routes:
+ - 192.0.255.4/32
+ - peer_address: 172.30.255.1
+ vrf: default
+ advertised_routes:
+ - 192.0.255.1/32
+ - 192.0.254.5/32
+ received_routes:
+ - 192.0.254.3/32
+ ```
"""
name = "VerifyBGPExchangedRoutes"
- description = "Verifies if BGP peers have correctly advertised/received routes with type as valid and active for a specified VRF."
- categories = ["bgp"]
- commands = [
- AntaTemplate(template="show bgp neighbors {peer} advertised-routes vrf {vrf}"),
- AntaTemplate(template="show bgp neighbors {peer} routes vrf {vrf}"),
+ description = "Verifies the advertised and received routes of BGP peers."
+ categories: ClassVar[list[str]] = ["bgp"]
+ commands: ClassVar[list[AntaCommand | AntaTemplate]] = [
+ AntaTemplate(template="show bgp neighbors {peer} advertised-routes vrf {vrf}", revision=3),
+ AntaTemplate(template="show bgp neighbors {peer} routes vrf {vrf}", revision=3),
]
class Input(AntaTest.Input):
- """
- Input parameters of the testcase.
- """
+ """Input model for the VerifyBGPExchangedRoutes test."""
- bgp_peers: List[BgpNeighbors]
- """List of BGP peers"""
+ bgp_peers: list[BgpNeighbor]
+ """List of BGP neighbors."""
- class BgpNeighbors(BaseModel):
- """
- This class defines the details of a BGP peer.
- """
+ class BgpNeighbor(BaseModel):
+ """Model for a BGP neighbor."""
peer_address: IPv4Address
- """IPv4 address of a BGP peer"""
+ """IPv4 address of a BGP peer."""
vrf: str = "default"
"""Optional VRF for BGP peer. If not provided, it defaults to `default`."""
- advertised_routes: List[IPv4Network]
- """List of advertised routes of a BGP peer."""
- received_routes: List[IPv4Network]
- """List of received routes of a BGP peer."""
+ advertised_routes: list[IPv4Network]
+ """List of advertised routes in CIDR format."""
+ received_routes: list[IPv4Network]
+ """List of received routes in CIDR format."""
def render(self, template: AntaTemplate) -> list[AntaCommand]:
- """Renders the template with the provided inputs. Returns a list of commands to be executed."""
-
- return [
- template.render(peer=bgp_peer.peer_address, vrf=bgp_peer.vrf, advertised_routes=bgp_peer.advertised_routes, received_routes=bgp_peer.received_routes)
- for bgp_peer in self.inputs.bgp_peers
- ]
+ """Render the template for each BGP neighbor in the input list."""
+ return [template.render(peer=str(bgp_peer.peer_address), vrf=bgp_peer.vrf) for bgp_peer in self.inputs.bgp_peers]
@AntaTest.anta_test
def test(self) -> None:
+ """Main test function for VerifyBGPExchangedRoutes."""
failures: dict[str, dict[str, Any]] = {"bgp_peers": {}}
# Iterating over command output for different peers
for command in self.instance_commands:
- peer = str(command.params["peer"])
- vrf = command.params["vrf"]
- advertised_routes = command.params["advertised_routes"]
- received_routes = command.params["received_routes"]
+ peer = command.params.peer
+ vrf = command.params.vrf
+ for input_entry in self.inputs.bgp_peers:
+ if str(input_entry.peer_address) == peer and input_entry.vrf == vrf:
+ advertised_routes = input_entry.advertised_routes
+ received_routes = input_entry.received_routes
+ break
failure = {vrf: ""}
# Verify if a BGP peer is configured with the provided vrf
@@ -530,7 +674,7 @@ class VerifyBGPExchangedRoutes(AntaTest):
# Validate received routes
else:
failure_routes = _add_bgp_routes_failure(received_routes, bgp_routes, peer, vrf, route_type="received_routes")
- failures = utils.deep_update(failures, failure_routes)
+ failures = deep_update(failures, failure_routes)
if not failures["bgp_peers"]:
self.result.is_success()
@@ -539,40 +683,51 @@ class VerifyBGPExchangedRoutes(AntaTest):
class VerifyBGPPeerMPCaps(AntaTest):
- """
- Verifies the multiprotocol capabilities of a BGP peer in a specified VRF.
- Expected results:
- * success: The test will pass if the BGP peer's multiprotocol capabilities are advertised, received, and enabled in the specified VRF.
- * failure: The test will fail if BGP peers are not found or multiprotocol capabilities are not advertised, received, and enabled in the specified VRF.
+ """Verifies the multiprotocol capabilities of a BGP peer in a specified VRF.
+
+ Expected Results
+ ----------------
+ * Success: The test will pass if the BGP peer's multiprotocol capabilities are advertised, received, and enabled in the specified VRF.
+ * Failure: The test will fail if BGP peers are not found or multiprotocol capabilities are not advertised, received, and enabled in the specified VRF.
+
+ Examples
+ --------
+ ```yaml
+ anta.tests.routing:
+ bgp:
+ - VerifyBGPPeerMPCaps:
+ bgp_peers:
+ - peer_address: 172.30.11.1
+ vrf: default
+ capabilities:
+ - ipv4Unicast
+ ```
"""
name = "VerifyBGPPeerMPCaps"
- description = "Verifies the multiprotocol capabilities of a BGP peer in a specified VRF"
- categories = ["bgp"]
- commands = [AntaCommand(command="show bgp neighbors vrf all")]
+ description = "Verifies the multiprotocol capabilities of a BGP peer."
+ categories: ClassVar[list[str]] = ["bgp"]
+ commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show bgp neighbors vrf all", revision=3)]
class Input(AntaTest.Input):
- """
- Input parameters of the testcase.
- """
+ """Input model for the VerifyBGPPeerMPCaps test."""
- bgp_peers: List[BgpPeers]
+ bgp_peers: list[BgpPeer]
"""List of BGP peers"""
- class BgpPeers(BaseModel):
- """
- This class defines the details of a BGP peer.
- """
+ class BgpPeer(BaseModel):
+ """Model for a BGP peer."""
peer_address: IPv4Address
- """IPv4 address of a BGP peer"""
+ """IPv4 address of a BGP peer."""
vrf: str = "default"
"""Optional VRF for BGP peer. If not provided, it defaults to `default`."""
- capabilities: List[MultiProtocolCaps]
- """Multiprotocol capabilities"""
+ capabilities: list[MultiProtocolCaps]
+ """List of multiprotocol capabilities to be verified."""
@AntaTest.anta_test
def test(self) -> None:
+ """Main test function for VerifyBGPPeerMPCaps."""
failures: dict[str, Any] = {"bgp_peers": {}}
# Iterate over each bgp peer
@@ -588,7 +743,7 @@ class VerifyBGPPeerMPCaps(AntaTest):
or (bgp_output := get_item(bgp_output, "peerAddress", peer)) is None
):
failure["bgp_peers"][peer][vrf] = {"status": "Not configured"}
- failures = utils.deep_update(failures, failure)
+ failures = deep_update(failures, failure)
continue
# Check each capability
@@ -599,12 +754,12 @@ class VerifyBGPPeerMPCaps(AntaTest):
# Check if capabilities are missing
if not capability_output:
failure["bgp_peers"][peer][vrf][capability] = "not found"
- failures = utils.deep_update(failures, failure)
+ failures = deep_update(failures, failure)
# Check if capabilities are not advertised, received, or enabled
elif not all(capability_output.get(prop, False) for prop in ["advertised", "received", "enabled"]):
failure["bgp_peers"][peer][vrf][capability] = capability_output
- failures = utils.deep_update(failures, failure)
+ failures = deep_update(failures, failure)
# Check if there are any failures
if not failures["bgp_peers"]:
@@ -614,38 +769,47 @@ class VerifyBGPPeerMPCaps(AntaTest):
class VerifyBGPPeerASNCap(AntaTest):
- """
- Verifies the four octet asn capabilities of a BGP peer in a specified VRF.
- Expected results:
- * success: The test will pass if BGP peer's four octet asn capabilities are advertised, received, and enabled in the specified VRF.
- * failure: The test will fail if BGP peers are not found or four octet asn capabilities are not advertised, received, and enabled in the specified VRF.
+ """Verifies the four octet asn capabilities of a BGP peer in a specified VRF.
+
+ Expected Results
+ ----------------
+ * Success: The test will pass if BGP peer's four octet asn capabilities are advertised, received, and enabled in the specified VRF.
+ * Failure: The test will fail if BGP peers are not found or four octet asn capabilities are not advertised, received, and enabled in the specified VRF.
+
+ Examples
+ --------
+ ```yaml
+ anta.tests.routing:
+ bgp:
+ - VerifyBGPPeerASNCap:
+ bgp_peers:
+ - peer_address: 172.30.11.1
+ vrf: default
+ ```
"""
name = "VerifyBGPPeerASNCap"
- description = "Verifies the four octet asn capabilities of a BGP peer in a specified VRF."
- categories = ["bgp"]
- commands = [AntaCommand(command="show bgp neighbors vrf all")]
+ description = "Verifies the four octet asn capabilities of a BGP peer."
+ categories: ClassVar[list[str]] = ["bgp"]
+ commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show bgp neighbors vrf all", revision=3)]
class Input(AntaTest.Input):
- """
- Input parameters of the testcase.
- """
+ """Input model for the VerifyBGPPeerASNCap test."""
- bgp_peers: List[BgpPeers]
- """List of BGP peers"""
+ bgp_peers: list[BgpPeer]
+ """List of BGP peers."""
- class BgpPeers(BaseModel):
- """
- This class defines the details of a BGP peer.
- """
+ class BgpPeer(BaseModel):
+ """Model for a BGP peer."""
peer_address: IPv4Address
- """IPv4 address of a BGP peer"""
+ """IPv4 address of a BGP peer."""
vrf: str = "default"
"""Optional VRF for BGP peer. If not provided, it defaults to `default`."""
@AntaTest.anta_test
def test(self) -> None:
+ """Main test function for VerifyBGPPeerASNCap."""
failures: dict[str, Any] = {"bgp_peers": {}}
# Iterate over each bgp peer
@@ -660,7 +824,7 @@ class VerifyBGPPeerASNCap(AntaTest):
or (bgp_output := get_item(bgp_output, "peerAddress", peer)) is None
):
failure["bgp_peers"][peer][vrf] = {"status": "Not configured"}
- failures = utils.deep_update(failures, failure)
+ failures = deep_update(failures, failure)
continue
bgp_output = get_value(bgp_output, "neighborCapabilities.fourOctetAsnCap")
@@ -668,12 +832,12 @@ class VerifyBGPPeerASNCap(AntaTest):
# Check if four octet asn capabilities are found
if not bgp_output:
failure["bgp_peers"][peer][vrf] = {"fourOctetAsnCap": "not found"}
- failures = utils.deep_update(failures, failure)
+ failures = deep_update(failures, failure)
# Check if capabilities are not advertised, received, or enabled
elif not all(bgp_output.get(prop, False) for prop in ["advertised", "received", "enabled"]):
failure["bgp_peers"][peer][vrf] = {"fourOctetAsnCap": bgp_output}
- failures = utils.deep_update(failures, failure)
+ failures = deep_update(failures, failure)
# Check if there are any failures
if not failures["bgp_peers"]:
@@ -683,38 +847,47 @@ class VerifyBGPPeerASNCap(AntaTest):
class VerifyBGPPeerRouteRefreshCap(AntaTest):
- """
- Verifies the route refresh capabilities of a BGP peer in a specified VRF.
- Expected results:
- * success: The test will pass if the BGP peer's route refresh capabilities are advertised, received, and enabled in the specified VRF.
- * failure: The test will fail if BGP peers are not found or route refresh capabilities are not advertised, received, and enabled in the specified VRF.
+ """Verifies the route refresh capabilities of a BGP peer in a specified VRF.
+
+ Expected Results
+ ----------------
+ * Success: The test will pass if the BGP peer's route refresh capabilities are advertised, received, and enabled in the specified VRF.
+ * Failure: The test will fail if BGP peers are not found or route refresh capabilities are not advertised, received, and enabled in the specified VRF.
+
+ Examples
+ --------
+ ```yaml
+ anta.tests.routing:
+ bgp:
+ - VerifyBGPPeerRouteRefreshCap:
+ bgp_peers:
+ - peer_address: 172.30.11.1
+ vrf: default
+ ```
"""
name = "VerifyBGPPeerRouteRefreshCap"
- description = "Verifies the route refresh capabilities of a BGP peer in a specified VRF."
- categories = ["bgp"]
- commands = [AntaCommand(command="show bgp neighbors vrf all")]
+ description = "Verifies the route refresh capabilities of a BGP peer."
+ categories: ClassVar[list[str]] = ["bgp"]
+ commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show bgp neighbors vrf all", revision=3)]
class Input(AntaTest.Input):
- """
- Input parameters of the testcase.
- """
+ """Input model for the VerifyBGPPeerRouteRefreshCap test."""
- bgp_peers: List[BgpPeers]
+ bgp_peers: list[BgpPeer]
"""List of BGP peers"""
- class BgpPeers(BaseModel):
- """
- This class defines the details of a BGP peer.
- """
+ class BgpPeer(BaseModel):
+ """Model for a BGP peer."""
peer_address: IPv4Address
- """IPv4 address of a BGP peer"""
+ """IPv4 address of a BGP peer."""
vrf: str = "default"
"""Optional VRF for BGP peer. If not provided, it defaults to `default`."""
@AntaTest.anta_test
def test(self) -> None:
+ """Main test function for VerifyBGPPeerRouteRefreshCap."""
failures: dict[str, Any] = {"bgp_peers": {}}
# Iterate over each bgp peer
@@ -729,7 +902,7 @@ class VerifyBGPPeerRouteRefreshCap(AntaTest):
or (bgp_output := get_item(bgp_output, "peerAddress", peer)) is None
):
failure["bgp_peers"][peer][vrf] = {"status": "Not configured"}
- failures = utils.deep_update(failures, failure)
+ failures = deep_update(failures, failure)
continue
bgp_output = get_value(bgp_output, "neighborCapabilities.routeRefreshCap")
@@ -737,12 +910,12 @@ class VerifyBGPPeerRouteRefreshCap(AntaTest):
# Check if route refresh capabilities are found
if not bgp_output:
failure["bgp_peers"][peer][vrf] = {"routeRefreshCap": "not found"}
- failures = utils.deep_update(failures, failure)
+ failures = deep_update(failures, failure)
# Check if capabilities are not advertised, received, or enabled
elif not all(bgp_output.get(prop, False) for prop in ["advertised", "received", "enabled"]):
failure["bgp_peers"][peer][vrf] = {"routeRefreshCap": bgp_output}
- failures = utils.deep_update(failures, failure)
+ failures = deep_update(failures, failure)
# Check if there are any failures
if not failures["bgp_peers"]:
@@ -752,30 +925,40 @@ class VerifyBGPPeerRouteRefreshCap(AntaTest):
class VerifyBGPPeerMD5Auth(AntaTest):
- """
- Verifies the MD5 authentication and state of IPv4 BGP peers in a specified VRF.
- Expected results:
- * success: The test will pass if IPv4 BGP peers are configured with MD5 authentication and state as established in the specified VRF.
- * failure: The test will fail if IPv4 BGP peers are not found, state is not as established or MD5 authentication is not enabled in the specified VRF.
+ """Verifies the MD5 authentication and state of IPv4 BGP peers in a specified VRF.
+
+ Expected Results
+ ----------------
+ * Success: The test will pass if IPv4 BGP peers are configured with MD5 authentication and state as established in the specified VRF.
+ * Failure: The test will fail if IPv4 BGP peers are not found, state is not as established or MD5 authentication is not enabled in the specified VRF.
+
+ Examples
+ --------
+ ```yaml
+ anta.tests.routing:
+ bgp:
+ - VerifyBGPPeerMD5Auth:
+ bgp_peers:
+ - peer_address: 172.30.11.1
+ vrf: default
+ - peer_address: 172.30.11.5
+ vrf: default
+ ```
"""
name = "VerifyBGPPeerMD5Auth"
- description = "Verifies the MD5 authentication and state of IPv4 BGP peers in a specified VRF"
- categories = ["routing", "bgp"]
- commands = [AntaCommand(command="show bgp neighbors vrf all")]
+ description = "Verifies the MD5 authentication and state of a BGP peer."
+ categories: ClassVar[list[str]] = ["bgp"]
+ commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show bgp neighbors vrf all", revision=3)]
class Input(AntaTest.Input):
- """
- Input parameters of the test case.
- """
+ """Input model for the VerifyBGPPeerMD5Auth test."""
- bgp_peers: List[BgpPeers]
- """List of IPv4 BGP peers"""
+ bgp_peers: list[BgpPeer]
+ """List of IPv4 BGP peers."""
- class BgpPeers(BaseModel):
- """
- This class defines the details of an IPv4 BGP peer.
- """
+ class BgpPeer(BaseModel):
+ """Model for a BGP peer."""
peer_address: IPv4Address
"""IPv4 address of BGP peer."""
@@ -784,6 +967,7 @@ class VerifyBGPPeerMD5Auth(AntaTest):
@AntaTest.anta_test
def test(self) -> None:
+ """Main test function for VerifyBGPPeerMD5Auth."""
failures: dict[str, Any] = {"bgp_peers": {}}
# Iterate over each command
@@ -798,7 +982,7 @@ class VerifyBGPPeerMD5Auth(AntaTest):
or (bgp_output := get_item(bgp_output, "peerAddress", peer)) is None
):
failure["bgp_peers"][peer][vrf] = {"status": "Not configured"}
- failures = utils.deep_update(failures, failure)
+ failures = deep_update(failures, failure)
continue
# Check if BGP peer state and authentication
@@ -806,7 +990,7 @@ class VerifyBGPPeerMD5Auth(AntaTest):
md5_auth_enabled = bgp_output.get("md5AuthEnabled")
if state != "Established" or not md5_auth_enabled:
failure["bgp_peers"][peer][vrf] = {"state": state, "md5_auth_enabled": md5_auth_enabled}
- failures = utils.deep_update(failures, failure)
+ failures = deep_update(failures, failure)
# Check if there are any failures
if not failures["bgp_peers"]:
@@ -816,45 +1000,60 @@ class VerifyBGPPeerMD5Auth(AntaTest):
class VerifyEVPNType2Route(AntaTest):
- """
- This test verifies the EVPN Type-2 routes for a given IPv4 or MAC address and VNI.
-
- Expected Results:
- * success: If all provided VXLAN endpoints have at least one valid and active path to their EVPN Type-2 routes.
- * failure: If any of the provided VXLAN endpoints do not have at least one valid and active path to their EVPN Type-2 routes.
+ """Verifies the EVPN Type-2 routes for a given IPv4 or MAC address and VNI.
+
+ Expected Results
+ ----------------
+ * Success: If all provided VXLAN endpoints have at least one valid and active path to their EVPN Type-2 routes.
+ * Failure: If any of the provided VXLAN endpoints do not have at least one valid and active path to their EVPN Type-2 routes.
+
+ Examples
+ --------
+ ```yaml
+ anta.tests.routing:
+ bgp:
+ - VerifyEVPNType2Route:
+ vxlan_endpoints:
+ - address: 192.168.20.102
+ vni: 10020
+ - address: aac1.ab5d.b41e
+ vni: 10010
+ ```
"""
name = "VerifyEVPNType2Route"
description = "Verifies the EVPN Type-2 routes for a given IPv4 or MAC address and VNI."
- categories = ["routing", "bgp"]
- commands = [AntaTemplate(template="show bgp evpn route-type mac-ip {address} vni {vni}")]
+ categories: ClassVar[list[str]] = ["bgp"]
+ commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaTemplate(template="show bgp evpn route-type mac-ip {address} vni {vni}", revision=2)]
class Input(AntaTest.Input):
- """Inputs for the VerifyEVPNType2Route test."""
+ """Input model for the VerifyEVPNType2Route test."""
- vxlan_endpoints: List[VxlanEndpoint]
- """List of VXLAN endpoints to verify"""
+ vxlan_endpoints: list[VxlanEndpoint]
+ """List of VXLAN endpoints to verify."""
class VxlanEndpoint(BaseModel):
- """VXLAN endpoint input model."""
+ """Model for a VXLAN endpoint."""
- address: Union[IPv4Address, MacAddress]
- """IPv4 or MAC address of the VXLAN endpoint"""
+ address: IPv4Address | MacAddress
+ """IPv4 or MAC address of the VXLAN endpoint."""
vni: Vni
- """VNI of the VXLAN endpoint"""
+ """VNI of the VXLAN endpoint."""
def render(self, template: AntaTemplate) -> list[AntaCommand]:
- return [template.render(address=endpoint.address, vni=endpoint.vni) for endpoint in self.inputs.vxlan_endpoints]
+ """Render the template for each VXLAN endpoint in the input list."""
+ return [template.render(address=str(endpoint.address), vni=endpoint.vni) for endpoint in self.inputs.vxlan_endpoints]
@AntaTest.anta_test
def test(self) -> None:
+ """Main test function for VerifyEVPNType2Route."""
self.result.is_success()
no_evpn_routes = []
bad_evpn_routes = []
for command in self.instance_commands:
- address = str(command.params["address"])
- vni = command.params["vni"]
+ address = command.params.address
+ vni = command.params.vni
# Verify that the VXLAN endpoint is in the BGP EVPN table
evpn_routes = command.json_output["evpnRoutes"]
if not evpn_routes:
@@ -878,30 +1077,40 @@ class VerifyEVPNType2Route(AntaTest):
class VerifyBGPAdvCommunities(AntaTest):
- """
- Verifies if the advertised communities of BGP peers are standard, extended, and large in the specified VRF.
- Expected results:
- * success: The test will pass if the advertised communities of BGP peers are standard, extended, and large in the specified VRF.
- * failure: The test will fail if the advertised communities of BGP peers are not standard, extended, and large in the specified VRF.
+ """Verifies if the advertised communities of BGP peers are standard, extended, and large in the specified VRF.
+
+ Expected Results
+ ----------------
+ * Success: The test will pass if the advertised communities of BGP peers are standard, extended, and large in the specified VRF.
+ * Failure: The test will fail if the advertised communities of BGP peers are not standard, extended, and large in the specified VRF.
+
+ Examples
+ --------
+ ```yaml
+ anta.tests.routing:
+ bgp:
+ - VerifyBGPAdvCommunities:
+ bgp_peers:
+ - peer_address: 172.30.11.17
+ vrf: default
+ - peer_address: 172.30.11.21
+ vrf: default
+ ```
"""
name = "VerifyBGPAdvCommunities"
- description = "Verifies if the advertised communities of BGP peers are standard, extended, and large in the specified VRF."
- categories = ["routing", "bgp"]
- commands = [AntaCommand(command="show bgp neighbors vrf all")]
+ description = "Verifies the advertised communities of a BGP peer."
+ categories: ClassVar[list[str]] = ["bgp"]
+ commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show bgp neighbors vrf all", revision=3)]
class Input(AntaTest.Input):
- """
- Input parameters for the test.
- """
+ """Input model for the VerifyBGPAdvCommunities test."""
- bgp_peers: List[BgpPeers]
- """List of BGP peers"""
+ bgp_peers: list[BgpPeer]
+ """List of BGP peers."""
- class BgpPeers(BaseModel):
- """
- This class defines the details of a BGP peer.
- """
+ class BgpPeer(BaseModel):
+ """Model for a BGP peer."""
peer_address: IPv4Address
"""IPv4 address of a BGP peer."""
@@ -910,6 +1119,7 @@ class VerifyBGPAdvCommunities(AntaTest):
@AntaTest.anta_test
def test(self) -> None:
+ """Main test function for VerifyBGPAdvCommunities."""
failures: dict[str, Any] = {"bgp_peers": {}}
# Iterate over each bgp peer
@@ -924,14 +1134,14 @@ class VerifyBGPAdvCommunities(AntaTest):
or (bgp_output := get_item(bgp_output, "peerAddress", peer)) is None
):
failure["bgp_peers"][peer][vrf] = {"status": "Not configured"}
- failures = utils.deep_update(failures, failure)
+ failures = deep_update(failures, failure)
continue
# Verify BGP peer's advertised communities
bgp_output = bgp_output.get("advertisedCommunities")
if not bgp_output["standard"] or not bgp_output["extended"] or not bgp_output["large"]:
failure["bgp_peers"][peer][vrf] = {"advertised_communities": bgp_output}
- failures = utils.deep_update(failures, failure)
+ failures = deep_update(failures, failure)
if not failures["bgp_peers"]:
self.result.is_success()
@@ -940,42 +1150,57 @@ class VerifyBGPAdvCommunities(AntaTest):
class VerifyBGPTimers(AntaTest):
- """
- Verifies if the BGP peers are configured with the correct hold and keep-alive timers in the specified VRF.
- Expected results:
- * success: The test will pass if the hold and keep-alive timers are correct for BGP peers in the specified VRF.
- * failure: The test will fail if BGP peers are not found or hold and keep-alive timers are not correct in the specified VRF.
+ """Verifies if the BGP peers are configured with the correct hold and keep-alive timers in the specified VRF.
+
+ Expected Results
+ ----------------
+ * Success: The test will pass if the hold and keep-alive timers are correct for BGP peers in the specified VRF.
+ * Failure: The test will fail if BGP peers are not found or hold and keep-alive timers are not correct in the specified VRF.
+
+ Examples
+ --------
+ ```yaml
+ anta.tests.routing:
+ bgp:
+ - VerifyBGPTimers:
+ bgp_peers:
+ - peer_address: 172.30.11.1
+ vrf: default
+ hold_time: 180
+ keep_alive_time: 60
+ - peer_address: 172.30.11.5
+ vrf: default
+ hold_time: 180
+ keep_alive_time: 60
+ ```
"""
name = "VerifyBGPTimers"
- description = "Verifies if the BGP peers are configured with the correct hold and keep alive timers in the specified VRF."
- categories = ["routing", "bgp"]
- commands = [AntaCommand(command="show bgp neighbors vrf all")]
+ description = "Verifies the timers of a BGP peer."
+ categories: ClassVar[list[str]] = ["bgp"]
+ commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show bgp neighbors vrf all", revision=3)]
class Input(AntaTest.Input):
- """
- Input parameters for the test.
- """
+ """Input model for the VerifyBGPTimers test."""
- bgp_peers: List[BgpPeers]
+ bgp_peers: list[BgpPeer]
"""List of BGP peers"""
- class BgpPeers(BaseModel):
- """
- This class defines the details of a BGP peer.
- """
+ class BgpPeer(BaseModel):
+ """Model for a BGP peer."""
peer_address: IPv4Address
- """IPv4 address of a BGP peer"""
+ """IPv4 address of a BGP peer."""
vrf: str = "default"
"""Optional VRF for BGP peer. If not provided, it defaults to `default`."""
hold_time: int = Field(ge=3, le=7200)
- """BGP hold time in seconds"""
+ """BGP hold time in seconds."""
keep_alive_time: int = Field(ge=0, le=3600)
- """BGP keep-alive time in seconds"""
+ """BGP keep-alive time in seconds."""
@AntaTest.anta_test
def test(self) -> None:
+ """Main test function for VerifyBGPTimers."""
failures: dict[str, Any] = {}
# Iterate over each bgp peer