LINUX.ORG.RU
ФорумTalks

[хроники пикирующего пингвина] sysvinit + service supervision, doing it right


0

1

Ещё раз: я не защищаю systemd, я критикую sysvinit, причём исключительно по части service supervision, остальное меня совершенно устраивает.

(c) GotF

А теперь, мужики, давайте подумаем. Вводная:

  • К init-у репарентятся все процессы с помершим родителем.
  • init для всего этого счастья ловит SIGCHLD-ы, когда они дохнут.
  • если померший процесс был запущен init-ом из правила inittab, он перезапускается в случае необходимости. В ином случае не происходит ничего.

Что нам мешает добавить гибкости в эту схему? init управляется через /dev/initctl. Мы можем слегка доработать его управление и получить возможность «ставить на контроль» произвольные PID-ы.

Следующая команда будет ставить указанный pid на контроль:

/sbin/telinit --waitpid $pid --run some command
Когда pid помрёт, init запустит 'some command'.

Собственно, всё. Это был механизм.

Теперь use case, для чего нам это нужно. Возьмём обычный rc.d-подобный метод запуска демонов. Напомню вам, что там происходит:

  • rc запускает нужный демон.
  • демон записывает в /var/run/blabla.pid свой pid.
  • пока содержимое /var/run/blabla.pid соответствует живому pid-у, демон считается запущенным.

Итак, вам нужен service supervision. По сути, всё, что вам нужно знать, это когда pid умрёт. Что мы делаем:

  • rc запускает демон blabla.
  • демон записывает в /var/run/blabla.pid свой pid.
  • rc выполняет команду /sbin/telinit --waitpid `cat /var/run/blabla.pid` --run /etc/rc.died blabla
  • когда процесс умирает (или если он уже мертв на момент попадания команды в init), init вызывает команду /etc/rc.died blabla. Если демон blabla всё еще нужен (не помечен как выключенный), он перезапускается.

Мысли? Мнения? Критика?

На мой чайниковский взгляд, выглядит вполне логично. Конечно, специализированные супервизоры содержат больше возможностей для контроля (http-запросы, ICMP, проверка порта, проверка сокета и т.п.), но это всё плохо вписывается в задачи init как базовой системы. В общем, по моему мнению, в топике описано ровно то, чего не хватает sysvinit. Большее должно быть уделом специализированных решений, в т.ч. не находящихся на наблюдаемой машине.

GotF ★★★★★
()

пока содержимое /var/run/blabla.pid соответствует живому pid-у, демон считается запущенным.

помойму, проще (и дешевле по ресурсам!) проверять, что файл все еще кем-то эксклюзивно заблокирован. А на проверку содержимого откатываться только для недо-файловых систем без возможности эксклюзивной блокировки.

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

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

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

Ты предлагаешь демоны переписывать. Это автоматически делает решение неправильным.

и дешевле по ресурсам!

По каким ресурсам? malloc(struct waitpid_rule_t) в init-е?

проверять

Ты уверен, что прочитал пост и понял написанное? Задача — не проверять.

geekless ★★
() автор топика

интересует проблема слотов: что будет, если я запущу несколько инстансов одного и того же демона? (/etc/rc.d/cyrus start 1 && /etc/rc.d/cyrus start 2)

еще интересует проблема isolation. Допустим, изолированный процесс запускает демон с опцией наследования permissions. Имхо, при подыхании родителя должен быть какой-то специальный механизм, который будет вычислять новые permissions. Иначе таким путем можно будет фигачить руткиты. (Правда, я не в курсе, как в линуксе работает изоляция, если она вообще есть :)

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

Чтение файла - неатомарная операция. Может статься так, что когда ты прочитал значение пида из файла, такого процесса уже и нет вовсе (например, он внезапно сегфолтнулся). А при проверке эксклюзивного доступа ядро гарантирует, что блокирующий процесс жив на момент проверки.

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

интересует проблема слотов: что будет, если я запущу несколько инстансов одного и того же демона? (/etc/rc.d/cyrus start 1 && /etc/rc.d/cyrus start 2)

Запускай с разными именами. ln -s blabla /etc/rc.d/blabla.1 ; ln -s blabla /etc/rc.d/blabla.2 , вот тебе и два демона. Код в /etc/rc.d/blabla, разумеется, должен поддерживать такую опцию, чтобы взлетело.

еще интересует проблема isolation. Допустим, изолированный процесс запускает демон с опцией наследования permissions. Имхо, при подыхании родителя должен быть какой-то специальный механизм, который будет вычислять новые permissions. Иначе таким путем можно будет фигачить руткиты.

Если честно, я ничего не понял. Можно на пальцах?

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

Чтение файла - неатомарная операция. Может статься так, что когда ты прочитал значение пида из файла, такого процесса уже и нет вовсе (например, он внезапно сегфолтнулся).

о_О

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

Прости, а чем вариант выше отличается от «может статься так, что когда ты проверил блокирование файла, в следующую миллисекунду процесс уже помер»?

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

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

Если честно, я ничего не понял. Можно на пальцах?

представь, что процесс запускается в «песочнице». Песочница разрешает ему, например, возможность послать смерть процессу-родителю, но разрешает читать данные из /home. Теперь мы убиваем родителя. Процесс меняет родителя на init и получает возможность убить init.
Теперь с точки зрения пользователя: он поставил «демон записных книжек» и в пермишшенах читает: «программа просит доступ к личным данным пользователя, программа просит доступ на остановку родителя». «Что такое остановка родителя?» - думает пользователь и клацает кнопку «разрешить всё».
При этом какой-то умный чел под видом «демона записных книжек» может зафигачить вирь, который будет при загрузке убивать систему... И прости-прощай, «пришло время переустановить Линукс, Линукс сам не переустановится».

(емнип, в линуксах init игнорирует SIGTERM, но это было чисто для иллюстрации)

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

Процесс меняет родителя на init и получает возможность убить init.

init невозможно убить.

(емнип, в линуксах init игнорирует SIGTERM, но это было чисто для иллюстрации)

Вот и я о том же, при чем тут init...

Мы говорим об отлове момента смерти системных демонов. Какие «записные книжки», какие «клацнуть кнопку»?

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

Еще добавлю, относительно вопроса «жив ли демон сейчас» двух мнений быть не может: демон жив, пока жив его процесс. Если он запускает какие-то дочерние процессы, которые имеют отношение лично к нему, они должны убиваться вместе с ним (например, при обрыве пайпа, или через что они там общаются). Если они не убиваются, это баг демона.

geekless ★★
() автор топика
Ответ на: комментарий от geekless
int main(int argc, char *argv[]) {
    pidExists = open("path/to/pid",O_WRONLY|O_CREAT|O_EXCL,0);
    if (-1!=pidExists) {
        return main_safe(argc,argv);
    } 
}

int main_safe(int argc, char *argv[]) {
//код проги
}

Помойму такой вызов open тоже является атомарным. То есть, создание (или несоздание) пида произойдет атомарно, а вот запуск основного кода (если он нужен) будет уже отложенным.

Если в файл нужно еще что-то писать, то юзать fopen вместо open.

stevejobs ★★★★☆
()

епта, я все перепутал :(

pid'у не обязательно быть lock'ом, можно сделать и то и другое

ладно, ты прав :)

stevejobs ★★★★☆
()

демон записывает в /var/run/blabla.pid свой pid.

а ядро уже держит в /proc/pid/ _все_ данные о процессе

пока содержимое /var/run/blabla.pid соответствует живому pid-у

/proc/pid всегда соответствует живому процессу

rc запускает демон blabla.

И что?

демон записывает в /var/run/blabla.pid свой pid.

Вместо того чтобы пройтись по /proc/<pid> в поисках экземпляра себя.

когда процесс умирает

Он исчезает из /proc

[/thread]

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

Можно вопрос - а зачем перезапускать умирающие процессы?

Чтобы дальше работали? Если они помирают регулярно и быстро, можно сделать задержку, как это работает с процессами в inittab. И вот:

когда процесс умирает (или если он уже мертв на момент попадания команды в init), init вызывает команду /etc/rc.died blabla

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

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

а ядро уже держит в /proc/pid/ _все_ данные о процессе

Да-да, а pid нужный rc угадает при помощи libastral.

Вместо того чтобы пройтись по /proc/<pid> в поисках экземпляра себя.

Нахера демону искать себя, если свой pid он прекрасно знает и так? Вы больны?

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

Чтобы дальше работали? Если они помирают регулярно и быстро, можно сделать задержку, как это работает с процессами в inittab. И вот:

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

Я правильно понимаю, что, вместо того, чтобы фиксить проблему, Ты хочешь фиксить только последствия?

И я правильно понял, что ты хочешь на init возложить функцию мониторинга?

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

И я правильно понял, что ты хочешь на init возложить функцию мониторинга?

Здрасте. Она на него возложена создателями Unix. init — это единственный процесс, получающий информацию о смерти «брошенных» процессов.

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

можно сделать проще, как в мобильниках: если демон объявляет себя recoverable, он должен реагировать на сигналы «save» и «restore» и быть готов, что его заморозят или разморозят в любое время.

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

Я правильно понимаю, что, вместо того, чтобы фиксить проблему, Ты хочешь фиксить только последствия?

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

И я правильно понял, что ты хочешь на init возложить функцию мониторинга?

Ну да, в других системах инициализации она давно есть. Думаю, что не сильно ошибусь, если скажу, что её нет только в SysV и BSD.

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

Да-да, а pid нужный rc угадает при помощи libastral.

Нет, при помощи правила по которому он его запустил

Нахера демону искать себя, если свой pid он прекрасно знает и так? Вы больны?

Ты наркоман? Pid - файл нужен для исключения дубликатов, когда это нужно и поиска сокетов клиентами, также когда это нужно.

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

Ты наркоман?

Нет, ты. Ты посмотри, что ты пишешь:

Нет, при помощи правила по которому он его запустил

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

Pid - файл нужен для исключения дубликатов, когда это нужно и поиска сокетов клиентами, также когда это нужно.

А мужики-то и не знают!

#!/bin/bash

. /etc/rc.conf
. /etc/rc.d/functions
. /etc/conf.d/dnsmasq

checkconfig() {
  local testout

  if ! testout=$(/usr/bin/dnsmasq --test 2>&1); then
    echo "$testout"
    return 1
  fi

  return 0
}

pidfile=/run/dnsmasq.pid
if [[ -r $pidfile ]]; then
  read -r PID < "$pidfile"
  if [[ ! -d /proc/$PID ]]; then
    # stale pidfile
    unset PID
    rm -f "$pidfile"
  fi
fi

case $1 in
  start)
    stat_busy "Starting DNS/DHCP daemon"
    if [[ -z $PID ]] && checkconfig &&
        /usr/bin/dnsmasq "--user=${DNSMASQ_USER:-nobody}" \
                          "--pid-file=$pidfile" \
                          "${DNSMASQ_OPTS[@]}"; then
      add_daemon dnsmasq
      stat_done
    else
      stat_fail
    fi
    ;;
  stop)
    stat_busy "Stopping DNS/DHCP daemon"
    if [[ $PID ]] && kill "$PID" &> /dev/null; then
      # dnsmasq doesn't clean up after itself
      rm -f "$pidfile"
      rm_daemon dnsmasq
      stat_done
    else
      stat_fail
    fi
    ;;
  restart)
    $0 stop
    sleep 1
    $0 start
    ;;
  checkconfig)
    # diagnostics will be printed, with zero/non-zero exit
    /usr/bin/dnsmasq --test
    ;;
  *)
    echo "usage: $0 <start|stop|restart|checkconfig>"
esac
geekless ★★
() автор топика
Ответ на: комментарий от geekless

Уфффффф! Перечитай этот скрипт! Pid-файлы появились во времена когда грепнуть /proc было тем ещё гемором, когда ext2 была только планом. В 17й строчке можно просто регекспом грепнуть /proc/[0-9]/cmdline и не ипать мозг. Там же можно определить с каким конфигом запущен экземпляр. А вот запусти в такой схеме 2 экземпляра dnsmasq на разных интерфейсах? Обкакаешся!

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

Pid-файлы появились во времена когда грепнуть /proc было тем ещё гемором

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

В 17й строчке можно просто регекспом грепнуть /proc/[0-9]/cmdline и не ипать мозг.

Ты глупый или хорошо притворяешься? rc запускает демона. Демон — это процесс. Демон запускается через посредников, которых может быть произвольное количество, хоть мульён. pid демона и его точную команду запуска знает только сам демон, но не знает тот, кто собирается его запускать. Самое очевидное, простое как топор и надёжное решение — это сделать «как запустишься, скажи мне свой pid вот в этот файл». Какой cmdline, ты собрался грепать? Из какого астрала доставать имя итогового процесса? Алло?

А вот запусти в такой схеме 2 экземпляра dnsmasq на разных интерфейсах? Обкакаешся!

Запускал по такой схеме 6 agetty на 6-ти виртуальных консолях. Брат жив.

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

если демон объявляет себя recoverable, он должен реагировать на сигналы «save» и «restore» и быть готов, что его заморозят или разморозят в любое время.

А ещё можно научить его разговаривать на суахили и непременно встроить в него дрова для всех видеокарточек чтобы он мог ругаться напрямую в видеопамять... ага...

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

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

Ты вообще в курсе, что в argv[0] у процесса может быть что угодно, любой бред? Вообще никак не связанное с реальным именем его исполняемого файла?

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

Запускал по такой схеме 6 agetty

dnsmasq!

и его точную команду запуска знает только сам демон

cat /proc/*/cmdline

Открой и сам посмотри, а не шлангуй. И не рассказывай бред про посредников...

Из какого астрала доставать имя итогового процесса? Алло?

т.е. cmdline никогда не будет актуален для rc ? А точно он его запускал? А демонизирующийся процесс не знает как его запустили?

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

dnsmasq!

Упражнение «найдите все места, где в скрипте надо заменить строку dnsmasq на значение переменной, сформированной из значения argv[0]» оставляю тебе для самостоятельной работы на дом. Должен же ты хоть чему-то научиться.

cat /proc/*/cmdline

Отлично. Начнём с самого простого:

$ cat /proc/1/cmdline
init [3]
Вопросы для домашего задания:
1. Совпадает ли имя исполняемого файла с именем из cmdline?
2. Если не совпадает, то почему?

А точно он его запускал?

Хороший вопрос! И мы переходим к следующему упражнению:

$ pgrep dnsmasq 
972
Вопросы:
1. Является ли данный процесс экземпляром /sbin/dnsmasq, или он просто изменил своё имя?
2. Запущен ли данный процесс как демон из rc, или это просто програмист отлаживает программу?

А демонизирующийся процесс не знает как его запустили?

Процесс A форкается в процесс Б, процесс Б форкается в процесс В, процесс В форкается в процесс Г. На всех шагах возможно произвольное число вызовов exec(). И снова вопрос: знает ли процесс A имя процесса Г?

не шлангуй

Да, не шлангуй, согласен.

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

Вообще ты фееричен. Мы тут тихо обсуждаем, как допилить пару фич в init, и тут приходишь ты, весь в белом. И начинаешь рассказывать, что десятелетиями используемый, проверенный и не вызывающий никаких нареканий метод старта демонов неправильный, а вот ты-то на саааамом деле, знаешь, как правильно.

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

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

От автоматических перезапускалок, а также заметания под ковёр и тихого риспона проблема вообще не будет решаться никогда.

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

Упражнение

Упражняйся в чтении вышеупомянутой строчки, из-за неё dnsmasq не запустится дважды (даже если это реально нужно)

Отлично. Начнём с самого простого: $ cat /proc/1/cmdline

Отлично, я процесс dnsmasq, я не нашёл тут строчки ^/somepathwhatiknow/dnsmasq. И?

Если не совпадает, то почему?

Т.е. ты берёшься за оптимизацию и не знаешь что ядро тоже порождает процессы?

Является ли данный процесс экземпляром /sbin/dnsmasq

Ну посмотри исходники pgrep.

Процесс A форкается в процесс Б, процесс Б форкается в процесс В, процесс В форкается в процесс Г. На всех шагах возможно произвольное число вызовов exec(). И снова вопрос: знает ли процесс A имя процесса Г?

Да, pstree например. Удивительное рядом

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

И начинаешь рассказывать, что десятелетиями используемый, проверенный и не вызывающий никаких нареканий метод старта демонов неправильный

Нет просто кто-то заигрался в системную инженерию, и мы имеем, то что имеем.

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

Не могу :) Т.к. самому пришлось написать кучу автоперезапускалок, некоторые их них до сих пор используются и решают следствие, а не причины.

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

Думаю, что не сильно ошибусь, если скажу, что её нет только в SysV и BSD.

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

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

Т.е. ты берёшься за оптимизацию и не знаешь что ядро тоже порождает процессы?

Ты даже не способен понять, о чем я говорю. Иди уже покури матчасть, чудак-человек. Еще раз для особо одаренных: имя процесса в общем случае != команде его запуска. Имя может быть любым. Вообще любым. Например таким: «udisks-daemon: not polling any devices».

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

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

Упражняйся в чтении вышеупомянутой строчки, из-за неё dnsmasq не запустится дважды (даже если это реально нужно)

Слушай, читатель, ты не можешь подправить скрипт под свои нужды, или что? Что ты мне тут распинаешься про инновационые методы запуска демонов, если ты даже не способен определить, что именно нужно доработать в указанном скрипте, чтобы при помощи него можно было запускать и останавливать произвольное число демонов? Это детская задачка из категории «здравствуйте товарищи студенты, в этом полугодии мы познакомимся с администрированием linux-систем». Иди восполняй свои пробелы.

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

Иди уже покури матчасть, чудак-человек. Еще раз для особо одаренных: имя процесса в общем случае

Кажется я тебе посоветовал интересоваться в /proc, а не в имени процесса. Pgrep привёл ты - я тебе посоветовал читать его исходники. Не шлангуй.

то ты мне тут распинаешься про инновационые методы запуска демонов, если ты даже не способен определить, что именно нужно доработать в указанном скрипте, чтобы при помощи него можно было запускать и останавливать произвольное число демонов?

киса, выдохни. Это ты тут распинаешься, о том, что ты изобрёл 100500й способ одевания трусов через голову.

Иди восполняй свои пробелы.

Кхм-кхм...

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

Я вынужден охладить твой пыл следующим вопросом: где находится функция, которая в зависимости от команды, переданной с помощью lxpanelctl, запускает тот или иной обработчик? есть ли она вообще?

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

Кажется я тебе посоветовал интересоваться в /proc, а не в имени процесса. Pgrep привёл ты - я тебе посоветовал читать его исходники. Не шлангуй.

Блджад, не шлангуй — это очень актуальный для тебя совет:

$ cat /proc/1/cmdline
init [3]
$ cat /proc/1183/cmdline
udisks-daemon: not polling any devices
Вопросы есть?

Это ты тут распинаешься, о том, что ты изобрёл 100500й способ одевания трусов через голову.

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

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

Тут как бы два варианта. Старый process_client_msg с прибитыми гвоздями константами. И новый process_command, который я еще ни подо что не использовал реально, только механизм передачи команды набросал.

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

От автоматических перезапускалок, а также заметания под ковёр и тихого риспона проблема вообще не будет решаться никогда.

Большие и сложные программы *всегда* содержат ошибки. Это аксиома.

Поэтому, если тебе необходимо, чтобы программа работала 24/7 без вмешательства людей, придется делать автоматическую перезапускалку (watchdog).

Других вариантов нет.

Заметать под ковёр ничего не нужно: факт перезапуска должен логгироваться, должен быть предусмотрен сбор отладочной информации (корки, хотя бы)...

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