This is a very quick and dirty way to backup network devices rom my GNS3 lab. I will likely expand on this in the future.
This is a simple Paramiko script that will SSH into each device perform “show run” and sve that output with in a text file with the IP, year, month and day in the title.
Everything is hard coded into this file, hostnames, IPs, credentials. This is only good for a lab and I’ll be working on something to improve this and probably include it in my Scrapli & Flask project.
I needed something quick and it’s a reuse of somthing I wrote in 2018 for practice. If it works, it works!
How it Works
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
import paramiko import time def connect(server_ip, server_port, user, passwd): ssh_client = paramiko.SSHClient() ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) print(f"Connecting to {server_ip}") ssh_client.connect(hostname=server_ip, port=server_port, username=user, password=passwd, look_for_keys=False, allow_agent=False) return ssh_client def get_shell(ssh_client): shell = ssh_client.invoke_shell() return shell def send_command(shell, command, timeout=1): print(f"Sending command: {command}") shell.send(command + "\n") time.sleep(timeout) def show(shell, n=10000): output = shell.recv(n) return output.decode() def close(ssh_client): if ssh_client.get_transport().is_active() == True: print("Closing the connection") ssh_client.close() |
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
import U_myparamiko from datetime import datetime SW1 = {"server_ip": "172.16.1.101", "server_port": "22", "user": "admin", "passwd": "Stefan2020"} SW2 = {"server_ip": "172.16.1.102", "server_port": "22", "user": "admin", "passwd": "Stefan2020"} SW3 = {"server_ip": "172.16.1.103", "server_port": "22", "user": "admin", "passwd": "Stefan2020"} R1 = {"server_ip": "172.16.1.104", "server_port": "22", "user": "admin", "passwd": "Stefan2020"} R2 = {"server_ip": "172.16.1.105", "server_port": "22", "user": "admin", "passwd": "Stefan2020"} R3 = {"server_ip": "172.16.1.106", "server_port": "22", "user": "admin", "passwd": "Stefan2020"} DC_SW1 = {"server_ip": "172.16.1.111", "server_port": "22", "user": "admin", "passwd": "Stefan2020"} DC_SW2 = {"server_ip": "172.16.1.112", "server_port": "22", "user": "admin", "passwd": "Stefan2020"} DC_SW3 = {"server_ip": "172.16.1.113", "server_port": "22", "user": "admin", "passwd": "Stefan2020"} DC_SW4 = {"server_ip": "172.16.1.114", "server_port": "22", "user": "admin", "passwd": "Stefan2020"} devices = [SW1,SW2,SW3,R1,R2,R3,DC_SW1,DC_SW2,DC_SW3,DC_SW4] for router in devices: print(router["server_ip"]) client = U_myparamiko.connect(**router) shell = U_myparamiko.get_shell(client) # U_myparamiko.send_command(shell, "enable") # U_myparamiko.send_command(shell, "cisco") U_myparamiko.send_command(shell, "term len 0") U_myparamiko.show(shell) #Clears shell buffer to 0, only receive the output from below, no banner U_myparamiko.send_command(shell, "sh run") output = U_myparamiko.show(shell) output_list = output.splitlines() output_list = output_list[11:-1] output = "\n".join(output_list) now = datetime.now() year = now.year month = now.month day = now.day file_name = f'{router["server_ip"]}_{year}-{month}-{day}_backup.cfg' with open(file_name, "w") as f: f.write(output) U_myparamiko.close(client) |
Problems
There are many many problems with a script like this, apart from the obvious security issues with including usernames/passwords in the script the major issue is everything is hard coded and there is no error checking.
Having everything hard coded is annoying as it’s not dynamic, the script cannot be picked up and moved or applied to new devices without major changes. We don’t want to perform a rewrite each time we use this.
We want to feed the script devices to backup and it then perform the backup. Minimal input!
The second major issue is that there is no error checking. When running this script I ran up against this problem as some devices in GNS3 had got into a non response state. The script hung and eventually errored when Paramiko hit the default timeout for the SSH connection. I ended up with only 2 devices backuped up properly. This is not what we want.
A third error is the script is linear. There is a no parallelism. If a single device takes 3 seconds to SSH into and backup, then 10 will take 30 seconds. This does not scale well.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
backup_test.py 172.16.1.101 Connecting to 172.16.1.101 Sending command: term len 0 Sending command: sh run Closing the connection 172.16.1.102 Connecting to 172.16.1.102 Sending command: term len 0 Sending command: sh run Closing the connection 172.16.1.103 Connecting to 172.16.1.103 Traceback (most recent call last): File "/home/stef/Python/ScrapliFlaskLab/scrapli_lab/testing/backup_test.py", line 24, in <module> client = U_myparamiko.connect(**router) File "/home/stef/Python/ScrapliFlaskLab/scrapli_lab/testing/U_myparamiko.py", line 8, in connect ssh_client.connect(hostname=server_ip, port=server_port, username=user, password=passwd, File "/home/stef/Python/ScrapliFlaskLab/scrapli/lib/python3.8/site-packages/paramiko/client.py", line 349, in connect retry_on_signal(lambda: sock.connect(addr)) File "/home/stef/Python/ScrapliFlaskLab/scrapli/lib/python3.8/site-packages/paramiko/util.py", line 279, in retry_on_signal return function() File "/home/stef/Python/ScrapliFlaskLab/scrapli/lib/python3.8/site-packages/paramiko/client.py", line 349, in <lambda> retry_on_signal(lambda: sock.connect(addr)) TimeoutError: [Errno 110] Connection timed out |