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#'
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)