Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kvm plugins improvements #186

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions plugins/virtualization/kvm_cpu
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ graph_args --base 1000 -r --lower-limit 0 --upper-limit %d""" % percent
print "%s_cpu.type DERIVE" % vm
print "%s_cpu.draw %s" % (vm, draw)
print "%s_cpu.info percent of cpu time used by virtual machine" % vm
draw = "STACK"
draw = "STACK"


def clean_vm_name(vm_name):
Expand All @@ -57,9 +57,12 @@ def clean_vm_name(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)
if os.path.isfile("/usr/libexec/qemu-kvm"):
return True
else:
kvm = Popen("which kvm", shell=True, stdout=PIPE)
kvm.communicate()
return not bool(kvm.returncode)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would propose to phrase this clearer (instead of relying on the coincidence of the implicit interger/boolean conversion):
return kvm.returncode == 0

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't change the original behavior. Just added one that fits more for RHEL/CentOS.
In general this part is from my point of view problematic in 2 cases:

  1. which lookups are expensive
  2. we're not only looking at kvm.

I can change it in general, but as I said the intend of my PR was not to change the original behavior. But I can come up with general improvements, if people would like to see that.


def find_vm_names(pids):
'''Find and clean vm names from pids
Expand All @@ -70,12 +73,12 @@ def find_vm_names(pids):
cmdline = open("/proc/%s/cmdline" % pid, "r")
result[pid] = clean_vm_name(re.sub(r"^.*-name\x00([a-zA-Z0-9.-_-]*)\x00\-.*$",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-system-x86_64", shell=True, stdout=PIPE)
pid = Popen("pidof qemu-kvm qemu-system-x86_64 kvm", shell=True, stdout=PIPE)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this list of names lack "qemu-system-i386"?
Other architectures are probably not available due to kvm being bound to intel/amd - right?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned above I did not change the original behavior. So I just kept qemu-system-x86_64 as it was the current behavior. I can add though other architectures as well.

return pid.communicate()[0].split()

def fetch(vms):
Expand All @@ -85,7 +88,7 @@ def fetch(vms):
for ( pid, name ) in vms.iteritems():
( 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']:
Expand All @@ -99,4 +102,3 @@ if __name__ == "__main__":
fetch(find_vm_names(list_pids()))
else:
fetch(find_vm_names(list_pids()))

21 changes: 12 additions & 9 deletions plugins/virtualization/kvm_io
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ graph_args --base 1024
print "%s_read.info I/O used by virtual machine %s" % (vm, vm)
print "%s_write.label %s" % (vm, vm)
print "%s_write.type COUNTER" % vm
print "%s_write.min 0" % vm
print "%s_write.min 0" % vm
print "%s_write.draw LINE1" % vm
print "%s_write.negative %s_read" % (vm, vm)
print "%s_write.info I/O used by virtual machine %s" % (vm, vm)
Expand All @@ -53,7 +53,7 @@ def clean_vm_name(vm_name):
vm_name = re.sub(suffix,'',vm_name)

return re.sub(r"[^a-zA-Z0-9_]", "_", vm_name)

def fetch(vms):
''' Fetch values for a list of pids
@param dictionnary {kvm_pid: cleaned vm name}
Expand All @@ -68,15 +68,18 @@ def fetch(vms):
if "write_bytes" in line:
write = line.split()[1]
print "%s_write.value %s" % (vms[pid], write)
break
break
f.close()

def detect_kvm():
''' Check if kvm is installed
'''
kvm = Popen("which kvm", shell=True, stdout=PIPE)
kvm.communicate()
return not bool(kvm.returncode)
if os.path.isfile("/usr/libexec/qemu-kvm"):
return True
else:
kvm = Popen("which kvm", shell=True, stdout=PIPE)
kvm.communicate()
return not bool(kvm.returncode)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above


def find_vm_names(pids):
'''Find and clean vm names from pids
Expand All @@ -87,14 +90,14 @@ def find_vm_names(pids):
cmdline = open("/proc/%s/cmdline" % pid, "r")
result[pid] = clean_vm_name(re.sub(r"^.*-name\x00([a-zA-Z0-9.-_-]*)\x00\-.*$",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-system-x86_64", shell=True, stdout=PIPE)
pid = Popen("pidof qemu-kvm qemu-system-x86_64 kvm", shell=True, stdout=PIPE)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

return pid.communicate()[0].split()

if __name__ == "__main__":
if len(sys.argv) > 1:
if sys.argv[1] in ['autoconf', 'detect']:
Expand Down
23 changes: 13 additions & 10 deletions plugins/virtualization/kvm_mem
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ graph_args --base 1024
print "%s_mem.min 0" % vm
print "%s_mem.draw %s" % (vm, draw)
print "%s_mem.info memory used by virtual machine %s" % (vm, vm)
draw = "STACK"
draw = "STACK"


def clean_vm_name(vm_name):
Expand All @@ -50,7 +50,7 @@ def clean_vm_name(vm_name):
vm_name = re.sub(suffix,'',vm_name)

return re.sub(r"[^a-zA-Z0-9_]", "_", vm_name)

def fetch(vms):
''' Fetch values for a list of pids
@param dictionnary {kvm_pid: cleaned vm name}
Expand All @@ -61,19 +61,22 @@ def fetch(vms):
cmdline = open("/proc/%s/cmdline" % pid, "r")
amount = re.sub(r"^.*-m\x00(.*)\x00-smp.*$",r"\1", cmdline.readline())
amount = int(amount) * 1024 * 1024
print "%s_mem.value %s" % (vms[pid], amount)
print "%s_mem.value %s" % (vms[pid], amount)
except:
cmdline = open("/proc/%s/cmdline" % pid, "r")
amount = re.sub(r"^.*-m\x00(\d+).*$",r"\1", cmdline.readline())
amount = int(amount) * 1024 * 1024
print "%s_mem.value %s" % (vms[pid], amount)
print "%s_mem.value %s" % (vms[pid], amount)

def detect_kvm():
''' Check if kvm is installed
'''
kvm = Popen("which kvm", shell=True, stdout=PIPE)
kvm.communicate()
return not bool(kvm.returncode)
if os.path.isfile("/usr/libexec/qemu-kvm"):
return True
else:
kvm = Popen("which kvm", shell=True, stdout=PIPE)
kvm.communicate()
return not bool(kvm.returncode)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above


def find_vm_names(pids):
'''Find and clean vm names from pids
Expand All @@ -84,14 +87,14 @@ def find_vm_names(pids):
cmdline = open("/proc/%s/cmdline" % pid, "r")
result[pid] = clean_vm_name(re.sub(r"^.*-name\x00([a-zA-Z0-9.-_-]*)\x00\-.*$",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-system-x86_64", shell=True, stdout=PIPE)
pid = Popen("pidof qemu-kvm qemu-system-x86_64 kvm", shell=True, stdout=PIPE)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

return pid.communicate()[0].split()

if __name__ == "__main__":
if len(sys.argv) > 1:
if sys.argv[1] in ['autoconf', 'detect']:
Expand Down
148 changes: 148 additions & 0 deletions plugins/virtualization/kvm_net_rh
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# vim: set fileencoding=utf-8
#
# Munin plugin to show the network I/O per vm
# On redhat based systems
#
# Copyright Igor Borodikhin
# Copyright Peter Meier
#
# License : GPLv3
#
#
# parsed environment variables:
# vmsuffix: part of vm name to be removed
#
#%# capabilities=autoconf
#%# family=contrib

import re, os, sys
from subprocess import Popen, PIPE

def config(vms):
''' Print the plugin's config
@param vm_names : a list of "cleaned" vms' name
'''
base_config = """graph_title KVM Network I/O
graph_vlabel Bytes rx(-)/tx(+) per second
graph_category Virtualization
graph_info This graph shows the network I/O of the virtual machines
graph_args --base 1024
"""
print base_config
for pid in vms:
macs = get_vm_macs(pid)
i = 0
for mac in macs:
print "%s_eth%s_in.label %s_eth%s" % (vms[pid],i, vms[pid], i)
print "%s_eth%s_in.type COUNTER" % (vms[pid], i)
print "%s_eth%s_in.min 0" % (vms[pid],i)
print "%s_eth%s_in.draw LINE2" % (vms[pid],i)
print "%s_eth%s_out.negative %s_eth%s_in" % (vms[pid], i, vms[pid], i)
print "%s_eth%s_out.label %s_eth%s" % (vms[pid], i, vms[pid], i)
print "%s_eth%s_out.type COUNTER" % (vms[pid], i)
print "%s_eth%s_out.min 0" % (vms[pid], i)
print "%s_eth%s_out.draw LINE2" % (vms[pid], i)
i += 1

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)

return re.sub(r"[^a-zA-Z0-9_]", "_", vm_name)

def fetch(vms):
''' Fetch values for a list of pids
@param dictionnary {kvm_pid: cleaned vm name}
'''
res = {}
macs_to_inf = find_macs_to_inf()
interfaces = {}
for pid in vms:
macs = get_vm_macs(pid)
i = 0
for mac in macs:
inf = macs_to_inf[mac]
with open("/sys/class/net/%s/statistics/rx_packets" % inf, 'r') as f:
print "%s_eth%s_in.value %s" % (vms[pid], i, f.readline()),
with open("/sys/class/net/%s/statistics/tx_packets" % inf, 'r') as f:
print "%s_eth%s_out.value %s" % (vms[pid], i, f.readline()),
i += 1

def detect_kvm():
''' Check if kvm is installed
'''
if os.path.isfile("/usr/libexec/qemu-kvm"):
return True
else:
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 dictionnary 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"^.*-name\x00([a-zA-Z0-9.-_-]*)\x00\-.*$",r"\1", cmdline.readline()))
return result

def get_vm_macs(pid):
'''Find macs for a pid
@return the mac addresses for a specified pid
'''
cmdline = open("/proc/%s/cmdline" % pid, "r")
line = cmdline.readline()
# macs are fe:... on the host
macs = [ re.sub(r"^\d{2}",'fe',p.split('=')[1]) for p in line.split(",") if re.match(r"^mac(addr)?=",p) ]
return macs

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].split()

def find_macs_to_inf():
''' Find interfaces for vms
@return a dictionary of macs to inf
'''
result = {}
inf = ""
kvm = Popen("ip a | grep -E -A 1 '(tap|vnet)' | awk '{print $2}' | grep -v '^$'", shell=True, stdout=PIPE)
res = kvm.communicate()[0].split('\n')
for line in res:
if len(line) > 0:
if re.match(r"^tap.*", line):
inf = re.sub(r"(tap[^:]+):", r"\1", line)
elif re.match(r"^vnet.*", line):
inf = re.sub(r"(vnet[^:]+):", r"\1", line)
else:
result[line] = inf

return result

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()))
else:
fetch(find_vm_names(list_pids()))
else:
fetch(find_vm_names(list_pids()))