Small update program written in python intended for use in Universal Blue that uses topgrade
for executing updates.
Includes systemd timers and services for auto update
dependencies (fedora): sudo dnf install python3-psutil libnotify
You can add this to your image by simply pulling down and installing the rpm:
COPY --from=ghcr.io/ublue-os/ublue-update:latest /rpms/ublue-update.noarch.rpm /tmp/rpms/
RUN rpm-ostree install /tmp/rpms/ublue-update.noarch.rpm
If you are on an image derived from uBlue main:
COPY --from=ghcr.io/ublue-os/ublue-update:latest /rpms/ublue-update.noarch.rpm /tmp/rpms/
RUN rpm-ostree override remove ublue-os-update-services && rpm-ostree install /tmp/rpms/ublue-update.noarch.rpm
Note If you are on an image derived from uBlue main, you will need to remove or disable automatic updates with rpm-ostreed, to do this, you need to remove or change this line in the config file:
AutomaticUpdatePolicy=stage
(set tonone
if you don't want to remove the line)
To run a complete system update, it's recommended to use systemd:
$ systemctl start ublue-update.service
This allows for passwordless system updates (user must be in wheel
group)
Only run user updates (rootless):
$ ublue-update
Only run system updates (requires root):
$ pkexec ublue-update --system
usage: ublue-update [-h] [-f] [-c] [-u] [-w] [--system]
options:
-h, --help show this help message and exit
-f, --force force manual update, skipping update checks
-c, --check run update checks and exit
-u, --updatecheck check for updates and exit
-w, --wait wait for transactions to complete and exit
--config CONFIG use the specified config file
--system only run system updates (requires root)
You can check the ublue-update logs by running this command:
$ journalctl -exu 'ublue-update.service'
Update scripts are separated into two files inside of /usr/share/ublue-update
Topgrade config ran as root, handles rpm-ostree and flatpaks.
Topgrade config ran as user, handles flatpaks and distrobox containers.
See topgrade
's GitHub for configuring these files.
-
/etc/ublue-update/ublue-update.toml
-
/usr/etc/ublue-update/ublue-update.toml
-
min_battery_percent
: checks if battery is above specified percent -
max_cpu_load_percent
: checks if cpu average load is under specified percent -
max_mem_percent
: checks if memory usage is below specified percent -
network_not_metered
: if true, checks if the current network connection is not marked as metered
In addition to the predefined checks above, it is also possible to implement
custom conditions through user-provided scripts and their exit codes.
Each entry in the checks.scripts
array must specify the following settings:
-
shell
: specifies the shell used to execute the custom script (e.g.bash
) -
run
: specifies the script text to be run using the specified shell -
message
: an optional message that is shown when the check fails -
name
: an optional human-readable name for this check
The parameters run
and file
are mutually exclusive, but at least one must be specified.
The shell
parameter is mandatory when using run
.
The custom script should use its exit code to indicate whether the updater should proceed
(exit code = 0
) or whether updates should be inhibited right now (any non-0 exit code).
If message
is not specified but the script has written text to stdout
,
that text will be used as the message.
dbus_notify
: enable graphical notifications via dbus
[checks]
min_battery_percent = 20.0 # Battery Level >= 20%?
max_cpu_load_percent = 50.0 # CPU Usage <= 50%?
max_mem_percent = 90.0 # RAM Usage <= 90%?
network_not_metered = true # Abort if network connection is metered
[[checks.scripts]]
name = "Example script that always fails"
shell = "bash"
run = "exit 1"
message = "Failure message - this message will always appear"
[[checks.scripts]]
name = "Example script that always succeeds"
shell = "bash"
run = "exit 0"
message = "Failure message - this message will never appear"
[[checks.scripts]]
name = "Example multiline script with custom message"
shell = "bash"
run = """
echo "This is a custom message"
exit 1
"""
[[checks.scripts]]
name = "Python script"
shell = "python3"
run = """
print("Python also works when installed")
exit(1)
"""
[[checks.scripts]]
name = "Example external script"
# shell = "bash" # specifying a shell is optional for external scripts/programs
file = "/bin/true"
[notify]
dbus_notify = false # Do not show notifications
You can build and test this package in a container by using the provided container file.
make builder-image
will create a container image with all dependencies installedmake builder-exec
will execute a shell inside the builder container to allow you easily build the rpm package withmake build-rpm
make
will trigger the build process and generate a.whl
package that can be installedpip install --user -e .
will allow to install an editable version of this package so you quickly edit and test the program
Special thanks to cukmekerb for helping troubleshoot/add features early in project development