Paramiko — Your First SSH Driver

20 min In Progress

Learning Objectives

  • Map an SSH session to connect → send_command → close
  • Build a minimal Paramiko-style driver class
  • Practice the pattern safely before touching a real device

Why Paramiko First

Paramiko is the lowest-level tool of the five: it knows SSH, and nothing else. It doesn't know it's talking to a Cisco router versus a Linux box — you handle every detail yourself. That makes it verbose, but it's the best place to start because nothing is hidden. Every other tool in this chapter is built on the same idea: open a connection, send text, read the reply, close the connection.

The Real Driver (Lab / Real-Device Code)

This is the production-grade version — the exact shape you'd deploy against a real device in GNS3, EVE-NG, or Cisco CML.

Lab-only: needs `pip install paramiko` plus a reachable SSH host. Running it here raises ModuleNotFoundError — that's expected. Try the simulated version below instead.
import paramiko

class paramiko_driver:
    def __init__(self, hostname, username, password):
        self.hostname = hostname
        self.username = username
        self.password = password
        self.client = paramiko.SSHClient()
        self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    def connect(self):
        self.client.connect(
            hostname=self.hostname,
            username=self.username,
            password=self.password,
        )

    def send_command(self, command):
        stdin, stdout, stderr = self.client.exec_command(command)
        return stdout.read().decode('utf-8')

    def close(self):
        self.client.close()

ssh = paramiko_driver('192.168.1.10', 'admin', 'secret')
ssh.connect()
print(ssh.send_command('uptime'))
ssh.close()

Practice Safely — Simulated SSH Session

Same class shape, real method names — connect(), send_command(), close() — but the transport underneath is a small in-script stand-in instead of a real SSH handshake. The muscle memory transfers directly to the real paramiko.SSHClient() above.

class simulated_ssh_session:
    """Stands in for paramiko.SSHClient -- same connect / send / close shape."""

    _CANNED_REPLIES = {
        'uptime': '14:02:07 up 19 days,  3:41,  1 user,  load average: 0.04, 0.02, 0.01',
        'show version': 'Cisco IOS Software, Version 15.2(7)E3, edge-router-1',
        'whoami': 'admin',
    }

    def __init__(self, hostname, username, password):
        self.hostname = hostname
        self.username = username
        self.password = password
        self.connected = False

    def connect(self):
        # A real paramiko.SSHClient() would open a TCP + SSH handshake here.
        self.connected = True

    def send_command(self, command):
        if not self.connected:
            raise RuntimeError('Call connect() before sending commands.')
        return self._CANNED_REPLIES.get(command, f'% Unknown command: {command}')

    def close(self):
        self.connected = False


class paramiko_style_driver:
    def __init__(self, hostname, username, password):
        self.hostname = hostname
        self.username = username
        self.password = password
        self.session = simulated_ssh_session(hostname, username, password)

    def connect(self):
        self.session.connect()

    def send_command(self, command):
        return self.session.send_command(command)

    def close(self):
        self.session.close()


driver = paramiko_style_driver('edge-router-1', 'admin', 'secret')
driver.connect()
print(driver.send_command('uptime'))
print(driver.send_command('show version'))
driver.close()

📝 Exercise: Add Convenience Methods to Your Driver

Extend paramiko_style_driver with get_uptime() and get_version() convenience methods, then add a status_report() method that combines both into one line. Run it to see the combined report.

code.py
Output

            
← Back to Chapter