Un complemento dinámico es un complemento personalizado que puede crear para cualquier nodo de transporte compatible, como un host ESXi, para comprobar el estado del nodo.

Se puede instalar un complemento dinámico en el tiempo de ejecución. Realiza las siguientes funciones:

  • Escribir un registro del sistema para el nodo de transporte afectado.
  • Ejecutar un comando o una CLI a través de la función run_command().
  • Leer las métricas existentes.
  • Exportar datos a wavefront (solo en un entorno de VMware Cloud).

Puede crear un complemento dinámico si tiene experiencia en la administración de NSX. Los complementos dinámicos también pueden crearse mediante el soporte de VMware. Un complemento creado debe enviarse a un repositorio de GIT para su validación. Antes de enviar el complemento, debe revisarlo y probarlo.

Administración de seguridad

Tras la finalización de la revisión y la prueba del complemento, el complemento, el resultado de la prueba y los cambios de código se envían para su validación a un repositorio de GIT. Utilizar los siguientes detalles del repositorio de GIT

  • GitLab: https://gitlab.eng.vmware.com/core-build/nsbu-sha-plugin
  • Producto: nsx-sha-plugins
  • Compatibilidad de Gitreview: Por el equipo de VMware

Una vez que el complemento se valida y se aprueba, se confirma en el repositorio de GIT. Todos los complementos dinámicos se compilan y se firman cuando se crea una nueva compilación. Cada complemento se empaqueta y se firma por separado. Puede obtener el complemento necesario de los archivos publicados de la compilación.

Cuando un complemento firmado se carga en el plano de administración, el plano de administración utiliza una clave pública para comprobar la firma y confirmar que este complemento es válido. Después de validar el complemento, los archivos del complemento se insertan en los hosts de destino a través de los canales protegidos entre el plano de administración y el plano de control central (CCP), y entre CCP y los hosts.

Si se reinicia una instancia del agente de estado del sistema (SHA), volverá a obtener los archivos del complemento del plano de administración. Dado que todos los archivos se publican a través de los canales protegidos y no se utilizan archivos temporales, se evita el riesgo de que los hackers puedan modificar scripts.

Además, para evitar riesgos de código perjudicial, SHA utiliza RestrictedPython para comprobar el script de Python del complemento antes de ejecutar el script.

Administración de versiones

Un complemento puede estar basado en un comando o una herramienta que no se admiten en versiones posteriores de NSX, por lo que cada complemento personalizado debe definir la versión de NSX compatible en el archivo manifest.yml. La versión debe ser una cadena de tipo REGEX para todas las versiones compatibles. SHA en el lado del host comprueba la versión del complemento personalizado y ejecuta solo los valores de REGEX coincidentes.

Las directivas de administración de versiones recomendadas son las siguientes:
  • Defina la versión de NSX compatible de una versión principal.

    Teniendo en cuenta que la mayoría de los comandos y las herramientas no cambian entre las versiones secundarias en la misma versión principal, el siguiente método es la forma sugerida para definir la versión de todas las versiones secundarias.

    Por ejemplo,

    version: ^2\.5\.[0-9.]+ <== The custom plugin supporting all NSX 2.5 releases

  • Cuando se publica una nueva versión principal, se deben revisar todos los complementos dinámicos enviados.
  • El autor del complemento debe actualizar el script cuando cambien las herramientas o los comandos relacionados.

Instalar un complemento dinámico

El nodo de transporte o el nodo de Edge en el que está instalado el complemento deben tener un mínimo de 30 MB de espacio de memoria. Además, tenga en cuenta que solo puede instalar 10 complementos como máximo. Una vez que el número de complementos alcance 10, se producirá un error si intenta volver a instalar un complemento.

Para instalar el complemento, realice estas tareas:
  1. Cree los archivos de complemento dinámicos en el repositorio de GIT. Para obtener más información sobre los archivos de complementos, consulte la sección Archivos de complemento dinámico.
  2. Active la compilación del producto en el repositorio de GIT para generar el paquete comprimido de los archivos de complemento dinámicos y descargar el paquete.
  3. Cree el complemento dinámico mediante la siguiente API con el método POST.

    https://<manager_ip>/api/v1/systemhealth/plugins

  4. Cargue el paquete comprimido del complemento de en el plano de administración mediante la siguiente API con el método POST. El plano de administración extrae el archivo cargado y realiza la validación requerida.

    /systemhealth/plugins/<plugin-id>/files/<file-name>/data

    Nota: El tamaño máximo del archivo comprimido del complemento es 500 k.
  5. Cree un grupo de nodos con los nodos de transporte necesarios como miembros mediante la siguiente API con el método POST.

    /<manager_ip>/api/v1/ns-groups

  6. Aplique el perfil de complemento al grupo de nodos mediante la creación de una nueva configuración de servicio mediante la siguiente API. El marco de configuración del servicio envía el contenido del complemento al grupo de nodos.

    https://<manager_ip>/api/v1/service-configs

Para obtener más información sobre las API, consulte la Guía de la API de NSX.

Obtener el estado del complemento

Una vez que se ejecuta el complemento dinámico, carga automáticamente el estado en el plano de administración a través del canal de mensajes actual. El plano de administración agrega la información de estado del complemento y la almacena en la base de datos. Para obtener el estado de todos los complementos en cada nodo, utilice la siguiente API con el método GET.

https://<manager_ip>/api/v1/systemhealth/plugins/status/<transport_node_id>

Ejemplo de solicitud:

GET https://<manager_ip>/api/v1/systemhealth/plugins/status/a257b981-1a1c-4b95-b16c-8646

Ejemplo de respuesta:
{
 "result_count":1,
 "results": [
 {
 "id": "72e1bd4b-6df6-42d0-9c59-a1c31312c9f1",
 "name": "health-check-compute",
 "status": "NORMAL",
 "detail": ""
 }
 ]
 }

Desinstalar un complemento dinámico

Para desinstalar un complemento, elimine la configuración del servicio mediante la siguiente API.

https://<manager_ip>/api/v1/service-configs/<service_config_id>

Otras API para administrar los complementos

En la siguiente tabla, se enumeran las API para administrar complementos dinámicos. Para obtener más información sobre las API, consulte la Guía de la API de NSX.

Tarea Método API
Eliminar un complemento ELIMINAR /systemhealth/plugins/<plugin-id>
Crear un perfil de estado del sistema POST /systemhealth/profiles

Ver el estado del complemento

GET /systemhealth/plugins/status/<node-id>
Habilitar el complemento La habilitación de un complemento es un proceso de dos pasos, como se indica a continuación:
  1. Utilice la siguiente API para establecer la propiedad enabled en true o false.

    https://<manager_ip>/api/v1/systemhealth/profiles/

  2. Utilice la siguiente API para aplicar el perfil SHA al grupo de NS.

    https://<manager_ip>/api/v1/service-configs

Cambiar el intervalo del complemento POST

Cambiar el intervalo del complemento es un proceso de dos pasos, como se indica a continuación:

  1. Utilice la siguiente API para establecer la propiedad config.

    https://<manager_ip>/api/v1/systemhealth/profiles/

  2. Utilice la siguiente API para aplicar el perfil SHA al grupo de NS.

    https://<manager_ip>/api/v1/service-configs

Archivos de complemento dinámico

Un complemento dinámico consta de los siguientes archivos:

  • Instalar archivo de especificaciones
    El archivo de especificación de instalación, manifest.yml, contiene la siguiente información para el agente de estado del sistema:
    • Estructura de complemento
    • Restricciones, si las hubiera
    • Cómo instalar y utilizar el complemento
    • Restricciones de seguridad para el script de comprobación de estado. Por ejemplo, los permisos que tiene el script y los archivos a los que puede acceder el script.
    En la siguiente tabla, se incluyen los campos que se especifican en un archivo manifest.yml.
    Nombre Descripción Requerido/opcional Ejemplo
    classes Especifica las clases necesarias en el script del complemento.

    Las clases se deben especificar con el siguiente formato. '<nombre_módulo>.<nombre_clase>'

    Opcional classes: ['datetime.datetime','datetime.date']
    modules Especifica los módulos necesarios en el script del complemento. Opcional modules: ['random', 'math']
    plugin

    Especifica la estructura del complemento de la siguiente manera:

    config: nombre del archivo de configuración

    script: nombre del archivo de script

    Necesario

    plugin:

    config: plugin.cfg.yml

    script: plugin.py

    version Especifica las versiones de NSX en las que se puede instalar este complemento. Necesario version: '^3\.1\.[0-9.]+'
    node_type

    Especifica tipos de nodos de NSX en los que se puede instalar este complemento. Los tipos de nodo disponibles son:

    • nsx-esx
    • nsx-bms
    • nsx-edge
    Necesario node_type: ['nsx-esx']
    metrics Especifica las métricas que se pueden consumir en el script del complemento. Opcional metrics: ['nsx.host.host-metrics']
    precondition

    Especifica la condición previa para el complemento. La condición previa disponible es wavefront.

    Nota: Este campo solo se aplica en un entorno de VMware Cloud (VMC).
    Opcional precondition: ['wavefront']
    No utilice los siguientes módulos integrados:
    • os

    • subprocess

    • sys

    • multiprocessing

    • importlib

    En la siguiente tabla, se enumeran las interfaces que se deben utilizar en lugar de las funciones integradas de los módulos correspondientes. Estas interfaces están proporcionadas por el sistema. Puede utilizarlos directamente sin especificar su módulo/clase en el archivo manifest.yml.
    Módulo Función integrada Interfaz de sustitución
    datetime datetime.date.strftime(self, fmt)

    datetime_date_strftime(dt, fmt)

    :param dt: date instance

    :param fmt: format string

    datetime datetime.date.today() datetime_date_today()
    sys sys.getrecursionlimit() sys_getrecursionlimit()
    sys sys.getrefcount(object) sys_getrefcount(object)
    sys sys.getsizeof(object, default) sys_getsizeof(object, default)
    sys sys.maxsize sys_maxsize
    sys sys.path sys_path
    Ejemplo de un archivo manifest.yml.
    # specify classes needed in plugin script 
    classes: ['datetime.datetime','datetime.date']
    # specify modules needed in plugin script 
    modules: ['random', 'math']
    # plugin structure
    plugin:
     config: plugin.cfg.yml
     script: plugin.py
    # specify nsx versions on which this plugin can be installed
    version: '^3\.1\.[0-9.]+'
    # specify nsx node type where this plugin can be installed
    node_type: ['nsx-esx']
    # specify metrics which can be consumed in plugin script
    metrics: ['nsx.host.host-metrics']
    # specify precondition for plugin 
    precondition: ['wavefront']
  • Archivo de perfil predeterminado

    El archivo de perfil predeterminado, plugin.cfg.yml, se utiliza para configurar el comportamiento del complemento, como la frecuencia de ejecución del script de comprobación de estado. Para cambiar las configuraciones predeterminadas, puede crear un perfil de SHA para un complemento dinámico específico y aplicarlo al nodo de transporte a través del grupo de NS mediante el plano de administración de a CCP para el canal de NestDB.

    En la siguiente tabla, se incluyen los campos que se especifican en un archivo plugin.cfg.yml.
    Nombre Descripción Requerido/opcional Ejemplo
    CHECK_INTERVAL Especifica el intervalo predeterminado en segundos para la ejecución del script de complemento. Necesario CHECK_INTERVAL: 20
    HABILITAR Especifica si el complemento está habilitado de forma predeterminada. Necesario ENABLE: true
    Ejemplo de un archivo plugin.cfg.yml.
    # Required field - default interval (unit: second) between plugin script executions.
    CHECK_INTERVAL: 20
    
    # Required field - whether plugin is enabled by default
    ENABLE: true
    
    # Plugin user can add other fields as below if needed to control plugin script logic.
    EXPORT_DATA: true
  • Script de comprobación de estado

    Un archivo de script de comprobación de estado, plugin.py, contiene un script Python para comprobar el estado de un nodo de transporte.

    En la siguiente tabla, se incluyen las funciones y las variables definidas por el sistema que se pueden utilizar y los datos que pueden leerse en un archivo plugin.py.
    Variable/Datos/Función Descripción Tipo Ejemplo
    logger Escribe la información de registro en syslog. La variable definida por el sistema, el registrador, se puede utilizar directamente en el script del complemento.

    El registro de salida tiene como prefijo el nombre y el identificador del complemento, tal como se muestra en la siguiente salida de ejemplo.

    2020-10-28T10:47:43Z nsx-sha: NSX 2101378 - [nsx@6876 comp="nsx-esx" subcomp="nsx-sha" username="root" level="INFO"] [name:hl-esx-002-04][id:a3eb14f1-d185-4bc7-bfaa-6cf888bbeb22] dynamic plugin - not export data

    Variable logger.info("this is a demo log")
    data_store

    El diccionario existente definido por el sistema que se utiliza para recuperar los datos proporcionados por el sistema. Por ejemplo: profile, metric y host_id.

    Variable profile = data_store['profile']
    profile

    Los datos de perfil son un diccionario analizado desde el perfil predeterminado (plugin.cfg.yml) o el perfil de SHA efectivo (aplicado por el usuario a través de la API del administrador) que se lee desde data_store. Tiene el siguiente formato:

    {'ENABLE': True, 'CHECK_INTERVAL': 20, 'EXPORT_DATA': True}

    Datos profile = data_store['profile']
    metric

    La métrica es un diccionario con 'value' y 'timestamp' que se lee desde data_store. Tiene el siguiente formato:

    data_store['metrics'][<nombre_métrica>]

    Donde

    La primera clave debe ser 'metrics'.

    La segunda clave es un nombre de métrica existente.

    Datos

    metric = data_store['metrics']['nsx.host.host-metrics']

    metric is: {

    ‘value’:XXX, <== the collected data of the metric

    ‘timestamp’: XXX <== timestamp of the data collected

    }

    Nota: es posible que la primera ejecución del complemento no devuelva una métrica, ya que actualmente se recopila una métrica asyncly con el complemento en ejecución, por lo que es posible que la métrica no se haya recopilado en la primera ejecución del complemento.

    host_id host_id es una instancia de la clase uuid.UUID que se lee desde data_store. Datos host_id = data_store['host_id']
    run_command Esta función ejecuta comandos en formato de lista. Tiene el siguiente formato.

    run_command(cmd, timeout=4)

    Donde

    • cmd: comandos que se ejecutarán. Debe tener el formato de lista como se muestra en el ejemplo.
    • timeout: tiempo de espera para la espera del resultado del comando. El tiempo de espera predeterminado es 4 s. El tiempo de espera no debe establecerse en más de 20 s.

    Esta función devuelve el resultado de la ejecución del comando.

    Función

    cmd = ['nsxdp-cli', 'ipfix', 'settings', 'granular', 'get', '--dvs-alias', 'nsxvswitch', '--dvport=dafa09ca-33ed-4e04-ae3d-1c53305d5fe6']

    res = run_command(cmd)

    Exportdata Esta función exporta datos a wavefront. Actualmente, un complemento dinámico solo admite la exportación a wavefront.
    Nota: Esta función solo se aplica en un entorno de VMware Cloud (VMC).
    Tiene el siguiente formato:

    Exportdata: ExportData(data={}, exports=[], source=host_uuid)

    Donde

    data: datos que se van a exportar; los datos deben tener el formato de diccionario como ejemplo.

    exports: lista de destinos para la exportación. En HL, solo admite wavefront en el destino. Es obligatoria.

    source: cadena de origen para la exportación. Resulta útil solo para el destino de wavefront. Es opcional, el valor predeterminado es host_uuid de NSX.

    La función no devuelve ningún valor.

    Función Exportdata(data={'esx.plugin.stats': {'stats': {'gc-esx-001': data}}}, exports=['wavefront'])
    Ejemplo de un archivo plugin.py.
    def report_test_data(edge_service_status):
        if edge_service_status == 'running':
            data = 2
        else:
            data = 3
        
        # examples on how to report data to wavefront.
        Exportdata(data={'esx.plugin.stats': {'stats': {'esx-dynamic-plugin-001': data}}}, exports=['wavefront'])
    
    
    def run():
        # examples on how to write log.
        logger.debug("this is a debug message!")
        logger.info("this is a demo message!")
        
        # examples on how to use specified module in manifest. Take 'random' as an example.
        s_res = random.randint(1,10)
        logger.warn("random.randint(1,10)=%s", s_res)
        
        # examples on how to use specified class in manifest. Take 'datetime' and 'date' as an example.
        logger.info('date.ctime(datetime.now()):{}'.format(date.ctime(datetime.now())))
        
        # examples on how to run cmd via interface run_command
        cmd = ['nsxdp-cli', 'ipfix', 'settings', 'granular', 'get', '--dvs-alias', 'nsxvswitch', '--dvport=dafa09ca-33ed-4e04-ae3d-1c53305d5fe6']
        c_res = run_command(cmd)
        logger.error("run_command(cmd) res:%s", c_res)
        
        # examples on how to read existing metrics from data_store
        m_res = data_store['metrics']['nsx.host.host-metrics']
        # examples on how to read effective profile from data_store
        profile = data_store['profile']
        logger.error("data_store['metrics']['nsx.host.host-metrics']:%s, profile:%s", m_res, profile)
        
        # examples on how to read host_id from data_store
        host_id = data_store['host_id']
        logger.info('host_id:{}'.format(host_id))
    
        if profile['EXPORT_DATA']:
            report_test_data('running')
            logger.info("dynamic plugin - exported data to wavefront")
        else:
            logger.info("dynamic plugin - not export data ")
        
        # examples on how to use substitute interfaces for sys. 
        logger.info("sys_path:{}".format(sys_path))
        logger.info("sys_getsizeof(1):{}".format(sys_getsizeof(1)))
        logger.info("sys_getrefcount(cmd):{}".format(sys_getrefcount(cmd)))
        logger.info("sys_maxsize:{}".format(sys_maxsize))
        logger.info("sys_getrecursionlimit():{}".format(sys_getrecursionlimit()))
        
        # examples on how to use substitute interfaces for datetime.
        today = datetime_date_today()
        logger.info("datetime today:{}".format(today))
        logger.info("datetime_date_strftime now:{}".format(datetime_date_strftime(datetime.now(), '%H:%M')))
        logger.info('date.ctime(today):{}'.format(date.ctime(today)))
    
    
    run()