Netmiko 脚本未连接到多个主机
Netmiko Script not connecting to multiple hosts
我正在编写一个脚本,该脚本从 CSV 文件中提取数据并连接到多个主机以执行 运行 命令。该脚本的行为就像连接到所有不同的设备,但实际上它只连接到列表中的第一个设备。我需要更改什么才能使其正常工作?
示例 CSV 文件:
hostnames,device_platform,device_role
co-acc-v1.nunya.com,cisco_ios,co-acc-v
co-agg-r1.nunya.com,cisco_ios,co-agg-r
co-edg-fw1.nunya.com,cisco_asa,co-edg-fw
co-acc-sw1.nunya.com,cisco_ios,co-acc-sw
co-acc-rsw1.nunya.com,broadcom_icos,co-acc-rsw
脚本如下:
from netmiko import ConnectHandler
import concurrent.futures
import csv
import datetime
import time
username = 'Cisco'
pwd = 'Cisco123'
t1 = time.perf_counter()
def fetch_hostnames():
with open('devices.csv', 'r') as file:
reader = csv.reader(file)
keys = next(reader)[1:]
hostnames = {key: dict(zip(keys, values)) for key, *values in reader}
return hostnames
def verification_file(filename, output, hostname):
with open(filename, 'w') as output_file:
output_file.write(output)
print(f'Verification commands were successfully captured on {hostname}!')
return
def run_verification_commands(hostname):
today_date = datetime.datetime.now()
year = today_date.year
day = today_date.day
month = today_date.month
connection_info = {
'port': 22,
'username': username.lower(),
'password': pwd,
'secret': pwd,
'fast_cli': False
}
for device, info in fetch_hostnames().items():
platform = info['device_platform']
print(f'Connecting to host {hostname}...')
ssh_connection = ConnectHandler(ip=device, device_type=platform, banner_timeout=200, **connection_info)
ssh_connection.enable()
ssh_connection.send_command('terminal length 0', strip_prompt=False, strip_command=False)
print(f'Generating running configuration for host {hostname}...')
output = ssh_connection.send_command('show running-config', strip_prompt=False, strip_command=False)
prompt_hostname = ssh_connection.find_prompt()[0:-1]
filename = f'{prompt_hostname}_{month}_{day}_{year}_verification.txt'
print(f'Backing up configuration for host {hostname}')
time.sleep(1)
verification_file(filename, output, hostname)
ssh_connection.disconnect()
return
with concurrent.futures.ThreadPoolExecutor() as exe:
hosts = fetch_hostnames()
results = exe.map(run_verification_commands, hosts)
t2 = time.perf_counter()
print(f'The script finished executing in {round(t2-t1,2)} seconds.')
这是脚本的输出:
"C:\Program Files\Python39\python.exe" "C:/Scripts/Python/NetChecks/NC/test.py"
Connecting to host co-acc-v1.nunya.com...
Connecting to host co-agg-r1.nunya.com...
Connecting to host co-edg-fw1.nunya.com...
Connecting to host co-acc-sw1.nunya.com...
Connecting to host co-acc-rsw1.nunya.com...
Generating running configuration for host co-acc-v1.nunya.com...
Generating running configuration for host co-agg-r1.nunya.com...
Generating running configuration for host co-edg-fw1.nunya.com...
Generating running configuration for host co-acc-sw1.nunya.com...
Generating running configuration for host co-acc-rsw1.nunya.com...
Backing up configuration for host co-acc-v1.nunya.com...
Backing up configuration for host co-agg-r1.nunya.com...
Backing up configuration for host co-edg-fw1.nunya.com...
Backing up configuration for host co-acc-sw1.nunya.com...
Backing up configuration for host co-acc-rsw1.nunya.com...
Verification commands were successfully captured on co-acc-v1.nunya.com!
Verification commands were successfully captured on co-agg-r1.nunya.com!
Verification commands were successfully captured on co-edg-fw1.nunya.com!
Verification commands were successfully captured on co-acc-sw1.nunya.com!
Verification commands were successfully captured on co-acc-rsw1.nunya.com!
但是当脚本 运行s 并且如果我在 co-acc-v1.nunya.com
上执行 show users
它显示我已连接多次:
co-acc-v1#show users
Line User Host(s) Idle Location
* 2 vty 0 cisco idle 00:00:01 1.1.1.1
3 vty 1 cisco idle 00:00:02 1.1.1.1
4 vty 2 cisco idle 00:00:00 1.1.1.1
5 vty 3 cisco idle 00:00:00 1.1.1.1
6 vty 4 cisco idle 00:00:01 1.1.1.1
7 vty 5 cisco idle 00:00:01 1.1.1.1
Interface User Mode Idle Peer Address
co-acc-v1#
for device, info in fetch_hostnames().items():
这个 for 循环是不必要的,因为它已经对每个主机执行了操作:
results = exe.map(run_verification_commands, hosts)
每次调用run_verification_commands
时,无论传递给它什么,因为for循环与原始数据相反,它总是会抓住第一个主机。
这可以通过在设置并发期货时传入数据来解决:
with concurrent.futures.ThreadPoolExecutor() as exe:
hostinfos = fetch_hostnames().items()
results = exe.map(run_verification_commands, hostinfos)
hostinfos
在这种情况下是一个元组列表,元组包括:
(<hostname>, <info>)
然后run_verification_commands
可以把主机名和信息分开:
def run_verification_commands(hostinfo):
hostname, info = hostinfo
现在可以去掉这一行,里面的代码被拉回一级:
for device, info in fetch_hostnames().items():
并修改了这一行:
ssh_connection = ConnectHandler(ip=device ...
到
ssh_connection = ConnectHandler(ip=hostname ...
这将使它像您希望的那样循环。
最后一个音符:
open(filename, 'w')
每次都会覆盖文件。如果要追加,请将 w
(写入)更改为 a
(追加)
我正在编写一个脚本,该脚本从 CSV 文件中提取数据并连接到多个主机以执行 运行 命令。该脚本的行为就像连接到所有不同的设备,但实际上它只连接到列表中的第一个设备。我需要更改什么才能使其正常工作?
示例 CSV 文件:
hostnames,device_platform,device_role
co-acc-v1.nunya.com,cisco_ios,co-acc-v
co-agg-r1.nunya.com,cisco_ios,co-agg-r
co-edg-fw1.nunya.com,cisco_asa,co-edg-fw
co-acc-sw1.nunya.com,cisco_ios,co-acc-sw
co-acc-rsw1.nunya.com,broadcom_icos,co-acc-rsw
脚本如下:
from netmiko import ConnectHandler
import concurrent.futures
import csv
import datetime
import time
username = 'Cisco'
pwd = 'Cisco123'
t1 = time.perf_counter()
def fetch_hostnames():
with open('devices.csv', 'r') as file:
reader = csv.reader(file)
keys = next(reader)[1:]
hostnames = {key: dict(zip(keys, values)) for key, *values in reader}
return hostnames
def verification_file(filename, output, hostname):
with open(filename, 'w') as output_file:
output_file.write(output)
print(f'Verification commands were successfully captured on {hostname}!')
return
def run_verification_commands(hostname):
today_date = datetime.datetime.now()
year = today_date.year
day = today_date.day
month = today_date.month
connection_info = {
'port': 22,
'username': username.lower(),
'password': pwd,
'secret': pwd,
'fast_cli': False
}
for device, info in fetch_hostnames().items():
platform = info['device_platform']
print(f'Connecting to host {hostname}...')
ssh_connection = ConnectHandler(ip=device, device_type=platform, banner_timeout=200, **connection_info)
ssh_connection.enable()
ssh_connection.send_command('terminal length 0', strip_prompt=False, strip_command=False)
print(f'Generating running configuration for host {hostname}...')
output = ssh_connection.send_command('show running-config', strip_prompt=False, strip_command=False)
prompt_hostname = ssh_connection.find_prompt()[0:-1]
filename = f'{prompt_hostname}_{month}_{day}_{year}_verification.txt'
print(f'Backing up configuration for host {hostname}')
time.sleep(1)
verification_file(filename, output, hostname)
ssh_connection.disconnect()
return
with concurrent.futures.ThreadPoolExecutor() as exe:
hosts = fetch_hostnames()
results = exe.map(run_verification_commands, hosts)
t2 = time.perf_counter()
print(f'The script finished executing in {round(t2-t1,2)} seconds.')
这是脚本的输出:
"C:\Program Files\Python39\python.exe" "C:/Scripts/Python/NetChecks/NC/test.py"
Connecting to host co-acc-v1.nunya.com...
Connecting to host co-agg-r1.nunya.com...
Connecting to host co-edg-fw1.nunya.com...
Connecting to host co-acc-sw1.nunya.com...
Connecting to host co-acc-rsw1.nunya.com...
Generating running configuration for host co-acc-v1.nunya.com...
Generating running configuration for host co-agg-r1.nunya.com...
Generating running configuration for host co-edg-fw1.nunya.com...
Generating running configuration for host co-acc-sw1.nunya.com...
Generating running configuration for host co-acc-rsw1.nunya.com...
Backing up configuration for host co-acc-v1.nunya.com...
Backing up configuration for host co-agg-r1.nunya.com...
Backing up configuration for host co-edg-fw1.nunya.com...
Backing up configuration for host co-acc-sw1.nunya.com...
Backing up configuration for host co-acc-rsw1.nunya.com...
Verification commands were successfully captured on co-acc-v1.nunya.com!
Verification commands were successfully captured on co-agg-r1.nunya.com!
Verification commands were successfully captured on co-edg-fw1.nunya.com!
Verification commands were successfully captured on co-acc-sw1.nunya.com!
Verification commands were successfully captured on co-acc-rsw1.nunya.com!
但是当脚本 运行s 并且如果我在 co-acc-v1.nunya.com
上执行 show users
它显示我已连接多次:
co-acc-v1#show users
Line User Host(s) Idle Location
* 2 vty 0 cisco idle 00:00:01 1.1.1.1
3 vty 1 cisco idle 00:00:02 1.1.1.1
4 vty 2 cisco idle 00:00:00 1.1.1.1
5 vty 3 cisco idle 00:00:00 1.1.1.1
6 vty 4 cisco idle 00:00:01 1.1.1.1
7 vty 5 cisco idle 00:00:01 1.1.1.1
Interface User Mode Idle Peer Address
co-acc-v1#
for device, info in fetch_hostnames().items():
这个 for 循环是不必要的,因为它已经对每个主机执行了操作:
results = exe.map(run_verification_commands, hosts)
每次调用run_verification_commands
时,无论传递给它什么,因为for循环与原始数据相反,它总是会抓住第一个主机。
这可以通过在设置并发期货时传入数据来解决:
with concurrent.futures.ThreadPoolExecutor() as exe:
hostinfos = fetch_hostnames().items()
results = exe.map(run_verification_commands, hostinfos)
hostinfos
在这种情况下是一个元组列表,元组包括:
(<hostname>, <info>)
然后run_verification_commands
可以把主机名和信息分开:
def run_verification_commands(hostinfo):
hostname, info = hostinfo
现在可以去掉这一行,里面的代码被拉回一级:
for device, info in fetch_hostnames().items():
并修改了这一行:
ssh_connection = ConnectHandler(ip=device ...
到
ssh_connection = ConnectHandler(ip=hostname ...
这将使它像您希望的那样循环。
最后一个音符:
open(filename, 'w')
每次都会覆盖文件。如果要追加,请将 w
(写入)更改为 a
(追加)