Como escrever um serviço do usuário systemd que requer uma sessão ativa

1

Eu criei um serviço de usuário systemd para executar um trabalho de backup de duplicidade uma vez por dia às 17:00 de maneira ampla com base em um artigo em Revista Fedora . Estou executando o Fedora 28 com o desktop Gnome. Minha configuração do timer do sistema é:

[Unit]
Description=daily-backup timer

[Timer]
OnCalendar=*-*-* 17:00:00
Unit=daily-backup.service
Persistent=true

[Install]
WantedBy=default.target

Isso funciona bem, exceto no caso em que a máquina foi desligada quando o backup estava prestes a ser executado. Na próxima vez que eu fizer login, a opção persistent garante que o backup seja executado imediatamente. Infelizmente, o script de backup falha neste ponto porque o script tenta ser executado antes que a sessão do usuário esteja ativa. O script de backup inicia tentando montar o disco de backup, se ainda não estiver montado:

#!/usr/bin/env bash

USER=$(whoami)
MOUNTPOINT="/run/media/$USER/$2"
DEVICE=$(blkid -l -o device -t LABEL="$2")

if [ ! -d "$MOUNTPOINT" ]; then
    gio mount --device $DEVICE
fi

# Call duplicity...

Parece, no entanto, que até que a sessão do usuário esteja ativa, o script não pode montar o disco. Eu posso contornar isso pesquisando por uma sessão ativa, mas esta é uma solução grosseira para o problema:

#!/usr/bin/env bash

USER=$(whoami)
MOUNTPOINT="/run/media/$USER/$2"
DEVICE=$(blkid -l -o device -t LABEL="$2")

# Poll for an active session
for i in {1..30}
do
    SESSION_STATE=$(loginctl show-user "$USER" -p State --value)
    [ "$SESSION_STATE" != "active" ] && sleep 1s || break
done

if [ ! -d "$MOUNTPOINT" ]; then
    gio mount --device $DEVICE
fi

Parece que deve haver uma maneira de configurar meu serviço de usuário systemd para exigir uma sessão de usuário ativa, mas não consegui descobrir como fazer isso. Alguém sabe se isso é possível?

    
por suilven 08.05.2018 / 18:04

2 respostas

0

tl; dr (resposta curta)

Eu acredito que não existe esse caminho, pelo menos fora da caixa (na forma de uma diretiva de unidade de sistema ou algo assim). No entanto, isso é certamente possível fora do systemd.

resposta longa

Seria bom se o systemd suportasse o acionamento baseado em eventos (de maneira semelhante ao do udev) ou permitisse a personalização de arquivos de unidade gerados automaticamente. Qualquer idéia, se implementada, resolveria esse problema, mas na verdade ambas são deficiências de longa data do systemd.

Você pode tentar implementar essa lógica por conta própria. Se eu entender corretamente o que você está tentando realmente alcançar, você deseja a semântica de "atrasar" a inicialização até que a sessão se torne ativa, em vez de "ignorar" a inicialização se a sessão estiver inativa quando o cronômetro for acionado.

Em seguida, a idéia básica seria ter um daemon que inicie como um serviço de usuário systemd, ouça os eventos de mudança de estado do logind no barramento do sistema e inicie / pare o cronômetro de acordo. Isso deve ser facilmente possível em Python (infelizmente, o bash está fora de questão porque não há ferramentas amigáveis ao shell que permitam escutar sinais no D-Bus).

    
por 10.05.2018 / 14:45
1

Parece (da linha USER=$(whoami) em seu script) que você está executando este serviço como um usuário não-root (provavelmente configurando User= no seu arquivo daily-backup.service .)

Você pode querer considerar configurar as unidades de serviço e temporizador como serviços do usuário, executadas pelo systemd --user manager.

Para isso, basta criar daily-backup.service e daily-backup.timer no diretório ~$USER/.config/systemd/user/ . Você pode essencialmente usar os arquivos que você criou no diretório do sistema, na maior parte não modificados. (Você pode remover a referência para User= , pois esse será o usuário para o qual você está configurando.)

Use os comandos systemctl --user ... para ativá-los, iniciá-los e verificar o status. Para a seção de instalação, use:

[Install]
WantedBy=default.target

Como o gerenciador de usuários só conhece um default.target (e não, por exemplo, multi-user.target .)

Para que a sessão do usuário inicie na inicialização, você pode ativar o linger; nesse caso, ela começará cedo e ficará ativa:

loginctl enable-linger $USER

(Veja a documentação para loginctl enable-linger .)

Na verdade, olhando para o artigo da Revista Fedora a que você se referiu, parece que é isso que eles tinham em mente. A parte "Automatizar com um temporizador" tem referências a $HOME/.config/systemd/user/ .

Se você quiser ler mais sobre as unidades de usuário do systemd, o Wiki do Arch Linux tem um bom artigo a>.

    
por 09.05.2018 / 07:39