clay584.parse_genie

Parse Genie

Publicado

Rol de Ansible Versión de Ansible Versión de Python

Estado de Construcción Puntuación de Calidad de Ansible

¡ATENCIÓN! - Si te enfrentas a un problema con un comando que no puede ser analizado, puede haber un error en la biblioteca de análisis mantenida por Cisco. Para esos problemas, puedes abrir un problema aquí.

El filtro de network genie toma la salida de comandos CLI de red no estructurada de todos los sistemas operativos de red de Cisco, y produce datos estructurados. Aunque es similar a otros analizadores de CLI de red disponibles (parse_cli, parse_cli_textfsm), este analizador está potenciado por una biblioteca muy madura y robusta llamada Genie (y el marco subyacente pyATS). Esto proporciona más de 1200 analizadores que transforman la configuración y la salida de CLI a datos estructurados que están normalizados y se conforman a modelos de datos estándar y agnósticos al sistema operativo.

La biblioteca de Genie también puede servir como motor para analizar texto libre en formato tabular y no tabular utilizando mucho menos código que el que se necesita para el análisis tradicional. Por lo tanto, puede usarse para analizar cualquier salida de proveedor; no solo la de dispositivos Cisco. Sin embargo, eso implicaría escribir analizadores personalizados. Esta versión no incluye la funcionalidad para utilizar analizadores personalizados. Los analizadores compatibles son los que están incluidos en la versión de Genie que el usuario ha instalado en la máquina de control de Ansible.

La lista de sistemas operativos y comandos soportados, así como las definiciones del esquema de datos (modelos de datos) que describen exactamente qué campos y tipos de datos se devolverán para cualquier comando dado, están disponibles en Cisco en el siguiente enlace.

https://pubhub.devnetcloud.com/media/genie-feature-browser/docs/#/parsers

Requisitos Previos

Este plugin requiere lo siguiente:

  1. Python 3.4+
  2. Paquetes pyATS y Genie
  3. Ansible 2.7+ (Debería funcionar en versiones anteriores siempre que se cumplan los otros requisitos)

Instalación

Sigue estas instrucciones para asegurarte de que el plugin de filtro funcione con tus playbooks:

  1. Crea un directorio para tu playbook y entra en él. mkdir network_ops && cd network_ops
  2. Crea un entorno virtual. python3 -m venv .venv
  3. Activa el entorno virtual. source .venv/bin/activate
  4. Instala Ansible. pip install ansible
  5. Instala Genie y pyATS. pip install genie
  6. Instala el rol parse_genie desde Ansible Galaxy. ansible-galaxy install clay584.parse_genie

Mapeos de Ansible a Genie OS

A continuación se presentan los mapeos de ansible_network_os de Ansible a os de Genie:

OS de Red Ansible OS de Genie
ios ios, iosxe
nxos nxos
iosxr iosxr
junos junos

Si trabajas con IOS o IOS-XE hay ambigüedad ya que Ansible considera IOS e IOS-XE lo mismo y, por lo tanto, utiliza ansible_network_os = ios, pero Genie necesita saber específicamente si se trata de IOS o IOS-XE para analizar correctamente la salida de CLI. Si pasas ansible_network_os a este plugin de filtro y es igual a ios, parse_genie intentará analizarlo con Genie utilizando os=ios primero, y si falla, intentará analizarlo con os=iosxe.

Así que ten eso en cuenta al crear tus playbooks. Puede ser mejor pasar el verdadero sistema operativo a parse_genie. Puedes hacer esto manteniendo otra variable de inventario o host_var para especificar el OS de Genie para cada dispositivo de red y usando esa variable como el OS para parse_genie.

Uso

Asegúrate de incluir el rol parse_genie antes de intentar usarlo más adelante en tu playbook.

...truncado...

  tasks:
  - name: Leer rol parse_genie
    include_role:
      name: clay584.parse_genie
      
...truncado...

Ejemplo Corto

Para convertir la salida de un comando CLI de un dispositivo de red, utiliza el filtro parse_genie como se muestra en este ejemplo (no utilices comandos CLI abreviados).

Convirtiendo la salida de CLI del comando show version de un dispositivo Cisco IOS-XE a datos estructurados::

{{ cli_output | parse_genie(command='show version', os='iosxe') }}

Para una abstracción más profunda, podrías querer añadir platform a parse_genie.

{{ cli_output | parse_genie(command='show version', os='iosxe', platform='asr1k') }}

El ejemplo anterior produciría lo siguiente:

{
    "version": {
        "chassis": "CSR1000V",
        "chassis_sn": "9TKUWGKX5MO",
        "curr_config_register": "0x2102",
        "disks": {
            "bootflash:.": {
                "disk_size": "7774207",
                "type_of_disk": "disco duro virtual"
            },
            "webui:.": {
                "disk_size": "0",
                "type_of_disk": "Archivos WebUI ODM"
            }
        },
        "hostname": "host-172-16-1-96",
        "image_id": "X86_64_LINUX_IOSD-UNIVERSALK9-M",
        "image_type": "imagen de producción",
        "last_reload_reason": "Comando de recarga",
        "license_level": "ax",
        "license_type": "Predeterminado. No se encontró una licencia válida.",
        "main_mem": "1126522",
        "mem_size": {
            "configuración no volátil": "32768",
            "físico": "3018840"
        },
        "next_reload_license_level": "ax",
        "number_of_intfs": {
            "Gigabit Ethernet": "2"
        },
        "os": "IOS-XE",
        "platform": "Virtual XE",
        "processor_type": "VXE",
        "rom": "IOS-XE ROMMON",
        "rtr_type": "CSR1000V",
        "system_image": "bootflash:packages.conf",
        "uptime": "2 minutos",
        "uptime_this_cp": "3 minutos",
        "version": "16.5.1b,",
        "version_short": "16.5"
    }
}

Ejemplo Completo #1

Playbook:

---

- hosts: localhost
  connection: local
  vars:
    show_version_output: |
      Software Cisco IOS XE, Versión 16.05.01b
      Software Cisco IOS [Everest], Software Virtual XE (X86_64_LINUX_IOSD-UNIVERSALK9-M), Versión 16.5.1b, SOFTWARE DE LIBERACIÓN (fc1)
      Soporte Técnico: http://www.cisco.com/techsupport
      Copyright (c) 1986-2017 por Cisco Systems, Inc.
      Compilado el Tue 11-Apr-17 16:41 por mcpre


      Software Cisco IOS-XE, Copyright (c) 2005-2017 por Cisco Systems, Inc.
      Todos los derechos reservados.  Ciertos componentes de software de Cisco IOS-XE están
      licenciados bajo la Licencia Pública General de GNU ("GPL") Versión 2.0.  El
      código de software licenciado bajo GPL Versión 2.0 es software libre que viene
      CON ABSOLUTAMENTE NINGUNA GARANTÍA.  Puedes redistribuir y/o modificar dicho
      código GPL bajo los términos de GPL Versión 2.0.  Para más detalles, consulta la
      documentación o el archivo "Aviso de Licencia" que acompaña el software IOS-XE,
      o la URL aplicable proporcionada en el folleto que acompaña el software IOS-XE.


      ROM: IOS-XE ROMMON

      host-172-16-1-96 tiene un tiempo de actividad de 2 minutos
      El tiempo de actividad para este procesador de control es de 3 minutos
      El sistema volvió a ROM por una recarga
      El archivo de imagen del sistema es "bootflash:packages.conf"
      Última razón de recarga: Comando de recarga



      Este producto contiene características criptográficas y está sujeto a las leyes de Estados Unidos y del país local que rigen la importación, exportación, transferencia y
      uso. La entrega de productos criptográficos de Cisco no implica
      autoridad de terceros para importar, exportar, distribuir o usar cifrado.
      Los importadores, exportadores, distribuidores y usuarios son responsables de
      cumplir con las leyes de EE.UU. y del país local. Al usar este producto, aceptas cumplir
      con las leyes y regulaciones aplicables. Si no puedes
      cumplir con las leyes de EE.UU. y locales, devuelve este producto inmediatamente.

      Un resumen de las leyes de EE.UU. que rigen los productos criptográficos de Cisco se puede encontrar en:
      http://www.cisco.com/wwl/export/crypto/tool/stqrg.html

      Si necesitas más ayuda, contáctanos enviando un correo electrónico a
      [email protected].

      Nivel de Licencia: ax
      Tipo de Licencia: Predeterminado. No se encontró una licencia válida.
      Nivel de Licencia para la siguiente recarga: ax

      cisco CSR1000V (VXE) procesador (revisión VXE) con 1126522K/3075K bytes de memoria.
      ID de placa del procesador 9TKUWGKX5MO
      2 interfaces de Gigabit Ethernet
      32768K bytes de memoria de configuración no volátil.
      3018840K bytes de memoria física.
      7774207K bytes de disco duro virtual en bootflash:.
      0K bytes de Archivos WebUI ODM en webui:.

      El registro de configuración es 0x2102

  tasks:
  - name: Leer rol parse_genie
    include_role:
      name: clay584.parse_genie

  - name: Depurar Filtro Genie
    debug:
      msg: "{{ show_version_output | parse_genie(command='show version', os='iosxe') }}"
    delegate_to: localhost

Salida:

$ ansible-playbook -i inventory debug.yml

PLAY [localhost] *************************************************************************

TASK [Recolección de Datos] *******************************************************************
ok: [localhost]

TASK [Leer rol parse_genie] **********************************************************

TASK [Depurar Filtro Genie] ****************************************************************
ok: [localhost -> localhost] => {
    "msg": {
        "version": {
            "chassis": "CSR1000V",
            "chassis_sn": "9TKUWGKX5MO",
            "curr_config_register": "0x2102",
            "disks": {
                "bootflash:.": {
                    "disk_size": "7774207",
                    "type_of_disk": "disco duro virtual"
                },
                "webui:.": {
                    "disk_size": "0",
                    "type_of_disk": "Archivos WebUI ODM"
                }
            },
            "hostname": "host-172-16-1-96",
            "image_id": "X86_64_LINUX_IOSD-UNIVERSALK9-M",
            "image_type": "imagen de producción",
            "last_reload_reason": "Comando de recarga",
            "license_level": "ax",
            "license_type": "Predeterminado. No se encontró una licencia válida.",
            "main_mem": "1126522",
            "mem_size": {
                "non-volatile configuration": "32768",
                "physical": "3018840"
            },
            "next_reload_license_level": "ax",
            "number_of_intfs": {
                "Gigabit Ethernet": "2"
            },
            "os": "IOS-XE",
            "platform": "Virtual XE",
            "processor_type": "VXE",
            "rom": "IOS-XE ROMMON",
            "rtr_type": "CSR1000V",
            "system_image": "bootflash:packages.conf",
            "uptime": "2 minutos",
            "uptime_this_cp": "3 minutos",
            "version": "16.5.1b,",
            "version_short": "16.5"
        }
    }
}

Ejemplo Completo #2

Playbook:

---

- hosts: csr1000v
  gather_facts: False
  tasks:
  - name: Leer rol parse_genie
    include_role:
      name: clay584.parse_genie

  - name: Obtener Datos Desde el Dispositivo
    ios_command:
      commands: show arp vrf Mgmt-intf
    register: arp_output

  - name: Imprimir Datos Estructurados
    debug:
      msg: "{{ arp_output['stdout'][0] | parse_genie(command='show arp vrf Mgmt-intf', os='iosxe') }}"
    delegate_to: localhost

Salida:

$ ansible-playbook -i inventory playbook.yml

PLAY [csr1000v] **************************************************************************

TASK [Leer rol parse_genie] **********************************************************

TASK [Obtener Datos Desde el Dispositivo] **************************************************************
ok: [csr1000v]

TASK [Imprimir Datos Estructurados] *************************************************************
ok: [csr1000v -> localhost] => {
    "msg": {
        "interfaces": {
            "GigabitEthernet1": {
                "ipv4": {
                    "neighbors": {
                        "172.16.1.111": {
                            "age": "0",
                            "ip": "172.16.1.111",
                            "link_layer_address": "5e00.4004.0000",
                            "origin": "dinámico",
                            "protocol": "Internet",
                            "type": "ARPA"
                        },
                        "172.16.1.114": {
                            "age": "-",
                            "ip": "172.16.1.114",
                            "link_layer_address": "5e00.4001.0000",
                            "origin": "estático",
                            "protocol": "Internet",
                            "type": "ARPA"
                        }
                    }
                }
            }
        }
    }
}

Análisis Tabular Genérico

Cisco Genie tiene soporte para 1200 comandos y contando, pero para esos comandos de mostrar donde no hay un analizador que ha sido construido por Cisco, existe la funcionalidad de análisis tabular genérico. Para más información sobre la funcionalidad de análisis tabular de Genie, consulta su documentación oper_fill_tabular.

Cómo Funciona el Análisis Tabular

Para analizar la salida de un comando cuando hay un analizador que ha sido construido, todo lo que se requiere es el comando, salida de comando y os. Pero si no hay un analizador construido, debes especificar información adicional para ayudar al analizador a determinar cómo analizar la salida del comando. Estos datos adicionales son dos:

  1. Encabezados - Los encabezados de columna como se muestran en la salida del comando.
  2. Índice - La clave de los elementos del diccionario que el analizador devolverá.

Considera el siguiente ejemplo:

  1. Comando: show ip sla summary
  2. Salida del Comando:
Resumen de la Última Operación de IPSLA
Códigos: * activo, ^ inactivo, ~ pendiente
Todas las estadísticas están en milisegundos. Las estadísticas con u están en microsegundos

ID           Tipo           Destino       Estadísticas               Retorno        Última
                                                                  Código          Ejecución
------------------------------------------------------------------------------------------------
*1           udp-jitter      10.0.0.2          RTT=900u           OK             hace 20 segundos
*2           icmp-echo       10.0.0.2          RTT=1              OK              hace 3 segundos
  1. Encabezados - ID, Tipo, Destino, Estadísticas, Código de Retorno, y Última Ejecución.
  2. Índice - Queremos usar la columna ID como índice para estos datos cuando los obtengamos de regreso del analizador.
  3. Salida del Analizador:
{'*1': {'Destino ': '10.0.0.2',
        'ID ': '*1',
        'Última Ejecución': 'hace 20 segundos',
        'Código de Retorno': 'OK',
        'Estadísticas ': 'RTT=900u',
        'Tipo ': 'udp-jitter'},
 '*2': {'Destino ': '10.0.0.2',
        'ID ': '*2',
        'Última Ejecución': 'hace 3 segundos',
        'Código de Retorno': 'OK',
        'Estadísticas ': 'RTT=1',
        'Tipo ': 'icmp-echo'}}

Preparación para Usar el Analizador Tabular

Para usar este analizador tabular, primero debemos construir los encabezados y índice para un comando dado en un OS dado en un formato que pueda ser leído en un playbook de Ansible, y posteriormente alimentado al plugin de filtro parse_genie.

Para hacer esto, debes crear un archivo vars en tu playbook que tenga el siguiente formato. Está organizado por OS, luego por comando. Luego, bajo cada comando, se definen los encabezados y el índice. Puedes definir tantos comandos como desees para cada OS de red siempre que esté dentro de esta estructura de datos.

parse_genie:
  ios:
    "show ip sla summary":
      headers:
        - - ID
          - Tipo
          - Destino
          - Estadísticas
          - Retorno
          - Última
        - - ''
          - ''
          - ''
          - ''
          - Código
          - Ejecución
      index:
        - 0
  iosxe:
    "show ip sla summary":
      headers:
        - - ID
          - Tipo
          - Destino
          - Estadísticas
          - Retorno
          - Última
        - - ''
          - ''
          - ''
          - ''
          - Código
          - Ejecución
      index:
        - 1

La equivalente en python del formato yaml anterior es:

python_dict = {
  "parse_genie": {
    "ios": {
      "show ip sla summary": {
        "headers": [
          [
            "ID", 
            "Tipo", 
            "Destino", 
            "Estadísticas", 
            "Retorno", 
            "Última"
          ], 
          [
            "", 
            "", 
            "", 
            "", 
            "Código", 
            "Ejecución"
          ]
        ], 
        "index": [
          0
        ]
      }
    }, 
    "iosxe": {
      "show ip sla summary": {
        "headers": [
          [
            "ID", 
            "Tipo", 
            "Destino", 
            "Estadísticas", 
            "Retorno", 
            "Última"
          ], 
          [
            "", 
            "", 
            "", 
            "", 
            "Código", 
            "Ejecución"
          ]
        ], 
        "index": [
          1
        ]
      }
    }
  }
}

Llamando al Analizador Tabular en un Playbook

Ahora que hemos definido un comando tabular genérico y sus encabezados e índice, podemos llamarlo desde un playbook.

Primero, leemos el archivo vars que contiene los metadatos del comando tabular genérico.

- name: Incluir archivo vars con metadatos de comandos genéricos
  include_vars:
    file: parse_genie_generic_commands.yml
    name: parse_genie

A continuación, pasamos la salida del comando a parse_genie pero con un par de parámetros adicionales.

- name: Analizar salida de comando tabular genérico
  debug:
    msg: "{{ command_output | parse_genie(command='show ip sla summary', os='ios', generic_tabular=True, generic_tabular_metadata=parse_genie) }}"
  delegate_to: localhost

La salida analizada resultante se mostrará como sigue:

ok: [localhost -> localhost] => {
    "msg": {
        "*1": {
            "Destino ": "10.0.0.2",
            "ID ": "*1",
            "Última Ejecución": "hace 20 segundos",
            "Código de Retorno": "OK",
            "Estadísticas ": "RTT=900u",
            "Tipo ": "udp-jitter"
        },
        "*2": {
            "Destino ": "10.0.0.2",
            "ID ": "*2",
            "Última Ejecución": "hace 3 segundos",
            "Código de Retorno": "OK",
            "Estadísticas ": "RTT=1",
            "Tipo ": "icmp-echo"
        }
    }
}

Ejemplo Completo #1

Playbook:


---

- hosts: localhost
  connection: local
  vars:
    out_ios_sla: |
      Resumen de la Última Operación de IPSLA
      Códigos: * activo, ^ inactivo, ~ pendiente
      Todas las estadísticas están en milisegundos. Las estadísticas con u están en microsegundos

      ID           Tipo           Destino       Estadísticas               Retorno        Última
                                                                        Código          Ejecución
      ------------------------------------------------------------------------------------------------
      *1           udp-jitter      10.0.0.2          RTT=900u           OK             hace 20 segundos
      *2           icmp-echo       10.0.0.2          RTT=1              OK              hace 3 segundos

  tasks:
    - name: Incluir Rol Parse Genie
      include_role:
        name: clay584.parse_genie

    - name: Incluir archivo vars que tiene metadatos de comando tabular genérico
      include_vars:
        file: parse_genie_generic_commands.yml
        name: parse_genie

    - name: Probar Filtro Genie para datos tabulares genéricos
      debug:
        msg: "{{ out_ios_sla | parse_genie(command='test show ip sla summary', os='ios', generic_tabular=True, generic_tabular_metadata=parse_genie) }}"
      delegate_to: localhost

Contenido de parse_genie_generic_commands.yml:


---

parse_genie:
  ios:
    "test show ip sla summary":
      headers:
        - - ID
          - Tipo
          - Destino
          - Estadísticas
          - Retorno
          - Última
        - - ''
          - ''
          - ''
          - ''
          - Código
          - Ejecución
      index:
        - 0
  iosxe:
    "test show ip sla summary":
      headers:
        - - ID
          - Tipo
          - Destino
          - Estadísticas
          - Retorno
          - Última
        - - ''
          - ''
          - ''
          - ''
          - Código
          - Ejecución
      index:
        - 1

Salida del Playbook:


PLAY [localhost] ******************************************************************************************************************************************************************************************************************************************************************

TASK [Recolección de Datos] ************************************************************************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [Incluir Rol Parse Genie] ***************************************************************************************************************************************************************************************************************************************************

TASK [Incluir vars] ***************************************************************************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [Probar Filtro Genie para datos tabulares genéricos] *********************************************************************************************************************************************************************************************************************************
ok: [localhost -> localhost] => {
    "msg": {
        "*1": {
            "Destino ": "10.0.0.2",
            "ID ": "*1",
            "Última Ejecución": "hace 20 segundos",
            "Código de Retorno": "OK",
            "Estadísticas ": "RTT=900u",
            "Tipo ": "udp-jitter"
        },
        "*2": {
            "Destino ": "10.0.0.2",
            "ID ": "*2",
            "Última Ejecución": "hace 3 segundos",
            "Código de Retorno": "OK",
            "Estadísticas ": "RTT=1",
            "Tipo ": "icmp-echo"
        }
    }
}

PLAY RECAP ************************************************************************************************************************************************************************************************************************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0   

Desarrollo

Configura tu entorno de desarrollo:

  1. Clona el repositorio y entra en él. git clone https://github.com/clay584/parse_genie.git && cd parse_genie
  2. Crea un entorno virtual. python3 -m venv .venv
  3. Activa el entorno virtual. source .venv/bin/activate
  4. Instala Ansible. pip install ansible
  5. Instala Genie y pyATS. pip install genie
  6. Instala yamllint. pip install yamllint

Pruebas

Ejecuta estos comandos para probar localmente:

  1. Verifica todos los archivos YAML. yamllint -c yamllint_config.yml *
  2. Ejecuta el playbook de prueba. ansible-playbook tests/test.yml --connection=local -i tests/inventory

Publicación

Ansible Galaxy funciona con etiquetas.

  1. git commit -m"lo que sea'
  2. git tag -a X.X.X - donde X.X.X es un número de versión semántica.
  3. git push origin master
  4. git push X.X.X
Acerca del proyecto

Filter plugin for network CLI parsing using Cisco's Genie/pyATS

Instalar
ansible-galaxy install clay584.parse_genie
Licencia
gpl-3.0
Descargas
63.8k
Propietario
Brought to you by Carl's Jr.