Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

kvm plugins improvements #186

Open
wants to merge 3 commits into from

3 participants

duritong Stig Sandbeck Mathisen georgetasioulis
duritong

I added a few improvements to the kvm plugins:

  • Make most of them also work on RedHat based systems
  • Add an additional kvm_net_rh Plugin that works on RedHat bases systems. It is more or less a copy of the existing kvm_net plugin, which does not work and which needed to many changes which I'm not sure would have broken things further.
duritong added some commits
georgetasioulis

Thanks for the RH compatible kvm plugins. cpu, mem & io work great, but net_rh throws me an error:

[root@kvm01 plugins]# munin-run kvm_net_rh 
Traceback (most recent call last):
  File "/etc/munin/plugins/kvm_net_rh", line 148, in 
    fetch(find_vm_names(list_pids()))
  File "/etc/munin/plugins/kvm_net_rh", line 76, in fetch
    inf = macs_to_inf[mac]
KeyError: 'fe:16:3c:b7:04:e4'
[root@kvm01 plugins]#

Any ideas?

Yeah, I had to clean that up a bit more, have a look at http://git.puppet.immerda.ch/?p=module-munin.git;a=blob;f=files/plugins/kvm_net;h=c7b5acabe3d91053dcd114a98a41e0214dc279b7;hb=a29438a07e9af6ccdcadd465492e527f6ba4a8ab That one works on my machine(TM). Will submit the fixed code as well later.

Thanks for your fast reply. I tried the code from git.puppet.immerda.ch but unfortunately it gives me the exact same error:

[root@kvm01 plugins]# munin-run kvm_net_rh
Traceback (most recent call last):
  File "/etc/munin/plugins/kvm_net_rh", line 147, in 
    fetch(find_vm_names(list_pids()))
  File "/etc/munin/plugins/kvm_net_rh", line 75, in fetch
    inf = macs_to_inf[mac]
KeyError: 'fe:16:3c:b7:04:e4'

Do I need anything other than

[kvm_*]
user root

in my /etc/munin/plugin-conf.d/munin-node file?

I noticed that the output of cat /proc/net/dev | awk '{ print $1 ":" $9 }' gives:

[root@kvm01 plugins]# cat /proc/net/dev | awk '{ print $1  ":" $9 }'
Inter-|:
face:multicast|bytes
lo:15871419:15871419
eth0::0
eth1:36943552750:7999558116
br0:9599102973:876120383
virbr0::0
virbr0-nic::0
kvm101.0:172085221:4326661656
kvm102.0::0
kvm105.0:797587876:117848764
kvm108.0:36188334:1710188659

Could the first 2 lines be a problem for the macs_to_inf function?

Stig Sandbeck Mathisen ssm added the enhancement label
Stig Sandbeck Mathisen ssm added the new plugin label
Stig Sandbeck Mathisen
Owner
ssm commented

Closing and opening old pull request, to have it tested by travis-ci.

Stig Sandbeck Mathisen ssm closed this
Stig Sandbeck Mathisen ssm reopened this
Stig Sandbeck Mathisen ssm commented on the diff
plugins/virtualization/kvm_net_rh
((53 lines not shown))
+ '''
+ # 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 e in Popen('cat /proc/net/dev | awk \'{ print $1 ":" $9 }\'', shell=True, stdout=PIPE).communicate()[0].split('\n'):
Stig Sandbeck Mathisen Owner
ssm added a note

This line seems to contain a bug, which should be fixed before we can merge.

% cat /proc/net/dev | awk '{ print $1 ":" $9 }'    
Inter-|:
face:multicast|bytes
eth0::0
eth1::5246
virbr0::0
lo::0

The format on my box is:

% cat /proc/net/dev
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
  eth0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
  eth1: 3833806033 3143411    0    0    0     0          0      5246 168429641 1939069    0    0    0     0       0          0
virbr0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
    lo: 86071620  477326    0    0    0     0          0         0 86071620  477326    0    0    0     0       0          0

...which looks more human-readable than strictly parsable.

On a reasonably modern linux kernel, perhaps what you can find with "find /sys/class/net/*/statistics/" may be more useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 12, 2012
  1. duritong
  2. duritong

    Make kvm plugins also work on RedHat based systems

    duritong authored
    On RedHat the binary that is used is called qemu-kvm not kvm.
Commits on Sep 15, 2012
  1. duritong

    fix graph by syncing output and config

    duritong authored
    What gets configured matches now what will be reported.
This page is out of date. Refresh to see the latest.
2  plugins/virtualization/kvm_cpu
View
@@ -75,7 +75,7 @@ def list_pids():
''' Find the pid of kvm processes
@return a list of pids from running kvm
'''
- pid = Popen("pidof kvm", shell=True, stdout=PIPE)
+ pid = Popen("pidof qemu-kvm kvm", shell=True, stdout=PIPE)
return pid.communicate()[0].split()
def fetch(vms):
2  plugins/virtualization/kvm_io
View
@@ -92,7 +92,7 @@ def list_pids():
''' Find the pid of kvm processes
@return a list of pids from running kvm
'''
- pid = Popen("pidof kvm", shell=True, stdout=PIPE)
+ pid = Popen("pidof qemu-kvm kvm", shell=True, stdout=PIPE)
return pid.communicate()[0].split()
if __name__ == "__main__":
2  plugins/virtualization/kvm_mem
View
@@ -89,7 +89,7 @@ def list_pids():
''' Find the pid of kvm processes
@return a list of pids from running kvm
'''
- pid = Popen("pidof kvm", shell=True, stdout=PIPE)
+ pid = Popen("pidof qemu-kvm kvm", shell=True, stdout=PIPE)
return pid.communicate()[0].split()
if __name__ == "__main__":
149 plugins/virtualization/kvm_net_rh
View
@@ -0,0 +1,149 @@
+#!/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 KVM
+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" % (vms[pid],i, vms[pid])
+ 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_in" % (vms[pid], i, vms[pid])
+ print "%s_eth%s_out.label %s" % (vms[pid], i, vms[pid])
+ 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 e in Popen('cat /proc/net/dev | awk \'{ print $1 ":" $9 }\'', shell=True, stdout=PIPE).communicate()[0].split('\n'):
Stig Sandbeck Mathisen Owner
ssm added a note

This line seems to contain a bug, which should be fixed before we can merge.

% cat /proc/net/dev | awk '{ print $1 ":" $9 }'    
Inter-|:
face:multicast|bytes
eth0::0
eth1::5246
virbr0::0
lo::0

The format on my box is:

% cat /proc/net/dev
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
  eth0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
  eth1: 3833806033 3143411    0    0    0     0          0      5246 168429641 1939069    0    0    0     0       0          0
virbr0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
    lo: 86071620  477326    0    0    0     0          0         0 86071620  477326    0    0    0     0       0          0

...which looks more human-readable than strictly parsable.

On a reasonably modern linux kernel, perhaps what you can find with "find /sys/class/net/*/statistics/" may be more useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ s = e.split(':')
+ if len(s) == 3:
+ interfaces[s[0]] = (s[1],s[2])
+ for pid in vms:
+ macs = get_vm_macs(pid)
+ i = 0
+ for mac in macs:
+ inf = macs_to_inf[mac]
+ values = interfaces[inf]
+ if len(values) == 2:
+ print "%s_eth%s_in.value %s" % (vms[pid], i, values[0])
+ print "%s_eth%s_out.value %s" % (vms[pid], i, values[1])
+ i += 1
+
+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 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 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()))
+
Something went wrong with that request. Please try again.