Назад | Перейти на главную страницу

Systemd: укажите, был ли скрипт запущен systemd или пользователем

Как узнать, был ли вызван сценарий из systemd или от пользователя?

Я создал сервис для демона старой школы. Мы только что перешли на systemd, и некоторые из моих администраторов любят напрямую вызывать rc-скрипт. Это не сработает в случае перезагрузки машины. Systemd не будет уважать PIDFile= потому что новый запущенный демон не является частью своей контрольной группы службы.

Я добавил служебный файл и файл rc_script. Я не могу отличаться по идентификатору пользователя, потому что для использования скрипта пользователь должен быть foobaruser.

Служба остановки теперь является проблемой, потому что systemd распознает это по удаленному файлу pid.

Итак, как мне узнать, был ли скрипт вызван из 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 / 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

Я согласен с другими постерами, что вы должны попытаться переписать службу, чтобы вообще не вызывать сценарий (это нормально, если ваши администраторы хотят продолжать его использовать, но нужны ли службе systemd все 36 параметров?) - но это также не трудно определить, был ли скрипт вызван из systemd.

  • systemd v232 добавил концепцию идентификатора вызова юнита, который передается юниту в $INVOCATION_ID переменная окружения. Вы можете проверить, настроено оно или нет.

  • systemd v231 + устанавливает $JOURNAL_STREAM переменная для служб, stdout или stderr которых подключены к журналу, что, похоже, относится к вашей службе, поэтому вы также можете проверить эту переменную, если вы используете systemd v231. (На v232 +, $INVOCATION_ID определенно лучший выбор.)

  • Я не думаю, что в более старых версиях systemd всегда присутствует переменная окружения, но вы, конечно, можете определить ее самостоятельно, добавив что-то вроде этого в свою службу:

    Environment=LAUNCHED_BY_SYSTEMD=1
    

Простое решение - использовать другой скрипт для запуска systemd. / Opt / foobar / rc_script должен просто вызвать systemctl start foobar.service и systemctl stop foobar.service.

Suse использует $SYSTEMD_NO_WRAP, но я не знаю, является ли это стандартом systemd или специфичным для Suse.

if test -z "$SYSTEMD_NO_WRAP"; then
...
    /usr/bin/systemctl [start|stop] xxx.service

Для «Amazon Linux 2» и «Red Hat Enterprise Linux 7» я нашел решение.

В этих системах Linux PID=1 является comm=systemd. Родительский идентификатор PPID запущенного скрипта systemd 1.

Могут быть другие системы Linux, где это не так.

#!/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

Используемые элементы / команды:

  • ps -o comm -p 1 --no-заголовки

    Получить имя команды процесса 1

  • tr -d ''

    Удалите пробелы форматирования из команды ps

  • "$ {PPID}"

    Родительский PID процесса bash