ACPI

Материал из noname.com.ua
Перейти к навигацииПерейти к поиску

Зачем это

При выключении сервера с виртуальными машинами очень хочется понимать что ВМки "поймали" сигнал от хоста и завершили работу максимально корректно (ну в пределах тех минут на сколько зватит УПСа)
За настройку выключения отвечает либвирт и в современных системах по-умолчанию это "виртуальная кнопка питания", событие от которой обрабатывается внутри ВМ

[о настройке выключения при работе от 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