Paramiko — Your First SSH Driver
20 min In ProgressLearning 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.
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.