fix(monitor): keep the LVM filter when the scan names its devices

This commit is contained in:
MacRimi
2026-10-30 17:32:25 +01:00
parent cf7b8363da
commit bd42df3ead
4 changed files with 105 additions and 3 deletions
+28 -2
View File
@@ -35,12 +35,38 @@ class LvmScopeTests(unittest.TestCase):
self.modules.start()
self.addCleanup(self.modules.stop)
lvmconfig = types.SimpleNamespace(returncode=0, stdout='global_filter=["r|/dev/zd.*|","r|/dev/rbd.*|"]\nfilter="a|.*|"\n')
def args(self, inventory=INVENTORY, code=0):
with patch.object(scope.subprocess, "run", return_value=types.SimpleNamespace(returncode=code, stdout=inventory)) as run:
def run(command, **_):
if command[0] == "lvmconfig":
return self.lvmconfig
return types.SimpleNamespace(returncode=code, stdout=inventory)
with patch.object(scope.subprocess, "run", side_effect=run) as mocked:
args = scope.lvm_device_args(self.standby)
self.assertEqual(run.call_args.args[0], ["lsblk", "-J", "-l", "-o", "KNAME,TYPE,PKNAME,FSTYPE"])
self.assertEqual(mocked.call_args_list[0].args[0], ["lsblk", "-J", "-l", "-o", "KNAME,TYPE,PKNAME,FSTYPE"])
return args
def test_volumes_lvm_filters_reject_are_not_named(self):
# A guest's volume group on a zvol is hidden by the Proxmox
# global_filter, which an explicit --devices list would bypass.
inventory = lsblk(("nvme0n1", "disk", None, None), ("nvme0n1p1", "part", "nvme0n1", "LVM2_member"),
("sda", "disk", None, None), ("sda1", "part", "sda", "LVM2_member"),
("zd48", "disk", None, None), ("zd48p3", "part", "zd48", "LVM2_member"),
("rbd0", "disk", None, None), ("rbd0p1", "part", "rbd0", "LVM2_member"))
self.assertEqual(self.args(inventory), ["--devices", "/dev/nvme0n1p1"])
self.excluded = {"sda", "nvme0n1"}
self.assertIsNone(self.args(inventory))
def test_an_unreadable_lvm_filter_skips_the_restricted_scan(self):
for output in (types.SimpleNamespace(returncode=5, stdout=""),
types.SimpleNamespace(returncode=0, stdout='global_filter=["x|/dev/zd.*|"]\n'),
types.SimpleNamespace(returncode=0, stdout='filter=["r|[|"]\n')):
self.lvmconfig = output
self.assertIsNone(self.args())
self.excluded = set()
self.assertEqual(self.args(), [])
def test_excluded_disks_and_their_partitions_are_not_in_the_scan(self):
self.assertEqual(self.args(), ["--devices", "/dev/nvme0n1p1,/dev/sdb1"])
self.assertNotIn((("sda",), {}), self.standby.call_args_list)
+36
View File
@@ -0,0 +1,36 @@
"""VM disk usage from the QEMU guest agent counts each filesystem once."""
import ast
from pathlib import Path
import unittest
SCRIPTS = Path(__file__).resolve().parents[1] / "AppImage/scripts"
def compute():
tree = ast.parse((SCRIPTS / "flask_server.py").read_text())
nodes = [node for node in tree.body
if (isinstance(node, ast.FunctionDef) and node.name == "_compute_vm_disk_from_fsinfo")
or (isinstance(node, ast.Assign) and any(getattr(t, "id", None) == "_VM_FS_SKIP_TYPES" for t in node.targets))]
namespace = {}
exec(compile(ast.Module(body=nodes, type_ignores=[]), "flask_server.py", "exec"), namespace)
return namespace["_compute_vm_disk_from_fsinfo"]
def fs(mountpoint, name, total, used, **disk):
return {"mountpoint": mountpoint, "name": name, "type": "ext4", "total-bytes": total,
"used-bytes": used, "disk": [{"bus": 0, "target": 0, "unit": 0, **disk}]}
class VmDiskFromFsinfo(unittest.TestCase):
def test_partitions_of_one_disk_without_dev_are_all_counted(self):
# Alpine's agent reports no `dev`: /boot and / share the disk fields.
result = compute()([fs("/boot", "sda1", 264371200, 29093888), fs("/", "sda3", 27736297472, 6119866368)])
self.assertEqual(result, (29093888 + 6119866368, 264371200 + 27736297472))
def test_bind_mounts_of_one_filesystem_are_counted_once(self):
mounts = [fs(path, "sda8", 1000, 400, dev="/dev/sda8") for path in ("/mnt/data", "/etc/hosts", "/var/lib/docker")]
self.assertEqual(compute()(mounts), (400, 1000))
if __name__ == "__main__":
unittest.main()