diff --git a/kvm_cpu b/kvm_cpu new file mode 100644 index 0000000..3196dc2 --- /dev/null +++ b/kvm_cpu @@ -0,0 +1,137 @@ +#!/usr/bin/env python3 +""" +=encoding utf8 + +=head1 NAME + +kvm_cpu - show CPU usage of VM + + +=head1 CONFIGURATION + +Parsed environment variables: + + vmsuffix: part of VM name to be removed + + +=head1 LICENSE + +GPLv3 + +SPDX-License-Identifier: GPL-3.0-only + + +=head1 AUTHORS + +Maxence Dunnewind + +Rodolphe QuiƩdeville + + +=head1 MAGIC MARKERS + + #%# capabilities=autoconf + #%# family=contrib + +=cut +""" + +import os +import re +import sys +from subprocess import Popen, PIPE + + +def config(vm_names): + ''' Print the plugin's config + @param vm_names : a list of "cleaned" vms' name + ''' + percent = 100 * len( + list( + filter( + lambda x: x[0:3] == 'cpu' and x[3] != ' ', open('/proc/stat', 'r').readlines()))) + + base_config = """graph_title KVM Virtual Machine CPU usage +graph_vlabel %% +graph_category virtualization +graph_scale no +graph_period second +graph_info This graph shows the current CPU used by virtual machines +graph_args --base 1000 -r --lower-limit 0 --upper-limit %d""" % percent + print(base_config) + for vm in vm_names: + print("%s_cpu.label %s" % (vm, vm)) + print("%s_cpu.min 0" % vm) + print("%s_cpu.type DERIVE" % vm) + print("%s_cpu.draw AREASTACK" % vm) + print("%s_cpu.info percent of cpu time used by virtual machine" % vm) + + +def clean_vm_name(vm_name): + ''' Replace all special chars + @param vm_name : a vm's name + @return cleaned vm's name + ''' + # suffix part defined in conf + suffix = os.getenv('vmsuffix') + if suffix: + vm_name = re.sub(suffix, '', vm_name) + # proxmox uses kvm with -name parameter + parts = vm_name.split('\x00') + if parts[0].endswith('kvm'): + try: + return parts[parts.index('-name') + 1] + except ValueError: + pass + return re.sub(r"[^a-zA-Z0-9_]", "_", vm_name) + + +def detect_kvm(): + ''' Check if kvm is installed ''' + kvm = Popen("which kvm", shell=True, stdout=PIPE) + kvm.communicate() + return not bool(kvm.returncode) + + +def find_vm_names(pids): + '''Find and clean vm names from pids + @return a dictionary of {pids : cleaned vm name} + ''' + result = {} + for pid in pids: + cmdline = open("/proc/%s/cmdline" % pid, "r") + result[pid] = clean_vm_name( + re.sub(r"^.*guest=([a-zA-Z0-9.-_-]*).*$", r"\1", cmdline.readline())) + return result + + +def list_pids(): + ''' Find the pid of kvm processes + @return a list of pids from running kvm + ''' + pid = Popen("pidof qemu-kvm qemu-system-x86_64 kvm", shell=True, stdout=PIPE) + return pid.communicate()[0].decode().split() + + +def fetch(vms): + ''' Fetch values for a list of pids + @param dictionary {kvm_pid: cleaned vm name} + ''' + for pid, name in vms.items(): + user, system = open("/proc/%s/stat" % pid, 'r').readline().split(' ')[13:15] + print('%s_cpu.value %d' % (name, int(user) + int(system))) + + +if __name__ == "__main__": + if len(sys.argv) > 1: + if sys.argv[1] in ['autoconf', 'detect']: + if detect_kvm(): + print("yes") + else: + print("no") + elif sys.argv[1] == "config": + config(find_vm_names(list_pids()).values()) + else: + fetch(find_vm_names(list_pids())) + else: + fetch(find_vm_names(list_pids()))