(feature) Add global and effective host config checks
Introduce reusable configuration checks for global settings and effective host runtime configuration. The checks now surface risky backup settings such as missing recursive rsync args, missing critical root excludes, invalid SSH settings, missing credentials, and retention gaps. Show these checks on the global config form, host edit form, and host detail page so operators can validate the compounded host/global config before starting real backup runs.
This commit is contained in:
@@ -347,10 +347,21 @@ class ViewTests(TestCase):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, "Backup root:")
|
||||
self.assertContains(response, "/backups")
|
||||
self.assertNotContains(response, "/mnt/pobsync/backups")
|
||||
self.assertContains(response, "Config Check")
|
||||
self.assertContains(response, "Runtime backup root")
|
||||
self.assertNotContains(response, "/opt/pobsync/backups")
|
||||
self.assertNotContains(response, "Pobsync home")
|
||||
|
||||
def test_global_config_form_renders_config_check_for_non_recursive_rsync(self) -> None:
|
||||
self.client.force_login(self.staff_user)
|
||||
GlobalConfig.objects.create(name="default", backup_root="/backups", rsync_args=["--numeric-ids"])
|
||||
|
||||
response = self.client.get(reverse("edit_global_config"))
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, "Global rsync recursion")
|
||||
self.assertContains(response, "Rsync args do not include archive or recursive transfer.")
|
||||
|
||||
def test_global_config_form_resets_backup_root_to_static_container_path(self) -> None:
|
||||
self.client.force_login(self.staff_user)
|
||||
GlobalConfig.objects.create(
|
||||
@@ -532,9 +543,44 @@ class ViewTests(TestCase):
|
||||
response = self.client.get(reverse("host_detail", args=[host.host]))
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, "Host rsync recursion")
|
||||
self.assertContains(response, "Host effective rsync recursion")
|
||||
self.assertContains(response, "Rsync args do not include archive or recursive transfer.")
|
||||
|
||||
def test_host_detail_warns_when_replace_excludes_drops_root_defaults(self) -> None:
|
||||
self.client.force_login(self.staff_user)
|
||||
GlobalConfig.objects.create(
|
||||
name="default",
|
||||
backup_root="/backups",
|
||||
rsync_args=["--archive"],
|
||||
excludes_default=["/proc/***", "/sys/***", "/dev/***", "/run/***", "/tmp/***"],
|
||||
)
|
||||
host = HostConfig.objects.create(
|
||||
host="web-01",
|
||||
address="web-01.example.test",
|
||||
excludes_replace=[],
|
||||
)
|
||||
|
||||
response = self.client.get(reverse("host_detail", args=[host.host]))
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, "Effective root excludes")
|
||||
self.assertContains(response, "excludes_replace is active")
|
||||
|
||||
def test_host_detail_warns_that_includes_are_raw_rsync_rules(self) -> None:
|
||||
self.client.force_login(self.staff_user)
|
||||
GlobalConfig.objects.create(name="default", backup_root="/backups", rsync_args=["--archive"])
|
||||
host = HostConfig.objects.create(
|
||||
host="web-01",
|
||||
address="web-01.example.test",
|
||||
includes=["/srv/www"],
|
||||
)
|
||||
|
||||
response = self.client.get(reverse("host_detail", args=[host.host]))
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, "Host includes")
|
||||
self.assertContains(response, "Includes are passed to rsync as raw --include rules.")
|
||||
|
||||
def test_scan_host_known_key_action_updates_selected_credential(self) -> None:
|
||||
self.client.force_login(self.staff_user)
|
||||
credential = SshCredential.objects.create(name="default-key", key_path="/var/lib/pobsync/state/ssh-credentials/1/identity")
|
||||
@@ -997,6 +1043,18 @@ class ViewTests(TestCase):
|
||||
self.assertContains(response, "*.tmp")
|
||||
self.assertContains(response, "--numeric-ids")
|
||||
|
||||
def test_host_config_form_renders_effective_config_check(self) -> None:
|
||||
self.client.force_login(self.staff_user)
|
||||
GlobalConfig.objects.create(name="default", backup_root="/backups", rsync_args=["--numeric-ids"])
|
||||
host = HostConfig.objects.create(host="web-01", address="web-01.example.test")
|
||||
|
||||
response = self.client.get(reverse("edit_host_config", args=[host.host]))
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, "Effective Config Check")
|
||||
self.assertContains(response, "Host effective rsync recursion")
|
||||
self.assertContains(response, "Rsync args do not include archive or recursive transfer.")
|
||||
|
||||
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")
|
||||
|
||||
Reference in New Issue
Block a user