ACPI
Зачем это
При выключении сервера с виртуальными машинами очень хочется понимать что ВМки "поймали" сигнал от хоста и завершили работу максимально корректно (ну в пределах тех минут на сколько зватит УПСа)
За настройку выключения отвечает либвирт и в современных системах по-умолчанию это "виртуальная кнопка питания", событие от которой обрабатывается внутри ВМ
[о настройке выключения при работе от UPS] - дополнительная информация
События ACPI в Linux
ACPI(Advanced Configuration and Power Interface) это стандарт (с 1996?) для управления питанием (но не только?)
- В современых системах события ACPI обрабатывает
systemd-logind
- Более сложные сценарии можно реализовать через
acpid service
- В этой доке только совсем базовый пример - то что было нужно мне на сейчас
События ACPI
обрабатываемые systemd-logind
Часть событий обрабатывает сервис systemd-logind
Какие именно события обрабатываются и как описано в файле /etc/systemd/logind.conf
(сокращенный пример)
[Login] [...] #HandlePowerKey=poweroff #HandleSuspendKey=suspend #HandleHibernateKey=hibernate #HandleLidSwitch=suspend #HandleLidSwitchExternalPower=suspend #HandleLidSwitchDocked=ignore #HandleRebootKey=reboot [...]
Значения по-умолчанию закоментированы, и нужны только для того что бы понимать, например не смотря на комментарий: #HandlePowerKey=poweroff
означает что при нажатии кнопки питания (или в случае виртуальной машины - получении соответвующего события) произойдет выключение
Возможные значения:
- ignore
- poweroff
- reboot
- suspend
- hibernate
- hybrid-sleep
Синтаксис файла очевиден - событие
=действие из списка
If we need to manage acpi events not covered by systemd-logind, with more complex or custom actions, we need to change strategy, install and run the acpid daemon. Let’s see how to proceed.
Однако если ни одно из действий не подходит, то нужно использовать ACPID
Сервис acpid
Установка:
$ sudo apt install acpid $ sudo systemctl enable --now acpid
(тут немного забегаю вперед, 2 rules loaded пока не созданы еще)
systemctl status acpid ● acpid.service - ACPI event daemon Loaded: loaded (/lib/systemd/system/acpid.service; disabled; vendor preset: enabled) Active: active (running) since Thu 2024-05-02 19:30:12 UTC; 3 days ago TriggeredBy: ● acpid.socket ● acpid.path Docs: man:acpid(8) Main PID: 499 (acpid) Tasks: 1 (limit: 44705) Memory: 284.0K CGroup: /system.slice/acpid.service └─499 /usr/sbin/acpid --logevents May 02 19:30:12 mgmt-1 systemd[1]: Started ACPI event daemon. May 02 19:30:12 mgmt-1 acpid[499]: starting up with netlink and the input layer May 02 19:30:12 mgmt-1 acpid[499]: 2 rules loaded May 02 19:30:12 mgmt-1 acpid[499]: waiting for events: event logging is on
Обработака событий ACPI
Мониторинг событий
- Для тесторивания можно воспользоваться утилитой
acpi_listen
которая покажет какие события происходят - Для виртуальной машины (а это именно мой случай) можно использовать команду
virsh shutdown guest1 --mode acpi
, естественно сначала отключив обработку этого события вsustemd
(В logind изменить HandlePowerKey на ignore)
Например
button/power PBTN 00000080 00000000 button/power LNXPWRBN:00 00000080 00000004
Тут 4 столбца
- device class
- kernel name for the device (по этому имени можно смотреть в /sys/bus/acpi/devices)
Например
cat /sys/bus/acpi/devices/LNXPWRBN\:00/input/input0/name Power Button
- код события
- последнее значение контекстно-зависимо,и имеет различное значение в зависимости от события
Создание обработчика событий
В случае Убунты
/etc/acpi/events/010_power_button
- обработчик на определенное событие
event=button/power action=/etc/acpi/acpi_power_button.sh %e
/etc/acpi/events/999_all
- на все
event=.* action=/etc/acpi/handler.sh %e
%e будет заменен кодом события)
Далее добавить собственно скрипты-обработчики
/etc/acpi/acpi_power_button.sh
#!/bin/bash echo "[$(date)][$@][$(id)] /sbin/shutdown -h now Power button pressed" | logger -t "acpi_power_button" echo "[$(date)][$@][$(id)] /sbin/shutdown -h now Power button pressed" > /etc/acpi_powerloss /sbin/shutdown -h now "Power button pressed"
Результат можно смотреть в логах
zcat /var/log/syslog*gz | grep 'acpi_power_button'
May 2 14:48:48 mgmt-1 acpid: executing action "/etc/acpi/acpi_power_button.sh button/power PBTN 00000080 00000000" May 2 14:48:48 mgmt-1 acpi_power_button: [Thu May 2 14:48:48 UTC 2024][button/power PBTN 00000080 00000000][uid=0(root) gid=0(root) groups=0(root)] /sbin/shutdown -h now Power button pressed
/etc/acpi/handler.sh
#!/bin/bash echo "[$(date)] $@" | logger -t "ACPID event handler"
zcat /var/log/syslog*gz | grep 'ACPID event handler' May 2 14:48:48 mgmt-1 ACPID event handler: [Thu May 2 14:48:48 UTC 2024] button/power PBTN 00000080 00000000