fix(monitor): handle a PBS on the same host and complete the PBS views

- Open a PBS installed on this host on the address in use, without probing it
- Never carry or offer localhost addresses between Monitors
- Read the PBS of a PVE+PBS host in Backup Server, with its hostname and version
- Offer the PBS storages without a connection, with address and fingerprint
- Show the disks and pools of a PBS in its Datastores tab
- Hide guest and PVE storage settings on a PBS
- Show a clearer status line for a PBS
This commit is contained in:
MacRimi
2026-10-19 18:18:18 +02:00
parent 311952cdf5
commit cb585632c6
19 changed files with 249 additions and 23 deletions
@@ -62,6 +62,29 @@ class MonitorLinksTests(unittest.TestCase):
self.assertEqual(by_key["pbs:pbs.example.com"]["native_url"], "https://pbs.example.com:8443")
self.assertFalse(any("example.com" in url for url in probed))
def test_pbs_installed_on_this_host_opens_its_own_interface_and_is_never_probed(self):
links.STORAGE_CFG.write_text("pbs: PBS\n\tdatastore PBS\n\tserver localhost\n\n"
"pbs: Same\n\tdatastore x\n\tserver 10.0.0.55\n\n"
"pbs: Lab\n\tdatastore store1\n\tserver 10.0.0.49\n")
probed = []
with mock.patch.object(links, "_own_addresses", return_value={"10.0.0.55"}), \
mock.patch.object(links, "_probe", side_effect=lambda url: probed.append(url) or False), \
mock.patch.object(links, "_is_private", return_value=True):
result = links.list_links()
pbs_rows = [row for row in result["links"] if row["group"] == "pbs"]
self.assertEqual([row["key"] for row in pbs_rows], ["pbs:local", "pbs:10.0.0.49"])
local = pbs_rows[0]
self.assertEqual((local["name"], local["local"], local["url"], local["status"]), ("PBS", True, None, "local"))
self.assertIsNone(local["native_url"])
self.assertFalse(any("localhost" in url or "10.0.0.55" in url for url in probed))
self.assertFalse(pbs_rows[1]["local"])
def test_loopback_names_are_this_host(self):
with mock.patch.object(links, "_own_addresses", return_value=set()):
self.assertTrue(links._is_this_host("127.0.0.1"))
self.assertTrue(links._is_this_host("::1"))
self.assertFalse(links._is_this_host("10.0.0.49"))
def test_pbs_host_lists_only_manual_entries(self):
links.pbs_manager.get_platform.return_value = {"product": "pbs", "hostname": "pbs-lab"}
links.add_link({"name": "amd", "url": "https://10.0.0.55:8008", "product": "pve"})
+33
View File
@@ -166,6 +166,39 @@ class PBSManagerTests(unittest.TestCase):
self.assertEqual(result["datastores"][0]["used"], 30)
self.assertEqual(set(result["services"]), set(pbs.PBS_SERVICES))
def test_pbs_installed_next_to_pve_is_read_locally_with_its_own_version(self):
def run(command, **kwargs):
if command[0] == "dpkg-query":
return SimpleNamespace(stdout="4.2.8-1", returncode=0)
return SimpleNamespace(stdout="[]", returncode=0)
with mock.patch.object(pbs, "get_platform", return_value={"product": "pve", "version": "9.1.4", "hostname": "rimegra"}), \
mock.patch.object(pbs.shutil, "which", return_value="/usr/sbin/proxmox-backup-manager"), \
mock.patch.object(pbs.Path, "exists", return_value=True), \
mock.patch.object(pbs, "_local_services", return_value={key: "active" for key in pbs.PBS_SERVICES}), \
mock.patch.object(pbs.subprocess, "run", side_effect=run):
self.assertTrue(pbs.local_available())
result = pbs.get_status("local")
self.assertEqual((result["name"], result["version"]), ("rimegra", "4.2.8-1"))
with mock.patch.object(pbs, "get_platform", return_value={"product": "pve"}), \
mock.patch.object(pbs.shutil, "which", return_value=None):
self.assertFalse(pbs.local_available())
def test_storage_pbs_without_a_connection_is_offered_with_its_address_and_fingerprint(self):
import monitor_links
storage = self.root / "storage.cfg"
storage.write_text("pbs: Local\n\tserver localhost\n\tdatastore a\n\n"
"pbs: Lab\n\tserver 10.0.0.49\n\tdatastore b\n\tfingerprint AA:BB\n\n"
"pbs: Known\n\tserver pbs.test\n\tdatastore c\n\tport 8007\n")
with mock.patch.object(monitor_links, "STORAGE_CFG", storage), \
mock.patch.object(monitor_links, "_own_addresses", return_value=set()), \
mock.patch.object(pbs, "is_pbs_host", return_value=False), \
mock.patch.object(pbs, "local_available", return_value=False), \
mock.patch.object(pbs, "_remote_get", return_value=[]):
pbs.save_server(self.server)
response = self.client.get("/api/pbs/servers", headers=self.headers)
self.assertEqual(response.json["detected"],
[{"name": "Lab", "url": "https://10.0.0.49:8007", "fingerprint": "AA:BB"}])
def test_connection_api_requires_full_admin_and_does_not_return_secret(self):
self.assertEqual(self.client.get("/api/pbs/servers").status_code, 401)
with mock.patch.object(pbs, "_remote_get", return_value=[]):