Skip to content

Commit

Permalink
fix(anta.tests): Second round of cleaning up BGP tests module (#914)
Browse files Browse the repository at this point in the history
  • Loading branch information
carl-baillargeon authored Dec 24, 2024
1 parent 891b8ba commit d8d9690
Show file tree
Hide file tree
Showing 6 changed files with 843 additions and 1,395 deletions.
87 changes: 83 additions & 4 deletions anta/input_models/routing/bgp.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@

from __future__ import annotations

from ipaddress import IPv4Address, IPv6Address
from ipaddress import IPv4Address, IPv4Network, IPv6Address
from typing import TYPE_CHECKING, Any
from warnings import warn

from pydantic import BaseModel, ConfigDict, PositiveInt, model_validator
from pydantic import BaseModel, ConfigDict, Field, PositiveInt, model_validator
from pydantic_extra_types.mac_address import MacAddress

from anta.custom_types import Afi, Safi
from anta.custom_types import Afi, BgpDropStats, BgpUpdateError, MultiProtocolCaps, Safi, Vni

if TYPE_CHECKING:
import sys
Expand Down Expand Up @@ -97,7 +98,7 @@ def eos_key(self) -> str:
return AFI_SAFI_EOS_KEY[(self.afi, self.safi)]

def __str__(self) -> str:
"""Return a string representation of the BgpAddressFamily model. Used in failure messages.
"""Return a human-readable string representation of the BgpAddressFamily for reporting.
Examples
--------
Expand Down Expand Up @@ -128,3 +129,81 @@ def __init__(self, **data: Any) -> None: # noqa: ANN401
stacklevel=2,
)
super().__init__(**data)


class BgpPeer(BaseModel):
"""Model for a BGP peer.
Only IPv4 peers are supported for now.
"""

model_config = ConfigDict(extra="forbid")
peer_address: IPv4Address
"""IPv4 address of the BGP peer."""
vrf: str = "default"
"""Optional VRF for the BGP peer. Defaults to `default`."""
advertised_routes: list[IPv4Network] | None = None
"""List of advertised routes in CIDR format. Required field in the `VerifyBGPExchangedRoutes` test."""
received_routes: list[IPv4Network] | None = None
"""List of received routes in CIDR format. Required field in the `VerifyBGPExchangedRoutes` test."""
capabilities: list[MultiProtocolCaps] | None = None
"""List of BGP multiprotocol capabilities. Required field in the `VerifyBGPPeerMPCaps` test."""
strict: bool = False
"""If True, requires exact match of the provided BGP multiprotocol capabilities.
Optional field in the `VerifyBGPPeerMPCaps` test. Defaults to False."""
hold_time: int | None = Field(default=None, ge=3, le=7200)
"""BGP hold time in seconds. Required field in the `VerifyBGPTimers` test."""
keep_alive_time: int | None = Field(default=None, ge=0, le=3600)
"""BGP keepalive time in seconds. Required field in the `VerifyBGPTimers` test."""
drop_stats: list[BgpDropStats] | None = None
"""List of drop statistics to be verified.
Optional field in the `VerifyBGPPeerDropStats` test. If not provided, the test will verifies all drop statistics."""
update_errors: list[BgpUpdateError] | None = None
"""List of update error counters to be verified.
Optional field in the `VerifyBGPPeerUpdateErrors` test. If not provided, the test will verifies all the update error counters."""
inbound_route_map: str | None = None
"""Inbound route map applied, defaults to None. Required field in the `VerifyBgpRouteMaps` test."""
outbound_route_map: str | None = None
"""Outbound route map applied, defaults to None. Required field in the `VerifyBgpRouteMaps` test."""
maximum_routes: int | None = Field(default=None, ge=0, le=4294967294)
"""The maximum allowable number of BGP routes, `0` means unlimited. Required field in the `VerifyBGPPeerRouteLimit` test"""
warning_limit: int | None = Field(default=None, ge=0, le=4294967294)
"""Optional maximum routes warning limit. If not provided, it defaults to `0` meaning no warning limit."""

def __str__(self) -> str:
"""Return a human-readable string representation of the BgpPeer for reporting."""
return f"Peer: {self.peer_address} VRF: {self.vrf}"


class BgpNeighbor(BgpPeer): # pragma: no cover
"""Alias for the BgpPeer model to maintain backward compatibility.
When initialised, it will emit a deprecation warning and call the BgpPeer model.
TODO: Remove this class in ANTA v2.0.0.
"""

def __init__(self, **data: Any) -> None: # noqa: ANN401
"""Initialize the BgpPeer class, emitting a depreciation warning."""
warn(
message="BgpNeighbor model is deprecated and will be removed in ANTA v2.0.0. Use the BgpPeer model instead.",
category=DeprecationWarning,
stacklevel=2,
)
super().__init__(**data)


class VxlanEndpoint(BaseModel):
"""Model for a VXLAN endpoint."""

address: IPv4Address | MacAddress
"""IPv4 or MAC address of the VXLAN endpoint."""
vni: Vni
"""VNI of the VXLAN endpoint."""

def __str__(self) -> str:
"""Return a human-readable string representation of the VxlanEndpoint for reporting."""
return f"Address: {self.address} VNI: {self.vni}"
5 changes: 2 additions & 3 deletions anta/reporter/md_reporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import logging
import re
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, ClassVar
from typing import TYPE_CHECKING, ClassVar, TextIO

from anta.constants import MD_REPORT_TOC
from anta.logger import anta_log_exception
Expand All @@ -17,7 +17,6 @@

if TYPE_CHECKING:
from collections.abc import Generator
from io import TextIOWrapper
from pathlib import Path

from anta.result_manager import ResultManager
Expand Down Expand Up @@ -72,7 +71,7 @@ class MDReportBase(ABC):
to generate and write content to the provided markdown file.
"""

def __init__(self, mdfile: TextIOWrapper, results: ResultManager) -> None:
def __init__(self, mdfile: TextIO, results: ResultManager) -> None:
"""Initialize the MDReportBase with an open markdown file object to write to and a ResultManager instance.
Parameters
Expand Down
Loading

0 comments on commit d8d9690

Please sign in to comment.