使用Nornir3自动化配置交换机

工作中因为交换机设备老旧,所以时常要更换一些交换机,包括接入层一些配置的调整。逐个配置太繁琐,有时候也会出现错误,因此决定用Nornir进行自动化推送保存配置。

准备工作

虽然说是自动化,但是还是需要一些配置是需要手工配置的:

  • 可管理的IP地址
  • 远程连接方式:SSH或者Telnet

编写配置文件

还是Nornir默认的几个配置文件,此处以H3C交换机为例。

  • config.yaml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    ---
    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: 100
  • defaults.yaml

    1
    2
    3
    4
    5
    ---
    username: root
    password: 'password'
    port: '22'
    platform: hp_comware
  • groups.yaml

    1
    2
    3
    4
    5
    6
    ---
    h3c:
    data:
    save_config_type: save
    backup_configs:
    - display current-configuration
  • hosts.yaml

    1
    2
    3
    4
    5
    ---
    sw1:
    hostname: 192.168.8.254
    groups:
    - h3c

交换机命令配置文件

我这里命名为config.txt,名称随意

  • config.txt

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    sysname test
    vlan 10
    vlan 20
    vlan 30
    inter range eth1/0/1 to eth1/0/8
    port link-type access
    port access vlan 10
    inter range eth1/0/9 to eth1/0/16
    port link-type access
    port access vlan 20
    inter range g1/0/17 to g1/0/23
    port link-type access
    port access vlan 30
    snmp-agent
    snmp-agent comm read simple public
    snmp-agent sys ver v2c

    config.txt里面为需要配置的命令。

推送交换机配置文件脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from nornir import InitNornir
from nornir.core.task import Result
from nornir_netmiko import netmiko_send_config,netmiko_save_config
from nornir_utils.plugins.functions import print_result,print_title


switch = InitNornir(config_file="config.yaml")

def push_and_save_configs(task):
save_type = task.host.groups[0].data.get("save_config_type","save")

config_push_result = task.run(netmiko_send_config,config_file="config.txt")
config_save_result = task.run(netmiko_save_config)

return Result(host=task.host,
result=[config_push_result.result,config_save_result.result],
changed=True
)
print_title("正在保存配置......")
results = switch.run(task=push_and_save_configs)
print_result(results)

脚本执行结果

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
"C:\Program Files\Python38\python.exe" E:/nonir_test/push_config.py
**** 正在保存配置...... **************************************************************
push_and_save_configs***********************************************************
* sw1 ** changed : True ********************************************************
vvvv push_and_save_configs ** changed : True vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
[ 'sysname test\n'
'[test]vlan 10\n'
'[test-vlan10]vlan 20\n'
'[test-vlan20]vlan 30\n'
'[test-vlan30]inter range eth1/0/1 to eth1/0/8\n'
'[test-if-range]port link-type access\n'
'[test-if-range]port access vlan 10\n'
'[test-if-range]inter range eth1/0/9 to eth1/0/16\n'
'[test-if-range]port link-type access\n'
'[test-if-range]port access vlan 20\n'
'[test-if-range]inter range g1/0/17 to g1/0/23\n'
'[test-if-range]port link-type access\n'
'[test-if-range]port access vlan 30\n'
'[test-if-range]snmp-agent\n'
'[test]snmp-agent comm read simple public\n'
'[test]snmp-agent sys ver v2c\n'
'[test]return\n'
'<test>',
'save force\n'
'Validating file. Please wait...\n'
'Saved the current configuration to mainboard device successfully.\n'
'[test]']
---- netmiko_send_config ** changed : True ------------------------------------- INFO
sysname test
[test]vlan 10
[test-vlan10]vlan 20
[test-vlan20]vlan 30
[test-vlan30]inter range eth1/0/1 to eth1/0/8
[test-if-range]port link-type access
[test-if-range]port access vlan 10
[test-if-range]inter range eth1/0/9 to eth1/0/16
[test-if-range]port link-type access
[test-if-range]port access vlan 20
[test-if-range]inter range g1/0/17 to g1/0/23
[test-if-range]port link-type access
[test-if-range]port access vlan 30
[test-if-range]snmp-agent
[test]snmp-agent comm read simple public
[test]snmp-agent sys ver v2c
[test]return
<test>
---- netmiko_save_config ** changed : True ------------------------------------- INFO
save force
Validating file. Please wait...
Saved the current configuration to mainboard device successfully.
[test]
^^^^ END push_and_save_configs ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

进程已结束,退出代码为 0

交换机执行完结果

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
[test]dis cu
#
version 7.1.070, Release 6318P01
#
sysname test
#
irf mac-address persistent timer
irf auto-update enable
undo irf link-delay
irf member 1 priority 1
#
lldp global enable
#
password-recovery enable
#
vlan 1
#
vlan 5
#
vlan 10
#
vlan 20
#
vlan 30
#
stp global enable
#
interface NULL0
#
interface Vlan-interface1
ip address dhcp-alloc
dhcp client identifier ascii 3cd2e58c491d-VLAN0001
#
interface Vlan-interface5
ip address 192.168.8.254 255.255.255.0
#
interface Ethernet1/0/1
port access vlan 10
#
interface Ethernet1/0/2
port access vlan 10
#
interface Ethernet1/0/3
port access vlan 10
#
interface Ethernet1/0/4
port access vlan 10
#
interface Ethernet1/0/5
port access vlan 10
#
interface Ethernet1/0/6
port access vlan 10
#
interface Ethernet1/0/7
port access vlan 10
#
interface Ethernet1/0/8
port access vlan 10
#
interface Ethernet1/0/9
port access vlan 20
#
interface Ethernet1/0/10
port access vlan 20
#
interface Ethernet1/0/11
port access vlan 20
#
interface Ethernet1/0/12
port access vlan 20
#
interface Ethernet1/0/13
port access vlan 20
#
interface Ethernet1/0/14
port access vlan 20
#
interface Ethernet1/0/15
port access vlan 20
#
interface Ethernet1/0/16
port access vlan 20
#
interface GigabitEthernet1/0/17
port access vlan 30
#
interface GigabitEthernet1/0/18
port access vlan 30
#
interface GigabitEthernet1/0/19
port access vlan 30
#
interface GigabitEthernet1/0/20
port access vlan 30
#
interface GigabitEthernet1/0/21
port access vlan 30
#
interface GigabitEthernet1/0/22
port access vlan 30
#
interface GigabitEthernet1/0/23
port access vlan 30
#
interface GigabitEthernet1/0/24
port access vlan 5
#
interface GigabitEthernet1/0/25
#
interface GigabitEthernet1/0/26
#
interface GigabitEthernet1/0/27
#
interface GigabitEthernet1/0/28
#
scheduler logfile size 16
#
line class aux
user-role network-admin
#
line class vty
user-role network-operator
#
line aux 0
user-role network-admin
#
line vty 0 4
authentication-mode scheme
user-role network-operator
protocol inbound ssh
#
line vty 5 63
user-role network-operator
#
ip route-static 0.0.0.0 0 192.168.8.1
#
snmp-agent
snmp-agent local-engineid 800063A2803CD2E58C492800000001
snmp-agent community read cipher $c$3$Rqh8sSNIfbVRstiA6l4bwgxjO9Kv7Y/bZt8=
snmp-agent sys-info version v2c v3
#

使用Filter进行过滤

有些因为版本问题,交换机执行命令可能有所差异,那么就需要用到Filter进行过滤,分别执行:

示例脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from nornir import InitNornir
from nornir.core.task import Result
from nornir_netmiko import netmiko_send_config,netmiko_save_config
from nornir_utils.plugins.functions import print_result,print_title
from nornir.core.filter import F


old_devs = InitNornir(config_file="config.yaml")
group1 = old_devs.filter(F(groups__contains="h3c_old"))
def push_and_save_configs(task):
save_type = task.host.groups[0].data.get("save_config_type","save")

config_push_result = task.run(netmiko_send_config,config_file="config.txt")
config_save_result = task.run(netmiko_save_config)

return Result(host=task.host,
result=[config_push_result.result,config_save_result.result],
changed=True
)
print_title("正在保存配置......")
results = group1.run(task=push_and_save_configs)
print_result(results)

对应的hosts文件和groups也需要做出调整,下面是hosts.yaml和groups.yaml示例文件。

  • hosts.yaml
1
2
3
4
5
6
7
8
9
---
sw1:
hostname: 192.168.8.254
groups:
- h3c
sw2:
hostname: 192.168.2.129
groups:
- h3c_old
  • groups.yaml
1
2
3
4
5
6
7
8
9
10
11
12
---
h3c:
data:
save_config_type: save
backup_configs:
- display current-configuration
h3c_old:
data:
save_config_type: save
backup_configs:
- display current-configuration

此脚本目前已经测试过华为与华三交换机,都正常可以使用。