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

Укажите зависимость systemd от любого из нескольких модулей?

Можно ли указать зависимость systemd от одного из нескольких модулей?

В настоящее время у меня есть единица Z, которая зависит хотя бы от одного из единиц A или B.

Настройка блока A как WantedBy единица Z и единица B должны быть WantedBy блок Z в основном работает.

Однако, если только один из модулей A или B может запуститься, процесс загрузки ожидает тайм-аута другого модуля, прежде чем запускать модуль Z. Я хочу исключить этот тайм-аут.

Модулям A и B требуется тайм-аут для правильной работы, однако, как только один из них запущен, нет необходимости ждать, пока другой модуль не истечет, прежде чем запускать модуль Z.

Есть ли способ указать, что блок Z зависит от блока A или блока B, но не нужно ждать одновременно блока A и блока B перед запуском блока Z?

В мире Debian система упаковки использует Provides чтобы указать что-то похожее на то, что я надеюсь здесь достичь.

Чего я пытаюсь достичь

Debian раньше поддерживал keyscript вариант в crypttab но не повторно реализовал эту опцию, когда апстрим переписывал сценарии запуска для перехода на systemd. Раньше я использовал keyscript чтобы прочитать мой ключ с USB-накопителя. В настоящее время я использую systemd unit файл, чтобы заменить keyscript вариант (блок А). Это прекрасно работает. Однако USB-накопители подвержены сбоям, поэтому для обеспечения избыточности я хочу перенести вторую копию моего ключа на второй USB-накопитель. И я хочу добавить второй systemd unit для этого второго USB-накопителя (модуль B), так что какой бы USB-накопитель ни был вставлен, systemd может использовать этот USB-накопитель и продолжить работу без тайм-аута.

Другие вещи, которые я пробовал

С помощью Conflicts чтобы указать, что A конфликтует с B, а B конфликтует с A. К сожалению, systemd обрабатывает конфликт перед попыткой запуска любого из модулей A или B и удаляет один из этих модулей из планировщика, прежде чем пытаться запустить оставшийся модуль. Таким образом, Z иногда терпит неудачу, например, если терпит неудачу A, но B добился бы успеха, если бы B уже был исключен из рассмотрения из-за конфликта с A.

С помощью JobTimeoutSec чтобы сократить время ожидания. К сожалению, это может привести к сбою Z, если таймаут A и B.

Предложения Майкла Хэмптона. Как он упоминает, пример NTP создает слабую зависимость между каждым клиентом и целью. Каждому клиенту NTP нужна цель, но цель не зависит от каждого из клиентов NTP, поэтому это работает. Однако, насколько я могу судить, слабая зависимость не влияет на единицу, если она не имеет [Install] раздел, определяющий дополнительную зависимость. Поэтому, когда я подтягиваю свои блоки A и B, WantedBy в [Install] секция создает таймаут блокировки. Если я удалю [Install] раздел, блоки A и B игнорируются.

Это работа для целевого юнита systemd.

Вместо того, чтобы приводить надуманный пример, я приведу реальный пример, который уже присутствует в вашей системе.

Рассмотрим NTP. Большинство компьютеров синхронизируются через NTP, но есть три (а может и больше) клиента NTP, из которых вы можете выбрать: systemd-timesyncd, chronyd или (классический) ntpd.

Каждый из сервисных модулей для этих клиентов NTP является частью цели, называемой time-sync.target, и слабо требует этого как такового.

Before=time-sync.target
Wants=time-sync.target

Таким образом, когда вы запускаете любой из клиентов NTP, time-sync.target запускается после запуска клиента NTP. Обратите внимание, что time-sync.target сам по себе пуст и фактически ничего не делает сам по себе.

Итак, если вы запускаете службу, которая требует, чтобы системное время было синхронизировано, и в противном случае выйдет из строя, вы можете потребовать, чтобы она запускалась только после time-sync.target началось.

After=time-sync.target
Requires=time-sync.target

Вы легко сможете адаптировать это к своему собственному сервису.

Я думаю, если бы эта функция существовала, она была бы в systemd.unit справочную страницу, и я не вижу ее там.

Решением может быть использование небольшого bash сценарий, который завершается успешно, как только запускается A или B, или терпит неудачу, если оба A и B не запускаются.