此产品的文档集力求使用非歧视性语言。在本文档集中,非歧视性语言是指不隐含针对年龄、残障、性别、种族身份、族群身份、性取向、社会经济地位和交叉性的歧视的语言。由于产品软件的用户界面中使用的硬编码语言、基于 RFP 文档使用的语言或引用的第三方产品使用的语言,文档中可能无法确保完全使用非歧视性语言。 深入了解思科如何使用包容性语言。
思科采用人工翻译与机器翻译相结合的方式将此文档翻译成不同语言,希望全球的用户都能通过各自的语言得到支持性的内容。 请注意:即使是最好的机器翻译,其准确度也不及专业翻译人员的水平。 Cisco Systems, Inc. 对于翻译的准确性不承担任何责任,并建议您总是参考英文原始文档(已提供链接)。
本文档没有任何特定的要求。
本文档中的信息基于以下软件和硬件版本:
switch(config)# feature nxsdk
switch(config)# feature bash-shell
switch(config)# run bash
bash-4.2$ vi /isan/bin/nxsdk-app.py
注意:最佳实践是在/isan/bin/目录中创建Python文件。Python文件需要执行权限才能运行 — 请勿将Python文件放置在/bootflash目录或其任何子目录中。
注意:不需要通过NX-OS创建和编辑Python文件。开发人员可以使用他们的本地环境创建应用程序,并使用他们选择的文件传输协议将完成的文件传输到设备。但是,开发人员使用NX-OS实用程序调试和排除脚本故障可能更加有效。
sdkThread函数
注意:从NX-SDK v1.5.0开始,第三个布尔参数可以传递到NxSdk.getSdkInst方法,该方法在为True时启用高级异常,在为False时禁用高级异常。此方法记录在此处。
一些常用方法包括:
注意:仅当命令支持以这些格式输出时,R_JSON和R_XML数据格式才起作用。在NX-OS中,可以通过将输出管道到请求的数据格式来验证命令是否支持特定数据格式的输出。如果piped命令返回有意义的输出,则支持该数据格式。例如,如果运行show mac address-table dynamic | NX-OS中的json返回JSON输出,NX-SDK也支持R_JSON数据格式。
一些有用的可选方法有:
N9K-C93180LC-EX# show Tra?
track Tracking information
Transceiver_DOM.py Returns all interfaces with DOM-capable transceivers inserted
在使用NX-SDK的Python应用中,自定义CLI命令是在sdkThread函数中创建和定义的。有两种类型的命令:Show命令和Config命令。
这两种方法分别允许创建show命令和config命令:
注意:此命令是cliP.newCliCmd("cmd_type"、"cmd_name"、"syntax")的子类,其中cmd_type为CONF_CMD 或SHOW_CMD (取决于所配置的命令类型),cmd_name是自定义NX-SDK应用程序内部命令的唯一名称,语法描述了可在命令中使用的关键字和参数。因此,此命令的API文档可能更有助于参考。
注意:此命令是cliP.newCliCmd("cmd_type"、"cmd_name"、"syntax")的子类,其中cmd_type为CONF_CMD或SHOW_CMD(取决于配置的命令类型),cmd_name是自定义NX-SDK应用程序内部命令的唯一名称,语法描述了可在命令中使用的关键字和参数。因此,此命令的API文档可能更有助于参考。
两种命令都有两个不同的组件:参数和关键字:
1. 参数是用于更改命令结果的值。例如,在命令show ip route 192.168.1.0中,有一个route关键字后跟一个接受IP地址的参数,该参数指定只显示包含所提供IP地址的路由。
2.关键字通过它们单独存在来更改命令的结果。例如,在show mac address-table dynamic命令中,有一个dynamic关键字,该关键字指定仅显示动态获取的MAC地址。
这两个组件在NX-SDK命令创建时的语法中定义。NxCliCmd对象的方法可用于修改两个组件的特定实施。
要查看常用命令组件的代码示例,请查看本文档的自定义CLI命令示例部分。
创建自定义CLI命令后,需要创建来自本文档后面所述的pyCmdHandler类的对象,并将其设置为NxCliParser对象的CLI回调处理程序对象。演示如下:
cmd_handler = pyCmdHandler()
cliP.setCmdHandler(cmd_handler)
然后,需要将NxCliParser对象添加到NX-OS CLI解析器树中,以便用户能够看到自定义CLI命令。这通过cliP.addToParseTree()命令完成,其中cliP是由sdk.getCliParser()方法返回的NxCliParser对象。
sdkThread函数示例
以下是使用前面介绍的函数的典型sdkThread函数的示例。此函数(典型自定义NX-SDK Python应用中的其他函数)使用全局变量,这些变量在脚本执行时实例化。
cliP = ""
sdk = ""
event_hdlr = ""
tmsg = ""
def sdkThread():
global cliP, sdk, event_hdlr, tmsg
sdk = nx_sdk_py.NxSdk.getSdkInst(len(sys.argv), sys.argv)
if not sdk:
return
sdk.setAppDesc("Returns all interfaces with DOM-capable transceivers inserted")
tmsg = sdk.getTracer()
tmsg.event("[{}] Started service".format(sdk.getAppName()))
cliP = sdk.getCliParser()
nxcmd = cliP.newShowCmd("show_port_bw_util_cmd", "port bw utilization [<port>]")
nxcmd.updateKeyword("port", "Port Information")
nxcmd.updateKeyword("bw", "Port Bandwidth Information")
nxcmd.updateKeyword("utilization", "Port BW utilization in (%)")
nxcmd.updateParam("<port>", "Optional Filter Port Ex) Ethernet1/1", nx_sdk_py.P_INTERFACE)
nxcmd1 = cliP.newConfigCmd("port_bw_threshold_cmd", "port bw threshold <threshold>")
nxcmd1.updateKeyword("threshold", "Port BW Threshold in (%)")
int_attr = nx_sdk_py.cli_param_type_integer_attr()
int_attr.min_val = 1;
int_attr.max_val = 100;
nxcmd1.updateParam("<threshold>", "Threshold Limit. Default 50%", nx_sdk_py.P_INTEGER, int_attr, len(int_attr))
mycmd = pyCmdHandler()
cliP.setCmdHandler(mycmd)
cliP.addToParseTree()
sdk.startEventLoop()
# If sdk.stopEventLoop() is called or application is removed from VSH...
tmsg.event("Service Quitting...!")
nx_sdk_py.NxSdk.__swig_destroy__(sdk)
pyCmdHandler类继承自nx_sdk_py库中的NxCmdHandler类。每当从NX-SDK应用程序发出的CLI命令时,都会调用pyCmdHandler类中定义的postCliCb(self, clicmd)方法。因此,postCliCb(self, clicmd)方法用于定义sdkThread函数内定义的自定义CLI命令在设备上的行为。
postCliCb(self, clicmd)函数返回布尔值。如果返回True,则假定命令已成功执行。如果由于任何原因命令未成功执行,应返回False。
clicmd参数使用在sdkThread函数中创建命令时为该命令定义的唯一名称。例如,如果您创建了一个具有唯一名称show_xcvr_dom的新show命令,则在检查了postCliCb(self, clicmd)函数的名称是否包含show_xcvr_dom后,建议使用相同的名称引用此命令。这里演示了这一点:
def sdkThread():
<snip>
sh_xcvr_dom = cliP.newShowCmd("show_xcvr_dom", "dom")
sh_xcvr_dom.updateKeyword("dom", "Show all interfaces with transceivers that are DOM-capable")
</snip>
class pyCmdHandler(nx_sdk_py.NxCmdHandler):
def postCliCb(self, clicmd):
if "show_xcvr_dom" in clicmd.getCmdName():
get_dom_capable_interfaces()
如果创建了使用参数的命令,则您很可能需要在postCliCb(self, clicmd)函数的某个点使用这些参数。这可以通过clicmd.getParamValue("<parameter>")方法完成,其中<parameter>是要获取用尖括号(<>)括起来的值的命令参数的名称。 此方法记录在此处。但是,此函数返回的值需要转换为所需的类型。这可以通过以下方法实现:
postCliCb(self, clicmd)功能(或任何后续功能)通常也是在将show命令输出打印到控制台的地方。这通过clicmd.printConsole()方法完成。
注意:如果应用程序遇到错误、未处理的异常或者突然退出,则根本不会显示clicmd.printConsole()函数的输出。因此,调试Python应用程序的最佳做法是使用由sdk.getTracer()方法返回的NxTrace对象将调试消息记录到系统日志,或使用打印语句并通过Bash shell的/isan/bin/python二进制文件执行应用程序。
pyCmdHandler类示例
以下代码用作上述pyCmdHandler类的示例。此代码取自此处提供的ip-motion NX-SDK应用中的ip_move.py文件。此应用程序的目的是跟踪用户定义IP地址在Nexus设备接口上的移动。为此,该代码通过设备的ARP缓存中的<ip>参数查找输入的IP地址的MAC地址,然后使用设备的MAC地址表验证MAC地址所在的VLAN。使用此MAC和VLAN,show system internal l2fm l2dbg macdb address <mac> vlan <vlan>命令显示最近与此组合关联的SNMP接口索引列表。然后,该代码使用show interface snmp-ifindex命令将最近的SNMP接口索引转换为易于理解的接口名称。
class pyCmdHandler(nx_sdk_py.NxCmdHandler):
def postCliCb(self, clicmd):
global cli_parser
if "show_ip_movement" in clicmd.getCmdName():
target_ip = nx_sdk_py.void_to_string(clicmd.getParamValue("<ip>"))
target_mac = get_mac_from_arp(cli_parser, clicmd, target_ip)
mac_vlan = ""
if target_mac:
mac_vlan = get_vlan_from_cam(cli_parser, clicmd, target_mac)
if mac_vlan:
find_mac_movement(cli_parser, clicmd, target_mac, mac_vlan)
else:
print("No entires in MAC address table")
clicmd.printConsole("No entries in MAC address table for {}".format(target_mac))
else:
clicmd.printConsole("No entries in ARP table for {}".format(target_ip))
return True
def get_mac_from_arp(cli_parser, clicmd, target_ip):
exec_cmd = "show ip arp {}".format(target_ip)
arp_cmd = cli_parser.execShowCmd(exec_cmd, nx_sdk_py.R_JSON)
if arp_cmd:
try:
arp_json = json.loads(arp_cmd)
except ValueError as exc:
return None
count = int(arp_json["TABLE_vrf"]["ROW_vrf"]["cnt-total"])
if count:
intf = arp_json["TABLE_vrf"]["ROW_vrf"]["TABLE_adj"]["ROW_adj"]
if intf.get("ip-addr-out") == target_ip:
target_mac = intf["mac"]
clicmd.printConsole("{} is currently present in ARP table, MAC address {}\n".format(target_ip, target_mac))
return target_mac
else:
return None
else:
return None
else:
return None
def get_vlan_from_cam(cli_parser, clicmd, target_mac):
exec_cmd = "show mac address-table address {}".format(target_mac)
mac_cmd = cli_parser.execShowCmd(exec_cmd, nx_sdk_py.R_JSON)
if mac_cmd:
try:
cam_json = json.loads(mac_cmd)
except ValueError as exc:
return None
mac_entry = cam_json["TABLE_mac_address"]["ROW_mac_address"]
if mac_entry:
if mac_entry["disp_mac_addr"] == target_mac:
egress_intf = mac_entry["disp_port"]
mac_vlan = mac_entry["disp_vlan"]
clicmd.printConsole("{} is currently present in MAC address table on interface {}, VLAN {}\n".format(target_mac, egress_intf, mac_vlan))
return mac_vlan
else:
return None
else:
return None
else:
return None
def find_mac_movement(cli_parser, clicmd, target_mac, mac_vlan):
exec_cmd = "show system internal l2fm l2dbg macdb address {} vlan {}".format(target_mac, mac_vlan)
l2fm_cmd = cli_parser.execShowCmd(exec_cmd)
if l2fm_cmd:
event_re = re.compile(r"^\s+(\w{3}) (\w{3}) (\d+) (\d{2}):(\d{2}):(\d{2}) (\d{4}) (0x\S{8}) (\d+)\s+(\S+) (\d+)\s+(\d+)\s+(\d+)")
unique_interfaces = []
l2fm_events = l2fm_cmd.splitlines()
for line in l2fm_events:
res = re.search(event_re, line)
if res:
day_name = res.group(1)
month = res.group(2)
day = res.group(3)
hour = res.group(4)
minute = res.group(5)
second = res.group(6)
year = res.group(7)
if_index = res.group(8)
db = res.group(9)
event = res.group(10)
src=res.group(11)
slot = res.group(12)
fe = res.group(13)
if "MAC_NOTIF_AM_MOVE" in event:
timestamp = "{} {} {} {}:{}:{} {}".format(day_name, month, day, hour, minute, second, year)
intf_dict = {"if_index": if_index, "timestamp": timestamp}
unique_interfaces.append(intf_dict)
if not unique_interfaces:
clicmd.printConsole("No entries for {} in L2FM L2DBG\n".format(target_mac))
if len(unique_interfaces) == 1:
clicmd.printConsole("{} has not been moving between interfaces\n".format(target_mac))
if len(unique_interfaces) > 1:
clicmd.printConsole("{} has been moving between the following interfaces, from most recent to least recent:\n".format(target_mac))
unique_interfaces = get_snmp_intf_index(unique_interfaces)
clicmd.printConsole("\t{} - {} (Current interface)\n".format(unique_interfaces[-1]["timestamp"], unique_interfaces[-1]["intf_name"]))
for intf in unique_interfaces[-2::-1]:
clicmd.printConsole("\t{} - {}\n".format(intf["timestamp"], intf["intf_name"]))
def get_snmp_intf_index(if_index_dict_list):
global cli_parser
snmp_ifindex = cli_parser.execShowCmd("show interface snmp-ifindex", nx_sdk_py.R_JSON)
snmp_ifindex_json = json.loads(snmp_ifindex)
snmp_ifindex_list = snmp_ifindex_json["TABLE_interface"]["ROW_interface"]
for index_dict in if_index_dict_list:
index = index_dict["if_index"]
for ifindex_json in snmp_ifindex_list:
if index == ifindex_json["snmp-ifindex"]:
index_dict["intf_name"] = ifindex_json["interface"]
return if_index_dict_list
本部分显示使用cliP.newShowCmd()或cliP.newConfigCmd()方法创建自定义CLI命令时所用语法参数的一些示例,其中cliP是sdk.getCliParser()方法返回的NxCliParser对象。
注意:NX-SDK v1.5.0(包含在NX-OS版本7.0(3)I7(3)中)引入了支持带左括号和右括号(“(”和“)”)的语法。 假设用户遵循这些给定示例中的任何一个(包括使用左括号和右括号语法)时,会使用NX-SDK v1.5.0。
此show命令采用单个关键字mac并将帮助字符串Show all misprogrammed MAC addresses on this device to the keyword添加到该关键字。
nx_cmd = cliP.newShowCmd("show_misprogrammed", "mac")
nx_cmd.updateKeyword("mac", "Shows all misprogrammed MAC addresses on this device")
此show命令采用单个参数<mac>。单词mac的尖括号表示这是一个参数。MAC地址的帮助字符串会添加到参数中,以检查是否存在编程错误。nx_cmd.updateParam()方法中的nx_sdk_py.P_MAC_ADDR.参数用于将参数的类型定义为MAC地址,这可以防止最终用户输入其他类型(如字符串、整数或IP地址)。
nx_cmd = cliP.newShowCmd("show_misprogrammed_mac", "<mac>")
nx_cmd.updateParam("<mac>", "MAC address to check for misprogramming", nx_sdk_py.P_MAC_ADDR)
此show命令可以选择使用单个关键字[mac]。mac一词的方括号表示此关键字是可选的。帮助字符串Show all misprogrammed MAC addresses on this device is added to the keyword。
nx_cmd = cliP.newShowCmd( "show_misprogrammed_mac" , "[mac]" )
nx_cmd.updateKeyword( "mac" , "Shows all misprogrammed MAC addresses on this device" )
此show命令可以选择采用单个参数[<mac>]。单词< mac >的括号表示此参数是可选的。单词mac的尖括号表示这是一个参数。MAC地址的帮助字符串会添加到参数中,以检查是否存在编程错误。nx_cmd.updateParam()方法中的nx_sdk_py.P_MAC_ADDR.参数用于将参数的类型定义为MAC地址,这可以防止最终用户输入其他类型(如字符串、整数或IP地址)。
nx_cmd = cliP.newShowCmd("show_misprogrammed_mac", "[<mac>]")
nx_cmd.updateParam("<mac>", "MAC address to check for misprogramming", nx_sdk_py.P_MAC_ADDR)
此show命令使用一个关键字mac,紧接着使用参数<mac-address>。单词mac-address的尖括号表示这是一个参数。将检查MAC地址是否误编程的帮助字符串添加到关键字。MAC地址的帮助字符串会添加到参数中,以检查是否存在编程错误。nx_cmd.updateParam()方法中的nx_sdk_py.P_MAC_ADDR.参数用于将参数的类型定义为MAC地址,这样可防止最终用户输入其他类型(如字符串、整数或IP地址)。
nx_cmd = cliP.newShowCmd("show_misprogrammed", "mac <mac-address>")
nx_cmd.updateKeyword("mac", "Check MAC address for misprogramming")
nx_cmd.updateParam("<mac-address>", "MAC address to check for misprogramming", nx_sdk_py.P_MAC_ADDR)
此show命令可以采用两个关键字之一,这两个关键字后面都跟有两个不同的参数。第一个关键字mac的参数为<mac-address>,第二个关键字ip的参数为<ip-address>。mac-address和ip-address两词周围的尖括号表示它们是参数。检查MAC地址是否误编程的帮助字符串被添加到mac关键字。用于检查误编程的MAC地址帮助字符串将添加到<mac-address>参数。nx_cmd.updateParam()方法中的nx_sdk_py.P_MAC_ADDR.参数用于将<mac-address>参数的类型定义为MAC地址,这可防止最终用户输入其他类型(如字符串、整数或IP地址)。检查IP地址是否编程错误的帮助字符串添加到ip关键字。用于检查误编程的IP地址帮助字符串将添加到<ip-address>参数中。nx_cmd.updateParam()方法中的nx_sdk_py.P_IP_ADDR.参数用于将<ip-address>参数的类型定义为IP地址,这可防止最终用户输入其他类型(如字符串、整数或IP地址)。
nx_cmd = cliP.newShowCmd("show_misprogrammed", "(mac <mac-address> | ip <ip-address>)")
nx_cmd.updateKeyword("mac", "Check MAC address for misprogramming")
nx_cmd.updateParam("<mac-address>", "MAC address to check for misprogramming", nx_sdk_py.P_MAC_ADDR)
nx_cmd.updateKeyword("ip", "Check IP address for misprogramming")
nx_cmd.updateParam("<ip-address>", "IP address to check for misprogramming", nx_sdk_py.P_IP_ADDR)
此show命令可以采用两个关键字之一,这两个关键字后面都跟有两个不同的参数。第一个关键字mac的参数为<mac-address>,第二个关键字ip的参数为<ip-address>。mac-address和ip-address两词周围的尖括号表示它们是参数。检查MAC地址是否误编程的帮助字符串被添加到mac关键字。用于检查误编程的MAC地址帮助字符串将添加到<mac-address>参数。nx_cmd.updateParam()方法中的nx_sdk_py.P_MAC_ADDR.参数用于将<mac-address>参数的类型定义为MAC地址,这可防止最终用户输入其他类型(如字符串、整数或IP地址)。检查IP地址是否编程错误的帮助字符串添加到ip关键字。用于检查误编程的IP地址帮助字符串将添加到<ip-address>参数中。nx_cmd.updateParam()方法中的nx_sdk_py.P_IP_ADDR.参数用于将<ip-address>参数的类型定义为IP地址,这可防止最终用户输入其他类型(如字符串、整数或IP地址)。此show命令可能会选择使用关键字[clear]。帮助字符串Clears addresses detected to be misprogrammed将添加到此可选关键字。
nx_cmd = cliP.newShowCmd("show_misprogrammed", "(mac <mac-address> | ip <ip-address>) [clear]")
nx_cmd.updateKeyword("mac", "Check MAC address for misprogramming")
nx_cmd.updateParam("<mac-address>", "MAC address to check for misprogramming", nx_sdk_py.P_MAC_ADDR)
nx_cmd.updateKeyword("ip", "Check IP address for misprogramming")
nx_cmd.updateParam("<ip-address>", "IP address to check for misprogramming", nx_sdk_py.P_IP_ADDR)
nx_cmd.updateKeyword("clear", "Clears addresses detected to be misprogrammed")
此show命令可以采用两个关键字之一,这两个关键字后面都跟有两个不同的参数。第一个关键字mac的参数为<mac-address>,第二个关键字ip的参数为<ip-address>。mac-address和ip-address两词周围的尖括号表示它们是参数。检查MAC地址是否编程错误的帮助字符串添加到mac关键字。用于检查误编程的MAC地址帮助字符串将添加到<mac-address>参数。nx_cmd.updateParam()方法中的nx_sdk_py.P_MAC_ADDR.参数用于将<mac-address>参数的类型定义为MAC地址,这可防止最终用户输入其他类型(如字符串、整数或IP地址)。检查IP地址是否编程错误的帮助字符串添加到ip关键字。用于检查误编程的IP地址帮助字符串将添加到<ip-address>参数中。nx_cmd.updateParam()方法中的nx_sdk_py.P_IP_ADDR.参数用于将<ip-address>参数的类型定义为IP地址,这可防止最终用户输入其他类型(如字符串、整数或IP地址)。此show命令可能选择性地采用参数[<module>]。帮助字符串Only clear addresses on specified module将添加到此可选参数。
nx_cmd = cliP.newShowCmd("show_misprogrammed", "(mac <mac-address> | ip <ip-address>) [<module>]")
nx_cmd.updateKeyword("mac", "Check MAC address for misprogramming")
nx_cmd.updateParam("<mac-address>", "MAC address to check for misprogramming", nx_sdk_py.P_MAC_ADDR)
nx_cmd.updateKeyword("ip", "Check IP address for misprogramming")
nx_cmd.updateParam("<ip-address>", "IP address to check for misprogramming", nx_sdk_py.P_IP_ADDR)
nx_cmd.updateParam("<module>", "Clears addresses detected to be misprogrammed", nx_sdk_py.P_INTEGER)
创建NX-SDK Python应用后,通常需要对其进行调试。如果代码中存在语法错误,NX-SDK会通知您,但由于Python NX-SDK库利用SWIG将C++库转换为Python库,因此代码执行时遇到的任何异常都会导致类似于以下内容的应用核心转储:
terminate called after throwing an instance of 'Swig::DirectorMethodException'
what(): SWIG director method error. Error detected when calling 'NxCmdHandler.postCliCb'
Aborted (core dumped)
由于此错误消息的性质不明确,调试Python应用程序的最佳做法是使用由sdk.getTracer()方法返回的NxTrace对象将调试消息记录到系统日志。演示如下:
#! /isan/bin/python
tracer = 0
def evt_thread():
<snip>
tracer = sdk.getTracer()
tracer.event("[NXSDK-APP][INFO] Started service")
<snip>
class pyCmdHandler(nx_sdk_py.NxCmdHandler):
def postCliCb(self, clicmd):
global tracer
tracer.event("[NXSDK-APP][DEBUG] Received command: {}".format(clicmd))
if "show_test_command" in clicmd.getCmdName():
tracer.event("[NXSDK-APP][DEBUG] `show_test_command` recognized")
如果无法将调试消息记录到系统日志中,另一种方法是使用print语句并通过Bash shell的/isan/bin/python二进制文件执行应用。但是,只有以这种方式执行时,才能看到这些print语句的输出 — 通过VSH外壳运行应用程序不会产生任何输出。此处显示了使用print语句的示例:
#! /isan/bin/python
tracer = 0
def evt_thread():
<snip>
print("[NXSDK-APP][INFO] Started service")
<snip>
class pyCmdHandler(nx_sdk_py.NxCmdHandler):
def postCliCb(self, clicmd):
print("[NXSDK-APP][DEBUG] Received command: {}".format(clicmd))
if "show_test_command" in clicmd.getCmdName():
print("[NXSDK-APP][DEBUG] `show_test_command` recognized")
一旦Python应用程序在Bash外壳中经过完全测试并做好部署准备,应通过VSH将该应用程序安装到生产环境中。这样,当设备重新加载时或在双管理引擎场景中发生系统切换时,应用将一直存在。要通过VSH部署应用,您需要使用NX-SDK和ENXOS SDK构建环境创建RPM包。Cisco DevNet提供一个Docker映像,可以轻松创建RPM包。
注意:有关在特定的操作系统上安装Docker的帮助,请参阅Docker的安装文档。
在支持Docker的主机上,使用docker pull dockercisco/nxsdk:<tag> 命令提取您选择的映像版本,其中<tag> 是您选择的映像版本的标记。您可以在此处查看可用的图像版本及其相应的标签。下面通过v1标记演示了这一点:
docker pull dockercisco/nxsdk:v1
从此映像启动名为nxsdk的容器,然后附加到该容器。如果您选择的标签不同,请用v1代替您的标签:
docker run -it --name nxsdk dockercisco/nxsdk:v1 /bin/bash
更新至最新版本的NX-SDK并导航至NX-SDK目录,然后从git中提取最新文件:
cd /NX-SDK/
git pull
如果需要使用较旧版本的NX-SDK,则可以使用相应的版本标记和git clone -b v<version> https://github.com/CiscoDevNet/NX-SDK.git命令来克隆NX-SDK分支,其中<version>是所需的NX-SDK版本。下面通过NX-SDK v1.0.0演示了这一点:
cd /
rm -rf /NX-SDK
git clone -b v1.0.0 https://github.com/CiscoDevNet/NX-SDK.git
接下来,将您的Python应用传输到Docker容器。有几种不同的方法可以做到这一点。
root@2dcbe841742a:~# exit
[root@localhost ~]# docker cp /app/python_app.py nxsdk:/root/
[root@localhost ~]# docker start nxsdk
nxsdk
[root@localhost ~]# docker attach nxsdk
root@2dcbe841742a:/# ls /root/
python_app.py
接下来,使用/NX-SDK/scripts/中的rpm_gen.py脚本,以便从Python应用程序创建RPM包。此脚本有一个必需的参数和两个必需的开关:
注意:文件名不需要包含任何文件扩展名,例如.py。在本示例中,如果文件名是python_app而不是python_app.py,则生成RPM软件包时不会出现问题。
此处演示了rpm_gen.py脚本的用法。
root@7bfd1714dd2f:~# python /NX-SDK/scripts/rpm_gen.py test_python_app -s /root/ -u #################################################################################################### Generating rpm package... <snip> RPM package has been built #################################################################################################### SPEC file: /NX-SDK/rpm/SPECS/test_python_app.spec RPM file : /NX-SDK/rpm/RPMS/test_python_app-1.0-1.0.0.x86_64.rpm
rpm_gen.py脚本输出的最后一行中指示了RPM软件包的文件路径。此文件必须从Docker容器复制到主机上,这样才能将其传输到要在其上运行应用程序的Nexus设备。退出Docker容器后,可以使用docker cp <container>:<container_filepath> <host_filepath>命令(其中<container>是NX-SDK Docker容器的名称(在本例中为nxsdk),<container_filepath>是RPM包在容器中的完整文件路径(在本例中为/NX-SDK/rpm/RPMS/test_python_app-1.0-1.0.0.x86_64.rpm),以及<host_filepath>是Docker主机上要向其传输RPM包的完整文件路径(在本例中为/root/)。 此命令如下所示:
root@7bfd1714dd2f:/# exit [root@localhost ~]# docker cp nxsdk:/NX-SDK/rpm/RPMS/test_python_app-1.0-1.0.0.x86_64.rpm /root/ [root@localhost ~]# ls /root/ anaconda-ks.cfg test_python_app-1.0-1.0.0.x86_64.rpm
使用首选的文件传输方法将此RPM软件包传输到Nexus设备。RPM软件包在设备上后,必须像安装SMU一样安装并激活该软件包。假设RPM软件包已传输到设备的bootflash,演示如下。
N9K-C93180LC-EX# install add bootflash:test_python_app-1.0-1.0.0.x86_64.rpm [####################] 100% Install operation 27 completed successfully at Tue May 8 06:40:13 2018 N9K-C93180LC-EX# install activate test_python_app-1.0-1.0.0.x86_64 [####################] 100% Install operation 28 completed successfully at Tue May 8 06:40:20 2018
注意:使用install add命令安装RPM软件包时,请包含存储设备和软件包的准确文件名。安装后激活RPM软件包时,请勿包含存储设备和文件名 — 请使用软件包本身的名称。您可以使用show install inactive命令验证软件包名称。
激活RPM软件包后,您可以使用NX-SDK和nxsdk service <application-name>配置命令启动应用程序,其中<application-name>是之前使用rpm_gen.py脚本时定义的Python文件名(以及随后的应用程序)的名称。演示如下:
N9K-C93180LC-EX# conf Enter configuration commands, one per line. End with CNTL/Z. N9K-C93180LC-EX(config)# nxsdk service-name test_python_app % This could take some time. "show nxsdk internal service" to check if your App is Started & Runnning
您可以使用show nxsdk internal service命令验证应用程序是否已启动并开始运行:
N9K-C93180LC-EX# show nxsdk internal service NXSDK Started/Temp unavailabe/Max services : 1/0/32 NXSDK Default App Path : /isan/bin/nxsdk NXSDK Supported Versions : 1.0 Service-name Base App Started(PID) Version RPM Package ------------------------- --------------- ----------------- ---------- ------------------------ test_python_app nxsdk_app4 VSH(23195) 1.0 test_python_app-1.0-1.0.0.x86_64
您还可以验证此应用创建的自定义CLI命令在NX-OS中是否可访问:
N9K-C93180LC-EX# show test? test_python_app Nexus Sdk Application
反馈