The backup file (#5672 "Backup file: pg_dump of config + audit + alert history, the secret key and a manifest"): steward-<UTC>.tar holding a pg_dump --format=custom with metrics', check results' and Docker/Traefik/ UniFi rows left out, the secret key, and a manifest. Every table is named KEPT or EXCLUDED in steward/backup/contents.py, and a guard test fails on a new one. The image gains postgresql-client-17 (approved, System 180). The restore (#5674 "Restore: `steward restore` and a CI test that a dump brings Steward back"): pg_restore in its three sections. Between data and constraints, a kept row pointing at a left-out row gets what its foreign key's ON DELETE says (alert_events.ansible_run_id is cleared). It refuses a non-empty database unless --wipe, and puts the backup's key in /data/secret.key. Migrations run on Steward's next start. `steward` stays the server command: it is now a click group that serves when given no subcommand. The publish smoke step backs up the booted image's database, restores it into a second one, checks a marker setting came back and plugin_metrics is empty, and starts Steward on it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
17 lines
610 B
Python
17 lines
610 B
Python
"""Steward's own backups as a scheduled job: make the file, send it, record
|
|
how it went (milestone 507)."""
|
|
from __future__ import annotations
|
|
|
|
from sqlalchemy import text
|
|
from sqlalchemy.ext.asyncio import create_async_engine
|
|
|
|
|
|
async def migration_heads(database_url: str) -> list[str]:
|
|
"""The migration revisions the database is at, for the manifest."""
|
|
engine = create_async_engine(database_url)
|
|
try:
|
|
async with engine.connect() as conn:
|
|
return list((await conn.execute(text("SELECT version_num FROM alembic_version"))).scalars())
|
|
finally:
|
|
await engine.dispose()
|