sábado, 25 de janeiro de 2014

Olho de Cylon do systemd

Um recurso imbatível do systemd é o olho de Cylon! ☺

Quando um daemon está demorando demais para iniciar ou terminar, o systemd exibe, desde a versão 198, esta temível animação:

http://youtu.be/PQfOwtBe9Bs

Infelizmente, com quiet nas opções de boot, não a vemos. Como remover quiet faz o kernel ficar muito falante, a melhor saída é mantê-la e adicionar systemd.show_status=1 e, para tirar o Plymouth, plymouth.enable=0.

[Atualização - 08/08/2014] O limite de tempo para desistir de esperar é de 90s se não for especificado no .service, seguindo a configuração global de /etc/systemd/system.conf. Os parâmetros para modificar são DefaultTimeoutStartSec= e DefaultTimeoutStopSec=. Evite mexer na configuração global. Configure em cada serviço quando necessário com TimeoutStartSec=, TimeoutStopSec= e TimeoutSec= (o último configura os anteriores de uma só vez).

Se não tiver aí nenhum daemon mal comportado (ainda bem!), aqui está o código do daemon fajuto que usei:

fajuto.c

#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <systemd/sd-daemon.h>
#include <systemd/sd-journal.h>

const int wait_time = 40;

void signal_handler(int signum)
{
    switch(signum)
    {
        case SIGABRT:
            sd_journal_print(LOG_NOTICE, "SIGABRT recebido, saindo com erro.");
            exit(EXIT_FAILURE);
            break;
        case SIGTERM:
            sd_journal_print(LOG_NOTICE, "SIGTERM recebido, esperando %ds para sair...", wait_time);
            sleep(wait_time);
            exit(EXIT_SUCCESS);
            break;
    }
}

int main(void)
{
    signal(SIGABRT, signal_handler);
    signal(SIGTERM, signal_handler);

    sd_notify(0, "READY=1");

    sd_journal_print(LOG_NOTICE, "Fajuto rodando. Passar bem.");

    while(1)
      ;

    return EXIT_SUCCESS;
}

/etc/systemd/system/fajuto.service

[Unit]
Description=Fajuto

[Service]
Type=notify
ExecStart=/usr/local/bin/fajuto

[Install]
WantedBy=multi-user.target

Compilação/instalação:

# yum -y install gcc glibc-devel systemd-devel
$ gcc -o fajuto fajuto.c -lsystemd-daemon -lsystemd-journal
$ strip fajuto
# mv fajuto /usr/local/bin
# chown root:root /usr/local/bin/fajuto

# systemctl daemon-reload
# systemctl enable fajuto.service
# systemctl start fajuto.service

O daemon não faz nada. É apenas um loop infinito. Ao receber SIGABRT, termina com exit code 1 (falha). Quando recebe SIGTERM, espera 40 segundos antes de terminar com exit code 0 (sucesso). Ao finalizar os processos durante o desligamento do sistema, a demora faz o systemd acionar o olho de Cylon (o temporizador é de 5 segundos). Podemos observar o comportamento, sem a animação ☹, com:

# systemctl --no-block stop fajuto.service
# systemctl status fajuto.service
fajuto.service - Fajuto
   Loaded: loaded (/etc/systemd/system/fajuto.service; enabled)
   Active: deactivating (stop-sigterm) since Sáb 2014-01-25 19:39:48 BRST; 14s ago
 Main PID: 219 (fajuto)
   CGroup: /system.slice/fajuto.service
           └─219 /usr/local/bin/fajuto

Jan 25 19:37:48 PLUTO systemd[1]: Starting Fajuto...
Jan 25 19:37:48 PLUTO fajuto[219]: Fajuto rodando. Passar bem.
Jan 25 19:37:48 PLUTO systemd[1]: Started Fajuto.
Jan 25 19:39:48 PLUTO systemd[1]: Stopping Fajuto...
Jan 25 19:39:48 PLUTO fajuto[219]: SIGTERM recebido, esperando 40s para sair...

Veja que, na saída de systemctl status, o estado do serviço ficará em "deactivating (stop-sigterm)" durante os 40 segundos até o daemon finalizar sua execução.

Testemos também systemctl kill:

# systemctl start fajuto.service
# systemctl kill --signal=SIGABRT fajuto.service
# systemctl status fajuto.service
fajuto.service - Fajuto
   Loaded: loaded (/etc/systemd/system/fajuto.service; enabled)
   Active: failed (Result: exit-code) since Sáb 2014-01-25 19:42:43 BRST; 8s ago
  Process: 701 ExecStart=/usr/local/bin/fajuto (code=exited, status=1/FAILURE)
 Main PID: 701 (code=exited, status=1/FAILURE)

Jan 25 19:41:52 PLUTO fajuto[701]: Fajuto rodando. Passar bem.
Jan 25 19:41:52 PLUTO systemd[1]: Started Fajuto.
Jan 25 19:42:43 PLUTO fajuto[701]: SIGABRT recebido, saindo com erro.
Jan 25 19:42:43 PLUTO systemd[1]: fajuto.service: main process exited, code=exited, status=1/FAILURE
Jan 25 19:42:43 PLUTO systemd[1]: Unit fajuto.service entered failed state.

Como comentado no post Básico dos arquivos unit do systemd, SuccessExitStatus=1 (na seção [Service]), por exemplo, faria o systemd considerar o exit code 1 como sucesso e o serviço não entraria em estado de falha.

Para desinstalar:

# systemctl stop fajuto.service
# systemctl disable fajuto.service
# rm -f /usr/local/bin/fajuto
# rm -f /etc/systemd/system/fajuto.service
# systemctl daemon-reload

Referências:
system shutdown: what unit is taking so long?
Allow stop jobs to be killed during shutdown
Opções de boot permanentes no GRUB
Limpando o menu de boot do Fedora

Tribute to the Original Cylon Centurions
Cylons (RDM) - Battlestar Wiki

[Atualização - 02/04/2014] Link em vez de embed.

Nenhum comentário:

Postar um comentário