Module paramiko#
Paramiko is an implementation of SSHv2 protocol on Python. Paramiko provides client-server functionality. Book covers only client functionality.
Since Paramiko is not part of standard Python module library, it needs to be installed:
pip install paramiko
Connection is established in this way: first, client is created and client configuration is set, then connection is initiated and an interactive session is returned:
In [2]: client = paramiko.SSHClient()
In [3]: client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
In [4]: client.connect(hostname="192.168.100.1", username="cisco", password="cisco",
...: look_for_keys=False, allow_agent=False)
In [5]: ssh = client.invoke_shell()
SSHClient is a class that represents a connection to SSH server. It performs client authentication.
String set_missing_host_key_policy
is optional, it indicates
which policy to use when connecting to a server whose key is unknown.
Policy paramiko.AutoAddPolicy()
automatically add new hostname and key to local HostKeys object.
Method connect
connects to SSH server and authenticates the connection. Parameters:
look_for_keys
- by default paramiko performs key authentication. To disable this, put the flag in Falseallow_agent
- paramiko can connect to a local SSH agent. This is necessary when working with keys and since in this case authentication is done by login/password, it should be disabled.
After execution of previous command there is already a connection to server.
Method invoke_shell
allows to set an interactive SSH session with server.
Method send#
Method send
- sends specified string to session and returns amount of sent bytes.
In [7]: ssh.send("enable\n")
Out[7]: 7
In [8]: ssh.send("cisco\n")
Out[8]: 6
In [9]: ssh.send("sh ip int br\n")
Out[9]: 13
Warning
In code, after send
you will need to put time.sleep, especially between
send
and recv
. Since this is an interactive session and commands are
slow to type, everything works without pauses.
Method recv#
Method recv
receives data from session. In parentheses, the maximum value in
bytes that can be obtained is indicated. This method returns a received string
In [10]: ssh.recv(3000)
Out[10]: b'\r\nR1>enable\r\nPassword: \r\nR1#sh ip int br\r\nInterface IP-Address OK? Method Status Protocol\r\nEthernet0/0 192.168.100.1 YES NVRAM up up \r\nEthernet0/1 192.168.200.1 YES NVRAM up up \r\nEthernet0/2 unassigned YES NVRAM up up \r\nEthernet0/3 192.168.130.1 YES NVRAM up up \r\nLoopback22 10.2.2.2 YES manual up up \r\nLoopback33 unassigned YES unset up up \r\nLoopback45 unassigned YES unset up up \r\nLoopback55 5.5.5.5 YES manual up up \r\nR1#'
Method close#
Method close
closes session:
In [11]: ssh.close()
Example of paramiko use#
Example of paramiko use (3_paramiko.py file):
import paramiko
import time
import socket
from pprint import pprint
def send_show_command(
ip,
username,
password,
enable,
command,
max_bytes=60000,
short_pause=1,
long_pause=5,
):
cl = paramiko.SSHClient()
cl.set_missing_host_key_policy(paramiko.AutoAddPolicy())
cl.connect(
hostname=ip,
username=username,
password=password,
look_for_keys=False,
allow_agent=False,
)
with cl.invoke_shell() as ssh:
ssh.send("enable\n")
ssh.send(f"{enable}\n")
time.sleep(short_pause)
ssh.send("terminal length 0\n")
time.sleep(short_pause)
ssh.recv(max_bytes)
result = {}
for command in commands:
ssh.send(f"{command}\n")
ssh.settimeout(5)
output = ""
while True:
try:
part = ssh.recv(max_bytes).decode("utf-8")
output += part
time.sleep(0.5)
except socket.timeout:
break
result[command] = output
return result
if __name__ == "__main__":
devices = ["192.168.100.1", "192.168.100.2", "192.168.100.3"]
commands = ["sh clock", "sh arp"]
result = send_show_command("192.168.100.1", "cisco", "cisco", "cisco", commands)
pprint(result, width=120)
Result of script execution:
{'sh arp': 'sh arp\r\n'
'Protocol Address Age (min) Hardware Addr Type Interface\r\n'
'Internet 192.168.100.1 - aabb.cc00.6500 ARPA Ethernet0/0\r\n'
'Internet 192.168.100.2 124 aabb.cc00.6600 ARPA Ethernet0/0\r\n'
'Internet 192.168.100.3 183 aabb.cc00.6700 ARPA Ethernet0/0\r\n'
'Internet 192.168.100.100 208 aabb.cc80.c900 ARPA Ethernet0/0\r\n'
'Internet 192.168.101.1 - aabb.cc00.6500 ARPA Ethernet0/0\r\n'
'Internet 192.168.102.1 - aabb.cc00.6500 ARPA Ethernet0/0\r\n'
'Internet 192.168.130.1 - aabb.cc00.6530 ARPA Ethernet0/3\r\n'
'Internet 192.168.200.1 - 0203.e800.6510 ARPA Ethernet0/1\r\n'
'Internet 192.168.200.100 18 6ee2.6d8c.e75d ARPA Ethernet0/1\r\n'
'R1#',
'sh clock': 'sh clock\r\n*08:25:22.435 UTC Mon Jul 20 2020\r\nR1#'}
Paginated command output#
Example of using paramiko to work with paginated output of show command (3_paramiko_more.py file):
import paramiko
import time
import socket
from pprint import pprint
import re
def send_show_command(
ip,
username,
password,
enable,
command,
max_bytes=60000,
short_pause=1,
long_pause=5,
):
cl = paramiko.SSHClient()
cl.set_missing_host_key_policy(paramiko.AutoAddPolicy())
cl.connect(
hostname=ip,
username=username,
password=password,
look_for_keys=False,
allow_agent=False,
)
with cl.invoke_shell() as ssh:
ssh.send("enable\n")
ssh.send(enable + "\n")
time.sleep(short_pause)
ssh.recv(max_bytes)
result = {}
for command in commands:
ssh.send(f"{command}\n")
ssh.settimeout(5)
output = ""
while True:
try:
page = ssh.recv(max_bytes).decode("utf-8")
output += page
time.sleep(0.5)
except socket.timeout:
break
if "More" in page:
ssh.send(" ")
output = re.sub(" +--More--| +\x08+ +\x08+", "\n", output)
result[command] = output
return result
if __name__ == "__main__":
devices = ["192.168.100.1", "192.168.100.2", "192.168.100.3"]
commands = ["sh run"]
result = send_show_command("192.168.100.1", "cisco", "cisco", "cisco", commands)
pprint(result, width=120)