La documentazione per questo prodotto è stata redatta cercando di utilizzare un linguaggio senza pregiudizi. Ai fini di questa documentazione, per linguaggio senza di pregiudizi si intende un linguaggio che non implica discriminazioni basate su età, disabilità, genere, identità razziale, identità etnica, orientamento sessuale, status socioeconomico e intersezionalità. Le eventuali eccezioni possono dipendere dal linguaggio codificato nelle interfacce utente del software del prodotto, dal linguaggio utilizzato nella documentazione RFP o dal linguaggio utilizzato in prodotti di terze parti a cui si fa riferimento. Scopri di più sul modo in cui Cisco utilizza il linguaggio inclusivo.
Cisco ha tradotto questo documento utilizzando una combinazione di tecnologie automatiche e umane per offrire ai nostri utenti in tutto il mondo contenuti di supporto nella propria lingua. Si noti che anche la migliore traduzione automatica non sarà mai accurata come quella fornita da un traduttore professionista. Cisco Systems, Inc. non si assume alcuna responsabilità per l’accuratezza di queste traduzioni e consiglia di consultare sempre il documento originale in inglese (disponibile al link fornito).
Nessun requisito specifico previsto per questo documento.
Le informazioni fornite in questo documento si basano sulle seguenti versioni software e hardware:
switch(config)# feature nxsdk
switch(config)# feature bash-shell
switch(config)# run bash
bash-4.2$ vi /isan/bin/nxsdk-app.py
Nota: È buona norma creare i file Python nella directory /isan/bin/. I file Python necessitano di autorizzazioni di esecuzione per poter essere eseguiti - non collocare i file Python nella directory /bootflash o in una delle sue sottodirectory.
Nota: Non è necessario creare e modificare file Python tramite NX-OS. Lo sviluppatore può creare l'applicazione utilizzando il proprio ambiente locale e trasferire i file completati nel dispositivo utilizzando un protocollo di trasferimento file di sua scelta. Tuttavia, potrebbe essere più efficiente per lo sviluppatore eseguire il debug e risolvere i problemi relativi allo script utilizzando le utilità NX-OS.
Funzione sdkThread
Nota: A partire da NX-SDK v1.5.0, è possibile passare un terzo parametro booleano al metodo NxSdk.getSdkInst, che attiva Eccezioni avanzate quando è True e disattiva Eccezioni avanzate quando è False. Questo metodo è documentato qui .
Di seguito sono riportati alcuni metodi comunemente utilizzati.
Nota: I formati di dati R_JSON e R_XML funzionano solo se il comando supporta l'output in tali formati. In NX-OS è possibile verificare se un comando supporta l'output in un particolare formato dati reindirizzando l'output al formato dati richiesto. Se il comando piped restituisce un output significativo, il formato dei dati è supportato. Ad esempio, se si esegue show mac address-table dynamic | json in NX-OS restituisce l'output JSON, quindi il formato dati R_JSON è supportato anche in NX-SDK.
Alcuni metodi facoltativi che possono essere utili sono:
N9K-C93180LC-EX# show Tra?
track Tracking information
Transceiver_DOM.py Returns all interfaces with DOM-capable transceivers inserted
In un'applicazione Python con l'utilizzo di NX-SDK, i comandi CLI personalizzati vengono creati e definiti all'interno della funzione sdkThread. Esistono due tipi di comandi: Mostra comandi e Config comandi.
I due metodi seguenti consentono di creare rispettivamente i comandi show e config:
Nota: Questo comando è una sottoclasse di cliP.newCliCmd("cmd_type", "cmd_name", "syntax") dove cmd_type è CONF_CMD o SHOW_CMD (a seconda del tipo di comando configurato), cmd_name è un nome univoco per il comando interno all'applicazione NX-SDK personalizzata e syntax descrive le parole chiave e i parametri che possono essere utilizzati nel comando. Per questo motivo, la documentazione API per questo comando potrebbe essere più utile come riferimento.
Nota: Questo comando è una sottoclasse di cliP.newCliCmd("cmd_type", "cmd_name", "syntax") dove cmd_type è CONF_CMD o SHOW_CMD (dipende dal tipo di comando configurato), cmd_name è un nome univoco per il comando interno all'applicazione NX-SDK personalizzata e syntax descrive le parole chiave e i parametri che è possibile utilizzare nel comando. Per questo motivo, la documentazione API per questo comando potrebbe essere più utile come riferimento.
Entrambi i tipi di comandi hanno due componenti diversi: Parametri e parole chiave:
1. I parametri sono valori utilizzati per modificare i risultati del comando. Ad esempio, nel comando show ip route 192.168.1.0, è presente una parola chiave route seguita da un parametro che accetta un indirizzo IP, il quale specifica che devono essere visualizzate solo le route che includono l'indirizzo IP fornito.
2. Le parole chiave modificano i risultati del comando esclusivamente tramite la loro presenza. Ad esempio, nel comando show mac address-table dynamic, è presente una parola chiave dynamic che specifica che devono essere visualizzati solo gli indirizzi MAC appresi in modo dinamico.
Entrambi i componenti vengono definiti nella sintassi di un comando NX-SDK al momento della creazione. Esistono metodi per l'oggetto NxCliCmd per modificare l'implementazione specifica di entrambi i componenti.
Per visualizzare esempi di codice dei componenti dei comandi di uso comune, consultare la sezione Esempi di comandi CLI personalizzati in questo documento.
Dopo aver creato i comandi CLI personalizzati, è necessario creare un oggetto dalla classe pyCmdHandler descritta più avanti in questo documento e impostarlo come oggetto gestore di callback CLI per l'oggetto NxCliParser. La dimostrazione è la seguente:
cmd_handler = pyCmdHandler()
cliP.setCmdHandler(cmd_handler)
Quindi, è necessario aggiungere l'oggetto NxCliParser all'albero del parser CLI di NX-OS in modo che i comandi CLI personalizzati siano visibili all'utente. A tale scopo, è necessario utilizzare il comando cliP.addToParseTree(), dove cliP è l'oggetto NxCliParser restituito dal metodo sdk.getCliParser().
Esempio di funzione sdkThread
Di seguito è riportato un esempio di una tipica funzione sdkThread con l'utilizzo delle funzioni descritte in precedenza. Questa funzione (tra le altre all'interno di una tipica applicazione Python NX-SDK personalizzata) utilizza variabili globali, che vengono istanziate sull'esecuzione dello script.
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)
La classe pyCmdHandler viene ereditata dalla classe NxCmdHandler all'interno della libreria nx_sdk_py. Il metodo postCliCb(self, clicmd) definito nella classe pyCmdHandler viene chiamato ogni volta che i comandi CLI provengono da un'applicazione NX-SDK. Di conseguenza, il metodo postCliCb(self, clicmd) è il punto in cui si definisce il comportamento sul dispositivo dei comandi CLI personalizzati definiti nella funzione sdkThread.
La funzione postCliCb(self, clicmd) restituisce un valore booleano. Se viene restituito True, si presume che il comando sia stato eseguito correttamente. Il valore False deve essere restituito se il comando non è stato eseguito correttamente per qualsiasi motivo.
Il parametro clicmd utilizza il nome univoco definito per il comando al momento della creazione nella funzione sdkThread. Ad esempio, se si crea un nuovo comando show con un nome univoco show_xcvr_dom, è consigliabile fare riferimento a questo comando con lo stesso nome nella funzione postCliCb(self, clicmd) dopo aver verificato se il nome dell'argomento clicmd contiene show_xcvr_dom. La dimostrazione è la seguente:
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()
Se viene creato un comando che utilizza parametri, è molto probabile che sia necessario utilizzare tali parametri in un determinato punto della funzione postCliCb(self, clicmd). A tale scopo, è possibile utilizzare il metodo clicmd.getParamValue("<parameter>"), dove <parameter> è il nome del parametro del comando di cui si desidera ottenere il valore racchiuso tra parentesi angolari (<>). Questo metodo è documentato qui. Tuttavia, il valore restituito da questa funzione deve essere convertito nel tipo necessario. A tale scopo, è possibile utilizzare i metodi seguenti:
La funzione postCliCb(self, clicmd) (o qualsiasi funzione successiva) si trova generalmente anche dove l'output del comando show viene stampato sulla console. Questa operazione viene eseguita con il metodo clicmd.printConsole().
Nota: Se l'applicazione rileva un errore, un'eccezione non gestita o si chiude improvvisamente, l'output della funzione clicmd.printConsole() non verrà visualizzato. Per questo motivo, quando si esegue il debug dell'applicazione Python, è consigliabile registrare i messaggi di debug nel syslog utilizzando un oggetto NxTrace restituito dal metodo sdk.getTracer() oppure utilizzare le istruzioni print ed eseguire l'applicazione tramite il binario /isan/bin/python della shell Bash.
Esempio di classe pyCmdHandler
Il codice seguente funge da esempio per la classe pyCmdHandler descritta in precedenza. Questo codice è tratto dal file ip_move.py nell'applicazione ip-move NX-SDK disponibile qui. Lo scopo di questa applicazione è tenere traccia dello spostamento di un indirizzo IP definito dall'utente tra le interfacce di un dispositivo Nexus. A tale scopo, il codice trova l'indirizzo MAC dell'indirizzo IP immesso tramite il parametro <ip> nella cache ARP del dispositivo, quindi verifica la VLAN in cui risiede tale indirizzo MAC utilizzando la tabella degli indirizzi MAC del dispositivo. Utilizzando questo indirizzo MAC e la VLAN, il comando show system internal l2fm l2dbg macdb address <mac> vlan <vlan> visualizza un elenco di indici dell'interfaccia SNMP a cui questa combinazione è stata recentemente associata. Il codice utilizza quindi il comando show interface snmp-ifindex per convertire gli indici recenti dell'interfaccia SNMP in nomi di interfaccia leggibili.
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
In questa sezione vengono illustrati alcuni esempi di parametri di sintassi utilizzati quando si creano comandi CLI personalizzati con i metodi cliP.newShowCmd() o cliP.newConfigCmd(), dove cliP è l'oggetto NxCliParser restituito dal metodo sdk.getCliParser().
Nota: Il supporto della sintassi con parentesi di apertura e chiusura ("(" e ")") è introdotto in NX-SDK v1.5.0, incluso in NX-OS release 7.0(3)I7(3). Si presume che l'utente utilizzi NX-SDK v1.5.0 quando segue uno di questi esempi forniti che includono la sintassi che utilizza le parentesi di apertura e chiusura.
Questo comando show accetta un singolo mac di parole chiave e aggiunge alla parola chiave una stringa di supporto Mostra tutti gli indirizzi MAC non programmati sul dispositivo.
nx_cmd = cliP.newShowCmd("show_misprogrammed", "mac")
nx_cmd.updateKeyword("mac", "Shows all misprogrammed MAC addresses on this device")
Questo comando show accetta un singolo parametro <mac>. Le parentesi angolari che racchiudono la parola mac indicano che si tratta di un parametro. Al parametro viene aggiunta una stringa di supporto dell'indirizzo MAC per verificare la presenza di errori di programmazione. Il parametro nx_sdk_py.P_MAC_ADDR nel metodo nx_cmd.updateParam() viene utilizzato per definire il tipo del parametro come indirizzo MAC, impedendo l'input dell'utente finale di un altro tipo, ad esempio una stringa, un numero intero o un indirizzo 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)
Il comando show accetta facoltativamente una singola parola chiave [mac]. Le parentesi che racchiudono la parola mac indicano che questa parola chiave è facoltativa. Alla parola chiave viene aggiunta una stringa di supporto Mostra tutti gli indirizzi MAC non programmati nel dispositivo.
nx_cmd = cliP.newShowCmd( "show_misprogrammed_mac" , "[mac]" )
nx_cmd.updateKeyword( "mac" , "Shows all misprogrammed MAC addresses on this device" )
Questo comando show accetta un singolo parametro [<mac>]. Le parentesi che racchiudono la parola < mac > indicano che questo parametro è facoltativo. Le parentesi angolari che racchiudono la parola mac indicano che si tratta di un parametro. Al parametro viene aggiunta una stringa di supporto dell'indirizzo MAC per verificare la presenza di errori di programmazione. Il parametro nx_sdk_py.P_MAC_ADDR nel metodo nx_cmd.updateParam() viene utilizzato per definire il tipo del parametro come indirizzo MAC, impedendo l'input dell'utente finale di un altro tipo, ad esempio una stringa, un numero intero o un indirizzo 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)
Il comando show accetta una singola parola chiave mac seguita immediatamente dal parametro <mac-address>. Le parentesi angolari che racchiudono la parola mac-address indicano che si tratta di un parametro. Alla parola chiave viene aggiunta una stringa di supporto di Controlla indirizzo MAC per errori di programmazione. Al parametro viene aggiunta una stringa di supporto dell'indirizzo MAC per verificare la presenza di errori di programmazione. Il parametro nx_sdk_py.P_MAC_ADDR nel metodo nx_cmd.updateParam() viene utilizzato per definire il tipo del parametro come indirizzo MAC, che impedisce l'input dell'utente finale di un altro tipo, ad esempio una stringa, un numero intero o un indirizzo 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)
Il comando show può accettare una di due parole chiave, entrambe con due parametri diversi. La prima parola chiave mac ha un parametro <mac-address>, mentre la seconda parola chiave ip ha un parametro <ip-address>. Le parentesi angolari che racchiudono le parole mac-address e ip-address indicano che si tratta di parametri. Alla parola chiave mac viene aggiunta una stringa di supporto di Controlla indirizzo MAC per errori di programmazione. Al parametro <mac-address> viene aggiunta una stringa di supporto dell'indirizzo MAC per verificare la presenza di errori di programmazione. Il parametro nx_sdk_py.P_MAC_ADDR nel metodo nx_cmd.updateParam() viene utilizzato per definire il tipo di parametro <mac-address> come indirizzo MAC, che impedisce l'input dell'utente finale di un altro tipo, ad esempio una stringa, un numero intero o un indirizzo IP. Alla parola chiave ip viene aggiunta una stringa di supporto di Verifica indirizzo IP per errori di programmazione. Al parametro <ip-address> viene aggiunta una stringa di supporto dell'indirizzo IP per verificare la presenza di errori di programmazione. Il parametro nx_sdk_py.P_IP_ADDR nel metodo nx_cmd.updateParam() viene utilizzato per definire il tipo del parametro <ip-address> come indirizzo IP, che impedisce l'input dell'utente finale di un altro tipo, ad esempio una stringa, un numero intero o un indirizzo 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)
Il comando show può accettare una di due parole chiave, entrambe con due parametri diversi. La prima parola chiave mac ha un parametro <mac-address>, mentre la seconda parola chiave ip ha un parametro <ip-address>. Le parentesi angolari che racchiudono le parole mac-address e ip-address indicano che si tratta di parametri. Alla parola chiave mac viene aggiunta una stringa di supporto di Controlla indirizzo MAC per errori di programmazione. Al parametro <mac-address> viene aggiunta una stringa di supporto dell'indirizzo MAC per verificare la presenza di errori di programmazione. Il parametro nx_sdk_py.P_MAC_ADDR nel metodo nx_cmd.updateParam() viene utilizzato per definire il tipo di parametro <mac-address> come indirizzo MAC, che impedisce l'input dell'utente finale di un altro tipo, ad esempio una stringa, un numero intero o un indirizzo IP. Alla parola chiave ip viene aggiunta una stringa di supporto di Verifica indirizzo IP per errori di programmazione. Al parametro <ip-address> viene aggiunta una stringa di supporto dell'indirizzo IP per verificare la presenza di errori di programmazione. Il parametro nx_sdk_py.P_IP_ADDR nel metodo nx_cmd.updateParam() viene utilizzato per definire il tipo del parametro <ip-address> come indirizzo IP, che impedisce l'input dell'utente finale di un altro tipo, ad esempio una stringa, un numero intero o un indirizzo IP. Per questo comando show è possibile usare la parola chiave [clear]. A questa parola chiave opzionale viene aggiunta una stringa di supporto che cancella gli indirizzi rilevati come non programmati.
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")
Il comando show può accettare una di due parole chiave, entrambe con due parametri diversi. La prima parola chiave mac ha un parametro <mac-address>, mentre la seconda parola chiave ip ha un parametro <ip-address>. Le parentesi angolari che racchiudono le parole mac-address e ip-address indicano che si tratta di parametri. Alla parola chiave mac viene aggiunta una stringa di supporto di Controlla indirizzo MAC per errori di programmazione. Al parametro <mac-address> viene aggiunta una stringa di supporto dell'indirizzo MAC per verificare la presenza di errori di programmazione. Il parametro nx_sdk_py.P_MAC_ADDR nel metodo nx_cmd.updateParam() viene utilizzato per definire il tipo di parametro <mac-address> come indirizzo MAC, che impedisce l'input dell'utente finale di un altro tipo, ad esempio una stringa, un numero intero o un indirizzo IP. Alla parola chiave ip viene aggiunta una stringa di supporto di Verifica indirizzo IP per errori di programmazione. Al parametro <ip-address> viene aggiunta una stringa di supporto dell'indirizzo IP per verificare la presenza di errori di programmazione. Il parametro nx_sdk_py.P_IP_ADDR nel metodo nx_cmd.updateParam() viene utilizzato per definire il tipo del parametro <ip-address> come indirizzo IP, che impedisce l'input dell'utente finale di un altro tipo, ad esempio una stringa, un numero intero o un indirizzo IP. Questo comando show accetta facoltativamente un parametro [<module>]. Una stringa di supporto Cancella solo indirizzi nel modulo specificato viene aggiunta a questo parametro facoltativo.
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)
Una volta creata un'applicazione Python NX-SDK, sarà spesso necessario eseguirne il debug. NX-SDK informa l'utente in caso di errori di sintassi nel codice, ma poiché la libreria Python NX-SDK utilizza SWIG per convertire le librerie C++ in librerie Python, qualsiasi eccezione rilevata al momento dell'esecuzione del codice genera un dump del core dell'applicazione simile al seguente:
terminate called after throwing an instance of 'Swig::DirectorMethodException'
what(): SWIG director method error. Error detected when calling 'NxCmdHandler.postCliCb'
Aborted (core dumped)
A causa della natura ambigua di questo messaggio di errore, è consigliabile eseguire il debug delle applicazioni Python registrando i messaggi di debug nel syslog con l'utilizzo di un oggetto NxTrace restituito dal metodo sdk.getTracer(). La dimostrazione è la seguente:
#! /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")
Se la registrazione dei messaggi di debug nel syslog non è un'opzione, un metodo alternativo consiste nell'utilizzare le istruzioni print ed eseguire l'applicazione tramite il binario /isan/bin/python della shell Bash. Tuttavia, l'output di queste istruzioni di stampa sarà visibile solo se eseguite in questo modo: l'esecuzione dell'applicazione tramite la shell VSH non produce alcun output. Di seguito è riportato un esempio di utilizzo dei rendiconti di stampa:
#! /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")
Una volta che un'applicazione Python è stata completamente testata nella shell Bash ed è pronta per la distribuzione, l'applicazione deve essere installata in produzione tramite VSH. In questo modo, l'applicazione può essere mantenuta anche quando il dispositivo viene ricaricato o quando il sistema viene sostituito in uno scenario con due supervisori. Per distribuire un'applicazione tramite VSH, è necessario creare un pacchetto RPM con l'utilizzo di un ambiente di generazione NX-SDK e ENXOS SDK. Cisco DevNet fornisce un'immagine Docker che consente la semplice creazione di pacchetti RPM.
Nota: Per assistenza nell'installazione di Docker su un sistema operativo specifico, consultare la documentazione relativa all'installazione di Docker.
Su un host compatibile con Docker, trascinare la versione dell'immagine desiderata con il comando docker pull dockercisco/nxsdk:<tag>, dove <tag> è il tag della versione dell'immagine scelta. Qui è possibile visualizzare le versioni delle immagini disponibili e i tag corrispondenti. Questa condizione viene dimostrata con il tag v1 riportato di seguito:
docker pull dockercisco/nxsdk:v1
Avviare un contenitore denominato nxsdk da questa immagine e collegarlo. Se il tag scelto è diverso, sostituire il tag con v1:
docker run -it --name nxsdk dockercisco/nxsdk:v1 /bin/bash
Aggiornare alla versione più recente di NX-SDK e passare alla directory di NX-SDK, quindi estrarre i file più recenti da git:
cd /NX-SDK/
git pull
Se è necessario utilizzare una versione precedente di NX-SDK, è possibile clonare il ramo di NX-SDK utilizzando il relativo tag di versione con il comando git clone -b v<version> https://github.com/CiscoDevNet/NX-SDK.git, dove <version> è la versione di NX-SDK necessaria. Ciò è dimostrato in NX-SDK v1.0.0:
cd /
rm -rf /NX-SDK
git clone -b v1.0.0 https://github.com/CiscoDevNet/NX-SDK.git
Quindi, trasferire l'applicazione Python al contenitore Docker. Ci sono diversi modi per farlo.
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
A questo punto, utilizzare lo script rpm_gen.py presente in /NX-SDK/scripts/per creare un pacchetto RPM dall'applicazione Python. Questo script ha un argomento obbligatorio e due opzioni obbligatorie:
Nota: Non è necessario che il nome file contenga estensioni, ad esempio .py. In questo esempio, se il nome del file è python_app anziché python_app.py, il pacchetto RPM verrà generato senza problemi.
Di seguito è illustrato l'utilizzo dello script 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
Il percorso del file del pacchetto RPM è indicato nella riga finale dell'output dello script rpm_gen.py. Questo file deve essere copiato dal contenitore Docker sull'host in modo che possa essere trasferito al dispositivo Nexus su cui si desidera eseguire l'applicazione. Dopo aver chiuso il contenitore Docker, è possibile eseguire facilmente il comando cp docker <container>:<container_filepath> <host_filepath>, dove <container> è il nome del contenitore Docker NX-SDK (in questo caso, nxsdk), <container_filepath> è il percorso completo del pacchetto RPM all'interno del contenitore (in questo caso, /NX-SDK/rpm/RPMS/test_python_app-1.0-1.0.0.x86_64.rpm). <host_filepath> è il percorso file completo sull'host Docker in cui deve essere trasferito il pacchetto RPM (in questo caso, /root/). Di seguito viene riportata la dimostrazione di questo comando:
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
Trasferire il pacchetto RPM al dispositivo Nexus utilizzando il metodo di trasferimento file preferito. Una volta che il pacchetto RPM si trova sul dispositivo, deve essere installato e attivato in modo simile a un SMU. Questa condizione viene dimostrata nel modo seguente, presupponendo che il pacchetto RPM sia stato trasferito al bootflash del dispositivo.
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
Nota: Quando si installa il pacchetto RPM con il comando install add, includere il dispositivo di storage e il nome file esatto del pacchetto. Quando si attiva il pacchetto RPM dopo l'installazione, non includere il dispositivo di storage e il nome del file. Utilizzare il nome del pacchetto. È possibile verificare il nome del pacchetto con il comando show install inactive.
Una volta attivato il pacchetto RPM, è possibile avviare l'applicazione con NX-SDK con il comando di configurazione nxsdk service <application-name>, dove <application-name> è il nome del nome file Python (e, successivamente, dell'applicazione) definito quando lo script rpm_gen.py è stato utilizzato in precedenza. La dimostrazione è la seguente:
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
È possibile verificare che l'applicazione sia attiva e avviata con il comando 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
È inoltre possibile verificare che i comandi CLI personalizzati creati da questa applicazione siano accessibili in NX-OS:
N9K-C93180LC-EX# show test? test_python_app Nexus Sdk Application