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

Сделать службу пользователя systemd зависимой от целевой системы

У меня есть пользовательская служба в ~/.config/systemd/user/example.service вот так:

[Unit]
Description=Example service
After=network.target

[Service]
ExecStart=/bin/bash -c 'host google.com > /var/tmp/example'

[Install]
WantedBy=default.target

Фактическая служба, которую я пытаюсь контролировать, на самом деле делает что-то полезное и, конечно же, получает доступ к сети; это просто упрощенный пример.

Услуга доступна через systemctl --user enable example.service который создает символическую ссылку ~/.config/systemd/user/default.target.wants/example.service указывает на ~/.config/systemd/user/example.service.

С этой настройкой и с systemd пользовательские сеансы включены, как описано на Arch Wiki, при запуске служба запускается от имени моего пользователя. Однако на самом деле он не запускается после настройки сети; вместо этого кажется, что он запускается немедленно, поскольку /var/tmp/example содержит:

;; connection timed out; no servers could be reached

(И фактическая служба, которую я пытаюсь контролировать, также не может подключиться к сети и не работает с аналогичными ошибками поиска имени)

Это означает, что служба фактически не запускается после network.target. Как мне заставить его ждать network.target перед запуском?

У меня была такая же проблема со сценарием резервного копирования пользовательского пространства, которому нужен доступ к Интернету. Я решил это, добавив ~/.config/systemd/user/wait-for-network.service это просто пинг google.com пока он не станет доступным:

[Unit]
Description=Ping a server on the internet until it becomes reachable

[Service]
Type=oneshot
ExecStart=/bin/bash -c 'while ! ping -c1 google.com; do sleep 1; done'
TimeoutStartSec=60s

Затем я сделал свой сценарий резервного копирования зависимым от него следующим образом:

[Unit]
Description=...
Requires=wait-for-network.service
After=wait-for-network.service

Это работает независимо от того, используете ли вы NetworkManager или каким-либо другим способом установить соединение.

Забудь network.target. man systemd.special говорит:

network.target
       systemd automatically adds dependencies of type After for
       this target unit to all SysV init script service units
       with an LSB header referring to the $network facility.

Таким образом, эта цель в первую очередь является хаком для совместимости скриптов инициализации SysV.

Предполагая, что ваше сетевое соединение обрабатывается NetworkManager, вы, конечно, были правы, полагаясь на эту цель, потому что NetworkManager.service определяет Before=network.target. Но это означает только то, что NetworkManager запущен, а не то, что сетевое соединение фактически установлено. Это может занять некоторое время (обходы по протоколу DHCP, рукопожатие Wi-Fi и т. Д.) И полностью является делом NetworkManager. По крайней мере, в моей системе (F18) есть служба под названием NetworkManager-wait-online. Он использует nm-online служебная программа для блокировки до тех пор, пока не будет установлено активное соединение. Пробовать Require, Before это в определении вашего модуля или используйте этот инструмент отдельно.