Linux: Acione um alarme em tempo real em uma condição de pouco espaço em disco

2

Eu quero assinar um daemon, no estilo inotify, para receber uma notificação quando o espaço livre em um determinado sistema de arquivos cair abaixo de uma determinada porcentagem. Isso é possível?

    
por weaver 07.05.2012 / 20:05

3 respostas

1

Isso funciona como um mecanismo baseado em eventos. Eu não corri por longos períodos, então não vou garantir sua estabilidade.

Isso usa uma API de chamada de sistema muito recente chamada fanotify. Provavelmente precisa de um kernel 2.6.37 ou superior para executá-lo (assim o EL5 está fora de questão, por exemplo). Se você receber reclamações que não irá compilar, provavelmente é um kernel muito antigo.

Compila com:

gcc -o notifier notifier.c

A maneira como funciona é assim: -

./notifier /home/file /dev/shm/monit 10

Os argumentos são os seguintes:

  1. Um arquivo no sistema de arquivos que você deseja monitorar.
  2. Um caminho para um arquivo que será criado se você ultrapassar o limite (e será excluído se estiver sob)
  3. Uma porcentagem de espaço livre que deve estar disponível para estar abaixo do limite.

Isto irá configurar o monitor. Cada identificador de arquivo fechado no sistema de arquivos que tinha um sinalizador de gravação aberto inicia a verificação de evento.

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <linux/fanotify.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <fcntl.h>

int main(const int argc, const char **argv) {
    if (argc < 4) {
        fprintf(stderr, "Supply a path to a file on the mountpoint to listen to, a monitor file and a free %% threshold..\n");
        exit(1);
    }

    if (access(argv[1], R_OK) < 0) {
        fprintf(stderr, "Unable to read file: %s\n", strerror(errno));
        exit(1);
    }

    int len, rc;
    unsigned char donestat = 0,  alerted = 0;
        const char *path = argv[1];
    const char *monpath = argv[2];
    int threshold = atoi(argv[3]);
    char buf[4096];
    struct fanotify_event_metadata *fem = NULL;
    int fan_fd = -1;
    uint64_t mask = FAN_CLOSE_WRITE;
    struct statvfs sfs;
    float bfree;

    memset(&sfs, 0, sizeof(sfs));
    unlink(monpath);

    if (threshold <= 0 || threshold >= 100) {
        fprintf(stderr, "Incorrect threshold provided");
        rc = 1;
        goto end;
    }

    fan_fd = fanotify_init(FAN_CLASS_NOTIF, FAN_CLOEXEC);
    if (fan_fd < 0) {
        perror("fanotify_init");
        rc = 1;
        goto end;
    }

    rc = fanotify_mark(fan_fd, FAN_MARK_ADD|FAN_MARK_MOUNT, mask, AT_FDCWD, path);
    if (rc < 0) {
        perror("fanotify_mark");
        rc = 1;
        goto end;
    }

    while ((len = read(fan_fd, buf, sizeof(buf))) > 0) {
        fem = (void *)buf;
        donestat = 0;

        while (FAN_EVENT_OK(fem, len)) {
            if (fem->vers < 2) {
                fprintf(stderr, "fanotify is too old\n");
                goto end;
            }

            if (!donestat) {
                rc = fstatvfs(fem->fd, &sfs);
                if (rc < 0) {
                    perror("fstatvfs");
                    rc = 1;
                    goto end;
                }
                bfree = 100 - (((float)(sfs.f_blocks - ((sfs.f_blocks - sfs.f_bfree))) / (float)(sfs.f_blocks)) * 100);
                if ((bfree < (float)threshold)) {
                    if (!alerted) {
                        creat(monpath, S_IRUSR|S_IWUSR);
                        alerted = 1;
                    }
                }
                else {
                    if (alerted) {
                        unlink(monpath);
                        alerted = 0;
                    }
                }
            }
            donestat = 1;
            close(fem->fd);
            fem = FAN_EVENT_NEXT(fem, len);
        }
    }
    if (len < 0) {
        perror("Read fan_fd");
        rc = 1;
        goto end;
    }

end:
    close(fan_fd);
    exit(rc);
}

De lá, você pode usar o inotify para observar o arquivo a ser criado / excluído para saber o resultado.

Para testar, defina o limite para algo que você sabe violar agora e, em seguida, toque em um arquivo no sistema de arquivos afetado. Você deve ter seu arquivo de monitor criado.

Obviamente, é provavelmente melhor colocar o arquivo do monitor em algum lugar que não esteja no mesmo sistema de arquivos (/ dev / shm é um bom lugar).

    
por 08.05.2012 / 00:13
4

Você pode usar o utilitário Monit para isso. Você pode definir o intervalo com o qual isso é verificado, mas 60 segundos é a norma para pesquisa.

A configuração do monitoramento do sistema de arquivos será semelhante a:

check device root with path /
    if SPACE usage > 80% then alert

check device var with path /var
    if SPACE usage > 80% then alert
    
por 07.05.2012 / 20:18
1

Uma vez que haverá mais coisas que você deseja monitorar, você pode querer passar algum tempo aprendendo nagios. Parece que você teve um caso em que ficou sem espaço, e não quer que essa falha específica aconteça novamente. Mas os sistemas podem falhar de maneiras inesperadas e todos os serviços devem ser monitorados.

Em uma pitada, você pode simplesmente usar os plugins. Eles são fáceis de instalar e fazem o que dizem (o check_disk verifica o espaço em disco). Eles retornam "não 0" na falha. A falha pode ser um aviso, crítica ou desconhecida.

apt-get install nagios-plugins

Adicionar algo assim ao crontab irá disparar $ send_error no fracasso. Será desencadeado se > 50% da partição "/" é usada.

send_error="command you want to run on failure"
*/5 * * * *  /usr/lib/nagios/plugins/check_disk -w 50% -c 25% -p / || $send_error
    
por 07.05.2012 / 21:56