Skip to content

v0.5.0

Choose a tag to compare

@github-actions github-actions released this 19 Oct 21:32
· 80 commits to main since this release
7aea28e

Changelog

Most of this release is about the data the manager decides to remove. A failed
update no longer deletes a secret the running release still reads,
backup --no-push no longer prunes the backup targets, and an operation queued
behind the deployment lock refuses a plan made for a release that has since
moved. Only the newest three pre-update backups are kept past retention, where
every one was, which filled the disk of a machine that updates often. A manifest that names an operation the manager
never runs, or gives a runtime-service step to anything but migrate, is
refused when it loads instead of doing nothing or failing at apply.
Notification targets are set with notify target add, and a migrate step is
told which operation is running it.

Upgrading moves the installation schema 11 → 12 on the first read and converts
nothing. Going back is not automatic, because a 0.4.x manager declines the
installation rather than dropping update.randomized_delay and
retention.pre_update_backups. Three more things change on upgrade:

  • The first backup or update after upgrading prunes the pre-update backups
    beyond the newest three, locally and on backup targets. To keep more, run
    morzer config set retention.pre_update_backups=<n> straight after
    upgrading, before the next scheduled backup or update.
  • A bundle that loaded under 0.4.0 may now be refused. operations may name
    only migrate, smoke_test, backup and restore, and only migrate may
    be a runtime-service step. Either mistake was a step that never ran or one
    that failed every time it was reached.
  • A migrate step or smoke test that branched on OPERATION_TYPE=apply now
    sees update or rollback on those operations, with PREVIOUS_VERSION set.

Added

  • A migration service is told what is running it. A runtime-service migrate step received none of the hook ABI's variables, so it could not tell an update from a re-apply or learn the version it was migrating to. It now gets the ones that mean the same inside a container: the product, installation and operation ids, OPERATION_TYPE, PHASE, RELEASE_VERSION, PREVIOUS_VERSION, LOG_LEVEL and DRY_RUN. Host paths and RESULT_FD are left out, so a service still reports its schema through database_schema_produces.
  • backup.before_update: a dev-mode machine can stop taking pre-update backups. The installation's skip_backup_before_update was honoured by update but no command could set it, so a sandbox following a channel every ten minutes took a full backup before every update. morzer config set backup.before_update=false turns it off on a dev-mode machine. A production machine refuses, because that backup is what a failed migration is recovered from; update --skip-backup --force still skips it for one update.
  • update.randomized_delay sets how late an update tick may run. A production update timer always waited up to 1800 seconds at random, whatever update.schedule said, and a dev-mode one never did. Set a duration in whole seconds, such as 10m, or 0 for none; unset keeps those defaults. morzer status shows the delay beside the schedule.

Changed

  • Only the newest pre-update backups are kept past retention. Every pre-update backup was exempt from pruning forever, so a machine that updates every few minutes kept a full backup per update until its disk filled. Now the newest three are exempt, and older ones are pruned like any other backup, locally and on backup targets. A successful update now applies retention too, after its pre-update backup, so a machine that only updates is pruned as well. The first backup or update after upgrading prunes the older ones already there, unless it is a backup run with --no-prune. Change the three with morzer config set retention.pre_update_backups=<n>; the newest is never pruned. Installation state moves to schema 12, so an older manager refuses it rather than dropping either setting.
  • morzer notify target add|remove|list: notification targets are set by a command. The notifications page said to configure them in installation.yaml, which is a report the manager rewrites, and nothing else wrote them. A target is checked when it is added, and nothing is sent to it: the URL must be https with no password in it, and every secret it names must be set and well formed. A URL kept in a secret is named by the target's --name wherever it is shown. status names the targets, and doctor warns about one whose secret has gone, which was dropped with only a log line.

Fixed

  • morzer exec passed a stopped service's failure off as the command's. The check that the service is running and the exec itself are two calls, so a container could stop between them. Compose then exited 1 with service "db" is not running, and exec exited 1 as if the command had failed. A failed command now checks the service again, and a service that is no longer running is refused with exit 7 and its state, as it is before the command runs. Whatever the command printed is still printed.
  • morzer exec refused a scaled service whose first instance was down. The check read only the first instance listed, so a stopped app-1 refused the command although app-2 was up and Compose would have run it there. A scaled service is now refused only when none of its instances is running.
  • A failed update could delete a secret the running release still reads. An update that failed before starting anything, on an image pull for example, left the old release's containers running against the new release's rendered secrets. Rendering removes any secret the release does not declare, so one only the old release declares was gone, and an old container that restarted could not read it. The update now renders the old release's secrets back as it rolls back. If that fails, the update stops at exit 12 instead of 11.
  • An operation that waited for the deployment lock ran a plan made for a release no longer installed. apply, update, rollback, backup and restore read the current release before taking the lock. With --wait, the operation they queued behind could move it, so an update queued behind another update to 1.3.0 journalled from 1.2.0 and told its hooks PREVIOUS_VERSION=1.2.0, and an apply queued behind a rollback re-converged the release just rolled off. Each now reads the release again once it holds the lock, and refuses with exit 2 if it changed, naming the release now installed. So does a change to the database schema the release recorded, and, for a rollback without --to, a change to the previous release. Run the command again to plan against what is there now.
  • A migrate step and the smoke test were always told the operation was apply. OPERATION_TYPE was apply and PREVIOUS_VERSION was absent on every run, so an update from 1.2.0 looked like a re-apply. They are now told update or rollback and the version being replaced. A first install is still apply, as the hook ABI reference now says.
  • backup --no-push pruned the backup targets. A local-only backup copied nothing to the targets but still applied retention there, removing their oldest backups to make room for one that never arrived. Retention on a target now runs only when this run's backup reached it, as an update's already did.
  • A backport release would have replaced the installer at the site root with its older copy. Every docs release published install.sh, and now schemas/, at the site root, so tagging 0.3.5 after 0.4.0 would have served 0.3.5's installer and schemas to everyone. Only a release that moves the documentation's latest alias publishes them now. The nightly check compares the published schemas with the newest release, as it already did install.sh.
  • The update timer fetched a private oci:// channel without credentials. systemd sets no HOME for the manager's units, and the registry client looked for the Docker configuration only under HOME, so it went anonymous and the registry refused it, while docker compose pull in the same run found root's login through the password database. The manager now finds the configuration the way the docker CLI does: DOCKER_CONFIG, then HOME, then the password database.
  • An operation under a name the manager never runs is refused. operations accepted any name, so a misspelled smoke-test: or an invented post_migrate: loaded cleanly and never ran, and the bundle's customer got no smoke test and no error. preflight, which the manifest reference listed as looked up, was never run either. A manifest may now declare only migrate, smoke_test, backup and restore, and a bundle declaring any other operation, preflight included, is now refused with the field named and the four listed. The published manifest schema closes the names the same way, so an editor underlines one before the manager sees it.
  • The schema URL in every scaffolded manifest returned 404. release new writes a yaml-language-server modeline naming https://morzecrew.github.io/morzer/schemas/selfhost-v1alpha1-manifest.json, which is also the schema's own $id, and nothing published the schemas there: the documentation site is versioned, and they lived only in the repository. Each docs release now publishes schemas/ at the site root beside install.sh, so an editor following the modeline gets the schema.
  • The publishing page told you to configure signing keys by editing installation.yaml. That file is a report the manager writes, and an edit to it changes nothing, so a machine set up from the page required no signature from your key. The page now shows init --signing-key … --require-signature and morzer release trust add. The updating, backups, parameters and release-command pages treated the same file as configuration and are corrected too, and the hook ABI page no longer lists preflight, pre-update and post-update as phases a hook runs in: they are reserved, and no release runs one.
  • A runtime-service smoke test, backup or restore is refused when the bundle loads. Only migrate can run a one-shot container. The other three handed the step to the hook runner, which a runtime-service step gives no command, so a runtime-service smoke test failed every apply that reached it with an internal error, a restore failed the same way, and a backup was refused only once one ran. The manifest now refuses a runtime-service under any operation but migrate, naming hook as what the others support.

Security

  • A refusal no longer sends a bundle's control characters to the terminal. A manifest, installation or secrets refusal names the field at fault, and a field under a map, such as an operation, a runtime or an extension, is named by its key as the bundle wrote it. A key carrying an escape sequence reached the terminal raw, so a release could clear the screen or rewrite what the operator read. A refusal holding a character that is not printable is now written escaped, \x1b rather than the character itself.

Installing this release

curl -fsSL https://morzecrew.github.io/morzer/install.sh | sh -s -- --version 0.5.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.5.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