本文基于nornir3.1.1进行代码测试和执行。
其实和nornir官方文档没什么大差别,写出来方便自己查阅和使用。
nornir,100%基于python3构成的自动化框架,易于NetDevOps进行二次开发和脚本编写,操作容易。
相比于ansible,操作更为简单容易,且只需使用python3即可完成配置和脚本编写。
加上支持使用netmiko,使得一些较为冷门的交换机如ruijie、h3c等无需二次开发插件即可进行脚本编写。
目前版本为3.1.1,与之前的版本差异较大,看同类文章时需注意版本。
安装
nornir本体和常用的插件。
1
| pip install nornir nornir_utils nornir_netmiko
|
使用
文件类型
nornir分为三类文件:
- 配置文件yaml
- 机器管理文件yaml
- 用户脚本py
配置文件
首先看配置文件yaml,一般使用config.yaml
,可自定义命名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| ---
inventory: plugin: SimpleInventory options: host_file: "inventory/hosts.yaml" group_file: "inventory/groups.yaml" defaults_file: "inventory/defaults.yaml"
runner: plugin: threaded options: num_workers: 64
|
也可以直接在python文件中使用变量指定。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| from nornir import InitNornir nr = InitNornir( runner={ "plugin": "threaded", "options": { "num_workers": 100, }, }, inventory={ "plugin": "SimpleInventory", "options": { "host_file": "inventory/hosts.yaml", "group_file": "inventory/groups.yaml" }, }, )
|
或两类混用指定配置。
1 2 3 4 5 6 7 8 9 10
| from nornir import InitNornir nr = InitNornir( config_file="config.yaml", runner={ "plugin": "threaded", "options": { "num_workers": 50, }, }, )
|
接着可以使用python文件进行测试,无异常则配置测试通过。
1 2
| from nornir import InitNornir nr = InitNornir(config_file="config.yaml")
|
机器管理文件
目前来看,例如host_file
不支持使用多个文件,无法像ansible使用多个文件进行分类管理。
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
| ---
cisco_3850: hostname: 192.168.1.1 port: 22 username: cisco password: cisco_password platform: cisco_ios groups: - access_switch data: role: access_switch
cisco_3548: hostname: 192.168.1.0 port: 22 username: cisco password: cisco_password platform: cisco_nxos groups: - core_switch data: role: core_switch
server_1: hostname: 192.168.1.2 username: root password: root_password
|
下面为nornir默认的key/value参数
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
| { "name": "str", "connection_options": { "$connection_type": { "extras": { "$key": "$value" }, "hostname": "str", "port": "int", "username": "str", "password": "str", "platform": "str" } }, "groups": [ "$group_name" ], "data": { "$key": "$value" }, "hostname": "str", "port": "int", "username": "str", "password": "str", "platform": "str" }
|
分组信息文件示例如下。
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
| --- access_switch: groups: - switch data: os_type: ios
core_switch: data: os_type: nxos groups: - switch
switch: data: type: switch test: test_dict: a: 1 b: 2 c: abcdef
linux: data: type: server
|
默认配置文件示例如下
1 2 3 4 5
| --- platform: linux groups: - linux
|
用户脚本
接下来使用脚本来查看配置文件内的机器参数。
1 2 3 4 5 6 7
| from nornir import InitNornir nr = InitNornir(config_file="config.yaml")
print(nr.inventory.hosts) print(nr.inventory.groups) print(nr.inventory.hosts['server_1'].keys()) print(nr.inventory.hosts['cisco_3850'].keys())
|
1 2 3 4
| {'cisco_3850': Host: cisco_3850, 'cisco_3548': Host: cisco_3548, 'server_1': Host: server_1} {'access_switch': Group: access_switch, 'core_switch': Group: core_switch, 'switch': Group: switch, 'linux': Group: linux} dict_keys([]) dict_keys(['role', 'os_type', 'type', 'test'])
|
输出1可以看到所有机器名称和它的hostname。
输出2可以看到所有组。
输出3可以看到server_1
的data
所有key。
输出4可以看到cisco_3850
的data
所有key。
并且这些输出都是用标准的python数据格式,字典输出而成,无需经过二次处理即可使用。这里面玩法有多少想必大家都很清楚了。
过滤器
filter
没错,对于inventory,nornir自带了一个过滤器,可以用来区分设备。
1
| print(nr.filter(os_type="nxos").inventory.hosts.keys())
|
1
| dict_keys(['cisco_3548'])
|
filter还可以循环使用,多个kv使用。
1 2
| print(nr.filter(os_type="nxos").filter(role="core_switch").inventory.hosts.keys()) print(nr.filter(os_type="nxos", role="core_switch").inventory.hosts.keys())
|
也可以作为变量,中转使用。
1 2
| filter_device=nr.filter(os_type="nxos") print(filter_device.filter(role="core_switch"))
|
甚至可以塞函数进去。
1 2 3 4
| def has_long_name(host): return len(host.name) == 11
nr.filter(filter_func=has_long_name).inventory.hosts.keys()
|
children_of_group
filter主要使用data里面的key-value进行过滤,如果根据组别拉出来则使用。
1
| print(nr.inventory.children_of_group("access_switch"))
|
F
nornir提供了过滤器对象F,可以使用它进行更加复杂的组合判断。__contains
可以判断是否符合指定字符串。
1 2 3 4 5 6 7 8 9
| from nornir.core.filter import F device = nr.filter(F(groups__contains="access_switch")) print(device.inventory.hosts.keys()) device = nr.filter(F(groups__contains="access_switch") | F(platform="linux")) print(device.inventory.hosts.keys()) device = nr.filter(F(groups__contains="access_switch") & F(platform="linux")) print(device.inventory.hosts.keys()) device = nr.filter(~F(platform="linux")) print(device.inventory.hosts.keys())
|
1 2 3 4
| dict_keys(['cisco_3850']) dict_keys(['cisco_3548', 'server_1']) dict_keys([]) dict_keys(['cisco_3850', 'cisco_3548'])
|
F甚至可以使用__
进行data内的字段直接访问,这时候加上__contains
可以判断是否为子字符串。
1 2
| device = nr.filter(F(test__test_dict__c__contains="def")) print(device.inventory.hosts.keys())
|
1
| dict_keys(['cisco_3850', 'cisco_3548'])
|