github preston-peterson/aerodrome v3.4.147

3 hours ago

Fixed

  • A failed update now puts the previous version back on its own. An update is now unpacked to the side and the new version is test-loaded before any of Aerodrome's own files change. If it can't load — a syntax error, a missing Python package — the update stops with the reason, Aerodrome's own files are left as they were, and the release stays staged so you can fix the cause and try again. A release that loads is then switched in all at once. If it then fails to start twice, Aerodrome puts the previous version — and the config.yaml it had — back on its own, and records what it put back and why. The Updates page tells you what was put back and why.
  • An update is refused, not half-applied, when Aerodrome can't restart itself. Installs without the restart permission that install.sh sets up (or started outside systemd) used to end up with new files under the old running code. Now the update is refused with "Aerodrome can't restart itself on this install" and Aerodrome's files don't change. Put the restart permission back with the command in INSTALL's "Applying sudoers updates" (or re-run install.sh), or update by hand.
  • Upgrading from a much older version no longer gets stuck restarting. The one-time rebuild of Aerodrome's data summaries now finishes before the web UI starts, so the first start after a big upgrade can take a few minutes longer — but it no longer collides with the database upgrade and restarts over and over. If that rebuild can't finish (for example, the disk is full, or the database can't be read for a moment), Aerodrome stops before upgrading the database and says why in the log, instead of upgrading it with incomplete numbers; it retries on the next start.
  • Aerodrome starts after a power cut even if its old process ID was reused. A leftover .tracker.pid naming a process that isn't Aerodrome could make it refuse to start ("Already running") until the file was deleted by hand, and main.py stop could signal the wrong process. Aerodrome now checks that the process really is Aerodrome on this install. main.py status and stop run from a different account than the service now say so instead of failing.
  • One maintenance task at a time. Starting an update, a restore, a server-side backup, a config import, the pre-restore cleanup, a backup delete or the switch to real data while another one is running now tells you what's running and since when, instead of letting the two collide. Two server-side backups can no longer run at once.
  • The Updates page stays responsive while an update is uploaded or downloaded. Uploading a release, applying one from GitHub and importing a config no longer pause every other page while they work.

Operational notes

  • This release is installed by your current version's updater. The new protection covers updates from the next release on.
  • Applying an update takes a few seconds longer.
  • If a new release changes its Python requirements, its packages are installed into Aerodrome's environment before the test-load, and they stay installed even if the update is then refused or rolled back. Releases only raise requirements to versions the release before them also works with; if the version you're running no longer loads with the new packages, the update says so in its result and the log.
  • Re-installing the same version or going back to an older one now needs an explicit request through the API (allow_reinstall=true / allow_downgrade=true on the apply call). Going back to a release older than this one makes the switch final at once — that release can't roll back — and keeps the version you left in .backups/<timestamp>/.
  • If you restart Aerodrome twice while the first start after a big upgrade is still running, the update counts as failed and is rolled back — apply it again and let it finish. A restart you ask for from the new version's own pages after it has come up (a setting that needs a restart, a config import, a restore, switching from demo to real data) confirms the update first and never counts.
  • After an update, the previous version waits in .update-old-<timestamp>/ for about 30 seconds after the new one answers, then moves to .backups/<timestamp>/ as before. That folder is what a rollback puts back: if it's deleted before then, Aerodrome keeps the new version instead of rolling back. A rolled-back release is kept in .update-failed-<timestamp>/ (the newest two).
  • A config.yaml that is a symlink to a file kept elsewhere stays a symlink when an update is rolled back; the file it points to gets its previous content back.

Behind the scenes

  • New updater.py (standard library only, imports no other Aerodrome module) holds the staged apply and the boot guard at the very top of main.py. Files are switched with a hard link (or, where hard links aren't allowed, a copy that only ever exists complete) plus an atomic rename, so main.py and updater.py are never missing; every step of the switch, the rollback and the confirmation is safe to interrupt and repeat, including on a completely full disk (where the disk also can't hard-link, a rolled-back release's copy in .update-failed-<timestamp>/ may then be incomplete; the install itself is always put back whole). Tests kill the process at every file operation of each and start the install's own main.py afterwards.
  • The new version confirms itself: once /api/version answers with the new version, it waits 30 seconds and makes the update permanent. A version that answers wrongly for 5 minutes exits so the guard can roll it back.
  • Update zips are checked for their unpacked size (200 MB), free space and compression method before anything is unpacked.
  • The release packaging now extracts the zip and test-imports it, so a module that Aerodrome loads at startup but isn't in git can't ship.
  • The rollup backfills take the database write lock up front and wait up to 60 s for it, and so do the schema migrations.
  • New GET /api/maintenance/status and POST /api/maintenance/ack; GET /api/updates/local/check adds a read-only preflight that reports folders an update couldn't replace, with the command that fixes them. See API.md.

Don't miss a new aerodrome release

NewReleases is sending notifications on new releases.