# - \#5 Módulos carregáveis

#### - Visão geral

Os módulos carregáveis são uma opção para estender as funcionalidades do
Zabbix com o foco em alta performance.

Existem outras formas de se estender as funcionalidades do Zabbix:

-   [parâmetros de usuário](userparameters) (métricas de agente)
-   [verificações externas](/pt/manual/config/items/itemtypes/external)
    (monitoração sem agente)
-   `system.run[]` [Item nativo do
    Zabbix](/pt/manual/config/items/itemtypes/zabbix_agent).

Todas estas formas funcionam muito bem, mas tem um problema intrínseco,
normalmente conhecido como 'fork()'. O Zabbix precisa direcionar um de
seus processos para gerenciar métrica que se quer obter, toda vez que é
necessário coleta-la, e isso não é uma boa opção para performance.
Normalmente isso não é um grande problema, mas se formos fazer uma
monitoração séria de sistemas críticos, com uma grande quantidade de
parâmetros ou scripts muito complexos / longos de se executar... isso
deixa de ser verdade.

O Zabbix 2.2 inovou ao adicionar o suporte a módulos carregáveis para
estender as funcionalidades do Zabbix Agent, Server e Proxy sem perder
performance.

Um módulo carregável é basicamente uma biblioteca compartilhada
utilizada por um processo do Zabbix e carregada junto com o mesmo. A
biblioteca precisará ter determinadas funções para que o Zabbix possa
detecta-las no arquivo e saber como trabalhar com ela.

Os módulos carregáveis tem uma grande quantidade de benefícios. O
aumento de performance e a habilidade de se aplicar qualquer lógica é
muito importante, mas talvez o maior ganho seja a habilidade de
desenvolver, usar e compartilhar os módulos. Isso auxilia nos processos
de manutenção livre de problemas e auxilia a entregar novas
funcionalidades de forma fácil e independente do código base do Zabbix.

#### - API de módulos

Para que uma biblioteca compartilhada possa ser tratada como um módulo
do Zabbix, é muito importante que ela implemente e exporte determinadas
funções. Atualmente são cinco as funções da API de módulos do Zabbix,
sendo duas obrigatórias e as outras três opcionais.

##### - Interfaces obrigatórias

As duas funções obrigatórias são: **zbx\_module\_api\_version()** e
**zbx\_module\_init()**:

``` {.c}
int zbx_module_api_version(void);
```

Esta função deve retornar a versão da API implementada no móduo,
atualmente existe somente uma versão: ZBX\_MODULE\_API\_VERSION\_ONE
(definida com o valor 1), então esta função deverá retornar esta
constante.

``` {.c}
int zbx_module_init(void);
```

Esta função é responsável por fazer a inicialização do módulo (se
existir). Se for concluída com sucesso deverá retornar: ZBX\_MODULE\_OK.
Em qualquer outra situação, deverá retornar: ZBX\_MODULE\_FAIL.

##### - Interfaces opcionais

Existem três funções opcionais: **zbx\_module\_item\_list()**,
**zbx\_module\_item\_timeout()** e **zbx\_module\_uninit()**:

``` {.c}
ZBX_METRIC  *zbx_module_item_list(void);
```

Esta função deverá retornar uma lista de itens suportados no módulo.
Cada item é definido como uma estrutura 'ZBX\_METRIC', veja a seção a
seguir para detalhes. Uma lista ZBX\_METRIC deverá possuir uma estrutura
onde o último campo **key** tem o valor **NULL**.

``` {.c}
void    zbx_module_item_timeout(int timeout);
```

Esta função é utilizada pelo Zabbix para especificar as configurações de
'timeout' no arquivo de configuração do Zabbix que o módulo deverá
obedecer. O tempo de espera é definido em segundos.

``` {.c}
int zbx_module_uninit(void);
```

Esta função executa a liberação de recursos, tal qual liberar recursos
alocados, fechar descritores de arquivo, etc..

Todas as funções são chamadas durante a inicialização do Zabbix, quando
o módulo é carregado, com exceção da função **zbx\_module\_uninit()**,
que será chamada quando o Zabbix estiver sendo terminado.

##### - Definindo itens

Cada item é definido com uma estrutura 'ZBX\_METRIC':

``` {.c}
typedef struct
{
    char        *key;
    unsigned    flags;
    int     (*function)();
    char        *test_param;
}
ZBX_METRIC;
```

Nesta estrutura:

-   **key** - a chave do item (ex. "dummy.random")
-   **flags** - pode ser 'CF\_HAVEPARAMS' ou '0' (dependendo do item
    aceitar parâmetros ou não)
-   **function** - é uma função em C que implementa o item (ex.
    "zbx\_module\_dummy\_random")
-   **test\_param** - é ua lista de parâmetros para ser utilizada quando
    o Zabbix Agent for inicializado usando a marca "-p" (ex "1,1000",
    pode ser 'NULL'). Uma exemplo de definição usando esta estrutura
    pode ser:

``` {.c}
static ZBX_METRIC keys[] =
{
    { "dummy.random", CF_HAVEPARAMS, zbx_module_dummy_random, "1,1000" },
    { NULL }
}
```

Cada função que implementa um item deve aceitar dois ponteiros, o
primeiro com o tipo AGENT\_REQUEST, o segundo com o tipo AGENT\_RESULT:

``` {.c}
int zbx_module_dummy_random(AGENT_REQUEST *request, AGENT_RESULT *result)
{
    ...

    SET_UI64_RESULT(result, from + rand() % (to - from + 1));

    return SYSINFO_RET_OK;
}
```

Estas funções deverão retornar 'SYSINFO\_RET\_OK', se o valor foi obtido
com sucesso. Qualquer outra situação o retorno deverá ser
'SYSINFO\_RET\_FAIL'. Veja o exemplo do módulo "dummy" a seguir para
detalhes sobre como obter informações sobre o AGENT\_REQUEST e como
configurar o AGENT\_RESULT.

##### - Construindo os módulos

Os módulos precisam ser construídos internamente na árvore do código
fonte do Zabbix, pois o módulo depende de algumas estruturas de dados
que são definidas nos cabeçalhos do Zabbix.

O cabeçalho mais importante para os módulos carregáveis é
**include/module.h**, que define as estruturas de dados. Outro cabeçalho
útil é **include/sysinc.h**, que faz a inclusão dos cabeçalhos de
sistema que serão necessários, que por sua vez auxilia o
**include/module.h** a funcionar adequadamente.

Para que **include/module.h** e **include/sysinc.h** sejam incluídos, o
comando **./configure** (sem parâmetros) deverá ser executado no
diretório raiz dos fontes do Zabbix. Isso irá criar o arquivo
**include/config.h**, com as dependências do **include/sysinc.h**. (Se
você tiver obtido o código fonte do Zabbix a partir do "Subversion
repository", o script **./configure** não existirá e o comando
**./bootstrap.sh** deverá ser executado primeiro para gera-lo.)

Com esta informação em mente, tudo está pronto para criar o módulo. O
módulo deverá incluir **sysinc.h** e **module.h**, e o script de criação
se certificará que estes dois arquivos estão disponíveis no **path**.
Veja o exemplo do módulo "dummy" a seguir para maiores detalhes.

Outro cabeçalho útil é o **include/log.h**, que define a função
**zabbix\_log()**, que poderá ser utilizada com o propósito de registro
e debug.

#### - Parâmetros de configuração

O Zabbix Agent, Server e Proxy suportam dois
[parâmetros](/pt/manual/appendix/config/zabbix_server) para lidar com os
módulos:

-   **LoadModulePath** – caminho completo para a localização dos módulos
    carregáveis
-   **LoadModule** – módulo(s) para ser carregado durante a
    inicialização. Os módulos deverão estar localizados no diretório
    definido em **LoadModulePath**. Também é permitida a inclusão de
    múltiplos módulos.

Por exemplo, para estender o Zabbix Agent nós podemos adicionar os
parâmetros a seguir:

    LoadModulePath=/usr/local/lib/zabbix/agent/
    LoadModule=mariadb.so
    LoadModule=apache.so
    LoadModule=kernel.so
    LoadModule=dummy.so

Quando o agente for inicializado ele irá carregar os módulos
**mariadb.so, apache.so, kernel.so and dummy.so** a partir do diretório
**/usr/local/lib/zabbix/agent**. Se um dos módulos estiver ausente, ou
não tiver com o permissionamento correto, ou não for um 'Módulo Zabbix'
a carga do agente irá falhar.

#### - Configuração na interface web

Os módulos carregáveis são suportados pelo Zabbix Agent, Server e Proxy.
Portanto, o tipo do item depende de onde foi carregado. Se o módulo
tiver sido carregado no agente, o tipo deverá ser "Agente Zabbix" ou
"Agente Zabbix (ativo)". Se o módulo tiver sido carregado no Server ou
Proxy, o tipo do item deverá ser "Verificação simples".

#### - Módulo Dummy

O código fonte do Zabbix 2.2 inclui um exemplo de módulo desenvolvido em
C. O módulo está localizado em **src/modules/dummy**:

    alex@alex:~trunk/src/modules/dummy$ ls -l
    -rw-rw-r-- 1 alex alex 9019 Apr 24 17:54 dummy.c
    -rw-rw-r-- 1 alex alex   67 Apr 24 17:54 Makefile
    -rw-rw-r-- 1 alex alex  245 Apr 24 17:54 README

O módulo é bem documentado e pode ser utilizado como um modelo para que
você construa os seus próprios módulos.

Após executar o **./configure** no diretório raiz dos fontes do Zabbix,
conforme informado anteriormente, apenas execute o comando **make** para
compilar o **dummy.so**.

``` {.c}
/*
** Zabbix
** Copyright (C) 2001-2013 Zabbix SIA
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
** MA  02110-1301, USA.
**/

#include "sysinc.h"
#include "module.h"

/* the variable keeps timeout setting for item processing */
static int    item_timeout = 0;

int    zbx_module_dummy_ping(AGENT_REQUEST *request, AGENT_RESULT *result);
int    zbx_module_dummy_echo(AGENT_REQUEST *request, AGENT_RESULT *result);
int    zbx_module_dummy_random(AGENT_REQUEST *request, AGENT_RESULT *result);

static ZBX_METRIC keys[] =
/* KEY               FLAG           FUNCTION                TEST PARAMETERS */
{
    {"dummy.ping",   0,             zbx_module_dummy_ping,  NULL},
    {"dummy.echo",   CF_HAVEPARAMS, zbx_module_dummy_echo,  "a message"},
    {"dummy.random", CF_HAVEPARAMS, zbx_module_dummy_random,"1,1000"},
    {NULL}
};

/******************************************************************************
*                                                                            *
* Function: zbx_module_api_version                                           *
*                                                                            *
* Purpose: returns version number of the module interface                    *
*                                                                            *
* Return value: ZBX_MODULE_API_VERSION_ONE - the only version supported by   *
*               Zabbix currently                                             *
*                                                                            *
******************************************************************************/
int    zbx_module_api_version()
{
    return ZBX_MODULE_API_VERSION_ONE;
}

/******************************************************************************
*                                                                            *
* Function: zbx_module_item_timeout                                          *
*                                                                            *
* Purpose: set timeout value for processing of items                         *
*                                                                            *
* Parameters: timeout - timeout in seconds, 0 - no timeout set               *
*                                                                            *
******************************************************************************/
void    zbx_module_item_timeout(int timeout)
{
    item_timeout = timeout;
}

/******************************************************************************
*                                                                            *
* Function: zbx_module_item_list                                             *
*                                                                            *
* Purpose: returns list of item keys supported by the module                 *
*                                                                            *
* Return value: list of item keys                                            *
*                                                                            *
******************************************************************************/
ZBX_METRIC    *zbx_module_item_list()
{
    return keys;
}

int    zbx_module_dummy_ping(AGENT_REQUEST *request, AGENT_RESULT *result)
{
    SET_UI64_RESULT(result, 1);

    return SYSINFO_RET_OK;
}

int    zbx_module_dummy_echo(AGENT_REQUEST *request, AGENT_RESULT *result)
{
    char    *param;

    if (1 != request→nparam)
    {
        /* set optional error message */
        SET_MSG_RESULT(result, strdup("Invalid number of parameters"));
        return SYSINFO_RET_FAIL;
    }

    param = get_rparam(request, 0);

    SET_STR_RESULT(result, strdup(param));

    return SYSINFO_RET_OK;
}

/******************************************************************************
*                                                                            *
* Function: zbx_module_dummy_random                                          *
*                                                                            *
* Purpose: a main entry point for processing of an item                      *
*                                                                            *
* Parameters: request - structure that contains item key and parameters      *
*              request→key - item key without parameters                    *
*              request→nparam - number of parameters                        *
*              request→timeout - processing should not take longer than     *
*                                 this number of seconds                     *
*              request→params[N-1] - pointers to item key parameters        *
*                                                                            *
*             result - structure that will contain result                    *
*                                                                            *
* Return value: SYSINFO_RET_FAIL - function failed, item will be marked      *
*                                 as not supported by zabbix                 *
*               SYSINFO_RET_OK - success                                     *
*                                                                            *
* Comment: get_rparam(request, N-1) can be used to get a pointer to the Nth  *
*          parameter starting from 0 (first parameter). Make sure it exists  *
*          by checking value of request→nparam.                             *
*                                                                            *
******************************************************************************/
int    zbx_module_dummy_random(AGENT_REQUEST *request, AGENT_RESULT *result)
{
    char  *param1, *param2;
    int   from, to;

    if (request→nparam != 2)
    {
        /* set optional error message */
        SET_MSG_RESULT(result, strdup("Invalid number of parameters"));
        return SYSINFO_RET_FAIL;
    }

    param1 = get_rparam(request, 0);
    param2 = get_rparam(request, 1);

    /* there is no strict validation of parameters for simplicity sake */
    from = atoi(param1);
    to = atoi(param2);

    if (from > to)
    {
        SET_MSG_RESULT(result, strdup("Incorrect range given"));
        return SYSINFO_RET_FAIL;
    }

    SET_UI64_RESULT(result, from + rand() % (to - from + 1));

    return SYSINFO_RET_OK;
}

/******************************************************************************
*                                                                            *
* Function: zbx_module_init                                                  *
*                                                                            *
* Purpose: the function is called on agent startup                           *
*          It should be used to call any initialization routines             *
*                                                                            *
* Return value: ZBX_MODULE_OK - success                                      *
*               ZBX_MODULE_FAIL - module initialization failed               *
*                                                                            *
* Comment: the module won't be loaded in case of ZBX_MODULE_FAIL             *
*                                                                            *
******************************************************************************/
int    zbx_module_init()
{
    /* initialization for dummy.random */
    srand(time(NULL));

    return ZBX_MODULE_OK;
}

/******************************************************************************
*                                                                            *
* Function: zbx_module_uninit                                                *
*                                                                            *
* Purpose: the function is called on agent shutdown                          *
*          It should be used to cleanup used resources if there are any      *
*                                                                            *
* Return value: ZBX_MODULE_OK - success                                      *
*               ZBX_MODULE_FAIL - function failed                            *
*                                                                            *
******************************************************************************/
int    zbx_module_uninit()
{
    return ZBX_MODULE_OK;
}
```

Este módulo exporta três novos itens:

-   `dummy.ping` - sempre retorna '1'
-   `dummy.echo[param1]` - retorna o primeiro parâmetro que for
    informado, por exemplo, `dummy.echo[ABC]` retornará: ABC
-   `dummy.random[param1, param2]` - retorna um número randômico dentro
    do range definido em param1-param2, por exemplo,
    `dummy.random[1,1000000]`

#### - Limitações

O suporte para módulos carregáveis foi implementado apenas na plataforma
UNIX. Isso significa que não irão funcionar em Agentes para Windows.

Em alguns casos o módulo pode precisar ler parâmetros de configuração do
*zabbix\_agentd.conf*. Isso ainda não é fornecido pela API, se você
precisar obter tais parâmetros você deverá implementar a análise do
arquivo de configurações.
