pyATS Genie Health Checks
genie-libs-health is a Python library within the pyATS framework, providing a robust mechanism for monitoring network device health status. It allows users to define custom health checks using YAML files, which are then executed against devices configured in a pyATS testbed. This library is part of the `genie` ecosystem and is primarily used for automated network device validation and troubleshooting. It is currently at version `26.3` and follows the `genie` release cadence, which typically aligns with `pyATS` monthly releases.
Common errors
-
ImportError: cannot import name 'Health' from 'genie_libs_health'
cause Attempting to import the `Health` class directly from the top-level package name `genie_libs_health`.fixThe `Health` class is nested within the `genie.libs.health.health` module. Use `from genie.libs.health.health import Health`. -
pyats.topology.loader.exceptions.InvalidTestbedError: Cannot load testbed 'None' or Failed to connect to device 'my_device'
cause The pyATS testbed file is missing, malformed, or the specified device in the testbed cannot be reached or authenticated.fixVerify the path to your `testbed.yaml` file. Check its YAML syntax. Ensure the device IP, username, password, and connection protocol are correct and that the device is network-reachable from where the script is run. -
AttributeError: 'NoneType' object has no attribute 'cli' (or similar during device interaction)
cause This usually indicates that the device object from the testbed was not properly loaded, or `device.connect()` failed to establish a connection, leaving the device object in an unusable state.fixEnsure `testbed.devices['my_device']` successfully retrieves a device object and that `my_device.connect()` completes without exceptions before attempting to run health checks. -
yaml.scanner.ScannerError: while scanning a simple key
cause The health check YAML file (`health_check.yaml`) contains syntax errors, such as incorrect indentation, missing colons, or improper structure.fixReview the health check YAML file carefully for any syntax errors. Use a YAML linter or validator to identify issues. Pay close attention to indentation and proper key-value pairing.
Warnings
- breaking pyATS and Genie (including genie-libs-health) versions are tightly coupled. Installing incompatible versions can lead to `ImportError`, `AttributeError`, or unexpected behavior.
- gotcha Health checks require a properly configured pyATS testbed and reachable network devices. Common failures stem from incorrect device IPs, usernames, passwords, or network connectivity issues.
- gotcha Health check definitions in YAML must strictly adhere to the `genie-libs-health` schema. Syntax errors, incorrect command names, or malformed regex patterns will lead to runtime exceptions or incorrect check results.
- gotcha Underlying Genie operational parsers (`genie.libs.ops`) must successfully parse command output for health checks to function. If a parser fails, the health check for that command will report an error.
Install
-
pip install genie-libs-health
Imports
- Health
from genie_libs_health import Health
from genie.libs.health.health import Health
Quickstart
import yaml
from unittest.mock import Mock # For a truly runnable example without a real device
from genie.libs.health.health import Health
# --- 1. Create a mock device and testbed for demonstration ---
# In a real scenario, you would load a testbed from a file:
# from pyats.topology import loader
# testbed = loader.load('path/to/testbed.yaml')
# my_device = testbed.devices['your_device_name']
# Mock a device and its connection/execution methods
mock_device = Mock()
mock_device.name = "my_mock_device"
mock_device.os = "iosxe"
mock_device.connected = False
mock_device.api.execute.return_value = {
"show version": "Cisco IOS XE Software, Version 17.3.4",
"show processes cpu sorted": "CPU utilization for five seconds: 5%/1%; one minute: 4%; five minutes: 3%"
}
# Define connect/disconnect behavior for the mock
def mock_connect():
print(f"Attempting to connect to {mock_device.name} (mocked)...")
mock_device.connected = True
print(f"Successfully connected to {mock_device.name} (mocked).")
mock_device.connect.side_effect = mock_connect
def mock_disconnect():
print(f"Disconnecting from {mock_device.name} (mocked)...")
mock_device.connected = False
mock_device.disconnect.side_effect = mock_disconnect
# Create a mock testbed containing our mock device
mock_testbed = Mock()
mock_testbed.devices = {'my_mock_device': mock_device}
mock_testbed.name = "mock_testbed"
# --- 2. Define a simple health check YAML in-memory ---
health_yaml_content = """
health_check_sections:
section_version_check:
commands:
show version:
- '.*Cisco IOS XE Software.*' # Checks for IOS XE in 'show version' output
section_cpu_usage_check:
commands:
show processes cpu sorted:
- 'CPU utilization for five seconds: [0-9]{1,2}%/' # Checks if CPU is valid percentage
"""
health_data = yaml.safe_load(health_yaml_content)
# --- 3. Initialize and run Health checks ---
try:
# Use the mock device (in a real scenario, this would be from testbed.devices)
my_device = mock_testbed.devices['my_mock_device']
my_device.connect() # This will call our mock_connect function
# Create Health object with the device and parsed health data
health = Health(device=my_device, health_data=health_data)
# Run all defined health checks
print(f"\nRunning health checks on {my_device.name}...")
health_result = health.check_all()
# Print results
print("\nHealth Check Results Summary:")
for section, result in health_result.items():
print(f" Section: '{section}' -> Status: {result['status']}")
if result['status'] == 'Fail':
print(f" Reason: {result.get('reason', 'No specific reason provided.')}")
for command, cmd_result in result.get('commands', {}).items():
if cmd_result.get('status') == 'Fail':
print(f" Command '{command}' failed: {cmd_result.get('reason', 'N/A')}")
except Exception as e:
print(f"An unexpected error occurred: {e}")
finally:
if my_device and my_device.connected:
my_device.disconnect()