Preventing disrupting reboots with Ubuntu automatic updates

Keeping your systems up to date is important, and Ubuntu makes this fairly easy. It’s also easy to enable automatic reboots when required for an update. The downside is that these updates can happen when they shouldn’t. With some custom SystemD services you can replace the built in automatic-reboot functionaly with a system that waits until conditions are appropriate to reboot.

Start by enabling automatic updates, but make sure Unattended-Upgrade::Automatic-Reboot' is set to "false"`.

When a reboot is needed Ubuntu places a file in /var/run/reboot-required. Make a service that reboots the system only if this file exists.

/etc/systemd/system/reboot-for-upgrades.service

[Unit]
Description=Reboot if updates require it
ConditionPathExists=/var/run/reboot-required

[Service]
Type=oneshot
ExecStart=/bin/true
ExecStop=/bin/systemctl reboot

This service’s start action does nothing, but it’s stop action reboots the machine. This is important for proper ordering with the services we want to delay or prevent a reboot.

This service needs to run after apt-daily-upgrade runs. So use a SystemD override to make this happen.

/etc/systemd/system/apt-daily-upgrade.service.d/override.conf

[Unit]
Requires=reboot-for-upgrades.service
Before=reboot-for-upgrades.service

Now make a SystemD service that will run before reboot-for-upgrades, which can ensure that the system is ready to reboot. In my case, I do not want a machine to reboot if the Citrix ICA Client is running, because this means a user is actively using this machine. This service will wait for the process to finish for up to 12 hours before allowing the reboot to complete.

/etc/systemd/system/wait-for-icaclient.service

[Unit]
Description=Wait for ICAClient to stop

[Service]
Type=oneshot
ExecStart=/bin/true
ExecStop=-/bin/sh -c 'tail --pid=$(pidof wfica) -f /dev/null'
TimeoutStopSec=12h

Again, the interesting work is done in ExecStop. In this case, tail's –pid feature is used to block until the wfica process exits. ExecStop is prefixed with a - so that if the command fails (which it will if wfica is not running) the service is still considered successfully stopped.

The dependency is created in an override for reboot-for-upgrades.service.

/etc/systemd/system/reboot-for-upgrades.service.d/wait-for-icaclient.conf

[Unit]
Requires=wait-for-icaclient.service
After=wait-for-icaclient.service

Now reboot-for-upgrades.service depends on wait-for-icaclient.service and should start after it. Because SystemD inverts ordering for stopping services, this means that wait-for-icaclient.service will complete it’s ExecStop command before reboot-for-upgrades.service can run it’s ExecStop command.