Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(anta.tests): Add test for Maintenance mode #1067

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions anta/tests/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,3 +345,68 @@ def test(self) -> None:

if act_condition != exp_condition or act_stratum != exp_stratum:
self.result.is_failure(f"{ntp_server} - Bad association - Condition: {act_condition}, Stratum: {act_stratum}")


class VerifyMaintenance(AntaTest):
"""Verifies that the device is not currently under or entering maintenance.

Expected Results
----------------
* Success: The test will pass if the device is not under or entering maintenance.
* Failure: The test will fail if the device is under or entering maintenance.

Examples
--------
```yaml
anta.tests.system:
- VerifyMaintenance:
```
"""

categories: ClassVar[list[str]] = ["Maintenance"]
commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show maintenance", revision=1)]

@AntaTest.anta_test
def test(self) -> None:
"""Main test function for VerifyMaintenance."""
self.result.is_success()

# If units is not empty we have to examine the output for details.
if units := get_value(self.instance_commands[0].json_output, "units"):
unitsundermaintenance = []
unitsenteringmaintenance = []
Comment on lines +376 to +377
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
unitsundermaintenance = []
unitsenteringmaintenance = []
units_under_maintenance = []
units_entering_maintenance = []

under = False
entering = False
Comment on lines +378 to +379
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you don't need the flags as you just need to check if the lists are empty or not

causes = []
# Iterate over units, check for units under or entering maintenance, and examine the causes.
for unit, info in units.items():
if info["state"] == "underMaintenance":
unitsundermaintenance.append(unit)
under = True
Comment on lines +384 to +385
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
unitsundermaintenance.append(unit)
under = True
units_under_maintenance.append(unit)

elif info["state"] == "maintenanceModeEnter":
unitsenteringmaintenance.append(unit)
entering = True
Comment on lines +387 to +388
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
unitsenteringmaintenance.append(unit)
entering = True
units_entering_maintenance.append(unit)

if info["adminState"] == "underMaintenance" and "Quiesce is configured" not in causes:
causes.append("Quiesce is configured")
if info["onBootMaintenance"] and "On-boot maintenance is configured" not in causes:
causes.append("On-boot maintenance is configured")
if info["intfsViolatingTrafficThreshold"] and "Interface traffic threshold violation" not in causes:
causes.append("Interface traffic threshold violation")

# This can occur if maintenance is configured but no unit is configured with 'quiesce'.
if not under and not entering and not causes:
self.result.is_success()
Comment on lines +397 to +398
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you already set is_success at the beginning so you don't need this. you can just return


# Building the error message.
else:
message = ""
unitsundermaintenance = ", ".join(unitsundermaintenance)
unitsenteringmaintenance = " ".join(unitsenteringmaintenance)
causes = ", ".join(causes)
if under:
message += f"Units under maintenance: '{unitsundermaintenance}'. "
if entering:
message += f"Units entering maintenance: '{unitsenteringmaintenance}'. "
if len(causes) > 0:
message += f"Possible causes: {causes}"
self.result.is_failure(message)
2 changes: 2 additions & 0 deletions examples/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,8 @@ anta.tests.system:
# Verifies there are no core dump files.
- VerifyFileSystemUtilization:
# Verifies that no partition is utilizing more than 75% of its disk space.
- VerifyMaintenance:
# Verifies that the device is not currently under or entering maintenance.
- VerifyMemoryUtilization:
# Verifies whether the memory utilization is below 75%.
- VerifyNTP:
Expand Down
200 changes: 200 additions & 0 deletions tests/units/anta_tests/test_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
VerifyCoredump,
VerifyCPUUtilization,
VerifyFileSystemUtilization,
VerifyMaintenance,
VerifyMemoryUtilization,
VerifyNTP,
VerifyNTPAssociations,
Expand Down Expand Up @@ -496,4 +497,203 @@
],
},
},
{
"name": "success-no-maintenance-configured",
"test": VerifyMaintenance,
"eos_data": [
{
"units": {},
"interfaces": {},
"vrfs": {},
"warnings": ["Maintenance Mode is disabled."],
},
],
"inputs": None,
"expected": {"result": "success"},
},
{
"name": "success-maintenance-configured-but-not-enabled",
"test": VerifyMaintenance,
"eos_data": [
{
"units": {
"System": {
"state": "active",
"adminState": "active",
"stateChangeTime": 0.0,
"onBootMaintenance": False,
"intfsViolatingTrafficThreshold": False,
"aggInBpsRate": 0,
"aggOutBpsRate": 0,
}
},
"interfaces": {},
"vrfs": {},
},
],
"inputs": None,
"expected": {"result": "success"},
},
{
"name": "success-multiple-units-but-not-enabled",
"test": VerifyMaintenance,
"eos_data": [
{
"units": {
"mlag": {
"state": "active",
"adminState": "active",
"stateChangeTime": 0.0,
"onBootMaintenance": False,
"intfsViolatingTrafficThreshold": False,
"aggInBpsRate": 0,
"aggOutBpsRate": 0,
},
"System": {
"state": "active",
"adminState": "active",
"stateChangeTime": 0.0,
"onBootMaintenance": False,
"intfsViolatingTrafficThreshold": False,
"aggInBpsRate": 0,
"aggOutBpsRate": 0,
},
},
"interfaces": {},
"vrfs": {},
},
],
"inputs": None,
"expected": {"result": "success"},
},
{
"name": "failure-maintenance-enabled",
"test": VerifyMaintenance,
"eos_data": [
{
"units": {
"mlag": {
"state": "underMaintenance",
"adminState": "underMaintenance",
"stateChangeTime": 1741257120.9532886,
"onBootMaintenance": False,
"intfsViolatingTrafficThreshold": False,
"aggInBpsRate": 0,
"aggOutBpsRate": 0,
},
"System": {
"state": "active",
"adminState": "active",
"stateChangeTime": 0.0,
"onBootMaintenance": False,
"intfsViolatingTrafficThreshold": False,
"aggInBpsRate": 0,
"aggOutBpsRate": 0,
},
},
"interfaces": {},
"vrfs": {},
},
],
"inputs": None,
"expected": {
"result": "failure",
"messages": [
"Units under maintenance: 'mlag'. Possible causes: Quiesce is configured",
],
},
},
{
"name": "failure-multiple-reasons",
"test": VerifyMaintenance,
"eos_data": [
{
"units": {
"mlag": {
"state": "underMaintenance",
"adminState": "underMaintenance",
"stateChangeTime": 1741257120.9532895,
"onBootMaintenance": False,
"intfsViolatingTrafficThreshold": False,
"aggInBpsRate": 0,
"aggOutBpsRate": 0,
},
"System": {
"state": "maintenanceModeEnter",
"adminState": "underMaintenance",
"stateChangeTime": 1741257669.7231765,
"onBootMaintenance": False,
"intfsViolatingTrafficThreshold": False,
"aggInBpsRate": 0,
"aggOutBpsRate": 0,
},
},
"interfaces": {},
"vrfs": {},
},
],
"inputs": None,
"expected": {
"result": "failure",
"messages": [
"Units under maintenance: 'mlag'. Units entering maintenance: 'System'. Possible causes: Quiesce is configured",
],
},
},
{
"name": "failure-onboot-maintenance",
"test": VerifyMaintenance,
"eos_data": [
{
"units": {
"System": {
"state": "underMaintenance",
"adminState": "underMaintenance",
"stateChangeTime": 1741258774.3756502,
"onBootMaintenance": True,
"intfsViolatingTrafficThreshold": False,
"aggInBpsRate": 0,
"aggOutBpsRate": 0,
}
},
"interfaces": {},
"vrfs": {},
},
],
"inputs": None,
"expected": {
"result": "failure",
"messages": [
"Units under maintenance: 'System'. Possible causes: Quiesce is configured, On-boot maintenance is configured",
],
},
},
{
"name": "failure-entering-maintenance-interface-violation",
"test": VerifyMaintenance,
"eos_data": [
{
"units": {
"System": {
"state": "maintenanceModeEnter",
"adminState": "underMaintenance",
"stateChangeTime": 1741257669.7231765,
"onBootMaintenance": False,
"intfsViolatingTrafficThreshold": True,
"aggInBpsRate": 0,
"aggOutBpsRate": 0,
}
},
"interfaces": {},
"vrfs": {},
},
],
"inputs": None,
"expected": {
"result": "failure",
"messages": [
"Units entering maintenance: 'System'. Possible causes: Quiesce is configured, Interface traffic threshold violation",
],
},
},
]
Loading