refactor: stop using legacy JSON for runtime config

Build runtime pobsync configuration exclusively from structured SQL
fields, leaving legacy JSON only for import and audit context. Add
SQL-first management commands for global and host configuration and
cover them with tests.
This commit is contained in:
2026-05-19 05:08:37 +02:00
parent a0eb5dcc8f
commit 6d9ddc4457
6 changed files with 231 additions and 45 deletions

View File

@@ -30,6 +30,7 @@ class ConfigRepositoryTests(TestCase):
"backup_root": "/ignored",
"pobsync_home": "/ignored",
"ssh": {"user": "ignored", "port": 22, "options": []},
"unknown": "must-not-leak",
"retention_defaults": {"daily": 99, "weekly": 99, "monthly": 99, "yearly": 99},
},
)
@@ -48,6 +49,7 @@ class ConfigRepositoryTests(TestCase):
"address": "ignored",
"retention": {"daily": 99, "weekly": 99, "monthly": 99, "yearly": 99},
"excludes_add": ["/ignored/***"],
"unknown": "must-not-leak",
},
)
@@ -65,3 +67,5 @@ class ConfigRepositoryTests(TestCase):
self.assertEqual(host_cfg["address"], "web-01.example.test")
self.assertEqual(host_cfg["retention"]["daily"], 7)
self.assertEqual(host_cfg["excludes_add"], ["/tmp/***"])
self.assertNotIn("unknown", global_cfg)
self.assertNotIn("unknown", host_cfg)

View File

@@ -0,0 +1,56 @@
from __future__ import annotations
from io import StringIO
from django.core.management import call_command
from django.test import TestCase
from pobsync_backend.config_source import DjangoConfigSource
from pobsync_backend.models import GlobalConfig, HostConfig
class ConfigureCommandsTests(TestCase):
def test_configure_global_creates_structured_config(self) -> None:
out = StringIO()
call_command(
"configure_pobsync_global",
backup_root="/backups",
pobsync_home="/opt/pobsync",
retention="daily=3,weekly=2,monthly=1,yearly=0",
stdout=out,
)
config = GlobalConfig.objects.get(name="default")
self.assertEqual(config.backup_root, "/backups")
self.assertEqual(config.retention_daily, 3)
self.assertIn("Created GlobalConfig", out.getvalue())
def test_configure_host_uses_global_retention_defaults(self) -> None:
GlobalConfig.objects.create(
name="default",
backup_root="/backups",
retention_daily=5,
retention_weekly=4,
retention_monthly=3,
retention_yearly=2,
)
out = StringIO()
call_command(
"configure_pobsync_host",
"web-01",
address="web-01.example.test",
exclude_add=["/tmp/***"],
rsync_extra_arg=["--delete"],
stdout=out,
)
host = HostConfig.objects.get(host="web-01")
self.assertEqual(host.retention_daily, 5)
self.assertEqual(host.excludes_add, ["/tmp/***"])
self.assertEqual(host.rsync_extra_args, ["--delete"])
effective = DjangoConfigSource().effective_config_for_host("web-01")
self.assertEqual(effective["retention"]["yearly"], 2)
self.assertEqual(effective["excludes_effective"], ["/tmp/***"])