O conjunto de documentação deste produto faz o possível para usar uma linguagem imparcial. Para os fins deste conjunto de documentação, a imparcialidade é definida como uma linguagem que não implica em discriminação baseada em idade, deficiência, gênero, identidade racial, identidade étnica, orientação sexual, status socioeconômico e interseccionalidade. Pode haver exceções na documentação devido à linguagem codificada nas interfaces de usuário do software do produto, linguagem usada com base na documentação de RFP ou linguagem usada por um produto de terceiros referenciado. Saiba mais sobre como a Cisco está usando a linguagem inclusiva.
A Cisco traduziu este documento com a ajuda de tecnologias de tradução automática e humana para oferecer conteúdo de suporte aos seus usuários no seu próprio idioma, independentemente da localização. Observe que mesmo a melhor tradução automática não será tão precisa quanto as realizadas por um tradutor profissional. A Cisco Systems, Inc. não se responsabiliza pela precisão destas traduções e recomenda que o documento original em inglês (link fornecido) seja sempre consultado.
Não existem requisitos específicos para este documento.
As informações neste documento são baseadas nestas versões de 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
Note: A melhor prática é criar arquivos Python no diretório /isan/bin/. Os arquivos Python precisam de permissões de execução para serem executados - não coloque os arquivos Python no diretório /bootflash ou em nenhum de seus subdiretórios.
Note: Não é necessário criar e editar arquivos Python por meio do NX-OS. O desenvolvedor pode criar o aplicativo usando seu ambiente local e transferir os arquivos concluídos para o dispositivo usando um protocolo de transferência de arquivos de sua escolha. No entanto, pode ser mais eficiente para o desenvolvedor depurar e solucionar problemas de seu script usando utilitários NX-OS.
função sdkThread
Note: A partir do NX-SDK v1.5.0, um terceiro parâmetro booleano pode ser passado para o método NxSdk.getSdkInst, que permite exceções avançadas quando verdadeiro e desativa exceções avançadas quando falso. Este método está documentado aqui .
Alguns métodos comumente usados incluem:
Note: Os formatos de dados R_JSON e R_XML só funcionam se o comando suportar a saída nesses formatos. No NX-OS, você pode verificar se um comando oferece suporte à saída em um formato de dados específico, inserindo a saída no formato de dados solicitado. Se o comando piped retornar uma saída significativa, o formato de dados será suportado. Por exemplo, se você executar show mac address-table dynamic | json no NX-OS retorna a saída JSON e o formato de dados R_JSON também é suportado no NX-SDK.
Alguns métodos opcionais que podem ser úteis são:
N9K-C93180LC-EX# show Tra?
track Tracking information
Transceiver_DOM.py Returns all interfaces with DOM-capable transceivers inserted
Em um aplicativo Python com o uso do NX-SDK, comandos CLI personalizados são criados e definidos na função sdkThread. Há dois tipos de comandos: Comandos show e Config.
Esses dois métodos permitem a criação de comandos show e de comandos config respectivamente:
Note: Este comando é uma subclasse de cliP.newCliCmd("cmd_type", "cmd_name", "syntax") onde cmd_type é CONF_CMD ou SHOW_CMD (dependendo do tipo de comando sendo configurado), cmd_name é um nome exclusivo para o comando internal para o aplicativo NX-SDK personalizado e a sintaxe descreve quais palavras-chave e parâmetros podem ser usados no comando. Por causa disso, a documentação da API para esse comando pode ser mais útil para referência.
Note: Este comando é uma subclasse de cliP.newCliCmd("cmd_type", "cmd_name", "syntax") onde cmd_type é CONF_CMD ou SHOW_CMD (depende do tipo de comando configurado), cmd_name é um nome exclusivo para o comando interno do aplicativo NX-SDK personalizado e sintaxe descreve quais palavras-chave e parâmetros podem ser usados no comando. Por causa disso, a documentação da API para esse comando pode ser mais útil para referência.
Ambos os tipos de comandos têm dois componentes diferentes: Parâmetros e palavras-chave:
1. Parâmetros são valores usados para alterar os resultados do comando. Por exemplo, no comando show ip route 192.168.1.0, há uma palavra-chave route seguida por um parâmetro que aceita um endereço IP, que especifica que somente as rotas que incluem o endereço IP fornecido devem ser mostradas.
2. Palavras-chave mudam os resultados do comando somente por sua presença. Por exemplo, no comando show mac address-table dynamic, há uma palavra-chave dinâmica, que especifica que somente endereços MAC aprendidos dinamicamente devem ser exibidos.
Os dois componentes são definidos na sintaxe de um comando NX-SDK quando ele é criado. Existem métodos para o objeto NxCliCmd para modificar a implementação específica de ambos os componentes.
Para ver exemplos de código de componentes de comando comumente usados, consulte a seção Exemplos de comandos CLI personalizados deste documento.
Após a criação de comandos CLI personalizados, um objeto da classe pyCmdHandler descrita mais adiante neste documento precisa ser criado e definido como o objeto de manipulador de chamada de retorno CLI para o objeto NxCliParser. Isto é demonstrado do seguinte modo:
cmd_handler = pyCmdHandler()
cliP.setCmdHandler(cmd_handler)
Em seguida, o objeto NxCliParser precisa ser adicionado à árvore de analisador CLI do NX-OS para que os comandos CLI personalizados sejam visíveis para o usuário. Isso é feito com o comando cliP.addToParseTree(), em que cliP é o objeto NxCliParser retornado pelo método sdk.getCliParser().
exemplo de função sdkThread
Aqui está um exemplo de uma função sdkThread típica com o uso das funções explicadas anteriormente. Esta função (entre outras dentro de um aplicativo típico personalizado NX-SDK Python) utiliza variáveis globais, que são instanciadas na execução do 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)
A classe pyCmdHandler é herdada da classe NxCmdHandler na biblioteca nx_sdk_py. O método postCliCb(self, click) definido na classe pyCmdHandler é chamado sempre que os comandos CLI originados de um aplicativo NX-SDK. Assim, o método postCliCb(self, click) é onde você define como os comandos CLI personalizados definidos na função sdkThread se comportam no dispositivo.
A função postCliCb(self, click) retorna um valor booleano. Se True for retornado, presume-se que o comando foi executado com êxito. False deve ser retornado se o comando não foi executado com êxito por qualquer motivo.
O parâmetro click usa o nome exclusivo que foi definido para o comando quando ele foi criado na função sdkThread. Por exemplo, se você criar um novo comando show com um nome exclusivo de show_xcvr_dom, então é recomendável consultar esse comando pelo mesmo nome na função postCliCb(self, click) depois de verificar se o nome do argumento click contém show_xcvr_dom. É demonstrado aqui:
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 um comando que utiliza parâmetros for criado, você provavelmente precisará usar esses parâmetros em algum ponto da função postCliCb(self, click). Isso pode ser feito com o método click.getParamValue("<parâmetro>"), em que <parâmetro> é o nome do parâmetro de comando que você deseja obter o valor entre colchetes angulares (<>). Este método está documentado aqui. No entanto, o valor retornado por esta função precisa ser convertido para o tipo necessário. Isso pode ser feito com estes métodos:
A função postCliCb(self, click) (ou quaisquer funções subsequentes) também normalmente será onde a saída do comando show é impressa no console. Isso é feito com o método click.printConsole().
Note: Se o aplicativo encontrar um erro, uma exceção não tratada ou, de outra forma, sair repentinamente, a saída da função click.printConsole() não será exibida. Por esse motivo, a melhor prática ao depurar seu aplicativo Python é registrar mensagens de depuração no syslog com o uso de um objeto NxTrace retornado pelo método sdk.getTracer(), ou usar instruções de impressão e executar o aplicativo através do binário Bash shell /isan/bin/python.
Exemplo de classe do pyCmdHandler
O código a seguir serve como exemplo para a classe pyCmdHandler descrita acima. Este código é extraído do arquivo ip_move.py no aplicativo NX-SDK de movimento de ip disponível aqui. A finalidade deste aplicativo é rastrear a movimentação de um endereço IP definido pelo usuário através das interfaces de um dispositivo Nexus. Para fazer isso, o código localiza o endereço MAC da entrada do endereço IP através do parâmetro <ip> dentro do cache ARP do dispositivo e, em seguida, verifica qual VLAN esse endereço MAC reside ao usar a tabela de endereços MAC do dispositivo. Usando esse MAC e VLAN, o comando show system internal l2fm l2dbg macdb address <mac> vlan <vlan> exibe uma lista de índices de interface SNMP aos quais essa combinação foi associada recentemente. O código usa o comando show interface snmp-ifindex para converter índices recentes de interface SNMP em nomes de interface legíveis por humanos.
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
Esta seção mostra alguns exemplos do parâmetro de sintaxe usado quando você cria comandos CLI personalizados com os métodos cliP.newShowCmd() ou cliP.newConfigCmd(), em que cliP é o objeto NxCliParser retornado pelo método sdk.getCliParser() .
Note: O suporte para sintaxe com parênteses de abertura e fechamento ("("(" e ")") é apresentado no NX-SDK v1.5.0, incluído no NX-OS Versão 7.0(3)I7(3). Supõe-se que o usuário utilize NX-SDK v1.5.0 quando segue qualquer um desses exemplos fornecidos que incluem sintaxe utilizando parênteses de abertura e fechamento.
Esse comando show usa uma única palavra-chave mac e adiciona uma sequência de caracteres auxiliar de Mostra todos os endereços MAC mal programados neste dispositivo à palavra-chave.
nx_cmd = cliP.newShowCmd("show_misprogrammed", "mac")
nx_cmd.updateKeyword("mac", "Shows all misprogrammed MAC addresses on this device")
Este comando show usa um único parâmetro <mac>. Os colchetes angulares que envolvem a palavra mac significam que este é um parâmetro. Uma cadeia de caracteres auxiliar do endereço MAC para verificar se há má programação é adicionada ao parâmetro. O parâmetro nx_sdk_py.P_MAC_ADDR no método nx_cmd.updateParam() é usado para definir o tipo do parâmetro como um endereço MAC, que impede a entrada de outro tipo pelo usuário final, como uma string, um inteiro ou um endereço 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)
Esse comando show pode, opcionalmente, ter uma única palavra-chave [mac]. Os colchetes envolventes em torno da palavra mac significam que essa palavra-chave é opcional. Uma sequência de ajuda de Mostra todos os endereços MAC mal programados neste dispositivo são adicionados à palavra-chave.
nx_cmd = cliP.newShowCmd( "show_misprogrammed_mac" , "[mac]" )
nx_cmd.updateKeyword( "mac" , "Shows all misprogrammed MAC addresses on this device" )
Esse comando show pode, opcionalmente, pegar um único parâmetro [<mac>]. Os colchetes envolventes em torno da palavra < mac > significam que esse parâmetro é opcional. Os colchetes angulares que envolvem a palavra mac significam que este é um parâmetro. Uma cadeia de caracteres auxiliar do endereço MAC para verificar se há má programação é adicionada ao parâmetro. O parâmetro nx_sdk_py.P_MAC_ADDR no método nx_cmd.updateParam() é usado para definir o tipo do parâmetro como um endereço MAC, que impede a entrada de outro tipo pelo usuário final, como uma string, um inteiro ou um endereço 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)
Esse comando show usa uma única palavra-chave mac imediatamente seguida pelo parâmetro <mac-address>. Os colchetes angulares que envolvem a palavra mac-address significam que este é um parâmetro. Uma sequência de ajuda de Verificar endereço MAC para má programação é adicionada à palavra-chave. Uma cadeia de caracteres auxiliar do endereço MAC para verificar se há má programação é adicionada ao parâmetro. O parâmetro nx_sdk_py.P_MAC_ADDR no método nx_cmd.updateParam() é usado para definir o tipo do parâmetro como um endereço MAC, que impede a entrada de outro tipo pelo usuário final, como uma string, um inteiro ou um endereço 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)
Esse comando show pode ter uma de duas palavras-chave, ambas com dois parâmetros diferentes seguindo-as. A primeira palavra-chave mac tem um parâmetro de <mac-address>, e a segunda palavra-chave ip tem um parâmetro de <ip-address>. Os colchetes angulares que envolvem as palavras mac-address e ip-address significam que são parâmetros. Uma sequência de ajuda de Verificar endereço MAC para má programação é adicionada à palavra-chave mac. Uma string auxiliar de endereço MAC para verificar se há má programação é adicionada ao parâmetro <mac-address>. O parâmetro nx_sdk_py.P_MAC_ADDR no método nx_cmd.updateParam() é usado para definir o tipo do <mac-address> como um endereço MAC, o que impede a entrada do usuário final de outro tipo, como string, inteiro ou endereço IP. Uma sequência de ajuda de Check IP address for misprograming é adicionada à palavra-chave ip. Uma string auxiliar de endereço IP para verificar se há programação incorreta é adicionada ao parâmetro <ip-address>. O parâmetro nx_sdk_py.P_IP_ADDR no método nx_cmd.updateParam() é usado para definir o tipo do <ip-address> como um endereço IP, o que impede a entrada do usuário final de outro tipo, como string, inteiro ou endereço 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)
Esse comando show pode ter uma de duas palavras-chave, ambas com dois parâmetros diferentes seguindo-as. A primeira palavra-chave mac tem um parâmetro de <mac-address>, e a segunda palavra-chave ip tem um parâmetro de <ip-address>. Os colchetes angulares que envolvem as palavras mac-address e ip-address significam que são parâmetros. Uma sequência de ajuda de Verificar endereço MAC para má programação é adicionada à palavra-chave mac. Uma string auxiliar de endereço MAC para verificar se há má programação é adicionada ao parâmetro <mac-address>. O parâmetro nx_sdk_py.P_MAC_ADDR no método nx_cmd.updateParam() é usado para definir o tipo do <mac-address> como um endereço MAC, o que impede a entrada do usuário final de outro tipo, como string, inteiro ou endereço IP. Uma sequência de ajuda de Check IP address for misprograming é adicionada à palavra-chave ip. Uma string auxiliar de endereço IP para verificar se há programação incorreta é adicionada ao parâmetro <ip-address>. O parâmetro nx_sdk_py.P_IP_ADDR no método nx_cmd.updateParam() é usado para definir o tipo do <ip-address> como um endereço IP, o que impede a entrada do usuário final de outro tipo, como string, inteiro ou endereço IP. Esse comando show pode, opcionalmente, ter uma palavra-chave [clear]. Uma sequência de caracteres auxiliar Limpa os endereços detectados como mal programados é adicionada a esta palavra-chave opcional.
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")
Esse comando show pode ter uma de duas palavras-chave, ambas com dois parâmetros diferentes seguindo-as. A primeira palavra-chave mac tem um parâmetro de <mac-address>, e a segunda palavra-chave ip tem um parâmetro de <ip-address>. Os colchetes angulares que envolvem as palavras mac-address e ip-address significam que são parâmetros. Uma sequência de ajuda de Verificar endereço MAC para programação incorreta é adicionada à palavra-chave mac. Uma string auxiliar de endereço MAC para verificar se há má programação é adicionada ao parâmetro <mac-address>. O parâmetro nx_sdk_py.P_MAC_ADDR no método nx_cmd.updateParam() é usado para definir o tipo do <mac-address> como um endereço MAC, o que impede a entrada do usuário final de outro tipo, como string, inteiro ou endereço IP. Uma sequência de ajuda de Check IP address for misprograming é adicionada à palavra-chave ip. Uma string auxiliar de endereço IP para verificar se há programação incorreta é adicionada ao parâmetro <ip-address>. O parâmetro nx_sdk_py.P_IP_ADDR no método nx_cmd.updateParam() é usado para definir o tipo do <ip-address> como um endereço IP, o que impede a entrada do usuário final de outro tipo, como string, inteiro ou endereço IP. Este comando show pode, opcionalmente, pegar um parâmetro [<module>]. Uma sequência de caracteres auxiliar Somente endereços claros no módulo especificado são adicionados a este parâmetro opcional.
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)
Depois que um aplicativo Python NX-SDK for criado, ele frequentemente precisará ser depurado. O NX-SDK informa você caso haja algum erro de sintaxe em seu código, mas como a biblioteca do Python NX-SDK utiliza o SWIG para converter bibliotecas C++ em bibliotecas Python, qualquer exceção encontrada no momento da execução do código resulta em um dump central do aplicativo semelhante a este:
terminate called after throwing an instance of 'Swig::DirectorMethodException'
what(): SWIG director method error. Error detected when calling 'NxCmdHandler.postCliCb'
Aborted (core dumped)
Devido à natureza ambígua desta mensagem de erro, a melhor prática para depurar aplicativos Python é registrar mensagens de depuração no syslog com o uso de um objeto NxTrace retornado pelo método sdk.getTracer(). Isto é demonstrado do seguinte modo:
#! /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 o registro de mensagens de depuração no syslog não for uma opção, um método alternativo é usar instruções de impressão e executar o aplicativo por meio do binário Bash shell /isan/bin/python. No entanto, a saída dessas instruções de impressão só será visível quando executadas dessa maneira - executar o aplicativo através do shell VSH não produz nenhuma saída. Um exemplo de utilização de instruções de impressão é mostrado aqui:
#! /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")
Depois que um aplicativo Python tiver sido totalmente testado no shell Bash e estiver pronto para implantação, o aplicativo deverá ser instalado na produção através da VSH. Isso permite que o aplicativo persista quando o dispositivo é recarregado ou quando a comutação do sistema ocorre em um cenário de supervisor duplo. Para implantar um aplicativo através da VSH, é necessário criar um pacote RPM com o uso de um ambiente de compilação NX-SDK e ENXOS SDK. O Cisco DevNet fornece uma imagem do Docker que permite a fácil criação de pacotes RPM.
Note: Para obter assistência para instalar o Docker em seu sistema operacional específico, consulte a documentação de instalação do Docker.
Em um host compatível com Docker, puxe a versão da imagem de sua escolha com o comando docker pull dockercisco/nxsdk:<tag>, onde <tag> é a marca da versão da imagem de sua escolha. Você pode exibir as versões de imagem disponíveis e suas marcas correspondentes aqui. Isso é demonstrado com a marca v1 aqui:
docker pull dockercisco/nxsdk:v1
Inicie um contêiner chamado nxsdk dessa imagem e anexe-o. Se a marca de sua escolha for diferente, substitua v1 pela sua marca:
docker run -it --name nxsdk dockercisco/nxsdk:v1 /bin/bash
Atualize para a versão mais recente do NX-SDK e navegue até o diretório NX-SDK e, em seguida, puxe os arquivos mais recentes do git:
cd /NX-SDK/
git pull
Se precisar usar uma versão mais antiga do NX-SDK, você pode clonar a filial NX-SDK com o uso da respectiva marca de versão com o comando git clone -b v<version> https://github.com/CiscoDevNet/NX-SDK.git, onde <version> é a versão do NX-SDK de que você precisa. Isso é demonstrado aqui com o NX-SDK v1.0.0:
cd /
rm -rf /NX-SDK
git clone -b v1.0.0 https://github.com/CiscoDevNet/NX-SDK.git
Em seguida, transfira o aplicativo Python para o contêiner Docker. Há algumas maneiras diferentes de fazer isso.
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
Em seguida, use o script rpm_gen.py localizado em /NX-SDK/scripts/ para criar um pacote RPM do aplicativo Python. Este script tem um argumento necessário e dois switches necessários:
Note: O nome do arquivo não precisa conter nenhuma extensão de arquivo, como .py. Neste exemplo, se o nome do arquivo fosse python_app em vez de python_app.py, o pacote RPM seria gerado sem um problema.
O uso do script rpm_gen.py é demonstrado aqui.
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
O caminho do arquivo para o pacote RPM é indicado na linha final da saída do script rpm_gen.py. Esse arquivo deve ser copiado do contêiner do Docker para o host para que possa ser transferido para o dispositivo Nexus no qual você deseja executar o aplicativo. Depois de sair do contêiner do Docker, isso pode ser feito facilmente com o comando docker cp <container>:<container_filepath> <host_filepath>, onde <container> é o nome do contêiner do Docker NX-SDK (neste caso, nxsdk), <container_filepath> é o caminho de arquivo completo do pacote RPM dentro do contêiner (neste caso, /NX-SDK/rpm/RPMS/test_python_app-1.0-1.0.0.x86_64.rpm) e <host_filepath> é o caminho de arquivo completo em nosso host Docker para o qual o pacote RPM deve ser transferido (neste caso, /root/). Este comando é demonstrado aqui:
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
Transfira este pacote RPM para o dispositivo Nexus com o uso do método preferido de transferência de arquivos. Quando o pacote RPM estiver no dispositivo, ele deverá ser instalado e ativado de forma semelhante a um SMU. Isto é demonstrado da seguinte forma, partindo do pressuposto de que o pacote RPM foi transferido para o flash de inicialização do 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
Note: Ao instalar o pacote RPM com o comando install add, inclua o dispositivo de armazenamento e o nome exato do pacote. Quando você ativar o pacote RPM após a instalação, não inclua o dispositivo de armazenamento e o nome do arquivo - use o nome do pacote em si. Você pode verificar o nome do pacote com o comando show install inative.
Quando o pacote RPM for ativado, você poderá iniciar o aplicativo com NX-SDK com o comando de configuração nxsdk service <application-name>, em que <application-name> é o nome do arquivo Python (e, subsequentemente, o aplicativo) que foi definido quando o script rpm_gen.py foi usado anteriormente. Isto é demonstrado do seguinte modo:
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
Você pode verificar se o aplicativo está ativo e começou a ser executado com o 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
Você também pode verificar se os comandos CLI personalizados criados por este aplicativo estão acessíveis no NX-OS:
N9K-C93180LC-EX# show test? test_python_app Nexus Sdk Application