Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(anta): Added testcases to verifying Route Type #925

Merged
merged 12 commits into from
Dec 20, 2024
Merged
30 changes: 30 additions & 0 deletions anta/custom_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,33 @@ def validate_regex(value: str) -> str:
SnmpErrorCounter = Literal[
"inVersionErrs", "inBadCommunityNames", "inBadCommunityUses", "inParseErrs", "outTooBigErrs", "outNoSuchNameErrs", "outBadValueErrs", "outGeneralErrs"
]

IPv4RouteType = Literal[
"connected",
"static",
"kernel",
"OSPF",
"OSPF inter area",
"OSPF external type 1",
"OSPF external type 2",
"OSPF NSSA external type 1",
"OSPF NSSA external type2",
"Other BGP Routes",
"iBGP",
"eBGP",
"RIP",
"IS-IS level 1",
"IS-IS level 2",
"OSPFv3",
"BGP Aggregate",
"OSPF Summary",
"Nexthop Group Static Route",
"VXLAN Control Service",
"Martian",
"DHCP client installed default route",
"Dynamic Policy Route",
"VRF Leaked",
"gRIBI",
"Route Cache Route",
"CBF Leaked Route",
]
28 changes: 28 additions & 0 deletions anta/input_models/routing/generic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# 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.
"""Module containing input models for generic routing tests."""

from __future__ import annotations

from ipaddress import IPv4Network

from pydantic import BaseModel, ConfigDict

from anta.custom_types import IPv4RouteType


class IPv4Routes(BaseModel):
"""Model for a list of IPV4 route entries."""

vitthalmagadum marked this conversation as resolved.
Show resolved Hide resolved
model_config = ConfigDict(extra="forbid")
prefix: IPv4Network
"""The IPV4 network to validate the route type."""
vrf: str = "default"
"""VRF context. Defaults to `default` VRF."""
route_type: IPv4RouteType
"""List of IPV4 Route type to validate the valid rout type."""

def __str__(self) -> str:
"""Return a human-readable string representation of the IPv4RouteType for reporting."""
return f"Prefix: {self.prefix} VRF: {self.vrf}"
75 changes: 75 additions & 0 deletions anta/tests/routing/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
from pydantic import model_validator

from anta.custom_types import PositiveInteger
from anta.input_models.routing.generic import IPv4Routes
from anta.models import AntaCommand, AntaTemplate, AntaTest
from anta.tools import get_value

if TYPE_CHECKING:
import sys
Expand Down Expand Up @@ -181,3 +183,76 @@ def test(self) -> None:
self.result.is_success()
else:
self.result.is_failure(f"The following route(s) are missing from the routing table of VRF {self.inputs.vrf}: {missing_routes}")


class VerifyIPv4RouteType(AntaTest):
"""Verifies the route-type of the IPv4 prefixes.

This test performs the following checks for each IPv4 route:
1. Verifies that the specified VRF is configured.
2. Verifies that the specified IPv4 route is exists in the configuration.
3. Verifies that the the specified IPv4 route is of the expected type.

Expected Results
----------------
* Success: If all of the following conditions are met:
- All the specified VRFs are configured.
- All the specified IPv4 routes are found.
- All the specified IPv4 routes are of the expected type.
* Failure: If any of the following occur:
- A specified VRF is not configured.
- A specified IPv4 route is not found.
- Any specified IPv4 route is not of the expected type.

Examples
--------
```yaml
anta.tests.routing:
generic:
- VerifyIPv4RouteType:
routes_entries:
- prefix: 10.10.0.1/32
vrf: default
route_type: eBGP
- prefix: 10.100.0.12/31
vrf: default
route_type: connected
- prefix: 10.100.1.5/32
vrf: default
route_type: iBGP
```
"""

categories: ClassVar[list[str]] = ["routing"]
commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show ip route vrf all", revision=4)]

class Input(AntaTest.Input):
"""Input model for the VerifyIPv4RouteType test."""

routes_entries: list[IPv4Routes]

@AntaTest.anta_test
def test(self) -> None:
"""Main test function for VerifyIPv4RouteType."""
self.result.is_success()
output = self.instance_commands[0].json_output

# Iterating over the all routes entries mentioned in the inputs.
for entry in self.inputs.routes_entries:
prefix = str(entry.prefix)
vrf = entry.vrf
expected_route_type = entry.route_type

# Verifying that on device, expected VRF is configured.
if (routes_details := get_value(output, f"vrfs.{vrf}.routes")) is None:
self.result.is_failure(f"{entry} - VRF not configured")
continue

# Verifying that the expected IPv4 route is present or not on the device
if (route_data := routes_details.get(prefix)) is None:
self.result.is_failure(f"{entry} - Route not found")
continue

# Verifying that the specified IPv4 routes are of the expected type.
if expected_route_type != (actual_route_type := route_data.get("routeType")):
self.result.is_failure(f"{entry} - Incorrect route type - Expected: {expected_route_type} Actual: {actual_route_type}")
16 changes: 16 additions & 0 deletions docs/api/tests.routing.generic.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ anta_title: ANTA catalog for generic routing tests
~ that can be found in the LICENSE file.
-->

# Tests

::: anta.tests.routing.generic

options:
show_root_heading: false
show_root_toc_entry: false
Expand All @@ -18,3 +21,16 @@ anta_title: ANTA catalog for generic routing tests
filters:
- "!test"
- "!render"

# Input models

::: anta.input_models.routing.generic

options:
show_root_heading: false
show_root_toc_entry: false
show_bases: false
merge_init_into_class: false
anta_hide_test_module_description: true
show_labels: true
filters: ["!^__str__"]
12 changes: 12 additions & 0 deletions examples/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,18 @@ anta.tests.routing.bgp:
- address: aac1.ab5d.b41e
vni: 10010
anta.tests.routing.generic:
- VerifyIPv4RouteType:
# Verifies the route-type of the IPv4 prefixes.
routes_entries:
- prefix: 10.10.0.1/32
vrf: default
route_type: eBGP
- prefix: 10.100.0.12/31
vrf: default
route_type: connected
- prefix: 10.100.1.5/32
vrf: default
route_type: iBGP
- VerifyRoutingProtocolModel:
# Verifies the configured routing protocol model.
model: multi-agent
Expand Down
46 changes: 45 additions & 1 deletion tests/units/anta_tests/routing/test_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import pytest
from pydantic import ValidationError

from anta.tests.routing.generic import VerifyRoutingProtocolModel, VerifyRoutingTableEntry, VerifyRoutingTableSize
from anta.tests.routing.generic import VerifyIPv4RouteType, VerifyRoutingProtocolModel, VerifyRoutingTableEntry, VerifyRoutingTableSize
from tests.units.anta_tests import test

DATA: list[dict[str, Any]] = [
Expand Down Expand Up @@ -304,6 +304,50 @@
"inputs": {"vrf": "default", "routes": ["10.1.0.1", "10.1.0.2"], "collect": "all"},
"expected": {"result": "failure", "messages": ["The following route(s) are missing from the routing table of VRF default: ['10.1.0.2']"]},
},
{
"name": "success-valid-route-type",
"test": VerifyIPv4RouteType,
"eos_data": [
{
"vrfs": {
"default": {"routes": {"10.10.0.1/32": {"routeType": "eBGP"}, "10.100.0.12/31": {"routeType": "connected"}}},
"MGMT": {"routes": {"10.100.1.5/32": {"routeType": "iBGP"}}},
}
}
],
"inputs": {
"routes_entries": [
{"vrf": "default", "prefix": "10.10.0.1/32", "route_type": "eBGP"},
{"vrf": "default", "prefix": "10.100.0.12/31", "route_type": "connected"},
{"vrf": "MGMT", "prefix": "10.100.1.5/32", "route_type": "iBGP"},
]
},
"expected": {"result": "success"},
},
{
"name": "failure-route-not-found",
"test": VerifyIPv4RouteType,
"eos_data": [{"vrfs": {"default": {"routes": {}}}}],
"inputs": {"routes_entries": [{"vrf": "default", "prefix": "10.10.0.1/32", "route_type": "eBGP"}]},
"expected": {"result": "failure", "messages": ["Prefix: 10.10.0.1/32 VRF: default - Route not found"]},
},
{
"name": "failure-invalid-route-type",
"test": VerifyIPv4RouteType,
"eos_data": [{"vrfs": {"default": {"routes": {"10.10.0.1/32": {"routeType": "eBGP"}}}}}],
"inputs": {"routes_entries": [{"vrf": "default", "prefix": "10.10.0.1/32", "route_type": "iBGP"}]},
"expected": {
"result": "failure",
"messages": ["Prefix: 10.10.0.1/32 VRF: default - Incorrect route type - Expected: iBGP Actual: eBGP"],
},
},
{
"name": "failure-vrf-not-configured",
"test": VerifyIPv4RouteType,
"eos_data": [{"vrfs": {}}],
"inputs": {"routes_entries": [{"vrf": "default", "prefix": "10.10.0.1/32", "route_type": "eBGP"}]},
"expected": {"result": "failure", "messages": ["Prefix: 10.10.0.1/32 VRF: default - VRF not configured"]},
},
]


Expand Down
Loading