Zabbix : superviser les tablespaces Oracle

Publié le 25 January 2019

Dans l’article précédent, nous avons vu comment exécuter des requêtes Oracle depuis Linux. Maintenant nous allons nous en servir pour superviser des tablespaces avec Zabbix.

La supervision va se faire en deux parties : une découverte automatique des tablespaces, et la supervision de l’espace libre.

Un export de mon template et des fichiers nécessaires peut être téléchargé à cette adresse : https://palc.fr/wp-content/uploads/template_oracle_tablespace.zip

La découverte automatique

La découverte des tablespace a été abordée dans l’article précédent, mais je vais revenir dessus.

Je vais utiliser un externalscript. Chez moi ils se trouvent dans le dossier /usr/lib/zabbix/externalscripts. Je vais donc dedans et je créé le fichier oracle_tablespace_discovery.ext :

SET heading OFF;
SET feedback OFF;

SELECT
  a.tablespace_name
FROM
  dba_data_files a
GROUP BY
  a.tablespace_name;

EXIT;

On notera la désactivation des en-tête et autres infos inutiles. Cette commande retourne uniquement les tablespaces, et rien d’autre.

Ensuite je créé un script oracle_tablespace_discovery.sh dans le même répertoire :

#!/bin/bash

LD_LIBRARY_PATH=/usr/lib/oracle/12.1/client64/lib

echo '{
  "data":['

for tablespace in `/usr/lib/oracle/12.1/client64/bin/sqlplus -s "$3/$4( (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = $1)(PORT = $2))) (CONNECT_DATA = (SERVICE_NAME = $5)))" (/usr/lib/zabbix/externalscripts/oracle_tablespace_discovery.ext`
do
  echo -n '    {"{#ORACLE_TABLESPACE_NAME}":"'
  echo -n $tablespace
  echo '"},'
done

echo '    {}'
echo '  ]
}'

Ce script lance la requête Oracle vue dans l’article précédent, et mets le résultat sous un format JSON pour que Zabbix puisse l’interpréter.

À noter le echo ' {}' à la fin. C’est pas très propre, mais c’est une méthode efficace et rapide pour éviter les erreurs JSON sur le dernier résultat retourné.

Maintenant on lance la commande à la main, pour tester :

/usr/lib/zabbix/externalscripts/oracle_tablespace_discovery.sh IP 1521 user password NOM_DU_SERVICE
{
  "data":[
    {"{#ORACLE_TABLESPACE_NAME}":"ZABBIX_TS"},
    {"{#ORACLE_TABLESPACE_NAME}":"UNDOTBS1"},
    {"{#ORACLE_TABLESPACE_NAME}":"SYSAUX"},
    {"{#ORACLE_TABLESPACE_NAME}":"USERS"},
    {"{#ORACLE_TABLESPACE_NAME}":"SYSTEM"},
    {"{#ORACLE_TABLESPACE_NAME}":"WF_TABLE"},
    {}
  ]
}

C’est exactement ce que l’ont veut. Il ne reste plus qu’à créer la règle de découverte correspondante. Elle doit juste avoir pour clé oracle_tablespace_discovery.sh[{HOST.IP},{$ORACLE_PORT},{$ORACLE_USER},{$ORACLE_PASSWORD},{$ORACLE_SERVICENAME}] :

On notera l’utilisation des macros, cette règle de découverte étant destinée à finir dans un template.

La supervision de l’espace libre

Là encore je vais utiliser un externalscript. D’abord la requête SQL, dans le fichier oracle_tablespace_stat.ext :

SET heading OFF;
SET feedback OFF;
SET LINE 250;

SELECT
    a.tablespace_name,
    TO_CHAR(SUM(a.bytes)) "Curb",
    TO_CHAR(SUM(decode(b.maxextend, NULL, A.BYTES, b.maxextend*8192))) "Maxb",
    TO_CHAR((SUM(a.bytes) - ROUND(c."Free"))) "TotalUsed",
    TO_CHAR(SUM(decode(b.maxextend, NULL, A.BYTES, b.maxextend*8192)) - (SUM(a.bytes) - ROUND(c."Free"))) "TotalFree",
    100*(SUM(a.bytes) - ROUND(c."Free"))/(SUM(DECODE(b.maxextend, NULL, A.BYTES, b.maxextend*8192))) "UPercent"
FROM
    dba_data_files a,
    sys.filext$ b,
    (SELECT d.tablespace_name , SUM(nvl(c.bytes,0)) "Free"
    FROM dba_tablespaces d, DBA_FREE_SPACE c
    WHERE d.tablespace_name = c.tablespace_name(+) GROUP BY d.tablespace_name
    ) c
WHERE a.file_id = b.file#(+)
    AND a.tablespace_name = c.tablespace_name
GROUP BY
    a.tablespace_name, c."Free"
ORDER BY
    ROUND(100*(SUM(a.bytes) - ROUND(c."Free"))/(SUM(decode(b.maxextend, NULL, A.BYTES, b.maxextend*8192)))) DESC;

EXIT;

Cette requête retourne le nom du tablespace, deux colonnes dont je ne comprends pas trop l’utilité, puis la taille totale et l’espace libre en octets, et enfin le pourcentage d’utilisation. Comme la requête doit obligatoirement être stockée dans un fichier, je suis obligé de tout retourner à chaque fois, sinon ça impliquerait de créer un fichier à la volée et ça créerait de la complexité.

je teste la requête.

LD_LIBRARY_PATH=/opt/oracle/instantclient_12_2 /opt/oracle/instantclient_12_2/sqlplus -s "user/password@ (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 1.2.3.4)(PORT = 1521))) (CONNECT_DATA = (SERVICE_NAME = NOM_DU_SERVICE)))" @/usr/lib/zabbix/externalscripts/oracle_tablespace_stat.ext

TABLESPACE_NAME Curb Maxb TotalUsed TotalFree UPercent
------------------------------ ---------------------------------------- ---------------------------------------- ---------------------------------------- ---------------------------------------- ----------
WF_TABLE 89120571392 93415538688 83884572672 9530966016 89.797237
SYSAUX 933232640 34359721984 879296512 33480425472 2.55909088
SYSTEM 807403520 34359721984 801243136 33558478848 2.33192555
ZABBIX_TS 104857600 104857600 1048576 103809024 1
USERS 5242880 34359721984 1376256 34358345728 .004005434
UNDOTBS1 728760320 34359721984 14548992 34345172992 .04234316

(ici j’ai réactivé l’affichage de l’en-tête des colonnes, pour que le résultat soit plus facile à comprendre)

Maintenant il reste à exploiter le résultat, via le script oracle_tablespace_stat.sh :

#!/bin/bash

LD_LIBRARY_PATH=/usr/lib/oracle/12.1/client64/lib

/usr/lib/oracle/12.1/client64/bin/sqlplus -s "$3/$4@ (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = $1)(PORT = $2))) (CONNECT_DATA = (SERVICE_NAME = $5)))" @/usr/lib/zabbix/externalscripts/oracle_tablespace_stat.ext | grep -E "^$6\W" | awk "{print \$$7}"

Ce script est assez simple. Il prends les mêmes paramètres que le script de découverte mais en rajouter deux autres : le nom du tablespace, et le numéro de la colonne dont on veut retrouver la donnée. J’ai choisis de faire le filtrage sur le numéro de colonne plutôt que sur son nom pour simplifier la commande. La clé Zabbix est moins clair, mais le script est beaucoup plus simple. C’est un compromis.

Testons le script à la main. Je vais demander le pourcentage d’espace utilisé sur le tablespace WF_TABLE :

/usr/lib/zabbix/externalscripts/stat.sh IP 1521 user password NOM_DU_SERVICE WF_TABLE 6
89.797237

Ce tablespace est bien utilisé à 89%. Le script est donc fonctionnel. Il ne reste plus qu’à créer les items.

Un exemple de clé : oracle_tablespace_stat.sh[{HOST.IP},{$ORACLE_PORT},{$ORACLE_USER},{$ORACLE_PASSWORD},{$ORACLE_SERVICENAME},{#ORACLE_TABLESPACE_NAME},2]

La configuration d’un des items :

Tous les items :

Il ne reste plus qu’à créer le trigger, avec l’expression : {Template Oracle:oracle_tablespace_stat.sh[{HOST.IP},{$ORACLE_PORT},{$ORACLE_USER},{$ORACLE_PASSWORD},{$ORACLE_SERVICENAME},{#ORACLE_TABLESPACE_NAME},6].min(#3)}>90