网络工程师的Python之路——Nornir3.0.0
版权声明:我已加入“维权骑士”的版权保护计划,知乎专栏“网路行者”下的所有文章均为我本人(知乎ID:弈心)原创,未经允许不得转载。
如果你喜欢我的文章,请关注我的知乎专栏“网路行者”,里面有更多像本文一样深度讲解计算机网络技术的优质文章。
2018年我写了《弈心:网络工程师的Python之路---Ansible篇》一文,以实验的方式手把手向大家教授了Ansible的使用方法,受到了热捧。本来我是想为Ansible单独出一本书的,但是没曾想就在2018年同年,对标Ansible的Nornir横空出世,并在计算机网络运维这个圈子里迅速抢占Ansible的地盘,短短不到三年的时间里Nornir已经从1.0版迅速更迭到了2020年9月16日发布的3.0.0版。Nornir发展如此迅猛主要有如下几个原因:
- 阵容强大: Nornir的作者是Napalm的作者David Barroso(github账号:dbarrosop)和netmiko的作者Kirk Byers,两位联手搞出了Nornir初代的框架,因为Nornir对比Ansible确实强大,后来有很多业界大佬比如思科的Dmitry Figol在2019年于巴塞罗那举办的Cisco Live上为Nornir站台力推Nornir,让更多业界开发者加入到了Nornir的开发之中,所以Nornir能迅速成1.0升级到今天的3.0版本。
- 下面两张图是NetDevOps界知名人物瑞典人Patrick Ogenstad放出的Nornir和Ansible的性能对比,可以看到在设备数量多于1000台的大型网络里,Nornir的效率完全是秒杀和吊打Ansible的存在(虽然两者都支持多线程并发,但是处理1万台设备,Ansible需要2300秒,Nornir只需要17秒,处理5000台设备Ansible需要900秒,Nornir只需要9秒,差距之大让你怀疑这俩根本不是一个量级的产品。)
3. 除了性能上的差距外,目前业界普遍公认的Nornir对比Ansible的优势还有如下几点:
a. Ansible完全基于YAML,和其他编程语言相比缺乏IDE,Linting、静态类型检查等工具的支持,虽然Nornir也要用到YAML,但是它的runbook是用Python写的,有了Python的助力我们可以通过Nornir做很多很多事情。
b. Ansible的剧本(Playbook)排错、debug、维护难度相当大,而基于Python的Nornir在这方面做的比Ansible好得多(虽然Nornir1.0到2.0, 2.0到3.0的跨度也比较大,但是总体排错难度比Ansilbe简单的多)。
c. Ansible完全基于YAML,让你根本体会不到编程的乐趣,就算你把Ansible用得贼溜,你的Python水平还在原地踏步甚至完全荒废,而使用Nornir的用户则不会有这种顾虑。
关于Nornir和Ansible的对比就介绍到这里,从目前的发展趋势以及我本人的使用体验来看,Nornir和Ansible并驾齐驱甚至超过Ansible我估计是早晚的事。对NetDevOps网工们来说,Nornir是你必须点亮的一个技能树,尤其是在设备数量众多的大型网络里,现在上车还来得及。
废话少说,下面正式进入正题。
开篇前的话
本文将提供7个Nornir的实验手把手地向大家讲解Nornir的入门知识,保证大家在读完本文并动手做完7个实验后能掌握Nornir的基本用法,兼顾到平时网络运维工作中一些比较常见的任务:比如读取设备信息,配置设备,保存设备配置等等。读过我专栏文章的朋友都清楚我是实战派的,不喜欢写太多理论,所有理论我都会放在实验中边做实验边讲。因为我始终坚信:花N个小时写上几千字让人看得昏昏欲睡的理论当不上花个十几分钟实际动手向他人演示一遍,
实验平台
看到下面这张图,经常读我书和专栏文章以及看我教学视频的朋友们应该都秒懂了,还是老规矩:一台CentOS 8主机(192.168.2.1)上跑Nornir,下面连上5台试验用的虚拟三层思科交换机IP从192.168.2.11到192.168.2.15。
Nornir3.0.0实验准备
Nornir3.0.0发布于2020年9月16日,它相比2.X时代(Nornir2最后一个版本为2.5)最大的区别是将所有插件分拆了出去,这也就意味着你在2.X时代光靠pip3 install nornir来安装一个nornir模块的做法已经行不通了。实验开始前请务必按照下面的方法通过pip安装好所有我们实验需要用到的Python模块以及Nornir插件(第一次接触Nornir的朋友我强烈建议在虚拟环境venv中来完成本文的所有实验):
pip3 install netmiko
pip3 install napalm
pip3 install nornir
pip3 install nornir_utils
pip3 install nornir_napalm
pip3 install nornir_netmiko
安装好上面的模块和插件后,请务必用pip freeze | grep nornir来确认你安装的是3.0.0版的Nornir,否则本文后面所有的内容都是鸡同鸭讲。
确认Nornir版本为3.0.0后,首先我们创建一个YAML文件,叫做config.yaml, 其内容如下:
---
inventory:
plugin: SimpleInventory
options:
host_file: "hosts.yaml"
group_file: "groups.yaml"
defaults_file: "defaults.yaml"
runner:
plugin: threaded
options:
num_workers: 100
Config.yaml是Nornir最基本的配置文件,其中包含了Nornir自带的Inventory插件SimpleInventory用来管理设备,下面的options里可以看到,我们等下还需要另外创建三个YAML文件:hosts.yaml,groups.yaml以及defautls.yaml用来分别存放设备(hosts)信息,分组(groups)信息,以及缺省(defaults)信息。
下面runner下的threaded插件表示我们将使用多线程来让Nornir执行任务,num_workers: 100表示我们最多启用100个线程(默认为20个)。关于多线程的内容我在《弈心:网络工程师的Python之路 -- Concurrent.Futures》和《弈心:网络工程师的Python之路 -- 多线程(Multithreading)》已经详细介绍过了,不了解的朋友可以去读一读。
接下来创建defaults.yaml,groups.yaml以及hosts.yaml三个文件,内容如下:
defaults.yaml
---
username: python
password: '123'
defaults.yaml的作用是用来填补hosts.yaml里遗漏的参数(等下讲hosts.yaml时会讲到它的作用),这里我们在defaults.yaml中定义了用来供Nornir通过SSH登录实验中要用到的5台交换机的用户名和密码。
注意:如果密码里含有数字,则必须加引号,比如password: '123',如果不含数字或者是字母+数字(字母开头或者数字开头都无所谓)的组合,则无须加引号,比如密码是python的话,可以写成password: python,密码是python123或者123python的话可以写成password: python123和password: 123python均没问题。
groups.yaml
---
cisco:
platform: ios
我们可以将Nornir要登录管理的设备(hosts)按厂商划为不同的分组,因为GNS3模拟器所使用的是虚拟的思科交换机,所以这里我们在groups.yaml里创建了一个叫做cisco的分组(组名可以自定义,一般取直观容易理解的组名)。另外Nornir是基于napalm来登录设备的,其对应的就是napalm里面的Driver Name,也就是下图里的ios:
hosts.yaml
---
sw1:
hostname: 192.168.2.11
username: python
password: '123'
groups:
- cisco
sw2:
hostname: 192.168.2.12
groups:
- cisco
hosts.yaml用来存放具体所要登录的设备的信息,比如hostname(也就是IP地址), username,password,以及该设备所属的设备组。这里可以看到,我们给sw1设置了username和password,但是对sw2却故意漏过了。这里不用担心,前面在讲defaults.yaml的时候提到了defaults.yaml的作用是就用来填补hosts.yaml里遗漏的参数,也就是说在运行nornir脚本时,nornir在登录sw2时发现hosts.yaml里遗漏了sw2的username和password,那么它会直接去看defaults.yaml是否有对应的参数并使用。
从这里我们可以看出defaults.yaml很好用。举个例子,假设我们要登录10台交换机,其中8台的用户名和密码都一样,只有剩下两台不一样,那么我们可以把8台交换机共同的用户名和密码写入defaults.yaml里面,然后在hosts.yaml里写入这8台交换机时故意漏掉它们的username和password(让nornir从defaults.yaml里去找),只针对剩下的两台交换机添加上它们的username和password即可。
注:在只有单一类型设备的情况下,groups.yaml是可以省去的,比如说实验里只用上了思科的ios设备,那么我们可以将groups.yaml给删除掉,将hosts.yaml的内容改为下面这样既可(这个技巧了解即可,实验中我们还是要用到groups.yaml的):
---
sw1:
hostname: 192.168.2.11
username: python
password: '123'
platform: ios
sw2:
hostname: 192.168.2.12
platform: ios
最后再检查一遍,看是否config.yaml, defaults.yaml, groups.yaml, hosts.yaml四个YAML文件都已准备就绪。
一切准备妥当后,下面正式进入实验环节。
实验1: 调用nornir_napalm来获取设备的facts和interfaces信息
创建一个名为nornir1.py的Python脚本,然后写入如下代码:
from nornir import InitNornir
from nornir_napalm.plugins.tasks import napalm_get
from nornir_utils.plugins.functions import print_result
nr = InitNornir(config_file="config.yaml", dry_run=True)
results = nr.run(task=napalm_get, getters=["facts", "interfaces"])
print_result(results)
实验1代码讲解:
这里我们从nornir中导入InitNornir子类,InitNornir的作用是用来初始化nornir,是nornir下面最重要的一个子类。
from nornir import InitNornir
另外我们还从
nornir_napalm.plugins.tasks中调用了napalm_get,napalm_get这个子类允许我们调用napalm的getter类的API来获取设备的信息(有关napalm的getter类API的内容在我书里以及视频里已经详细介绍过)。
from nornir_napalm.plugins.tasks import napalm_get
最后我们调用
nornir_utils.plugins.functions中的print_result来将我们通过nornir_napalm的getter类API得到的设备信息打印出来。
from nornir_utils.plugins.functions import print_result
使用InitNornir()函数来初始化设备并将它赋值给变量nr。InitNonir()函数中需要放入config_file这个参数,针对这个参数这里我们使用的是前面提到的config.yaml这个文件, 后面的dry_run参数在调用nornir_napalm时必须设为True。
nr = InitNornir(config_file="config.yaml", dry_run=True)
然后我们调用nr.run()函数来正式使用napalm下的两个getter类API,"facts"和"interfaces"分别对应的是get_facts和get_interfaces两个getter类API:
results = nr.run(task=napalm_get, getters=["facts", "interfaces"])
最后用print_result()将结果打印出来(注意这里nr.run()返回的值的类型为
nornir.core.task.AggregatedResult,必须用nornir.utils里的print_result()才能将它完整打印出来,我们常用的print()对它是无效的):
results = nr.run(task=napalm_get, getters=["facts", "interfaces"])
运行脚本看效果:
实验2: 调用nornir_netmiko来获取设备信息
除nornir_napalm外,我们还可以用nornir_netmiko来向设备输入各种show命令以获取设备信息,这里我们创建第二个实验脚本nornir2.py并放入下面代码:
from nornir import InitNornir
from nornir_netmiko import netmiko_send_command
from nornir_utils.plugins.functions import print_result
nr = InitNornir(config_file="config.yaml")
results = nr.run(netmiko_send_command, command_string='sh clock')
print_result(results)
实验2代码讲解:
实验2的代码也很简单,这里我们用netmiko的send_command函数向SW1和SW2执行show clock命令,
results = nr.run(netmiko_send_command, command_string='sh clock')
运行脚本看效果:
运行代码过后可以看到两台交换机当前的时间,这里注意: SW1和SW2当前时间只间隔了0.143秒 (10:15:19.475 - 10:15:19.618),说明Nornir是并发进行的(如果想进一步验证,还可以在hosts里面加上剩下的SW3, SW4, SW5甚至更多的交换机来一起show clock)。
另外除了netmiko_send_command外,我们还可以在nornir里面使用netmiko_send_config, netmiko_file_transfer, netmiko_save_config等函数,经常用netmiko的读者朋友对它们应该不会感到陌生。
实验3: 使用filter()配合F()来做高级过滤
在Nornir中,可以使用filter()以及在filter()里配合F()函数来做过滤,前者叫做简单过滤(simple filtering),后者叫做高级过滤(advanced filtering)。针对过滤的内容我将分成三个实验来讲,实验3中我将介绍filter配合F()函数做过滤的方法,实验4中我将介绍使用filter()过滤的方法,实验5中我将介绍filter()配合lambda来做过滤的方法。先讲advanced filtering后讲simple filtering的原因是后者设计到一些扩展内容,需要放在后面来讲。
开始实验3前,首先修改groups.yaml和hosts.yaml两个文件。
在groups.yaml里面将之前的cisco这个group拿掉,然后重新划分好两个group,分别取名为cisco_group1和cisco_group2:
---
cisco_group1:
platform: ios
cisco_group2:
platform: ios
在hosts.yaml里添加sw3和sw4,将之前的sw1和sw2划入cisco_group1,将sw3和sw4划入cisco_group2。
---
sw1:
hostname: 192.168.2.11
username: python
password: '123'
platform: ios
groups:
- cisco_group1
sw2:
hostname: 192.168.2.12
platform: ios
groups:
- cisco_group1
sw3:
hostname: 192.168.2.13
platform: ios
groups:
- cisco_group2
sw4:
hostname: 192.168.2.14
platform: ios
groups:
- cisco_group2
然后创建第三个实验脚本nornir3.py,脚本代码内容如下:
from nornir import InitNornir
from nornir_netmiko import netmiko_send_command
from nornir_utils.plugins.functions import print_result
from nornir.core.filter import F
nr = InitNornir(config_file="config.yaml")
group1 = nr.filter(F(groups__contains="cisco_group1"))
group2 = nr.filter(~F(groups__contains="cisco_group1"))
results = group1.run(netmiko_send_command, command_string='sh ip int brief')
print_result(results)
实验3代码讲解:
在Nornir中我们可以使用nornir.core.filter下面的F()函数来做过滤:
from nornir.core.filter import F
Nornir的过滤中支持取非操作,首先我们调用nr.filter(F(groups__contains="cisco_group1")来过滤cisco_group1下的SW1和SW2,将其赋值给变量group1,这里注意F()函数里面的groups__contains参数,中间的那个__是双下划线不是单下划线。
group1 = nr.filter(F(groups__contains="cisco_group1"))
然后在F的前面加上一个波浪号~对其进行取非来过滤cisco_group2下的SW3和SW4,并将结果赋值给变量group2(因为我们这里总共只有cisco_group1和cisco_group2两个group,因此对cisco_group1取非后过滤出的就是cisco_group2)
group2 = nr.filter(~F(groups__contains="cisco_group1"))
这里我们首先打印出group1的内容,可以看到它只返回了SW1和SW2的show ip int brief的回显内容。
results = group1.run(netmiko_send_command, command_string='sh ip int brief')
print_result(results)
然后在脚本里将results = group1.run(netmiko_send_command, command_string='sh ip int brief')改为results = group2.run(netmiko_send_command, command_string='sh ip int brief'),然后再次执行脚本,打印出group2也就是SW3和SW4的show ip int brief的回显内容:
这时你肯定会问:怎么取消过滤,一次性将4台交换机的show ip int brief全部打印出来呢?答案很简单,只需要将group1.run()或group2.run()替换成nr.run()就行了:
results = nr.run(netmiko_send_command, command_string='sh ip int brief')
print_result(results)
运行脚本看效果:
实验4: 使用filter()来做简单过滤
实验4是本文的重点内容,涉及的知识点会较多。
inventory.hosts和inventory.groups
开始实验4讲filter()函数之前,先来讲下inventory.hosts和inventory.groups。首先来回顾一下目前为止我们hosts.yaml和groups.yaml文件中的内容:
hosts.yaml
groups.yaml
开篇时讲到了,Inventory是Nornir中最重要的组成部分, 它包含了inventory.hosts以及inventory.groups,分别对应了我们前面讲到的hosts.yaml以及groups.yaml两个文件,在Nornir中我们可以通过调用nr.inventory.hosts和nr.inventory.groups来查看我们的inventory中有哪些hosts以及groups,下面我将用解释器来做演示:
>>> from nornir import InitNornir
>>> nr = InitNornir(config_file='config.yaml')
>>> nr.inventory.hosts
{'sw1': Host: sw1, 'sw2': Host: sw2, 'sw3': Host: sw3, 'sw4': Host: sw4}
>>> nr.inventory.groups
{'cisco_group1': Group: cisco_group1, 'cisco_group2': Group: cisco_group2}
>>>
在此基础上,我们还可以继续指定交换机名称,并获取它的某一参数:
>>> nr.inventory.hosts['sw1'].platform
'ios'
>>> nr.inventory.hosts['sw1'].username
'python'
>>> nr.inventory.hosts['sw1'].password
'123'
>>> nr.inventory.hosts['sw2'].hostname
'192.168.2.12'
>>> nr.inventory.hosts['sw3'].hostname
'192.168.2.13'
>>> nr.inventory.hosts['sw4'].hostname
'192.168.2.14'
>>>
同样的道理,针对groups也可以做同样的操作:
>>> nr.inventory.groups['cisco_group1'].platform
'ios'
>>> nr.inventory.groups['cisco_group2'].platform
'ios'
>>>
这里可以看到,只要你在hosts.yaml和groups.yaml中放的键值对越多(也就是信息越多),那么能够你筛选的参数也就越多。
讲完inventory.hosts和inventory.groups后,来看下实验4的内容,首先将hosts.yaml文件里的内容修改如下:
---
sw1:
hostname: 192.168.2.11
username: python
password: '123'
platform: ios
groups:
- cisco_group1
data:
building: '1'
level: '1'
sw2:
hostname: 192.168.2.12
platform: ios
groups:
- cisco_group1
data:
building: '1'
level: '2'
sw3:
hostname: 192.168.2.13
platform: ios
groups:
- cisco_group2
data:
builiding: '2'
level: '1'
sw4:
hostname: 192.168.2.14
platform: ios
groups:
- cisco_group2
data:
building: '2'
level: '2'
这里我们为每台交换机添加了额外的信息(data),标注了它们所在的位置。比如SW1在building 1 level 1,SW2在building 1 level 2等等,和前面提到的密码一样,如果value中只使用数字,那么必须对其加上引号才行,所以这里写成building: '1', level: '1',如果value中有字母,或者字母数字混用,则不用加引号,比如building: A, building: A1, building: 1A等等。
注意:data下面的键值对起的是备注的作用,键名(key)可以任意命名,不一定必须是building, level,你也可以使用其他的一些键名比如country, region, ntp, dhcp等等,你就算使用abc, xyz做键名也是可以的,并不影响我们后面的过滤,只是用这些键名没有意义罢了。
接下来创建第四个实验脚本nornir4.py,脚本代码内容如下:
from nornir import InitNornir
from nornir_netmiko import netmiko_send_command
from nornir_utils.plugins.functions import print_result
nr = InitNornir(config_file="config.yaml")
targets = nr.filter(building='1')
results = targets.run(netmiko_send_command, command_string='sh ip arp ')
print_result(results)
实验4代码讲解:
filter()的用法比F()更简单,它其中的参数即为我们hosts.yaml里面data下面的键名,这里我们过滤出4个交换机里面位置在Building 1里的交换机,也就是SW1和SW2,然后打印出它们输入show ip arp命令后的回显内容。
targets = nr.filter(building='1')
运行脚本看效果:
这里你也可以用level来过滤,写成targets = nr.filter(level='1')或者targets = nr.filter(level='2'),这个就留给大家自行去尝试。
实验5: 在filter()中使用lambda来过滤单个或多个设备
在filter()中我们还可以使用参数filter_func然后配合lambda来做过滤,可以过滤单个设备,也可以过滤多个设备,首先来看如何使用lambda来过滤单个设备。
在filter()中使用lambda来过滤单个设备
首先创建实验5的脚本nornir5.py,然后放入下列代码:
from nornir import InitNornir
from nornir_netmiko import netmiko_send_command
from nornir_utils.plugins.functions import print_result
nr = InitNornir(config_file="config.yaml")
sw4 = nr.filter(filter_func=lambda host: host.name== 'sw4')
results = sw4.run(netmiko_send_command, command_string='sh ip arp')
print_result(results)
实验5代码(一)讲解:
这里我们调用filter()里的filter_func参数,将lambda host: host.name=='sw4'赋值给它,即可过滤出sw4这台交换机(注意,host.name对应的sw4是我们在hosts.yaml文件中给192.168.2.14这台交换机取的名称,这个host.name对应的设备名称只在本地有效,和交换机真实的hostname没有任何关系,如果你在hosts.yaml中给这台交换机取名为abc,那么这里lambda后面就要写成lambda host: host.name=='abc')
sw4 = nr.filter(filter_func=lambda host: host.name== 'sw4')
运行脚本看效果:
如果在生产网络环境下你记不住设备在host.yaml中对应的设备名称,但是你知道该设备的IP地址,那么在这里你也可以用sw4 = nr.filter(filter_func=lambda host: host.hostname=='192.168.2.14'),以IP地址来过滤该设备,这里就不演示了。
在filter()中使用lambda来过滤多个设备
除了过滤单个设备外,在filter()中还可以用lambda配合列表来过滤多个设备,将nornir5.py的代码稍作修改如下:
from nornir import InitNornir
from nornir_netmiko import netmiko_send_command
from nornir_utils.plugins.functions import print_result
nr = InitNornir(config_file="config.yaml")
#sw4 = nr.filter(filter_func=lambda host: host.name== 'sw4')
switches = ['sw1','sw2','sw3']
sw1_sw2_sw3 = nr.filter(filter_func=lambda host: host.name in switches)
results = sw1_sw2_sw3.run(netmiko_send_command, command_string='sh ip arp')
print_result(results)
实验5代码(二)讲解:
这里我们首先使用switches = ['sw1', 'sw2', 'sw3']来创建一个列表,该列表的元素为sw1,sw2,sw3这三个等下将被我们用lambda过滤的设备名称。
switches = ['sw1','sw2','sw3']
然后我们将之前的sw4 = nr.filter(filter_func=lambda host: host.name== 'sw4')稍作替代,将host.name=='sw4'这部分改为host.name in switches即可,它表示遍历列表switches里的所有元素,也就帮我们过滤出了sw1, sw2, sw3三台交换机。
sw1_sw2_sw3 = nr.filter(filter_func=lambda host: host.name in switches)
运行脚本看效果:
同样的原理,如果你想使用IP地址来过滤,只需要将代码稍作修改如下即可:
switches = ['192.168.2.11', '192.168.2.12', '192.168.2.13']
sw1_sw2_sw3 = nr.filter(filter_func=lambda host: host.hostname in switches)
验证部分省略,留给大家自行尝试。
实验6: 用Nornir给设备做配置
也许你已经猜到了,既然nornir和netmiko有联系,那我们可以用nornir_netmiko下的netmiko_send_config给网络设备做配置。首先我们创建一个commands.cfg文件用来存放需要配置的命令,这里我们给4台交换机配置一个VLAN999,并取名为nornir_vlan:
然后创建脚本nornir6.py,写入下列代码:
from nornir import InitNornir
from nornir_netmiko import netmiko_send_command, netmiko_send_config
from nornir_utils.plugins.functions import print_result, print_title
nr = InitNornir(config_file="config.yaml")
def config(cisco):
cisco.run(task=netmiko_send_config, config_file='commands.cfg')
cisco.run(task=netmiko_send_command, command_string='show vlan brief')
print_title('正在配置VLAN999')
results = nr.run(task=config)
print_result(results)
实验6代码讲解:
除了netmiko_send_command外,现在我们也从nornir_netmiko中另外导入了netmiko_send_config用来给交换机配置VLAN999。
from nornir_netmiko import netmiko_send_command, netmiko_send_config
这里除了print_result外,我们还从
nornir_utils.plugins.functions中导入了print_title,它的作用顾名思义是在Nornir返回的结果中打印标题,提示我们这个Nornir脚本在做什么。
from nornir_utils.plugins.functions import print_result, print_title
定义一个函数config(cisco)用来给给4台交换机做配置, 这里注意参数名为自定义,这里我用的是cisco。另外在run()函数里使用netmiko_send_config时,需要配置参数config_file来调用实验开始前我们准备的commands.cfg这个配置命令文件,配置完成过后,我们继续使用netmiko_send_command来输入命令show vlan brief以验证VLAN999是否配置成功。
def config(cisco):
cisco.run(task=netmiko_send_config, config_file='commands.cfg')
cisco.run(task=netmiko_send_command, command_string='show vlan brief')
用print_title()打印出标题,最后使用nr.run()来运行函数config()
print_title('正在配置VLAN999')
results = nr.run(task=config)
运行脚本看效果(注意看“正在配置VLAN999"这个标题的位置):
实验7: 用Nornir保存设备配置
在Nornir中给设备保存配置的思路很简单,首先用nornir_naplam中的get-config这个getter类API获取设备的show run,然后从
nornir_utils.plugins.taks.files中调取write_file插件,该插件支持创建文本文件来保存我们的设备的配置
首先创建脚本nornir7.py,将下列代码写入该脚本:
from nornir import InitNornir
from nornir_napalm.plugins.tasks import napalm_get
from nornir_utils.plugins.functions import print_result
from nornir_utils.plugins.tasks.files import write_file
from datetime import date
def backup_configurations(task):
r = task.run(task=napalm_get, getters=["config"])
task.run(task=write_file, content=r.result["config"]["running"], filename=str(task.host.name) + "-" + str(date.today()) + ".txt")
nr = InitNornir(config_file="config.yaml")
result = nr.run(name="正在备份交换机配置", task=backup_configurations)
print_result(result)
实验7代码讲解:
这里我们从
nornir_utils.plugins.tasks.files里调用write_file,等下用作保存文本文件
from nornir_utils.plugins.tasks.files import write_file
创建一个函数backup_configuration(task),在该函数中我们使用napalm中的get-config这个getter类API来获取设备的show run配置,然后调用write_file来将show_run内容写进文本文件,该文本文件名称的格式为swx-yyyy-mm-dd.txt
def backup_configurations(task):
r = task.run(task=napalm_get, getters=["config"])
task.run(task=write_file, content=r.result["config"]["running"], filename=str(task.host.name) + "-" + str(date.today()) + ".txt")
除了实验6中提到的print_title()外,我们还可以在nr.run()里面加入参数name来给nornir的输出内容加上标题和脚注。
result = nr.run(name="正在备份交换机配置", task=backup_configurations)
运行脚本看效果:
脚本跑完过后可以看到当前目录下多出了4台交换机的配置文件: