Следующий подход, похоже, запускает сценарий только при завершении работы, а не при перезагрузке. Вы можете отредактировать файл systemd-poweroff.service
следующим образом:
sudo systemctl edit --full systemd-poweroff.service
В разделе [Service]
вы можете добавить строку ExecStartPre
:
ExecStartPre=/path/to/script/pfsenseshutdown.sh
Таким образом, сценарий не будет выполняться, если вы выключите систему с помощью halt
. Чтобы справиться с этим случаем, вы можете добавить ту же строку в systemd-halt.service
.
Обратите внимание, что при таком подходе конфигурационный файл, показанный в вопросе, не используется.
РЕДАКТИРОВАТЬ: возможный недостаток предыдущего подхода заключается в том, что выполняемый скрипт содержит команду ssh
, которая может не работать прямо перед выключением системы (возможно, systemd уже остановил необходимые сетевые услуги). Приведенный ниже подход пытается этого избежать.
Для этого решения я создал модуль pfsenseshutdown.service
со следующим содержимым
[Unit]
Description=PFSense Shutdown script
DefaultDedendencies=no
[Service]
Type=oneshot
ExecStart=/usr/bin/touch /dev/shm/shuttingdown
[Install]
WantedBy=systemd-halt.service systemd-poweroff.service
При запуске процедуры завершения работы этот файл, кажется, вызывает выполнение строки ExecStart
сразу же, вызывая существование файла / dev / shm / shuttingdown
(каталог / dev / shm
является файловой системой памяти, поэтому он будет очищен после перезагрузки).
Теперь, чтобы убедиться, что ваш сценарий выполняется до полной деинициализации сети, я запустил
systemctl edit --full networking.service
Первоначально он содержал следующую строку ExecStop
на моей виртуальной машине ubuntu 16.04:
ExecStop=/sbin/ifdown -a --read-environment
Эта строка была заменена версией, которая сначала запускает ваш сценарий, в этом примере:
ExecStop=/path/to/script/pfsenseshutdown.sh && /sbin/ifdown -a --read-environment
The pfsenseshutdown.sh
, затем проверяет, существует ли файл в / dev / shm
, и соответственно выполняет команду ssh. Я также добавил небольшую команду sleep
: systemd выполняет множество операций параллельно, и это, надеюсь, поможет предотвратить сбой теста, потому что файл еще не существует .
#!/bin/bash
sleep 1
if [ -e /dev/shm/shuttingdown ] ; then
# Your ssh command here
fi
exit
закрывает текущий процесс оболочки¹.
В $(resolve_ip)
resolve_ip
выполняется в процессе подоболочки.
Можно сделать:
my_ip=$(resolve_ip) || exit
master_ip=$(resolve_ip "$hostname") || exit
if [ "$my_ip" = "$master_ip" ];...
Для выхода основной оболочки (с тем же кодом выхода, что и подоболочка ), когда подоболочка завершается с ненулевым -статусом выхода.
Кроме того, поскольку resolve_ip
выполняется в среде подоболочки, переменные $ip
и $host
не сохранятся после возврата из этой подоболочки.
Также обратите внимание, что (...)
в (>&2 echo "Error: $1")
также запускает подоболочку. В этом нет необходимости, если только вы не хотите покрыть случай, когда stderr является сломанным каналом, и запись сообщения об ошибке вызовет доставку SIGPIPE в основной процесс оболочки, поскольку echo
встроен.
Здесь вместо возврата вывода через стандартный выводвы можете вернуть его, сохранив в пользовательских переменных:
resolve_ip (){ # args: ip_var [host]
if [ "$#" -eq 1 ]; then
host=localhost
eval "$1="'$(dig +short myip.opendns.com @resolver1.opendns.com)'
else
host=$2
eval "$1="'$(dig +short "$2")'
fi
if eval '[ -z "${'"$1"'}" ]'; then
error "Could not resolve $host"
fi
}
#...
resolve_ip my_ip
resolve_ip master_ip "$hostname"
if [ "$my_ip" = "$master_ip" ];...
¹ Строго говоря, среды подоболочек не обязательно должны быть реализованы с дочерними процессами, а некоторые оболочки, такие как ksh93
, не делают этого в целях оптимизации, но все же exit
происходит выход только из подоболочки, а не из основной оболочки. Однако ksh93
имеет форму ${...; }
или подстановку команд, которая не включает среду подоболочки, поэтому exit
в этом случае приведет к выходу из основной оболочки.