(feature) Add host config editing view
Add a staff-only Django form for editing operational host settings while keeping host identity stable. Support address, enablement, SSH/source overrides, include/exclude lists, rsync extra args, and retention settings using the same SQL-backed HostConfig model consumed by backup and scheduler flows. Parse newline-separated list fields into JSON lists, preserve nullable excludes_replace semantics, and cover rendering plus update behavior with view tests.
This commit is contained in:
@@ -68,6 +68,7 @@ class ViewTests(TestCase):
|
||||
self.assertContains(response, "20260519-021500Z__ABCDEFGH")
|
||||
self.assertContains(response, "Discover snapshots")
|
||||
self.assertContains(response, "Edit schedule")
|
||||
self.assertContains(response, "Edit config")
|
||||
|
||||
def test_host_detail_returns_404_for_unknown_host(self) -> None:
|
||||
self.client.force_login(self.staff_user)
|
||||
@@ -231,6 +232,92 @@ class ViewTests(TestCase):
|
||||
self.assertContains(response, "cron expression must have exactly 5 fields")
|
||||
self.assertFalse(ScheduleConfig.objects.filter(host=host).exists())
|
||||
|
||||
def test_host_config_form_renders_existing_values(self) -> None:
|
||||
self.client.force_login(self.staff_user)
|
||||
host = HostConfig.objects.create(
|
||||
host="web-01",
|
||||
address="web-01.example.test",
|
||||
includes=["/srv"],
|
||||
excludes_add=["*.tmp"],
|
||||
rsync_extra_args=["--numeric-ids"],
|
||||
)
|
||||
|
||||
response = self.client.get(reverse("edit_host_config", args=[host.host]))
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, "Config: web-01")
|
||||
self.assertContains(response, "web-01.example.test")
|
||||
self.assertContains(response, "/srv")
|
||||
self.assertContains(response, "*.tmp")
|
||||
self.assertContains(response, "--numeric-ids")
|
||||
|
||||
def test_host_config_form_updates_host_config(self) -> None:
|
||||
self.client.force_login(self.staff_user)
|
||||
host = HostConfig.objects.create(host="web-01", address="old.example.test")
|
||||
|
||||
response = self.client.post(
|
||||
reverse("edit_host_config", args=[host.host]),
|
||||
{
|
||||
"address": "new.example.test",
|
||||
"enabled": "on",
|
||||
"ssh_user": "backup",
|
||||
"ssh_port": "2222",
|
||||
"source_root": "/srv",
|
||||
"includes": "/srv/www\n/srv/db",
|
||||
"excludes_add": "*.tmp\ncache/",
|
||||
"excludes_replace": "",
|
||||
"rsync_extra_args": "--numeric-ids\n--delete",
|
||||
"retention_daily": "7",
|
||||
"retention_weekly": "4",
|
||||
"retention_monthly": "2",
|
||||
"retention_yearly": "1",
|
||||
},
|
||||
follow=True,
|
||||
)
|
||||
|
||||
self.assertRedirects(response, reverse("host_detail", args=[host.host]))
|
||||
self.assertContains(response, "Host config saved for web-01.")
|
||||
host.refresh_from_db()
|
||||
self.assertEqual(host.address, "new.example.test")
|
||||
self.assertEqual(host.ssh_user, "backup")
|
||||
self.assertEqual(host.ssh_port, 2222)
|
||||
self.assertEqual(host.source_root, "/srv")
|
||||
self.assertEqual(host.includes, ["/srv/www", "/srv/db"])
|
||||
self.assertEqual(host.excludes_add, ["*.tmp", "cache/"])
|
||||
self.assertIsNone(host.excludes_replace)
|
||||
self.assertEqual(host.rsync_extra_args, ["--numeric-ids", "--delete"])
|
||||
self.assertEqual(host.retention_daily, 7)
|
||||
self.assertEqual(host.retention_yearly, 1)
|
||||
|
||||
def test_host_config_form_can_replace_global_excludes(self) -> None:
|
||||
self.client.force_login(self.staff_user)
|
||||
host = HostConfig.objects.create(host="web-01", address="web-01.example.test")
|
||||
|
||||
response = self.client.post(
|
||||
reverse("edit_host_config", args=[host.host]),
|
||||
{
|
||||
"address": host.address,
|
||||
"ssh_user": "",
|
||||
"ssh_port": "",
|
||||
"source_root": "",
|
||||
"includes": "",
|
||||
"excludes_add": "",
|
||||
"excludes_replace": "*.cache\nnode_modules/",
|
||||
"rsync_extra_args": "",
|
||||
"retention_daily": "14",
|
||||
"retention_weekly": "8",
|
||||
"retention_monthly": "12",
|
||||
"retention_yearly": "0",
|
||||
},
|
||||
follow=True,
|
||||
)
|
||||
|
||||
self.assertRedirects(response, reverse("host_detail", args=[host.host]))
|
||||
host.refresh_from_db()
|
||||
self.assertFalse(host.enabled)
|
||||
self.assertEqual(host.excludes_add, [])
|
||||
self.assertEqual(host.excludes_replace, ["*.cache", "node_modules/"])
|
||||
|
||||
def _snapshot(self, host: HostConfig, dirname: str) -> SnapshotRecord:
|
||||
started_at = datetime.strptime(dirname.split("__", 1)[0], "%Y%m%d-%H%M%SZ").replace(tzinfo=timezone.utc)
|
||||
return SnapshotRecord.objects.create(
|
||||
|
||||
Reference in New Issue
Block a user