Skip to content

v0.7.0

Choose a tag to compare

@github-actions github-actions released this 26 Oct 20:41
· 85 commits to main since this release
a1eb763

Changelog

Fixes found by rehearsing the whole lifecycle on rebuilt and unattended
machines. An unattended update now takes its pre-update backup, a timer runs
when it is installed rather than at the next boot, and a networked machine
pulls the image its backups read volumes through. A rebuilt machine needs no
init --repair after its import. A release that migrates with a service now
has a known database schema, and keeps a failed migration's last lines of
output in the error.

Upgrading changes no schema: the installation stays at 12, and a bundle built
for 0.6.0 installs unchanged. Five things behave differently:

  • installation import installs the systemd units, as init does. On a host
    running systemd where the manager does not run as root, it now fails at that
    step; --install-units=false opts out.
  • An apply or update that pulls the release's images from a registry also
    pulls the pinned volume helper image, and an update pulls it before its
    pre-update backup. A registry or mirror that does not carry it is a warning,
    not a failure.
  • A release that migrates with a service and declares
    database_schema_produces has that schema recorded after its next
    successful converge. The schema checks of rollback, update and the
    unattended gate, skipped until now, then run against it, so an unattended
    update that went ahead on 0.6.0 can now be held for a person.
  • Timers installed by 0.6.0 or earlier are enabled and not started, and
    config set does not start them. morzer init --repair, or a reboot, does.
  • release verify prints a warning, and still exits 0, for a release that
    migrates with a service and declares no database_schema_produces.

No JSON output changed.

Fixed

  • A release that migrates with a service never had a known database schema. A migration run as a one-shot container cannot report the schema it leaves, so the installed schema stayed 0, and rollback, update and the unattended gate skipped their schema checks. When a migration service succeeds and no step reported a schema, the release's database_schema_produces is now recorded as the schema it left. A schema a hook reports still wins over the declaration. release verify warns, and still exits 0, when a release migrates with a service and declares no database_schema_produces. (#143, RFC 0033)
  • A re-apply reset a known database schema to 0. The schema recorded after a converge came from that run's migrations alone, and a migration that reported none, such as one run as a service, recorded 0. So an apply, including the one at every boot, could forget the schema an earlier migration had reported, and rollback, update and the unattended gate then skipped their schema checks. A converge of the installed release that reports no schema now keeps the recorded one. An update still records only what its migrations report, because a new release's migrations may have moved the schema. How a migration service reports the schema it leaves is proposed in RFC 0033.
  • A networked machine's first backup could refuse for want of the volume helper image. Backups read volumes through a pinned busybox, and nothing pulled it: apply pulled only the release's images, and a backup refuses rather than pulls on purpose. So unless somebody had acted on doctor's warning, the first backup failed with the volume helper image … is not on this machine, the pre-update backup included. An apply or update that pulls the release's images from a registry now pulls the helper as well, and an update pulls it before its pre-update backup, so a machine that lost it, to docker image prune -a for example, is not refused. A failed helper pull is a warning and does not fail the operation. A release whose images all travel in the bundle pulls nothing, so an offline machine still preloads it by hand, as doctor says.
  • A failed migration service's output was lost unless --verbose was passed. A runtime-service migrate step that exited non-zero reported only its exit code, and the hint sent the operator to a log that did not hold the output. The container is removed when it exits and the journal keeps no output, so a unit started by systemd, which runs without --verbose, lost the migration's error entirely. The error now quotes the last lines the container printed, as a failed hook's does, taken from both streams in the order they arrived, so a migration that reports its failure on stdout is not quoted as Compose's own progress on stderr.
  • secret set exited 6 before the first apply, though the value was stored. init makes the release current, so the restart after a secret change rendered every secret the release declares, and refused over a required one the operator had not set yet. A release needing two values only the operator has could not be given the first without exit 6, which a script under set -e reads as the value not being saved. set, generate, rotate and edit now restart nothing, and render nothing, when the deployment has no containers at all. When the render or the restart fails on a deployment that has them, the error now says the change was stored, and the exit code still says which failed.
  • A timer that init or config set installed did not fire until the next reboot. The backup, update and fleet timers were enabled and never started, so systemctl list-timers showed no next run and the schedule an operator had just set waited for a boot. A timer is now started when it is enabled. The product's own service is still only enabled, because starting it runs apply --startup. A timer an operator disabled stays stopped. On a machine set up by an earlier version, morzer init --repair starts its timers, and so does a reboot.
  • A failed init --repair removed the units it had found installed. When installing the units failed, the undo removed every unit the product manages rather than only what the failed install had created, so a timer that would not start, or an enable that failed, took the product's service file with it. Only a completed install is undone now; a failed one already reverses its own changes. Separately, an install interrupted part-way now still stops and disables what it had started and enabled before removing the files it wrote.
  • update --check refused on a machine installed from a registry until its first update. init --release oci://… recorded no release source, so the bare check said this installation has no recorded release source, even with update.channel set. init now records the ref it installed from, as update does. A machine with no recorded source, or one that cannot list versions such as a local path, now checks the repository of update.channel when one is set. A ref passed to --check is still used as given. A machine installed before this change still has no recorded source; setting update.channel, or one update from a ref, gives it one.
  • Attestation counts mixed two units with more than one target. doctor and attest push counted each statement once per target that lacked it, and reported that against a total of statements, so two targets after five operations read 10 of 5 attestation(s) are only on this machine, and the push that closed the gap reported ten. Every count is now of statements: 5 of 5 attestation(s) are missing from at least one of 2 targets, then pushed 5 attestation(s) to 2 targets. With one target, doctor still says only on this machine. The per-target missing and pushed fields of attest push --json were already per target and are unchanged.
  • attest verify --against-live reported a migration service's image as missing. A release that migrates with one-shot services, flyway in a container for example, attests their images, and those services exit by design once the migrations are done. So the check failed with exit 3 on every healthy machine running such a release, and could not serve as a cron or CI gate. An image that only the release's migrate services run is no longer expected to be running. An image that a service the deployment starts also runs is still reported when nothing runs it.
  • A machine rebuilt by installation import needed an init --repair nobody was told to run, and the remedy doctor printed for it failed as printed. The import minted no signing key, so the first update or restore minted one that installation state never recorded, and it installed no systemd units, so the service and the timers stayed missing. It now mints and records the signing key, keeping the lost machine's as its predecessor, and installs the units as init does; --install-units=false opts out. Separately, init --repair now finds the installation the way every other command does, so --product is needed only on a machine with several, and secret state that already has a recovery recipient needs neither --recovery-recipient nor --no-recovery-recipient. (#135)
  • An unattended update could never take its pre-update backup. update --unattended, which the update timer runs, did not wire the backup engine that a manual update wires. With update.auto_apply on and the pre-update backup left on, every tick that found a release to install failed at that step with no backup engine is configured, exit 10. A tick now takes the same pre-update backup a manual update does.

Installing this release

curl -fsSL https://morzecrew.github.io/morzer/install.sh | sh -s -- --version 0.7.0

The script verifies the checksum always and the signature whenever
minisign is present; --require-signature makes a missing minisign fatal,
which is what a production runbook sets. --print-only shows everything it
detected and would do, and changes nothing. install.sh is an asset of this
release and is covered by SHA256SUMS below.

Verifying this release by hand

ARCHIVE=morzer_0.7.0_linux_amd64.tar.zst   # the one you downloaded

curl -fsSLO https://raw.githubusercontent.com/morzecrew/morzer/main/morzer.pub
minisign -Vm SHA256SUMS -p morzer.pub
grep " ${ARCHIVE}$" SHA256SUMS | sha256sum -c -

SHA256SUMS covers every architecture, so checking it whole fails on the
archives you did not download — and --ignore-missing, the usual way
around that, reports OK when no archive is present at all. Pulling out
the line for the file you have fails when there is nothing to check.

The signing key is the same for every release. If you have verified a
morzer release before, use the copy you already have rather than fetching
it again — a key that changes between releases is the thing worth noticing.

Release bundles are a separate artifact with their own signature and their
own key; see
https://morzecrew.github.io/morzer/reference/release-commands/#verification