Update flatpaks using timers
I've recently replaced all possible apps I had from snaps to Flatpaks.
One of the key feature from flatpak that I like to have and is not present in snaps is being able to install packages as a regular user (rather than requirering a superuser access). On the other hand snap packages are able to update themselves without any interaction, a feature that flatpak lacks by default.
I lied. I still use snaps for Microk8s, LXD and Notable. While Notable has some viable alternatives regarding its installation process, I'm still stuck with snaps for the 2 others. Maybe viable ports will be done soon ? :)
To fix this issue, I'm leveraging Systemd, service unit files, timers, and the ability of systemd to configure such items without admin rights.
Unit files
Both a service unit and a timer unit are needed (they're specific type of systemd's unit file).
At core, a service unit triggers a command which last until the service or the system is stopped. A service can be extensivly configured with environment variables, complex dependencies, pre and post execution commands, etc. In our case, we're just looking to execute a simple task.
The timer will “wrap” the service unit with a configuration tailored to control the regularity of the service execution. A timer unit always relate to a service unit by sharing its name (They'll just have different extensions).
Service unit
The service unit file is created through systemctl (no need to know where the file is, we can let systemd manage that):
systemctl --user edit --force --full flatpak-update.service
# --force will create a new unit if it doesn't already exists
# --full will edit a file in place instead of creating an override
[Unit]
Description=Update flatpak apps
After=network-online.target
[Service]
Type=simple
ExecStart=flatpak update --noninteractive --assumeyes
[Install]
WantedBy=multi-user.target
The most important instruction is ExecStart
which contains the update command. We're also enforcing a dependency to network availability.
Timer unit
If you start the newly created service as is (systemctl --user start flatpak-update.service
) it'll update your packages but won't be scheduled. To trigger that unit on a regular basis, you need a timer:
systemctl --user edit --force --full flatpak-update.timer
[Unit]
Description=Update flatpack packages every hours
[Timer]
OnBootSec=15min
OnUnitActiveSec=1h
[Install]
WantedBy=timers.target
The most important instruction (and a bit cryptic one) is OnUnitActiveSec
which says “Once you ran a unit for the first time, trigger that unit again at the given interval, starting at first launch", which in our case is 1h. In other words, once a system boots, it'll wait 15 minutes, trigger the service unit, and do so each hours with that “first trigger time” as a reference point.
Activate
All components are ready, we just need to start the timer and set it as enabled:
systemctl --user start flatpak-update.timer # Start the timer
systemctl --user enable flatpak-update.timer # Start the timer again when the system (re)starts
You should be able to check the status of your timer(s) now:
systemctl --user list-timers # See your timers and their related timing infos
systemctl --user list-timers --all # --all: Shows non-started timers
More infos
If you're curious about the location of the files your created, the info is available with the status action :
systemctl --user status flatpak-update
...
Loaded: loaded (<your_home>/.config/systemd/user/flatpak-update.service; ...
This will also report the status of the last run of your service.
Also notice: using --user
means a different instance for systemd than the global one. Each users will have its own repport regarding health. A healthy system won't mean a user (through systemd point of view) will have the same healthy report. Check both:
systemctl is-system-running
systemctl --user is-system-running
Links
For more infos, you can check the following links:
- Archlinux's wiki page about systemd user instances
- If you're editing a file with systemctl edit, without the
--full
option, you'll override an already existing unit file (another Archlinux wiki link)