Python for Network Engineers
1. Why Python for Network Engineering?
Network engineers have traditionally managed devices one at a time — logging in via SSH or console, typing commands, reading output, and repeating the process across dozens or hundreds of devices. This manual approach is slow, error-prone, and does not scale. Python has become the dominant scripting language for network automation because it is readable, powerful, and supported by a rich ecosystem of networking libraries that handle SSH connections, vendor abstraction, data parsing, and API interaction out of the box.
The shift toward network automation aligns with the network automation and controller-based networking trends that are now core topics in the CCNA curriculum. Understanding Python fundamentals and key networking libraries is an expected baseline skill for modern network engineers.
| Manual CLI Approach | Python Automation Approach |
|---|---|
| Log into each device individually — one at a time | Script iterates a device list and connects to all in a loop |
| Type the same commands on every device | Commands defined once in a variable or template; applied consistently to all devices |
| Read output visually — human error possible | Output parsed programmatically — results extracted and compared to expected values |
| Changes on 100 devices take hours | Changes on 100 devices take seconds to minutes |
| No automatic logging or audit trail | All commands and outputs logged to file automatically |
| Inconsistency — every engineer types slightly differently | Identical configuration applied every time from the same source code |
1.1 Python vs Other Automation Options
| Tool / Language | Strength | Best Use Case |
|---|---|---|
| Python | Flexible; huge library ecosystem; universal network support; easy to learn | Custom scripts; data parsing; API integration; complex logic |
| Ansible | Agentless; YAML-based (no programming required); idempotent modules; Cisco IOS/NX-OS/ASA modules built-in | Bulk configuration deployment; desired-state enforcement; playbook-based workflows |
| Bash / shell scripts | Lightweight; always available on Linux/macOS | Simple file manipulation; invoking other tools; quick one-liners |
| Terraform | Infrastructure-as-code; declarative; multi-cloud support | Cloud infrastructure provisioning; virtualised network functions |
Related pages: Network Automation Overview | Ansible Overview | Controller-Based Networking | Northbound & Southbound APIs | JSON, XML & YANG | NETCONF & RESTCONF | Netmiko Show Commands Lab | NAPALM Multi-Vendor Lab | NETCONF with Python (ncclient) Lab | Jinja2 Config Generation Lab
2. Python Networking Library Landscape
The Python ecosystem for networking is rich and layered. Libraries exist at every level — from raw SSH transport up to high-level vendor-agnostic abstraction. Understanding which library solves which problem prevents reinventing the wheel.
| Library | Layer / Purpose | Key Feature | Install |
|---|---|---|---|
| Paramiko | SSH transport (low-level) | Pure Python SSH2 implementation; low-level control over SSH channels and sessions; Netmiko is built on top of it | pip install paramiko |
| Netmiko | SSH automation (mid-level) | Handles SSH quirks of 50+ network vendor platforms (Cisco IOS, NX-OS, EOS, Junos, etc.); auto-detects prompts; sends commands and returns output; built for network engineers | pip install netmiko |
| NAPALM | Multi-vendor abstraction (high-level) | Vendor-neutral API for get/configure operations across IOS, NX-OS, EOS, Junos, IOS-XR; returns structured Python dictionaries; supports config diff and merge | pip install napalm |
| TextFSM | Output parsing | Template-based parser that converts unstructured CLI output (show commands) into structured Python lists/dicts using regex templates (NTC-Templates library) | pip install textfsm |
| nornir | Automation framework | Python-native automation framework (Ansible alternative); uses inventory files; runs tasks in parallel; integrates with Netmiko, NAPALM, and other plugins | pip install nornir |
| requests | HTTP/REST API client | HTTP GET/POST/PUT/DELETE for REST APIs (Cisco DNA Center, Meraki, NSO, SD-WAN vManage); returns JSON responses | pip install requests |
| ncclient | NETCONF client | Implements NETCONF protocol (RFC 6241) for structured device configuration and state retrieval using XML/YANG | pip install ncclient |
| pyATS / Genie | Testing framework | Cisco's test and validation framework; Genie parsers provide structured output for hundreds of show commands; used for network validation and CI/CD pipelines | pip install pyats genie |
3. Netmiko – SSH Automation for Network Devices
Netmiko (developed by Kirk Byers) is the most widely used Python library for SSH-based network automation. It solves the frustrating problem that raw Paramiko SSH sessions require manual handling of every router's unique prompt behaviour, pagination, error messages, and timing. Netmiko abstracts all of this — you specify the device type and Netmiko handles the rest.
3.1 What Netmiko Does Automatically
| Challenge with Raw SSH | How Netmiko Handles It |
|---|---|
Different prompt patterns per vendor
(Router# vs Switch> vs
hostname@) |
Device type parameter triggers the correct prompt regex pattern for each vendor's CLI |
Pagination — --More-- after 24 lines of
output |
Automatically disables pagination with
terminal length 0 (Cisco) or equivalent on
login |
| Timing — need to wait for command output before sending next command | Waits for the prompt to return before proceeding; handles slow or high-latency devices |
Enable mode — need to enter enable and
provide password |
Automatically enters enable mode using the
secret parameter |
Config mode — need to enter
configure terminal before making changes |
send_config_set() automatically enters and
exits config mode around the supplied commands |
| SSH key fingerprint acceptance | Handles host key acceptance automatically |
3.2 Netmiko Supported Device Types (Selected)
| Device Type String | Vendor / OS |
|---|---|
cisco_ios |
Cisco IOS and IOS-XE routers and switches |
cisco_nxos |
Cisco Nexus (NX-OS) |
cisco_asa |
Cisco ASA firewall |
cisco_xr |
Cisco IOS-XR (ASR 9000, NCS) |
arista_eos |
Arista EOS switches |
juniper_junos |
Juniper Junos routers and switches |
hp_procurve |
HP ProCurve / Aruba switches |
linux |
Linux servers (useful for network function VMs) |
3.3 Core Netmiko Methods
| Method | Purpose | Returns |
|---|---|---|
ConnectHandler(**device) |
Establishes the SSH connection to the device | Connection object |
send_command(cmd) |
Sends a single show command and waits for the prompt to return | String — full command output |
send_command(cmd, use_textfsm=True) |
Sends a show command and parses output with TextFSM using NTC-Templates | List of dicts — structured data |
send_config_set(commands) |
Enters config mode, sends a list of configuration commands, exits config mode | String — command echoes and any output |
save_config() |
Saves the running configuration
(write memory or equivalent) |
String — confirmation output |
disconnect() |
Closes the SSH session cleanly | None |
find_prompt() |
Returns the current CLI prompt — useful for verifying connection state | String — current prompt (e.g., Router#) |
4. Simple Show-Command Script with Netmiko
The following scripts demonstrate practical Netmiko patterns — from the simplest single-device connection to a multi-device loop that collects interface information across a fleet.
4.1 Script 1 – Connect and Run a Single Show Command
#!/usr/bin/env python3
"""
Script 1: Connect to a Cisco IOS device via SSH and retrieve
the output of 'show version'.
"""
from netmiko import ConnectHandler
# Device connection dictionary
device = {
"device_type": "cisco_ios",
"host": "192.168.1.1",
"username": "admin",
"password": "cisco123",
"secret": "enable123", # Enable password
}
# Establish connection
connection = ConnectHandler(**device)
# Enter enable mode (if not already in it)
connection.enable()
# Send the show command and capture output
output = connection.send_command("show version")
# Print the raw output
print(output)
# Clean up the SSH session
connection.disconnect()
print("Connection closed.")
4.2 Script 2 – Multi-Device Loop with show ip interface brief
#!/usr/bin/env python3
"""
Script 2: Connect to multiple Cisco IOS devices, run
'show ip interface brief', and print per-device results.
"""
from netmiko import ConnectHandler
# List of devices to automate
devices = [
{"device_type": "cisco_ios", "host": "10.0.0.1",
"username": "admin", "password": "cisco123", "secret": "enable123"},
{"device_type": "cisco_ios", "host": "10.0.0.2",
"username": "admin", "password": "cisco123", "secret": "enable123"},
{"device_type": "cisco_ios", "host": "10.0.0.3",
"username": "admin", "password": "cisco123", "secret": "enable123"},
]
command = "show ip interface brief"
# Iterate over every device
for device in devices:
print(f"\n{'='*60}")
print(f"Connecting to {device['host']}...")
try:
conn = ConnectHandler(**device)
conn.enable()
hostname = conn.find_prompt().replace("#", "") # Extract hostname
output = conn.send_command(command)
conn.disconnect()
print(f"Hostname: {hostname}")
print(output)
except Exception as e:
print(f"ERROR connecting to {device['host']}: {e}")
print("\nAll devices processed.")
4.3 Script 3 – Structured Output with TextFSM Parsing
#!/usr/bin/env python3
"""
Script 3: Run 'show ip interface brief' and use TextFSM
(via use_textfsm=True) to get structured data as a list
of Python dictionaries instead of raw string output.
Requires: pip install netmiko ntc_templates
"""
from netmiko import ConnectHandler
import json
device = {
"device_type": "cisco_ios",
"host": "192.168.1.1",
"username": "admin",
"password": "cisco123",
"secret": "enable123",
}
conn = ConnectHandler(**device)
conn.enable()
# use_textfsm=True triggers TextFSM parsing via NTC-Templates
interfaces = conn.send_command(
"show ip interface brief",
use_textfsm=True
)
conn.disconnect()
# 'interfaces' is now a list of dicts — one per interface
print(f"Found {len(interfaces)} interfaces:\n")
for intf in interfaces:
print(f" Interface: {intf['intf']:<20} "
f"IP: {intf['ipaddr']:<16} "
f"Status: {intf['status']:<10} "
f"Protocol: {intf['proto']}")
# Pretty-print the full structured data as JSON
print("\nFull structured output:")
print(json.dumps(interfaces, indent=2))
4.4 Script 4 – Push Configuration Changes
#!/usr/bin/env python3
"""
Script 4: Push a list of configuration commands to a device.
Adds a loopback interface, sets a description, and saves.
"""
from netmiko import ConnectHandler
device = {
"device_type": "cisco_ios",
"host": "192.168.1.1",
"username": "admin",
"password": "cisco123",
"secret": "enable123",
}
# Configuration commands to apply
config_commands = [
"interface Loopback99",
"description Managed by Python Automation",
"ip address 10.99.99.1 255.255.255.255",
"no shutdown",
]
conn = ConnectHandler(**device)
conn.enable()
# send_config_set enters config mode, applies all commands, exits
output = conn.send_config_set(config_commands)
print("Configuration output:")
print(output)
# Save the running configuration
save_output = conn.save_config()
print("\nSave output:")
print(save_output)
conn.disconnect()
print("Configuration applied and saved.")
5. 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, vendor-neutral API for interacting with network devices. Where Netmiko gives you SSH access with vendor-aware prompt handling, NAPALM goes further — it defines a common set of methods that work identically across different vendor platforms, returning structured Python data regardless of vendor.
The key value proposition: you write your automation code once using
NAPALM's standard API, and it works against a Cisco IOS router, an
Arista EOS switch, and a Juniper router without changing a single line
of business logic — only the driver parameter changes.
5.1 NAPALM Supported Drivers
| Driver Name | Vendor / OS | Transport Used |
|---|---|---|
ios |
Cisco IOS and IOS-XE | SSH (via Netmiko) |
nxos |
Cisco NX-OS | NX-API (HTTP/HTTPS) |
nxos_ssh |
Cisco NX-OS | SSH (via Netmiko) |
iosxr |
Cisco IOS-XR | SSH (via Netmiko) |
eos |
Arista EOS | eAPI (HTTP/HTTPS) |
junos |
Juniper JunOS | NETCONF (via ncclient) |
5.2 NAPALM Core Get Methods
NAPALM's getter methods provide structured data in Python dictionaries — no parsing required. Every getter works the same way on every supported platform:
| NAPALM Getter | What It Returns | Equivalent CLI Command (IOS) |
|---|---|---|
get_facts() |
Hostname, FQDN, vendor, model, OS version, serial number, uptime, interface list | show version |
get_interfaces() |
Per-interface details — MAC, speed, MTU, description, is_up, is_enabled, last_flapped | show interfaces |
get_interfaces_ip() |
IP addresses per interface with prefix length | show ip interface brief |
get_bgp_neighbors() |
BGP neighbour state, ASN, uptime, prefix counts | show bgp summary |
get_arp_table() |
ARP table entries — IP, MAC, interface, age | show arp |
get_route_to(destination) |
Routing table entry for a specific destination | show ip route <dst> |
get_snmp_information() |
SNMP community strings, contact, location | show snmp |
get_config(retrieve="all") |
Running, startup, and/or candidate configuration | show running-config |
get_vlans() |
VLAN database — VLAN IDs, names, associated interfaces | show vlan |
get_lldp_neighbors() |
LLDP neighbour table — port, hostname, interface | show lldp neighbors |
5.3 NAPALM Configuration Management
| NAPALM Method | Purpose |
|---|---|
load_merge_candidate(config=…) |
Load new config that will be merged into the running configuration (adds to existing config) |
load_replace_candidate(config=…) |
Load new config that will replace the entire running configuration (full replacement — use with care) |
compare_config() |
Returns a diff showing what would change — lets you review before committing; extremely useful for change management |
commit_config() |
Applies the loaded candidate configuration to the device |
rollback() |
Reverts to the previous configuration — available on platforms that support configuration rollback (EOS, Junos, IOS-XR); limited on classic IOS |
discard_config() |
Cancels a loaded candidate without applying it |
6. Simple NAPALM Scripts
6.1 Script 5 – Collect Facts with NAPALM
#!/usr/bin/env python3
"""
Script 5: Use NAPALM to collect structured device facts from
a Cisco IOS device. The same code works for Arista EOS or
Juniper JunOS by changing only the driver name.
Requires: pip install napalm
"""
import napalm
import json
# Select the correct driver for the vendor
driver = napalm.get_network_driver("ios") # Change to "eos" or "junos" etc.
# Connect to the device
device = driver(
hostname = "192.168.1.1",
username = "admin",
password = "cisco123",
optional_args = {"secret": "enable123"}, # IOS enable password
)
device.open()
# Collect structured facts — same method on every vendor
facts = device.get_facts()
print("=== Device Facts ===")
print(json.dumps(facts, indent=2))
# Collect interface IP addresses
interfaces_ip = device.get_interfaces_ip()
print("\n=== Interface IP Addresses ===")
print(json.dumps(interfaces_ip, indent=2))
device.close()
print("\nConnection closed.")
6.2 Script 6 – Preview Config Changes with NAPALM Diff
#!/usr/bin/env python3
"""
Script 6: Use NAPALM's compare_config() to preview what will
change on the device before committing — a safe change
management workflow.
"""
import napalm
driver = napalm.get_network_driver("ios")
device = driver(
hostname = "192.168.1.1",
username = "admin",
password = "cisco123",
optional_args = {"secret": "enable123"},
)
device.open()
# New configuration snippet to merge in
new_config = """
interface Loopback100
description Managed by NAPALM
ip address 10.100.100.1 255.255.255.255
no shutdown
"""
# Load as a merge candidate (non-destructive — adds to existing config)
device.load_merge_candidate(config=new_config)
# Review the diff BEFORE committing
diff = device.compare_config()
if diff:
print("=== Configuration Diff (+ = add, - = remove) ===")
print(diff)
# Only commit if the diff looks correct
confirm = input("\nCommit this change? (yes/no): ")
if confirm.lower() == "yes":
device.commit_config()
print("Configuration committed.")
else:
device.discard_config()
print("Changes discarded — device unchanged.")
else:
print("No changes detected — device already in desired state.")
device.discard_config()
device.close()
6.3 Script 7 – Multi-Vendor Inventory Script
#!/usr/bin/env python3
"""
Script 7: Collect hostname, model, and OS version from a
mixed-vendor fleet (Cisco IOS + Arista EOS) using the same
NAPALM get_facts() call — vendor-agnostic code.
"""
import napalm
import json
# Mixed-vendor device inventory
inventory = [
{"driver": "ios", "host": "10.0.0.1",
"username": "admin", "password": "cisco123",
"optional_args": {"secret": "enable123"}},
{"driver": "ios", "host": "10.0.0.2",
"username": "admin", "password": "cisco123",
"optional_args": {"secret": "enable123"}},
{"driver": "eos", "host": "10.0.0.3",
"username": "admin", "password": "arista123",
"optional_args": {}},
]
results = []
for entry in inventory:
driver_name = entry.pop("driver") # Extract driver name
drv = napalm.get_network_driver(driver_name)
dev = drv(**entry)
try:
dev.open()
facts = dev.get_facts()
results.append({
"host": entry["host"],
"vendor": facts["vendor"],
"hostname": facts["hostname"],
"model": facts["model"],
"os_version": facts["os_version"],
})
dev.close()
except Exception as e:
results.append({"host": entry["host"], "error": str(e)})
# Print summary table
print(f"\n{'Host':<15} {'Vendor':<10} {'Hostname':<20} "
f"{'Model':<20} {'OS Version'}")
print("-" * 85)
for r in results:
if "error" in r:
print(f"{r['host']:<15} ERROR: {r['error']}")
else:
print(f"{r['host']:<15} {r['vendor']:<10} {r['hostname']:<20} "
f"{r['model']:<20} {r['os_version']}")
7. Netmiko vs NAPALM – When to Use Each
| Dimension | Netmiko | NAPALM |
|---|---|---|
| Abstraction level | Mid-level — vendor-aware SSH; returns raw CLI string output | High-level — vendor-neutral API; returns structured Python dicts |
| Output format | Raw string (unless use_textfsm=True is used) | Always structured Python dictionaries — no parsing needed |
| Vendor coverage | 50+ vendor platforms; any device with SSH CLI access | 6 core platforms (IOS, NX-OS, IOS-XR, EOS, JunOS); community drivers extend this |
| Config management | Sends raw config commands; no native diff or rollback | load/compare/commit/rollback workflow — supports safe config change management |
| Arbitrary commands | Yes — any command the device accepts can be sent | Limited to defined getters; for arbitrary commands must
drop to Netmiko or use cli() method |
| Transport | SSH only | SSH, NETCONF, or HTTP API depending on driver and vendor |
| Best for | Ad-hoc troubleshooting scripts; collecting any show command output; sending config to many devices quickly; legacy or unusual vendors | Multi-vendor automation where structured data is needed; network-wide inventory collection; safe config management with diff preview |
8. Output Parsing – TextFSM and NTC-Templates
A critical challenge in SSH-based automation is converting the unstructured text output of CLI show commands into structured data (lists, dictionaries) that Python can process programmatically. Two primary approaches exist:
| Parsing Method | How It Works | Pros | Cons |
|---|---|---|---|
| Manual string parsing (split / regex) | Python str.split(), str.find(),
or re module applied directly to the output
string |
No dependencies; maximum flexibility | Fragile — breaks if output format changes; must write and maintain parser for every command on every vendor |
| TextFSM + NTC-Templates | Template-based parser using regular expression grammars;
NTC-Templates provides pre-built templates for hundreds of
Cisco/Arista/Juniper show commands; Netmiko integrates
automatically with use_textfsm=True |
No regex writing needed; community-maintained; returns consistent structured dicts | Limited to supported commands in the NTC-Templates library; templates must be maintained as IOS output changes |
| NAPALM getters | Vendor abstraction layer handles parsing internally — the getter method returns structured data regardless of vendor CLI differences | Zero parsing code; fully structured; vendor-neutral | Limited to the specific getters NAPALM defines; cannot retrieve arbitrary show command data |
| Genie (pyATS) | Cisco's Genie library provides structured parsers for thousands of show commands across IOS, NX-OS, EOS, and more; integrates with pyATS test framework | Extremely comprehensive; official Cisco support | Heavier dependency; primarily for Cisco platforms |
9. Python Environment Setup for Network Automation
Before running any of the scripts on this page, you need a properly configured Python environment. Here is the recommended setup:
9.1 Install Python and Create a Virtual Environment
# Verify Python 3.8+ is installed
python3 --version
# Create a virtual environment (keeps project dependencies isolated)
python3 -m venv netauto-env
# Activate the virtual environment
# On macOS/Linux:
source netauto-env/bin/activate
# On Windows:
netauto-env\Scripts\activate
# Your prompt changes to show (netauto-env) when active
9.2 Install Networking Libraries
# Install Netmiko and TextFSM support (NTC-Templates)
pip install netmiko ntc_templates
# Install NAPALM (includes IOS, NX-OS, EOS, JunOS drivers)
pip install napalm
# Install requests (for REST API interaction)
pip install requests
# Install nornir (automation framework — optional)
pip install nornir nornir-netmiko nornir-napalm
# Freeze current versions to requirements.txt for reproducibility
pip freeze > requirements.txt
# Reinstall from requirements.txt on another system:
pip install -r requirements.txt
9.3 Best Practices for Credentials
Never hard-code credentials directly in scripts. Use one of these approaches:
| Approach | How It Works | Recommended? |
|---|---|---|
| Environment variables | import os; pw = os.environ["NET_PASSWORD"] |
✔ Yes — simple; keeps credentials out of source code |
| .env file + python-dotenv | Store in a .env file (add to
.gitignore); load with
from dotenv import load_dotenv |
✔ Yes — convenient for development |
| getpass() | import getpass; pw = getpass.getpass()
— prompts user at runtime with no echo |
✔ Yes — good for interactive scripts |
| Vault / secrets manager | HashiCorp Vault, AWS Secrets Manager, CyberArk — retrieve credentials at runtime via API | ✔ Best for production automation pipelines |
| Hard-coded in script | Password written directly as a string literal in the source code | ✘ Never — credentials leak into version control |
10. Error Handling in Network Scripts
Network devices are unreliable — SSH timeouts, authentication failures, and command errors are normal. Production automation scripts must handle errors gracefully so that one failed device does not crash the entire script.
#!/usr/bin/env python3
"""
Script 8: Robust multi-device script with proper error handling,
logging, and result collection.
"""
from netmiko import ConnectHandler
from netmiko.exceptions import (
NetMikoTimeoutException,
NetMikoAuthenticationException,
)
import logging
import json
from datetime import datetime
# Configure logging to file and console
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(message)s",
handlers=[
logging.FileHandler(f"netauto_{datetime.now().strftime('%Y%m%d_%H%M')}.log"),
logging.StreamHandler()
]
)
devices = [
{"device_type": "cisco_ios", "host": "10.0.0.1",
"username": "admin", "password": "cisco123", "secret": "enable123"},
{"device_type": "cisco_ios", "host": "10.0.0.2",
"username": "admin", "password": "wrongpass", "secret": "enable123"},
{"device_type": "cisco_ios", "host": "10.0.99.99", # Unreachable
"username": "admin", "password": "cisco123", "secret": "enable123"},
]
results = {}
for device in devices:
host = device["host"]
logging.info(f"Connecting to {host}")
try:
conn = ConnectHandler(**device)
conn.enable()
hostname = conn.find_prompt().replace("#", "")
output = conn.send_command("show ip interface brief")
conn.disconnect()
results[host] = {"status": "success", "hostname": hostname,
"output": output}
logging.info(f"{host} ({hostname}) — SUCCESS")
except NetMikoTimeoutException:
results[host] = {"status": "timeout"}
logging.error(f"{host} — TIMEOUT (device unreachable)")
except NetMikoAuthenticationException:
results[host] = {"status": "auth_failed"}
logging.error(f"{host} — AUTHENTICATION FAILED")
except Exception as e:
results[host] = {"status": "error", "message": str(e)}
logging.error(f"{host} — ERROR: {e}")
# Summary
print(f"\n{'='*50}")
print("SUMMARY")
print(f"{'='*50}")
for host, result in results.items():
print(f"{host:<15} {result['status']}")
# Save full results to JSON
with open("results.json", "w") as f:
json.dump(results, f, indent=2)
print("\nResults saved to results.json")
11. Python for Networking Quick-Reference Summary
| Concept | Key Fact |
|---|---|
| Primary Python SSH library for network devices | Netmiko — built on Paramiko; handles 50+ vendor platforms |
| Netmiko device type for Cisco IOS | "cisco_ios" |
| Send a show command (Netmiko) | conn.send_command("show version") |
| Send config commands (Netmiko) | conn.send_config_set(["cmd1", "cmd2"]) |
| Parse output to structured data (Netmiko) | send_command("show …", use_textfsm=True)
→ list of dicts |
| NAPALM purpose | Vendor-neutral API — same code works on IOS, EOS, JunOS; returns structured dicts |
| NAPALM get device facts | device.get_facts() — hostname, model,
vendor, OS version, serial, uptime |
| NAPALM safe config change workflow | load_merge_candidate → compare_config → commit_config (or discard_config) |
| TextFSM + NTC-Templates purpose | Parse raw CLI show-command output to structured Python lists/dicts using pre-built regex templates |
| Never do this with credentials | Hard-code passwords in scripts — use environment variables, .env, getpass(), or a secrets manager |
| Netmiko install | pip install netmiko |
| NAPALM install | pip install napalm |
| NTC-Templates install | pip install ntc_templates |
| Netmiko exception for unreachable device | NetMikoTimeoutException |
| Netmiko exception for wrong password | NetMikoAuthenticationException |