Bug 35405

Summary: запуск триггеров навсегда отключается при запуске apt-get install через ssh
Product: Sisyphus Reporter: Alexey Sheplyakov <asheplyakov>
Component: rpmAssignee: placeholder <placeholder>
Status: NEW --- QA Contact: qa-sisyphus
Severity: normal    
Priority: P3 CC: aen, asy, at, avm, boyarsh, darktemplaralt, evg, glebfm, imz, inger, iv, lav, ldv, mike, placeholder, rider, vt
Version: unstableKeywords: regression, usability
Hardware: all   
OS: Linux   
Bug Depends on: 42201    
Bug Blocks: 34231    

Description Alexey Sheplyakov 2018-09-17 18:27:23 MSK
Исходное состояние: машина ALT p8 (для определенности K workstation), для определенности назовем ее farhost

Действия:

1) Заменяем репозиторий на Sisyphus

   ssh root@farhost "find /etc/apt/sources.list.d -type f -name '*.list' | xargs -n1 sed -re 's;^([#]*\s*rpm)\s+[[][^]]+[]](.*)$;\1 \2;' -re 's;p8/branch/;Sisyphus/;' -i"

2) обновляем apt & rpm

  ssh root@farhost 'apt-get update && apt-get install -y rpm'


Ожидаемый результат: либо

а) корректное обновление пакетов apt, rpm, и их зависимостей, 
б) какая-нибудь ошибка (выход с статусом != 0, желательно с более-менее понятным сообщением)

Наблюдаемый результат:

Обновление apt, rpm, и их зависимостей завершается нормально (apt-get выходит с кодом 0), однако остается файл   /var/lib/rpm/delay-posttrans-filetriggers. В результате при дальнейшей установке и/или обновлении пакетов не выполняется ни один filetrigger, в результате чего нарушается работоспособность обновленных/установленных пакетов (не обновляются альтернативы, не запускается ldconfig при установке библиотек с нетривиальными /etc/ld.so.conf.d/*.conf, и т.п.)

Предполагаемая причина:

apt-get install не ждет, пока завершится отложенное выполнение триггеров, а отложенное выполнение триггеров болезненно реагирует на SIGHUP


Костыль:

ssh root@farhost 'apt-get install -y rpm && sleep 15'
Comment 1 Aleksei Nikiforov 2018-09-17 18:28:58 MSK
А screen или tmux на удалённой машине помогает?
Comment 2 Alexey Sheplyakov 2018-09-17 18:44:38 MSK
> А screen или tmux на удалённой машине помогает?

Вопрос не понят.
Comment 3 Anton Farygin 2018-09-17 19:31:07 MSK
Это, наверное, ещё происходит при конфигурации с systemd ?
Comment 4 Alexey Sheplyakov 2018-09-17 19:36:02 MSK
> Это, наверное, ещё происходит при конфигурации с systemd?

Да.
Comment 5 Anton Farygin 2018-09-17 19:41:25 MSK
В systemd есть настройка - прибивать пользовательские процессы после закрытия сеанса.
KillUserProcesses=no

https://www.freedesktop.org/software/systemd/man/logind.conf.html

попробуйте выставить в это значение, скорее всего поможет.
Comment 6 Alexey Sheplyakov 2018-09-17 19:53:48 MSK
> В systemd есть настройка - прибивать пользовательские процессы после закрытия
сеанса.

Дык и без systemd есть масса ситуаций, к примеру, 

apt-get -y dist-upgrade && shutdown -r now

(тут даже и по ssh ходить не надо).

Ошибка в том, что apt выходит раньше, чем завершается обновление, а не в том, что злой systemd что-то там убивает. Причем проявляется эта ошибка совершенно в неожиданных ситуациях, "на ровном месте".

P.S. А костыль я и сам придумал (&& sleep 10)
Comment 7 Dmitry V. Levin 2018-09-18 09:34:26 MSK
Это apt или rpm не ждёт завершения файлтриггеров?
Comment 8 Dmitry V. Levin 2018-09-18 09:37:05 MSK
или речь идёт исключительно об обновлении пакета rpm?
Comment 9 Anton Farygin 2018-09-18 09:38:49 MSK
После запуска apt get dist-upgrade файлтриггеры rpm выполняются в фоновом режиме.

Кто там из них не ждёт - непонятно. скорее всего rpm/librpm.
Comment 10 Ivan A. Melnikov 2018-09-18 12:18:00 MSK
> Ошибка в том, что apt выходит раньше, чем завершается обновление.

Это не баг, это фича^{tm}. Не сдержусь и распишу подробности.

Файлтриггеры намеренно откладываются[1][2] чтобы они выполнялись после перестроения базы rpm; а это может происходить только после того, как apt, использующий rpm как библиотеку, завершит работу.

[1]: http://git.altlinux.org/gears/r/rpm.git?p=rpm.git;a=blob;f=alt/rpm.spec;h=925462302b2cceaf05cdd10416385061c65e1394#l358
[2]: http://git.altlinux.org/gears/r/rpm.git?p=rpm.git;a=blob;f=scripts/postupdate.in;h=519efcfa1d5670809fedb60b318efe7a5b7ae925

Так что их вообще никто не ждёт, и ждать их некому (кроме пользователя), и это как бы by design.

Проблемы же тут видятся две, и хотелось бы посмотреть на них отдедельно.

Во-первых, пользователь, похоже, может красиво запороть себе систему невинно выглядящим `apt-get dist-upgrade && reboot`, если в этом dist-upgrade обновился rpm.

Во-вторых, чтобы вывести систему из этого состояния необходимы нетривиальные действия вроде запуска /usr/lib/rpm/postupdate вручную.
Comment 11 Anton Farygin 2018-09-18 12:43:58 MSK
пример с ssh выглядит более реалистичным.
Comment 12 Alexey Sheplyakov 2018-09-19 14:19:09 MSK
> пример с ssh выглядит более реалистичным.

Мне удалось "вступить" в оба варианта на практике.
Comment 13 Alexey Sheplyakov 2018-09-19 14:27:51 MSK
Более изящный костыль:

sudo systemd-run --service-type=forking --wait apt-get install -y rpm

systemd запускает "временный" сервис и дожидается, пока не выйдут все процессы-потомки (благодаря --service-type=forking)
Comment 14 Michael Shigorin 2018-09-19 16:41:29 MSK
Приколачивать rpm к systemd из-за корявости systemd -- это даже не костыль...
Comment 15 Anton Farygin 2018-09-19 16:46:12 MSK
Нет, конечно корявость systemd тут не при чём. Он позволяет исправить архитектуру обновления apt + rpm. 
Ведь при apt-get -y dist-upgrade && reboot 
systemd может и не быть.
Comment 16 Michael Shigorin 2018-09-19 16:50:18 MSK
Уход в фон был, как мне кажется, сделан из соображений удобства человека -- тогда уж разумней переделать на синхрон и всё.
Comment 17 Anton Farygin 2018-09-19 16:52:27 MSK
если это возможно. я не вижу много удобств в фоновом выполнении скриптов после установки - мало ли что вылезет в них плохого. Как отработать код возврата ?

Сталкивался уже с ситуацией, когда один кривой скрипт в filetrigger ломает запуск всех остальных.
Comment 18 Dmitry V. Levin 2018-09-19 16:53:48 MSK
(In reply to comment #16)
> Уход в фон был, как мне кажется, сделан из соображений удобства человека --

Уход в фон был сделан для того, чтобы дождаться завершения всех пользователей старой базы данных.
Comment 19 Anton Farygin 2018-09-19 16:55:11 MSK
Это для перестройки базы. а для filetrigger ?
Comment 20 Dmitry V. Levin 2018-09-19 17:02:29 MSK
(In reply to comment #19)
> Это для перестройки базы.

Да, и это сейчас происходит при каждом обновлении пакета rpm.

> а для filetrigger ?

Обычно файлтриггеры выполняются синхронно по окончании транзакции.

Выполнение файлтриггеров откладывается и происходит в фоне только в одном случае - при обновлении пакета rpm с 4.0.4:

%triggerpostun -- rpm <= 4.0.4
touch /var/lib/rpm/delay-posttrans-filetriggers
Comment 21 Sergey Y. Afonin 2018-10-23 10:14:27 MSK
(In reply to comment #5)

> В systemd есть настройка - прибивать пользовательские процессы после закрытия
> сеанса.
> KillUserProcesses=no

На всякий случай о моменте, когда оно началось, и почему:
https://lists.altlinux.org/pipermail/sisyphus/2018-April/366620.html

"Теперь значение по умолчанию default-kill-user-processes=true"
Comment 22 Alexey Sheplyakov 2018-10-28 19:54:55 MSK
> На всякий случай о моменте, когда оно началось, и почему:
https://lists.altlinux.org/pipermail/sisyphus/2018-April/366620.html

Вызывающе неверная информация.

Проблема в том, что apt выходит раньше, чем завершаются триггеры. Именно поэтому

apt-get dist-upgrade -y && shutdown -r now

оставляет систему в "интересном" состоянии

P.S. Подход "во всем виноват systemd" не позволяет ничего понять (не говоря уж об исправлении)
Comment 23 Sergey Y. Afonin 2018-10-28 20:24:14 MSK
(In reply to comment #22)

> Проблема в том, что apt выходит раньше, чем завершаются триггеры. Именно
> поэтому

Нет, проблема в том, что systemd прибивает процессы, когда это, скажем так, не очень нужно. Или очень не нужно.

> apt-get dist-upgrade -y && shutdown -r now

А что же не "... && reboot -f" то сразу.
Comment 24 Sergey Y. Afonin 2018-10-28 20:33:05 MSK
(In reply to comment #22)

> P.S. Подход "во всем виноват systemd" не позволяет ничего понять (не говоря уж
> об исправлении)

По-моему тут всё разобрано и совершенно понятно. И, кстати, этот баг - явный кандидат на WONTFIX, так как единственное решение - это kill-user-processes=no ввиду того, что и базу перестраивать, и триггреры исполнять после обновления 4.0.4 > 4.13 надо после завершения rpm. Но сделать этого нельзя ввиду того, рази чего было сделано true.
Comment 25 Alexey Sheplyakov 2018-10-29 14:48:01 MSK
> единственное решение - это kill-user-processes=no

проблема в том, что apt выходит раньше, чем завершаются триггеры, потому пользователь (или скрипт, запущенный пользователем), не может определить, когда обновление завершилось и можно безопасно запустить следующее действие (например, reboot). apt вынужден выходить до запуска триггеров по причине тупости librpm. Более подробно изложено в https://bugzilla.altlinux.org/show_bug.cgi?id=35405#c10

> этот баг - явный кандидат на WONTFIX

Сколько ярлыков ни приклей, проблема не перестанет от этого существовать: обновление может легко и без видимых причин запороть систему, и как ее потом выводить из этого состояния -- совершенно не очевидно.
Comment 26 Sergey Y. Afonin 2018-10-30 10:41:46 MSK
(In reply to comment #25)

> apt вынужден выходить до запуска триггеров по причине тупости librpm.
> Более подробно изложено в comment #10

Я, вообще-то, умею читать. И там написно, что это - не баг.

> > этот баг - явный кандидат на WONTFIX
> 
> Сколько ярлыков ни приклей, проблема не перестанет от этого существовать:
> обновление может легко и без видимых причин запороть систему, и как ее потом
> выводить из этого состояния -- совершенно не очевидно.

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

В качестве рекомендации, "&& reboot" я бы вообще никогда не советовал. Всегда надо посмотреть, что там как прошло, рестарт сервисов и т.п.
Comment 27 Anton Farygin 2018-10-30 10:44:40 MSK
Я согласен с тем, что обновление должно уметь проходить в автоматическом режиме и для этого было бы отлично иметь инструмент, отслеживающий окончания процесса обновления.

По идее, если отменить запуск filetrigger в background, то должно стать легче.
Comment 28 Alexey Sheplyakov 2018-10-30 15:12:52 MSK
> А в скрипте, на самом деле, и перестроение базы можно отследить, и работу триггеров. ps в помощь, что называется.

Автоматизация 80 lvl. Вам не стыдно?

> В качестве рекомендации, "&& reboot" я бы вообще никогда не советовал. Всегда
надо посмотреть, что там как прошло, рестарт сервисов и т.п.

То есть Вы утверждаете, что apt-rpm -- настолько ненадежный инструмент, что результат его работы нужно всегда проверять вручную?
Comment 29 Alexey Sheplyakov 2018-10-30 15:44:01 MSK
А почему, собственно, apt'у обязательно нужно завершиться для перестройки rpmdb?

$ git grep -n rpmtsOpenDB
apt-pkg/rpm/rpmhandler.cc:405:   if (rpmtsOpenDB(Handler, O_RDONLY) != 0)
apt-pkg/rpm/rpmpm.cc:802:   if (rpmtsOpenDB(TS, O_RDWR) != 0)
apt-pkg/rpm/rpmsystem.cc:263:   if (rpmtsOpenDB(ts, O_RDONLY))

$ git grep -e 'rpmtsCloseDB' |wc -l
0

А потому, что он умеет открывать rpmdb, но не умеет ее закрывать.

P.S. Жду новых удивительных историй о том, что это не баг, и о том, что завершения триггеров можно дождаться с помощью ps
Comment 30 Sergey Y. Afonin 2018-10-30 19:22:06 MSK
(In reply to comment #28)

> То есть Вы утверждаете, что apt-rpm -- настолько ненадежный инструмент, что
> результат его работы нужно всегда проверять вручную?

Я, наверное, открою страшную тайну, но я скажу. Нет ни одного способа проверить, что произвольный пакет обновился на 100% хорошо. Ни у одного пакетного менеджера, ни в одном дистрибутиве.
Comment 31 Ivan A. Melnikov 2018-11-06 13:00:23 MSK
(In reply to comment #29)
[...]
> $ git grep -e 'rpmtsCloseDB' |wc -l
> 0

TIMTOWDI. Try `git grep rpmtsFree`.
Comment 32 Ivan Zakharyaschev 2022-09-01 15:24:50 MSK
(In reply to Alexey Sheplyakov from comment #29)
> А почему, собственно, apt'у обязательно нужно завершиться для перестройки
> rpmdb?
> 
> $ git grep -n rpmtsOpenDB
> apt-pkg/rpm/rpmhandler.cc:405:   if (rpmtsOpenDB(Handler, O_RDONLY) != 0)
> apt-pkg/rpm/rpmpm.cc:802:   if (rpmtsOpenDB(TS, O_RDWR) != 0)
> apt-pkg/rpm/rpmsystem.cc:263:   if (rpmtsOpenDB(ts, O_RDONLY))
> 
> $ git grep -e 'rpmtsCloseDB' |wc -l
> 0
> 
> А потому, что он умеет открывать rpmdb, но не умеет ее закрывать.
> 
> P.S. Жду новых удивительных историй о том, что это не баг, и о том, что
> завершения триггеров можно дождаться с помощью ps

(In reply to Ivan A. Melnikov from comment #31)
> (In reply to comment #29)
> [...]
> > $ git grep -e 'rpmtsCloseDB' |wc -l
> > 0
> 
> TIMTOWDI. Try `git grep rpmtsFree`.

Сейчас в apt-0.5.15lorg2-alt79 есть обёртки над основным процессом, которые выполняют в конце действия из POST_UPDATE_SCRIPT -- туда rpm их запишет (например, перестройку базы данных, я так думаю, с последующим запуском отложенных триггеров).

Мне кажется, что лучше будет это сделать не с помощью обёрток, а внутри функций apt в те моменты по завершении транзакций, когда база данных rpm закрывается. Там, надеюсь, будет ясно, что apt работает с один экземпляром "системного пакетного менеджера" и не будет сомнений, что кто-то ещё держит базу открытой.

В случае apt-shell это будет более правильный подход, потому что он позволяет делать транзакции многократно.

Также это сработает для клиентов libapt (таких как packagekit, synaptic, etc.), которые сами напрямую базу данных rpm не открывают, конечно, т.е. всё нам интересное может контролировать libapt.