以juniper和华为设备为例
交换机必要配置,配置简单,使用ssh模式传输
#juniper set system services netconf ssh #华为
local-user netconf-dark password irreversible-cipher $1c$16[R/:A_aG$sG-KWmUb!SCz=R9y[P%KE&9.'P"+:XJ=-`<S76p.$
local-user netconf-dark privilege level 15
local-user netconf-dark service-type api
netconf
source ip 10.0.3.105
netconf使用XML格式来请求和接收数据,使用简单举例
使用ssh连接交换机
C:\Users\86185>ssh 10.0.3.101 -s netconf Password: <!-- No zombies were killed during the creation of this user interface --> <!-- user dark, class j-super-user --> <hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> <capabilities> <capability>urn:ietf:params:netconf:base:1.0</capability> <capability>urn:ietf:params:netconf:capability:candidate:1.0</capability> <capability>urn:ietf:params:netconf:capability:confirmed-commit:1.0</capability> <capability>urn:ietf:params:netconf:capability:validate:1.0</capability> <capability>urn:ietf:params:netconf:capability:url:1.0?scheme=http,ftp,file</capability> <capability>urn:ietf:params:xml:ns:netconf:base:1.0</capability> <capability>urn:ietf:params:xml:ns:netconf:capability:candidate:1.0</capability> <capability>urn:ietf:params:xml:ns:netconf:capability:confirmed-commit:1.0</capability> <capability>urn:ietf:params:xml:ns:netconf:capability:validate:1.0</capability> <capability>urn:ietf:params:xml:ns:netconf:capability:url:1.0?protocol=http,ftp,file</capability> <capability>http://xml.juniper.net/netconf/junos/1.0</capability> <capability>http://xml.juniper.net/dmi/system/1.0</capability> </capabilities> <session-id>65770</session-id> </hello> ]]>]]>
juniper请求端口信息
<rpc> <get-interface-information> <interface-name>xe-0/0/1</interface-name> <detail/> </get-interface-information> </rpc>
juniper提交配置
<rpc> <commit/> </rpc>
华为请求trunk接口信息
<?xml version="1.0" encoding="UTF-8"?> <rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="1024"> <get> <filter type="subtree"> <ifmtrunk xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0"> <TrunkIfs> <TrunkIf> <ifName></ifName> <minUpNum></minUpNum> <trunkType></trunkType> </TrunkIf> </TrunkIfs> </ifmtrunk> </filter> </get> </rpc>
以上是netconf的简单原生操作,如果我们要在python环境中使用netconf,首先需要下载读取YANG文件,封装get get-config commit edit_config lock unlock等功能,根据不同厂商选择不同的YANG API,其次还需要创建sock连接,通过ssh交互netconf报文,设备厂商繁多,各家功能对应的TAG名称也不一致,自己一步一步写起来太过复杂,好在python中有较为成熟的库可供我们使用
ncclient
ncclient是一个用于NETCONF客户端的Python库,可以在python环境中使用netconf协议检索下发交换机配置
host = '10.0.3.105' username = 'username' passwd = 'password' #connect()返回一个连接对象 netconf_connection = manager.connect(host=host, username=username, password=passwd, port=830, hostkey_verify=False ) #获取交换机端口简要信息XML语句 interface_index = """ <device-state xmlns="urn:huawei:params:xml:ns:yang:huawei-device"> <optical-module-infos> <interface-list> </interface-list> </optical-module-infos> </device-state> """ rpc_conf = netconf_connection.get(filter =('subtree',interface_info)) print(rpc)
得到如下信息
<?xml version="1.0" encoding="UTF-8"?><data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"><device-state xmlns="urn:huawei:params:xml:ns:yang:huawei-device"><optical-module-infos><interface-list><interface-name>XGigabitEthernet0/0/1</interface-name><physical-index>1</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/2</interface-name><physical-index>2</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/3</interface-name><physical-index>3</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/4</interface-name><physical-index>4</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/5</interface-name><physical-index>5</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/6</interface-name><physical-index>6</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/7</interface-name><physical-index>7</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/8</interface-name><physical-index>8</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/9</interface-name><physical-index>9</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/10</interface-name><physical-index>10</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/11</interface-name><physical-index>11</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/12</interface-name><physical-index>12</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/13</interface-name><physical-index>13</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/14</interface-name><physical-index>14</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/15</interface-name><physical-index>15</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/16</interface-name><physical-index>16</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/17</interface-name><physical-index>17</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/18</interface-name><physical-index>18</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/19</interface-name><physical-index>19</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/20</interface-name><physical-index>20</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/21</interface-name><physical-index>21</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/22</interface-name><physical-index>22</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/23</interface-name><physical-index>23</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/24</interface-name><physical-index>24</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/25</interface-name><physical-index>25</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/26</interface-name><physical-index>26</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/27</interface-name><physical-index>27</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/28</interface-name><physical-index>28</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/29</interface-name><physical-index>29</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/30</interface-name><physical-index>30</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/31</interface-name><physical-index>31</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/32</interface-name><physical-index>32</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/33</interface-name><physical-index>33</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/34</interface-name><physical-index>34</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/35</interface-name><physical-index>35</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/36</interface-name><physical-index>36</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/37</interface-name><physical-index>37</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/38</interface-name><physical-index>38</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/39</interface-name><physical-index>39</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/40</interface-name><physical-index>40</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/41</interface-name><physical-index>41</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/42</interface-name><physical-index>42</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/43</interface-name><physical-index>43</physical-index><present>false</present></interface-list><interface-list><interface-name>XGigabitEthernet0/0/44</interface-name><physical-index>44</physical-index><present>false</present></interface-list><interface-list><interface-name>100GE0/0/1</interface-name><physical-index>1</physical-index><present>false</present></interface-list><interface-list><interface-name>100GE0/0/2</interface-name><physical-index>2</physical-index><present>false</present></interface-list><interface-list><interface-name>40GE0/0/3</interface-name><physical-index>3</physical-index><present>false</present></interface-list><interface-list><interface-name>40GE0/0/4</interface-name><physical-index>4</physical-index><present>false</present></interface-list><interface-list><interface-name>40GE0/0/5</interface-name><physical-index>5</physical-index><present>false</present></interface-list><interface-list><interface-name>40GE0/0/6</interface-name><physical-index>6</physical-index><present>false</present></interface-list></optical-module-infos></device-state></data>View Code
请问这一堆乱糟糟的是什么东西,也没个换行符-_-!
别急,我们需要封装一些功能进去
1 #首先自己写一个类 2 class Netconf: 3 #封装一些connect必要的参数 4 def __init__(self,*args,**kwargs): 5 self.host = kwargs['host'] 6 self.port = kwargs.get('port',830) 7 self.username = kwargs['username'] 8 self.passwd = kwargs['passwd'] 9 self.hostkey_verify=kwargs.get('hostkey_verify',False) 10 #connect方法 11 def conn(self): 12 try: 13 netconf_conn = manager.connect(host=self.host,port=self.port,username=self.username,password=self.passwd,hostkey_verify=self.hostkey_verify) 14 return netconf_conn 15 except Exception as a: 16 print(a) 17 print(""" 18 --------------------------------------------------------------------------------------- 19 sample: Netconf(host='10.0.3.105',username='netconf-dark',passwd='1234567',port=830) 20 """ 21 ) 22 #get_config方法,获取的交换机的所有配置 23 def get_conf(self): 24 netconf_conn = self.conn() 25 return netconf_conn.get_config(source='running').data_xml 26 #写个方法处理下得到的数据,以xml树形格式进行返回 27 def get_xml(self,command=None): 28 netconf_conn = self.conn() 29 rpc_replay = netconf_conn.get(filter=('subtree',command)).data_xml 30 rpc_xml = xml.dom.minidom.parseString(rpc_replay).toprettyxml() 31 return rpc_replay 32 #以字典形式进行返回,方便做数据处理 33 def get_dic(self,command=None): 34 netconf_conn = self.conn() 35 rpc_replay = netconf_conn.get(filter=('subtree',command)).data_xml 36 rpc_dict = xmltodict.parse(rpc_replay) 37 return rpc_dict 38 #以json方式进行返回 39 def get_json(self,command=None): 40 rpc_replay = self.get_dic(command) 41 rpc_json = json.dumps(rpc_replay, indent=1) 42 return rpc_json 43 def server_capabilities(self): 44 netconf_conn = self.conn() 45 return netconf_conn.server_capabilities
我们来用下好不好使
interface_info = """ <interfaces-state xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"> <interface> <name></name> <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip"> <address></address> </ipv4> </interface> </interfaces-state> """ conn = Netconf(host='10.0.3.105',username='netconf',passwd='netconf123456') rpc_json = conn.get_json(interface_index) rpc_xml = conn.get_xml(interface_index) with open('/home/dark/interface_info.json') as a: a.write(rpc_json) with open('/home/dark/interface_info.xml') as a: a.write(rpc_xml)
运行以上代码
#json格式,输出太长,截取一小段 { "data": { "@xmlns": "urn:ietf:params:xml:ns:netconf:base:1.0", "@xmlns:nc": "urn:ietf:params:xml:ns:netconf:base:1.0", "interfaces-state": { "@xmlns": "urn:ietf:params:xml:ns:yang:ietf-interfaces", "interface": [ { "name": "NULL0" }, { "name": "MEth0/0/1" }, { "name": "Vlanif1" }, { "name": "XGigabitEthernet0/0/1" }, { "name": "XGigabitEthernet0/0/2" }, { "name": "XGigabitEthernet0/0/3" }, { "name": "XGigabitEthernet0/0/4" }, { "name": "40GE0/0/3" }, { "name": "40GE0/0/4" }, { "name": "40GE0/0/5" }, { "name": "40GE0/0/6" }, { "name": "LoopBack0", "ipv4": { "@xmlns": "urn:ietf:params:xml:ns:yang:ietf-ip", "address": { "ip": "192.168.35.60", "netmask": "255.255.255.255", "origin": "static" } } }, { "name": "Vlanif48", "ipv4": { "@xmlns": "urn:ietf:params:xml:ns:yang:ietf-ip", "address": { "ip": "10.40.0.70", "netmask": "255.255.255.252", "origin": "static" } } }, { "name": "LoopBack1", "ipv4": { "@xmlns": "urn:ietf:params:xml:ns:yang:ietf-ip", "address": { "ip": "192.168.39.17", "netmask": "255.255.255.252", "origin": "static" } } }, { "name": "MEth0/0/2" } ] } } }json格式
#XML格式,输出太长,截取一小段 <?xml version="1.0" ?> <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"> <interfaces-state xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"> <interface> <name>NULL0</name> </interface> <interface> <name>MEth0/0/1</name> </interface> <interface> <name>Vlanif1</name> </interface> <interface> <name>XGigabitEthernet0/0/1</name> </interface> <interface> <name>XGigabitEthernet0/0/2</name> </interface> <interface> <name>XGigabitEthernet0/0/3</name> </interface> <interface> <name>40GE0/0/3</name> </interface> <interface> <name>40GE0/0/4</name> </interface> <interface> <name>40GE0/0/5</name> </interface> <interface> <name>40GE0/0/6</name> </interface> <interface> <name>LoopBack0</name> <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip"> <address> <ip>192.168.35.60</ip> <netmask>255.255.255.255</netmask> <origin>static</origin> </address> </ipv4> </interface> <interface> <name>Nve1</name> </interface> <interface> <name>Vlanif48</name> <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip"> <address> <ip>10.40.0.70</ip> <netmask>255.255.255.252</netmask> <origin>static</origin> </address> </ipv4> </interface> <interface> <name>LoopBack1</name> <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip"> <address> <ip>192.168.39.17</ip> <netmask>255.255.255.252</netmask> <origin>static</origin> </address> </ipv4> </interface> <interface> <name>MEth0/0/2</name> </interface> </interfaces-state> </data>XML格式
代码中的interfac_info的XML字符串来自哪里?这就需要用到YANG API,有公共的YANG,各家厂商也有自己的YANG
例如华为CE系列的https://support.huawei.com/hedex/hdx.do?docid=EDOC1000179511&lang=zh&id=library_change_preview&from=HedExLite
也可以通过get请求格式化成XML文档树,如下
juniper还可以通过命令行输出XML格式,华为没找类似功能,可能是我手里的交换机太垃圾
如果是通过YANG API文件检索的字符串,我们用ncclient执行操作时只需要content部分,如下黑色框区域
如果是get到的XML文档树,需要哪个模块就点开哪个模块复制就行,例如我们需要获取每个端口的ipaddress,如下
先找到interfaces-state这一层,展开
我们可以获取关于接口的N多信息,如果我们只需要其中的一部分可以进行如下操作
interface_info = """ <interfaces-state xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"> <interface> <name></name> <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip"> <address></address> </ipv4> </interface> </interfaces-state> """ #根层必须有,子层的父层也必须有,到子层后需要哪些标签就写对应的标签 rpc_xml = conn.get_xml(interface_info) print(rpc_xml)
输出如下,截取部分
同样的,juniper通过GET到XML结构树,这里不得不感叹下juniper的便捷,灵活性,从以下输出可以看到juniper的XML树形结构与配置命令的层次结构极其相似
来get一下接口信息,这次输出json格式
rpc_json = conn.get_json('<configuration><interfaces></interfaces></configuration>') print(rpc_json)
运行以上代码,截取一小部分
以上是ncclient的GET操作,ncclient的manager模块还有许多其他方法,如下
、
接着说edit_config和commit,discard_changss,这些方法用于对交换机配置的变更,我们需要封装进我们自己的类,改变如下
1 class Netconf: 2 #封装一些connect必要的参数 3 def __init__(self,*args,**kwargs): 4 self.host = kwargs['host'] 5 self.port = kwargs.get('port',830) 6 self.username = kwargs['username'] 7 self.passwd = kwargs['passwd'] 8 self.hostkey_verify=kwargs.get('hostkey_verify',False) 9 self.device_params=kwargs.get('device_params',None) 10 #connect方法 11 def conn(self): 12 try: 13 netconf_conn = manager.connect(host=self.host,port=self.port,username=self.username,\ 14 password=self.passwd,hostkey_verify=self.hostkey_verify,device_params=self.device_params) 15 return netconf_conn 16 except Exception as a: 17 print(a) 18 print(""" 19 --------------------------------------------------------------------------------------- 20 sample: Netconf(host='10.0.3.105',username='netconf-dark',passwd='1234567',port=830) 21 """ 22 ) 23 #get_config方法,获取的交换机的所有配置 24 def get_conf(self): 25 netconf_conn = self.conn() 26 return netconf_conn.get_config(source='running').data_xml 27 #写个方法处理下得到的数据,以xml树形格式进行返回 28 def get_xml(self,command=None): 29 netconf_conn = self.conn() 30 rpc_replay = netconf_conn.get(filter=('subtree',command)).data_xml 31 rpc_xml = xml.dom.minidom.parseString(rpc_replay).toprettyxml() 32 33 return rpc_xml.strip() 34 #以字典形式进行返回,方便做数据处理 35 def get_dic(self,command=None): 36 netconf_conn = self.conn() 37 rpc_replay = netconf_conn.get(filter=('subtree',command)).data_xml 38 rpc_dict = xmltodict.parse(rpc_replay) 39 return rpc_dict 40 #以json方式进行返回 41 def get_json(self,command=None): 42 rpc_replay = self.get_dic(command) 43 rpc_json = json.dumps(rpc_replay, indent=1) 44 return rpc_json 45 #server端所支持的能力,返回迭代器 46 def server_capabilities(self): 47 netconf_conn = self.conn() 48 return netconf_conn.server_capabilities 49 #edit_config方法,target可使用candidate或running 50 def edit(self,command=None,target='candidate'): 51 netconf_conn = self.conn() 52 reply = netconf_conn.edit_config(target=target,config=command) 53 return reply 54 #清除未提交配置 55 def rollback(self): 56 netconf_conn = self.conn() 57 # netconf_conn.rpc('<discard-changes/>') 58 return netconf_conn.discard_changes() 59 60 #提交配置,confirmed代表是否进行回滚,timout表示多久回滚 61 def commit(self,confirmed=False,timeout=None): 62 netconf_conn = self.conn() 63 return netconf_conn.commit(confirmed=confirmed,timeout=timeout)
edit_config方法有一个必要的参数,config,XML格式,target参数需要注意,值可为candidate或running,对于juniper必须使用candidate,因为juniper配置完设备后需要commit提交配置
首先我们使用 server_capabilities方法看下设备是否支持edit_config
jun_conn = Netconf(host='10.0.3.101',username='username',passwd='passwd',port=1211,device_params={'name':'junos'}) hw_conn = Netconf(host='10.0.3.105',username='netconf',passwd='passwd') for cap in hw_conn.server_capabilities(): print(cap) for cap in jun_conn.server_capabilities(): print(cap)
输出如下,juniper对网络可编程支持性较好,操作舒服,以下案例均使用juniper设备
#HW rn:ietf:params:netconf:base:1.0 urn:ietf:params:netconf:base:1.1 urn:ietf:params:netconf:capability:writable-running:1.0 urn:ietf:params:netconf:capability:candidate:1.0 urn:ietf:params:netconf:capability:startup:1.0 urn:ietf:params:netconf:capability:rollback-on-error:1.0 urn:ietf:params:netconf:capability:with-defaults:1.0 urn:ietf:params:netconf:capability:notification:1.0 urn:ietf:params:xml:ns:yang:1?revision=2017-02-20&module=yang urn:ietf:params:xml:ns:yang:ietf-inet-types?revision=2013-07-15&module=ietf-inet-types urn:ietf:params:xml:ns:yang:ietf-yang-types?revision=2013-07-15&module=ietf-yang-types urn:ietf:params:xml:ns:yang:ietf-yang-library?revision=2018-01-17&module=ietf-yang-library urn:ietf:params:xml:ns:yang:ietf-interfaces?revision=2014-05-08&module=ietf-interfaces&feature=arbitrary-names,pre-provisioning,if-mib #juniper urn:ietf:params:netconf:base:1.0 urn:ietf:params:netconf:capability:candidate:1.0 urn:ietf:params:netconf:capability:confirmed-commit:1.0 urn:ietf:params:netconf:capability:validate:1.0 urn:ietf:params:netconf:capability:url:1.0?scheme=http,ftp,file urn:ietf:params:xml:ns:netconf:base:1.0 urn:ietf:params:xml:ns:netconf:capability:candidate:1.0 urn:ietf:params:xml:ns:netconf:capability:confirmed-commit:1.0 urn:ietf:params:xml:ns:netconf:capability:validate:1.0 urn:ietf:params:xml:ns:netconf:capability:url:1.0?protocol=http,ftp,file http://xml.juniper.net/netconf/junos/1.0 http://xml.juniper.net/dmi/system/1.0
来使用下我们新增的方法,通用YANG API edit_config方法使用的tag是<config>,内层标签则需要查找设备厂商所提供的API
jun_conn = Netconf(host='10.0.3.101',username='usernam',passwd='password',port=1211,device_params={'name':'junos'}) snmp = ''' <config> <configuration> <snmp> <community> <name>dark123456</name> <authorization>read-only</authorization> </community> </snmp> </configuration> </config> ''' jun_conn.edit(snmp)
运行以上代码后在设备上可以看到配置已经下发,但未提交,需要注意的是对于华为设备如果candidate数据库中有未提交配置时不可操作running数据库
dark@Test-Route# show | compare [edit snmp] community 000123a { ... } + community dark123456 { + authorization read-only; + } [edit]
dark@Test-Route> show configuration snmp | display set
set snmp community test authorization read-only
运行以下代码进行配置回滚
jun_conn.rollback()
执行后在设备上查看未提交配置为空
让我们回到下发配置未提交时,执行以下方法,commit并在1分钟后回滚配置
jun_conn.edit(snmp) jun_conn.commit(confirmed=True,timeout=60)
可以看到配置将在1分钟内回滚
执行jun_conn.commit(),查看设备配置,配置已经下发并提交
然后我们进行配置删除
执行以下代码
del_snmp = ''' <config> <configuration> <snmp> <community operation="delete"> <name>dark123456</name> <authorization>read-only</authorization> </community> </snmp> </configuration> </config>''' jun_conn.edit(del_snmp) jun_conn.commit()
配置已删除
再试下华为设备,添加vlan 671
执行以下代码
vlan = ''' <config> <huawei-vlan:vlans xmlns:huawei-vlan="urn:huawei:params:xml:ns:yang:huawei-vlan" > <huawei-vlan:vlan> <huawei-vlan:id >671</huawei-vlan:id> </huawei-vlan:vlan> </huawei-vlan:vlans> </config> ''' hw_conn.edit(command=vlan,target='running')
至此ncclient基本增删改查方法与格式化输出封装完毕
出门溜娃,下周继续.................