
Table of Contents Link to heading
- Introduction
- What is Netmiko?
- Why Netmiko?
- Setting Up Netmiko
- Automating Network Tasks with Netmiko
- Common Real-World Netmiko Issues
- Troubleshooting Tips
- Conclusion
Introduction Link to heading
In today’s fast-paced networking landscape, automation is no longer optional—it’s essential. Managing network devices manually is inefficient and error-prone, but Python-based automation frameworks like Netmiko make it easy to interact with network devices programmatically. In this blog, we’ll explore how to use the Netmiko module to automate configuration and verification tasks on Cisco devices.
What is Netmiko? Link to heading
Netmiko is a Python library that simplifies SSH connections to network devices. Built on Paramiko, it provides high-level functionality tailored for network engineers, making device interactions seamless. It supports multiple vendors, including Cisco, Juniper, Arista, and more.
Why Netmiko? Link to heading
Netmiko simplifies SSH automation in networking for several reasons:
- Vendor Support: Works with Cisco, Juniper, Arista, HP, and more.
- Simplified SSH Handling: Abstracts low-level SSH complexities.
- Efficiency: Bulk configuration across multiple devices with minimal effort.
- Error Handling: Provides built-in timeout mechanisms.
Setting Up Netmiko Link to heading
Before diving into automation, ensure you have Netmiko installed. You can install it using pip:
pip install netmiko
You’ll also need access to networking devices and valid credentials.
Automating Network Tasks with Netmiko Link to heading
The script you’ve crafted demonstrates a practical use case: configuring a Cisco router and verifying the settings. Let’s break it down.
Define Device Parameters Link to heading
We define three Cisco devices with their IP addresses, credentials, and device types:
from netmiko import ConnectHandler
r1 = {
"device_type": "cisco_ios",
"ip": "2001:DB8:CAFE:1::1",
"username": "admin",
"password": "admin",
}
r2 = {
"device_type": "cisco_ios",
"ip": "10.254.3.1",
"username": "admin",
"password": "admin",
}
r3 = {
"device_type": "cisco_ios",
"ip": "10.254.3.2",
"username": "admin",
"password": "admin",
}
Establish SSH Connections Link to heading
Using ConnectHandler
, we initiate SSH sessions with all three routers:
connection_r1 = ConnectHandler(**r1)
connection_r2 = ConnectHandler(**r2)
connection_r3 = ConnectHandler(**r3)
Apply Configuration Commands Link to heading
We send commands to configure the loopback interface and BGP routing on R3:
config_commands = [
"interface Loopback1",
"ip address 10.3.254.1 255.255.255.0",
"ipv6 address 2001:DB8:CAFE:3254::1/64",
"exit",
"router bgp 65510",
"address-family ipv4",
"network 10.3.254.0 mask 255.255.255.0",
"address-family ipv6",
"network 2001:DB8:CAFE:3254::/64",
"exit-address-family",
"end",
]
output = connection_r3.send_config_set(config_commands)
Verification Link to heading
We check the configurations on all routers by running show
commands:
show_commands = [
"show bgp ipv4 unicast 10.3.254.0/24",
"show bgp ipv6 unicast 2001:DB8:CAFE:3254::1/64",
"show ip route 10.3.254.1",
"show ipv6 route 2001:DB8:CAFE:3254::1",
]
for connection in (connection_r1, connection_r2, connection_r3):
for command in show_commands:
output += f"{command}\n{connection.send_command(command)}\n\n"
Closing Connections Link to heading
Once done, we close all SSH connections:
connection_r1.disconnect()
connection_r2.disconnect()
connection_r3.disconnect()
Print the Output Link to heading
To review results:
print(output)
Common Real-World Netmiko Issues Link to heading
Authentication Failures Link to heading
- Issue: Incorrect credentials or unsupported authentication methods.
- Example: If a device rejects SSH login, Netmiko may throw a
NetmikoAuthenticationException
. - Fix: Double-check the username/password and ensure SSH is enabled on the device.
Connection Timeouts Link to heading
- Issue: Netmiko fails to establish an SSH session.
- Example:
NetmikoTimeoutException: TCP connection to device failed
. - Fix: Verify the device is reachable, check firewall rules, and increase the timeout value.
Unsupported Device Types Link to heading
- Issue: Netmiko doesn’t recognise the specified
device_type
. - Example:
ValueError: Unsupported 'device_type' currently supported platforms are...
. - Fix: Ensure the correct
device_type
is used from Netmiko’s supported list.
Command Execution Errors Link to heading
- Issue: Commands fail due to syntax errors or interactive prompts.
- Example: Some commands require confirmation (e.g.,
write memory
). - Fix: Use
send_command_timing()
instead ofsend_command()
to handle interactive prompts.
Output Parsing Issues Link to heading
- Issue: Unexpected output formatting or missing data.
- Example:
show
command output may be truncated or misformatted. - Fix: Use
strip_prompt=False
insend_command()
to retain full responses.
Session Hanging or Not Closing Link to heading
- Issue: SSH sessions remain open, causing resource exhaustion.
- Example: Netmiko script runs but doesn’t release connections.
- Fix: Always call
connection.disconnect()
after execution.
Troubleshooting Tips Link to heading
Handling Authentication Failures Link to heading
If you encounter login issues, ensure:
- The username and password are correct.
- The device supports SSH (some may require enabling SSH manually).
- You handle authentication errors gracefully using
NetmikoAuthenticationException
.
Resolving Connection Timeouts Link to heading
If Netmiko fails to connect:
- Verify the IP address and port (default is 22).
- Check if the device is reachable (ping it first).
- Increase the timeout value using
timeout=60
in your connection parameters.
Managing Command Execution Errors Link to heading
If commands fail:
- Ensure the command syntax matches the device’s CLI.
- Use
send_command_timing()
instead ofsend_command()
for commands requiring interactive input. - Implement exception handling for unexpected errors.
Debugging Output Issues Link to heading
If output is missing or incorrect:
- Print the raw output using
print(connection.find_prompt())
. - Use
strip_prompt=False
insend_command()
to retain the full response. - Log outputs for debugging.
Closing Connections Properly Link to heading
Always disconnect after execution:
connection.disconnect()
This prevents lingering SSH sessions that may cause issues.
Using Logging for Debugging Link to heading
Enable logging to track errors:
import logging
logging.basicConfig(level=logging.DEBUG)
This helps identify where the script fails.
Conclusion Link to heading
Automating network tasks using Netmiko enhances efficiency, minimises errors, and accelerates operational workflows. Whether configuring routers, gathering information, or implementing changes across multiple devices, Netmiko makes automation seamless for network engineers.
So why manually configure devices when Python can do it for you? 🚀
Click to expand the complete code we have discussed
#!/usr/bin/python
# -*- coding: utf-8 -*-
from netmiko import ConnectHandler
# Define device parameters
r1 = {
"device_type": "cisco_ios",
"ip": "2001:DB8:CAFE:1::1",
"username": "admin",
"password": "admin",
}
r2 = {
"device_type": "cisco_ios",
"ip": "10.254.3.1",
"username": "admin",
"password": "admin",
}
r3 = {
"device_type": "cisco_ios",
"ip": "10.254.3.2",
"username": "admin",
"password": "admin",
}
# Establish SSH connections to the all routers
connection_r1 = ConnectHandler(**r1)
connection_r2 = ConnectHandler(**r2)
connection_r3 = ConnectHandler(**r3)
# Define the configuration commands to be implemented in R3
config_commands = [
"interface Loopback1",
"ip address 10.3.254.1 255.255.255.0",
"ipv6 address 2001:DB8:CAFE:3254::1/64",
"exit",
"router bgp 65510",
"address-family ipv4",
"network 10.3.254.0 mask 255.255.255.0",
"address-family ipv6",
"network 2001:DB8:CAFE:3254::/64",
"exit-address-family",
"end",
]
# Send the configuration commands to R3
output = connection_r3.send_config_set(config_commands)
# Verify the configuration from all routers
show_commands = [
"show bgp ipv4 unicast 10.3.254.0/24",
"show bgp ipv6 unicast 2001:DB8:CAFE:3254::1/64",
"show ip route 10.3.254.1",
"show ipv6 route 2001:DB8:CAFE:3254::1",
]
for connection in (connection_r1, connection_r2, connection_r3):
for command in show_commands:
output += command + "\n"
output += connection.send_command(command) + "\n"
output += "\n"
# Close the connections
connection.disconnect()
# Print the output
print(output)