diff --git a/anta/decorators.py b/anta/decorators.py index f128f7914..37f4fe2ff 100644 --- a/anta/decorators.py +++ b/anta/decorators.py @@ -24,7 +24,7 @@ def deprecated_test(new_tests: list[str] | None = None) -> Callable[[F], F]: ---- new_tests (Optional[list[str]]): A list of new test classes that should replace the deprecated test. - Returns: + Returns ------- Callable[[F], F]: A decorator that can be used to wrap test functions. @@ -37,7 +37,7 @@ def decorator(function: F) -> F: ---- function (F): The test function to be decorated. - Returns: + Returns ------- F: The decorated function. @@ -68,7 +68,7 @@ def skip_on_platforms(platforms: list[str]) -> Callable[[F], F]: ---- platforms (list[str]): List of hardware models on which the test should be skipped. - Returns: + Returns ------- Callable[[F], F]: A decorator that can be used to wrap test functions. @@ -81,7 +81,7 @@ def decorator(function: F) -> F: ---- function (F): The test function to be decorated. - Returns: + Returns ------- F: The decorated function. diff --git a/anta/inventory/__init__.py b/anta/inventory/__init__.py index 6ba423653..f55780f56 100644 --- a/anta/inventory/__init__.py +++ b/anta/inventory/__init__.py @@ -98,7 +98,7 @@ def _parse_networks( inventory (AntaInventory): AntaInventory to add the parsed devices to **kwargs (dict[str, Any]): Additional keywork arguments to pass to the device constructor - Raises: + Raises ------ InventoryIncorrectSchemaError: Inventory file is not following AntaInventory Schema. @@ -131,7 +131,7 @@ def _parse_ranges( inventory (AntaInventory): AntaInventory to add the parsed devices to **kwargs (dict[str, Any]): Additional keywork arguments to pass to the device constructor - Raises: + Raises ------ InventoryIncorrectSchemaError: Inventory file is not following AntaInventory Schema. @@ -187,7 +187,7 @@ def parse( insecure (bool): Disable SSH Host Key validation disable_cache (bool): Disable cache globally - Raises: + Raises ------ InventoryRootKeyError: Root key of inventory is missing. InventoryIncorrectSchemaError: Inventory file is not following AntaInventory Schema. @@ -255,7 +255,7 @@ def get_inventory(self, *, established_only: bool = False, tags: list[str] | Non established_only: Whether or not to include only established devices. Default False. tags: List of tags to filter devices. - Returns: + Returns ------- AntaInventory: An inventory with filtered AntaDevice objects. diff --git a/anta/models.py b/anta/models.py index 32ed6a5ee..3b2b49012 100644 --- a/anta/models.py +++ b/anta/models.py @@ -80,7 +80,7 @@ def render(self, **params: dict[str, Any]) -> AntaCommand: ---- params: dictionary of variables with string values to render the Python f-string - Returns: + Returns ------- command: The rendered AntaCommand. This AntaCommand instance have a template attribute that references this @@ -494,7 +494,7 @@ async def wrapper( This list must have the same length and order than the `instance_commands` instance attribute. kwargs: Any keyword argument to pass to the test. - Returns: + Returns ------- result: TestResult instance attribute populated with error status if any diff --git a/anta/reporter/__init__.py b/anta/reporter/__init__.py index 41926e887..3a32ba6c4 100644 --- a/anta/reporter/__init__.py +++ b/anta/reporter/__init__.py @@ -34,7 +34,7 @@ def _split_list_to_txt_list(self, usr_list: list[str], delimiter: str | None = N usr_list (list[str]): List of string to concatenate delimiter (str, optional): A delimiter to use to start string. Defaults to None. - Returns: + Returns ------- str: Multi-lines string @@ -53,7 +53,7 @@ def _build_headers(self, headers: list[str], table: Table) -> Table: headers (list[str]): List of headers table (Table): A rich Table instance - Returns: + Returns ------- Table: A rich Table instance with headers @@ -75,7 +75,7 @@ def _color_result(self, status: TestStatus) -> str: ---- status (TestStatus): status value to color - Returns: + Returns ------- str: the colored string @@ -101,7 +101,7 @@ def report_all( testcase (str, optional): A test name to search for. Defaults to None. title (str, optional): Title for the report. Defaults to 'All tests results'. - Returns: + Returns ------- Table: A fully populated rich Table @@ -135,7 +135,7 @@ def report_summary_tests( testcase (str, optional): A test name to search for. Defaults to None. title (str, optional): Title for the report. Defaults to 'All tests results'. - Returns: + Returns ------- Table: A fully populated rich Table @@ -185,7 +185,7 @@ def report_summary_hosts( host (str, optional): IP Address of a host to search for. Defaults to None. title (str, optional): Title for the report. Defaults to 'All tests results'. - Returns: + Returns ------- Table: A fully populated rich Table @@ -257,7 +257,7 @@ def render(self, data: list[dict[str, Any]], *, trim_blocks: bool = True, lstrip trim_blocks (bool, optional): enable trim_blocks for J2 rendering. Defaults to True. lstrip_blocks (bool, optional): enable lstrip_blocks for J2 rendering. Defaults to True. - Returns: + Returns ------- str: rendered template diff --git a/anta/result_manager/__init__.py b/anta/result_manager/__init__.py index 21e54984f..902eb2562 100644 --- a/anta/result_manager/__init__.py +++ b/anta/result_manager/__init__.py @@ -164,7 +164,7 @@ def get_result_by_test(self, test_name: str) -> list[TestResult]: ---- test_name (str): Test name to use to filter results - Returns: + Returns ------- list[TestResult]: List of results related to the test. @@ -178,7 +178,7 @@ def get_result_by_host(self, host_ip: str) -> list[TestResult]: ---- host_ip (str): IP Address of the host to use to filter results. - Returns: + Returns ------- list[TestResult]: List of results related to the host. diff --git a/anta/runner.py b/anta/runner.py index e7967b0ad..81cc55ad0 100644 --- a/anta/runner.py +++ b/anta/runner.py @@ -32,7 +32,7 @@ def log_cache_statistics(devices: list[AntaDevice]) -> None: ---- devices: List of devices in the inventory. - Returns: + Returns ------- None: Log the cache statistics for each device in the inventory. @@ -62,7 +62,7 @@ async def main(manager: ResultManager, inventory: AntaInventory, catalog: AntaCa tags: List of tags to filter devices from the inventory. Defaults to None. established_only: Include only established device(s). Defaults to True. - Returns: + Returns ------- any: ResultManager object gets updated with the test results. diff --git a/anta/tests/aaa.py b/anta/tests/aaa.py index 712cab3d0..3f2fb2ce3 100644 --- a/anta/tests/aaa.py +++ b/anta/tests/aaa.py @@ -20,9 +20,19 @@ class VerifyTacacsSourceIntf(AntaTest): """Verifies TACACS source-interface for a specified VRF. - Expected Results: - * Success: The test will pass if the provided TACACS source-interface is configured in the specified VRF. - * Failure: The test will fail if the provided TACACS source-interface is NOT configured in the specified VRF. + Expected Results + ---------------- + * Success: The test will pass if the provided TACACS source-interface is configured in the specified VRF. + * Failure: The test will fail if the provided TACACS source-interface is NOT configured in the specified VRF. + + Examples + -------- + ```yaml + anta.tests.aaa: + - VerifyTacacsSourceIntf: + intf: Management0 + vrf: MGMT + ``` """ name = "VerifyTacacsSourceIntf" @@ -54,9 +64,21 @@ def test(self) -> None: class VerifyTacacsServers(AntaTest): """Verifies TACACS servers are configured for a specified VRF. - Expected Results: - * Success: The test will pass if the provided TACACS servers are configured in the specified VRF. - * Failure: The test will fail if the provided TACACS servers are NOT configured in the specified VRF. + Expected Results + ---------------- + * Success: The test will pass if the provided TACACS servers are configured in the specified VRF. + * Failure: The test will fail if the provided TACACS servers are NOT configured in the specified VRF. + + Examples + -------- + ```yaml + anta.tests.aaa: + - VerifyTacacsServers: + servers: + - 10.10.10.21 + - 10.10.10.22 + vrf: MGMT + ``` """ name = "VerifyTacacsServers" @@ -96,9 +118,20 @@ def test(self) -> None: class VerifyTacacsServerGroups(AntaTest): """Verifies if the provided TACACS server group(s) are configured. - Expected Results: - * Success: The test will pass if the provided TACACS server group(s) are configured. - * Failure: The test will fail if one or all the provided TACACS server group(s) are NOT configured. + Expected Results + ---------------- + * Success: The test will pass if the provided TACACS server group(s) are configured. + * Failure: The test will fail if one or all the provided TACACS server group(s) are NOT configured. + + Examples + -------- + ```yaml + anta.tests.aaa: + - VerifyTacacsServerGroups: + groups: + - TACACS-GROUP1 + - TACACS-GROUP2 + ``` """ name = "VerifyTacacsServerGroups" @@ -130,9 +163,25 @@ def test(self) -> None: class VerifyAuthenMethods(AntaTest): """Verifies the AAA authentication method lists for different authentication types (login, enable, dot1x). - Expected Results: - * Success: The test will pass if the provided AAA authentication method list is matching in the configured authentication types. - * Failure: The test will fail if the provided AAA authentication method list is NOT matching in the configured authentication types. + Expected Results + ---------------- + * Success: The test will pass if the provided AAA authentication method list is matching in the configured authentication types. + * Failure: The test will fail if the provided AAA authentication method list is NOT matching in the configured authentication types. + + Examples + -------- + ```yaml + anta.tests.aaa: + - VerifyAuthenMethods: + methods: + - local + - none + - logging + types: + - login + - enable + - dot1x + ``` """ name = "VerifyAuthenMethods" @@ -176,9 +225,24 @@ def test(self) -> None: class VerifyAuthzMethods(AntaTest): """Verifies the AAA authorization method lists for different authorization types (commands, exec). - Expected Results: - * Success: The test will pass if the provided AAA authorization method list is matching in the configured authorization types. - * Failure: The test will fail if the provided AAA authorization method list is NOT matching in the configured authorization types. + Expected Results + ---------------- + * Success: The test will pass if the provided AAA authorization method list is matching in the configured authorization types. + * Failure: The test will fail if the provided AAA authorization method list is NOT matching in the configured authorization types. + + Examples + -------- + ```yaml + anta.tests.aaa: + - VerifyAuthzMethods: + methods: + - local + - none + - logging + types: + - commands + - exec + ``` """ name = "VerifyAuthzMethods" @@ -215,9 +279,26 @@ def test(self) -> None: class VerifyAcctDefaultMethods(AntaTest): """Verifies the AAA accounting default method lists for different accounting types (system, exec, commands, dot1x). - Expected Results: - * Success: The test will pass if the provided AAA accounting default method list is matching in the configured accounting types. - * Failure: The test will fail if the provided AAA accounting default method list is NOT matching in the configured accounting types. + Expected Results + ---------------- + * Success: The test will pass if the provided AAA accounting default method list is matching in the configured accounting types. + * Failure: The test will fail if the provided AAA accounting default method list is NOT matching in the configured accounting types. + + Examples + -------- + ```yaml + anta.tests.aaa: + - VerifyAcctDefaultMethods: + methods: + - local + - none + - logging + types: + - system + - exec + - commands + - dot1x + ``` """ name = "VerifyAcctDefaultMethods" @@ -261,9 +342,26 @@ def test(self) -> None: class VerifyAcctConsoleMethods(AntaTest): """Verifies the AAA accounting console method lists for different accounting types (system, exec, commands, dot1x). - Expected Results: - * Success: The test will pass if the provided AAA accounting console method list is matching in the configured accounting types. - * Failure: The test will fail if the provided AAA accounting console method list is NOT matching in the configured accounting types. + Expected Results + ---------------- + * Success: The test will pass if the provided AAA accounting console method list is matching in the configured accounting types. + * Failure: The test will fail if the provided AAA accounting console method list is NOT matching in the configured accounting types. + + Examples + -------- + ```yaml + anta.tests.aaa: + - VerifyAcctConsoleMethods: + methods: + - local + - none + - logging + types: + - system + - exec + - commands + - dot1x + ``` """ name = "VerifyAcctConsoleMethods" diff --git a/anta/tests/bfd.py b/anta/tests/bfd.py index 04bcdac67..d52871afc 100644 --- a/anta/tests/bfd.py +++ b/anta/tests/bfd.py @@ -24,9 +24,22 @@ class VerifyBFDSpecificPeers(AntaTest): """Verifies if the IPv4 BFD peer's sessions are UP and remote disc is non-zero in the specified VRF. - Expected results: - * Success: The test will pass if IPv4 BFD peers are up and remote disc is non-zero in the specified VRF. - * Failure: The test will fail if IPv4 BFD peers are not found, the status is not UP or remote disc is zero in the specified VRF. + Expected Results + ---------------- + * Success: The test will pass if IPv4 BFD peers are up and remote disc is non-zero in the specified VRF. + * Failure: The test will fail if IPv4 BFD peers are not found, the status is not UP or remote disc is zero in the specified VRF. + + Examples + -------- + ```yaml + anta.tests.bfd: + - VerifyBFDSpecificPeers: + bfd_peers: + - peer_address: 192.0.255.8 + vrf: default + - peer_address: 192.0.255.7 + vrf: default + ``` """ name = "VerifyBFDSpecificPeers" @@ -57,7 +70,11 @@ def test(self) -> None: for bfd_peer in self.inputs.bfd_peers: peer = str(bfd_peer.peer_address) vrf = bfd_peer.vrf - bfd_output = get_value(self.instance_commands[0].json_output, f"vrfs..{vrf}..ipv4Neighbors..{peer}..peerStats..", separator="..") + bfd_output = get_value( + self.instance_commands[0].json_output, + f"vrfs..{vrf}..ipv4Neighbors..{peer}..peerStats..", + separator="..", + ) # Check if BFD peer configured if not bfd_output: @@ -66,7 +83,12 @@ def test(self) -> None: # Check BFD peer status and remote disc if not (bfd_output.get("status") == "up" and bfd_output.get("remoteDisc") != 0): - failures[peer] = {vrf: {"status": bfd_output.get("status"), "remote_disc": bfd_output.get("remoteDisc")}} + failures[peer] = { + vrf: { + "status": bfd_output.get("status"), + "remote_disc": bfd_output.get("remoteDisc"), + } + } if not failures: self.result.is_success() @@ -77,9 +99,28 @@ def test(self) -> None: class VerifyBFDPeersIntervals(AntaTest): """Verifies the timers of the IPv4 BFD peers in the specified VRF. - Expected results: - * Success: The test will pass if the timers of the IPv4 BFD peers are correct in the specified VRF. - * Failure: The test will fail if the IPv4 BFD peers are not found or their timers are incorrect in the specified VRF. + Expected Results + ---------------- + * Success: The test will pass if the timers of the IPv4 BFD peers are correct in the specified VRF. + * Failure: The test will fail if the IPv4 BFD peers are not found or their timers are incorrect in the specified VRF. + + Examples + -------- + ```yaml + anta.tests.bfd: + - VerifyBFDPeersIntervals: + bfd_peers: + - peer_address: 192.0.255.8 + vrf: default + tx_interval: 1200 + rx_interval: 1200 + multiplier: 3 + - peer_address: 192.0.255.7 + vrf: default + tx_interval: 1200 + rx_interval: 1200 + multiplier: 3 + ``` """ name = "VerifyBFDPeersIntervals" @@ -121,7 +162,11 @@ def test(self) -> None: tx_interval = bfd_peers.tx_interval * 1000 rx_interval = bfd_peers.rx_interval * 1000 multiplier = bfd_peers.multiplier - bfd_output = get_value(self.instance_commands[0].json_output, f"vrfs..{vrf}..ipv4Neighbors..{peer}..peerStats..", separator="..") + bfd_output = get_value( + self.instance_commands[0].json_output, + f"vrfs..{vrf}..ipv4Neighbors..{peer}..peerStats..", + separator="..", + ) # Check if BFD peer configured if not bfd_output: @@ -157,18 +202,30 @@ class VerifyBFDPeersHealth(AntaTest): Optionally, it can also verify that BFD peers have not been down before a specified threshold of hours. - Expected results: - * Success: The test will pass if all IPv4 BFD peers are up, the discriminator value of each remote system is non-zero, - and the last downtime of each peer is above the defined threshold. - * Failure: The test will fail if any IPv4 BFD peer is down, the discriminator value of any remote system is zero, - or the last downtime of any peer is below the defined threshold. + Expected Results + ---------------- + * Success: The test will pass if all IPv4 BFD peers are up, the discriminator value of each remote system is non-zero, + and the last downtime of each peer is above the defined threshold. + * Failure: The test will fail if any IPv4 BFD peer is down, the discriminator value of any remote system is zero, + or the last downtime of any peer is below the defined threshold. + + Examples + -------- + ```yaml + anta.tests.bfd: + - VerifyBFDPeersHealth: + down_threshold: 2 + ``` """ name = "VerifyBFDPeersHealth" description = "Verifies the health of all IPv4 BFD peers." categories: ClassVar[list[str]] = ["bfd"] # revision 1 as later revision introduces additional nesting for type - commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show bfd peers", revision=1), AntaCommand(command="show clock")] + commands: ClassVar[list[AntaCommand | AntaTemplate]] = [ + AntaCommand(command="show bfd peers", revision=1), + AntaCommand(command="show clock"), + ] class Input(AntaTest.Input): """Input model for the VerifyBFDPeersHealth test.""" diff --git a/anta/tests/configuration.py b/anta/tests/configuration.py index 5d1af0c54..35d7b2b77 100644 --- a/anta/tests/configuration.py +++ b/anta/tests/configuration.py @@ -18,9 +18,17 @@ class VerifyZeroTouch(AntaTest): """Verifies ZeroTouch is disabled. - Expected Results: - * Success: The test will pass if ZeroTouch is disabled. - * Failure: The test will fail if ZeroTouch is enabled. + Expected Results + ---------------- + * Success: The test will pass if ZeroTouch is disabled. + * Failure: The test will fail if ZeroTouch is enabled. + + Examples + -------- + ```yaml + anta.tests.configuration: + - VerifyZeroTouch: + ``` """ name = "VerifyZeroTouch" @@ -41,10 +49,17 @@ def test(self) -> None: class VerifyRunningConfigDiffs(AntaTest): """Verifies there is no difference between the running-config and the startup-config. - Expected Results: - * Success: The test will pass if there is no difference between the running-config and the startup-config. - * Failure: The test will fail if there is a difference between the running-config and the startup-config. + Expected Results + ---------------- + * Success: The test will pass if there is no difference between the running-config and the startup-config. + * Failure: The test will fail if there is a difference between the running-config and the startup-config. + Examples + -------- + ```yaml + anta.tests.configuration: + - VerifyRunningConfigDiffs: + ``` """ name = "VerifyRunningConfigDiffs" diff --git a/anta/tests/connectivity.py b/anta/tests/connectivity.py index a14022ec0..8b383a404 100644 --- a/anta/tests/connectivity.py +++ b/anta/tests/connectivity.py @@ -19,9 +19,24 @@ class VerifyReachability(AntaTest): """Test network reachability to one or many destination IP(s). - Expected Results: - * Success: The test will pass if all destination IP(s) are reachable. - * Failure: The test will fail if one or many destination IP(s) are unreachable. + Expected Results + ---------------- + * Success: The test will pass if all destination IP(s) are reachable. + * Failure: The test will fail if one or many destination IP(s) are unreachable. + + Examples + -------- + ```yaml + anta.tests.connectivity: + - VerifyReachability: + hosts: + - source: Management0 + destination: 1.1.1.1 + vrf: MGMT + - source: Management0 + destination: 8.8.8.8 + vrf: MGMT + ``` """ name = "VerifyReachability" @@ -76,11 +91,26 @@ def test(self) -> None: class VerifyLLDPNeighbors(AntaTest): """Verifies that the provided LLDP neighbors are present and connected with the correct configuration. - Expected Results: - * Success: The test will pass if each of the provided LLDP neighbors is present and connected to the specified port and device. - * Failure: The test will fail if any of the following conditions are met: - - The provided LLDP neighbor is not found. - - The system name or port of the LLDP neighbor does not match the provided information. + Expected Results + ---------------- + * Success: The test will pass if each of the provided LLDP neighbors is present and connected to the specified port and device. + * Failure: The test will fail if any of the following conditions are met: + - The provided LLDP neighbor is not found. + - The system name or port of the LLDP neighbor does not match the provided information. + + Examples + -------- + ```yaml + anta.tests.connectivity: + - VerifyLLDPNeighbors: + neighbors: + - port: Ethernet1 + neighbor_device: DC1-SPINE1 + neighbor_port: Ethernet1 + - port: Ethernet2 + neighbor_device: DC1-SPINE2 + neighbor_port: Ethernet1 + ``` """ name = "VerifyLLDPNeighbors" diff --git a/anta/tests/field_notices.py b/anta/tests/field_notices.py index 167676523..db8a8bfa6 100644 --- a/anta/tests/field_notices.py +++ b/anta/tests/field_notices.py @@ -21,9 +21,17 @@ class VerifyFieldNotice44Resolution(AntaTest): Reference: https://www.arista.com/en/support/advisories-notices/field-notice/8756-field-notice-44 - Expected Results: - * Success: The test will pass if the device is using an Aboot version that fixes the bug discussed in the Field Notice 44. - * Failure: The test will fail if the device is not using an Aboot version that fixes the bug discussed in the Field Notice 44. + Expected Results + ---------------- + * Success: The test will pass if the device is using an Aboot version that fixes the bug discussed in the Field Notice 44. + * Failure: The test will fail if the device is not using an Aboot version that fixes the bug discussed in the Field Notice 44. + + Examples + -------- + ```yaml + anta.tests.field_notices: + - VerifyFieldNotice44Resolution: + ``` """ name = "VerifyFieldNotice44Resolution" @@ -117,9 +125,17 @@ class VerifyFieldNotice72Resolution(AntaTest): Reference: https://www.arista.com/en/support/advisories-notices/field-notice/17410-field-notice-0072 - Expected Results: - * Success: The test will pass if the device is not exposed to FN72 and the issue has been mitigated. - * Failure: The test will fail if the device is exposed to FN72 and the issue has not been mitigated. + Expected Results + ---------------- + * Success: The test will pass if the device is not exposed to FN72 and the issue has been mitigated. + * Failure: The test will fail if the device is exposed to FN72 and the issue has not been mitigated. + + Examples + -------- + ```yaml + anta.tests.field_notices: + - VerifyFieldNotice72Resolution: + ``` """ name = "VerifyFieldNotice72Resolution" diff --git a/anta/tests/greent.py b/anta/tests/greent.py index e0ebb3e09..b8b700420 100644 --- a/anta/tests/greent.py +++ b/anta/tests/greent.py @@ -16,9 +16,17 @@ class VerifyGreenTCounters(AntaTest): """Verifies if the GreenT (GRE Encapsulated Telemetry) counters are incremented. - Expected Results: - * Success: The test will pass if the GreenT counters are incremented. - * Failure: The test will fail if the GreenT counters are not incremented. + Expected Results + ---------------- + * Success: The test will pass if the GreenT counters are incremented. + * Failure: The test will fail if the GreenT counters are not incremented. + + Examples + -------- + ```yaml + anta.tests.greent: + - VerifyGreenT: + ``` """ name = "VerifyGreenTCounters" @@ -40,9 +48,17 @@ def test(self) -> None: class VerifyGreenT(AntaTest): """Verifies if a GreenT (GRE Encapsulated Telemetry) policy other than the default is created. - Expected Results: - * Success: The test will pass if a GreenT policy is created other than the default one. - * Failure: The test will fail if no other GreenT policy is created. + Expected Results + ---------------- + * Success: The test will pass if a GreenT policy is created other than the default one. + * Failure: The test will fail if no other GreenT policy is created. + + Examples + -------- + ```yaml + anta.tests.greent: + - VerifyGreenTCounters: + ``` """ name = "VerifyGreenT" diff --git a/anta/tests/hardware.py b/anta/tests/hardware.py index 51edf590c..cac13c86a 100644 --- a/anta/tests/hardware.py +++ b/anta/tests/hardware.py @@ -19,9 +19,21 @@ class VerifyTransceiversManufacturers(AntaTest): """Verifies if all the transceivers come from approved manufacturers. - Expected Results: - * Success: The test will pass if all transceivers are from approved manufacturers. - * Failure: The test will fail if some transceivers are from unapproved manufacturers. + Expected Results + ---------------- + * Success: The test will pass if all transceivers are from approved manufacturers. + * Failure: The test will fail if some transceivers are from unapproved manufacturers. + + Examples + -------- + ```yaml + anta.tests.hardware: + - VerifyTransceiversManufacturers: + manufacturers: + - Not Present + - Arista Networks + - Arastra, Inc. + ``` """ name = "VerifyTransceiversManufacturers" @@ -52,9 +64,17 @@ def test(self) -> None: class VerifyTemperature(AntaTest): """Verifies if the device temperature is within acceptable limits. - Expected Results: - * Success: The test will pass if the device temperature is currently OK: 'temperatureOk'. - * Failure: The test will fail if the device temperature is NOT OK. + Expected Results + ---------------- + * Success: The test will pass if the device temperature is currently OK: 'temperatureOk'. + * Failure: The test will fail if the device temperature is NOT OK. + + Examples + -------- + ```yaml + anta.tests.hardware: + - VerifyTemperature: + ``` """ name = "VerifyTemperature" @@ -77,9 +97,17 @@ def test(self) -> None: class VerifyTransceiversTemperature(AntaTest): """Verifies if all the transceivers are operating at an acceptable temperature. - Expected Results: - * Success: The test will pass if all transceivers status are OK: 'ok'. - * Failure: The test will fail if some transceivers are NOT OK. + Expected Results + ---------------- + * Success: The test will pass if all transceivers status are OK: 'ok'. + * Failure: The test will fail if some transceivers are NOT OK. + + Examples + -------- + ```yaml + anta.tests.hardware: + - VerifyTransceiversTemperature: + ``` """ name = "VerifyTransceiversTemperature" @@ -110,9 +138,17 @@ def test(self) -> None: class VerifyEnvironmentSystemCooling(AntaTest): """Verifies the device's system cooling status. - Expected Results: - * Success: The test will pass if the system cooling status is OK: 'coolingOk'. - * Failure: The test will fail if the system cooling status is NOT OK. + Expected Results + ---------------- + * Success: The test will pass if the system cooling status is OK: 'coolingOk'. + * Failure: The test will fail if the system cooling status is NOT OK. + + Examples + -------- + ```yaml + anta.tests.hardware: + - VerifyEnvironmentSystemCooling: + ``` """ name = "VerifyEnvironmentSystemCooling" @@ -134,9 +170,19 @@ def test(self) -> None: class VerifyEnvironmentCooling(AntaTest): """Verifies the status of power supply fans and all fan trays. - Expected Results: - * Success: The test will pass if the fans status are within the accepted states list. - * Failure: The test will fail if some fans status is not within the accepted states list. + Expected Results + ---------------- + * Success: The test will pass if the fans status are within the accepted states list. + * Failure: The test will fail if some fans status is not within the accepted states list. + + Examples + -------- + ```yaml + anta.tests.hardware: + - VerifyEnvironmentCooling: + states: + - ok + ``` """ name = "VerifyEnvironmentCooling" @@ -171,9 +217,19 @@ def test(self) -> None: class VerifyEnvironmentPower(AntaTest): """Verifies the power supplies status. - Expected Results: - * Success: The test will pass if the power supplies status are within the accepted states list. - * Failure: The test will fail if some power supplies status is not within the accepted states list. + Expected Results + ---------------- + * Success: The test will pass if the power supplies status are within the accepted states list. + * Failure: The test will fail if some power supplies status is not within the accepted states list. + + Examples + -------- + ```yaml + anta.tests.hardware: + - VerifyEnvironmentPower: + states: + - ok + ``` """ name = "VerifyEnvironmentPower" @@ -205,9 +261,17 @@ def test(self) -> None: class VerifyAdverseDrops(AntaTest): """Verifies there are no adverse drops on DCS-7280 and DCS-7500 family switches (Arad/Jericho chips). - Expected Results: - * Success: The test will pass if there are no adverse drops. - * Failure: The test will fail if there are adverse drops. + Expected Results + ---------------- + * Success: The test will pass if there are no adverse drops. + * Failure: The test will fail if there are adverse drops. + + Examples + -------- + ```yaml + anta.tests.hardware: + - VerifyAdverseDrops: + ``` """ name = "VerifyAdverseDrops" diff --git a/anta/tests/interfaces.py b/anta/tests/interfaces.py index 939ccea1a..88972dc9d 100644 --- a/anta/tests/interfaces.py +++ b/anta/tests/interfaces.py @@ -26,9 +26,18 @@ class VerifyInterfaceUtilization(AntaTest): Load interval (default to 5 minutes) is defined in device configuration. - Expected Results: - * Success: The test will pass if all interfaces have a usage below the threshold. - * Failure: The test will fail if one or more interfaces have a usage above the threshold. + Expected Results + ---------------- + * Success: The test will pass if all interfaces have a usage below the threshold. + * Failure: The test will fail if one or more interfaces have a usage above the threshold. + + Examples + -------- + ```yaml + anta.tests.interfaces: + - VerifyInterfaceUtilization: + threshold: 70.0 + ``` """ name = "VerifyInterfaceUtilization" @@ -79,9 +88,17 @@ def test(self) -> None: class VerifyInterfaceErrors(AntaTest): """Verifies that the interfaces error counters are equal to zero. - Expected Results: - * Success: The test will pass if all interfaces have error counters equal to zero. - * Failure: The test will fail if one or more interfaces have non-zero error counters. + Expected Results + ---------------- + * Success: The test will pass if all interfaces have error counters equal to zero. + * Failure: The test will fail if one or more interfaces have non-zero error counters. + + Examples + -------- + ```yaml + anta.tests.interfaces: + - VerifyInterfaceErrors: + ``` """ name = "VerifyInterfaceErrors" @@ -106,9 +123,17 @@ def test(self) -> None: class VerifyInterfaceDiscards(AntaTest): """Verifies that the interfaces packet discard counters are equal to zero. - Expected Results: - * Success: The test will pass if all interfaces have discard counters equal to zero. - * Failure: The test will fail if one or more interfaces have non-zero discard counters. + Expected Results + ---------------- + * Success: The test will pass if all interfaces have discard counters equal to zero. + * Failure: The test will fail if one or more interfaces have non-zero discard counters. + + Examples + -------- + ```yaml + anta.tests.interfaces: + - VerifyInterfaceDiscards: + ``` """ name = "VerifyInterfaceDiscards" @@ -132,9 +157,17 @@ def test(self) -> None: class VerifyInterfaceErrDisabled(AntaTest): """Verifies there are no interfaces in the errdisabled state. - Expected Results: - * Success: The test will pass if there are no interfaces in the errdisabled state. - * Failure: The test will fail if there is at least one interface in the errdisabled state. + Expected Results + ---------------- + * Success: The test will pass if there are no interfaces in the errdisabled state. + * Failure: The test will fail if there is at least one interface in the errdisabled state. + + Examples + -------- + ```yaml + anta.tests.interfaces: + - VerifyInterfaceErrDisabled: + ``` """ name = "VerifyInterfaceErrDisabled" @@ -160,9 +193,26 @@ class VerifyInterfacesStatus(AntaTest): - If line protocol status is not provided and interface status is "up", expect both status and line protocol to be "up" - If interface status is not "up", check only the interface status without considering line protocol status - Expected Results: - * Success: The test will pass if the provided interfaces are all in the expected state. - * Failure: The test will fail if any interface is not in the expected state. + Expected Results + ---------------- + * Success: The test will pass if the provided interfaces are all in the expected state. + * Failure: The test will fail if any interface is not in the expected state. + + Examples + -------- + ```yaml + anta.tests.interfaces: + - VerifyInterfacesStatus: + interfaces: + - name: Ethernet1 + status: up + - name: Port-Channel100 + status: down + line_protocol_status: lowerLayerDown + - name: Ethernet49/1 + status: adminDown + line_protocol_status: notPresent + ``` """ name = "VerifyInterfacesStatus" @@ -224,9 +274,17 @@ def test(self) -> None: class VerifyStormControlDrops(AntaTest): """Verifies there are no interface storm-control drop counters. - Expected Results: - * Success: The test will pass if there are no storm-control drop counters. - * Failure: The test will fail if there is at least one storm-control drop counter. + Expected Results + ---------------- + * Success: The test will pass if there are no storm-control drop counters. + * Failure: The test will fail if there is at least one storm-control drop counter. + + Examples + -------- + ```yaml + anta.tests.interfaces: + - VerifyStormControlDrops: + ``` """ name = "VerifyStormControlDrops" @@ -254,9 +312,17 @@ def test(self) -> None: class VerifyPortChannels(AntaTest): """Verifies there are no inactive ports in all port channels. - Expected Results: - * Success: The test will pass if there are no inactive ports in all port channels. - * Failure: The test will fail if there is at least one inactive port in a port channel. + Expected Results + ---------------- + * Success: The test will pass if there are no inactive ports in all port channels. + * Failure: The test will fail if there is at least one inactive port in a port channel. + + Examples + -------- + ```yaml + anta.tests.interfaces: + - VerifyPortChannels: + ``` """ name = "VerifyPortChannels" @@ -282,9 +348,17 @@ def test(self) -> None: class VerifyIllegalLACP(AntaTest): """Verifies there are no illegal LACP packets in all port channels. - Expected Results: - * Success: The test will pass if there are no illegal LACP packets received. - * Failure: The test will fail if there is at least one illegal LACP packet received. + Expected Results + ---------------- + * Success: The test will pass if there are no illegal LACP packets received. + * Failure: The test will fail if there is at least one illegal LACP packet received. + + Examples + -------- + ```yaml + anta.tests.interfaces: + - VerifyIllegalLACP: + ``` """ name = "VerifyIllegalLACP" @@ -310,9 +384,18 @@ def test(self) -> None: class VerifyLoopbackCount(AntaTest): """Verifies that the device has the expected number of loopback interfaces and all are operational. - Expected Results: - * Success: The test will pass if the device has the correct number of loopback interfaces and none are down. - * Failure: The test will fail if the loopback interface count is incorrect or any are non-operational. + Expected Results + ---------------- + * Success: The test will pass if the device has the correct number of loopback interfaces and none are down. + * Failure: The test will fail if the loopback interface count is incorrect or any are non-operational. + + Examples + -------- + ```yaml + anta.tests.interfaces: + - VerifyLoopbackCount: + number: 3 + ``` """ name = "VerifyLoopbackCount" @@ -351,9 +434,17 @@ def test(self) -> None: class VerifySVI(AntaTest): """Verifies the status of all SVIs. - Expected Results: - * Success: The test will pass if all SVIs are up. - * Failure: The test will fail if one or many SVIs are not up. + Expected Results + ---------------- + * Success: The test will pass if all SVIs are up. + * Failure: The test will fail if one or many SVIs are not up. + + Examples + -------- + ```yaml + anta.tests.interfaces: + - VerifySVI: + ``` """ name = "VerifySVI" @@ -383,9 +474,22 @@ class VerifyL3MTU(AntaTest): You can define a global MTU to check, or an MTU per interface and you can also ignored some interfaces. - Expected Results: - * Success: The test will pass if all layer 3 interfaces have the proper MTU configured. - * Failure: The test will fail if one or many layer 3 interfaces have the wrong MTU configured. + Expected Results + ---------------- + * Success: The test will pass if all layer 3 interfaces have the proper MTU configured. + * Failure: The test will fail if one or many layer 3 interfaces have the wrong MTU configured. + + Examples + -------- + ```yaml + anta.tests.interfaces: + - VerifyL3MTU: + mtu: 1500 + ignored_interfaces: + - Vxlan1 + specific_mtu: + - Ethernet1: 2500 + ``` """ name = "VerifyL3MTU" @@ -430,9 +534,20 @@ def test(self) -> None: class VerifyIPProxyARP(AntaTest): """Verifies if Proxy-ARP is enabled for the provided list of interface(s). - Expected Results: - * Success: The test will pass if Proxy-ARP is enabled on the specified interface(s). - * Failure: The test will fail if Proxy-ARP is disabled on the specified interface(s). + Expected Results + ---------------- + * Success: The test will pass if Proxy-ARP is enabled on the specified interface(s). + * Failure: The test will fail if Proxy-ARP is disabled on the specified interface(s). + + Examples + -------- + ```yaml + anta.tests.interfaces: + - VerifyIPProxyARP: + interfaces: + - Ethernet1 + - Ethernet2 + ``` """ name = "VerifyIPProxyARP" @@ -471,9 +586,23 @@ class VerifyL2MTU(AntaTest): Test that L2 interfaces are configured with the correct MTU. It supports Ethernet, Port Channel and VLAN interfaces. You can define a global MTU to check and also an MTU per interface and also ignored some interfaces. - Expected Results: - * Success: The test will pass if all layer 2 interfaces have the proper MTU configured. - * Failure: The test will fail if one or many layer 2 interfaces have the wrong MTU configured. + Expected Results + ---------------- + * Success: The test will pass if all layer 2 interfaces have the proper MTU configured. + * Failure: The test will fail if one or many layer 2 interfaces have the wrong MTU configured. + + Examples + -------- + ```yaml + anta.tests.interfaces: + - VerifyL2MTU: + mtu: 1500 + ignored_interfaces: + - Management1 + - Vxlan1 + specific_mtu: + - Ethernet1/1: 1500 + ``` """ name = "VerifyL2MTU" @@ -519,9 +648,23 @@ def test(self) -> None: class VerifyInterfaceIPv4(AntaTest): """Verifies if an interface is configured with a correct primary and list of optional secondary IPv4 addresses. - Expected Results: - * Success: The test will pass if an interface is configured with a correct primary and secondary IPv4 address. - * Failure: The test will fail if an interface is not found or the primary and secondary IPv4 addresses do not match with the input. + Expected Results + ---------------- + * Success: The test will pass if an interface is configured with a correct primary and secondary IPv4 address. + * Failure: The test will fail if an interface is not found or the primary and secondary IPv4 addresses do not match with the input. + + Examples + -------- + ```yaml + anta.tests.interfaces: + - VerifyInterfaceIPv4: + interfaces: + - name: Ethernet2 + primary_ip: 172.30.11.0/31 + secondary_ips: + - 10.10.10.0/31 + - 10.10.10.10/31 + ``` """ name = "VerifyInterfaceIPv4" @@ -600,9 +743,18 @@ def test(self) -> None: class VerifyIpVirtualRouterMac(AntaTest): """Verifies the IP virtual router MAC address. - Expected Results: - * Success: The test will pass if the IP virtual router MAC address matches the input. - * Failure: The test will fail if the IP virtual router MAC address does not match the input. + Expected Results + ---------------- + * Success: The test will pass if the IP virtual router MAC address matches the input. + * Failure: The test will fail if the IP virtual router MAC address does not match the input. + + Examples + -------- + ```yaml + anta.tests.interfaces: + - VerifyIpVirtualRouterMac: + mac_address: 00:1c:73:00:dc:01 + ``` """ name = "VerifyIpVirtualRouterMac" diff --git a/anta/tests/lanz.py b/anta/tests/lanz.py index 515b33819..8632acdd1 100644 --- a/anta/tests/lanz.py +++ b/anta/tests/lanz.py @@ -17,9 +17,17 @@ class VerifyLANZ(AntaTest): """Verifies if LANZ (Latency Analyzer) is enabled. - Expected results: - * Success: The test will pass if LANZ is enabled. - * Failure: The test will fail if LANZ is disabled. + Expected Results + ---------------- + * Success: The test will pass if LANZ is enabled. + * Failure: The test will fail if LANZ is disabled. + + Examples + -------- + ```yaml + anta.tests.lanz: + - VerifyLANZ: + ``` """ name = "VerifyLANZ" diff --git a/anta/tests/logging.py b/anta/tests/logging.py index 9e612025c..77ac2b35a 100644 --- a/anta/tests/logging.py +++ b/anta/tests/logging.py @@ -30,7 +30,7 @@ def _get_logging_states(logger: logging.Logger, command_output: str) -> str: logger: The logger object. command_output: The `show logging` output. - Returns: + Returns ------- str: The operational logging states. @@ -43,9 +43,17 @@ def _get_logging_states(logger: logging.Logger, command_output: str) -> str: class VerifyLoggingPersistent(AntaTest): """Verifies if logging persistent is enabled and logs are saved in flash. - Expected Results: - * Success: The test will pass if logging persistent is enabled and logs are in flash. - * Failure: The test will fail if logging persistent is disabled or no logs are saved in flash. + Expected Results + ---------------- + * Success: The test will pass if logging persistent is enabled and logs are in flash. + * Failure: The test will fail if logging persistent is disabled or no logs are saved in flash. + + Examples + -------- + ```yaml + anta.tests.logging: + - VerifyLoggingPersistent: + ``` """ name = "VerifyLoggingPersistent" @@ -74,9 +82,19 @@ def test(self) -> None: class VerifyLoggingSourceIntf(AntaTest): """Verifies logging source-interface for a specified VRF. - Expected Results: - * Success: The test will pass if the provided logging source-interface is configured in the specified VRF. - * Failure: The test will fail if the provided logging source-interface is NOT configured in the specified VRF. + Expected Results + ---------------- + * Success: The test will pass if the provided logging source-interface is configured in the specified VRF. + * Failure: The test will fail if the provided logging source-interface is NOT configured in the specified VRF. + + Examples + -------- + ```yaml + anta.tests.logging: + - VerifyLoggingSourceIntf: + interface: Management0 + vrf: default + ``` """ name = "VerifyLoggingSourceInt" @@ -106,9 +124,21 @@ def test(self) -> None: class VerifyLoggingHosts(AntaTest): """Verifies logging hosts (syslog servers) for a specified VRF. - Expected Results: - * Success: The test will pass if the provided syslog servers are configured in the specified VRF. - * Failure: The test will fail if the provided syslog servers are NOT configured in the specified VRF. + Expected Results + ---------------- + * Success: The test will pass if the provided syslog servers are configured in the specified VRF. + * Failure: The test will fail if the provided syslog servers are NOT configured in the specified VRF. + + Examples + -------- + ```yaml + anta.tests.logging: + - VerifyLoggingHosts: + hosts: + - 1.1.1.1 + - 2.2.2.2 + vrf: default + ``` """ name = "VerifyLoggingHosts" @@ -143,9 +173,17 @@ def test(self) -> None: class VerifyLoggingLogsGeneration(AntaTest): """Verifies if logs are generated. - Expected Results: - * Success: The test will pass if logs are generated. - * Failure: The test will fail if logs are NOT generated. + Expected Results + ---------------- + * Success: The test will pass if logs are generated. + * Failure: The test will fail if logs are NOT generated. + + Examples + -------- + ```yaml + anta.tests.logging: + - VerifyLoggingLogsGeneration: + ``` """ name = "VerifyLoggingLogsGeneration" @@ -172,9 +210,17 @@ def test(self) -> None: class VerifyLoggingHostname(AntaTest): """Verifies if logs are generated with the device FQDN. - Expected Results: - * Success: The test will pass if logs are generated with the device FQDN. - * Failure: The test will fail if logs are NOT generated with the device FQDN. + Expected Results + ---------------- + * Success: The test will pass if logs are generated with the device FQDN. + * Failure: The test will fail if logs are NOT generated with the device FQDN. + + Examples + -------- + ```yaml + anta.tests.logging: + - VerifyLoggingHostname: + ``` """ name = "VerifyLoggingHostname" @@ -208,9 +254,17 @@ def test(self) -> None: class VerifyLoggingTimestamp(AntaTest): """Verifies if logs are generated with the approprate timestamp. - Expected Results: - * Success: The test will pass if logs are generated with the appropriated timestamp. - * Failure: The test will fail if logs are NOT generated with the appropriated timestamp. + Expected Results + ---------------- + * Success: The test will pass if logs are generated with the appropriated timestamp. + * Failure: The test will fail if logs are NOT generated with the appropriated timestamp. + + Examples + -------- + ```yaml + anta.tests.logging: + - VerifyLoggingTimestamp: + ``` """ name = "VerifyLoggingTimestamp" @@ -242,9 +296,17 @@ def test(self) -> None: class VerifyLoggingAccounting(AntaTest): """Verifies if AAA accounting logs are generated. - Expected Results: - * Success: The test will pass if AAA accounting logs are generated. - * Failure: The test will fail if AAA accounting logs are NOT generated. + Expected Results + ---------------- + * Success: The test will pass if AAA accounting logs are generated. + * Failure: The test will fail if AAA accounting logs are NOT generated. + + Examples + -------- + ```yaml + anta.tests.logging: + - VerifyLoggingAccounting: + ``` """ name = "VerifyLoggingAccounting" @@ -266,9 +328,17 @@ def test(self) -> None: class VerifyLoggingErrors(AntaTest): """Verifies there are no syslog messages with a severity of ERRORS or higher. - Expected Results: + Expected Results + ---------------- * Success: The test will pass if there are NO syslog messages with a severity of ERRORS or higher. * Failure: The test will fail if ERRORS or higher syslog messages are present. + + Examples + -------- + ```yaml + anta.tests.logging: + - VerifyLoggingErrors: + ``` """ name = "VerifyLoggingErrors" diff --git a/anta/tests/mlag.py b/anta/tests/mlag.py index 1d0229281..eb5066f15 100644 --- a/anta/tests/mlag.py +++ b/anta/tests/mlag.py @@ -20,12 +20,20 @@ class VerifyMlagStatus(AntaTest): """Verifies the health status of the MLAG configuration. - Expected Results: - * Success: The test will pass if the MLAG state is 'active', negotiation status is 'connected', + Expected Results + ---------------- + * Success: The test will pass if the MLAG state is 'active', negotiation status is 'connected', peer-link status and local interface status are 'up'. - * Failure: The test will fail if the MLAG state is not 'active', negotiation status is not 'connected', + * Failure: The test will fail if the MLAG state is not 'active', negotiation status is not 'connected', peer-link status or local interface status are not 'up'. - * Skipped: The test will be skipped if MLAG is 'disabled'. + * Skipped: The test will be skipped if MLAG is 'disabled'. + + Examples + -------- + ```yaml + anta.tests.mlag: + - VerifyMlagStatus: + ``` """ name = "VerifyMlagStatus" @@ -56,10 +64,18 @@ def test(self) -> None: class VerifyMlagInterfaces(AntaTest): """Verifies there are no inactive or active-partial MLAG ports. - Expected Results: - * Success: The test will pass if there are NO inactive or active-partial MLAG ports. - * Failure: The test will fail if there are inactive or active-partial MLAG ports. - * Skipped: The test will be skipped if MLAG is 'disabled'. + Expected Results + ---------------- + * Success: The test will pass if there are NO inactive or active-partial MLAG ports. + * Failure: The test will fail if there are inactive or active-partial MLAG ports. + * Skipped: The test will be skipped if MLAG is 'disabled'. + + Examples + -------- + ```yaml + anta.tests.mlag: + - VerifyMlagInterfaces: + ``` """ name = "VerifyMlagInterfaces" @@ -83,11 +99,19 @@ def test(self) -> None: class VerifyMlagConfigSanity(AntaTest): """Verifies there are no MLAG config-sanity inconsistencies. - Expected Results: - * Success: The test will pass if there are NO MLAG config-sanity inconsistencies. - * Failure: The test will fail if there are MLAG config-sanity inconsistencies. - * Skipped: The test will be skipped if MLAG is 'disabled'. - * Error: The test will give an error if 'mlagActive' is not found in the JSON response. + Expected Results + ---------------- + * Success: The test will pass if there are NO MLAG config-sanity inconsistencies. + * Failure: The test will fail if there are MLAG config-sanity inconsistencies. + * Skipped: The test will be skipped if MLAG is 'disabled'. + * Error: The test will give an error if 'mlagActive' is not found in the JSON response. + + Examples + -------- + ```yaml + anta.tests.mlag: + - VerifyMlagConfigSanity: + ``` """ name = "VerifyMlagConfigSanity" @@ -116,10 +140,20 @@ def test(self) -> None: class VerifyMlagReloadDelay(AntaTest): """Verifies the reload-delay parameters of the MLAG configuration. - Expected Results: - * Success: The test will pass if the reload-delay parameters are configured properly. - * Failure: The test will fail if the reload-delay parameters are NOT configured properly. - * Skipped: The test will be skipped if MLAG is 'disabled'. + Expected Results + ---------------- + * Success: The test will pass if the reload-delay parameters are configured properly. + * Failure: The test will fail if the reload-delay parameters are NOT configured properly. + * Skipped: The test will be skipped if MLAG is 'disabled'. + + Examples + -------- + ```yaml + anta.tests.mlag: + - VerifyMlagReloadDelay: + reload_delay: 300 + reload_delay_non_mlag: 330 + ``` """ name = "VerifyMlagReloadDelay" @@ -154,10 +188,22 @@ def test(self) -> None: class VerifyMlagDualPrimary(AntaTest): """Verifies the dual-primary detection and its parameters of the MLAG configuration. - Expected Results: - * Success: The test will pass if the dual-primary detection is enabled and its parameters are configured properly. - * Failure: The test will fail if the dual-primary detection is NOT enabled or its parameters are NOT configured properly. - * Skipped: The test will be skipped if MLAG is 'disabled'. + Expected Results + ---------------- + * Success: The test will pass if the dual-primary detection is enabled and its parameters are configured properly. + * Failure: The test will fail if the dual-primary detection is NOT enabled or its parameters are NOT configured properly. + * Skipped: The test will be skipped if MLAG is 'disabled'. + + Examples + -------- + ```yaml + anta.tests.mlag: + - VerifyMlagDualPrimary: + detection_delay: 200 + errdisabled: True + recovery_delay: 60 + recovery_delay_non_mlag: 0 + ``` """ name = "VerifyMlagDualPrimary" @@ -204,10 +250,19 @@ def test(self) -> None: class VerifyMlagPrimaryPriority(AntaTest): """Verify the MLAG (Multi-Chassis Link Aggregation) primary priority. - Expected Results: - * Success: The test will pass if the MLAG state is set as 'primary' and the priority matches the input. - * Failure: The test will fail if the MLAG state is not 'primary' or the priority doesn't match the input. - * Skipped: The test will be skipped if MLAG is 'disabled'. + Expected Results + ---------------- + * Success: The test will pass if the MLAG state is set as 'primary' and the priority matches the input. + * Failure: The test will fail if the MLAG state is not 'primary' or the priority doesn't match the input. + * Skipped: The test will be skipped if MLAG is 'disabled'. + + Examples + -------- + ```yaml + anta.tests.mlag: + - VerifyMlagPrimaryPriority: + primary_priority: 3276 + ``` """ name = "VerifyMlagPrimaryPriority" diff --git a/anta/tests/multicast.py b/anta/tests/multicast.py index e98104a18..35f4d3e68 100644 --- a/anta/tests/multicast.py +++ b/anta/tests/multicast.py @@ -19,9 +19,20 @@ class VerifyIGMPSnoopingVlans(AntaTest): """Verifies the IGMP snooping status for the provided VLANs. - Expected Results: - * Success: The test will pass if the IGMP snooping status matches the expected status for the provided VLANs. - * Failure: The test will fail if the IGMP snooping status does not match the expected status for the provided VLANs. + Expected Results + ---------------- + * Success: The test will pass if the IGMP snooping status matches the expected status for the provided VLANs. + * Failure: The test will fail if the IGMP snooping status does not match the expected status for the provided VLANs. + + Examples + -------- + ```yaml + anta.tests.multicast: + - VerifyIGMPSnoopingVlans: + vlans: + 10: False + 12: False + ``` """ name = "VerifyIGMPSnoopingVlans" @@ -53,9 +64,18 @@ def test(self) -> None: class VerifyIGMPSnoopingGlobal(AntaTest): """Verifies the IGMP snooping global status. - Expected Results: - * Success: The test will pass if the IGMP snooping global status matches the expected status. - * Failure: The test will fail if the IGMP snooping global status does not match the expected status. + Expected Results + ---------------- + * Success: The test will pass if the IGMP snooping global status matches the expected status. + * Failure: The test will fail if the IGMP snooping global status does not match the expected status. + + Examples + -------- + ```yaml + anta.tests.multicast: + - VerifyIGMPSnoopingGlobal: + enabled: True + ``` """ name = "VerifyIGMPSnoopingGlobal" diff --git a/anta/tests/profiles.py b/anta/tests/profiles.py index 827f5fac6..54fc0b7aa 100644 --- a/anta/tests/profiles.py +++ b/anta/tests/profiles.py @@ -19,9 +19,18 @@ class VerifyUnifiedForwardingTableMode(AntaTest): """Verifies the device is using the expected UFT (Unified Forwarding Table) mode. - Expected Results: - * Success: The test will pass if the device is using the expected UFT mode. - * Failure: The test will fail if the device is not using the expected UFT mode. + Expected Results + ---------------- + * Success: The test will pass if the device is using the expected UFT mode. + * Failure: The test will fail if the device is not using the expected UFT mode. + + Examples + -------- + ```yaml + anta.tests.profiles: + - VerifyUnifiedForwardingTableMode: + mode: 3 + ``` """ name = "VerifyUnifiedForwardingTableMode" @@ -49,9 +58,18 @@ def test(self) -> None: class VerifyTcamProfile(AntaTest): """Verifies that the device is using the provided Ternary Content-Addressable Memory (TCAM) profile. - Expected Results: - * Success: The test will pass if the provided TCAM profile is actually running on the device. - * Failure: The test will fail if the provided TCAM profile is not running on the device. + Expected Results + ---------------- + * Success: The test will pass if the provided TCAM profile is actually running on the device. + * Failure: The test will fail if the provided TCAM profile is not running on the device. + + Examples + -------- + ```yaml + anta.tests.profiles: + - VerifyTcamProfile: + profile: vxlan-routing + ``` """ name = "VerifyTcamProfile" diff --git a/anta/tests/ptp.py b/anta/tests/ptp.py index 1f354cbf0..4c2c99091 100644 --- a/anta/tests/ptp.py +++ b/anta/tests/ptp.py @@ -19,10 +19,18 @@ class VerifyPtpModeStatus(AntaTest): """Verifies that the device is configured as a Precision Time Protocol (PTP) Boundary Clock (BC). - Expected Results: - * Success: The test will pass if the device is a BC. - * Failure: The test will fail if the device is not a BC. - * Error: The test will error if the 'ptpMode' variable is not present in the command output. + Expected Results + ---------------- + * Success: The test will pass if the device is a BC. + * Failure: The test will fail if the device is not a BC. + * Error: The test will error if the 'ptpMode' variable is not present in the command output. + + Examples + -------- + ```yaml + anta.tests.ptp: + - VerifyPtpModeStatus: + ``` """ name = "VerifyPtpModeStatus" @@ -51,10 +59,19 @@ class VerifyPtpGMStatus(AntaTest): To test PTP failover, re-run the test with a secondary GMID configured. - Expected Results: - * Success: The test will pass if the device is locked to the provided Grandmaster. - * Failure: The test will fail if the device is not locked to the provided Grandmaster. - * Error: The test will error if the 'gmClockIdentity' variable is not present in the command output. + Expected Results + ---------------- + * Success: The test will pass if the device is locked to the provided Grandmaster. + * Failure: The test will fail if the device is not locked to the provided Grandmaster. + * Error: The test will error if the 'gmClockIdentity' variable is not present in the command output. + + Examples + -------- + ```yaml + anta.tests.ptp: + - VerifyPtpGMStatus: + gmid: 0xec:46:70:ff:fe:00:ff:a9 + ``` """ class Input(AntaTest.Input): @@ -89,10 +106,18 @@ def test(self) -> None: class VerifyPtpLockStatus(AntaTest): """Verifies that the device was locked to the upstream Precision Time Protocol (PTP) Grandmaster (GM) in the last minute. - Expected Results: - * Success: The test will pass if the device was locked to the upstream GM in the last minute. - * Failure: The test will fail if the device was not locked to the upstream GM in the last minute. - * Error: The test will error if the 'lastSyncTime' variable is not present in the command output. + Expected Results + ---------------- + * Success: The test will pass if the device was locked to the upstream GM in the last minute. + * Failure: The test will fail if the device was not locked to the upstream GM in the last minute. + * Error: The test will error if the 'lastSyncTime' variable is not present in the command output. + + Examples + -------- + ```yaml + anta.tests.ptp: + - VerifyPtpLockStatus: + ``` """ name = "VerifyPtpLockStatus" @@ -122,10 +147,18 @@ def test(self) -> None: class VerifyPtpOffset(AntaTest): """Verifies that the Precision Time Protocol (PTP) timing offset is within +/- 1000ns from the master clock. - Expected Results: - * Success: The test will pass if the PTP timing offset is within +/- 1000ns from the master clock. - * Failure: The test will fail if the PTP timing offset is greater than +/- 1000ns from the master clock. - * Skipped: The test will be skipped if PTP is not configured. + Expected Results + ---------------- + * Success: The test will pass if the PTP timing offset is within +/- 1000ns from the master clock. + * Failure: The test will fail if the PTP timing offset is greater than +/- 1000ns from the master clock. + * Skipped: The test will be skipped if PTP is not configured. + + Examples + -------- + ```yaml + anta.tests.ptp: + - VerifyPtpOffset: + ``` """ name = "VerifyPtpOffset" @@ -160,9 +193,17 @@ class VerifyPtpPortModeStatus(AntaTest): The interfaces can be in one of the following state: Master, Slave, Passive, or Disabled. - Expected Results: - * Success: The test will pass if all PTP enabled interfaces are in a valid state. - * Failure: The test will fail if there are no PTP enabled interfaces or if some interfaces are not in a valid state. + Expected Results + ---------------- + * Success: The test will pass if all PTP enabled interfaces are in a valid state. + * Failure: The test will fail if there are no PTP enabled interfaces or if some interfaces are not in a valid state. + + Examples + -------- + ```yaml + anta.tests.ptp: + - VerifyPtpPortModeStatus: + ``` """ name = "VerifyPtpPortModeStatus" diff --git a/anta/tests/routing/bgp.py b/anta/tests/routing/bgp.py index bfb5b0110..e38e061e1 100644 --- a/anta/tests/routing/bgp.py +++ b/anta/tests/routing/bgp.py @@ -68,11 +68,11 @@ def _check_peer_issues(peer_data: dict[str, Any] | None) -> dict[str, Any]: ---- peer_data (dict, optional): The BGP peer data dictionary nested in the `show bgp summary` command. - Returns: + Returns ------- dict: Dictionary with keys indicating issues or an empty dictionary if no issues. - Raises: + Raises ------ ValueError: If any of the required keys ("peerState", "inMsgQueue", "outMsgQueue") are missing in `peer_data`, i.e. invalid BGP peer data. @@ -117,7 +117,7 @@ def _add_bgp_routes_failure( 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'. - Returns: + Returns ------- dict[str, dict[str, dict[str, dict[str, list[str]]]]]: A dictionary containing the missing routes and invalid or inactive routes. @@ -158,9 +158,33 @@ class VerifyBGPPeerCount(AntaTest): 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" @@ -278,9 +302,26 @@ class VerifyBGPPeersHealth(AntaTest): 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" @@ -400,9 +441,30 @@ class VerifyBGPSpecificPeers(AntaTest): 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" @@ -521,9 +583,32 @@ class VerifyBGPExchangedRoutes(AntaTest): 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" @@ -596,9 +681,23 @@ def test(self) -> None: 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. + 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" @@ -668,9 +767,21 @@ def test(self) -> None: 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. + 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" @@ -734,9 +845,21 @@ def test(self) -> None: 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. + 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" @@ -800,9 +923,23 @@ def test(self) -> None: 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. + 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" @@ -861,9 +998,23 @@ def test(self) -> None: class VerifyEVPNType2Route(AntaTest): """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. + 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" @@ -924,9 +1075,23 @@ def test(self) -> None: 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. + 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" @@ -983,9 +1148,27 @@ def test(self) -> None: 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. + 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" diff --git a/anta/tests/routing/generic.py b/anta/tests/routing/generic.py index 3f76c3b1e..220554190 100644 --- a/anta/tests/routing/generic.py +++ b/anta/tests/routing/generic.py @@ -18,9 +18,19 @@ class VerifyRoutingProtocolModel(AntaTest): """Verifies the configured routing protocol model is the one we expect. - Expected Results: - * Success: The test will pass if the configured routing protocol model is the one we expect. - * Failure: The test will fail if the configured routing protocol model is not the one we expect. + Expected Results + ---------------- + * Success: The test will pass if the configured routing protocol model is the one we expect. + * Failure: The test will fail if the configured routing protocol model is not the one we expect. + + Examples + -------- + ```yaml + anta.tests.routing: + generic: + - VerifyRoutingProtocolModel: + model: multi-agent + ``` """ name = "VerifyRoutingProtocolModel" @@ -49,9 +59,20 @@ def test(self) -> None: class VerifyRoutingTableSize(AntaTest): """Verifies the size of the IP routing table of the default VRF. - Expected Results: - * Success: The test will pass if the routing table size is between the provided minimum and maximum values. - * Failure: The test will fail if the routing table size is not between the provided minimum and maximum values. + Expected Results + ---------------- + * Success: The test will pass if the routing table size is between the provided minimum and maximum values. + * Failure: The test will fail if the routing table size is not between the provided minimum and maximum values. + + Examples + -------- + ```yaml + anta.tests.routing: + generic: + - VerifyRoutingTableSize: + minimum: 2 + maximum: 20 + ``` """ name = "VerifyRoutingTableSize" @@ -89,9 +110,22 @@ def test(self) -> None: class VerifyRoutingTableEntry(AntaTest): """Verifies that the provided routes are present in the routing table of a specified VRF. - Expected Results: - * Success: The test will pass if the provided routes are present in the routing table. - * Failure: The test will fail if one or many provided routes are missing from the routing table. + Expected Results + ---------------- + * Success: The test will pass if the provided routes are present in the routing table. + * Failure: The test will fail if one or many provided routes are missing from the routing table. + + Examples + -------- + ```yaml + anta.tests.routing: + generic: + - VerifyRoutingTableEntry: + vrf: default + routes: + - 10.1.0.1 + - 10.1.0.2 + ``` """ name = "VerifyRoutingTableEntry" diff --git a/anta/tests/routing/ospf.py b/anta/tests/routing/ospf.py index a6d7539a8..38ba26958 100644 --- a/anta/tests/routing/ospf.py +++ b/anta/tests/routing/ospf.py @@ -22,7 +22,7 @@ def _count_ospf_neighbor(ospf_neighbor_json: dict[str, Any]) -> int: ---- ospf_neighbor_json (dict[str, Any]): The JSON output of the `show ip ospf neighbor` command. - Returns: + Returns ------- int: The number of OSPF neighbors. @@ -41,7 +41,7 @@ def _get_not_full_ospf_neighbors(ospf_neighbor_json: dict[str, Any]) -> list[dic ---- ospf_neighbor_json (dict[str, Any]): The JSON output of the `show ip ospf neighbor` command. - Returns: + Returns ------- list[dict[str, Any]]: A list of OSPF neighbors whose adjacency state is not `full`. @@ -63,10 +63,19 @@ def _get_not_full_ospf_neighbors(ospf_neighbor_json: dict[str, Any]) -> list[dic class VerifyOSPFNeighborState(AntaTest): """Verifies all OSPF neighbors are in FULL state. - Expected Results: - * Success: The test will pass if all OSPF neighbors are in FULL state. - * Failure: The test will fail if some OSPF neighbors are not in FULL state. - * Skipped: The test will be skipped if no OSPF neighbor is found. + Expected Results + ---------------- + * Success: The test will pass if all OSPF neighbors are in FULL state. + * Failure: The test will fail if some OSPF neighbors are not in FULL state. + * Skipped: The test will be skipped if no OSPF neighbor is found. + + Examples + -------- + ```yaml + anta.tests.routing: + ospf: + - VerifyOSPFNeighborState: + ``` """ name = "VerifyOSPFNeighborState" @@ -90,10 +99,20 @@ def test(self) -> None: class VerifyOSPFNeighborCount(AntaTest): """Verifies the number of OSPF neighbors in FULL state is the one we expect. - Expected Results: - * Success: The test will pass if the number of OSPF neighbors in FULL state is the one we expect. - * Failure: The test will fail if the number of OSPF neighbors in FULL state is not the one we expect. - * Skipped: The test will be skipped if no OSPF neighbor is found. + Expected Results + ---------------- + * Success: The test will pass if the number of OSPF neighbors in FULL state is the one we expect. + * Failure: The test will fail if the number of OSPF neighbors in FULL state is not the one we expect. + * Skipped: The test will be skipped if no OSPF neighbor is found. + + Examples + -------- + ```yaml + anta.tests.routing: + ospf: + - VerifyOSPFNeighborCount: + number: 3 + ``` """ name = "VerifyOSPFNeighborCount" diff --git a/anta/tests/security.py b/anta/tests/security.py index 9e411a06f..be90a2452 100644 --- a/anta/tests/security.py +++ b/anta/tests/security.py @@ -22,9 +22,17 @@ class VerifySSHStatus(AntaTest): """Verifies if the SSHD agent is disabled in the default VRF. - Expected Results: - * Success: The test will pass if the SSHD agent is disabled in the default VRF. - * Failure: The test will fail if the SSHD agent is NOT disabled in the default VRF. + Expected Results + ---------------- + * Success: The test will pass if the SSHD agent is disabled in the default VRF. + * Failure: The test will fail if the SSHD agent is NOT disabled in the default VRF. + + Examples + -------- + ```yaml + anta.tests.security: + - VerifySSHStatus: + ``` """ name = "VerifySSHStatus" @@ -49,9 +57,19 @@ def test(self) -> None: class VerifySSHIPv4Acl(AntaTest): """Verifies if the SSHD agent has the right number IPv4 ACL(s) configured for a specified VRF. - Expected results: - * Success: The test will pass if the SSHD agent has the provided number of IPv4 ACL(s) in the specified VRF. - * Failure: The test will fail if the SSHD agent has not the right number of IPv4 ACL(s) in the specified VRF. + Expected Results + ---------------- + * Success: The test will pass if the SSHD agent has the provided number of IPv4 ACL(s) in the specified VRF. + * Failure: The test will fail if the SSHD agent has not the right number of IPv4 ACL(s) in the specified VRF. + + Examples + -------- + ```yaml + anta.tests.security: + - VerifySSHIPv4Acl: + number: 3 + vrf: default + ``` """ name = "VerifySSHIPv4Acl" @@ -88,9 +106,19 @@ def test(self) -> None: class VerifySSHIPv6Acl(AntaTest): """Verifies if the SSHD agent has the right number IPv6 ACL(s) configured for a specified VRF. - Expected results: - * Success: The test will pass if the SSHD agent has the provided number of IPv6 ACL(s) in the specified VRF. - * Failure: The test will fail if the SSHD agent has not the right number of IPv6 ACL(s) in the specified VRF. + Expected Results + ---------------- + * Success: The test will pass if the SSHD agent has the provided number of IPv6 ACL(s) in the specified VRF. + * Failure: The test will fail if the SSHD agent has not the right number of IPv6 ACL(s) in the specified VRF. + + Examples + -------- + ```yaml + anta.tests.security: + - VerifySSHIPv6Acl: + number: 3 + vrf: default + ``` """ name = "VerifySSHIPv6Acl" @@ -127,9 +155,17 @@ def test(self) -> None: class VerifyTelnetStatus(AntaTest): """Verifies if Telnet is disabled in the default VRF. - Expected Results: - * Success: The test will pass if Telnet is disabled in the default VRF. - * Failure: The test will fail if Telnet is NOT disabled in the default VRF. + Expected Results + ---------------- + * Success: The test will pass if Telnet is disabled in the default VRF. + * Failure: The test will fail if Telnet is NOT disabled in the default VRF. + + Examples + -------- + ```yaml + anta.tests.security: + - VerifyTelnetStatus: + ``` """ name = "VerifyTelnetStatus" @@ -150,9 +186,17 @@ def test(self) -> None: class VerifyAPIHttpStatus(AntaTest): """Verifies if eAPI HTTP server is disabled globally. - Expected Results: - * Success: The test will pass if eAPI HTTP server is disabled globally. - * Failure: The test will fail if eAPI HTTP server is NOT disabled globally. + Expected Results + ---------------- + * Success: The test will pass if eAPI HTTP server is disabled globally. + * Failure: The test will fail if eAPI HTTP server is NOT disabled globally. + + Examples + -------- + ```yaml + anta.tests.security: + - VerifyAPIHttpStatus: + ``` """ name = "VerifyAPIHttpStatus" @@ -173,9 +217,18 @@ def test(self) -> None: class VerifyAPIHttpsSSL(AntaTest): """Verifies if eAPI HTTPS server SSL profile is configured and valid. - Expected results: - * Success: The test will pass if the eAPI HTTPS server SSL profile is configured and valid. - * Failure: The test will fail if the eAPI HTTPS server SSL profile is NOT configured, misconfigured or invalid. + Expected Results + ---------------- + * Success: The test will pass if the eAPI HTTPS server SSL profile is configured and valid. + * Failure: The test will fail if the eAPI HTTPS server SSL profile is NOT configured, misconfigured or invalid. + + Examples + -------- + ```yaml + anta.tests.security: + - VerifyAPIHttpsSSL: + profile: default + ``` """ name = "VerifyAPIHttpsSSL" @@ -206,9 +259,19 @@ def test(self) -> None: class VerifyAPIIPv4Acl(AntaTest): """Verifies if eAPI has the right number IPv4 ACL(s) configured for a specified VRF. - Expected results: - * Success: The test will pass if eAPI has the provided number of IPv4 ACL(s) in the specified VRF. - * Failure: The test will fail if eAPI has not the right number of IPv4 ACL(s) in the specified VRF. + Expected Results + ---------------- + * Success: The test will pass if eAPI has the provided number of IPv4 ACL(s) in the specified VRF. + * Failure: The test will fail if eAPI has not the right number of IPv4 ACL(s) in the specified VRF. + + Examples + -------- + ```yaml + anta.tests.security: + - VerifyAPIIPv4Acl: + number: 3 + vrf: default + ``` """ name = "VerifyAPIIPv4Acl" @@ -245,10 +308,20 @@ def test(self) -> None: class VerifyAPIIPv6Acl(AntaTest): """Verifies if eAPI has the right number IPv6 ACL(s) configured for a specified VRF. - Expected results: - * Success: The test will pass if eAPI has the provided number of IPv6 ACL(s) in the specified VRF. - * Failure: The test will fail if eAPI has not the right number of IPv6 ACL(s) in the specified VRF. - * skipped: The test will be skipped if the number of IPv6 ACL(s) or VRF parameter is not provided. + Expected Results + ---------------- + * Success: The test will pass if eAPI has the provided number of IPv6 ACL(s) in the specified VRF. + * Failure: The test will fail if eAPI has not the right number of IPv6 ACL(s) in the specified VRF. + * Skipped: The test will be skipped if the number of IPv6 ACL(s) or VRF parameter is not provided. + + Examples + -------- + ```yaml + anta.tests.security: + - VerifyAPIIPv6Acl: + number: 3 + vrf: default + ``` """ name = "VerifyAPIIPv6Acl" @@ -285,11 +358,30 @@ def test(self) -> None: class VerifyAPISSLCertificate(AntaTest): """Verifies the eAPI SSL certificate expiry, common subject name, encryption algorithm and key size. - Expected Results: - * Success: The test will pass if the certificate's expiry date is greater than the threshold, + Expected Results + ---------------- + * Success: The test will pass if the certificate's expiry date is greater than the threshold, and the certificate has the correct name, encryption algorithm, and key size. - * Failure: The test will fail if the certificate is expired or is going to expire, + * Failure: The test will fail if the certificate is expired or is going to expire, or if the certificate has an incorrect name, encryption algorithm, or key size. + + Examples + -------- + ```yaml + anta.tests.security: + - VerifyAPISSLCertificate: + 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 + ``` """ name = "VerifyAPISSLCertificate" @@ -382,9 +474,21 @@ def test(self) -> None: class VerifyBannerLogin(AntaTest): """Verifies the login banner of a device. - Expected results: - * Success: The test will pass if the login banner matches the provided input. - * Failure: The test will fail if the login banner does not match the provided input. + Expected Results + ---------------- + * Success: The test will pass if the login banner matches the provided input. + * Failure: The test will fail if the login banner does not match the provided input. + + Examples + -------- + ```yaml + anta.tests.security: + - VerifyBannerLogin: + 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. + ``` """ name = "VerifyBannerLogin" @@ -414,9 +518,21 @@ def test(self) -> None: class VerifyBannerMotd(AntaTest): """Verifies the motd banner of a device. - Expected results: - * Success: The test will pass if the motd banner matches the provided input. - * Failure: The test will fail if the motd banner does not match the provided input. + Expected Results + ---------------- + * Success: The test will pass if the motd banner matches the provided input. + * Failure: The test will fail if the motd banner does not match the provided input. + + Examples + -------- + ```yaml + anta.tests.security: + - VerifyBannerMotd: + 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. + ``` """ name = "VerifyBannerMotd" @@ -446,9 +562,32 @@ def test(self) -> None: class VerifyIPv4ACL(AntaTest): """Verifies the configuration of IPv4 ACLs. - Expected results: - * Success: The test will pass if an IPv4 ACL is configured with the correct sequence entries. - * Failure: The test will fail if an IPv4 ACL is not configured or entries are not in sequence. + Expected Results + ---------------- + * Success: The test will pass if an IPv4 ACL is configured with the correct sequence entries. + * Failure: The test will fail if an IPv4 ACL is not configured or entries are not in sequence. + + Examples + -------- + ```yaml + anta.tests.security: + - VerifyIPv4ACL: + 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 + ``` """ name = "VerifyIPv4ACL" diff --git a/anta/tests/services.py b/anta/tests/services.py index edbc12e92..a5d2afaf8 100644 --- a/anta/tests/services.py +++ b/anta/tests/services.py @@ -22,9 +22,18 @@ class VerifyHostname(AntaTest): """Verifies the hostname of a device. - Expected results: - * Success: The test will pass if the hostname matches the provided input. - * Failure: The test will fail if the hostname does not match the provided input. + Expected Results + ---------------- + * Success: The test will pass if the hostname matches the provided input. + * Failure: The test will fail if the hostname does not match the provided input. + + Examples + -------- + ```yaml + anta.tests.services: + - VerifyHostname: + hostname: s1-spine1 + ``` """ name = "VerifyHostname" @@ -52,10 +61,22 @@ def test(self) -> None: class VerifyDNSLookup(AntaTest): """Verifies the DNS (Domain Name Service) name to IP address resolution. - Expected Results: - * Success: The test will pass if a domain name is resolved to an IP address. - * Failure: The test will fail if a domain name does not resolve to an IP address. - * Error: This test will error out if a domain name is invalid. + Expected Results + ---------------- + * Success: The test will pass if a domain name is resolved to an IP address. + * Failure: The test will fail if a domain name does not resolve to an IP address. + * Error: This test will error out if a domain name is invalid. + + Examples + -------- + ```yaml + anta.tests.services: + - VerifyDNSLookup: + domain_names: + - arista.com + - www.google.com + - arista.ca + ``` """ name = "VerifyDNSLookup" @@ -90,9 +111,24 @@ def test(self) -> None: class VerifyDNSServers(AntaTest): """Verifies if the DNS (Domain Name Service) servers are correctly configured. - Expected Results: - * Success: The test will pass if the DNS server specified in the input is configured with the correct VRF and priority. - * Failure: The test will fail if the DNS server is not configured or if the VRF and priority of the DNS server do not match the input. + Expected Results + ---------------- + * Success: The test will pass if the DNS server specified in the input is configured with the correct VRF and priority. + * Failure: The test will fail if the DNS server is not configured or if the VRF and priority of the DNS server do not match the input. + + Examples + -------- + ```yaml + anta.tests.services: + - VerifyDNSServers: + dns_servers: + - server_address: 10.14.0.1 + vrf: default + priority: 1 + - server_address: 10.14.0.11 + vrf: MGMT + priority: 0 + ``` """ name = "VerifyDNSServers" @@ -142,9 +178,22 @@ def test(self) -> None: class VerifyErrdisableRecovery(AntaTest): """Verifies the errdisable recovery reason, status, and interval. - Expected Results: - * Success: The test will pass if the errdisable recovery reason status is enabled and the interval matches the input. - * Failure: The test will fail if the errdisable recovery reason is not found, the status is not enabled, or the interval does not match the input. + Expected Results + ---------------- + * Success: The test will pass if the errdisable recovery reason status is enabled and the interval matches the input. + * Failure: The test will fail if the errdisable recovery reason is not found, the status is not enabled, or the interval does not match the input. + + Examples + -------- + ```yaml + anta.tests.services: + - VerifyErrdisableRecovery: + reasons: + - reason: acl + interval: 30 + - reason: bpduguard + interval: 30 + ``` """ name = "VerifyErrdisableRecovery" diff --git a/anta/tests/snmp.py b/anta/tests/snmp.py index 25ab802b5..09cc5310b 100644 --- a/anta/tests/snmp.py +++ b/anta/tests/snmp.py @@ -19,9 +19,18 @@ class VerifySnmpStatus(AntaTest): """Verifies whether the SNMP agent is enabled in a specified VRF. - Expected Results: - * Success: The test will pass if the SNMP agent is enabled in the specified VRF. - * Failure: The test will fail if the SNMP agent is disabled in the specified VRF. + Expected Results + ---------------- + * Success: The test will pass if the SNMP agent is enabled in the specified VRF. + * Failure: The test will fail if the SNMP agent is disabled in the specified VRF. + + Examples + -------- + ```yaml + anta.tests.snmp: + - VerifySnmpStatus: + vrf: default + ``` """ name = "VerifySnmpStatus" @@ -48,9 +57,19 @@ def test(self) -> None: class VerifySnmpIPv4Acl(AntaTest): """Verifies if the SNMP agent has the right number IPv4 ACL(s) configured for a specified VRF. - Expected results: - * Success: The test will pass if the SNMP agent has the provided number of IPv4 ACL(s) in the specified VRF. - * Failure: The test will fail if the SNMP agent has not the right number of IPv4 ACL(s) in the specified VRF. + Expected Results + ---------------- + * Success: The test will pass if the SNMP agent has the provided number of IPv4 ACL(s) in the specified VRF. + * Failure: The test will fail if the SNMP agent has not the right number of IPv4 ACL(s) in the specified VRF. + + Examples + -------- + ```yaml + anta.tests.snmp: + - VerifySnmpIPv4Acl: + number: 3 + vrf: default + ``` """ name = "VerifySnmpIPv4Acl" @@ -87,9 +106,19 @@ def test(self) -> None: class VerifySnmpIPv6Acl(AntaTest): """Verifies if the SNMP agent has the right number IPv6 ACL(s) configured for a specified VRF. - Expected results: - * Success: The test will pass if the SNMP agent has the provided number of IPv6 ACL(s) in the specified VRF. - * Failure: The test will fail if the SNMP agent has not the right number of IPv6 ACL(s) in the specified VRF. + Expected Results + ---------------- + * Success: The test will pass if the SNMP agent has the provided number of IPv6 ACL(s) in the specified VRF. + * Failure: The test will fail if the SNMP agent has not the right number of IPv6 ACL(s) in the specified VRF. + + Examples + -------- + ```yaml + anta.tests.snmp: + - VerifySnmpIPv6Acl: + number: 3 + vrf: default + ``` """ name = "VerifySnmpIPv6Acl" @@ -126,9 +155,18 @@ def test(self) -> None: class VerifySnmpLocation(AntaTest): """Verifies the SNMP location of a device. - Expected results: - * Success: The test will pass if the SNMP location matches the provided input. - * Failure: The test will fail if the SNMP location does not match the provided input. + Expected Results + ---------------- + * Success: The test will pass if the SNMP location matches the provided input. + * Failure: The test will fail if the SNMP location does not match the provided input. + + Examples + -------- + ```yaml + anta.tests.snmp: + - VerifySnmpLocation: + location: New York + ``` """ name = "VerifySnmpLocation" @@ -156,9 +194,18 @@ def test(self) -> None: class VerifySnmpContact(AntaTest): """Verifies the SNMP contact of a device. - Expected results: - * Success: The test will pass if the SNMP contact matches the provided input. - * Failure: The test will fail if the SNMP contact does not match the provided input. + Expected Results + ---------------- + * Success: The test will pass if the SNMP contact matches the provided input. + * Failure: The test will fail if the SNMP contact does not match the provided input. + + Examples + -------- + ```yaml + anta.tests.snmp: + - VerifySnmpContact: + contact: Jon@example.com + ``` """ name = "VerifySnmpContact" diff --git a/anta/tests/software.py b/anta/tests/software.py index 5282682d2..3cc77322f 100644 --- a/anta/tests/software.py +++ b/anta/tests/software.py @@ -18,9 +18,20 @@ class VerifyEOSVersion(AntaTest): """Verifies that the device is running one of the allowed EOS version. - Expected Results: - * Success: The test will pass if the device is running one of the allowed EOS version. - * Failure: The test will fail if the device is not running one of the allowed EOS version. + Expected Results + ---------------- + * Success: The test will pass if the device is running one of the allowed EOS version. + * Failure: The test will fail if the device is not running one of the allowed EOS version. + + Examples + -------- + ```yaml + anta.tests.software: + - VerifyEOSVersion: + versions: + - 4.25.4M + - 4.26.1F + ``` """ name = "VerifyEOSVersion" @@ -47,9 +58,20 @@ def test(self) -> None: class VerifyTerminAttrVersion(AntaTest): """Verifies that he device is running one of the allowed TerminAttr version. - Expected Results: - * Success: The test will pass if the device is running one of the allowed TerminAttr version. - * Failure: The test will fail if the device is not running one of the allowed TerminAttr version. + Expected Results + ---------------- + * Success: The test will pass if the device is running one of the allowed TerminAttr version. + * Failure: The test will fail if the device is not running one of the allowed TerminAttr version. + + Examples + -------- + ```yaml + anta.tests.software: + - VerifyTerminAttrVersion: + versions: + - v1.13.6 + - v1.8.0 + ``` """ name = "VerifyTerminAttrVersion" @@ -77,9 +99,17 @@ def test(self) -> None: class VerifyEOSExtensions(AntaTest): """Verifies that all EOS extensions installed on the device are enabled for boot persistence. - Expected Results: - * Success: The test will pass if all EOS extensions installed on the device are enabled for boot persistence. - * Failure: The test will fail if some EOS extensions installed on the device are not enabled for boot persistence. + Expected Results + ---------------- + * Success: The test will pass if all EOS extensions installed on the device are enabled for boot persistence. + * Failure: The test will fail if some EOS extensions installed on the device are not enabled for boot persistence. + + Examples + -------- + ```yaml + anta.tests.software: + - VerifyEOSExtensions: + ``` """ name = "VerifyEOSExtensions" diff --git a/anta/tests/stp.py b/anta/tests/stp.py index 85f0c835f..b2496d663 100644 --- a/anta/tests/stp.py +++ b/anta/tests/stp.py @@ -19,9 +19,21 @@ class VerifySTPMode(AntaTest): """Verifies the configured STP mode for a provided list of VLAN(s). - Expected Results: - * Success: The test will pass if the STP mode is configured properly in the specified VLAN(s). - * Failure: The test will fail if the STP mode is NOT configured properly for one or more specified VLAN(s). + Expected Results + ---------------- + * Success: The test will pass if the STP mode is configured properly in the specified VLAN(s). + * Failure: The test will fail if the STP mode is NOT configured properly for one or more specified VLAN(s). + + Examples + -------- + ```yaml + anta.tests.stp: + - VerifySTPMode: + mode: rapidPvst + vlans: + - 10 + - 20 + ``` """ name = "VerifySTPMode" @@ -49,7 +61,12 @@ def test(self) -> None: for command in self.instance_commands: if "vlan" in command.params: vlan_id = command.params["vlan"] - if not (stp_mode := get_value(command.json_output, f"spanningTreeVlanInstances.{vlan_id}.spanningTreeVlanInstance.protocol")): + if not ( + stp_mode := get_value( + command.json_output, + f"spanningTreeVlanInstances.{vlan_id}.spanningTreeVlanInstance.protocol", + ) + ): not_configured.append(vlan_id) elif stp_mode != self.inputs.mode: wrong_stp_mode.append(vlan_id) @@ -64,9 +81,17 @@ def test(self) -> None: class VerifySTPBlockedPorts(AntaTest): """Verifies there is no STP blocked ports. - Expected Results: - * Success: The test will pass if there are NO ports blocked by STP. - * Failure: The test will fail if there are ports blocked by STP. + Expected Results + ---------------- + * Success: The test will pass if there are NO ports blocked by STP. + * Failure: The test will fail if there are ports blocked by STP. + + Examples + -------- + ```yaml + anta.tests.stp: + - VerifySTPBlockedPorts: + ``` """ name = "VerifySTPBlockedPorts" @@ -89,9 +114,17 @@ def test(self) -> None: class VerifySTPCounters(AntaTest): """Verifies there is no errors in STP BPDU packets. - Expected Results: - * Success: The test will pass if there are NO STP BPDU packet errors under all interfaces participating in STP. - * Failure: The test will fail if there are STP BPDU packet errors on one or many interface(s). + Expected Results + ---------------- + * Success: The test will pass if there are NO STP BPDU packet errors under all interfaces participating in STP. + * Failure: The test will fail if there are STP BPDU packet errors on one or many interface(s). + + Examples + -------- + ```yaml + anta.tests.stp: + - VerifySTPCounters: + ``` """ name = "VerifySTPCounters" @@ -115,9 +148,20 @@ def test(self) -> None: class VerifySTPForwardingPorts(AntaTest): """Verifies that all interfaces are in a forwarding state for a provided list of VLAN(s). - Expected Results: - * Success: The test will pass if all interfaces are in a forwarding state for the specified VLAN(s). - * Failure: The test will fail if one or many interfaces are NOT in a forwarding state in the specified VLAN(s). + Expected Results + ---------------- + * Success: The test will pass if all interfaces are in a forwarding state for the specified VLAN(s). + * Failure: The test will fail if one or many interfaces are NOT in a forwarding state in the specified VLAN(s). + + Examples + -------- + ```yaml + anta.tests.stp: + - VerifySTPForwardingPorts: + vlans: + - 10 + - 20 + ``` """ name = "VerifySTPForwardingPorts" @@ -162,9 +206,21 @@ def test(self) -> None: class VerifySTPRootPriority(AntaTest): """Verifies the STP root priority for a provided list of VLAN or MST instance ID(s). - Expected Results: - * Success: The test will pass if the STP root priority is configured properly for the specified VLAN or MST instance ID(s). - * Failure: The test will fail if the STP root priority is NOT configured properly for the specified VLAN or MST instance ID(s). + Expected Results + ---------------- + * Success: The test will pass if the STP root priority is configured properly for the specified VLAN or MST instance ID(s). + * Failure: The test will fail if the STP root priority is NOT configured properly for the specified VLAN or MST instance ID(s). + + Examples + -------- + ```yaml + anta.tests.stp: + - VerifySTPRootPriority: + priority: 32768 + instances: + - 10 + - 20 + ``` """ name = "VerifySTPRootPriority" diff --git a/anta/tests/system.py b/anta/tests/system.py index 4c849da8a..223dcc953 100644 --- a/anta/tests/system.py +++ b/anta/tests/system.py @@ -24,9 +24,18 @@ class VerifyUptime(AntaTest): """Verifies if the device uptime is higher than the provided minimum uptime value. - Expected Results: - * Success: The test will pass if the device uptime is higher than the provided value. - * Failure: The test will fail if the device uptime is lower than the provided value. + Expected Results + ---------------- + * Success: The test will pass if the device uptime is higher than the provided value. + * Failure: The test will fail if the device uptime is lower than the provided value. + + Examples + -------- + ```yaml + anta.tests.system: + - VerifyUptime: + minimum: 86400 + ``` """ name = "VerifyUptime" @@ -53,10 +62,18 @@ def test(self) -> None: class VerifyReloadCause(AntaTest): """Verifies the last reload cause of the device. - Expected results: - * Success: The test will pass if there are NO reload causes or if the last reload was caused by the user or after an FPGA upgrade. - * Failure: The test will fail if the last reload was NOT caused by the user or after an FPGA upgrade. - * Error: The test will report an error if the reload cause is NOT available. + Expected Results + ---------------- + * Success: The test will pass if there are NO reload causes or if the last reload was caused by the user or after an FPGA upgrade. + * Failure: The test will fail if the last reload was NOT caused by the user or after an FPGA upgrade. + * Error: The test will report an error if the reload cause is NOT available. + + Examples + -------- + ```yaml + anta.tests.system: + - VerifyReloadCause: + ``` """ name = "VerifyReloadCause" @@ -89,14 +106,21 @@ def test(self) -> None: class VerifyCoredump(AntaTest): """Verifies if there are core dump files in the /var/core directory. - Expected Results: - * Success: The test will pass if there are NO core dump(s) in /var/core. - * Failure: The test will fail if there are core dump(s) in /var/core. + Expected Results + ---------------- + * Success: The test will pass if there are NO core dump(s) in /var/core. + * Failure: The test will fail if there are core dump(s) in /var/core. - Note: + Info ---- - * This test will NOT check for minidump(s) generated by certain agents in /var/core/minidump. - + * This test will NOT check for minidump(s) generated by certain agents in /var/core/minidump. + + Examples + -------- + ```yaml + anta.tests.system: + - VerifyCoreDump: + ``` """ name = "VerifyCoredump" @@ -120,9 +144,17 @@ def test(self) -> None: class VerifyAgentLogs(AntaTest): """Verifies that no agent crash reports are present on the device. - Expected Results: - * Success: The test will pass if there is NO agent crash reported. - * Failure: The test will fail if any agent crashes are reported. + Expected Results + ---------------- + * Success: The test will pass if there is NO agent crash reported. + * Failure: The test will fail if any agent crashes are reported. + + Examples + -------- + ```yaml + anta.tests.system: + - VerifyAgentLogs: + ``` """ name = "VerifyAgentLogs" @@ -145,9 +177,17 @@ def test(self) -> None: class VerifyCPUUtilization(AntaTest): """Verifies whether the CPU utilization is below 75%. - Expected Results: - * Success: The test will pass if the CPU utilization is below 75%. - * Failure: The test will fail if the CPU utilization is over 75%. + Expected Results + ---------------- + * Success: The test will pass if the CPU utilization is below 75%. + * Failure: The test will fail if the CPU utilization is over 75%. + + Examples + -------- + ```yaml + anta.tests.system: + - VerifyCPUUtilization: + ``` """ name = "VerifyCPUUtilization" @@ -169,9 +209,17 @@ def test(self) -> None: class VerifyMemoryUtilization(AntaTest): """Verifies whether the memory utilization is below 75%. - Expected Results: - * Success: The test will pass if the memory utilization is below 75%. - * Failure: The test will fail if the memory utilization is over 75%. + Expected Results + ---------------- + * Success: The test will pass if the memory utilization is below 75%. + * Failure: The test will fail if the memory utilization is over 75%. + + Examples + -------- + ```yaml + anta.tests.system: + - VerifyMemoryUtilization: + ``` """ name = "VerifyMemoryUtilization" @@ -193,9 +241,17 @@ def test(self) -> None: class VerifyFileSystemUtilization(AntaTest): """Verifies that no partition is utilizing more than 75% of its disk space. - Expected Results: - * Success: The test will pass if all partitions are using less than 75% of its disk space. - * Failure: The test will fail if any partitions are using more than 75% of its disk space. + Expected Results + ---------------- + * Success: The test will pass if all partitions are using less than 75% of its disk space. + * Failure: The test will fail if any partitions are using more than 75% of its disk space. + + Examples + -------- + ```yaml + anta.tests.system: + - VerifyFileSystemUtilization: + ``` """ name = "VerifyFileSystemUtilization" @@ -216,9 +272,17 @@ def test(self) -> None: class VerifyNTP(AntaTest): """Verifies that the Network Time Protocol (NTP) is synchronized. - Expected Results: - * Success: The test will pass if the NTP is synchronised. - * Failure: The test will fail if the NTP is NOT synchronised. + Expected Results + ---------------- + * Success: The test will pass if the NTP is synchronised. + * Failure: The test will fail if the NTP is NOT synchronised. + + Examples + -------- + ```yaml + anta.tests.system: + - VerifyNTP: + ``` """ name = "VerifyNTP" diff --git a/anta/tests/vlan.py b/anta/tests/vlan.py index 0add6d157..4054eb55c 100644 --- a/anta/tests/vlan.py +++ b/anta/tests/vlan.py @@ -21,11 +21,22 @@ class VerifyVlanInternalPolicy(AntaTest): """Verifies if the VLAN internal allocation policy is ascending or descending and if the VLANs are within the specified range. - Expected Results: - * Success: The test will pass if the VLAN internal allocation policy is either ascending or descending + Expected Results + ---------------- + * Success: The test will pass if the VLAN internal allocation policy is either ascending or descending and the VLANs are within the specified range. - * Failure: The test will fail if the VLAN internal allocation policy is neither ascending nor descending + * Failure: The test will fail if the VLAN internal allocation policy is neither ascending nor descending or the VLANs are outside the specified range. + + Examples + -------- + ```yaml + anta.tests.vlan: + - VerifyVlanInternalPolicy: + policy: ascending + start_vlan_id: 1006 + end_vlan_id: 4094 + ``` """ name = "VerifyVlanInternalPolicy" diff --git a/anta/tests/vxlan.py b/anta/tests/vxlan.py index 691d84f5e..3f083262c 100644 --- a/anta/tests/vxlan.py +++ b/anta/tests/vxlan.py @@ -23,13 +23,22 @@ class VerifyVxlan1Interface(AntaTest): """Verifies if the Vxlan1 interface is configured and 'up/up'. - !!! warning - The name of this test has been updated from 'VerifyVxlan' for better representation. - - Expected Results: - * Success: The test will pass if the Vxlan1 interface is configured with line protocol status and interface status 'up'. - * Failure: The test will fail if the Vxlan1 interface line protocol status or interface status are not 'up'. - * Skipped: The test will be skipped if the Vxlan1 interface is not configured. + Warning + ------- + The name of this test has been updated from 'VerifyVxlan' for better representation. + + Expected Results + ---------------- + * Success: The test will pass if the Vxlan1 interface is configured with line protocol status and interface status 'up'. + * Failure: The test will fail if the Vxlan1 interface line protocol status or interface status are not 'up'. + * Skipped: The test will be skipped if the Vxlan1 interface is not configured. + + Examples + -------- + ```yaml + anta.tests.vxlan: + - VerifyVxlan1Interface: + ``` """ name = "VerifyVxlan1Interface" @@ -58,10 +67,18 @@ def test(self) -> None: class VerifyVxlanConfigSanity(AntaTest): """Verifies that no issues are detected with the VXLAN configuration. - Expected Results: - * Success: The test will pass if no issues are detected with the VXLAN configuration. - * Failure: The test will fail if issues are detected with the VXLAN configuration. - * Skipped: The test will be skipped if VXLAN is not configured on the device. + Expected Results + ---------------- + * Success: The test will pass if no issues are detected with the VXLAN configuration. + * Failure: The test will fail if issues are detected with the VXLAN configuration. + * Skipped: The test will be skipped if VXLAN is not configured on the device. + + Examples + -------- + ```yaml + anta.tests.vxlan: + - VerifyVxlanConfigSanity: + ``` """ name = "VerifyVxlanConfigSanity" @@ -90,10 +107,21 @@ def test(self) -> None: class VerifyVxlanVniBinding(AntaTest): """Verifies the VNI-VLAN bindings of the Vxlan1 interface. - Expected Results: - * Success: The test will pass if the VNI-VLAN bindings provided are properly configured. - * Failure: The test will fail if any VNI lacks bindings or if any bindings are incorrect. - * Skipped: The test will be skipped if the Vxlan1 interface is not configured. + Expected Results + ---------------- + * Success: The test will pass if the VNI-VLAN bindings provided are properly configured. + * Failure: The test will fail if any VNI lacks bindings or if any bindings are incorrect. + * Skipped: The test will be skipped if the Vxlan1 interface is not configured. + + Examples + -------- + ```yaml + anta.tests.vxlan: + - VerifyVxlanVniBinding: + bindings: + 10010: 10 + 10020: 20 + ``` """ name = "VerifyVxlanVniBinding" @@ -142,10 +170,21 @@ def test(self) -> None: class VerifyVxlanVtep(AntaTest): """Verifies the VTEP peers of the Vxlan1 interface. - Expected Results: - * Success: The test will pass if all provided VTEP peers are identified and matching. - * Failure: The test will fail if any VTEP peer is missing or there are unexpected VTEP peers. - * Skipped: The test will be skipped if the Vxlan1 interface is not configured. + Expected Results + ---------------- + * Success: The test will pass if all provided VTEP peers are identified and matching. + * Failure: The test will fail if any VTEP peer is missing or there are unexpected VTEP peers. + * Skipped: The test will be skipped if the Vxlan1 interface is not configured. + + Examples + -------- + ```yaml + anta.tests.vxlan: + - VerifyVxlanVtep: + vteps: + - 10.1.1.5 + - 10.1.1.6 + ``` """ name = "VerifyVxlanVtep" @@ -183,10 +222,20 @@ def test(self) -> None: class VerifyVxlan1ConnSettings(AntaTest): """Verifies the interface vxlan1 source interface and UDP port. - Expected Results: - * Success: Passes if the interface vxlan1 source interface and UDP port are correct. - * Failure: Fails if the interface vxlan1 source interface or UDP port are incorrect. - * Skipped: Skips if the Vxlan1 interface is not configured. + Expected Results + ---------------- + * Success: Passes if the interface vxlan1 source interface and UDP port are correct. + * Failure: Fails if the interface vxlan1 source interface or UDP port are incorrect. + * Skipped: Skips if the Vxlan1 interface is not configured. + + Examples + -------- + ```yaml + anta.tests.vxlan: + - VerifyVxlan1ConnSettings: + source_interface: Loopback1 + udp_port: 4789 + ``` """ name = "VerifyVxlan1ConnSettings" diff --git a/anta/tools/utils.py b/anta/tools/utils.py index 595caf41f..328f3c98e 100644 --- a/anta/tools/utils.py +++ b/anta/tools/utils.py @@ -18,7 +18,7 @@ def get_failed_logs(expected_output: dict[Any, Any], actual_output: dict[Any, An expected_output (dict): Expected output of a test. actual_output (dict): Actual output of a test - Returns: + Returns ------- str: Failed log of a test. diff --git a/docs/README.md b/docs/README.md index e4757f5bd..209a37547 100755 --- a/docs/README.md +++ b/docs/README.md @@ -4,14 +4,11 @@ ~ that can be found in the LICENSE file. --> -[![License](https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg)](https://github.com/arista-netdevops-community/anta/blob/main/LICENSE) -[![Linting and Testing Anta](https://github.com/arista-netdevops-community/anta/actions/workflows/code-testing.yml/badge.svg)](https://github.com/arista-netdevops-community/anta/actions/workflows/code-testing.yml) -[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) -![GitHub commit activity (branch)](https://img.shields.io/github/commit-activity/m/arista-netdevops-community/anta) -[![github release](https://img.shields.io/github/release/arista-netdevops-community/anta.svg)](https://github.com/arista-netdevops-community/anta/releases/) -[![image](https://img.shields.io/pypi/v/anta.svg)](https://pypi.python.org/pypi/anta) -![PyPI - Downloads](https://img.shields.io/pypi/dm/anta) -![coverage](https://raw.githubusercontent.com/arista-netdevops-community/anta/coverage-badge/latest-release-coverage.svg) +| **Code** | [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) [![Numpy](https://img.shields.io/badge/Docstring_format-numpy-blue)](https://numpydoc.readthedocs.io/en/latest/format.html) | +| :------------: | :-------| +| **License** | [![License](https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg)](https://github.com/arista-netdevops-community/anta/blob/main/LICENSE) | +| **GitHub** | [![CI](https://github.com/arista-netdevops-community/anta/actions/workflows/code-testing.yml/badge.svg)](https://github.com/arista-netdevops-community/anta/actions/workflows/code-testing.yml) ![Coverage](https://raw.githubusercontent.com/arista-netdevops-community/anta/coverage-badge/latest-release-coverage.svg) ![Commit](https://img.shields.io/github/last-commit/arista-netdevops-community/anta) ![GitHub commit activity (branch)](https://img.shields.io/github/commit-activity/m/arista-netdevops-community/anta) [![Github release](https://img.shields.io/github/release/arista-netdevops-community/anta.svg)](https://github.com/arista-netdevops-community/anta/releases/) [![Contributors](https://img.shields.io/github/contributors/arista-netdevops-community/anta)](https://github.com/arista-netdevops-community/anta/graphs/contributors) | +| **PyPi** | ![PyPi Version](https://img.shields.io/pypi/v/anta) ![Python Versions](https://img.shields.io/pypi/pyversions/anta) ![Python format](https://img.shields.io/pypi/format/anta) ![PyPI - Downloads](https://img.shields.io/pypi/dm/anta) | # Arista Network Test Automation (ANTA) Framework diff --git a/docs/advanced_usages/custom-tests.md b/docs/advanced_usages/custom-tests.md index 87402c1a3..2e26671b9 100644 --- a/docs/advanced_usages/custom-tests.md +++ b/docs/advanced_usages/custom-tests.md @@ -192,7 +192,14 @@ If the user needs to provide inputs for your test, you need to define a [pydanti ```python class (AntaTest): ... - class Input(AntaTest.Input): # pylint: disable=missing-class-docstring + class Input(AntaTest.Input): + """Inputs for my awesome test + Examples: + -------- + your.module.path: + - YourTestName: + field_name: example_field_value + """ : """""" ``` diff --git a/docs/api/tests.aaa.md b/docs/api/tests.aaa.md index bdbe7ec9b..dabbc43e7 100644 --- a/docs/api/tests.aaa.md +++ b/docs/api/tests.aaa.md @@ -4,10 +4,15 @@ ~ that can be found in the LICENSE file. --> -# ANTA catalog for interfaces tests +# ANTA catalog for AAA tests ::: anta.tests.aaa options: show_root_heading: false show_root_toc_entry: false + show_bases: false merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.bfd.md b/docs/api/tests.bfd.md index d28521fbc..6d6b06e26 100644 --- a/docs/api/tests.bfd.md +++ b/docs/api/tests.bfd.md @@ -4,10 +4,15 @@ ~ that can be found in the LICENSE file. --> -# ANTA catalog for bfd tests +# ANTA catalog for BFD tests ::: anta.tests.bfd options: show_root_heading: false show_root_toc_entry: false + show_bases: false merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.configuration.md b/docs/api/tests.configuration.md index aaee1f447..602761016 100644 --- a/docs/api/tests.configuration.md +++ b/docs/api/tests.configuration.md @@ -4,10 +4,15 @@ ~ that can be found in the LICENSE file. --> -# ANTA catalog for configuration tests +# ANTA catalog for device configuration tests ::: anta.tests.configuration options: show_root_heading: false show_root_toc_entry: false + show_bases: false merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.connectivity.md b/docs/api/tests.connectivity.md index 8a1b8a217..efd088793 100644 --- a/docs/api/tests.connectivity.md +++ b/docs/api/tests.connectivity.md @@ -10,4 +10,9 @@ options: show_root_heading: false show_root_toc_entry: false + show_bases: false merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.field_notices.md b/docs/api/tests.field_notices.md index ed0e8371c..84b701ce9 100644 --- a/docs/api/tests.field_notices.md +++ b/docs/api/tests.field_notices.md @@ -10,4 +10,9 @@ options: show_root_heading: false show_root_toc_entry: false + show_bases: false merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.greent.md b/docs/api/tests.greent.md new file mode 100644 index 000000000..1dc30607d --- /dev/null +++ b/docs/api/tests.greent.md @@ -0,0 +1,18 @@ + + +# ANTA catalog for GreenT tests + +::: anta.tests.greent + options: + show_root_heading: false + show_root_toc_entry: false + show_bases: false + merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.hardware.md b/docs/api/tests.hardware.md index 6e841960c..6fea7fd62 100644 --- a/docs/api/tests.hardware.md +++ b/docs/api/tests.hardware.md @@ -10,4 +10,9 @@ options: show_root_heading: false show_root_toc_entry: false + show_bases: false merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.interfaces.md b/docs/api/tests.interfaces.md index b21da40c9..e58d0c28a 100644 --- a/docs/api/tests.interfaces.md +++ b/docs/api/tests.interfaces.md @@ -10,4 +10,9 @@ options: show_root_heading: false show_root_toc_entry: false + show_bases: false merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.lanz.md b/docs/api/tests.lanz.md new file mode 100644 index 000000000..d2c848f21 --- /dev/null +++ b/docs/api/tests.lanz.md @@ -0,0 +1,18 @@ + + +# ANTA catalog for LANZ tests + +::: anta.tests.lanz + options: + show_root_heading: false + show_root_toc_entry: false + show_bases: false + merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.logging.md b/docs/api/tests.logging.md index e9acc20a7..b96408be5 100644 --- a/docs/api/tests.logging.md +++ b/docs/api/tests.logging.md @@ -10,4 +10,9 @@ options: show_root_heading: false show_root_toc_entry: false + show_bases: false merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.md b/docs/api/tests.md index 40c7d8ae9..4b1bb4910 100644 --- a/docs/api/tests.md +++ b/docs/api/tests.md @@ -4,22 +4,28 @@ ~ that can be found in the LICENSE file. --> -# ANTA Tests landing page +# ANTA Tests Landing Page -This section describes all the available tests provided by ANTA package. +This section describes all the available tests provided by the ANTA package. +## Available Tests + +Here are the tests that we currently provide: - [AAA](tests.aaa.md) - [BFD](tests.bfd.md) - [Configuration](tests.configuration.md) - [Connectivity](tests.connectivity.md) - [Field Notice](tests.field_notices.md) +- [GreenT](tests.greent.md) - [Hardware](tests.hardware.md) - [Interfaces](tests.interfaces.md) +- [LANZ](tests.lanz.md) - [Logging](tests.logging.md) - [MLAG](tests.mlag.md) - [Multicast](tests.multicast.md) - [Profiles](tests.profiles.md) +- [PTP](tests.ptp.md) - [Routing Generic](tests.routing.generic.md) - [Routing BGP](tests.routing.bgp.md) - [Routing OSPF](tests.routing.ospf.md) @@ -32,6 +38,6 @@ This section describes all the available tests provided by ANTA package. - [VLAN](tests.vlan.md) - [VXLAN](tests.vxlan.md) +## Using the Tests - -All these tests can be imported in a [catalog](../usage-inventory-catalog.md) to be used by [the anta cli](../cli/nrfu.md) or in your [own framework](../advanced_usages/as-python-lib.md) +All these tests can be imported in a [catalog](../usage-inventory-catalog.md) to be used by [the ANTA CLI](../cli/nrfu.md) or in your [own framework](../advanced_usages/as-python-lib.md). diff --git a/docs/api/tests.mlag.md b/docs/api/tests.mlag.md index 6ce419b84..2648f12f1 100644 --- a/docs/api/tests.mlag.md +++ b/docs/api/tests.mlag.md @@ -4,10 +4,15 @@ ~ that can be found in the LICENSE file. --> -# ANTA catalog for mlag tests +# ANTA catalog for MLAG tests ::: anta.tests.mlag options: show_root_heading: false show_root_toc_entry: false + show_bases: false merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.multicast.md b/docs/api/tests.multicast.md index 2b03420c4..134a7fde2 100644 --- a/docs/api/tests.multicast.md +++ b/docs/api/tests.multicast.md @@ -4,10 +4,15 @@ ~ that can be found in the LICENSE file. --> -# ANTA catalog for multicast tests +# ANTA catalog for multicast and IGMP tests ::: anta.tests.multicast options: show_root_heading: false show_root_toc_entry: false + show_bases: false merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.profiles.md b/docs/api/tests.profiles.md index c6d06e737..daee34901 100644 --- a/docs/api/tests.profiles.md +++ b/docs/api/tests.profiles.md @@ -10,4 +10,9 @@ options: show_root_heading: false show_root_toc_entry: false + show_bases: false merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.ptp.md b/docs/api/tests.ptp.md new file mode 100644 index 000000000..bee08bb0c --- /dev/null +++ b/docs/api/tests.ptp.md @@ -0,0 +1,18 @@ + + +# ANTA catalog for PTP tests + +::: anta.tests.ptp + options: + show_root_heading: false + show_root_toc_entry: false + show_bases: false + merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.routing.bgp.md b/docs/api/tests.routing.bgp.md index 23468662c..bef6b513f 100644 --- a/docs/api/tests.routing.bgp.md +++ b/docs/api/tests.routing.bgp.md @@ -10,4 +10,9 @@ options: show_root_heading: false show_root_toc_entry: false + show_bases: false merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.routing.generic.md b/docs/api/tests.routing.generic.md index 3853fb0d4..deb182a9f 100644 --- a/docs/api/tests.routing.generic.md +++ b/docs/api/tests.routing.generic.md @@ -4,10 +4,15 @@ ~ that can be found in the LICENSE file. --> -# ANTA catalog for routing-generic tests +# ANTA catalog for generic routing tests ::: anta.tests.routing.generic options: show_root_heading: false show_root_toc_entry: false + show_bases: false merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.routing.ospf.md b/docs/api/tests.routing.ospf.md index c4e6fed0e..4be5d7e10 100644 --- a/docs/api/tests.routing.ospf.md +++ b/docs/api/tests.routing.ospf.md @@ -4,10 +4,15 @@ ~ that can be found in the LICENSE file. --> -# ANTA catalog for routing-ospf tests +# ANTA catalog for OSPF tests ::: anta.tests.routing.ospf options: show_root_heading: false show_root_toc_entry: false + show_bases: false merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.security.md b/docs/api/tests.security.md index 1186b31c6..83f532243 100644 --- a/docs/api/tests.security.md +++ b/docs/api/tests.security.md @@ -10,4 +10,9 @@ options: show_root_heading: false show_root_toc_entry: false + show_bases: false merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.services.md b/docs/api/tests.services.md index 82a7b38ad..07b7cd5a5 100644 --- a/docs/api/tests.services.md +++ b/docs/api/tests.services.md @@ -10,4 +10,9 @@ options: show_root_heading: false show_root_toc_entry: false + show_bases: false merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.snmp.md b/docs/api/tests.snmp.md index a015d04d2..86ec6752f 100644 --- a/docs/api/tests.snmp.md +++ b/docs/api/tests.snmp.md @@ -10,4 +10,9 @@ options: show_root_heading: false show_root_toc_entry: false + show_bases: false merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.software.md b/docs/api/tests.software.md index 7a2f0ec00..e7f7729fd 100644 --- a/docs/api/tests.software.md +++ b/docs/api/tests.software.md @@ -10,4 +10,9 @@ options: show_root_heading: false show_root_toc_entry: false + show_bases: false merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.stp.md b/docs/api/tests.stp.md index f86dac47d..ce1056410 100644 --- a/docs/api/tests.stp.md +++ b/docs/api/tests.stp.md @@ -10,4 +10,9 @@ options: show_root_heading: false show_root_toc_entry: false + show_bases: false merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.system.md b/docs/api/tests.system.md index 621c17b48..0019957c3 100644 --- a/docs/api/tests.system.md +++ b/docs/api/tests.system.md @@ -10,4 +10,9 @@ options: show_root_heading: false show_root_toc_entry: false + show_bases: false merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.vlan.md b/docs/api/tests.vlan.md index 0e1aa1517..33a17b573 100644 --- a/docs/api/tests.vlan.md +++ b/docs/api/tests.vlan.md @@ -4,10 +4,15 @@ ~ that can be found in the LICENSE file. --> -# ANTA catalog for vlan tests +# ANTA catalog for VLAN tests ::: anta.tests.vlan options: show_root_heading: false show_root_toc_entry: false + show_bases: false merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/api/tests.vxlan.md b/docs/api/tests.vxlan.md index a4dcff36f..0acbc4c47 100644 --- a/docs/api/tests.vxlan.md +++ b/docs/api/tests.vxlan.md @@ -10,4 +10,9 @@ options: show_root_heading: false show_root_toc_entry: false + show_bases: false merge_init_into_class: false + show_labels: true + filters: + - "!test" + - "!render" diff --git a/docs/contribution.md b/docs/contribution.md index 49df256bb..a41a4e0c6 100644 --- a/docs/contribution.md +++ b/docs/contribution.md @@ -219,7 +219,7 @@ Image will be generated under `docs/imgs/uml/` and can be inserted in your docum Writing documentation is crucial but managing links can be cumbersome. To be sure there is no dead links, you can use [`muffet`](https://github.com/raviqqe/muffet) with the following command: ```bash -muffet -c 2 --color=always http://127.0.0.1:8000 -e fonts.gstatic.com +muffet -c 2 --color=always http://127.0.0.1:8000 -e fonts.gstatic.com -b 8192 ``` ## Continuous Integration diff --git a/docs/imgs/animated-svg.md b/docs/imgs/animated-svg.md deleted file mode 100644 index 6a27a50ff..000000000 --- a/docs/imgs/animated-svg.md +++ /dev/null @@ -1,8 +0,0 @@ - - -Repository: https://github.com/marionebl/svg-term-cli -Command: `cat anta-nrfu.cast | svg-term --height 10 --window --out anta.svg` diff --git a/docs/scripts/__init__.py b/docs/scripts/__init__.py new file mode 100644 index 000000000..c6adabbde --- /dev/null +++ b/docs/scripts/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Arista Networks, Inc. +# Use of this source code is governed by the Apache License 2.0 +# that can be found in the LICENSE file. +"""Scripts for ANTA documentation.""" diff --git a/docs/templates/python/material/anta_test.html b/docs/templates/python/material/anta_test.html new file mode 100644 index 000000000..ade0ba691 --- /dev/null +++ b/docs/templates/python/material/anta_test.html @@ -0,0 +1,163 @@ +{% if obj.members %} + {{ log.debug("Rendering children of " + obj.path) }} + +
+ + {% if root_members %} + {% set members_list = config.members %} + {% else %} + {% set members_list = none %} + {% endif %} + + {% if config.group_by_category %} + + {% with %} + + {% if config.show_category_heading %} + {% set extra_level = 1 %} + {% else %} + {% set extra_level = 0 %} + {% endif %} + + {% with attributes = obj.attributes|filter_objects( + filters=config.filters, + members_list=members_list, + inherited_members=config.inherited_members, + keep_no_docstrings=config.show_if_no_docstring, + ) %} + {% if attributes %} + {% if config.show_category_heading %} + {% filter heading(heading_level, id=html_id ~ "-attributes") %}Attributes{% endfilter %} + {% endif %} + {% with heading_level = heading_level + extra_level %} + {% for attribute in attributes|order_members(config.members_order, members_list) %} + {% if members_list is not none or attribute.is_public(check_name=False) %} + {% include attribute|get_template with context %} + {% endif %} + {% endfor %} + {% endwith %} + {% endif %} + {% endwith %} + + {% with classes = obj.classes|filter_objects( + filters=config.filters, + members_list=members_list, + inherited_members=config.inherited_members, + keep_no_docstrings=config.show_if_no_docstring, + ) %} + {% if classes %} + {% if config.show_category_heading %} + {% filter heading(heading_level, id=html_id ~ "-classes") %}Classes{% endfilter %} + {% endif %} + {% with heading_level = heading_level + extra_level %} + {% for class in classes|order_members(config.members_order, members_list) %} + {% if class.name == "Input" %} + {% filter heading(heading_level, id=html_id ~ "-attributes") %}Inputs{% endfilter %} + {% set root = False %} + {% set heading_level = heading_level + 1 %} + {% set old_obj = obj %} + {% set obj = class %} + {% include "attributes_table.html" with context %} + {% set obj = old_obj %} + {% else %} + {% if members_list is not none or class.is_public(check_name=False) %} + {% include class|get_template with context %} + {% endif %} + {% endif %} + {% endfor %} + {% endwith %} + {% endif %} + {% endwith %} + + {% with functions = obj.functions|filter_objects( + filters=config.filters, + members_list=members_list, + inherited_members=config.inherited_members, + keep_no_docstrings=config.show_if_no_docstring, + ) %} + {% if functions %} + {% if config.show_category_heading %} + {% filter heading(heading_level, id=html_id ~ "-functions") %}Functions{% endfilter %} + {% endif %} + {% with heading_level = heading_level + extra_level %} + {% for function in functions|order_members(config.members_order, members_list) %} + {% if not (obj.kind.value == "class" and function.name == "__init__" and config.merge_init_into_class) %} + {% if members_list is not none or function.is_public(check_name=False) %} + {% include function|get_template with context %} + {% endif %} + {% endif %} + {% endfor %} + {% endwith %} + {% endif %} + {% endwith %} + + {% if config.show_submodules %} + {% with modules = obj.modules|filter_objects( + filters=config.filters, + members_list=members_list, + inherited_members=config.inherited_members, + keep_no_docstrings=config.show_if_no_docstring, + ) %} + {% if modules %} + {% if config.show_category_heading %} + {% filter heading(heading_level, id=html_id ~ "-modules") %}Modules{% endfilter %} + {% endif %} + {% with heading_level = heading_level + extra_level %} + {% for module in modules|order_members(config.members_order.alphabetical, members_list) %} + {% if members_list is not none or module.is_public(check_name=False) %} + {% include module|get_template with context %} + {% endif %} + {% endfor %} + {% endwith %} + {% endif %} + {% endwith %} + {% endif %} + + {% endwith %} + + {% else %} + + {% for child in obj.all_members + |filter_objects( + filters=config.filters, + members_list=members_list, + inherited_members=config.inherited_members, + keep_no_docstrings=config.show_if_no_docstring, + ) + |order_members(config.members_order, members_list) + %} + + {% if not (obj.is_class and child.name == "__init__" and config.merge_init_into_class) %} + + {% if members_list is not none or child.is_public(check_name=False) %} + {% if child.is_attribute %} + {% with attribute = child %} + {% include attribute|get_template with context %} + {% endwith %} + + {% elif child.is_class %} + {% with class = child %} + {% include class|get_template with context %} + {% endwith %} + + {% elif child.is_function %} + {% with function = child %} + {% include function|get_template with context %} + {% endwith %} + + {% elif child.is_module and config.show_submodules %} + {% with module = child %} + {% include module|get_template with context %} + {% endwith %} + + {% endif %} + {% endif %} + + {% endif %} + + {% endfor %} + + {% endif %} + +
+{% endif %} diff --git a/docs/templates/python/material/attributes_table.html b/docs/templates/python/material/attributes_table.html new file mode 100644 index 000000000..49971459b --- /dev/null +++ b/docs/templates/python/material/attributes_table.html @@ -0,0 +1,70 @@ +{% if obj.members %} + {{ log.debug("Rendering children of " + obj.path) }} + +
+ {# Notice inherited members false #} + {% with attributes = obj.attributes|filter_objects( + filters=config.filters, + members_list=members_list, + inherited_members=false, + keep_no_docstrings=config.show_if_no_docstring, + ) %} + + + + + + + + + + + {% for attribute in attributes %} + + + + + + + {% endfor %} + +
NameTypeDescriptionDefault
{{ attribute.name }} + {% if attribute.annotation %} + {% with expression = attribute.annotation %} + {% include "expression.html" with context %} + {% endwith %} + {% endif %} + +
+ {{ attribute.docstring.value }} +
+
+ {% if attribute.value %} + {% with expression = attribute.value %} + {% include "expression.html" with context %} + {% endwith %} + {% else %} + - + {% endif %} +
+ {%endwith %} + {% with classes = obj.classes|filter_objects( + filters=config.filters, + members_list=members_list, + inherited_members=false, + keep_no_docstrings=config.show_if_no_docstring, + ) %} + {% for class in classes %} + {% filter heading(heading_level, id=html_id ~ "-attributes") %}{{class.name}}{% endfilter %} +
+ {% set root = False %} + {% set heading_level = heading_level + 1 %} + {% set old_obj = obj %} + {% set obj = class %} + {% include "attributes_table.html" with context %} + {% set obj = old_obj %} +
+ {% endfor %} + {%endwith %} +
+{% endif %} diff --git a/docs/templates/python/material/class.html b/docs/templates/python/material/class.html new file mode 100644 index 000000000..940103b4f --- /dev/null +++ b/docs/templates/python/material/class.html @@ -0,0 +1,35 @@ +{% extends "_base/class.html" %} +{% set anta_test = namespace(found=false) %} +{% for base in class.bases %} +{% set basestr = base | string %} +{% if "AntaTest" == basestr %} +{% set anta_test.found = True %} +{% endif %} +{% endfor %} +{% block children %} +{% if anta_test.found %} + {% set root = False %} + {% set heading_level = heading_level + 1 %} + {% include "anta_test.html" with context %} + {# render source after children - TODO make add flag to respect disabling it.. though do we want to disable?#} +
+ Source code in + {%- if class.relative_filepath.is_absolute() -%} + {{ class.relative_package_filepath }} + {%- else -%} + {{ class.relative_filepath }} + {%- endif -%} + + {{ class.source|highlight(language="python", linestart=class.lineno, linenums=True) }} +
+{% else %} + {{ super() }} +{% endif %} +{% endblock children %} + +{# Do not render source before children for AntaTest #} +{% block source %} +{% if not anta_test.found %} + {{ super() }} +{% endif %} +{% endblock source %} diff --git a/docs/templates/python/material/docstring/examples.html b/docs/templates/python/material/docstring/examples.html new file mode 100644 index 000000000..d8709c9b3 --- /dev/null +++ b/docs/templates/python/material/docstring/examples.html @@ -0,0 +1,14 @@ +{{ log.debug("Rendering examples section") }} + +{% import "language.html" as lang with context %} + +
+ {{ "Examples" | convert_markdown(heading_level +1, html_id, strip_paragraph=True) }} + {% for section_type, sub_section in section.value %} + {% if section_type.value == "text" %} + {{ sub_section|convert_markdown(heading_level, html_id) }} + {% elif section_type.value == "examples" %} + {{ sub_section|highlight(language="pycon", linenums=False) }} + {% endif %} + {% endfor %} +
diff --git a/examples/tests.yaml b/examples/tests.yaml index e56460c28..72606b112 100644 --- a/examples/tests.yaml +++ b/examples/tests.yaml @@ -218,11 +218,11 @@ anta.tests.profiles: anta.tests.ptp: - VerifyPtpModeStatus: - - VerifyPtpPortModeStatus: - - VerifyPtpLockStatus: - VerifyPtpGMStatus: gmid: 0xec:46:70:ff:fe:00:ff:a9 + - VerifyPtpLockStatus: - VerifyPtpOffset: + - VerifyPtpPortModeStatus: anta.tests.security: - VerifySSHStatus: diff --git a/mkdocs.yml b/mkdocs.yml index 2fe6c232f..183adb597 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -76,12 +76,12 @@ extra_javascript: watch: - docs - # Watch src/ directory to reload on changes to docstrings for mkdocstrings plugin. - anta plugins: - mkdocstrings: default_handler: python + custom_templates: docs/templates handlers: python: import: @@ -89,6 +89,7 @@ plugins: - https://mkdocstrings.github.io/objects.inv - https://mkdocstrings.github.io/griffe/objects.inv options: + docstring_style: numpy docstring_options: ignore_init_summary: true docstring_section_style: table @@ -105,6 +106,7 @@ plugins: # show_symbol_type_toc: true # default filters here filters: ["!^_[^_]"] + - search: lang: en - git-revision-date-localized: @@ -155,7 +157,7 @@ nav: - Getting Started: getting-started.md - Installation: requirements-and-installation.md - Inventory & Tests catalog: usage-inventory-catalog.md - - Anta CLI: + - ANTA CLI: - Overview: cli/overview.md - NRFU: cli/nrfu.md - Execute commands: cli/exec.md @@ -169,19 +171,22 @@ nav: - Caching in ANTA: advanced_usages/caching.md - Developing ANTA tests: advanced_usages/custom-tests.md - ANTA as a Python Library: advanced_usages/as-python-lib.md - - Test Catalog Documentation: + - Tests Documentation: - Overview: api/tests.md - AAA: api/tests.aaa.md - BFD: api/tests.bfd.md - Configuration: api/tests.configuration.md - Connectivity: api/tests.connectivity.md - Field Notices: api/tests.field_notices.md + - GreenT: api/tests.greent.md - Hardware: api/tests.hardware.md - Interfaces: api/tests.interfaces.md + - LANZ: api/tests.lanz.md - Logging: api/tests.logging.md - MLAG: api/tests.mlag.md - Multicast: api/tests.multicast.md - Profiles: api/tests.profiles.md + - PTP: api/tests.ptp.md - Routing: - Generic: api/tests.routing.generic.md - BGP: api/tests.routing.bgp.md diff --git a/pyproject.toml b/pyproject.toml index 551629cb7..5c1fd4599 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -76,6 +76,7 @@ dev = [ "yamllint>=1.32.0", ] doc = [ + "fontawesome_markdown", "mkdocs>=1.3.1", "mkdocs-autorefs>=0.4.1", "mkdocs-bootswatch>=1.1", @@ -84,9 +85,8 @@ doc = [ "mkdocs-material>=8.3.9", "mkdocs-material-extensions>=1.0.3", "mkdocstrings[python]>=0.20.0", - "fontawesome_markdown", "mike==2.0.0", - "griffe" + "griffe", ] [project.urls] @@ -97,7 +97,6 @@ Contributing = "https://www.anta.ninja/main/contribution/" [project.scripts] anta = "anta.cli:cli" - ################################ # Tools ################################ @@ -303,7 +302,6 @@ exclude = [ "aioeapi.py" # Remove this when https://github.com/jeremyschulman/aio-eapi/pull/13 is merged ] -# Same as Black. line-length = 165 # Assume Python 3.8 as this is the lowest supported version for ANTA @@ -332,6 +330,9 @@ unfixable = [] # Allow unused variables when underscore-prefixed. dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" +[tool.ruff.lint.pydocstyle] +convention = "numpy" + [tool.ruff.lint.mccabe] # Unlike Flake8, default to a complexity level of 10. max-complexity = 10