PatchInventory: kvm_net

File kvm_net, 3.9 kB (added by admin, 3 years ago)
Line 
1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3# vim: set fileencoding=utf-8
4#
5# Munin plugin to show the network I/O per vm
6#
7# Copyright Maxence Dunnewind, Rodolphe Quiédeville
8#
9# License : GPLv3
10#
11# need to be run with root privilege to execute brctl
12#
13#
14# parsed environment variables:
15# vmsuffix: part of vm name to be removed
16#
17#%# capabilities=autoconf
18#%# family=contrib
19
20import re, os, sys
21from subprocess import Popen, PIPE
22
23def config(vm_names):
24    ''' Print the plugin's config
25    @param vm_names : a list of "cleaned" vms' name
26    '''
27    base_config = """graph_title KVM Network I/O
28graph_vlabel Bytes rx(-)/tx(+) per second
29graph_category KVM
30graph_info This graph shows the network I/O of the virtual machines
31graph_args --base 1024
32    """
33    print base_config
34    for vm in vm_names:
35        print "%s_in.label %s" % (vm, vm)
36        print "%s_in.type COUNTER" % vm
37        print "%s_in.min 0" % vm
38        print "%s_in.draw LINE2" % vm
39        print "%s_out.negative %s_in" % (vm, vm)
40        print "%s_out.label %s" % (vm, vm)
41        print "%s_out.type COUNTER" % vm
42        print "%s_out.min 0" % vm
43        print "%s_out.draw LINE2" % vm
44
45def clean_vm_name(vm_name):
46    ''' Replace all special chars
47    @param vm_name : a vm's name
48    @return cleaned vm's name
49    '''
50    # suffix part defined in conf
51    suffix = os.getenv('vmsuffix')
52    if suffix:
53        vm_name = re.sub(suffix,'',vm_name)
54
55    return re.sub(r"[^a-zA-Z0-9_]", "_", vm_name)
56   
57def fetch(vms):
58    ''' Fetch values for a list of pids
59    @param dictionnary {kvm_pid: cleaned vm name}
60    '''
61    macs = find_vms_tap()
62    res = {}
63    for pid in vms:
64        mac = get_vm_mac(pid)
65        try:
66            tap = "tap%s" % macs[mac]
67            f = open("/proc/net/dev", "r")
68            for line in f.readlines():
69                if tap in line:
70                    line = line.split(':')[1]
71                    print "%s_in.value %s" % (vms[pid], line.split()[0]) 
72                    print "%s_out.value %s" % (vms[pid], line.split()[8]) 
73                    break
74                else:
75                    f.close()
76        except:
77            continue
78
79def detect_kvm():
80    ''' Check if kvm is installed
81    '''
82    kvm = Popen("which kvm", shell=True, stdout=PIPE)
83    kvm.communicate()
84    return not bool(kvm.returncode)
85
86def find_vm_names(pids):
87    '''Find and clean vm names from pids
88    @return a dictionnary of {pids : cleaned vm name}
89    '''
90    result = {}
91    for pid in pids:
92        cmdline = open("/proc/%s/cmdline" % pid, "r")
93        result[pid] = clean_vm_name(re.sub(r"^.*-name\x00([a-zA-Z0-9.-]*)\x00\-.*$",r"\1", cmdline.readline()))       
94    return result
95   
96def get_vm_mac(pid):
97    '''Find and clean vm names from pids
98    @return the mac address for a specified pid
99    '''
100    cmdline = open("/proc/%s/cmdline" % pid, "r")
101    mac = re.sub(r"^.*macaddr=(..:..:..:..:..:..).*$",r"\1", cmdline.readline())
102    return mac
103
104def list_pids():
105    ''' Find the pid of kvm processes
106    @return a list of pids from running kvm
107    '''
108    pid = Popen("pidof kvm", shell=True, stdout=PIPE)
109    return pid.communicate()[0].split()
110
111def find_vms_tap():
112    ''' Check if kvm is installed
113    @return a list of pids from running kvm
114    '''
115    result = {}
116    kvm = Popen("brctl showmacs br0 | grep no", shell=True, stdout=PIPE)
117    res = kvm.communicate()[0].split('\n')
118    for line in res:
119        try:
120            tap = str(int(line.split()[0]) - 1)
121            mac = line.split()[1]
122            result[mac] = tap
123        except:
124            continue
125    return result
126   
127if __name__ == "__main__":
128    if len(sys.argv) > 1:
129        if sys.argv[1] in ['autoconf', 'detect']:
130            if detect_kvm():
131                print "yes"
132            else:
133                print "no"
134        elif sys.argv[1] == "config":
135            config(find_vm_names(list_pids()).values())
136        else:
137            fetch(find_vm_names(list_pids()))
138    else:
139        fetch(find_vm_names(list_pids()))
140