Fixed
- Saving settings is all-or-nothing. Saving Settings, adding or removing a watchlist entry, importing a config and restoring a config backup now either save
config.yamlcompletely or change nothing and tell you why — for example, that the disk is full. Before, a save on a full disk could report success and leaveconfig.yamlcut short, so Aerodrome would fail to start or lose settings at its next restart. Two saves at the same moment — from two browser tabs, say — can no longer leaveconfig.yamlhalf-written or mixed. Aconfig.yamlthat Aerodrome can't write — one you made read-only, or one that belongs to another account — is no longer reported as saved when it wasn't: the save fails and says why. A save that fails as a whole now shows its reason instead of "1 validation error(s)". - Aerodrome starts even if
config.yamlcan't be read. Ifconfig.yamlis empty, cut short or has a YAML mistake when Aerodrome starts — typically a hand edit with a typo — Aerodrome no longer stops and restarts over and over with the web page gone. It starts on the last settings that worked, keeps your file as.backups/config.yaml.broken.<date>so nothing is lost, and logs which copy it used and its web port. Settings shows a notice saying what happened, until you dismiss it. - A listen port or address that can't be used no longer takes the web page away. If the web server's port or address in
config.yamlcan't be listened on — for example, a port another program has taken since you chose it — and the last settings that worked use one that can, Aerodrome starts on those instead and keeps your file in.backups/, as above. It never falls back to settings that listen more widely than yours (all addresses instead of the one you set): an address you narrowed on purpose that isn't up yet at boot is waited for, not replaced. - Settings refuses settings that can't work on this machine — a listen address that isn't one of its addresses, a port another program already uses or that Aerodrome isn't allowed to use, and a database location whose folder doesn't exist — instead of saving them and failing at the next restart. Importing or restoring a config checks the same settings.
- Adding or removing a watchlist entry keeps the comments in
config.yaml. - Backups and uploads take care of their disk space. An abandoned or dropped backup download no longer leaves a database-sized file behind, and leftovers from earlier versions and from interrupted runs are cleaned up when Aerodrome starts. Your backup zips and update snapshots are never touched. A backup that wouldn't fit on the disk is refused instead of filling it, and a server-side backup only appears in the list once it is complete. Oversized uploads, a second large upload while one is still being received, an upload while a restore or update runs, and uploads that wouldn't fit on the disk are refused straight away, with a message saying why, instead of after the whole file was sent. If the disk fills up while a restore upload is being received, it says so. An upload that stops arriving — say, the laptop sending it went to sleep — is cancelled after two minutes instead of blocking every other upload until Aerodrome restarts. The backup download says what's running instead of starting while another maintenance task runs.
- The page stays responsive while you switch from demo to real data. The check that the new receiver answers no longer pauses every other page while it waits.
Operational notes
- A hand edit to
config.yamlwith a YAML mistake no longer stops Aerodrome: the previous settings stay in use and your edit is kept in.backups/config.yaml.broken.<date>. Fix it there, copy it back overconfig.yamland restart..pre-restorecopies ofconfig.yamlare never used for this. - A restore upload and an update upload are now received into
.backups/.tmpon the install's own disk instead of the system temp folder (which is memory on some systems). A restore upload needs about three times its size free there, plus the database's size; building a backup needs about twice the database's size free. A restore upload must be a single backup file. - Backup zips, uploads being received and
config.yamlare now created readable only by the account Aerodrome runs as, in a.backups/folder only that account can open. Copy backups off the machine as that account (or withsudo). - The first time this release runs, it also makes an existing
.backups/folder, the backup zips in it,config.yamland the copies of it kept next to it private where they are readable by other local accounts, and logs each change. After an update this happens once the update is confirmed — about 30 seconds after the new version first answers — so an update that is rolled back changes none of them. It does this once: a mode you open up later on purpose is kept. Files that belong to another account, and the database files, are left as they are. - A
config.yamlthat is a link into a folder Aerodrome can't write, or that belongs to another account Aerodrome may write as, is still saved — in place, keeping its owner. main.py statusandmain.py stoponly readconfig.yaml; they never change it.
Behind the scenes
- New
config_io.pyis the one wayconfig.yamlis written: render, check it loads the way startup reads it, write a temp file beside it, fsync, rename, fsync the folder — all under one lock, with the running config swapped only after the file is saved. A Settings save keeps the file's comments only when that reads back exactly as saved (an unquoted22:00would read back as a number), and the switch to real data and the demo-feeder port recovery stage the new file before anything else changes. A test forbids any other way of writing, copying or moving onto it. - The last config that started is kept as
.backups/config.yaml.last-good— written once a start can listen on its address, and, after an update, once the update is confirmed (the config that release started with, not one saved while it was being confirmed); never by a save. Startup recovery falls back to it, then to the newest automaticconfig.yaml.bak.<date>that loads and whose database still exists, and never replacesconfig.yamlwithout first keeping the unreadable copy and recording what it did; a kill at any step is repaired by the next start. It never runs while another Aerodrome owns the install. - Hardened request-size limits: every request body is capped by its route, whatever its content type, the two large uploads are checked (one at a time, free space, maintenance running) before their first byte is read, and an upload's form is limited to what it needs.
- Hardened the upload checks: a request the same-origin rules refuse is refused before anything else is looked at.
- Hardened the backup download: it is refused when another website's page asks for it, it is one maintenance task at a time, and its file is gone from disk before the download starts.
- New
GET /api/maintenance/statusfieldconfigandPOST /api/maintenance/ack {"kind": "config"}. See API.md.