LINUX.ORG.RU

Как это будет выглядеть в виде systemd юнита?

 ,


1

2
extra_commands="reinit"

depend() {
    need net
    need postgresql
}

start() {
    ebegin "Starting ${NAME}"

    start-stop-daemon --start --background \
                      --user ${USER} \
                      --pidfile ${PID} --make-pidfile \
                      --exec ${BIN} -- ${CONF}

    eend $?
}

stop() {
    ebegin "Stopping ${NAME}"

    start-stop-daemon --stop --user ${USER} --pidfile ${PID}

    eend $?
}

reinit() {
    stop

    ebegin "Start and reinitialization ${NAME}"

    start-stop-daemon --start --background \
                      --user ${USER} \
                      --pidfile ${PID} --make-pidfile \
                      --exec ${BIN} -- ${CONF} --reinit

    eend $?
}

Start и stop отлично ложатся на ExecStart, но как идиоматично (и без костылей) переписать reinit для systemd?

Deleted

Ответ на: комментарий от anonymous

Соль в том, что сначала нужно именно тормознуть, а потом запустить с другим параметром.

Reload был бы в самый раз, если бы не необходимость остановить сервис перед тем, как переинициализировать.

Deleted
()

Спросил в #systemd на freenode. Мне ответили, что systemd этого не умеет и единственный верный путь — переписывать логику своего сервиса так, чтобы она подстраивалась под логику systemd.

Я все-таки рано начал тыкать systemd и он все еще не готов?

Deleted
()

Есть ExecStart, ExecStop и ExecReload. Последнее должно тебе подойти. В любом случае там еще пачка параметров есть. Посмотри ман.

Radjah ★★★★★
()
Последнее исправление: Radjah (всего исправлений: 1)
Ответ на: комментарий от Radjah

ExecReload

Нет, это не подходит.

В любом случае там еще пачка параметров есть

Какой из них мне мог бы помочь? Прочитал всю документацию, но простого и понятного решения для такой простой задачи я не вижу.

Deleted
()
Ответ на: комментарий от Deleted

Подставь костыль. Добавь ещё один сервис с правильными аргументами, который перед запуском будет останавливать твой сервис. А твой сервис перед запуском должен останавливать сервис с reinit. Или запили возможность reinit'а отдельной операцией и всё будет нормально.

Ivan_qrt ★★★★★
()
Ответ на: комментарий от Deleted

--reinit Что вообще это значит? Это вообще не похоже на задачу для автоматизации и должно выполняться вручную.

И еще ExecReload= можно добавить несколько раз и они будут выполняться по порядку.

surefire ★★★
()
Ответ на: комментарий от surefire

А задача автоматизации инициализации, если программа сама не умеет, решают через юнит, который запускается перед основным и проверяет условия необходимые для инициализации через директивы Condition*. Для примера можно посмотреть как происходит генерация ключей sshd в Arch`е

sshd.service
sshdgenkeys.service

surefire ★★★
()

reinit — это запуск со специальными параметрами, при этом после выполнения специфичных действий процесс завершается или продолжает работу как обычно?

intelfx ★★★★★
()
Ответ на: комментарий от Deleted

Reload был бы в самый раз, если бы не необходимость остановить сервис перед тем, как переинициализировать.

Остановка и последующий запуск сервиса был бы в самый раз, если бы не необходимость остановить сервис перед тем, как переинициализировать.

Так что ли?

Siado ★★★★★
()
Ответ на: комментарий от Deleted

Я все-таки рано начал тыкать systemd и он все еще не готов?

всех corner-cases не предусмотреть, а системд принципиально пытается отказаться от пользовательской логики «сложных» шелл-скриптов в пользу «стандартного» поведения, на совместимость при этом плевать, ведь других систем кроме линуксов с системд не существует же.

val-amart ★★★★★
()
Ответ на: комментарий от Ivan_qrt

Подставь костыль.

Костыли всегда успеется сделать.

Добавь ещё один сервис с правильными аргументами, который перед запуском будет останавливать твой сервис.

Логика нарушается. Сервис то один, и при запуске systemctl status начнутся неочевидности.

Deleted
()
Ответ на: комментарий от Deleted

По факту это тот же restart, но с полным сбросом состояния сервиса.

А restart по дефолту разве не выполняет сброс состояния?
Какой конкретно параметр состояния не сбрасывается?
Добавьте сброс в ExecStartPre/ExecStopPre.

ArcFi
()
Ответ на: комментарий от ArcFi

А restart по дефолту разве не выполняет сброс состояния?

Нет, и не должен ни в коем случае.

Какой конкретно параметр состояния не сбрасывается?

Все. Reinit это суть рестарт с нуля, когда сервис полностью очищает свое состояние и заполняет его заново.

Deleted
()
Ответ на: комментарий от val-amart

всех corner-cases не предусмотреть,

В openrc же как-то предусмотрели. Если systemd не хуже, как говорят его фанаты, то значит и в нем должна быть возможность сделать так, как мне удобно.

Deleted
()
Ответ на: комментарий от Deleted

Есть мнение, что у вашего сервиса неправильная логика.
Полный сброс состояния нужно добавить ExecStartPre/ExecStopPre, а частичный сброс повесить на ExecReload.
И тогда команда restart будет рестартить со сбросом состояния, а reload — без.

ArcFi
()
Ответ на: комментарий от Deleted

А запускать после --reinit не нужно? Я просто не очень понимаю к какому результату у тебя приводит команда reinit.

Deleted
()
Ответ на: комментарий от Deleted

А запускать после --reinit не нужно?

А это и есть запуск. Запуск со сбросом всего состояния сервиса.

Deleted
()
Ответ на: комментарий от ArcFi

Полный сброс состояния нужно добавить ExecStartPre/ExecStopPre

Нет, при каждом старте сброс состояния происходить не должен.

Deleted
()
Ответ на: комментарий от Deleted

Ага... То есть у тебя это не релоад и не рестарт, а другой способ запуска с другим результатом. ИМХО у тебя просто логика работы в программе поломана.

Deleted
()
Ответ на: комментарий от Deleted

То есть у тебя это не релоад и не рестарт, а другой способ запуска с другим результатом.

Результат запуска — работающий сервис. Но перед запуском он сбрасывает все состояние.

ИМХО у тебя просто логика работы в программе поломана.

Чтобы запустить сервис без init я просто пишу

/path/to/service
Чтобы запустить его так, как будто он работает с нуля, то я его запускаю
/path/to/service --reinit

Подобная логика встречается в немалом количестве ПО. Тот же chromium — разница только в том, что у меня это ПО работает как сервис (потому что web).

И самое главное — это очень удобно.

А сказать о том, что «это сервис неправильный» очень просто. Проще чем принять для себя, что systemd не подходит для нормального решения задач сложнее, чем просто запуск бинарника.

p.s. Хотя мне сейчас очень хотелось бы, чтобы он мог. Потому что хочется поддержать работу на systemd-based дистрибутивах.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от Deleted

Чем в логике работы программы отличается простой запуск от запуска с --reinit? «Холодный» запуск с принудительной проверкой всего и вся?

Если подобная «поломанность» как-то фиксируется, например, lock-файлом, то можно ExecStartPre проверку добавить.

Я подобные загоны только в netfilter-persistent видел, но там по сути oneshot-сервис.

Radjah ★★★★★
()
Ответ на: комментарий от Deleted

Нет, при каждом старте сброс состояния происходить не должен.

Тогда сделайте дополнительный юнит daemon-reinit.service, который будет выполнять reinit и который можно дёргать по требованию.

ArcFi
()
Ответ на: комментарий от Radjah

Чем в логике работы программы отличается простой запуск от запуска с --reinit? «Холодный» запуск с принудительной проверкой всего и вся?

Вроде того. Не совсем, но в первом приближении похоже.

Если подобная «поломанность» как-то фиксируется, например, lock-файлом, то можно ExecStartPre проверку добавить.

Костыльно.

Вообще я не думал, что с такой банальщиной (см. openrc скрипт) могут возникнуть такие проблемы.

Deleted
()
Ответ на: комментарий от ArcFi

Тогда сделайте дополнительный юнит daemon-reinit.service, который будет выполнять reinit и который можно дёргать по требованию.

Да, есть такой вариант, но придется править сервис немного (если уж никак с systemd по-другому не сделать).

Запускать в юните systemctl не считается моветоном?

Deleted
()
Ответ на: комментарий от Deleted

Чтобы запустить его так, как будто он работает с нуля, то я его запускаю

Я всё ещё не понимаю зачем об этом знать иниту. Если ты запускаешь reinit руками, то в сервис это пихать не нужно. В сервис нужно пихать то, что должно работать автоматически без вмешательства пользователя.

Deleted
()
Ответ на: комментарий от Deleted

Если ты запускаешь reinit руками, то в сервис это пихать не нужно.

Если ты можешь запустить nginx руками, то в сервис это пихать не нужно.

p.s. то, что я привел пример того, как это работает вне init, не значит, что я именно так всегда его и запускаю.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от Deleted

Отлично. Тогда так:

mydaemon.service:

[Service]
ExecStart=/path/to/mydaemon ${EXTRA}
ExecStartPost=/bin/rm -f /run/mydaemon/extra
#ExecStop= # не нужно, само прибьётся
EnvironmentFile=/run/mydaemon/extra

mydaemon-reinit.service:

[Service]
Type=oneshot
ExecStart=/bin/sh -c "echo EXTRA=--reinit > /run/mydaemon/extra"
ExecStart=/usr/bin/systemctl restart mydaemon

Да, дополнительные действия (кроме start, restart, reload) в юниты не добавить. Этому вполне есть обоснование.

intelfx ★★★★★
()
Последнее исправление: intelfx (всего исправлений: 3)
Ответ на: комментарий от Deleted

А как ты запускаешь reinit не руками?

У нас, возможно, разное понимание «руками». Подразумеваю «непосредственно».

service myservice reinit

Deleted
()
Ответ на: комментарий от intelfx

Спасибо!

Это именно то, что я подразумевал под костылями. Видимо, без них в systemd не взлетит.

Остановлюсь тогда, пожалуй, на костылях.

Deleted
()
Ответ на: комментарий от Deleted

Тебе уже сколько человек сказали, твоя логика reinit вот это настоящий костыль, а ты все равно как Д’Артаньян. Даже эта строка extra_commands="reinit" уже намекает на, то что впереди костыль.

surefire ★★★
()
Ответ на: комментарий от Deleted

Вообще вполне возможен еще один костыль (в рамках программы это как раз не костыль) с TERM и новым запуском сервиса, после.

anonymous_sama ★★★★★
()

Можно обойтись без второго юнита.
Выполнять reinit через bash-wrapper, который будет ловить SIGUSR1 от systemctl kill.

ArcFi
()
Ответ на: комментарий от surefire

твоя логика reinit вот это настоящий костыль

В ответ предлагая более сложные решения, которые по сравнению с этим костылем и являются.

--reinit это очень простая сущность.

Если есть красивое KISS решение — так напиши его. Я его с радостью имплементирую.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от Deleted

В традиционной парадигме реинициализация сервиса не является задачей системного менеджера, а для инициализации достаточно хуков.
Причина в том, что в общем случае эта задача нетривиальна, деструктивна по отношению к существующим данным и чаще всего не поддерживается самим сервисом.

ArcFi
()
Ответ на: комментарий от intelfx

только это

/usr/bin/systemctl

может быть не всегда так

$ /usr/bin/systemctl
-bash: /usr/bin/systemctl: No such file or directory
$ which systemctl
/bin/systemctl
$

Deleted
()
Ответ на: комментарий от Deleted

Дебиан ставит systemd в /, чтобы поддержать split /usr? Ожидаемо, они всегда любили костылить.

Впрочем, ну очевидно же, что пути надо подправить.

intelfx ★★★★★
()
Ответ на: комментарий от intelfx

это убунта. но подозреваю, что в дебиане то же самое.

Deleted
()
Ответ на: комментарий от intelfx

По сущности мало что изменится, потому что после reinit всегда обязательно запускается сервис (и отдельно за все время ни разу запускать не приходилось).

p.s. иначе бы оно так и было сделано

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от ArcFi

В традиционной парадигме

в общем случае

Если нечего написать кроме общих фраз — лучше не писать ничего.

Другие решения есть, подобные тому, о чем intelfx пишет. По факту они уходя из init требуют действий по проверке того, что происходит с сервисом — запущен ли он до этого и пр., то есть находиться в рамках init тут выглядит наиболее оптимальным вариантом.

Deleted
()

Тему не читал...

Но первом приближении и при условии что start-stop-daemon у тебя существующая отдельная функция в виде обычного bash скрипта оно будет выглядеть вот так:

--- a	2016-11-17 18:52:13.919935499 +0500
+++ b	2016-11-17 19:15:44.585299755 +0500
@@ -1,9 +1,11 @@
+#!/bin/sh
+source core-functions.sh
 extra_commands="reinit"
 
-depend() {
-    need net
-    need postgresql
-}
+#depend() {
+#    need net
+#    need postgresql
+#}
 
 start() {
     ebegin "Starting ${NAME}"
@@ -35,4 +37,28 @@
                       --exec ${BIN} -- ${CONF} --reinit
 
     eend $?
-}
\ В конце файла нет новой строки
+}
+
+case "$1" in
+start)
+        msg "Starting..."
+        start
+        msg "done."
+        ;;
+stop)
+        msg "Stopping..."
+        stop
+        msg "done."
+        ;;
+reinit)
+        msg "Reinit..."
+        stop
+        msg "done."
+	reinit
+	;;
+*)
+        echo "Usage: $0 {start|stop|reinit}"
+        exit 1
+        ;;
+esac
+exit 0
\ В конце файла нет новой строки

Файл core-functions.sh брать по ссылке. И успехов.

init_6 ★★★★★
()
Ответ на: комментарий от Deleted

По факту они уходя из init требуют действий по проверке того, что происходит с сервисом — запущен ли он до этого и пр., то есть находиться в рамках init тут выглядит наиболее оптимальным вариантом.

Да, ты прав. О всяких гонках с перезапуском (и банальной необходимости в таком случае сохранять вывод is-active в переменную, останавливать, делать reinit и условно перезапускать) я и не подумал.

intelfx ★★★★★
()
Ответ на: комментарий от intelfx

Гм, ты вообще не в тему написал.

Как скажешь. Я попервах, во ранее время появления systemd, именно так и портировал для себя недостающее из openrc.

init_6 ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.