collect disk info

This commit is contained in:
illustris 2023-10-04 13:39:33 +05:30
parent 6e90f95e1c
commit df8526254c
Signed by: illustris
GPG Key ID: 56C8FC0B899FEFA3
3 changed files with 100 additions and 2 deletions

3
.gitignore vendored
View File

@ -1,3 +1,4 @@
result
*~
*.deb
*.deb
__pycache__

View File

@ -14,6 +14,8 @@ import cProfile
from concurrent.futures import ThreadPoolExecutor
from threading import Lock
import qmblock
DEFAULT_PORT = 9116
DEFAULT_INTERVAL = 10
DEFAULT_PREFIX = "pve"
@ -110,7 +112,6 @@ def extract_nic_info_from_monitor(vm_id):
"model": cfg["model"],
"macaddr": cfg["macaddr"],
"ifname": cfg["ifname"]
}
for netdev, cfg in nics_map.items()
]
@ -191,7 +192,14 @@ def collect_kvm_metrics():
gauge = create_or_get_gauge(metric_name, nic_labels.keys())
gauge.labels(**nic_labels).set(value)
def map_disk_proc(id):
for disk_name, disk_info in qmblock.extract_disk_info_from_monitor(id).items():
disk_labels = {"id": id, "disk_name": disk_name}
prom_disk_info = create_or_get_info("kvm_disk", disk_labels.keys())
prom_disk_info.labels(**disk_labels).info({k: v for k, v in disk_info.items() if k not in disk_labels.keys()})
list(executor.map(map_netstat_proc, [ proc[2] for proc in procs ]))
list(executor.map(map_disk_proc, [ proc[2] for proc in procs ]))
def main():
parser = argparse.ArgumentParser(description='PVE metrics exporter for Prometheus')

89
src/pvemon/qmblock.py Normal file
View File

@ -0,0 +1,89 @@
import pexpect
import re
import os
def get_device(disk_path):
try:
return os.readlink(disk_path).split('/')[-1]
except OSError:
return None
def extract_disk_info_from_monitor(vm_id):
child = pexpect.spawn(f'qm monitor {vm_id}')
# Wait for the QEMU monitor prompt
child.expect('qm>', timeout=10)
# Execute 'info block'
child.sendline('info block')
# Wait for the prompt again
child.expect('qm>', timeout=10)
# Parse the output
raw_output = child.before.decode('utf-8').strip()
child.close()
disks_map = {}
disks = [x.strip() for x in raw_output.split("drive-")[1:]]
for disk in disks:
data = [x.strip() for x in disk.split("\n")]
pattern = r'(\w+) \(#block(\d+)\): (.+) \(([\w, -]+)\)'
match = re.match(pattern, data[0])
if not match:
continue
disk_name, block_id, disk_path, disk_type_and_mode = match.groups()
disk_type = disk_type_and_mode.split(", ")[0]
if "efidisk" in disk_name: # TODO: handle this later
continue
disks_map[disk_name]={
"disk_name": disk_name,
"block_id": block_id,
"disk_path": disk_path,
"disk_type": disk_type,
}
if "read-only" in disk_type_and_mode:
disks_map[disk_name]["read_only"] = "true"
if disk_type == "qcow2":
disks_map[disk_name]["vol_name"] = disk_path.split("/")[-1].split(".")[0]
if "/dev/zvol" in disk_path:
disks_map[disk_name]["disk_type"] = "zvol"
disks_map[disk_name]["pool"] = "/".join(disk_path.split("/")[3:-1])
disks_map[disk_name]["vol_name"] = disk_path.split("/")[-1]
disks_map[disk_name]["device"] = get_device(disk_path)
elif re.match(r'/dev/[^/]+/vm-\d+-disk-\d+', disk_path): # lvm
disks_map[disk_name]["disk_type"] = "lvm"
vg_name, vol_name = re.search(r'/dev/([^/]+)/(vm-\d+-disk-\d+)', disk_path).groups()
disks_map[disk_name]["vg_name"] = vg_name
disks_map[disk_name]["vol_name"] = vol_name
disks_map[disk_name]["device"] = get_device(disk_path)
elif "/dev/rbd-pve" in disk_path: # rbd
disks_map[disk_name]["disk_type"] = "rbd"
rbd_parts = disk_path.split('/')
disks_map[disk_name]["cluster_id"] = rbd_parts[-3]
disks_map[disk_name]["pool_name"] = rbd_parts[-2]
disks_map[disk_name]["vol_name"] = rbd_parts[-1]
disks_map[disk_name]["device"] = get_device(disk_path)
elif "/dev/rbd-pve" in disk_path:
disks_map[disk_name]["disk_type"] = "rbd"
rbd_parts = disk_path.split('/')
pool_name = rbd_parts[-3]
vm_id = rbd_parts[-1].split('-')[1]
disk_number = rbd_parts[-1].split('-')[-1]
disks_map[disk_name]["pool_name"] = pool_name
disks_map[disk_name]["rbd_vm_id"] = vm_id
disks_map[disk_name]["rbd_disk_number"] = disk_number
for line in data[1:-1]:
if "Attached to" in line:
attached_to = line.split(":")[-1].strip()
if "virtio" in attached_to:
attached_to=attached_to.split("/")[3]
disks_map[disk_name]["attached_to"] = attached_to
if "Cache mode" in line:
for cache_mode in line.split(":")[-1].strip().split(", "):
disks_map[disk_name][f"cache_mode_{cache_mode}"] = "true"
if "Detect zeroes" in line:
disks_map[disk_name]["detect_zeroes"] = "on"
return disks_map
if __name__ == "__main__":
import json
import sys
print(json.dumps(extract_disk_info_from_monitor(sys.argv[1])))