- tools/backup_rondgang.py draait backup en terugzetten tegen een echte
Docker-daemon in de CI: postgres-sidecar vullen, backuppen, alles weggooien,
terugzetten, en controleren dat de database daarna nog kan schrijven. Alle
bestaande backuptests vervangen Docker door een nep, dus die keten was nooit
bewezen
- daardoor gevonden: het terugzetten gaf de appdata de verkeerde eigenaar. Het
archief bevat de echte uid (postgres draait als 70 en zegt dat nergens in de
metadata); die gaat nu voor op PUID en op onze eigen uid
- een mislukte --update rolt terug naar de commit van ervoor en start die
opnieuw, in plaats van een stilstaande server en een rijtje commando's
- met een registry-image (SU_IMAGE) wordt er gepulld in plaats van gebouwd
- nieuw --reconfigure: bind, poort, account of hoofdmap wijzigen zonder de
broncode aan te raken
- nieuw --uninstall --purge: ook het volume, de gegevensmap en het account,
per onderdeel gevraagd. Zonder --purge somt --uninstall nu op wat blijft
- --dir wordt op een volledig pad gecontroleerd, het tijdelijke bestand voor
het beheerdersaccount is niet meer voorspelbaar, en er gaat nog een
rondgang naar de docker-daemon in plaats van twee
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
Ik sprong met tientallen (0.7.90 → 0.8.00 → … → 0.9.00 → 0.10.00) en liep
daarmee de reeks uit: dit schema rolt over bij .90, dus na 0.9.90 hoort 1.0.00
te komen. "0.10.00" bestond niet, en schond ook het formaat v0.0.00 uit de
projectafspraken.
De vijftien uitgaven van deze sessie zijn hernummerd naar 0.7.81 t/m 0.7.95,
aaneengesloten. In één doorloop met een tabel, want 0.8.81 wordt 0.7.90 en
0.7.90 wordt 0.7.81 — achtereenvolgende vervangingen zouden elkaar overschrijven.
Meegenomen: verwijzingen in de documentatie, .env.example, install.sh en de
tests. Verkorte vormen als "vanaf v0.10" zijn vervangen door het volledige
nummer, want die waren niet automatisch te herleiden.
De commit-onderwerpen in de geschiedenis dragen nog de oude nummers; VERSION en
CHANGELOG zijn leidend.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
De CI-runner draait als root, en drie tests gingen daar onderuit omdat ze
stilzwijgend van een gewone gebruiker uitgingen:
- rechten intrekken met chmod 000 houdt root niet tegen, dus er werd niets
overgeslagen; de weigering komt nu uit het inpakken zelf
- `backups.os` ís de os-module, dus het onderscheppen van chown ving ook wat
tarfile als root zelf chownt; er wordt nu op het exacte doelpad getoetst
- het geval "draait al als niet-root" liep als root juist de hele afdaal-tak in
en zou daar echt een gebruiker aanmaken; de uid wordt nu nagebootst
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
- bij de installatie wordt gevraagd onder welk account Server Up draait: een
nieuw systeemaccount 'serverup', het account waarmee je werkt, een bestaand
account, of root zoals voorheen (--user NAAM slaat de vraag over)
- nieuw docker-entrypoint.sh: start als root, zet /data, stacks en backups
klaar, en zakt met setpriv af naar SU_UID:SU_GID met de capabilities die
nodig blijven (chown, dac_override, fowner - alle drie al in Docker's
standaardset)
- appdata blijft daarbij bewust ongemoeid; die mappen zijn van de apps zelf
- de gid van de docker-socket wordt uit de socket zelf gelezen, zodat het
account niet in de docker-groep hoeft (dat zou root op de host geven)
- installatieformulier vult PUID/PGID met de ids waaronder Server Up draait in
plaats van de 1000 die 44 sjablonen blind noemen
- een onleesbaar bestand laat de rest van de backup niet meer sneuvelen; wat
ontbreekt komt in het log en in de metadata (skipped)
- terugzetten herstelt het eigenaarschap van appdata, dat tarfile met
filter="data" laat vallen
- CI controleert in een echte container dat setpriv bestaat, dat er wordt
afgezakt, dat de socket-gid meekomt, dat /data schrijfbaar is en dat SU_UID=0
root laat blijven
- SU_UID=0 in .env is de ontsnappingsklep naar het oude gedrag
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
- Een backup bevatte alleen de stackmap: compose, .env en metadata.
LIBRARY_DIR en de appdata-map staan naast elkaar, geen genestelde mappen, dus
je maakte een backup, kreeg een groen vinkje en hield bij terugzetten een lege
app over. Een archief heeft nu drie takken: de stackmap, de appdata van die
stack, en een dump per database
- De dump is geen dubbelop: een tar van een draaiende PostgreSQL is een
momentopname van bestanden die tijdens het inpakken veranderden. Bij
terugzetten komt de dump erin nadat de container draait, met een wachtlus.
Stond de container tijdens de backup uit, dan is dat een waarschuwing in het
log en geen stille overslag
- Nieuwe instelling BACKUP_APPDATA (standaard aan), uit te zetten bij een
mediabibliotheek waar dit in de honderden gigabytes loopt
- apps/newt en apps/pangolin. Server Up had al een Pangolin-integratie met een
publiceerknop per stack, maar je moest Pangolin zelf elders vandaan halen
- Nieuwe stap in de setup-wizard na git: koppelen aan een bestaande Pangolin,
hier installeren, of overslaan. De wizard hing zijn afhandeling aan
stapnummers, dus met een stap ertussen ging de git-stap mis; dat gaat nu op de
naam van de stap
- depends_on waarschuwt nu ook op de stackpagina. Haal je Mosquitto later weg,
dan viel Zigbee2MQTT stil zonder dat iets zei waarom
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
Backups (core/backups.py, core/scheduler.py):
- Terugzetten met een klik: stack stoppen, huidige map opzij, uitpakken,
starten. Mislukt het uitpakken, dan wordt de oude situatie teruggeplaatst.
- Bewaarbeleid: aantal per stack en/of maximale leeftijd; de nieuwste backup
van een stack blijft altijd staan.
- Geplande backups (dagelijks/wekelijks) via een eigen planner in de app, geen
cron. Een gemiste ronde loopt bij de eerstvolgende gelegenheid alsnog.
- Automatisch een backup voor het bijwerken of verwijderen van een stack.
Mislukt die, dan gaat de actie door - anders kun je een kapotte stack niet
meer opruimen.
- Uitpakken met tarfile + filter="data": absolute paden en ..-ingangen worden
geweigerd. Met een kaal `tar xzf` kon een geprepareerd archief buiten de
stackmap schrijven.
- Twee bugs in de oude implementatie: de returncode van tar werd genegeerd
(mislukte backup gold als succes) en backups binnen dezelfde seconde
overschreven elkaar.
Updates per app (core/stackupdates.py, core/registry.py):
- Badge op de stackkaart als er een nieuwer image is; bijwerken doet de
bestaande update-knop.
- Vergelijking via de Registry API v2 (Docker-Content-Digest) in plaats van
`docker manifest inspect`: dat laatste geeft per platform een aparte digest
terwijl RepoDigests de manifest-list-digest bevat, wat bij elk multi-arch
image permanent "update beschikbaar" zou opleveren.
- Drie statussen: update / current / unknown. Lokaal gebouwd, nog niet gepulld
of registry onbereikbaar geeft unknown en dus geen badge.
- Dagelijkse achtergrondcheck, resultaten 6 uur gecached.
Verder:
- docs/backups.md, met nadruk op wat er niet in een backup zit: de
Docker-volumes met de eigenlijke appdata.
- Backup-instellingen onder Instellingen; backup-geschiedenis per stack.
- 197 tests groen (40 nieuwe).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7oLCRYzY5ixJ5Sv8Y8EFb