Netmiko — SSH That Knows It's a Router

20 min In Progress

Learning Objectives

  • Understand the device_type parameter and what it buys you
  • Use send_command() vs send_config_set()
  • Decide when to reach for Netmiko instead of raw Paramiko

Why Netmiko

Netmiko is Paramiko with one extra ingredient: device_type. Tell it the device is 'cisco_ios' and it automatically handles the things Paramiko makes you do by hand — paging through long output, entering enable mode, knowing what a config prompt looks like. If your target is a router, switch, or firewall, this is almost always the better starting point over raw Paramiko.

The Real Driver (Lab / Real-Device Code)

The production version, including the device_params dictionary Netmiko expects.

Lab-only: needs `pip install netmiko` plus a reachable device. Running it here raises ModuleNotFoundError — expected.
from netmiko import ConnectHandler

class netmiko_driver:
    def __init__(self, device_params):
        self.device_params = device_params
        self.connection = None

    def connect(self):
        self.connection = ConnectHandler(**self.device_params)

    def get_version(self):
        return self.connection.send_command('show version')

    def configure_acl(self, acl_lines):
        return self.connection.send_config_set(acl_lines)

    def disconnect(self):
        if self.connection:
            self.connection.disconnect()

ios_device = {
    'device_type': 'cisco_ios',
    'host': '192.168.1.1',
    'username': 'admin',
    'password': 'secret',
}

net = netmiko_driver(ios_device)
net.connect()
print(net.get_version())
net.disconnect()

Practice Safely — Simulated Netmiko Session

The simulated session takes the same device_params dict a real ConnectHandler would, and exposes the same three methods you'd actually call: send_command, send_config_set, disconnect.

class simulated_netmiko_session:
    """Mimics netmiko.ConnectHandler: knows the device_type up front and
    exposes send_command / send_config_set / disconnect."""

    def __init__(self, device_params):
        self.device_params = device_params
        self.connected = False
        self.applied_config = []

    def connect(self):
        self.connected = True

    def send_command(self, command):
        if command == 'show version':
            return f"{self.device_params['device_type']} -- edge-router-1, uptime 19 days"
        return f'% Unknown command: {command}'

    def send_config_set(self, lines):
        self.applied_config.extend(lines)
        return '\n'.join(f'edge-router-1(config)# {line}' for line in lines)

    def disconnect(self):
        self.connected = False


class netmiko_style_driver:
    def __init__(self, device_params):
        self.device_params = device_params
        self.connection = simulated_netmiko_session(device_params)

    def connect(self):
        self.connection.connect()

    def get_version(self):
        return self.connection.send_command('show version')

    def configure_acl(self, acl_lines):
        return self.connection.send_config_set(acl_lines)

    def disconnect(self):
        self.connection.disconnect()


ios_device = {'device_type': 'cisco_ios', 'host': 'edge-router-1'}
net = netmiko_style_driver(ios_device)
net.connect()
print(net.get_version())
print(net.configure_acl([
    'ip access-list extended BLOCK_BAD',
    'deny ip 10.0.0.0 0.255.255.255 any',
    'permit ip any any',
]))
net.disconnect()

📝 Exercise: Add save() to Your Driver

Netmiko's real connection has a save_config() method that writes the running config to startup config. Add the same to the simulated session and a matching save() method on the driver, then call it after applying the ACL.

code.py
Output

            
← Back to Chapter