collect disk info
This commit is contained in:
parent
6e90f95e1c
commit
df8526254c
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
result
|
result
|
||||||
*~
|
*~
|
||||||
*.deb
|
*.deb
|
||||||
|
__pycache__
|
||||||
|
|||||||
@ -14,6 +14,8 @@ import cProfile
|
|||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
|
|
||||||
|
import qmblock
|
||||||
|
|
||||||
DEFAULT_PORT = 9116
|
DEFAULT_PORT = 9116
|
||||||
DEFAULT_INTERVAL = 10
|
DEFAULT_INTERVAL = 10
|
||||||
DEFAULT_PREFIX = "pve"
|
DEFAULT_PREFIX = "pve"
|
||||||
@ -110,7 +112,6 @@ def extract_nic_info_from_monitor(vm_id):
|
|||||||
"model": cfg["model"],
|
"model": cfg["model"],
|
||||||
"macaddr": cfg["macaddr"],
|
"macaddr": cfg["macaddr"],
|
||||||
"ifname": cfg["ifname"]
|
"ifname": cfg["ifname"]
|
||||||
|
|
||||||
}
|
}
|
||||||
for netdev, cfg in nics_map.items()
|
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 = create_or_get_gauge(metric_name, nic_labels.keys())
|
||||||
gauge.labels(**nic_labels).set(value)
|
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_netstat_proc, [ proc[2] for proc in procs ]))
|
||||||
|
list(executor.map(map_disk_proc, [ proc[2] for proc in procs ]))
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description='PVE metrics exporter for Prometheus')
|
parser = argparse.ArgumentParser(description='PVE metrics exporter for Prometheus')
|
||||||
|
|||||||
89
src/pvemon/qmblock.py
Normal file
89
src/pvemon/qmblock.py
Normal 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])))
|
||||||
Loading…
x
Reference in New Issue
Block a user