Updates¶
The box is an image (bootc). An update is a newer image from where the box
follows (bootc status: a registry, or in the lab containers-storage):
it is downloaded alongside the running one and started on the next boot,
and the previous one stays, to go back to. strongholdd drives it
(internal/updates); bootc's own bootc-fetch-apply-updates.timer stays
off, because in a pair the two boxes must not restart together.
By hand¶
stronghold update # what runs, what's newer, what's downloaded, the previous
stronghold update check # ask the source (metadata only)
stronghold update download # download now, start at the next reboot
stronghold update apply # restart into it (downloading first if needed)
stronghold update rollback # restart into the previous image
The same is in the UI (System tab) and the API (/v1/updates); the UI
shows the host image, Stronghold and the functions' images apart, since
they are versioned apart (D23): a new host image may bring Fedora's
updates with the same Stronghold. A restart is a soft reboot (userspace
only) when the kernel is the same, else a reboot; one downloaded already
starts with a reboot, nothing fetched again.
A download fetches the functions' images too: those the new image's
stronghold package names for the functions the box runs in containers
(stronghold-prefetch-images@.service, from the new image's cache when
it has one, else pulled), so that after the restart each container
starts at once; without them it pulls its own first, the function down
until it has (an IDS image took three minutes in the lab). The window
always downloads first; an apply with nothing downloaded doesn't, and
its containers pull after the restart. If they can't be fetched the
update goes on; they are pulled after it, as before. A box from
packages pulls them after the upgrade (its new quadlets are only there
then).
In a pair, apply and rollback on the active box hand over to the
standby first, so the gateway stays up; without a peer that can take
over they refuse (--force: go ahead, the gateway goes down). On the
standby they just restart it.
Automatically¶
# stronghold.yaml
updates:
automatic: true
days: [sun] # default every day
at: "03:30" # local time, the window's start (default 03:30)
In the window (two hours) the box checks every ten minutes until it has either found no newer image or updated:
- A box alone restarts into the newer image.
- In a pair the standby goes first (only while its peer is active and answers, so the gateway stays up). The active box waits until its peer runs the new image (the peer's state says which image it booted), then hands over and updates; so the pair updates one box at a time, and ends with the roles swapped.
- A backup first, if the backup settings ask for one
(
backups.before-update): without it, the update doesn't go ahead.
After an update¶
A box that restarts into a new image checks that it works (a marker,
written before the restart, says it is one; strongholdd stopped by its own
soft reboot, or a reboot that returns at once, is the restart, not a
failure, and leaves the marker): within five
minutes its config must be active and applied without error. If not, it
goes back to the previous image (bootc rollback) and says so in the
updates' events; it doesn't try that image again on its own until a newer
one comes (the next check finds the same one, and the window is over by
then).
That check runs inside strongholdd, so a new image whose strongholdd
doesn't start is caught by greenboot instead (Fedora's
greenboot, greenboot-rs, in the image): its required health check
(/usr/lib/greenboot/check/required.d/50-strongholdd.sh) wants
strongholdd running and its API answering within three minutes of boot.
A boot where it doesn't is red: greenboot reboots, and after three red
boots (GREENBOOT_MAX_BOOT_ATTEMPTS) GRUB boots the previous image and
greenboot keeps it. Its red.d script leaves
/var/lib/stronghold/greenboot-red; the previous image's strongholdd
finds it, says which image didn't start (an event, and a critical
updates alert) and ends the update it was doing. greenboot's own
default checks (greenboot-default-health-checks: the repositories
resolve, the update server answers) aren't installed: a gateway whose
WAN is down is still a healthy box.
Limits¶
- The source is whatever the box was installed or switched to (
bootc switch); changing it isn't in the UI yet. - Images aren't signature-checked by Stronghold; that is the registry's
and the container policy's (
/etc/containers/policy.json). - A box installed from packages has no image: its updates are dnf's
("A box installed from packages", below). PackageKit asks
NetworkManager whether the box is online, so the WANs' default routes
are in the main table too (
wan.md, "How it routes"); with them only in the WANs' tables, PackageKit 1.4.0 thought the box offline and its downloads failed ("cacheonly option is activated").
A box installed from packages¶
Its updates are its packages', from the system's dnf repositories,
through PackageKit as the functions' installs are: strongholdd runs
pkcon, never dnf itself (internal/updates/packages.go).
- Check refreshes the repositories and lists the updates (
pkcon refresh,get-updates): the status shows how many, how many are security updates, and their packages. - Download prepares them as an offline update (
pkcon --only-download update). - Apply triggers the offline update and reboots (
pkcon offline-trigger): the packages are installed while the box boots (system-update.target, Fedora's offline updates, as GNOME Software does them), so nothing is replaced under the running services, and it boots again into them. - After it the box says how PackageKit's update ended (
pkcon offline-status) and checks itself as after an image update; but packages have no previous version to go back to, so a box that doesn't work is reported (a critical alert), not rolled back.rollbackis refused. - The window and the pair work as for images: the standby goes
first; for the pair, a box's "image" is its pending updates
(
packages:up-to-dateonce there are none), and the active box follows once its peer, the standby, has none pending. - The same commands, API and UI;
GET /v1/updatessaysmode: packages. Cockpit's Software Updates page anddnf upgradestill work too: Stronghold just does it in its window, one box at a time.
Going back¶
An older image (after bootc rollback, or an update rolled back) may find
a config with settings that came with the newer Stronghold. The config
is parsed strictly (D13), so it wouldn't load, and the box would run
without its config. Instead (internal/core/fallback.go):
- Each build records the commit it last applied
(
/var/lib/stronghold/applied.json, by version). - A config that needs a newer Stronghold (a key this build doesn't know, or a newer schema version) isn't an error: the box runs the commit this build last applied, or if it has none, the newest commit in the history it can read.
- The config directory isn't touched: the newer image runs the current
config again. Meanwhile changes (UI, CLI, API, the peer's sync) are
refused, since saving would drop the newer settings; the status says
why, and a critical
configalert goes out. - A key that is only a typo looks the same: the box runs its last applied config, and the status names the key.
- In the lab: an unknown key added to gw2's config; after a restart it ran its last applied commit, all its firewall zones in place.