The documentation set for this product strives to use bias-free language. For the purposes of this documentation set, bias-free is defined as language that does not imply discrimination based on age, disability, gender, racial identity, ethnic identity, sexual orientation, socioeconomic status, and intersectionality. Exceptions may be present in the documentation due to language that is hardcoded in the user interfaces of the product software, language used based on RFP documentation, or language that is used by a referenced third-party product. Learn more about how Cisco is using Inclusive Language.
There are no specific requirements for this document.
The information in this document is based on these software and hardware versions:
switch(config)# feature nxsdk
switch(config)# feature bash-shell
switch(config)# run bash
bash-4.2$ vi /isan/bin/nxsdk-app.py
Note: Best practice is to create Python files in the /isan/bin/ directory. Python files need execution permissions in order to run - do not place Python files in the /bootflash directory or any of its subdirectories.
Note: It is not required to create and edit Python files through NX-OS. The developer may create the application using their local environment and transfer the completed files to the device using a file transfer protocol of their choice. However, it might be more efficient for the developer to debug and troubleshoot their script using NX-OS utilities.
sdkThread Function
Note: Starting from NX-SDK v1.5.0, a third Boolean parameter can be passed into the NxSdk.getSdkInst method, which enables Advanced Exceptions when True and disables Advanced Exceptions when False. This method is documented here .
Some commonly-used methods include:
Note: The R_JSON and R_XML data formats only work if the command supports output in those formats. In NX-OS, you can verify whether a command supports output in a particular data format by piping the output to the requested data format. If the piped command returns meaningful output, then that data format is supported. For example, if you run show mac address-table dynamic | json in NX-OS returns JSON output, then the R_JSON data format is supported in NX-SDK as well.
Some optional methods that can be helpful are:
N9K-C93180LC-EX# show Tra?
track Tracking information
Transceiver_DOM.py Returns all interfaces with DOM-capable transceivers inserted
In a Python application with the use of NX-SDK, custom CLI commands are created and defined within the sdkThread function. There are two types of commands: Show commands, and Config commands.
These two methods allow the creation of show commands and config commands respectively:
Note: This command is a subclass of cliP.newCliCmd("cmd_type", "cmd_name", "syntax") where cmd_type is either CONF_CMD or SHOW_CMD (depending on the type of command being configured), cmd_name is a unique name for the command internal to the custom NX-SDK application, and syntax describes what keywords and parameters can be used in the command. Because of this, the API documentation for this command might be more helpful for reference.
Note: This command is a subclass of cliP.newCliCmd("cmd_type", "cmd_name", "syntax") where cmd_type is either CONF_CMD or SHOW_CMD (it depends on the type of command that is configured), cmd_name is a unique name for the command internal to the custom NX-SDK application, and syntax describes what keywords and parameters can be used in the command. Because of this, the API documentation for this command might be more helpful for reference.
Both types of commands have two different components: Parameters and Keywords:
1. Parameters are values used to change the results of the command. For example, in the command show ip route 192.168.1.0, there is a route keyword followed by a parameter that accepts an IP address, which specifies that only routes that include the provided IP address should be shown.
2. Keywords change the results of the command through their presence alone. For example, in the command show mac address-table dynamic, there is a dynamic keyword, which specifies that only dynamically-learned MAC addresses are to be displayed.
Both components are defined in the syntax of an NX-SDK command when it is created. Methods for the NxCliCmd object exist to modify the specific implementation of both the components.
In order to view code examples of commonly-used command components, view the Custom CLI Command Examples section of this document.
After custom CLI commands have been created, an object from the pyCmdHandler class described later in this document needs to be created and set as the CLI callback handler object for the NxCliParser object. This is demonstrated as follows:
cmd_handler = pyCmdHandler()
cliP.setCmdHandler(cmd_handler)
Then, the NxCliParser object needs to be added to the NX-OS CLI parser tree so that custom CLI commands are visible to the user. This is done with the cliP.addToParseTree() command, where cliP is the NxCliParser object returned by the sdk.getCliParser() method.
sdkThread Function Example
Here is an example of a typical sdkThread function with the use of the functions explained previously. This function (among others within a typical custom NX-SDK Python application) utilizes global variables, which are instantiated on script execution.
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)
The pyCmdHandler class is inherited from the NxCmdHandler class within the nx_sdk_py library. The postCliCb(self, clicmd) method defined within the pyCmdHandler class is called whenever CLI commands that originate from an NX-SDK application. Thus, the postCliCb(self, clicmd) method is where you define how the custom CLI commands defined within the sdkThread function behave on the device.
The postCliCb(self, clicmd) function returns a Boolean value. If True is returned, then it is presumed that the command has been executed successfully. False should be returned if the command did not execute successfully for any reason.
The clicmd parameter uses the unique name that was defined for the command when it was created in the sdkThread function. For example, if you create a new show command with a unique name of show_xcvr_dom, then it is recommended to refer to this command by the same name in the postCliCb(self, clicmd) function after you have checked to see if the clicmd argument's name contains show_xcvr_dom. It is demonstrated here:
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()
If a command that utilizes parameters is created, then you will most likely need to use those parameters at some point in the postCliCb(self, clicmd) function. This can be done with the clicmd.getParamValue("<parameter>") method, where <parameter> is the name of the command parameter that you wish to get the value of enclosed by angular brackets (<>). This method is documented here. However, the value returned by this function needs to be converted to the type that you need. This can be done with these methods:
The postCliCb(self, clicmd) function (or any subsequent functions) will also typically be where show command output is printed to the console. This is done with the clicmd.printConsole() method.
Note: If the application encounters an error, unhandled exception, or otherwise suddenly exits, then output from the clicmd.printConsole() function will not be displayed at all. For this reason, best practice when you debug your Python application is to either log debug messages to the syslog with the use of an NxTrace object returned by the sdk.getTracer() method, or use print statements and execute the application via the Bash shell's /isan/bin/python binary.
pyCmdHandler Class Example
The following code serves as an example for the pyCmdHandler class described above. This code is taken from the ip_move.py file in the ip-movement NX-SDK application available here. The purpose of this application is to track the movement of a user-defined IP address across interfaces of a Nexus device. To do this, the code finds the MAC address of the IP address input through the <ip> parameter within the device's ARP cache, then verifies which VLAN that MAC address resides in using the device's MAC address table. Using this MAC and VLAN, the show system internal l2fm l2dbg macdb address <mac> vlan <vlan> command displays a list of SNMP interface indexes that this combination has recently been associated with. The code then uses the show interface snmp-ifindex command to translate recent SNMP interface indexes into human-legible interface names.
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
This section showcases some examples of the syntax parameter used when you create custom CLI commands with the cliP.newShowCmd() or the cliP.newConfigCmd() methods, where cliP is the NxCliParser object returned by the sdk.getCliParser() method.
Note: Support for syntax with opening and closing parentheses ("(" and ")") is introduced in NX-SDK v1.5.0, included in NX-OS Release 7.0(3)I7(3). It is assumed that the user utilizes NX-SDK v1.5.0 when they follow any of these given examples that include syntax utilizing opening and closing parentheses.
This show command takes a single keyword mac and adds a helper string of Shows 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")
This show command takes a single parameter <mac>. The enclosing angle brackets around the word mac signify that this is a parameter. A helper string of MAC address to check for misprogramming is added to the parameter. The nx_sdk_py.P_MAC_ADDR parameter in the nx_cmd.updateParam() method is used to define the type of the parameter as a MAC address, which prevents end user input of another type, such as a string, integer, or IP address.
nx_cmd = cliP.newShowCmd("show_misprogrammed_mac", "<mac>")
nx_cmd.updateParam("<mac>", "MAC address to check for misprogramming", nx_sdk_py.P_MAC_ADDR)
This show command may optionally take a single keyword [mac]. The enclosing brackets around the word mac signify that this keyword is optional. A helper string of Shows 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" )
This show command may optionally take a single parameter [<mac>]. The enclosing brackets around the word < mac > signify that this parameter is optional. The enclosing angle brackets around the word mac signify that this is a parameter. A helper string of MAC address to check for misprogramming is added to the parameter. The nx_sdk_py.P_MAC_ADDR parameter in the nx_cmd.updateParam() method is used to define the type of the parameter as a MAC address, which prevents end user input of another type, such as a string, integer, or IP address.
nx_cmd = cliP.newShowCmd("show_misprogrammed_mac", "[<mac>]")
nx_cmd.updateParam("<mac>", "MAC address to check for misprogramming", nx_sdk_py.P_MAC_ADDR)
This show command takes a single keyword mac immediately followed by the parameter <mac-address>. The enclosing angle brackets around the word mac-address signify that this is a parameter. A helper string of Check MAC address for misprogramming is added to the keyword. A helper string of MAC address to check for misprogramming is added to the parameter. The nx_sdk_py.P_MAC_ADDR parameter in the nx_cmd.updateParam() method is used in order to define the type of the parameter as a MAC address, which prevents end user input of another type, such as a string, integer, or IP address.
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)
This show command can take one of two keywords, both of which have two different parameters following them. The first keyword mac has a parameter of <mac-address>, and the second keyword ip has a parameter of <ip-address>. The enclosing angle brackets around the words mac-address and ip-address signify that they are parameters. A helper string of Check MAC address for misprogramming is added to the mac keyword. A helper string of MAC address to check for misprogramming is added to the <mac-address> parameter. The nx_sdk_py.P_MAC_ADDR parameter in the nx_cmd.updateParam() method is used to define the type of the <mac-address> parameter as a MAC address, which prevents the end user input of another type, such as a string, integer, or IP address. A helper string of Check IP address for misprograming is added to the ip keyword. A helper string of IP address to check for misprogramming is added to the <ip-address> parameter. The nx_sdk_py.P_IP_ADDR parameter in the nx_cmd.updateParam() method is used to define the type of the <ip-address> parameter as an IP address, which prevents the end user input of another type, such as a string, integer, or IP address.
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)
This show command can take one of two keywords, both of which have two different parameters following them. The first keyword mac has a parameter of <mac-address>, and the second keyword ip has a parameter of <ip-address>. The enclosing angle brackets around the words mac-address and ip-address signify that they are parameters. A helper string of Check MAC address for misprogramming is added to the mac keyword. A helper string of MAC address to check for misprogramming is added to the <mac-address> parameter. The nx_sdk_py.P_MAC_ADDR parameter in the nx_cmd.updateParam() method is used to define the type of the <mac-address> parameter as a MAC address, which prevents the end user input of another type, such as a string, integer, or IP address. A helper string of Check IP address for misprograming is added to the ip keyword. A helper string of IP address to check for misprogramming is added to the <ip-address> parameter. The nx_sdk_py.P_IP_ADDR parameter in the nx_cmd.updateParam() method is used to define the type of the <ip-address> parameter as an IP address, which prevents the end user input of another type, such as a string, integer, or IP address. This show command might optionally take a keyword [clear]. A helper string Clears addresses detected to be misprogrammed is added to this optional keyword.
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")
This show command can take one of two keywords, both of which have two different parameters following them. The first keyword mac has a parameter of <mac-address>, and the second keyword ip has a parameter of <ip-address>. The enclosing angle brackets around the words mac-address and ip-address signify that they are parameters. A helper string of Check MAC address for misprogrammingis added to the mac keyword. A helper string of MAC address to check for misprogramming is added to the <mac-address> parameter. The nx_sdk_py.P_MAC_ADDR parameter in the nx_cmd.updateParam() method is used to define the type of the <mac-address> parameter as a MAC address, which prevents the end user input of another type, such as a string, integer, or IP address. A helper string of Check IP address for misprograming is added to the ip keyword. A helper string of IP address to check for misprogramming is added to the <ip-address> parameter. The nx_sdk_py.P_IP_ADDR parameter in the nx_cmd.updateParam() method is used to define the type of the <ip-address> parameter as an IP address, which prevents the end user input of another type, such as a string, integer, or IP address. This show command might optionally take a parameter [<module>]. A helper string Only clear addresses on specified module is added to this optional parameter.
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)
Once an NX-SDK Python application has been created, it will often need to be debugged. NX-SDK informs you in case there are any syntax errors in your code, but because the Python NX-SDK library utilizes SWIG to translate C++ libraries to Python libraries, any exceptions encountered at the time of the code execution result in an application core dump similar to this:
terminate called after throwing an instance of 'Swig::DirectorMethodException'
what(): SWIG director method error. Error detected when calling 'NxCmdHandler.postCliCb'
Aborted (core dumped)
Due to the ambiguous nature of this error message, best practice to debug Python applications is to log debug messages to the syslog with the use of an NxTrace object returned by the sdk.getTracer() method. This is demonstrated as follows:
#! /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")
If logging debug messages to the syslog is not an option, an alternative method is to use print statements and execute the application via the Bash shell's /isan/bin/python binary. However, the output from these print statements will only be visible when executed in this manner - running the application through the VSH shell does not produce any output. An example of utilizing print statements is shown here:
#! /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")
Once a Python application has been fully tested in the Bash shell and is ready for deployment, the application should be installed into production through VSH. This allows the application to persist when the device reloads or when system switchover occurs in a dual-supervisor scenario. In order to deploy an application through VSH, you need to create an RPM package with the use of an NX-SDK and ENXOS SDK build environment. Cisco DevNet provides a Docker image that allows for easy RPM package creation.
Note: For assistance in order to install Docker on your specific operating system, refer to Docker's installation documentation.
On a Docker-capable host, pull the image version of your choice with the docker pull dockercisco/nxsdk:<tag> command, where <tag> is the tag of the image version of your choice. You can view the available image versions and their corresponding tags here. This is demonstrated with the v1 tag here:
docker pull dockercisco/nxsdk:v1
Start a container named nxsdk from this image and attach to it. If the tag of your choice is different, substitute v1 for your tag:
docker run -it --name nxsdk dockercisco/nxsdk:v1 /bin/bash
Update to the latest version of NX-SDK and navigate to the NX-SDK directory, then pull the latest files from git:
cd /NX-SDK/
git pull
If you need to use an older version of NX-SDK, you can clone the NX-SDK branch with the use of the respective version tag with the git clone -b v<version> https://github.com/CiscoDevNet/NX-SDK.git command, where <version> is the version of NX-SDK you need. This is demonstrated here with NX-SDK v1.0.0:
cd /
rm -rf /NX-SDK
git clone -b v1.0.0 https://github.com/CiscoDevNet/NX-SDK.git
Next, transfer your Python application to the Docker container. There are a few different ways to do this.
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
Next, use the rpm_gen.py script located in /NX-SDK/scripts/ in order to create an RPM package from the Python application. This script has one required argument, and two required switches:
Note: The filename does not need to contain any file extensions, such as .py. In this example, if the filename was python_app instead of python_app.py, the RPM package would be generated without an issue.
Usage of the rpm_gen.py script is demonstrated here.
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
The filepath to the RPM package is indicated in the final line of the rpm_gen.py script output. This file must be copied off of the Docker container onto the host so that it can be transferred to the Nexus device that you wish to run the application on. After you exit the Docker container, it can be done easily with the docker cp <container>:<container_filepath> <host_filepath> command, where <container> is the name of the NX-SDK Docker container (in this case, nxsdk), <container_filepath> is the full filepath of the RPM package inside the container (in this case, /NX-SDK/rpm/RPMS/test_python_app-1.0-1.0.0.x86_64.rpm), and <host_filepath> is the full filepath on our Docker host where the RPM package is to be transferred to (in this case, /root/). This command is demonstrated here:
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
Transfer this RPM package to the Nexus device with the use of your preferred method of file transfer. Once the RPM package is on the device, it must be installed and activated similarly to a SMU. This is demonstrated as follows, under the assumption that the RPM package was transferred to the bootflash of the device.
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
Note: When you install the RPM package with the install add command, include the storage device and exact filename of the package. When you activate the RPM package after installation, do not include the storage device and filename - use the name of the package itself. You can verify the package name with the show install inactive command.
Once the RPM package is activated, you can start the application with NX-SDK with the nxsdk service <application-name> configuration command, where <application-name> is the name of the Python filename (and, subsequently, the application) that was defined when rpm_gen.py script was used earlier. This is demonstrated as follows:
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
You can verify that the application is up and has started to run with the show nxsdk internal service command:
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
You can also verify that custom CLI commands created by this application are accessible in NX-OS:
N9K-C93180LC-EX# show test? test_python_app Nexus Sdk Application