search for orphan disks
This commit is contained in:
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
action="${1:-}"
|
action="${1:-}"
|
||||||
FOLDER='/opt/idssys/ta-proxmenu'
|
FOLDER='/opt/idssys/ta-proxmenu'
|
||||||
VERS='2026.9.22-1'
|
VERS='2026.9.22-2'
|
||||||
|
|
||||||
noupdate=' '
|
noupdate=' '
|
||||||
|
|
||||||
|
|||||||
+15
-1
@@ -30,6 +30,8 @@ def enabled(value):
|
|||||||
def references(root, nodes, guests):
|
def references(root, nodes, guests):
|
||||||
"""Read pmxcfs on this host, including offline guests and all config sections."""
|
"""Read pmxcfs on this host, including offline guests and all config sections."""
|
||||||
refs, errors, seen, contents = {}, [], set(), {}
|
refs, errors, seen, contents = {}, [], set(), {}
|
||||||
|
guest_names = {(guest['type'], str(guest['vmid'])): guest.get('name')
|
||||||
|
for guest in guests}
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
for kind, directory in [('qemu', 'qemu-server'), ('lxc', 'lxc')]:
|
for kind, directory in [('qemu', 'qemu-server'), ('lxc', 'lxc')]:
|
||||||
folder = root / node['node'] / directory
|
folder = root / node['node'] / directory
|
||||||
@@ -48,6 +50,18 @@ def references(root, nodes, guests):
|
|||||||
continue
|
continue
|
||||||
contents[str(path)] = content
|
contents[str(path)] = content
|
||||||
seen.add((node['node'], kind, path.stem))
|
seen.add((node['node'], kind, path.stem))
|
||||||
|
name = guest_names.get((kind, path.stem))
|
||||||
|
name_key = 'name' if kind == 'qemu' else 'hostname'
|
||||||
|
for line in content.splitlines():
|
||||||
|
line = line.strip()
|
||||||
|
if line.startswith('['):
|
||||||
|
break
|
||||||
|
key, sep, value = line.partition(':')
|
||||||
|
if sep and key == name_key and value.strip():
|
||||||
|
name = value.strip()
|
||||||
|
break
|
||||||
|
guest_id = f"{'VM' if kind == 'qemu' else 'LXC'} {path.stem}"
|
||||||
|
guest_label = f'{name} ({guest_id})' if name else f'{guest_id} (name unavailable)'
|
||||||
section = 'current'
|
section = 'current'
|
||||||
for line in content.splitlines():
|
for line in content.splitlines():
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
@@ -61,7 +75,7 @@ def references(root, nodes, guests):
|
|||||||
continue
|
continue
|
||||||
for volume in VOLUME.findall(value):
|
for volume in VOLUME.findall(value):
|
||||||
refs.setdefault(volume, []).append({
|
refs.setdefault(volume, []).append({
|
||||||
'node': node['node'], 'guest': f'{kind} {path.stem}',
|
'node': node['node'], 'guest': guest_label,
|
||||||
'unused': bool(re.fullmatch(r'unused\d+', key)) and section == 'current',
|
'unused': bool(re.fullmatch(r'unused\d+', key)) and section == 'current',
|
||||||
'section': section,
|
'section': section,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -20,13 +20,14 @@ class ReportTests(unittest.TestCase):
|
|||||||
for kind in ('qemu-server', 'lxc'):
|
for kind in ('qemu-server', 'lxc'):
|
||||||
(self.root / node / kind).mkdir(parents=True)
|
(self.root / node / kind).mkdir(parents=True)
|
||||||
(self.root / 'a/qemu-server/100.conf').write_text(
|
(self.root / 'a/qemu-server/100.conf').write_text(
|
||||||
|
'name: app-server\n'
|
||||||
'scsi0: local:vm-100-disk-0,size=10G\n'
|
'scsi0: local:vm-100-disk-0,size=10G\n'
|
||||||
'unused0: local:vm-100-disk-1\n'
|
'unused0: local:vm-100-disk-1\n'
|
||||||
'efidisk0: shared:vm-100-efi\n'
|
'efidisk0: shared:vm-100-efi\n'
|
||||||
'tpmstate0: shared:vm-100-tpm\n'
|
'tpmstate0: shared:vm-100-tpm\n'
|
||||||
'[snap]\nscsi0: local:vm-100-old\n'
|
'[snap]\nscsi0: local:vm-100-old\n'
|
||||||
'[PENDING]\nscsi1: local:vm-100-pending\n')
|
'[PENDING]\nscsi1: local:vm-100-pending\n')
|
||||||
(self.root / 'b/lxc/200.conf').write_text('rootfs: local:subvol-200-disk-0\nmp0: shared:subvol-200-disk-1,mp=/data\n')
|
(self.root / 'b/lxc/200.conf').write_text('hostname: fileserver\nrootfs: local:subvol-200-disk-0\nmp0: shared:subvol-200-disk-1,mp=/data\n')
|
||||||
self.nodes = [{'node': n, 'status': 'online'} for n in ('a', 'b')]
|
self.nodes = [{'node': n, 'status': 'online'} for n in ('a', 'b')]
|
||||||
self.guests = [{'node': 'a', 'type': 'qemu', 'vmid': 100}, {'node': 'b', 'type': 'lxc', 'vmid': 200}]
|
self.guests = [{'node': 'a', 'type': 'qemu', 'vmid': 100}, {'node': 'b', 'type': 'lxc', 'vmid': 200}]
|
||||||
self.refs, self.errors, _ = disks.references(self.root, self.nodes, self.guests)
|
self.refs, self.errors, _ = disks.references(self.root, self.nodes, self.guests)
|
||||||
@@ -44,7 +45,9 @@ class ReportTests(unittest.TestCase):
|
|||||||
|
|
||||||
def test_candidates_unused_replication_and_backing(self):
|
def test_candidates_unused_replication_and_backing(self):
|
||||||
self.assertEqual(self.result('local:vm-999-disk-0')[0], 'Orphan candidate')
|
self.assertEqual(self.result('local:vm-999-disk-0')[0], 'Orphan candidate')
|
||||||
self.assertEqual(self.result('local:vm-100-disk-1')[0], 'Unused disk')
|
self.assertEqual(self.result('local:vm-100-disk-1'), ('Unused disk', 'app-server (VM 100)'))
|
||||||
|
self.assertIn('a/app-server (VM 100)', self.result('local:vm-100-disk-0', node='b')[1])
|
||||||
|
self.assertIn('b/fileserver (LXC 200)', self.result('local:subvol-200-disk-0')[1])
|
||||||
self.assertEqual(self.result('local:vm-100-disk-0', node='b')[0], 'Needs review')
|
self.assertEqual(self.result('local:vm-100-disk-0', node='b')[0], 'Needs review')
|
||||||
self.assertEqual(self.result('local:base-900-disk-0')[0], 'Needs review')
|
self.assertEqual(self.result('local:base-900-disk-0')[0], 'Needs review')
|
||||||
self.assertEqual(self.result('local:999/base-999-disk-0.qcow2')[0], 'Needs review')
|
self.assertEqual(self.result('local:999/base-999-disk-0.qcow2')[0], 'Needs review')
|
||||||
|
|||||||
Reference in New Issue
Block a user