anta/anta/cli/nrfu/__init__.py
Daniel Baumann 8a6a3342fc
Merging upstream version 1.3.0.
Signed-off-by: Daniel Baumann <daniel@debian.org>
2025-03-17 07:33:51 +01:00

150 lines
4.4 KiB
Python

# 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."""
from __future__ import annotations
from typing import TYPE_CHECKING
import click
from anta.cli.nrfu import commands
from anta.cli.utils import AliasedGroup, catalog_options, inventory_options
from anta.result_manager import ResultManager
from anta.result_manager.models import AntaTestStatus
if TYPE_CHECKING:
from anta.catalog import AntaCatalog
from anta.inventory import AntaInventory
class IgnoreRequiredWithHelp(AliasedGroup):
"""Custom Click Group.
https://stackoverflow.com/questions/55818737/python-click-application-required-parameters-have-precedence-over-sub-command-he
Solution to allow help without required options on subcommand
This is not planned to be fixed in click as per: https://github.com/pallets/click/issues/295#issuecomment-708129734.
"""
def parse_args(self, ctx: click.Context, args: list[str]) -> list[str]:
"""Ignore MissingParameter exception when parsing arguments if `--help` is present for a subcommand."""
# Adding a flag for potential callbacks
ctx.ensure_object(dict)
ctx.obj["args"] = args
if "--help" in args:
ctx.obj["_anta_help"] = True
try:
return super().parse_args(ctx, args)
except click.MissingParameter:
if "--help" not in args:
raise
# Fake presence of the required params so that help can display
for param in self.params:
if param.required:
param.value_is_missing = lambda value: False # type: ignore[method-assign] # noqa: ARG005
return super().parse_args(ctx, args)
HIDE_STATUS: list[str] = list(AntaTestStatus)
HIDE_STATUS.remove("unset")
@click.group(invoke_without_command=True, cls=IgnoreRequiredWithHelp)
@click.pass_context
@inventory_options
@catalog_options
@click.option(
"--device",
"-d",
help="Run tests on a specific device. Can be provided multiple times.",
type=str,
multiple=True,
required=False,
)
@click.option(
"--test",
"-t",
help="Run a specific test. Can be provided multiple times.",
type=str,
multiple=True,
required=False,
)
@click.option(
"--ignore-status",
help="Exit code will always be 0.",
show_envvar=True,
is_flag=True,
default=False,
)
@click.option(
"--ignore-error",
help="Exit code will be 0 if all tests succeeded or 1 if any test failed.",
show_envvar=True,
is_flag=True,
default=False,
)
@click.option(
"--hide",
default=None,
type=click.Choice(HIDE_STATUS, case_sensitive=False),
multiple=True,
help="Hide results by type: success / failure / error / skipped'.",
required=False,
)
@click.option(
"--dry-run",
help="Run anta nrfu command but stop before starting to execute the tests. Considers all devices as connected.",
type=str,
show_envvar=True,
is_flag=True,
default=False,
)
def nrfu(
ctx: click.Context,
inventory: AntaInventory,
tags: set[str] | None,
catalog: AntaCatalog,
device: tuple[str],
test: tuple[str],
hide: tuple[str],
*,
ignore_status: bool,
ignore_error: bool,
dry_run: bool,
catalog_format: str = "yaml",
) -> None:
"""Run ANTA tests on selected inventory devices."""
# If help is invoke somewhere, skip the command
if ctx.obj.get("_anta_help"):
return
# We use ctx.obj to pass stuff to the next Click functions
ctx.ensure_object(dict)
ctx.obj["result_manager"] = ResultManager()
ctx.obj["ignore_status"] = ignore_status
ctx.obj["ignore_error"] = ignore_error
ctx.obj["hide"] = set(hide) if hide else None
ctx.obj["catalog"] = catalog
ctx.obj["catalog_format"] = catalog_format
ctx.obj["inventory"] = inventory
ctx.obj["tags"] = tags
ctx.obj["device"] = device
ctx.obj["test"] = test
ctx.obj["dry_run"] = dry_run
# Invoke `anta nrfu table` if no command is passed
if not ctx.invoked_subcommand:
ctx.invoke(commands.table)
nrfu.add_command(commands.table)
nrfu.add_command(commands.csv)
nrfu.add_command(commands.json)
nrfu.add_command(commands.text)
nrfu.add_command(commands.tpl_report)
nrfu.add_command(commands.md_report)