NAPALM: Network Automation and Programmability Abstraction Layer with Multivendor Support
NAPALM (Network Automation and Programmability Abstraction Layer with Multivendor support) is a Python library that provides a unified API to interact with various network devices from different vendors (e.g., Cisco IOS/XR/NX-OS, Arista EOS, Juniper Junos). It abstracts away vendor-specific complexities, offering a consistent way to retrieve operational data and manage configurations. The current version is 5.1.0, with regular releases, typically major updates every 6-12 months and minor/patch releases in between.
Common errors
-
napalm.base.exceptions.ConnectionException: Cannot connect to device 192.168.1.1
cause Network connectivity issues, incorrect hostname/IP, wrong port, firewall blocking, or invalid device credentials/access method.fixVerify network reachability (ping), check SSH/API port (default 22 for SSH, 443/830 for API/NETCONF), ensure correct username/password, and confirm device is configured for programmatic access (SSH, API enabled, correct user privileges). -
TypeError: 'NoneType' object is not callable (e.g., when calling `get_network_driver('nonexistent_driver')`)cause The specified network driver name is incorrect, unsupported, or a required underlying dependency for the driver is not installed.fixDouble-check the driver name against NAPALM's documentation (e.g., 'ios', 'eos', 'junos', 'nxos'). If it's a valid driver, ensure all necessary optional dependencies (e.g., `pip install napalm[full]` or specific driver extras) are installed. -
napalm.base.exceptions.MergeConfigException: Configuration validation failed: ... (followed by device error messages)
cause The configuration payload provided to `load_merge_candidate` or `load_replace_candidate` contains syntax errors or conflicts with the device's current configuration.fixReview the configuration changes being pushed. Test the configuration snippet manually on the device CLI to ensure it's valid. Inspect the device's error messages for specific syntax issues. -
napalm.base.exceptions.LockError: Unable to lock device's configuration
cause Another process or user has an exclusive lock on the device's configuration, preventing NAPALM from making changes.fixWait for the other process/user to release the lock, or manually clear the lock on the device if no active changes are being performed. In some cases, increasing the `lock_config_timeout` optional argument might help if the device is slow to respond.
Warnings
- breaking Python 3.8 support was dropped in NAPALM v5.1.0. NAPALM now requires Python 3.9+ (including 3.13 support).
- breaking Arista EOS versions older than 4.23 are no longer supported starting with NAPALM v5.0.0. Additionally, the `eos_fn0039_config` optional argument for EOS was removed.
- gotcha NAPALM v4.0.0 introduced extensive type hinting. While not a breaking change in terms of runtime behavior, it impacts static analysis and how developers might perceive function signatures. If relying on introspection or type checks, be aware of these additions.
- gotcha The behavior of `force_no_enable` for Netmiko-based drivers (like IOS and NX-OS) was fixed in v3.1.0. If you maintain a third-party driver that uses Netmiko but does not utilize `enable` features, older NAPALM versions might have exhibited unexpected behavior.
Install
-
pip install napalm -
pip install napalm[full]
Imports
- get_network_driver
from napalm import get_network_driver
- NapalmBaseException
from napalm.exceptions import NapalmBaseException
from napalm.base.exceptions import NapalmBaseException
Quickstart
from napalm import get_network_driver
def connect_and_get_facts(hostname, username, password):
try:
driver = get_network_driver("ios") # Replace 'ios' with your device type (e.g., 'eos', 'junos', 'nxos')
device = driver(
hostname,
username,
password,
optional_args={
"port": 22, # Or 830 for NETCONF, 443 for API
"secret": "", # If using privilege escalation
"config_file": None # Path to an external config file
}
)
print(f"Connecting to {hostname}...")
device.open()
print(f"Successfully connected to {hostname}.")
facts = device.get_facts()
print("Device Facts:")
for k, v in facts.items():
print(f" {k}: {v}")
# Example: Get interface details
# interfaces = device.get_interfaces()
# print("Interfaces:", interfaces)
except Exception as e:
print(f"Error connecting or retrieving data: {e}")
finally:
if 'device' in locals() and device.is_open:
device.close()
print(f"Disconnected from {hostname}.")
if __name__ == "__main__":
# Replace with your actual device details
DEVICE_HOSTNAME = os.environ.get('NAPALM_TEST_HOSTNAME', '192.168.1.1')
DEVICE_USERNAME = os.environ.get('NAPALM_TEST_USERNAME', 'admin')
DEVICE_PASSWORD = os.environ.get('NAPALM_TEST_PASSWORD', 'password')
# Make sure to set these environment variables or change the default values
connect_and_get_facts(DEVICE_HOSTNAME, DEVICE_USERNAME, DEVICE_PASSWORD)