Python Netmiko for SSH Automation
Python Netmiko for SSH Automation
Introduction
Network engineers have traditionally relied on the command-line interface to configure and troubleshoot devices one at a time. While CLI mastery remains essential, modern networks demand a faster, more repeatable approach. SSH-based automation with Python allows you to programmatically connect to network devices, execute commands, parse output, and save results — all without manually typing into a terminal session.
In this lesson you will learn how Python scripts leverage SSH to interact with Cisco devices. We will walk through the entire workflow: defining device connectivity details in a structured file, writing a Python script that connects to a switch, running multiple show commands, formatting the output, and saving it to a file. By the end you will understand how to break an automation project into manageable steps, apply prompting principles when working with coding assistants, and appreciate why automating routine data extraction is the foundation for every advanced network automation use case.
Key Concepts
Before writing any code, there are several building blocks you need to understand.
SSH as the Transport Layer
Cisco IOS XE devices expose two broad categories of programmatic access:
| Access Method | Description |
|---|---|
| SSH (CLI scripting) | Scripts access normal CLI commands through an SSH session |
| Model-Driven Programmability | Uses YANG data models with protocols such as NETCONF or RESTCONF |
SSH-based automation sits on the left side of that spectrum. It is the simplest entry point because you are sending the same show and configure commands you already know — the difference is that a Python library handles the connection, authentication, and output capture for you.
The Testbed File
A testbed file (commonly named testbed.yml) is a YAML document that stores device connectivity details: hostname, IP address, credentials, platform type, and connection protocol. Instead of hard-coding connection parameters inside every script, you define them once in the testbed and load the file at runtime. This separation of data from logic makes your scripts portable and easier to maintain.
A testbed entry for a device called FE1 would include information such as the management IP, SSH port, username, and password — all referenced by the script when it needs to open an SSH session.
The Three "S" Prompting Principle
When you use a coding assistant to help generate automation scripts, the quality of the output depends on how you structure your request. The Three "S" Principle provides a framework:
| Principle | Meaning |
|---|---|
| Specific | State exactly what libraries, devices, and commands you need |
| Sequential | Break the task into ordered steps so the assistant follows a logical flow |
| Simple | Keep each prompt focused on one piece of functionality |
Applying these principles means you do not ask for an entire automation solution in a single request. Instead you issue multiple, targeted prompts — each one building on the output of the previous step.
How It Works
The end-to-end process for SSH-based network device data extraction follows a clear sequence of operations.
Step-by-Step Workflow
-
Load the testbed — Import the required Python libraries (for example, the Genie testbed loader, the
loggingmodule, anddatetime). Then load thetestbed.ymlfile so the script knows which devices are available and how to reach them. -
Connect to the device — Using the device name defined in the testbed (e.g.,
FE1), open an SSH session. Enable prompt recovery (prompt_recovery=True) so the script can handle unexpected prompts or delays without hanging indefinitely. -
Execute show commands — Run a series of show commands against the device and capture the output. Typical commands for a data-extraction use case include:
show version
show ip interface brief
show vlan
-
Parse and format the output — Rather than working with raw CLI text, parse the command output into structured data. This makes it straightforward to extract specific fields such as the software version, interface status, or VLAN membership.
-
Save results to a file — Write the formatted output to a file whose name includes the current date and time. Timestamped filenames ensure that each collection run produces a unique artifact you can compare against previous baselines.
-
Disconnect from the device — Cleanly close the SSH session to free resources on both the automation host and the network device.
Breaking the Project into Smaller Steps
A critical best practice is to decompose the project into smaller, focused steps rather than attempting to write the entire script at once. Each step can be developed, tested, and debugged independently. For the data-extraction use case the decomposition looks like this:
- Prompt 1 — Import libraries and load the testbed file.
- Prompt 2 — Connect to device
FE1with prompt recovery enabled. - Prompt 3 — Run
show version,show ip interface brief, andshow vlan; parse the output. - Prompt 4 — Save output to a file stamped with the current date.
- Prompt 5 — Disconnect from the device.
- Prompt 6 — Simplify and improve overall code debuggability.
This incremental approach not only produces cleaner code, it also makes troubleshooting far easier because you can isolate failures to a single step.
Configuration Example
Below is the Python script structure that implements the workflow described above. The script is typically saved as show_cmds.py.
Importing Libraries and Loading the Testbed
from genie.testbed import load
import logging
from datetime import datetime
testbed = load('testbed.yml')
The load function reads the YAML testbed file and returns an object containing all defined devices and their connection parameters.
Connecting to the Device
device = testbed.devices['FE1']
device.connect(prompt_recovery=True)
Setting prompt_recovery=True is important in lab and production environments alike. If the device presents an unexpected prompt — for instance a certificate warning or a --More-- pager — the library can recover automatically instead of timing out.
Running Show Commands and Parsing Output
show_version = device.parse('show version')
show_ip_int = device.parse('show ip interface brief')
show_vlan = device.parse('show vlan')
Each parse call sends the command over SSH, collects the raw text output, and converts it into a structured Python dictionary. You can then access individual fields programmatically — for example, extracting the IOS XE version string or listing only interfaces in the up/up state.
Saving Output to a Timestamped File
timestamp = datetime.now().strftime('%Y-%m-%d_%H%M%S')
filename = f'output_{timestamp}.txt'
with open(filename, 'w') as f:
f.write('=== show version ===\n')
f.write(str(show_version))
f.write('\n=== show ip interface brief ===\n')
f.write(str(show_ip_int))
f.write('\n=== show vlan ===\n')
f.write(str(show_vlan))
Including the timestamp in the filename means you can schedule this script to run repeatedly and build a historical record of device state over time.
Disconnecting
device.disconnect()
Always disconnect gracefully. Leaving orphaned SSH sessions open can consume VTY lines on the device and eventually lock out further remote access.
Verification
After running the script, verify that the output file was created and contains the expected data:
ls -l output_*.txt
cat output_2025-01-15_143022.txt
You should see structured output for each of the three show commands, clearly separated by section headers.
Real-World Application
Automating Method-of-Procedure Workflows
The data-extraction script is rarely a standalone deliverable. In production it becomes a building block inside a larger method-of-procedure (MOP) workflow. A typical MOP automation sequence looks like this:
- Connect to the Cisco switch.
- Collect pre-check commands (using the same
show_cmds.pylogic). - Apply a configuration change — for example, create a new VLAN.
- Collect post-check commands.
- Compare pre-check and post-check output to ensure the change was successful.
By reusing the show-command collection script for both pre-checks and post-checks, you guarantee consistency and eliminate the risk of forgetting a verification step.
Workflow Automation with CI/CD Pipelines
Once your scripts are reliable, the next evolution is to remove the need to trigger them manually. Workflow engines let you define configurable automated processes that run one or more jobs. Workflows can be triggered by an event in your code repository, triggered manually on demand, or executed on a defined schedule.
Workflow definitions are stored as YAML files in a .github/workflows directory. A runner — a server that executes the workflow when triggered — picks up the job, checks out your code, installs dependencies, and runs your Python scripts against the network. This moves your automation from a laptop-dependent activity to a centralized, auditable, and repeatable operation.
Test-Driven Network Automation
The most mature approach to network automation adopts a test-driven methodology. The progression from manual operations to full Network-as-Code follows a clear maturity path:
| Maturity Level | Characteristics |
|---|---|
| Manual triggering | Hardcoded values, no validation, scripts run ad-hoc |
| Minimum Viable Product (MVP) | Source of truth exists, automated workflow, may lack verification |
| Network as Code (NaC) | Versioned and complete configuration, automated testing, robust pipelines |
In test-driven automation the cycle is:
- Create a test for the desired outcome.
- Run the test — it should fail because the change has not been applied yet.
- Make the planned configuration change.
- Run the test again — it should now pass.
Building tests into your pipeline adds static validation, pre-change snapshots, and post-change snapshots around every configuration update. This gives you confidence that changes are correct and complete before you notify stakeholders.
Best Practice: Always start with SSH-based data extraction scripts. Once you can reliably collect and parse device output, you have the foundation for pre/post checks, compliance audits, inventory collection, and configuration drift detection.
Summary
- SSH-based Python automation lets you connect to Cisco devices, run show commands, parse output into structured data, and save results — replacing repetitive manual CLI sessions.
- A testbed file centralizes device connectivity details so scripts remain clean and portable across different environments.
- Breaking automation projects into small, sequential steps improves code quality and simplifies debugging.
- The show-command extraction script becomes a reusable component inside MOP workflows that automate pre-checks, configuration changes, and post-checks.
- Workflow engines and test-driven automation represent the next level of maturity, moving from manual script execution toward fully automated, validated network operations.
In the next lesson we will explore how to extend these Python foundations to push configuration changes to devices and handle error scenarios gracefully.