sábado, 28 de dezembro de 2013

Básico dos arquivos unit do systemd

Desconsiderando daemons ativados por soquete/dbus, a seguir algumas das principais opções da seção [Service] dos arquivos unit.

Type=

Define como o systemd tratará o processo executado por ExecStart=.
forking

Binários que usem o clássico comportamento de criar um processo separado do inicial via fork() como descrito em daemon(7). Essa opção existe para compatibilidade; deve ser evitada se possível quando o programa suportar rodar diretamente sem "daemonização".

simple

O padrão quando Type= não for especificado. Para daemons que não usem fork(). Não leva em conta o estado de execução para dependências. No momento em que o binário começar a ser executado, o systemd considerará que sua inicialização está completa (o que nem sempre é o caso) e prosseguirá.

oneshot

Mesma coisa que simple, mas apenas inicia dependências quando o processo terminar sua execução. Não serve para daemons.

idle

Mesma coisa que simple, porém com uma modificação para rodar o binário depois que não haver mais jobs pendentes. Específico para gettys. Tem pouca utilidade para daemons.

notify

Melhor de todos. Tem as vantagens de simple e leva em conta para dependências quando o daemon está pronto. Precisa que o código do daemon seja modificado para usar a API de notificação do systemd. Ou seja, o código do programa precisa ser levemente alterado. Exemplo: rsyslog.
PIDFile=

Válido para serviços do tipo forking. Indica o arquivo pid contendo o processo principal do daemon. Se não for especificado, o systemd tentará autodetectar.

ExecStartPre=

Serve para rodar algum preparativo antes do daemon ser iniciado. Pode ser repetido. Os comandos serão executados de forma serial, um depois do outro. Não foi feito para rodar daemons nem processos duradouros.

ExecStart=

A opção mais importante: especifica o que deve ser executado. Com Type=oneshot, pode ser repetido e os comandos serão executados de forma serial, um após o outro.

ExecStartPost=

Idem a ExecStartPre=, mas executado após ExecStart= finalizar.

RemainAfterExit=

Diz para o systemd ignorar quando o(s) processo(s) de ExecStart= finalizar(em) e continuar tratando o serviço como ativo, apenas rodando eventuais comandos de ExecStop= quando for manualmente parado. Costuma ser usado em conjunto com Type=oneshot para rodar programas que precisem ser executados uma única vez.

EnvironmentFile=

Informa um arquivo contendo definições de variáveis (FOO=bar), que são substituídas dentro do arquivo unit. Muito usado para importar configurações de /etc/sysconfig.

ExecStop=

O systemd envia SIGTERM (e SIGKILL depois de um temporizador) para todos os processos do serviço no momento de finalizá-lo. Com o uso de cgroups, nenhum consegue fugir. O daemon precisa reagir corretamente ao sinal. Quando não o fizer, o comando necessário para terminá-lo é especificado aqui.

Para enviar sinal durante a execução:
systemctl kill --signal=<sinal> <nome>.service (caso --signal= não seja especificado, usa SIGTERM)

Para escolher quem receberá o sinal:
systemctl kill --signal=<sinal> --kill-who=<main|control|all> <nome>.service
all → todos os processos. (padrão)
main → apenas o processo principal.
control → processos iniciados por ExecStartPre=, ExecStartPost=, ExecReload=, ExecStop= e o processo pai de ExecStart= caso seja do tipo forking.
KillMode=

Mesmo com ExecStop= presente, os sinais descritos acima ainda são enviados automaticamente após sua execução. KillMode= configura como os processos serão finalizados pelo mecanismo interno.
control-group → todos os processos do daemon passarão pelo rodo. (padrão)
process → apenas o processo principal.
none → nenhum processo.
ExecReload=

Quando o daemon suportar algum tipo de reload, usado para recarregar as configurações sem interromper o serviço, ExecReload= instrui o init como executá-lo. Geralmente contém um comando do próprio binário ou então um /usr/bin/kill -<sinal> $MAINPID. Essa é uma variável mantida pelo systemd contendo o pid do processo principal do daemon. Não existe uma padronização de como binários diversos lidam com reload, por isso o systemd não generalizou esse trabalho. É comum um SIGHUP ser o suficiente, mas só lendo a documentação do daemon para ter certeza. Caso o arquivo .service não contenha a entrada, você pode usar systemctl kill como comentado acima para enviar sinais diretamente durante a execução.

StandardOutput=

Controla onde a saída dos processos (STDOUT) do serviço em questão será conectada. Por padrão, joga no journal. Opções disponíveis: inherit, null, tty, syslog, kmsg, journal, syslog+console, kmsg+console, journal+console ou socket.

StandardError=

Idem acima, porém para STDERR. O padrão é inherit, que usa a mesma configuração de StandardOutput=. Ou seja: journal.

---
Quem se depara pela primeira vez com o systemd pode pensar que é possível usar shell script dentro dos arquivos unit. Atenção: são arquivos INI-style e não shell scripts.

Todos os comandos colocados em Exec<foo> precisam ter seu caminho absoluto (/usr/bin/blabla) especificado. Repetindo: os arquivos unit não são shell scripts. Argumentos de linha de comando contendo espaços devem ser colocados assim:

ExecStart=/usr/bin/blabla "--bla=foo bar"

Os comandos especificados nas opções Exec<foo> podem ser prefixados com um hífen, que indica para o systemd desconsiderar exit codes anormais (ou arquivo inexistente para EnvironmentFile=), mantendo o serviço como ativo e não em estado de falha — o que cancela a execução de comandos posteriores. Por exemplo: se o programa de ExecStartPre= terminar com um exit code anormal, o serviço entrará em estado de falha e ExecStart= não será executado. SuccessExitStatus= permite modificar quais valores são tratados como sucesso.

Se você realmente precisar de shell, existem duas opções. Para coisas simples, é possível invocar diretamente o Bash (ou outro shell qualquer) assim:

ExecStart=/usr/bin/bash -c '<lista de comandos>'

Ou então crie um script (/usr/local/libexec é um bom lugar), dê permissão de execução e referencie-o com o caminho completo em ExecStart= num serviço do tipo simple ou, se você quiser que o script termine antes de prosseguir, oneshot.

Por fim, o systemd é compatível com com scripts SysV. Coloque-os em /etc/init.d. Depois de rodar systemctl daemon-reload, será criado um serviço virtual com o nome de cada script e a extensão .service. Note que scripts SysV precisam seguir uma padronização também; não é qualquer shell script que qualifica-se como tal (1, 2). As (poucas) incompatibilidades estão documentadas aqui: Compatibility with SysV.

Isso é o básico para facilitar a interpretação dos arquivos. Não comentei sobre opções de ordenação da seção [Unit] (Requires=, BindsTo=, Before=, After=, etc.) nem de instalação de [Install].

Lembre que não devemos editar diretamente os arquivos presentes em /usr/lib, que é área do gerenciador de pacotes. O systemd provê meios limpos e persistentes para personalizar suas opções. Veja em Modificar parâmetros de arquivos .service.

As man pages são excelentes. Valem a leitura: systemd.index.

Nenhum comentário:

Postar um comentário