Although this is similar to the previous post of Scrapli Async and Multi threading. The difference is here is that it is a working example of what will be used in the Scrapli & Flask Project.
In the code below I will be using Scrapli to connect to 8 of my devices in the GNS3 lab to get the version. The number of devices is doubled to 16, reusing the first 8, so checking the version twice.
I have an update to this below that is how I have incorporated it into Flask.
Lab

Code Output
************************************************************
device: R2 ---> Version: 12.4(13b)
device: SW2 ---> Version: 15.0(20121031:162848)
device: SW3 ---> Version: 15.1(20130726:213425)
device: R1 ---> Version: 15.2(4)S5
device: R3 ---> Version: 16.12.3
device: SW1 ---> Version: 12.2(20100802:165548)
device: SW2 ---> Version: 15.0(20121031:162848)
device: SW1 ---> Version: 12.2(20100802:165548)
device: DC_SW1 ---> Version: 7.3(0)D1(1)
device: DC_SW2 ---> Version: 7.3(0)D1(1)
device: SW3 ---> Version: 15.1(20130726:213425)
device: R1 ---> Version: 15.2(4)S5
device: R3 ---> Version: 16.12.3
device: R2 ---> Version: 12.4(13b)
device: DC_SW3 ---> Version: 9.3(1)
device: DC_SW4 ---> Version: 9.3(1)
device: DC_SW2 ---> Version: 7.3(0)D1(1)
device: DC_SW1 ---> Version: 7.3(0)D1(1)
device: DC_SW3 ---> Version: 9.3(1)
device: DC_SW4 ---> Version: 9.3(1)
************************************************************
Execution time in seconds: 8.420679807662964Code
The code below is the actual file from the Scrapli & Flask project, I have used this to test with a device list and what will likely happen in the working version of the Scrapli and Flask Project. Right now this is a working example of Scrapli using multithreading for a range of Cisco devices when only entering an IP address. There are still some things I need address with this script such as what happens if I have three device types. I will make an update once I have the Arista switches working to test with them.
This code took me a while to get working because of the try/except for the Scrapli driver version. The Nexus switches were connecting but then taking a long time to time out. I think 15 seconds is the default timeout for connection, prompt and to get a return once a command is sent.
I used the three timeouts above to modify the behaviour. Before the timeout changes to get the version of 8 devices it was taking 30+ seconds. Now for 16 devices it is down to 8 seconds.
More Scrapli timeout reading can be found here
from scrapli.driver.core import IOSXEDriver, NXOSDriver
import time
import queue
from threading import Thread
class CiscoCommands:
def __init__(self):
self.username = 'admin'
self.password = 'Stefan2020'
def conn(self, ip):
switch = {
"host": ip,
"auth_username":self.username,
"auth_password":self.password,
"auth_strict_key":False,
# "auth_bypass": True,
"transport": "paramiko",
"timeout_ops": 2,
"timeout_socket": 1,
"timeout_transport": 1
}
try:
host = IOSXEDriver(**switch)
host.open()
os = "ios"
except:
host = NXOSDriver(**switch)
host.open()
os = "nxos"
return host, os
def show_version(self, ip, genie_list, error_ips):
while True:
ip = q.get()
host, os = CiscoCommands.conn(self, ip)
output = host.send_command("show version")
# Genie Parsed Response
genie_parsed_response = output.genie_parse_output()
if os == "ios":
hostname = genie_parsed_response['version']['hostname']
ip = ip
sw_version = genie_parsed_response['version']['version']
try:
model = genie_parsed_response['version']['chassis']
except:
model = "Unknown"
os_type = genie_parsed_response['version']['os']
chassis_sn = genie_parsed_response['version']['chassis_sn']
uptime = genie_parsed_response['version']['uptime']
genie_dict = {"Hostname":hostname,
"IP":ip,
"Version":sw_version,
"Model":model,
"OS":os_type,
"Chassis":chassis_sn,
"Uptime":uptime
}
genie_list.append(genie_dict)
elif os == "nxos":
hostname = genie_parsed_response['platform']['hardware']['device_name']
ip = ip
sw_version = genie_parsed_response['platform']['software']['system_version']
try:
model = genie_parsed_response['platform']['hardware']['model']
except:
model = "Unknown"
os_type = genie_parsed_response['platform']['os']
chassis_sn = genie_parsed_response['platform']['hardware']['processor_board_id']
uptime = genie_parsed_response['platform']['kernel_uptime']['days']
genie_dict = {"Hostname":hostname,
"IP":ip,
"Version":sw_version,
"Model":model,
"OS":os_type,
"Chassis":chassis_sn,
"Uptime":uptime
}
genie_list.append(genie_dict)
q.task_done()
# return hostname,ip,sw_version,model,os_type,chassis_sn,uptime
if __name__ == '__main__':
switches = ["172.16.1.101",
"172.16.1.102",
"172.16.1.103",
"172.16.1.104",
"172.16.1.105",
"172.16.1.106",
"172.16.1.111",
"172.16.1.112",
"172.16.1.113",
"172.16.1.114",
"172.16.1.101",
"172.16.1.102",
"172.16.1.103",
"172.16.1.104",
"172.16.1.105",
"172.16.1.106",
"172.16.1.111",
"172.16.1.112",
"172.16.1.113",
"172.16.1.114"
]
cmd = CiscoCommands()
startTime = time.time()
q = queue.Queue()
genie_list = []
error_ips = []
for thread_no in range(8):
worker = Thread(target=cmd.show_version, args=(q, genie_list, error_ips, ), daemon=True)
worker.start()
for switch in switches:
q.put(switch)
q.join()
print("\n")
print("*"*60)
# Print Successes
for device in genie_list:
print(f"device: {device['Hostname']} ---> Version: {device['Version']}")
# print("\n")
# Print IPs with errors
print("\n")
if error_ips != []:
for ip in error_ips:
print(f"Error connecting to {ip['IP Address']}")
# with open ("Scrapli_Connection_Error_IPs.txt", "a") as f:
# f.write(ip + "\n")
print("*"*60)
executionTime = (time.time() - startTime)
print('Execution time in seconds: ' + str(executionTime))Update! Adding to Flask
I have made numerous changes to integrate the code above into flask. The main two were; the creation of the threads into its own function and error checking.
Below is the form that the IPS are input. And below that is the output to the console when IPs are submited through the Flask form.
I have used a list of all 8 IP addresses in my lab and four IP addresses that Scrapli will fail to connect to.
Right now there is no DB update, so Flask just redirects to the Device Inventory once the Scapli script has run.
# IPs input to form
2.2.2.2
172.16.1.101
172.16.1.102
172.16.1.103
172.16.1.104
172.16.1.105
1.1.1.1
172.16.1.106
4.4.4.4
172.16.1.111
172.16.1.112
172.16.1.113
172.16.1.114
3.3.3.3
['2.2.2.2', '172.16.1.101', '172.16.1.102', '172.16.1.103', '172.16.1.104', '172.16.1.105', '1.1.1.1', '172.16.1.106', '4.4.4.4', '172.16.1.111', '172.16.1.112', '172.16.1.113', '172.16.1.114', '3.3.3.3']
ERROR!!!!!
ERROR!!!!!
ERROR!!!!!
ERROR!!!!!
[{'Hostname': 'SW1', 'IP': '172.16.1.101', 'Version': '12.2(20100802:165548)', 'Model': 'Unknown', 'OS': 'IOS', 'Chassis': '2048002', 'Uptime': '3 days, 1 hour, 29 minutes'}, {'Hostname': 'SW2', 'IP': '172.16.1.102', 'Version': '15.0(20121031:162848)', 'Model': 'Unknown', 'OS': 'IOS', 'Chassis': '2048003', 'Uptime': '3 days, 1 hour, 29 minutes'}, {'Hostname': 'SW3', 'IP': '172.16.1.103', 'Version': '15.1(20130726:213425)', 'Model': 'Unknown', 'OS': 'IOS', 'Chassis': '2048004', 'Uptime': '3 days, 1 hour, 29 minutes'}, {'Hostname': 'R1', 'IP': '172.16.1.104', 'Version': '15.2(4)S5', 'Model': '7206VXR', 'OS': 'IOS', 'Chassis': '4279256517', 'Uptime': '3 days, 1 hour, 29 minutes'}, {'Hostname': 'R3', 'IP': '172.16.1.106', 'Version': '16.12.3', 'Model': 'CSR1000V', 'OS': 'IOS-XE', 'Chassis': '9202RL75OHO', 'Uptime': '5 days, 10 hours, 35 minutes'}, {'Hostname': 'R2', 'IP': '172.16.1.105', 'Version': '12.4(13b)', 'Model': '2691', 'OS': 'IOS', 'Chassis': 'XXXXXXXXXXX', 'Uptime': '1 day, 8 hours, 30 minutes'}, {'Hostname': 'DC_SW2', 'IP': '172.16.1.112', 'Version': '7.3(0)D1(1)', 'Model': 'NX-OSv', 'OS': 'NX-OS', 'Chassis': 'TM8C709500B', 'Uptime': 5}, {'Hostname': 'DC_SW1', 'IP': '172.16.1.111', 'Version': '7.3(0)D1(1)', 'Model': 'NX-OSv', 'OS': 'NX-OS', 'Chassis': 'TM8C583900B', 'Uptime': 5}, {'Hostname': 'DC_SW3', 'IP': '172.16.1.113', 'Version': '9.3(1)', 'Model': 'Nexus9000 9000v', 'OS': 'NX-OS', 'Chassis': '9P9V3GQPHCF', 'Uptime': 5}, {'Hostname': 'DC_SW4', 'IP': '172.16.1.114', 'Version': '9.3(1)', 'Model': 'Nexus9000 9000v', 'OS': 'NX-OS', 'Chassis': '9P9V3GQPHCF', 'Uptime': 5}]
************************************************************
device: SW1 ---> Version: 12.2(20100802:165548)
device: SW2 ---> Version: 15.0(20121031:162848)
device: SW3 ---> Version: 15.1(20130726:213425)
device: R1 ---> Version: 15.2(4)S5
device: R3 ---> Version: 16.12.3
device: R2 ---> Version: 12.4(13b)
device: DC_SW2 ---> Version: 7.3(0)D1(1)
device: DC_SW1 ---> Version: 7.3(0)D1(1)
device: DC_SW3 ---> Version: 9.3(1)
device: DC_SW4 ---> Version: 9.3(1)
Error connecting to 1.1.1.1
Error connecting to 2.2.2.2
Error connecting to 4.4.4.4
Error connecting to 3.3.3.3
************************************************************
Execution time in seconds: 5.309101104736328