How To(1) Paramiko & Python for Network Automation
How To(1) Paramiko & Python for Network Automation
In this tutorial, we’ll see how to initiate SSH from Paramiko Python library to Cisco Device.
Paramiko is a pure-Python implementation of the SSHv2 protocol, providing both client and server functionality.
It is better to first understand Paramiko and then look into other network automation tools such as “Netmiko, NAPALM, Nornir, etc…” so that you will get a clear understanding of SSH connection details from Python.
Upon Paramiko API documentation you will find multiple “Core SSH protocol classes” and the one that we will deal with is the Client class.
And here Client they have given us a sample script, as shown below:
# Initializing SSH Client.
client = SSHClient()
# Loading system hosts keys
client.load_system_host_keys()
# Connecting to Linux server "ssh.example.com".
client.connect('ssh.example.com')
# Executing the command "ls -l" in a Linux server.
stdin, stdout, stderr = client.exec_command('ls -l')
From the above example, The method they are using is exec_command()
This exec_command()
method is suitable for connecting to Linux servers because that is having the intelligence to identify the standard input, output, and error based on the response type stdout as it will print the data.
For example, if you are getting an error, it will come in stderr automatically.
exec_command(command, bufsize=-1, timeout=None, get_pty=False, environment=None)
# Execute a command on the SSH server.
# A new Channel is opened and the requested command is executed.
# The command’s input and output streams are returned as Python file-like objects representing stdin, stdout, and stderr.
But to interact with Network Devices such as Routers and Switches, it is better to use invoke_shell()
method.
Because that will initiate an interactive shell session on the SSH “server” in our case it will be our Router or Switch and we will send a stream of data “In our case Commands“, and then this will be just printing the output.
In this case, Paramiko doesn’t check whether it is an error message or a success message, It will just print as it is.
First code:
Now, let’s go to our python terminal and start writing our first code:
If you need to build your Separated and Isolated Python Development Environment for Learning.
So, you can follow my latest tutorial.
Install Paramiko
First, we need to Install Paramiko:
pip install paramiko
OR
python3 -m pip install paramiko
Check reachability and accessibility
Then, check Cisco Router reachability and accessibility:
moalaa@devnet-automation-01:~$ ping R1.MoAlaa.com -c 2
PING R1.MoAlaa.com (192.168.100.101) 56(84) bytes of data.
64 bytes from R1.MoAlaa.com (192.168.100.101): icmp_seq=1 ttl=255 time=1.35 ms
64 bytes from R1.MoAlaa.com (192.168.100.101): icmp_seq=2 ttl=255 time=2.69 ms
moalaa@devnet-automation-01:~$ ssh moalaa@R1.MoAlaa.com
Password:
C
____ _ _ _
| _ \ _____ _| \ | | ___| |_
| | | |/ _ \ \ / / \| |/ _ \ __|
| |_| | __/\ V /| |\ | __/ |_
|____/ \___| \_/ |_| \_|\___|\__|
_ _ _ _
/ \ _ _| |_ ___ _ __ ___ __ _| |_(_) ___ _ __
/ _ \| | | | __/ _ \| '_ ` _ \ / _` | __| |/ _ \| '_ \
/ ___ \ |_| | || (_) | | | | | | (_| | |_| | (_) | | | |
/_/ \_\__,_|\__\___/|_| |_| |_|\__,_|\__|_|\___/|_| |_|
R1-ASR1#
Start the Python shell
Then, start the Python shell, simply type python3 and hit Enter in the terminal:
(MoAlaa_DevNet_env) moalaa@devnet-automation-01:~$ python3
Python 3.8.10 (default, Nov 14 2022, 12:59:47)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
Import Paramiko
Then, we need to import Paramiko:
>>> from paramiko import client
>>>
Host details
Then, we will define the host details.
Defining a string hostname. So the device’s name is “R1.MoAlaa.com“. Either, we can give the IP Address or Hostname here.
>>> hostname = "R1.MoAlaa.com"
Defining a string “username“. So the device’s username is “moalaa“.
>>> username = "moalaa"
Defining a string “password“. So the device’s password is “cisco“.
>>> password = "cisco"
Now we’ll create SSH client “ssh_client“. So that will be client.SSHClient()
.
>>> ssh_client = client.SSHClient()
Set policy “AutoAddPolicy” to use when connecting to devices without a known host key.
>>> ssh_client.set_missing_host_key_policy(client.AutoAddPolicy())
Now, let’s connect to our Router:
>>> ssh_client.connect(hostname=hostname,
... port=22,
... username=username,
... password=password,
... look_for_keys=False, allow_agent=False)
>>>
Now, it should be connected successfully.
Now, if you want to execute a command, such as “show interfaces description”.
We need first initiate, invoke_shell()
or the exec_command()
method.
So, we will create another variable “device_access” and using invoke_shell()
method.
>>> device_access = ssh_client.invoke_shell()
Now, we’ll try to send the commands terminal len 0
and show interfaces description
directly and see what happens.
We have a method called send()
which will use the initiated SSH channel and just send the data “command” in our case.
>>> device_access.send("terminal len 0\n")
15
>>>
>>> device_access.send("show interfaces description\n")
28
>>>
Now, we’ll try receiving the data “output”.
So, we will create another variable “output ” and using recv()
method.
We need to set the bytes of data that we need to receive. So we will give the maximum “65535“
>>> output = device_access.recv(65535)
Now, we’ll try printing the output on our screen.
Note: We need to use the
decode()
method to convert the output bytes into a human-readable format.
>>> print(output.decode())
C
____ _ _ _
| _ \ _____ _| \ | | ___| |_
| | | |/ _ \ \ / / \| |/ _ \ __|
| |_| | __/\ V /| |\ | __/ |_
|____/ \___| \_/ |_| \_|\___|\__|
_ _ _ _
/ \ _ _| |_ ___ _ __ ___ __ _| |_(_) ___ _ __
/ _ \| | | | __/ _ \| '_ ` _ \ / _` | __| |/ _ \| '_ \
/ ___ \ |_| | || (_) | | | | | | (_| | |_| | (_) | | | |
/_/ \_\__,_|\__\___/|_| |_| |_|\__,_|\__|_|\___/|_| |_|
R1-ASR1#terminal len 0
R1-ASR1#show interfaces description
Interface Status Protocol Description
Gi1 up up
Gi1.12 up up Connection to R2-ASR2
Gi1.13 up up Connection to R3-ASR3
Gi1.14 up up Connection to R4-ASR4
Gi1.15 up up Connection to R5-ASR5
Gi2 up up "MANAGEMENT INTERFACE - DON'T TOUCH ME"
Gi3 admin down down "MNG - Int - PFSense FW"
Lo0 up up
Lo7 up up
Lo8 up up
Lo100 up up
Lo101 up up Configured with nornir-netmiko
Lo102 up up Configured with nornir-netmiko
Lo200 up up
Lo201 up up Configured with nornir-scrapli
Lo202 up up Configured with nornir-scrapli
Lo300 up up
Lo301 up up Configured with nornir-napalm
Lo400 up up
Lo1000 up up
R1-ASR1#
>>>
Finally
We need to close this SSH connection by using close()
method.
>>> ssh_client.close()
>>>