华为OPS,自定义命令,动态执行命令
个人博客地址
OPS
适用阶段 |
OPS API |
---|---|
订阅阶段 |
|
执行阶段 |
|
订阅阶段和执行阶段 |
|
参数 |
参数说明 |
取值 |
---|---|---|
tag |
用于标识条件。 |
字符串形式,不区分大小写,长度范围是1~12,由字母、数字和下划线组成,以字母开头。tag不能为""、None、and、or以及andnot,不能包含\0。 |
pattern |
指定匹配命令的正则表达式。 |
字符串形式,取值范围是1~128个字符,不能包含\0。 |
enter |
指定匹配正则表达式的时间。 |
布尔型,取值如下:
缺省值是False。 |
sync |
指定命令行触发执行动作后,是否等待脚本执行结束。 |
布尔型,取值如下:
缺省值是True。 |
async_skip |
在sync取值为False时,指定是否跳过原有命令执行。 |
布尔型,取值如下:
缺省值是False。 |
sync_wait |
在sync取值为True时,指定命令行同步等待脚本执行的时间。 |
整数形式,取值范围是1~2147483647,单位是秒。缺省值是30秒。 |
参数 |
参数说明 |
取值 |
---|---|---|
tag |
用于标识条件。 |
字符串形式,不区分大小写,长度范围是1~12,由字母、数字和下划线组成,以字母开头。tag不能为""、None、and、or以及andnot,不能包含\0。 |
network |
指定路由前缀。 |
点分十进制形式。 |
maskLen |
指定掩码长度。 |
整数形式,取值范围是0~32。 |
minLen |
指定掩码长度匹配范围的下限。 |
整数形式,必须大于等于maskLen的值。缺省值是None,表示掩码长度匹配范围的下限是0。 |
maxLen |
指定掩码长度匹配范围的上限。 |
整数形式,必须大于等于minLen的值。缺省值是None,表示掩码长度匹配范围的上限是0。 |
neLen |
指定不匹配的掩码长度。 |
整数形式,必须大于等于minLen的值,小于等于maxLen的值。缺省值是None,表示不匹配的掩码长度是0。 |
optype |
指定路由事件变更类型。 |
枚举类型,取值如下:
缺省值是all。 |
protocol |
指定路由协议属性。 |
字符串形式,缺省值为all,表示所有路由协议。
|
OPS 脚本模板
1 # -*- coding: utf-8 -*- # 声明使用utf-8编码格式,可以在Python脚本中添加中文注释。 2 3 # 固定语句,导入ops模块。导入ops模块后,才能在脚本中使用设备支持的OPS API。详见OPS API列表。 4 import ops 5 # 固定语句,导入sys模块。sys模块负责程序与设备内置Python解释器的交互,提供了一系列的函数和变量。 6 # 导入sys模块后,可以使用这些函数和变量。函数和变量的相关信息,请参考官方Python文档。 7 import sys 8 # 固定语句,导入os模块。os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口。 9 # 导入os模块后,可以使用这些接口。接口的相关信息,请参考官方Python文档。 10 import os 11 12 # 固定语句,定义订阅处理函数ops_condition。该函数在配置脚本助手的时候调用,用于订阅事件,由设备内置的框架脚本_frame.py调度执行。 13 # 函数ops_condition的输入参数是_frame.py中创建的ops对象,用户可以在该对象下进行数据访问。 14 def ops_condition(ops): 15 # 当前是订阅阶段,需要使用适用于订阅阶段的OPS API,详见设备支持的OPS API中的表6-1。以下以定时器事件订阅为例。 16 # 使用ops.timer.cron接口订阅一个定时器,以t1标识。其含义为在每周一06:00触发执行阶段指定的动作。可以根据实际需求修改该定时器。 17 # 当输入的参数值为字符串时,需要在字符串两端使用双引号。 18 # status和err_str为用户定义的脚本变量,分别表示ops.timer.cron接口的第一个返回值和第二个返回值。 19 # 通常在调试阶段,可以通过print语句将返回值打印出来,便于查看调试信息和定位问题。 20 # 对于OPS API,用户可以根据实际需求决定是否需要返回值。如需要返回值,则必须根据各OPS API接口原型指定返回值的个数。 21 # 返回值的含义因OPS API而异。详细描述请参见各OPS API。 22 # 对于ops.timer.cron接口,第一个返回值是数字时,0表示该API执行成功,1表示该API执行失败。 23 # 第二个返回值仅当第一个返回值为1时返回,为字符串形式,描述执行失败的原因。 24 status, err_str = ops.timer.cron("t1", "0 6 * * 1") 25 # 指定函数的返回值。函数的返回值可以作为处理结果,也可以通过result函数明确返回处理结果(详见返回事件执行结果)。 26 # 函数的返回值作为函数的输出,可以赋值给其他变量,作为其他函数的输入。 27 # 这里指定函数ops_condition的返回值为0,表示返回值为0时,ops_condition函数执行成功。 28 return 0 29 30 # 固定语句,定义执行处理函数ops_execute。该函数在脚本事件执行的时候调用,用于执行动作,由设备内置的框架脚本_frame.py调度执行。 31 # 函数ops_execute的输入参数是_frame.py中创建的ops对象,用户可以在该对象下进行数据访问。 32 def ops_execute(ops): 33 # 当前是执行阶段,需要使用适用于执行阶段的OPS API,详见设备支持的OPS API中的表6-1。 34 # 以下以打开命令行通道、执行命令行命令和关闭命令行通道为例。 35 # 打开命令行通道。只有打开命令行通道之后,才能执行命令行。执行完命令行之后,需要关闭命令行通道。 36 # handle和err_desp为用户定义的脚本变量,分别表示ops.cli.open接口的第一个返回值和第二个返回值。 37 # 通常在调试阶段,可以通过print语句将返回值打印出来,便于查看调试信息和定位问题。 38 # 执行命令行命令和关闭命令行通道接口使用打开命令行通道接口的第一个返回值作为输入参数。因此使用打开命令行通道接口时,必须指定返回值。 39 handle, err_desp = ops.cli.open() 40 # 执行命令display interface gigabitethernet 1/0/1。 41 # 返回值result为None时,表示命令行未能发送给CLI或者命令行执行超时,其他值为显示输出,即CLI中执行的命令行。 42 # 返回值n11为Next:0表示后续没有输出了,Next:1表示后续还有输出。返回值n12仅在返回值result为None时显示,表示命令行执行失败的原因。 43 result1, n11, n12 = ops.cli.execute(handle, "display interface gigabitethernet 1/0/1") 44 # 执行命令display current-configuration interface gigabitethernet 1/0/1。 45 result2, n21, n22 = ops.cli.execute(handle, "display current-configuration interface gigabitethernet 1/0/1") 46 # 命令行执行结束,关闭命令行通道。 47 result = ops.cli.close(handle) 48 # 将display interface gigabitethernet 1/0/1命令的显示结果记录到日志中,可以在日志文件中查看相应信息。 49 log1, descri_str1 = ops.syslog(result1, "informational", "syslog") 50 # 将display current-configuration interface gigabitethernet 1/0/1命令的显示结果记录到日志中,可以在日志文件中查看相应信息。 51 log2, descri_str2 = ops.syslog(result2, "informational", "syslog") 52 # 指定函数的返回值。函数的返回值可以作为处理结果,也可以通过result函数明确返回处理结果(详见返回事件执行结果)。 53 # 函数的返回值作为函数的输出,可以赋值给其他变量,作为其他函数的输入。 54 # 这里指定函数ops_execute的返回值为0,表示返回值为0时,ops_execute函数执行成功。 55 return 0
1 # -*- coding: utf-8 -*- 2 import ops # 导入ops模块 3 import sys # 导入sys模块 4 import os # 导入os模块 5 import re # 导入re模块,正则表达式 6 # 订阅处理函数 7 def ops_condition (ops): 8 # 检测有新增邻居事件,这里仅订阅邻居是交换机和路由器类型的事件,如果需要订阅其他类型的事件,请按照下面格式补充 9 value1, err_str1 = ops.lldp.subscribe("add1", ops.lldp.LLDP_NEIGHBOR_EVENT_ADD, "INTERFACE_ALL", ops.lldp.LLDP_NEIGHBOR_TYPE_SWITCH) 10 value11, err_str11 = ops.lldp.subscribe("add2", ops.lldp.LLDP_NEIGHBOR_EVENT_ADD, "INTERFACE_ALL", ops.lldp.LLDP_NEIGHBOR_TYPE_ROUTER) 11 12 # 检测有删除邻居事件 13 value2, err_str2 = ops.lldp.subscribe("delete1", ops.lldp.LLDP_NEIGHBOR_EVENT_DEL, "INTERFACE_ALL", ops.lldp.LLDP_NEIGHBOR_TYPE_SWITCH) 14 value22, err_str21 = ops.lldp.subscribe("delete2", ops.lldp.LLDP_NEIGHBOR_EVENT_DEL, "INTERFACE_ALL", ops.lldp.LLDP_NEIGHBOR_TYPE_ROUTER) 15 16 # 组合事件,新增邻居或删除邻居,最多支持8个事件组合 17 value10, err_str10 = ops.correlate("add1 or add2 or delete1 or delete2") 18 return 0 19 20 # 工作处理函数 21 def ops_execute (ops): 22 # 获取系统环境变量_lldp_event,表示事件触发类型 23 key, value = ops.environment.get("_lldp_event") 24 inter, value = ops.environment.get("_lldp_interface") 25 26 if key == "OPR_TYPE_ADD": 27 28 # 打开命令行通道 29 handle, err_desp = ops.cli.open() 30 neighbor, n11, n21 = ops.cli.execute(handle,"display lldp neighbor interface " + inter) 31 32 resultsys = re.search(r'System[\s]+name[\s:]*\S*', neighbor).group() 33 sysname = re.split(':', resultsys) 34 35 resultport = re.search(r'Port\s+ID\s{2,}:*\S*', neighbor).group() 36 port = re.split(':', resultport) 37 38 # 进入系统视图 39 result, n11, n21 = ops.cli.execute(handle,"system-view") 40 41 # 进入接口视图 42 result, n11, n21 = ops.cli.execute(handle,"interface " + inter) 43 44 # 设置接口描述信息 45 result, n11, n21 = ops.cli.execute(handle,"description " + "To-" + sysname[1] + "-" + port[1]) 46 47 48 # 关闭命令行通道 49 result = ops.cli.close(handle) 50 51 52 elif key == "OPR_TYPE_DEL": 53 handle, err_desp = ops.cli.open() 54 55 # 进入系统视图 56 result, n11, n21 = ops.cli.execute(handle,"system-view") 57 58 # 进入接口视图 59 result, n11, n21 = ops.cli.execute(handle,"interface " + inter) 60 61 # 设置接口描述信息 62 result, n11, n21 = ops.cli.execute(handle,"undo description") 63 64 # 关闭命令行通道 65 result = ops.cli.close(handle) 66 67 else: 68 return 1 69 return 0
#下载lldp.py文件 tftp 10.0.64.74 get ops/lldp.py #ops 安装 lldp.py ops install file lldp.py #查看是否被安装 <test>dir $_user/ Directory of flash:/$_user/ Idx Attr Size(Byte) Date Time FileName 0 drw- - Oct 15 2021 15:54:30 __pycache__ 1 -rw- 2,603 Oct 14 2021 15:29:20 lldp.py 2 drw- - May 27 2020 11:35:19 huawei_pys 3 -rw- 612 Oct 14 2021 16:43:13 dangerouscli.py 4 -rw- 912 Oct 15 2021 11:47:06 ospfroute.py 5 -rw- 2,145 Oct 15 2021 15:54:20 20211015.py 6 -rw- 471 Oct 14 2021 15:25:17 portshutdown.py #ops注册 [test]ops [test-ops] script-assistant python lldp.py #设备开启lldp [test]lldp enable #查看接口是否自动配置描述信息 [test]dis cu int MEth 0/0/1 # interface MEth0/0/1 description To-CN-ZhZ01-SW-B-eth-0-10 ip address 10.0.3.105 255.255.255.0 # #禁用LLDP [test]undo lldp enable #查看接口描述信息是否被删除 Info: Global LLDP is disabled successfully. [test]dis cu int me [test]dis cu int MEth 0/0/1 # interface MEth0/0/1 ip address 10.0.3.105 255.255.255.0
import ops def ops_condition (ops): value1, descri_str1 = ops.cli.subscribe("cli1", "reboot", enter=False, sync=False,async_skip=True, sync_wait=60) value2, descri_str2 = ops.cli.subscribe("cli2", "stp disable", enter=False, sync=False,async_skip=True, sync_wait=60) value3, descri_str3 = ops.cli.subscribe("cli3", "stp enable", enter=False, sync=False,async_skip=True, sync_wait=60) value10, err_str10 = ops.correlate("cli1 or cli2 or cli3") return 0 def ops_execute (ops): value, descri_str = ops.terminal.write("Dangerous order, please contact the administrator to execute", vty="all")
验证
#加载ops略 #执行关闭与开启stp和reboot命令 [test]stp enable [test] Dangerous order, please contact the administrator to execute [test]undo stp enable [test] Dangerous order, please contact the administrator to execute [test]q <test>reboot <test> Dangerous order, please contact the administrator to execute
import ops,sys def ops_condition (ops): #result1_value, result2_description = ops.route.subscribe(tag, network, maskLen, minLen=None, maxLen=None, neLen=None, optype=all, protocol=all) #network可以自定义环境变量,在ops视图下使用environment ospf_routes 10.2.1.0设定值 #获取自定义环境变量值 slotid, errstr = ops.environment.get("ospf_routes") value,descri_str=ops.route.subscribe("route1", slotid, 24, minLen=None, maxLen=None, neLen=None, optype="all", protocol="ospf") return 0 def ops_execute (ops): key,values = ops.environment.get("_routing_type") if key == "Delete": handle, err_desp = ops.cli.open() cli, n11, n21 = ops.cli.execute(handle,"sys") cli, n11, n21 = ops.cli.execute(handle,"interface vlan 1588") cli1, n12, n22 = ops.cli.execute(handle,"shutdown") result = ops.cli.close(handle)
测试
#定义环境变量 [test-ops] environment ospf_routes 122.114.1.0 #加载ops脚本略 #查看ospf路由 [test]dis ospf routing 122.114.1.0 OSPF Process 1 with Router ID 192.168.35.60 Destination : 122.114.1.0/24 AdverRouter : 5.5.5.5 Area : 0.0.0.0 Cost : 2 Type : Stub NextHop : 10.35.0.133 Interface : Vlanif1588 Priority : Low Age : 22h42m42s [test] #删除接口ospf后查看vlanif接口是否自动down interface Vlanif1588 ip address 10.35.0.134 255.255.255.252 ospf enable 1 area 0.0.0.0 # return [test-Vlanif1588]undo ospf enable ar 0 [test-Vlanif1588]dis this # interface Vlanif1588 shutdown ip address 10.35.0.134 255.255.255.252 # return [test-Vlanif1588]
import ops,sys,os,re def ops_condition (ops): value, descri_str = ops.cli.subscribe("cli1", "start", enter=True, sync=False,async_skip=True, sync_wait=60) value1, descri_str1 = ops.cli.subscribe("cli2", "rollback", enter=True, sync=False,async_skip=True, sync_wait=60) value2, descri_str2 = ops.cli.subscribe("cli3", "end", enter=True, sync=False,async_skip=True, sync_wait=60) value10, err_str10 = ops.correlate("cli1 or cli2 or cli3") return 0 def ops_execute (ops): key,value = ops.environment.get('_cli_command') if key =="start": #value, descri_str = ops.terminal.write(key, vty="all") handle, err_desp = ops.cli.open() ops.cli.execute(handle,"system-view") ops.cli.execute(handle,"ospf") ops.cli.execute(handle,"ar 0") ops.cli.execute(handle,"vlan 1587") ops.cli.execute(handle,"interface vlan 1587") ops.cli.execute(handle,"ip address 10.35.0.33 30") ops.cli.execute(handle,"ospf enable area 0") ops.cli.execute(handle,"interface XGigabitEthernet 0/0/5") ops.cli.execute(handle,"port link-type trunk") ops.cli.execute(handle,"undo port trunk allow-pass vlan 1") ops.cli.execute(handle,"port trunk allow-pass vlan 1587") ops.cli.execute(handle,"quit") result = ops.cli.close(handle) elif key =="rollback": handle, err_desp = ops.cli.open() ops.cli.execute(handle,"system-view") ops.cli.execute(handle,"undo interface vlan 1587") ops.cli.execute(handle,"undo vlan 1587") ops.cli.execute(handle,"interface XGigabitEthernet 0/0/5") ops.cli.execute(handle,"undo port trunk allow-pass vlan 1587") ops.cli.execute(handle,"undo port link-type") ops.cli.execute(handle,"quit") result = ops.cli.close(handle) elif key =='end': handle, err_desp = ops.cli.open() ops.cli.execute(handle,"system-view") ops.cli.execute(handle,"ops") ops.cli.execute(handle,"undo script-assistant python 20211015.py") ops.cli.execute(handle,"quit") ops.cli.execute(handle,"quit") ops.cli.execute(handle,"ops uninstall file 20211015.py") ops.cli.execute(handle,"delete 20211015.py") ops.cli.execute(handle,"y") result = ops.cli.close(handle)
测试
[test]dis vlan 1587 Error: The VLAN does not exist. [test]start [test]dis vlan 1587 -------------------------------------------------------------------------------- U: Up; D: Down; TG: Tagged; UT: Untagged; MP: Vlan-mapping; ST: Vlan-stacking; #: ProtocolTransparent-vlan; *: Management-vlan; -------------------------------------------------------------------------------- VID Type Ports -------------------------------------------------------------------------------- 1587 common TG:XGE0/0/5(D) VID Status Property MAC-LRN Statistics Description -------------------------------------------------------------------------------- 1587 enable default enable disable VLAN 1587 [test]dis cu int vlan 1587 # interface Vlanif1587 ip address 10.35.0.33 255.255.255.252 ospf enable 1 area 0.0.0.0 # return [test]rollback [test]dis vlan 1587 Error: The VLAN does not exist. [test]end [test]dis ops assistant current ------------------------------------------------------------------ Assistant State Condition ------------------------------------------------------------------ lldp.py ready multi dangerouscli.py ready multi ospfroute.py ready URM ------------------------------------------------------------------
华为ops核心思想
调用OPS API配置侦听事件,编写事件所触发的执行脚本,命令行能实现的功能都可以写入脚本,也可以读取系统变量来动态执行命令