Skip to content

Commit 2d44164

Browse files
saironclaude
andcommitted
Add pre-shutdown phase to coordinate shutdown with Supervisor
Introduce haos-pre-shutdown.target, a phase Supervisor enters before a API-triggered reboot or power off. ha-cli@.service conflicts with the target, so the console CLI is stopped by a regular stop job instead of restart-looping once Supervisor stops the CLI plugin (#4584). While the CLI is down, haos-shutdown-notice@.service takes over its tty and shows a shutdown notice, so the console no longer shows just a blinking cursor. It is a template enabled through ha-cli@.service's Also=, keeping the console instance defined in a single place. hassos-supervisor.service gets a longer "docker stop" timeout. As the unit is already ordered after docker.service, Supervisor can now stop Home Assistant Core, add-ons and plugins gracefully on SIGTERM before Docker tears the containers down (#4642). Supervisor will the target and perform the graceful shutdown via a separate change. Closes #4584, closes #4642 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 820768d commit 2d44164

6 files changed

Lines changed: 64 additions & 3 deletions

File tree

buildroot-external/rootfs-overlay/usr/lib/systemd/system/ha-cli@.service

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
Description=Home Assistant CLI
33
Wants=hassos-supervisor.service
44
After=systemd-user-sessions.service plymouth-quit-wait.service getty-pre.target hassos-supervisor.service
5-
Conflicts=getty@%i.service
5+
Conflicts=getty@%i.service haos-pre-shutdown.target
66

77
# If additional gettys are spawned during boot then we should make
88
# sure that this is synchronized before getty.target, even though
99
# getty.target didn't actually pull it in.
10-
Before=getty.target
10+
Before=getty.target haos-pre-shutdown.target
1111

1212
# IgnoreOnIsolate causes issues with sulogin, if someone isolates
1313
# rescue.target or starts rescue.service from multi-user.target or
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
[Install]
22
DefaultInstance=tty1
3+
# Enable the matching console shutdown notice for the same instance, so the
4+
# tty1 default lives in exactly one place.
5+
Also=haos-shutdown-notice@%i.service
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[Unit]
2+
Description=Home Assistant OS pre-shutdown phase
3+
# Started explicitly by Supervisor before an API-triggered reboot/shutdown so
4+
# that units conflicting with it (e.g. ha-cli@.service) are stopped cleanly
5+
# before Supervisor stops the matching plugin containers.
6+
DefaultDependencies=no
7+
RefuseManualStop=yes
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[Unit]
2+
Description=Home Assistant OS console shutdown notice on %I
3+
DefaultDependencies=no
4+
ConditionPathExists=/dev/%i
5+
# Take over the console once the Home Assistant CLI instance has been stopped,
6+
# and have the notice up before the pre-shutdown phase completes so there is no
7+
# blank gap. Enabled via ha-cli@.service's "Also=".
8+
After=ha-cli@%i.service
9+
Before=haos-pre-shutdown.target
10+
11+
[Service]
12+
Type=simple
13+
ExecStart=/usr/libexec/haos-shutdown-notice
14+
TTYPath=/dev/%i
15+
TTYReset=yes
16+
StandardOutput=tty
17+
StandardError=journal
18+
19+
[Install]
20+
WantedBy=haos-pre-shutdown.target

buildroot-external/rootfs-overlay/usr/lib/systemd/system/hassos-supervisor.service

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@ Restart=always
1515
RestartSec=5s
1616
ExecStartPre=-/usr/bin/docker stop hassio_supervisor
1717
ExecStart=/usr/sbin/hassos-supervisor
18-
ExecStop=-/usr/bin/docker stop hassio_supervisor
18+
# This unit is ordered After=docker.service, so on host shutdown it is
19+
# stopped before Docker tears containers down. Supervisor handles the
20+
# SIGTERM from "docker stop" by gracefully stopping Home Assistant Core,
21+
# apps and plugins; allow ample time for that to complete.
22+
ExecStop=-/usr/bin/docker stop -t 420 hassio_supervisor
23+
TimeoutStopSec=450s
1924

2025
[Install]
2126
WantedBy=multi-user.target
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/bin/sh
2+
# ==============================================================================
3+
# Display a shutdown notice on the console.
4+
#
5+
# Started via haos-pre-shutdown.target when a reboot or power off is triggered
6+
# via API. The Home Assistant CLI on default tty is stopped at that point, so
7+
# without this the console would just show a blinking cursor.
8+
# ==============================================================================
9+
10+
# Move to the top, clear the screen and hide the cursor.
11+
printf '\033[H\033[2J\033[?25l'
12+
13+
cat <<'EOF'
14+
15+
16+
Home Assistant is shutting down...
17+
18+
This can take a moment, the system will power off or restart shortly.
19+
20+
EOF
21+
22+
# Keep the service alive so the notice stays on screen until Systemd kills
23+
# this service and starts printing its messages.
24+
while true; do
25+
sleep 3600
26+
done

0 commit comments

Comments
 (0)