在平时的网络运维工作中,网工少不了要给新设备做批量配置。其中一些配置比如line vty下的transport input ssh以及AAA、SNMP之类的属于共有配置,所有此类命令在所有设备上是统一没有差异的,写一个Python脚本用Paramiko、Netmiko或者pexpect等SSH模块就能轻松搞定。但是针对那些有差异化的配置,比如每个端口下的description(比如用来描述每个端口下面所连接的服务器的名称,服务器的物理端口(网卡)号,以及服务器的用途等等),每个端口的功能(access port还是trunk port?如果是access port,access哪个VLAN?因为存在差异,你不能简单的用一个interface range来一次性统一完成所有端口的配置)以及在不同交换机上划分和创建不同的VLAN id等等,光靠上述SSH模块是很难搞定的,就算能搞定,写出来的脚本的代码量也是相当庞大,不便于维护的。这时就有必要用到Jinja2这个模板引擎来帮助我们完成这些量大又有差异化的配置。

本文将以一台华为思科设备为例,讲解如何使用Jinja2来完成对该交换机多个端口的配置

华为篇:

ensp拓扑:

网工Python之路 -- CSV和Jinja2批量配置交换机(量大又有差异化的配置)_第1张图片

switch ports2.csv文件内容如下:

网工Python之路 -- CSV和Jinja2批量配置交换机(量大又有差异化的配置)_第2张图片


interface-template2.j2文件内容如下:

interface {{ interface  }}
  description Link to {{ server }} port {{ port }} for {{ purpose }}
  {% if vlan == "Trunk" -%}
  port link-type trunk
  {% else -%}
  port link-type access
  port default vlan  {{ vlan }}
  {% endif -%}
  undo shutdown


jinja2_peizhiSW.py文件内容如下:

from jinja2 import Template
import csv
from netmiko import ConnectHandler

csv_file = open('switch ports2.csv')
template_file = open('interface-template2.j2')

reader = csv.DictReader(csv_file)
interface_template = Template(template_file.read(), keep_trailing_newline=True)

interface_configs = ''

for row in reader:
    interface_config = interface_template.render(
    interface = row['Interface'],
    vlan = row['VLAN'],
    server = row['Server'],
    link = row['Port'],
    purpose = row['Purpose']
    )
    interface_configs += interface_config

config_set = interface_configs.split('\n')

SW = {
 'device_type': 'huawei',
 'ip': '192.168.88.1',
 'username': 'admin',
 'password': 'admin123',
    }

connect = ConnectHandler(**SW)
print ('Connected to switch')

output = connect.send_config_set(config_set) #output = connect.send_config_set(config_set, cmd_verify=False) 注释这个是Netmiko 3需要的自身的一个"bug",我查看了我的netmiko是2所以不需要这个参数
print(output)



执行结果:

执行成功  cmd打印的
PS D:\Python_Files\python2020item\CSV_Jinja2> python .\jinja2_peizhiSW.py
Connected to switch
Traceback (most recent call last):
  File ".\jinja2_peizhiSW.py", line 35, in 
    output = connect.send_config_set(config_set, cmd_verify=False)
TypeError: send_config_set() got an unexpected keyword argument 'cmd_verify'
PS D:\Python_Files\python2020item\CSV_Jinja2>
PS D:\Python_Files\python2020item\CSV_Jinja2>
PS D:\Python_Files\python2020item\CSV_Jinja2> python .\jinja2_peizhiSW.py
Connected to switch
system-view
Enter system view, return user view with Ctrl+Z.
[RR]interface Ethernet0/0/0
[RR-Ethernet0/0/0]  description Link to esxi-01 port  for VM Host
[RR-Ethernet0/0/0]  port link-type trunk
[RR-Ethernet0/0/0]  undo shutdown
Info: Interface Ethernet0/0/0 is not shutdown.
[RR-Ethernet0/0/0]
[RR-Ethernet0/0/0]interface Ethernet0/0/1
[RR-Ethernet0/0/1]  description Link to esxi-01 port  for VM Host
[RR-Ethernet0/0/1]  port link-type trunk
[RR-Ethernet0/0/1]  undo shutdown
Info: Interface Ethernet0/0/1 is not shutdown.
[RR-Ethernet0/0/1]
[RR-Ethernet0/0/1]interface Ethernet0/0/2
[RR-Ethernet0/0/2]  description Link to esxi-02 port  for VM Host
[RR-Ethernet0/0/2]  port link-type trunk
[RR-Ethernet0/0/2]  undo shutdown
Info: Interface Ethernet0/0/2 is not shutdown.
[RR-Ethernet0/0/2]
[RR-Ethernet0/0/2]interface Ethernet0/0/3
[RR-Ethernet0/0/3]  description Link to esxi-02 port  for VM Host
[RR-Ethernet0/0/3]  port link-type trunk
[RR-Ethernet0/0/3]  undo shutdown
Info: Interface Ethernet0/0/3 is not shutdown.
[RR-Ethernet0/0/3]
[RR-Ethernet0/0/3]interface Ethernet0/0/4
[RR-Ethernet0/0/4]  description Link to db-01 port  for Database Server
[RR-Ethernet0/0/4]  port link-type access
[RR-Ethernet0/0/4]  port default vlan  80
[RR-Ethernet0/0/4]  undo shutdown
Info: Interface Ethernet0/0/4 is not shutdown.
[RR-Ethernet0/0/4]
[RR-Ethernet0/0/4]interface Ethernet0/0/5
[RR-Ethernet0/0/5]  description Link to db-02 port  for Database Server
[RR-Ethernet0/0/5]  port link-type access
[RR-Ethernet0/0/5]  port default vlan  80
[RR-Ethernet0/0/5]  undo shutdown
Info: Interface Ethernet0/0/5 is not shutdown.
[RR-Ethernet0/0/5]
[RR-Ethernet0/0/5]interface Ethernet0/0/6
[RR-Ethernet0/0/6]  description Link to app-01 port  for App Server
[RR-Ethernet0/0/6]  port link-type access
[RR-Ethernet0/0/6]  port default vlan  80
[RR-Ethernet0/0/6]  undo shutdown
Info: Interface Ethernet0/0/6 is not shutdown.
[RR-Ethernet0/0/6]
[RR-Ethernet0/0/6]interface Ethernet0/0/7
[RR-Ethernet0/0/7]  description Link to app-02 port  for App Server
[RR-Ethernet0/0/7]  port link-type access
[RR-Ethernet0/0/7]  port default vlan  80
[RR-Ethernet0/0/7]  undo shutdown
Info: Interface Ethernet0/0/7 is not shutdown.
[RR-Ethernet0/0/7]
[RR-Ethernet0/0/7]
[RR-Ethernet0/0/7]return

PS D:\Python_Files\python2020item\CSV_Jinja2>







=======================================================================================
交换机配置也对应上了

[RR]dis  cur
[V200R003C00]
#
 sysname RR
#
 snmp-agent local-engineid 800007DB03000000000000
 snmp-agent sys-info version v3
 snmp-agent group v3 MyGroup privacy read-view View_ALL write-view View_ALL notify-view View_ALL
 snmp-agent target-host trap-hostname V3HOST address 192.168.88.3 udp-port 162 trap-paramsname V3TRAP
 snmp-agent target-host trap-paramsname V3TRAP v3 securityname MyUser privacy
 snmp-agent mib-view View_ALL include iso 
 snmp-agent usm-user v3 MyUser MyGroup authentication-mode sha 4705BD8CE37634ECB4D7DE1D59E200E00DFF5B06 privacy-mode aes128 4705BD8CE37634ECB4D7DE1D59E200E00DFF5B06
 snmp-agent trap source GigabitEthernet0/0/0
 snmp-agent trap enable
 snmp-agent 
#
 clock timezone China-Standard-Time minus 08:00:00
#
portal local-server load flash:/portalpage.zip
#
 drop illegal-mac alarm
#
vlan batch 80
#
 wlan ac-global carrier id other ac id 0
#                                         
 set cpu-usage threshold 80 restore 75
#
aaa 
 authentication-scheme default
 authorization-scheme default
 accounting-scheme default
 domain default 
 domain default_admin 
 local-user admin password cipher %$%$b^!*~`,kEQm{^F(k8;_             Please press ENTER to execute command 
[RR]dis  int  brie
[RR]dis  int  brief 
PHY: Physical
*down: administratively down
(l): loopback
(s): spoofing
(b): BFD down
^down: standby
(e): ETHOAM down
(d): Dampening Suppressed
InUti/OutUti: input utility/output utility
Interface                   PHY   Protocol InUti OutUti   inErrors  outErrors
Ethernet0/0/0               down  down        0%     0%          0          0
Ethernet0/0/1               down  down        0%     0%          0          0
Ethernet0/0/2               down  down        0%     0%          0          0
Ethernet0/0/3               down  down        0%     0%          0          0
Ethernet0/0/4               down  down        0%     0%          0          0
Ethernet0/0/5               down  down        0%     0%          0          0
Ethernet0/0/6               down  down        0%     0%          0          0
Ethernet0/0/7               down  down        0%     0%          0          0
GigabitEthernet0/0/0        up    up          0%     0%          0          0
GigabitEthernet0/0/1        down  down        0%     0%          0          0
LoopBack3                   up    up(s)       0%     0%          0          0
LoopBack4                   up    up(s)       0%     0%          0          0
LoopBack6                   up    up(s)       0%     0%          0          0
LoopBack8                   up    up(s)       0%     0%          0          0
LoopBack9                   up    up(s)       0%     0%          0          0
LoopBack66                  up    up(s)       0%     0%          0          0
LoopBack88                  up    up(s)       0%     0%          0          0
NULL0                       up    up(s)       0%     0%          0          0
[RR]  
[RR]
[RR]dis int des  
[RR]dis int description brei
[RR]dis int description brie
[RR]dis int description brie
                        ^
Error: Wrong parameter found at '^' position.
[RR]dis int description ?   
  Ethernet         Ethernet interface
  GigabitEthernet  GigabitEthernet interface
  LoopBack         LoopBack interface
  NULL             NULL interface
  |                Matching output
               Please press ENTER to execute command 
[RR]dis int description 
PHY: Physical
*down: administratively down
(l): loopback
(s): spoofing
(b): BFD down
^down: standby
(e): ETHOAM down
(d): Dampening Suppressed
Interface                     PHY     Protocol Description            
Eth0/0/0                      down    down     Link to esxi-01 port  for VM Host
Eth0/0/1                      down    down     Link to esxi-01 port  for VM Host
Eth0/0/2                      down    down     Link to esxi-02 port  for VM Host
Eth0/0/3                      down    down     Link to esxi-02 port  for VM Host
Eth0/0/4                      down    down     Link to db-01 port  for Database 
                                               Server                 
Eth0/0/5                      down    down     Link to db-02 port  for Database 
                                               Server                 
Eth0/0/6                      down    down     Link to app-01 port  for App Serv
                                               er                     
Eth0/0/7                      down    down     Link to app-02 port  for App Serv
                                               er                     
GE0/0/0                       up      up       HUAWEI, AR Series, GigabitEtherne
                                               t0/0/0 Interface       
GE0/0/1                       down    down     HUAWEI, AR Series, GigabitEtherne
                                               t0/0/1 Interface       
Loop3                         up      up(s)    HUAWEI, AR Series, LoopBack3 Inte
                                               rface                  
Loop4                         up      up(s)    HUAWEI, AR Series, LoopBack4 Inte
                                               rface                  
Loop6                         up      up(s)    HUAWEI, AR Series, LoopBack6 Inte
                                               rface                  
Loop8                         up      up(s)    HUAWEI, AR Series, LoopBack8 Inte
                                               rface                  
Loop9                         up      up(s)    HUAWEI, AR Series, LoopBack9 Inte
                                               rface                  
Loop66                        up      up(s)    HUAWEI, AR Series, LoopBack66 Int
                                               erface                 
Loop88                        up      up(s)    HUAWEI, AR Series, LoopBack88 Int
                                               erface                 
NULL0                         up      up(s)    HUAWEI, AR Series, NULL0 Interfac
                                               e                      
[RR]



思科篇:

实验拓扑:



网工Python之路 -- CSV和Jinja2批量配置交换机(量大又有差异化的配置)_第3张图片


switch ports-gns3.csv文件内容:

网工Python之路 -- CSV和Jinja2批量配置交换机(量大又有差异化的配置)_第4张图片


interface-template-gns3.j2文件内容:

interface {{ interface }}
  description Link to {{ server }} port {{ port }} for {{ purpose }}
  switchport
  {% if vlan == "Trunk" -%}
  switchport mode trunk
  {% else -%}
  switchport mode access
  switchport access vlan {{ vlan }}
  spanning-tree portfast
  {% endif -%}
  no shutdown



jinja2_peizhiSW-gns3.py

from jinja2 import Template
import csv
from netmiko import ConnectHandler

csv_file = open('switch ports-gns3.csv')
template_file = open('interface-template-gns3.j2')

reader = csv.DictReader(csv_file)
interface_template = Template(template_file.read(), keep_trailing_newline=True)

interface_configs = ''

for row in reader:
    interface_config = interface_template.render(
    interface = row['Interface'],
    vlan = row['VLAN'],
    server = row['Server'],
    link = row['Port'],
    purpose = row['Purpose']
    )
    interface_configs += interface_config

config_set = interface_configs.split('\n')

SW = {
 'device_type': 'cisco_ios',
 'ip': '192.168.88.1',
 'username': 'admin',
 'password': 'admin123',
    }

connect = ConnectHandler(**SW)
print ('Connected to switch')

output = connect.send_config_set(config_set) #output = connect.send_config_set(config_set, cmd_verify=False) 注释这个是Netmiko 3需要的自身的一个"bug",我查看了我的netmiko是2所以不需要这个参数
print(output)






执行结果:
!
interface FastEthernet3/0
 description Link to esxi-01 port  for VM Host
 switchport mode trunk
!
interface FastEthernet3/1
 description Link to esxi-01 port  for VM Host
 switchport mode trunk
!
interface FastEthernet3/2
 description Link to esxi-02 port  for VM Host
 switchport mode trunk
!
interface FastEthernet3/3
 description Link to esxi-02 port  for VM Host
 switchport mode trunk
!
interface FastEthernet3/4
 description Link to db-01 port  for Database Server
 switchport access vlan 80
!
interface FastEthernet3/5
 description Link to db-02 port  for Database Server
 switchport access vlan 80
!
interface FastEthernet3/6
 description Link to app-01 port  for App Server
 switchport access vlan 80
!         
interface FastEthernet3/7
 description Link to app-02 port  for App Server
 switchport access vlan 80
!
interface FastEthernet3/8


================================

PS D:\Python_Files\python2020item\CSV_Jinja2> python .\jinja2_peizhiSW-gns3.py
Connected to switch
config term
Enter configuration commands, one per line.  End with CNTL/Z.
R1(config)#interface FastEthernet3/0
R1(config-if)#  description Link to esxi-01 port  for VM Host
R1(config-if)#  switchport
R1(config-if)#  switchport mode trunk
R1(config-if)#  no shutdown
R1(config-if)#
R1(config-if)#interface FastEthernet3/1
R1(config-if)#  description Link to esxi-01 port  for VM Host
R1(config-if)#  switchport
R1(config-if)#  switchport mode trunk
R1(config-if)#  no shutdown
R1(config-if)#
R1(config-if)#interface FastEthernet3/2
R1(config-if)#  description Link to esxi-02 port  for VM Host
R1(config-if)#  switchport
R1(config-if)#  switchport mode trunk
R1(config-if)#  no shutdown
R1(config-if)#
R1(config-if)#interface FastEthernet3/3
R1(config-if)#  description Link to esxi-02 port  for VM Host
R1(config-if)#  switchport
R1(config-if)#  switchport mode trunk
R1(config-if)#  no shutdown
R1(config-if)#
R1(config-if)#interface FastEthernet3/4
R1(config-if)#  description Link to db-01 port  for Database Server
R1(config-if)#  switchport
R1(config-if)#  switchport mode access
R1(config-if)#  switchport access vlan 80
%Access VLAN 80 does not exist. Please add it to vlan database
R1(config-if)#  spanning-tree port type edge
                                   ^
% Invalid input detected at '^' marker.

R1(config-if)#  no shutdown
R1(config-if)#
R1(config-if)#interface FastEthernet3/5
R1(config-if)#  description Link to db-02 port  for Database Server
R1(config-if)#  switchport
R1(config-if)#  switchport mode access
R1(config-if)#  switchport access vlan 80
%Access VLAN 80 does not exist. Please add it to vlan database
R1(config-if)#  spanning-tree port type edge
                                   ^
% Invalid input detected at '^' marker.

R1(config-if)#  no shutdown
R1(config-if)#
R1(config-if)#interface FastEthernet3/6
R1(config-if)#  description Link to app-01 port  for App Server
R1(config-if)#  switchport
R1(config-if)#  switchport mode access
R1(config-if)#  switchport access vlan 80
%Access VLAN 80 does not exist. Please add it to vlan database
R1(config-if)#  spanning-tree port type edge
                                   ^
% Invalid input detected at '^' marker.

R1(config-if)#  no shutdown
R1(config-if)#
R1(config-if)#interface FastEthernet3/7
R1(config-if)#  description Link to app-02 port  for App Server
R1(config-if)#  switchport
R1(config-if)#  switchport mode access
R1(config-if)#  switchport access vlan 80
%Access VLAN 80 does not exist. Please add it to vlan database
R1(config-if)#  spanning-tree port type edge
                                   ^
% Invalid input detected at '^' marker.

R1(config-if)#  no shutdown
R1(config-if)#
R1(config-if)#
R1(config-if)#end
R1#
PS D:\Python_Files\python2020item\CSV_Jinja2>









=================================================
思科配置ssh
配置ssh如下:
R1(config)#line vty 0 4
R1(config-line)#transport input all    【可以选ssh  telnet  我都选了,all】
R1(config-line)#login local    【使用本地定义的用户名密码登录】
R1(config-line)#
R1(config-line)#exi

R1(config)#username admin privilege 15 password cisco  【定义本地定义的用户名密码】

R1(config)#crypto key generate rsa
% Please define a domain-name first.     【务必先定义domain-name】
R1(config)#
R1(config)#ip domain-name xxh.com
R1(config)#
R1(config)#crypto key generate rsa   【发现配置了ip domain-name xxh.com和crypto key generate rsa  之后,22端口能测试通了!crypto key generate rsa在路由器上产生一对RSA密钥就会自动启用SSH.如果你删除这对RSA密钥,就会自动禁用该SSH服务器】

之后配置ip,我之后再用CRT测试,发现ssh2不行,ssh1倒是可以登录。
R1#show   ip  ssh
SSH Enabled - version 1.99
Authentication timeout: 120 secs; Authentication retries: 3
R1#
R1#conf  t
R1(config)#ip ssh version 2
R1(config)#exi
R1#show   ip  ssh
SSH Enabled - version 2.0
Authentication timeout: 120 secs; Authentication retries: 3
R1#
R1#
R1#




注意:重启路由器之后,gns模拟器需要crypto key generate rsa重新生成key才能恢复ssh功能,不然又不能ssh了
R1#conf
Configuring from terminal, memory, or network [terminal]? 
Enter configuration commands, one per line.  End with CNTL/Z.
R1(config)#crypto key generate rsa
The name for the keys will be: R1.xxh.com
Choose the size of the key modulus in the range of 360 to 2048 for your
  General Purpose Keys. Choosing a key modulus greater than 512 may take
  a few minutes.

How many bits in the modulus [512]: 
% Generating 512 bit RSA keys, keys will be non-exportable...[OK]

R1(config)#
R1(config)#
R1(config)#
R1(config)#
R1(config)#
*Mar  1 00:00:54.711: %SSH-5-ENABLED: SSH 2.0 has been enabled
R1(config)#
*Mar  1 00:01:15.199: %SYS-5-CONFIG_I: Configured from console by admin on vty0 (192.168.88.3)
R1(config)#