Skip to content

Commit

Permalink
Merge branch 'main' into fix/isis_input
Browse files Browse the repository at this point in the history
  • Loading branch information
gmuloc authored Jan 15, 2025
2 parents 54f6742 + d57b53e commit 432ff67
Show file tree
Hide file tree
Showing 260 changed files with 4,821 additions and 2,091 deletions.
33 changes: 7 additions & 26 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@ on:

jobs:
pypi:
name: Publish version to Pypi servers
name: Publish Python 🐍 distribution 📦 to PyPI
runs-on: ubuntu-latest
environment:
name: production
url: https://pypi.org/p/anta
permissions:
id-token: write
steps:
- name: Checkout code
uses: actions/checkout@v4
Expand All @@ -19,33 +24,9 @@ jobs:
- name: Build package
run: |
python -m build
- name: Publish package to Pypi
- name: Publish distribution 📦 to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}

release-coverage:
name: Updated ANTA release coverage badge
runs-on: ubuntu-20.04
needs: [pypi]
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
run: pip install genbadge[coverage] tox tox-gh-actions
- name: "Run pytest via tox for ${{ matrix.python }}"
run: tox
- name: Generate coverage badge
run: genbadge coverage -i .coverage.xml -o badge/latest-release-coverage.svg
- name: Publish coverage badge to gh-pages branch
uses: JamesIves/github-pages-deploy-action@v4
with:
branch: coverage-badge
folder: badge
release-doc:
name: "Publish documentation for release ${{github.ref_name}}"
runs-on: ubuntu-latest
Expand Down
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ repos:
- '<!--| ~| -->'

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.4
rev: v0.9.1
hooks:
- id: ruff
name: Run Ruff linter
Expand All @@ -55,7 +55,7 @@ repos:
name: Run Ruff formatter

- repo: https://github.com/pycqa/pylint
rev: "v3.3.2"
rev: "v3.3.3"
hooks:
- id: pylint
name: Check code style with pylint
Expand Down Expand Up @@ -85,7 +85,7 @@ repos:
types: [text]

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.14.0
rev: v1.14.1
hooks:
- id: mypy
name: Check typing with mypy
Expand Down
2 changes: 1 addition & 1 deletion anta/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""Arista Network Test Automation (ANTA) Framework."""
Expand Down
10 changes: 4 additions & 6 deletions anta/catalog.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""Catalog related functions."""
Expand Down Expand Up @@ -182,7 +182,7 @@ def flatten_modules(data: dict[str, Any], package: str | None = None) -> dict[Mo
except Exception as e:
# A test module is potentially user-defined code.
# We need to catch everything if we want to have meaningful logs
module_str = f"{module_name[1:] if module_name.startswith('.') else module_name}{f' from package {package}' if package else ''}"
module_str = f"{module_name.removeprefix('.')}{f' from package {package}' if package else ''}"
message = f"Module named {module_str} cannot be imported. Verify that the module exists and there is no Python syntax issues."
anta_log_exception(e, message, logger)
raise ValueError(message) from e
Expand Down Expand Up @@ -223,16 +223,14 @@ def check_tests(cls: type[AntaCatalogFile], data: Any) -> Any: # noqa: ANN401
raise ValueError(msg) # noqa: TRY004 pydantic catches ValueError or AssertionError, no TypeError
if len(test_definition) != 1:
msg = (
f"Syntax error when parsing: {test_definition}\n"
"It must be a dictionary with a single entry. Check the indentation in the test catalog."
f"Syntax error when parsing: {test_definition}\nIt must be a dictionary with a single entry. Check the indentation in the test catalog."
)
raise ValueError(msg)
for test_name, test_inputs in test_definition.copy().items():
test: type[AntaTest] | None = getattr(module, test_name, None)
if test is None:
msg = (
f"{test_name} is not defined in Python module {module.__name__}"
f"{f' (from {module.__file__})' if module.__file__ is not None else ''}"
f"{test_name} is not defined in Python module {module.__name__}{f' (from {module.__file__})' if module.__file__ is not None else ''}"
)
raise ValueError(msg)
test_definitions.append(AntaTestDefinition(test=test, inputs=test_inputs))
Expand Down
2 changes: 1 addition & 1 deletion anta/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""ANTA CLI."""
Expand Down
2 changes: 1 addition & 1 deletion anta/cli/_main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""ANTA CLI."""
Expand Down
2 changes: 1 addition & 1 deletion anta/cli/check/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""Click commands to validate configuration files."""
Expand Down
2 changes: 1 addition & 1 deletion anta/cli/check/commands.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
# pylint: disable = redefined-outer-name
Expand Down
2 changes: 1 addition & 1 deletion anta/cli/console.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""ANTA Top-level Console.
Expand Down
2 changes: 1 addition & 1 deletion anta/cli/debug/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""Click commands to execute EOS commands on remote devices."""
Expand Down
2 changes: 1 addition & 1 deletion anta/cli/debug/commands.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
# pylint: disable = redefined-outer-name
Expand Down
2 changes: 1 addition & 1 deletion anta/cli/debug/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""Utils functions to use with anta.cli.debug module."""
Expand Down
2 changes: 1 addition & 1 deletion anta/cli/exec/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""Click commands to execute various scripts on EOS devices."""
Expand Down
2 changes: 1 addition & 1 deletion anta/cli/exec/commands.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""Click commands to execute various scripts on EOS devices."""
Expand Down
2 changes: 1 addition & 1 deletion anta/cli/exec/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.

Expand Down
2 changes: 1 addition & 1 deletion anta/cli/get/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""Click commands to get information from or generate inventories."""
Expand Down
2 changes: 1 addition & 1 deletion anta/cli/get/commands.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
# pylint: disable = redefined-outer-name
Expand Down
2 changes: 1 addition & 1 deletion anta/cli/get/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""Utils functions to use with anta.cli.get.commands module."""
Expand Down
2 changes: 1 addition & 1 deletion anta/cli/nrfu/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""Click commands that run ANTA tests using anta.runner."""
Expand Down
2 changes: 1 addition & 1 deletion anta/cli/nrfu/commands.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""Click commands that render ANTA tests results."""
Expand Down
4 changes: 2 additions & 2 deletions anta/cli/nrfu/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""Utils functions to use with anta.cli.nrfu.commands module."""
Expand Down Expand Up @@ -157,7 +157,7 @@ def save_markdown_report(ctx: click.Context, md_output: pathlib.Path) -> None:
Path to save the markdown report.
"""
try:
MDReportGenerator.generate(results=_get_result_manager(ctx), md_filename=md_output)
MDReportGenerator.generate(results=_get_result_manager(ctx).sort(["name", "categories", "test"]), md_filename=md_output)
console.print(f"Markdown report saved to {md_output} ✅", style="cyan")
except OSError:
console.print(f"Failed to save Markdown report to {md_output} ❌", style="cyan")
Expand Down
9 changes: 6 additions & 3 deletions anta/cli/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""Utils functions to use with anta.cli module."""
Expand All @@ -17,6 +17,7 @@
from anta.catalog import AntaCatalog
from anta.inventory import AntaInventory
from anta.inventory.exceptions import InventoryIncorrectSchemaError, InventoryRootKeyError
from anta.logger import anta_log_exception

if TYPE_CHECKING:
from click import Option
Expand Down Expand Up @@ -242,7 +243,8 @@ def wrapper(
insecure=insecure,
disable_cache=disable_cache,
)
except (TypeError, ValueError, YAMLError, OSError, InventoryIncorrectSchemaError, InventoryRootKeyError):
except (TypeError, ValueError, YAMLError, OSError, InventoryIncorrectSchemaError, InventoryRootKeyError) as e:
anta_log_exception(e, f"Failed to parse the inventory: {inventory}", logger)
ctx.exit(ExitCode.USAGE_ERROR)
return f(*args, inventory=i, **kwargs)

Expand Down Expand Up @@ -319,7 +321,8 @@ def wrapper(
try:
file_format = catalog_format.lower()
c = AntaCatalog.parse(catalog, file_format=file_format) # type: ignore[arg-type]
except (TypeError, ValueError, YAMLError, OSError):
except (TypeError, ValueError, YAMLError, OSError) as e:
anta_log_exception(e, f"Failed to parse the catalog: {catalog}", logger)
ctx.exit(ExitCode.USAGE_ERROR)
return f(*args, catalog=c, **kwargs)

Expand Down
31 changes: 29 additions & 2 deletions anta/constants.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""Constants used in ANTA."""

from __future__ import annotations

ACRONYM_CATEGORIES: set[str] = {"aaa", "mlag", "snmp", "bgp", "ospf", "vxlan", "stp", "igmp", "ip", "lldp", "ntp", "bfd", "ptp", "lanz", "stun", "vlan"}
ACRONYM_CATEGORIES: set[str] = {
"aaa",
"avt",
"bfd",
"bgp",
"igmp",
"ip",
"isis",
"lanz",
"lldp",
"mlag",
"ntp",
"ospf",
"ptp",
"snmp",
"stp",
"stun",
"vlan",
"vxlan",
}
"""A set of network protocol or feature acronyms that should be represented in uppercase."""

MD_REPORT_TOC = """**Table of Contents:**
Expand All @@ -26,3 +45,11 @@
r"No source interface .*",
]
"""List of known EOS errors that should set a test status to 'failure' with the error message."""

UNSUPPORTED_PLATFORM_ERRORS = [
"not supported on this hardware platform",
"Invalid input (at token 2: 'trident')",
]
"""Error messages indicating platform or hardware unsupported commands.
Will set the test status to 'skipped'. Includes both general hardware
platform errors and specific ASIC family limitations."""
29 changes: 27 additions & 2 deletions anta/custom_types.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""Module that provides predefined types for AntaTest.Input instances."""
Expand Down Expand Up @@ -154,16 +154,38 @@ def validate_regex(value: str) -> str:
ErrDisableReasons = Literal[
"acl",
"arp-inspection",
"bgp-session-tracking",
"bpduguard",
"dot1x",
"dot1x-coa",
"dot1x-session-replace",
"evpn-sa-mh",
"fabric-link-failure",
"fabric-link-flap",
"hitless-reload-down",
"lacp-no-portid",
"lacp-rate-limit",
"license-enforce",
"link-flap",
"mlagasu",
"mlagdualprimary",
"mlagissu",
"mlagmaintdown",
"no-internal-vlan",
"out-of-voqs",
"portchannelguard",
"portgroup-disabled",
"portsec",
"speed-misconfigured",
"storm-control",
"stp-no-portid",
"stuck-queue",
"tapagg",
"uplink-failure-detection",
"xcvr-misconfigured",
"xcvr-overheat",
"xcvr-power-unsupported",
"xcvr-unsupported",
]
ErrDisableInterval = Annotated[int, Field(ge=30, le=86400)]
Percent = Annotated[float, Field(ge=0.0, le=100.0)]
Expand Down Expand Up @@ -208,7 +230,6 @@ def validate_regex(value: str) -> str:
SnmpErrorCounter = Literal[
"inVersionErrs", "inBadCommunityNames", "inBadCommunityUses", "inParseErrs", "outTooBigErrs", "outNoSuchNameErrs", "outBadValueErrs", "outGeneralErrs"
]

IPv4RouteType = Literal[
"connected",
"static",
Expand Down Expand Up @@ -238,3 +259,7 @@ def validate_regex(value: str) -> str:
"Route Cache Route",
"CBF Leaked Route",
]
SnmpVersion = Literal["v1", "v2c", "v3"]
SnmpHashingAlgorithm = Literal["MD5", "SHA", "SHA-224", "SHA-256", "SHA-384", "SHA-512"]
SnmpEncryptionAlgorithm = Literal["AES-128", "AES-192", "AES-256", "DES"]
DynamicVlanSource = Literal["dmf", "dot1x", "dynvtep", "evpn", "mlag", "mlagsync", "mvpn", "swfwd", "vccbfd"]
2 changes: 1 addition & 1 deletion anta/decorators.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Copyright (c) 2023-2025 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""decorators for tests."""
Expand Down
Loading

0 comments on commit 432ff67

Please sign in to comment.