网络自动化的用例
使用 Python Netmiko 模块自动执行来自多个供应商的交换机、路由器和防火墙。
我经常发现自己处于面对“不友好的”网络的位置。所谓不友好,我的意思是那里没有现有的文档,或者即使存在,也已经过时或被故意隐藏。考虑到这一点,在本文中,我描述了自己发现的用于恢复控制、审计、记录和自动化这些网络的有用工具。请注意,我不会尝试在此处完整记录任何工具。我主要想给您足够的真实示例,以证明您可以通过这些工具节省多少时间和精力,并且我希望本文能激励您探索官方文档和示例代码。
为了省钱,我想使用开源工具从网络上的所有设备收集信息。我还没有找到一种适用于通常遇到的所有供应商和操作系统版本的工具。SNMP 可以提供很多我需要的信息,但它必须首先在每个设备上手动配置。事实上,大规模启用 SNMP 可能是本文中描述的网络自动化工具的首批用例之一。
大多数现代设备都支持 REST API,但公司通常背负着许多不支持比 Telnet 和 SSH 更高级功能的遗留设备。我选择了 SSH 访问作为最低的共同标准,因为每个设备都必须支持此功能才能在网络上进行管理。
我首选的自动化语言是 Python,因此下一个问题是找到一个 Python 模块,该模块可以抽象化 SSH 登录过程,从而轻松运行命令并收集命令输出。
为什么选择 Netmiko?几年前,我发现了 Paramiko SSH 模块,并使用它在多家公司创建了 Linux 服务器的实时清单。它使我能够登录到主机并收集命令的输出,例如 lspci
、dmidecode
和 lsmod
。
命令输出填充了一个数据库,工程师可以使用该数据库搜索特定的硬件。当我随后尝试使用 Paramiko 清点网络交换机时,我发现某些交换机供应商和操作系统组合会导致 Paramiko SSH 会话挂起。我可以看到 SSH 登录本身是成功的,但会话会在登录后立即挂起。我从未能够确定原因,但在研究挂起问题时发现了 Netmiko。当我用 Netmiko 代码替换所有 Paramiko 代码后,我的所有会话挂起问题都消失了,而且我从此没有回头。Netmiko 也针对网络设备管理任务进行了优化,而 Paramiko 更像是一个通用的 SSH 模块。
以编程方式处理命令行界面熟悉“Expect”语言的人会认识到发送命令并匹配返回的 CLI 提示符和命令输出以确定命令是否成功的技术。对于大多数网络设备而言,CLI 提示符会根据您处于非特权模式、处于“enable”模式还是处于“config”模式而变化。
例如,CLI 提示符通常将是设备主机名,后跟特定字符。
非特权模式
sfo03-r7r9-sw1>
特权或“enable”模式
sfo03-r7r9-sw1#
“Config”模式
sfo03-r7r9-sw1(config)#
这些不同的提示符使您能够以编程方式从一种模式转换到另一种模式,并确定转换是否成功。
抽象化Netmiko 抽象化了与交换机通信时需要执行的许多常见操作。例如,如果您运行一个生成多页输出的命令,则交换机 CLI 通常会“分页”输出,等待输入后再显示下一页。这使得收集多页输出作为单个文本 blob 变得困难。关闭分页的命令因交换机供应商而异。例如,对于一个供应商,这可能是 terminal length 0
,而对于另一个供应商,这可能是 set cli pager off
。Netmiko 抽象化了此操作,因此您只需使用 disable_paging()
函数,它将为特定设备运行适当的命令。
Netmiko 支持越来越多的网络供应商和产品组合。您可以在文档中找到当前列表。Netmiko 不会自动检测供应商,因此您在使用这些功能时需要指定该信息。某些供应商的产品线具有不同的 CLI 命令。例如,Dell 有两种类型:dell_force10
和 dell_powerconnect
;Cisco 在不同的产品线上有多个 CLI 版本,包括 cisco_ios
、cisco_nxos
和 cisco_asa
。
Netmiko 的官方代码和文档位于 https://github.com/ktbyers/netmiko,作者在他的 主页 上收集了许多有用的文章。
如果您熟悉开发者工具,可以直接克隆 GIT 仓库。对于典型的最终用户,使用 pip
安装 Netmiko 应该就足够了
# pip install netmiko
几点注意事项
在加入网络自动化潮流之前,您需要理清以下事项
- 大规模配置:请注意,传统的“逐盒”网络管理的缓慢速度可能在某种程度上保护了您免受大规模错误的影响。如果您手动进行更改,则通常会在访问几个设备后收到问题警报。使用网络自动化工具,您可以在几秒钟内使您的所有网络设备变得无用。
- 配置备份策略:理想情况下,这将包括版本控制功能,以便您可以回滚到特定的“已知良好”时间点。在您花大价钱购买此功能之前,请查看 RANCID 包。
- 带外网络管理:几乎所有现代交换机或网络设备都将具有专用的 OOB 端口。这种物理上独立的网络允许您从配置错误中恢复,这些错误可能会使您与您正在管理的设备断开连接。
- 测试策略:例如,设置一个专门的代表性设备池,永久用于测试和概念验证。在生产网络上推出更改时,首先在少量设备上验证自动化,然后再尝试一次性对数百个设备进行操作。
Netmiko 的作者创建了几个名为 Netmiko Tools 的独立脚本,您无需编写任何 Python 代码即可使用它们。有关详细信息,请查阅官方文档,因为我在此处仅提供一些亮点。
在撰写本文时,有三个工具
netmiko-show
在一个或多个设备上运行任意“show”命令。默认情况下,它将显示完整配置,但您可以使用 --cmd
选项提供备用命令。请注意,“show”命令可以显示许多未存储在实际设备配置中的详细信息。
例如,您可以显示来自多个设备的生成树协议 (STP) 详细信息
% netmiko-show --cmd "show spanning-tree detail" arista-eos |
↪egrep "(last change|from)"
sfo03-r1r12-sw1.txt: Number of topology changes 2307 last
↪change occurred 19:14:09 ago
sfo03-r1r12-sw1.txt: from Ethernet1/10/2
sfo03-r1r12-sw2.txt: Number of topology changes 6637 last
↪change occurred 19:14:09 ago
sfo03-r1r12-sw2.txt: from Ethernet1/53
当跟踪导致 STP 抖动问题的特定交换机和交换机端口时,此信息非常有用。通常,您会寻找拓扑更改计数非常高且快速增加,并且“上次更改时间”以秒为单位。 “from”字段为您提供了更改的源端口,使您可以缩小问题根源的范围。
查找此信息的“老式”方法是登录到最顶层的交换机,查看其 STP 详细信息,找到问题端口,登录到此端口下游的交换机,查看其 STP 详细信息,然后重复此过程,直到找到问题的根源。Netmiko Tools 允许您在单个操作中对整个网络进行搜索,以查找您需要的所有信息。
netmiko-cfg
将配置片段应用于一个或多个设备。使用 --cmd
选项指定配置命令,或使用 --infile
从文件读取配置。这可以用于大规模配置。大规模更改可能包括整个网络的 DNS 服务器、NTP 服务器、SNMP 社区字符串或 syslog 服务器。例如,要在所有 Arista 交换机上配置只读 SNMP 社区
$ netmiko-cfg --cmd "snmp-server community mysecret ro"
↪arista-eos
您仍然需要验证您发送的命令是否适用于目标设备的供应商和操作系统组合,因为 Netmiko 不会为您完成所有这些工作。请参阅下面的“groups”机制,了解如何仅将供应商特定的配置应用于来自特定供应商的设备。
netmiko-grep
在多个设备的配置中搜索字符串。例如,验证 Arista 交换机中的当前 syslog 目标
$ netmiko-grep --use-cache "logging host" arista-eos
sfo03-r2r7-sw1.txt:logging host 10.7.1.19
sfo03-r3r14-sw1.txt:logging host 10.8.6.99
sfo03-r3r16-sw1.txt:logging host 10.8.6.99
sfo03-r4r18-sw1.txt:logging host 10.7.1.19
所有 Netmiko 工具都依赖于设备“清单”,该清单是以 YAML 格式存储在当前目录或您的主目录中的“.netmiko.yml”文件。
清单中的每个设备都具有以下格式
sfo03-r1r11-sw1:
device_type: cisco_ios
ip: sfo03-r1r11-sw1
username: netadmin
password: secretpass
port: 22
设备条目后可以跟组定义。组只是一个组名称,后跟设备列表
cisco-ios:
- sfo03-r1r11-sw1
cisco-nxos:
- sfo03-r1r12-sw2
- sfo03-r3r17-sw1
arista-eos:
- sfo03-r1r10-sw2
- sfo03-r6r6-sw1
例如,您可以使用组名称“cisco-nxos”来运行 Cisco Nexus NX-OS 唯一的命令,例如 feature
% netmiko-cfg --cmd "feature interface-vlan" cisco-nxos
请注意,设备类型示例只是一种组类型。其他组可以指示物理位置(“SFO03”、“RKV02”)、角色(“TOR”、“spine”、“leaf”、“core”)、所有者(“Eng”、“QA”)或任何其他对您有意义的类别。
由于我正在处理数百个设备,因此我不想手动创建 YAML 格式的清单文件。相反,我从一个简单的设备列表和相应的 Netmiko“device_type”开始
sfo03-r1r11-sw1,cisco_ios
sfo03-r1r12-sw2,cisco_nxos
sfo03-r1r10-sw2,arista_eos
sfo03-r4r5-sw3,arista_eos
sfo03-r1r12-sw1,cisco_nxos
sfo03-r5r15-sw2,dell_force10
然后,我使用标准的 Linux 命令创建 YAML 清单文件
% grep -v '^#' simplelist.txt | awk -F, '{printf("%s:\n
↪device_type:
%s\n ip: %s\n username: netadmin\n password:
↪secretpass\n port:
22\n",$1,$2,$1)}' >> .netmiko.yml
我正在使用集中式身份验证系统,因此所有设备的用户名称和密码都相同。上面的命令产生以下 YAML 格式的文件
sfo03-r1r11-sw1:
device_type: cisco_ios
ip: sfo03-r1r11-sw1
username: netadmin
password: secretpass
port: 22
sfo03-r1r12-sw2:
device_type: cisco_nxos
ip: sfo03-r1r12-sw2
username: netadmin
password: secretpass
port: 22
sfo03-r1r10-sw2:
device_type: arista_eos
ip: sfo03-r1r10-sw2
username: netadmin
password: secretpass
port: 22
创建此清单后,您可以针对单个设备或设备组使用 Netmiko Tools。
创建清单的副作用是,您现在拥有了网络上设备的总清单;您还证明了设备名称可以通过 DNS 解析,并且您拥有正确的登录凭据。这实际上是我工作过的某些环境中向前迈出的一大步。
请注意,netmiko-grep
会在本地缓存设备配置。构建缓存后,您可以通过指定 --use-cache
选项来使后续搜索操作运行得更快。
现在应该很明显,您可以使用 Netmiko Tools 进行大量管理和自动化,而无需编写任何 Python 代码。同样,有关所有选项和更多示例,请参阅官方文档。
开始使用 Netmiko 编码现在您已经了解了 Netmiko Tools 的功能,您可能会想到需要实际编码的独特场景。
郑重声明,目前我并不认为自己是高级 Python 程序员,因此此处的示例可能不是最优的。我也将我的示例限制为代码片段,而不是完整的脚本。示例代码使用 Python 2.7。
我对问题的方法在我意识到 Netmiko Tools 命令之前,我编写了很多代码,并且我发现自己重复了很多它们的功能。我最初的方法是将问题分解为两个独立的阶段。第一阶段是“扫描”交换机并在本地存储其配置和命令输出,第二阶段是处理和搜索存储的数据。
我的第一个脚本是一个“扫描器”,它从一个简单的文本文件中读取交换机主机名和 Netmiko 设备类型的列表,登录到每个交换机,运行一系列 CLI 命令,然后将每个命令的输出存储在文本文件中以供以后处理。
读取设备列表我的首要任务是从 CSV 格式的简单文本文件中读取网络设备及其 Netmiko“设备类型”的列表。我包含了 csv 模块,因此可以使用 csv.Dictreader 函数,该函数将 CSV 字段作为 Python 字典返回。我喜欢 CSV 文件格式,因为任何具有有限 UNIX/Linux 技能的人都可能知道如何使用它,而且如果您有现有的网络设备数据库,它是一种非常常见的数据导出文件类型。
例如,以下是 CSV 格式的交换机名称和设备类型列表
sfo03-r1r11-sw1,cisco_ios
sfo03-r1r12-sw2,cisco_nxos
sfo03-r1r10-sw2,arista_eos
sfo03-r4r5-sw3,arista_eos
sfo03-r1r12-sw1,cisco_nxos
sfo03-r5r15-sw2,dell_force10
以下 Python 代码从命令行读取数据文件名,打开该文件,然后迭代每个设备条目,调用将运行实际 Netmiko 代码的 login_switch()
函数
import csv
import sys
import logging
def main():
# get data file from command line
devfile = sys.argv[1]
# open file and extract the two fields
with open(devfile,'rb') as devicesfile:
fields = ['hostname','devtype']
hosts = csv.DictReader(devicesfile,fieldnames=fields,
↪delimiter=',')
# iterate through list of hosts, calling "login_switch()"
# for each one
for host in hosts:
hostname = host['hostname']
print "hostname = ",hostname
devtype = host['devtype']
login_switch(hostname,devtype)
login_switch()
函数运行任意数量的命令,并将输出存储在基于设备名称的目录下的单独文本文件中
# import required module
from netmiko import ConnectHandler
# login into switch and run command
def login_switch(host,devicetype):
# required arguments to ConnectHandler
device = {
# device_type and ip are read from data file
'device_type': devicetype,
'ip':host,
# device credentials are hardcoded in script for now
'username':'admin',
'password':'secretpass',
}
# if successful login, run command on CLI
try:
net_connect = ConnectHandler(**device)
commands = "show version"
output = net_connect.send_command(commands)
# construct directory path based on device name
path = '/root/login/scan/' + host + "/"
make_dir(path)
filename = path + "show_version"
# store output of command in file
handle = open (filename,'w')
handle.write(output)
handle.close()
# if unsuccessful, print error
except Exception as e:
print "RAN INTO ERROR "
print "Error: " + str(e)
此代码打开与设备的连接,执行 show version
命令,并将输出存储在 /root/login/scan/<devicename>/show_version 中。
show version
输出非常有用,因为它通常包含供应商、型号、操作系统版本、硬件详细信息、序列号和 MAC 地址。以下是来自 Arista 交换机的示例
Arista DCS-7050QX-32S-R
Hardware version: 01.31
Serial number: JPE16292961
System MAC address: 444c.a805.6921
Software image version: 4.17.0F
Architecture: i386
Internal build version: 4.17.0F-3304146.4170F
Internal build ID: 21f25f02-5d69-4be5-bd02-551cf79903b1
Uptime: 25 weeks, 4 days, 21 hours and 32
minutes
Total memory: 3796192 kB
Free memory: 1230424 kB
此信息使您可以创建各种有用的东西,例如网络硬件清单和软件版本报告,您可以将其用于审计和计划的软件更新。
我当前的脚本运行 show lldp neighbors
、show run
、show interface status
并记录设备 CLI 提示符以及 show version
。
上面的代码示例构成了您开始使用 Netmiko 所需的大部分内容。现在,您有一种无需手动键入任何内容即可在任意数量的设备上运行任意命令的方法。从任何意义上讲,这都不是软件定义网络 (SDN),但这仍然是从“逐盒”网络管理方法向前迈出的一大步。
接下来,让我们在示例网络上试用扫描脚本
$ python scanner.py devices.csv
hostname = sfo03-r1r15-sw1
hostname = sfo03-r3r19-sw0
hostname = sfo03-r1r16-sw2
hostname = sfo03-r3r8-sw2
RAN INTO ERROR
Error: Authentication failure: unable to connect dell_force10
↪sfo03-r3r8-sw2:22
Authentication failed.
hostname = sfo03-r3r10-sw2
hostname = sfo03-r3r11-sw1
hostname = sfo03-r4r14-sw2
hostname = sfo03-r4r15-sw1
如果您有很多设备,您可能会遇到登录失败的情况,如上面扫描中间的情况所示。这些可能是由多种原因引起的,包括设备已关闭、无法通过网络访问、脚本具有不正确的凭据等等。预计需要多次尝试才能解决所有问题,然后才能在大型网络上获得“干净”的运行。
这完成了流程的“扫描”部分,现在您需要的所有数据都本地存储在“scan”目录中以供进一步分析,该目录包含每个设备的子目录
$ ls scan/
sfo03-r1r10-sw2 sfo03-r2r14-sw2 sfo03-r3r18-sw1 sfo03-r4r8-sw2
↪sfo03-r6r14-sw2
sfo03-r1r11-sw1 sfo03-r2r15-sw1 sfo03-r3r18-sw2 sfo03-r4r9-sw1
↪sfo03-r6r15-sw1
sfo03-r1r12-sw0 sfo03-r2r16-sw1 sfo03-r3r19-sw0 sfo03-r4r9-sw2
↪sfo03-r6r16-sw1
sfo03-r1r12-sw1 sfo03-r2r16-sw2 sfo03-r3r19-sw1 sfo03-r5r10-sw1
↪sfo03-r6r16-sw2
sfo03-r1r12-sw2 sfo03-r2r2-sw1 sfo03-r3r4-sw2 sfo03-r5r10-sw2
↪sfo03-r6r17- sw1
您可以看到每个子目录都包含每个命令输出的单独文件
$ ls sfo03-r1r10-sw2/
show_lldp prompt show_run show_version show_int_status
通过日志记录进行调试
Netmiko 在运行时通常非常安静,因此很难判断与网络设备交互时出现问题的位置。我发现调试问题最简单的方法是使用日志记录模块。我通常保持禁用状态,但是当我想启用调试时,我会取消注释以下以 logging.basicConfig
行开头的行
import logging
if __name__ == "__main__":
# logging.basicConfig(level=logging.DEBUG)
main()
然后我运行脚本,它会在控制台上生成输出,显示 netmiko 模块与远程设备(在本例中为名为“sfo03-r1r10-sw2”的交换机)之间的整个 SSH 对话
DEBUG:netmiko:In disable_paging
DEBUG:netmiko:Command: terminal length 0
DEBUG:netmiko:write_channel: terminal length 0
DEBUG:netmiko:Pattern is: sfo03\-r1r10\-sw2
DEBUG:netmiko:_read_channel_expect read_data: terminal
↪length 0
DEBUG:netmiko:_read_channel_expect read_data: Pagination
disabled.
sfo03-r1r10-sw2#
DEBUG:netmiko:Pattern found: sfo03\-r1r10\-sw2 terminal
↪length 0
Pagination disabled.
sfo03-r1r10-sw2#
DEBUG:netmiko:terminal length 0
Pagination disabled.
sfo03-r1r10-sw2#
DEBUG:netmiko:Exiting disable_paging
在本例中,Netmiko 发送的 terminal length 0
命令成功。在以下示例中,发送以更改终端宽度的命令被交换机 CLI 拒绝,并显示“Authorization denied”消息
DEBUG:netmiko:Entering set_terminal_width
DEBUG:netmiko:write_channel: terminal width 511
DEBUG:netmiko:Pattern is: sfo03\-r1r10\-sw2
DEBUG:netmiko:_read_channel_expect read_data: terminal
↪width 511
DEBUG:netmiko:_read_channel_expect read_data: % Authorization
denied for command 'terminal width 511'
sfo03-r1r10-sw2#
DEBUG:netmiko:Pattern found: sfo3\-r1r10\-sw2 terminal
↪width 511
% Authorization denied for command 'terminal width 511'
sfo03-r1r10-sw2#
DEBUG:netmiko:terminal width 511
% Authorization denied for command 'terminal width 511'
sfo03-r1r10-sw2#
DEBUG:netmiko:Exiting set_terminal_width
日志记录还将详细显示整个 SSH 登录和身份验证序列。我不得不处理一台交换机,该交换机正在使用 SSH 客户端默认禁用的已弃用的 SSH 密码,导致 SSH 会话在尝试进行身份验证时失败。通过日志记录,我可以看到客户端拒绝了交换机提供的密码。我还发现了另一种类型的交换机,其中 Netmiko 连接似乎挂起。日志记录显示它卡在了 more?
提示符处,因为分页在登录后从未成功禁用。在这台特定的交换机上,禁用分页的命令必须在特权模式下运行。我的快速修复是在输入“enable”模式后添加 disable_paging()
函数。
现在您已经拥有了所有想要的数据,您可以开始处理它了。
一个非常简单的示例是“审计”类型的检查,该检查验证 DNS 中注册的主机名是否与设备中配置的主机名匹配。如果这些不匹配,则在登录到设备、关联 syslog 消息或查看 LLDP 和 CPD 输出时,将导致各种混乱。
import os
import sys
directory = "/root/login/scan"
for filename in os.listdir(directory):
prompt_file = directory + '/' + filename + '/prompt'
try:
prompt_fh = open(prompt_file,'rb')
except IOError:
"Can't open:", prompt_file
sys.exit()
with prompt_fh:
prompt = prompt_fh.read()
prompt = prompt.rstrip('#')
if (filename != prompt):
print 'switch DNS hostname %s != configured
↪hostname %s' %(filename, prompt)
此脚本打开扫描目录,打开每个“prompt”文件,通过剥离“#”字符来派生配置的主机名,将其与子目录文件名(根据 DNS,它是主机名)进行比较,并在它们不匹配时打印一条消息。在下面的示例中,脚本找到一个 DNS 交换机名称与交换机上配置的主机名不匹配的交换机
$ python name_check.py
switch DNS hostname sfo03-r1r12-sw2 != configured hostname
↪SFO03-R1R10-SW1-Cisco_Core
现实情况是,大多数复杂的网络都是由多人使用不同的命名约定、工作方式、技能组合等在多年内构建起来的。我已经积累了许多“审计”类型的检查,这些检查可以查找和纠正随着时间推移可能会蔓延到网络中的不一致之处。这是网络自动化的完美用例,因为您可以一次查看所有内容,而不是一次浏览每个设备。
性能在初始调试期间,我让“扫描”脚本以串行方式登录到每个交换机。这对于少量交换机来说效果很好,但是当我一次扫描数百个交换机时,性能就成了一个问题。我使用了 Python 多处理模块来启动一堆“工作进程”,这些工作进程并行地与交换机交互。这将扫描部分的处理时间缩短到几分钟,因为整个扫描所花费的时间与最慢的交换机完成扫描所花费的时间相同。交换机扫描问题非常适合多处理模型,因为各个工作进程之间没有事件或数据需要协调。Netmiko Tools 也利用多处理并使用缓存系统来提高性能。
未来方向到目前为止,我用 Netmiko 编写的最复杂的脚本是登录到每个交换机,收集 LLDP 邻居信息,并生成整个网络的纯文本拓扑图。对于那些不熟悉 LLDP 的人来说,这是链路层发现协议。大多数现代网络设备每 30 秒都会从每个端口发送 LLDP 组播。LLDP 数据包含许多详细信息,包括交换机主机名、端口名称、MAC 地址、设备型号、供应商、操作系统等等。它允许任何给定设备了解其所有直接邻居。
例如,这是交换机上典型的 LLDP 显示。 “邻居”列向您显示有关连接到每个本地端口的内容的详细信息
sfo03-r1r5-sw1# show lldp neighbors
Port Neighbor Device ID Neighbor Port ID TTL
Et1 sfo03-r1r3-sw1 Ethernet1 120
Et2 sfo03-r1r3-sw2 Te1/0/2 120
Et3 sfo03-r1r4-sw1 Te1/0/2 120
Et4 sfo03-r1r6-sw1 Ethernet1 120
Et5 sfo03-r1r6-sw2 Te1/0/2 120
通过询问所有网络设备其 LLDP 邻居列表,可以构建网络地图。我的方法是为顶层交换机构建本地交换机端口及其 LLDP 邻居的列表,然后递归地跟踪交换机层次结构中的每个交换机链路,并将每个条目添加到嵌套字典中。当存在冗余链路和要避免的无限循环时,此过程变得非常复杂,但我发现它是了解复杂 Python 数据结构的好方法。
以下输出来自我的“mapper”脚本。它使用缩进(从左到右)来显示交换机的层次结构,在本例中为三层深
sfo03-r1r5-core:Et6 sfo03-r1r8-sw1:Ethernet1
sfo03-r1r8-sw1:Et22 sfo03-r6r8-sw3:Ethernet48
sfo03-r1r8-sw1:Et24 sfo03-r6r8-sw2:Te1/0/1
sfo03-r1r8-sw1:Et25 sfo03-r3r7-sw2:Te1/0/1
sfo03-r1r8-sw1:Et26 sfo03-r3r7-sw1:24
它在交换机主机名旁边打印端口名称,这使您可以查看交换机间链路的“两侧”。当您尝试在网络上定位自己时,这非常有用。我仍在开发此脚本,但它当前生成可以转换为网络图的“实时”网络拓扑图。
我希望这些信息能激发您调查网络自动化。从 Netmiko Tools 和清单文件开始,了解可能实现的功能。您可能会遇到需要一些 Python 编码的场景,无论是使用 Netmiko Tools 的输出,还是您自己的独立脚本。无论哪种方式,Netmiko 功能都使自动化大型多供应商网络变得相当容易。