systemd: Shut down computer at a certain uptime
Motivation
Paid-per-time cloud services. I don’t want to forget one of those running, just to get a fat bill at the end of the month. And if the intended use is short sessions anyhow, make sure that the machine shuts down by itself after a given amount of time. Just make sure that a shutdown by the machine itself accounts for cutting the costs. And sane cloud provider does that except for, possibly, costs for storing the VM’s disk image.
So this is the cloud computing parallel to “did I lock the door?”.
The examples here are based upon systemd 241 on Debian GNU/Linux 10.
The main service
There is more than one way to do this. I went for two services: One that calls /sbin/shutdown with a five minute delay (so I get a chance to cancel it) and then second is a timer for the uptime limit.
So the main service is this file as /etc/systemd/system/uptime-limiter.service:
[Unit] Description=Limit uptime service [Service] ExecStart=/sbin/shutdown -h +5 "System it taken down by uptime-limit.service" Type=simple [Install] WantedBy=multi-user.target
The naïve approach is to just enable the service and expect it to work. Well, it does work when started manually, but when this service starts as part of the system bringup, the shutdown request is registered but later ignored. Most likely because systemd somehow cancels pending shutdown requests when it reaches the ultimate target.
I should mention that adding After=multi-user.target in the unit file didn’t help. Maybe some other target. Don’t know.
The timer service
So the way to ensure that the shutdown command is respected is to trigger it off with a timer service.
The timer service as /etc/systemd/system/uptime-limiter.timer, in this case allows for 6 hours of uptime (plus the extra 5 minutes given by the main service):
[Unit] Description=Timer for Limit uptime service [Timer] OnBootSec=6h AccuracySec=1s [Install] WantedBy=timers.target
and enable it:
# systemctl enable uptime-limiter.timer
Created symlink /etc/systemd/system/timers.target.wants/uptime-limiter.timer → /etc/systemd/system/uptime-limiter.timer.
Note two things here: That I enabled the timer, not the service itself, by adding the .timer suffix. And I didn’t start it. For that, there’s the –now flag.
So there are two steps: When the timer fires off, the call to /sbin/shutdown takes place, and that causes nagging wall messages to start once a minute, and eventually a shutdown. Mission complete.
What timers are pending
Ah, that’s surprisingly easy:
# systemctl list-timers
NEXT LEFT LAST PASSED UNIT ACTIVATES
Sun 2021-01-31 17:38:28 UTC 14min left n/a n/a systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
Sun 2021-01-31 20:50:22 UTC 3h 26min left Sun 2021-01-31 12:36:41 UTC 4h 47min ago apt-daily.timer apt-daily.service
Sun 2021-01-31 23:23:28 UTC 5h 59min left n/a n/a uptime-limiter.timer uptime-limiter.service
Sun 2021-01-31 23:23:34 UTC 5h 59min left Sun 2021-01-31 17:23:34 UTC 44s ago google-oslogin-cache.timer google-oslogin-cache.service
Mon 2021-02-01 00:00:00 UTC 6h left Sun 2021-01-31 12:36:41 UTC 4h 47min ago logrotate.timer logrotate.service
Mon 2021-02-01 00:00:00 UTC 6h left Sun 2021-01-31 12:36:41 UTC 4h 47min ago man-db.timer man-db.service
Mon 2021-02-01 06:49:19 UTC 13h left Sun 2021-01-31 12:36:41 UTC 4h 47min ago apt-daily-upgrade.timer apt-daily-upgrade.service
Clean and simple. And this is probably why this method is better than a long delay on shutdown, which is less clear about what it’s about to do, as shown next.
Note that a timer service can be stopped, which is parallel to canceling a shutdown. Restarting it to push the time limit further won’t work in this case, because the service is written related to OnBootSec.
Is there a shutdown pending?
To check if a shutdown is about to happen:
$ cat /run/systemd/shutdown/scheduled
USEC=1612103418427661
WARN_WALL=1
MODE=poweroff
WALL_MESSAGE=System it taken down by uptime-limit.service
There are different reports on what happens when the shutdown is canceled. On my system, the file was deleted in response to “shutdown -c”, but not when the shutdown was canceled because the system had just booted up. There’s other suggested ways too, but in the end, it appears like there’s no definite way to tell if a system has a shutdown scheduled or not. At least not as of systemd 241.
That USEC line is the epoch time for when shutdown will take place. A Perl guy like me goes
$ perl -e 'print scalar gmtime(1612103418427661/1e6)'
but that’s me.
What didn’t work
So this shows what doesn’t work: Enable the main service (as well as start it right away with the –now flag):
# systemctl enable --now uptime-limiter Created symlink /etc/systemd/system/multi-user.target.wants/uptime-limiter.service → /etc/systemd/system/uptime-limiter.service. Broadcast message from root@instance-1 (Sun 2021-01-31 14:15:19 UTC): System it taken down by uptime-limit.service The system is going down for poweroff at Sun 2021-01-31 14:25:19 UTC!
So the broadcast message is out there right away. But this is misleading: It won’t work at all when the service is started automatically during system boot.
Reader Comments
No me sirve para nada