一.概述
可能是因为使用的是eve里面csr1000v的缘故,在用netconfig配置路由器的接口,up接口,并配置ospf时,发现相同的代码,有时执行不成功,有时又能执行成功。代码把功能进行了拆分,分别为配置接口IP、no shutdown接口、配置ospf的router-id、宣告ospf的网络,每执行一个任务都通过netconfig连接路由器的TCP830一次,出现失败的一般都是第一个任务是成功的、后面三个有可能成功,也有可能失败,因此就想着能否把所有的任务集中在一起执行,这样配置一台路由器就只需netconfig连接一次,从而提高效率。
二.解决思路
经过手工编写payload测试,把接口配置、OSOF配置写在一起,可以正常执行,接下来就是怎么编写模板文件。因为多个接口配置其实是差不多,只是重复代码的问题。查询jinja2的模板可以支持宏,在宏里面还可定义循环语句,后面给宏传参的时候,只需传元素为字典的列表即可。
三.配置步骤(不用sqlite3数据库)
1.创建templates目录,里面放置宏文件和模板文件
①宏文件macro.html分别定义三个宏,用于配置接口ip,up接口,配置ospf,文件内容如下:
{% macro set_if_ip(if_infors) -%}
{%- for infor in if_infors %}
<interface>
<{{ infor.if_type }}>
<name>{{ infor.if_no }}</name>
<ip>
<address>
<primary>
<address>{{ infor.if_ip }}</address>
<mask>{{ infor.mask }}</mask>
</primary>
</address>
</ip>
</{{ infor.if_type }}>
</interface>
{%- endfor %}
{%- endmacro %}
{% macro set_if_up(ip_infors) -%}
{%- for infor in ip_infors %}
<interface>
<name>{{ infor.if_type }}{{ infor.if_no }}</name>
<enabled>true</enabled>
</interface>
{%- endfor %}
{%- endmacro %}
{% macro set_ospf(ospf_infors) -%}
{%- for infor in ospf_infors %}
<router>
<ios-ospf:ospf>
<ios-ospf:id>{{ infor.process_id }}</ios-ospf:id>
<ios-ospf:router-id>{{ infor.router_id }}</ios-ospf:router-id>
<ios-ospf:network>
<ios-ospf:ip>{{ infor.network }}</ios-ospf:ip>
<ios-ospf:mask>{{ infor.wild_mask }}</ios-ospf:mask>
<ios-ospf:area>{{ infor.area }}</ios-ospf:area>
</ios-ospf:network>
</ios-ospf:ospf>
</router>
{%- endfor %}
{%- endmacro %}
②模板文件if_and_ospf_config.xml导入前面配置的宏文件,文件内容如下:
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> <native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native" xmlns:ios-ospf="http://cisco.com/ns/yang/Cisco-IOS-XE-ospf"> {% import "macro.html" as macro %} {{ macro.set_if_ip( if_infors ) }} {{ macro.set_ospf( ospf_infors ) }} </native> <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"> {{ macro.set_if_up( if_infors )}} </interfaces> </config>
|
2.配置yang_xml_maker_template.py文件,将xml文件转换为jinja2模板,文件内容如下:
from jinja2 import FileSystemLoader, Environment
def netconf_if_and_ospf(if_infs, ospf_infs):
loader = FileSystemLoader('templates')
netconf_template = Environment(loader=loader).get_template('if_and_ospf_config.xml')
return netconf_template.render(if_infors=if_infs, ospf_infors=ospf_infs)
3.配置netconf_request.py文件,使用netconfig连接路由器,文件内容如下:
# -*- coding: utf-8 -*-
import lxml.etree as et
from ncclient import manager
from ncclient.operations import RPCError
def csr_netconf_config(ip, username, password, payload_xml, port='830'):
with manager.connect(host=ip,
port=port,
username=username,
password=password,
timeout=90,
hostkey_verify=False,
device_params={'name': 'csr'}) as m:
try:
response = m.edit_config(target='running', config=payload_xml).xml
data = et.fromstring(response.encode('utf-8'))
except RPCError as e:
data = e._raw
print(et.tostring(data, pretty_print=True))
4.配置netconf_all_auto.py文件,提供数据;调用yang_xml_maker_template.py中的方法,使用模板,传参给宏,生成request的payload;调用netconf_request.py的方法netconfig连接路由器,执行payload,文件内容如下:
# -*- coding: utf-8 -*-
from netconf_request import csr_netconf_config
from yang_xml_maker_template import netconf_if_and_ospf
csr1_ifs = [{'if_type': 'GigabitEthernet', 'if_no': '1', 'if_ip': '137.78.5.1', 'mask': '255.255.255.0'},
{'if_type': 'GigabitEthernet', 'if_no': '2', 'if_ip': '61.128.1.1', 'mask': '255.255.255.0'},
{'if_type': 'Loopback', 'if_no': '0', 'if_ip': '1.1.1.1', 'mask': '255.255.255.0'}]
csr2_ifs = [{'if_type': 'GigabitEthernet', 'if_no': '1', 'if_ip': '61.128.1.2', 'mask': '255.255.255.0'},
{'if_type': 'GigabitEthernet', 'if_no': '2', 'if_ip': '202.100.1.2', 'mask': '255.255.255.0'},
{'if_type': 'Loopback', 'if_no': '0', 'if_ip': '2.2.2.2', 'mask': '255.255.255.0'}]
csr1_ospf = [{'process_id': '1', 'router_id': '1.1.1.1', 'network': '137.78.5.1', 'wild_mask': '0.0.0.0', 'area': '0'},
{'process_id': '1', 'router_id': '1.1.1.1', 'network': '61.128.1.1', 'wild_mask': '0.0.0.0', 'area': '0'}]
csr2_ospf = [{'process_id': '1', 'router_id': '2.2.2.2', 'network': '202.100.1.2', 'wild_mask': '0.0.0.0', 'area': '0'},
{'process_id': '1', 'router_id': '2.2.2.2', 'network': '61.128.1.2', 'wild_mask': '0.0.0.0', 'area': '0'}]
all_network_data = [{'ip': '192.168.10.100', 'interface': csr1_ifs, 'ospf': csr1_ospf},
{'ip': '192.168.10.200', 'interface': csr2_ifs, 'ospf': csr2_ospf}]
username = 'admin'
password = 'Cisc0123'
def netconf_all_auto():
for csr in all_network_data:
print('配置接口IP和OSPF')
csr_netconf_config(csr['ip'], username, password, netconf_if_and_ospf(csr['interface'], csr['ospf']), port='830')
if __name__ == '__main__':
netconf_all_auto()
四.配置步骤(使用sqlite3数据库)
1.创建templates目录,里面放置宏文件和模板文件
2.配置yang_xml_maker_template.py文件,将xml文件转换为jinja2模板
3.配置netconf_request.py文件,使用netconfig连接路由器,
---这三步与前面相同
4.添加database目录,并创建使用SQLite驱动的netconf.db数据库文件,通过如下sql建表,并插入数据
drop table router_infor;
create table router_infor
(
[router_id] integer PRIMARY KEY AUTOINCREMENT,
[ip] varchar,
[login_name] varchar,
[login_passwd] varchar
);
insert into router_infor values (null,'192.168.10.100','admin','Cisc0123');
insert into router_infor values (null,'192.168.10.200','admin','Cisc0123');
drop table interface_infors;
create table interface_infors(
id integer,
if_type varchar,
if_no integer,
if_ip varchar,
mask varchar,
foreign key (id) references router_infor(router_id)
);
insert into interface_infors values (1,'GigabitEthernet', 1, '137.78.5.1', '255.255.255.0');
insert into interface_infors values (1,'GigabitEthernet', 2, '61.128.1.1', '255.255.255.0');
insert into interface_infors values (1,'Loopback', 0, '1.1.1.1', '255.255.255.255');
insert into interface_infors values (2,'GigabitEthernet', 1, '61.128.1.2', '255.255.255.0');
insert into interface_infors values (2,'GigabitEthernet', 2, '202.100.1.2', '255.255.255.0');
insert into interface_infors values (2,'Loopback', 0, '2.2.2.2', '255.255.255.255');
drop table ospf_infors;
create table ospf_infors
(
id integer,
process_id integer,
router_id varchar,
network varchar,
wild_mask varchar,
area integer,
foreign key (id) references router_infor (router_id)
);
insert into ospf_infors values (1,1, '1.1.1.1', '137.78.5.1', '0.0.0.0', 0);
insert into ospf_infors values (1,1, '1.1.1.1', '61.128.1.1', '0.0.0.0', 0);
insert into ospf_infors values (2,1, '2.2.2.2', '61.128.1.2', '0.0.0.0', 0);
insert into ospf_infors values (2,1, '2.2.2.2', '202.100.1.2', '0.0.0.0', 0);
4.配置netconf_all_auto.py文件,文件内容如下:
from netconf_request import csr_netconf_config
from yang_xml_maker_template import netconf_if_and_ospf
import sqlite3
def dict_factory(cursor, row): # 定义方法,查询数据库,返回字典
d = {}
for idx, col in enumerate(cursor.description):
d[col[0]] = row[idx]
return d
def netconf_all_auto():
con = sqlite3.connect("./database/netconf.db")
con.row_factory = dict_factory
cur = con.cursor()
sql = cur.execute("select * from router_infor").fetchall()
for csr in sql:
print('配置接口IP和OSPF')
int_infors = cur.execute("select * from interface_infors where id = {}".format(csr['router_id'])).fetchall()
ospf_infors = cur.execute("select * from ospf_infors where id = {}".format(csr['router_id'])).fetchall()
payload = netconf_if_and_ospf(int_infors, ospf_infors)
csr_netconf_config(csr['ip'], csr['login_name'], csr['login_passwd'], payload, port='830')
if __name__ == '__main__':
netconf_all_auto()
五.验证效果
经过实际测试,每次都能成功执行。