
Я хотел бы запустить скрипт, когда мой компьютер (Ubuntu 22.04) выключается, но при этом сеть все еще доступна.
Совет вэта темалюбезно объяснил, как создать файл службы systemd, который будет запускаться при завершении работы, и скрипт действительно запустился, но скрипт не смог выполнить задачу, требующую доступа к сети, поэтому я предполагаю, что сетевое взаимодействие уже было отключено.
Если найдены различные темы (например,Вот этот) о том, как убедиться, что скрипт запущен до отключения сети, но все они, похоже, давали немного разные советы. Я пробовал различные перестановки Before=network-online.target, After=network-online.target и Requires=network-online.target, но ни одна из них не сработала.
Кто-нибудь знает, как убедиться, что скрипт может работать, пока сеть доступна?
Кстати, я не привязан к тому, чтобы делать это как системную работу. Я предполагал, что это будет лучшим способом сделать это, но если есть другой способ достичь того же самого, то это было бы прекрасно.
решение1
Не знаю, поможет ли это, но рассмотрите возможность просмотра файлов systemd .target. Это то, что systemd на самом деле запускает при завершении работы. Вот ссылка.
shutdown.target
A special target unit that terminates the services on system
shutdown.
Services that shall be terminated on system shutdown shall add
Conflicts= and Before= dependencies to this unit for their service
unit, which is implicitly done when DefaultDependencies=yes is set
(the default).
Файлы .target находятся /usr/lib/systemd/system
вместе с файлами .service. Если бы это был я, я бы делал это на виртуальной машине, где я могу легко откатить снимок ;)
решение2
Хорошо, я еще немного поэкспериментировал и добился прогресса, но пока еще не решил проблему.
Оказывается, сеть работает, если у меня есть After=network.target в файле службы. Похоже, что не работает разрешение имен. Так что если я запускаю взаимодействие с удаленным компьютером, указав имя хоста удаленного компьютера, то оно не работает, но если я указываю его, используя его IP-адрес, то оно работает.
Я надеялся, что смогу исправить это, указав After=network.target nss-lookup.target, но это не помогло.
Есть идеи, что еще я могу попробовать?
решение3
Навскидку, почему бы не сделать bash-скрипт:
#!/bin/bash
Your Commands;
shutdown -h now
Выключение не должно выполняться до тех пор, пока «Ваши команды» не будут выполнены.
Скрипт можно назвать «myshutdown» и даже присвоить ему псевдоним системной команды.
(Мне кажется, что это слишком упрощенно, и я уверен, что кто-нибудь укажет мне на ошибки!) (Спасибо за редактирование кода, «Марко»)
решение4
Ключом к пониманию того, как остановить службу при отключении до потери сети, является знание того, чтопорядок выключения - это обратный порядку запуска. Поэтому ваша служба должна начатьсяпосле network-online.target
при этом также имея зависимость от network-online.target
, поскольку он требует, чтобы сеть была включена. Кроме того, есть ExecStart=
и ExecStop=
действия, которые вы можете определить. Поскольку вы хотите, чтобы скрипт запускался при завершении работы, то есть при остановке службы, вы хотите определить ExecStop=
указание на ваш скрипт.
Чтобы настроить это, сделайте следующее:
- в[Единица]раздел, создаем
Requires=network-online.target
зависимость - Установите порядок
After=network-online.target
. - в[Услуга]раздел, не определяйте
ExecStart=
действие. - Установите
RemainAfterExit=true
, поскольку мы не создалиExecStart=
действие. - Наконец, создайте
ExecStop=
действие, указывающее на ваш скрипт, напримерExecStop=/home/username/bin/testscript.sh
.
Помнить,порядок выключения - это обратный порядку запуска. Поэтому, когда ваша служба остановлена, ваш скрипт, который находится в ExecStop=
, будет запущен. И поскольку мы запустили эту службупосле network-online.target
, он будет закрытдовсе службы network-online.target
отключены.
В качестве примера...
Вот простой тестовый скрипт, который использует curl
для получения вашего публичного IP-адреса. Таким образом, для корректной работы требуется DNS.
#!/bin/bash
# NAME: testscript.sh
# PATH: /home/username/bin
NOW=`date`
IP=`curl -s https://ipinfoio/ip`
echo $NOW $IP >> /home/username/ipaddresses
Далее создайте файл службы/юнита systemd в /etc/systemd/system
. Я назвал его testservice.service
.
[Unit]
Description:Test service to execute at shutdown prior to losing network
Requires=network-online.target
After=network-online.target
[Service]
Type=oneshot
RemainAfterExit=true
ExecStop=/home/username/bin/testscript.sh
[Install]
WantedBy=multi-user.target
Сообщите systemd, чтобы он прочитал наш файл:
sudo systemctl daemon-reload
Включить услугу:
sudo systemctl enable testservice.service
Затем перезагрузите систему, и вы увидите, что файл /home/username/ipaddress
обновится с указанием временной метки при завершении работы и вашего публичного IP-адреса.