Systemd: Informa se o script foi executado pelo systemd ou pelo usuário

2

Como posso saber se um script foi chamado pelo systemd ou por um usuário?

Eu criei um serviço para um daemon da velha escola. Nós apenas mudamos para systemd e alguns dos meus administradores gostam de chamar o script rc diretamente. Isso não funcionará muito bem no caso de reinicialização da máquina. O Systemd não irá honrar o PIDFile= porque o novo daemon iniciado não faz parte do seu cgroup para o serviço.

Eu adicionei o arquivo de serviço e o rc_script. Eu não posso diferir pelo id do usuário, porque para usar o script o usuário tem que ser foobaruser .

O serviço de parada agora é um problema, porque o systemd reconhecerá isso do arquivo pid excluído.

Então, como eu descubro se o script foi chamado pelo systemd?

foobar.service

[Unit]
Description=Foobar Service
After=syslog.target network.target

[Service]
Type=forking
User=foobaruser
LimitNOFILE=60000
LimitNPROC=8000
TasksMax=8000
PIDFile=/local/foobar/foo.pid
ExecStart=/opt/foobar/rc_script start
ExecStop=/opt/foobar/rc_script stop
TimeoutSec=100
TimeoutStopSec=300
KillMode=none
RemainAfterExit=no
Environment=LANG=de_DE.UTF-8

[Install]
WantedBy=multi-user.target

/ opt / foobar / esqueleto rc_script

#!/bin/bash
case $1 in
start)
  VAR_IS_SYSTEMD=$( ... script to check if bash is run from systemd ... )
  if [ "$VAR_IS_SYSTEMD" = false ] ; then
    sudo systemctl start foobar.service
    exit
  fi
  # start service within systemd
  ;;
stop)
  # stop service
  ;;
esac
    
por notes-jj 14.08.2018 / 17:09

3 respostas

3

Concordo com os outros posters de que você deve tentar reescrever o serviço para não chamar o script (tudo bem se seus administradores quiserem continuar usando-o, mas o serviço systemd precisa de todas as 36 opções?) - mas também não é difícil detectar se o script foi chamado pelo systemd.

  • O systemd v232 adicionou o conceito de um ID de invocação de uma unidade, que é passado para a unidade na variável de ambiente $INVOCATION_ID . Você pode verificar se isso está definido ou não.

  • systemd v231 + define a variável $JOURNAL_STREAM para serviços cujo stdout ou stderr está conectado ao diário, o que parece ser o caso do seu serviço, portanto, você também pode verificar essa variável se estiver no systemd v231. (Na v232 +, $INVOCATION_ID é definitivamente a melhor escolha.)

  • Em versões antigas do systemd, não acho que exista uma variável de ambiente que esteja sempre presente, mas você pode definir uma delas adicionando algo assim ao seu serviço:

    Environment=LAUNCHED_BY_SYSTEMD=1
    
por 22.08.2018 / 13:02
2

Uma solução simples é usar um script diferente para o systemd iniciar. O / opt / foobar / rc_script deve apenas chamar systemctl start foobar.service e systemctl stop foobar.service .

Suse usa $SYSTEMD_NO_WRAP , mas não sei se isso é padrão do systemd ou específico do Suse.

if test -z "$SYSTEMD_NO_WRAP"; then
...
    /usr/bin/systemctl [start|stop] xxx.service
    
por 14.08.2018 / 21:34
0

Para o "Amazon Linux 2" e o "Red Hat Enterprise Linux 7", encontrei uma solução.

Nesses sistemas de sistema Linux, processo PID=1 é comm=systemd . O ID pai PPID do script iniciado pelo systemd é 1 .

Pode haver outros sistemas Linux onde isso não é o caso.

#!/bin/bash
VAR_IS_SYSTEMD_SYSTEM=$( [[ $(ps -o comm -p 1 --no-headers | tr -d ' ') == "systemd" ]] && echo true )
echo VAR_IS_SYSTEMD_SYSTEM = ${VAR_IS_SYSTEMD_SYSTEM}

VAR_IS_DAEMON_SCRIPT=$( [[ "${PPID}" == "1" ]] && echo true )
echo VAR_IS_DAEMON_SCRIPT = ${VAR_IS_DAEMON_SCRIPT}

if [[ "${VAR_IS_SYSTEMD_SYSTEM}" = true ]] && [[ "${VAR_IS_DAEMON_SCRIPT}" = true ]]; then
  echo "You are a systemd Daemon Script"
else
  echo "You are a normal Script"
fi

Elementos / Comandos usados:

  • ps -o comm -p 1 --no-cabeçalhos

    Obtenha o nome do comando do processo 1

  • tr -d ''

    Remova a formatação do espaço em branco do comando ps

  • "$ {PPID}"

    Parent PID do processo bash

por 17.08.2018 / 17:53