From fff687b3b801e149fa6a9ff089fde6149d605ca2 Mon Sep 17 00:00:00 2001 From: Quentin Smith Date: Mon, 6 Jan 2014 01:50:04 -0500 Subject: [PATCH] Add xen_net munin plugin for monitoring network status. --- debian/changelog | 6 ++ debian/xvm-munin-host-config.postinst | 2 +- host/etc/munin/plugin-conf.d/{xen_cpu => xen_} | 2 +- host/etc/munin/plugins/xen_net | 1 + .../share/xvm-munin-host-config/plugins/xen_net | 106 ++++++++++++++++++++ 5 files changed, 115 insertions(+), 2 deletions(-) rename host/etc/munin/plugin-conf.d/{xen_cpu => xen_} (74%) create mode 120000 host/etc/munin/plugins/xen_net create mode 100755 host/usr/share/xvm-munin-host-config/plugins/xen_net diff --git a/debian/changelog b/debian/changelog index 9bbbd2d..32499c9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +xvm-munin-config (0.0.18) unstable; urgency=low + + * Add xen_net munin plugin for monitoring network status. + + -- Quentin Smith Mon, 06 Jan 2014 01:41:38 -0500 + xvm-munin-config (0.0.17) unstable; urgency=low * Python 2.7 apparently treats "%\n" as a format specifier, when it used diff --git a/debian/xvm-munin-host-config.postinst b/debian/xvm-munin-host-config.postinst index fc2de88..b182729 100755 --- a/debian/xvm-munin-host-config.postinst +++ b/debian/xvm-munin-host-config.postinst @@ -30,7 +30,7 @@ case "$1" in ### BEGIN xvm-munin-config munin ALL=(postfix) SETENV: NOPASSWD: /etc/munin/plugins/postfix_mailqueue munin ALL=(munin) SETENV: NOPASSWD: ALL -munin ALL=(root) SETENV: NOPASSWD: /etc/munin/plugins/hddtemp_smartctl , /etc/munin/plugins/smart_* , /etc/munin/plugins/xen_cpu +munin ALL=(root) SETENV: NOPASSWD: /etc/munin/plugins/hddtemp_smartctl , /etc/munin/plugins/smart_* , /etc/munin/plugins/xen_* ### END xvm-munin-config EOF diff --git a/host/etc/munin/plugin-conf.d/xen_cpu b/host/etc/munin/plugin-conf.d/xen_ similarity index 74% rename from host/etc/munin/plugin-conf.d/xen_cpu rename to host/etc/munin/plugin-conf.d/xen_ index 79defca..2805590 100644 --- a/host/etc/munin/plugin-conf.d/xen_cpu +++ b/host/etc/munin/plugin-conf.d/xen_ @@ -1,3 +1,3 @@ -[xen_cpu] +[xen_*] user root command sudo -E %c diff --git a/host/etc/munin/plugins/xen_net b/host/etc/munin/plugins/xen_net new file mode 120000 index 0000000..5419eb6 --- /dev/null +++ b/host/etc/munin/plugins/xen_net @@ -0,0 +1 @@ +/usr/share/xvm-munin-host-config/plugins/xen_net \ No newline at end of file diff --git a/host/usr/share/xvm-munin-host-config/plugins/xen_net b/host/usr/share/xvm-munin-host-config/plugins/xen_net new file mode 100755 index 0000000..822b3e0 --- /dev/null +++ b/host/usr/share/xvm-munin-host-config/plugins/xen_net @@ -0,0 +1,106 @@ +#!/usr/bin/python + +import sys +sys.path.append('/usr/lib/xen-default/lib/python/') +from xen.lowlevel import xs +from collections import defaultdict +import os +import re + +xsc = xs.xs() + +def live_vms(): + domids = set(xsc.ls('', '/local/domain')) + + vms = dict() + + for domid in domids: + try: + uuid, data = get_dom(int(domid)) + except (xs.Error, TypeError, AttributeError): + continue # went down since we started + vms[uuid] = data + return vms + +def get_dom(domid): + data = dict(domid=domid) + data['name'] = xsc.read('', '/local/domain/%d/name' % domid) + data['uuid'] = xsc.read('', '/local/domain/%d/vm' % domid)[4:] + if data['name'][0:2] == 'd_': + data['munin_name'] = 'db domid %d' % domid + else: + data['munin_name'] = data['name'] + data['munin_var'] = 'uuid_'+data['uuid'].replace('-', '_') + return data['munin_var'], data + +def parse_net_dev(): + """Parse /proc/net/dev to determine down/up counters for each interface. + + N.B. Note that "down" and "up" are with respect to the host. + """ + usage = {} + for line in open('/proc/net/dev', 'r'): + if ':' not in line: + continue # skip header lines + iface, fields = line.split(':') + iface = iface.strip() + fields = fields.split() + usage[iface] = {'down': int(fields[0]), + 'up': int(fields[8])} + return usage + +IFACE_NAME_RE = re.compile(r'^(vif|tap)(\d+)\.(\d+)$') + +def get_net_usage(): + """Group /proc/net/dev counters by domain. + + N.B. Note that "down" and "up" are reversed - from the perspective of the guest. + """ + by_dev = parse_net_dev() + by_domain = defaultdict(lambda: {'down': 0, 'up': 0}) + for iface in by_dev: + m = IFACE_NAME_RE.match(iface) + if m: + viftype, domid, ifcount = m.groups() + domid = int(domid) + by_domain[domid]['down'] += by_dev[iface]['up'] + by_domain[domid]['up'] += by_dev[iface]['down'] + return by_domain + +if __name__ == '__main__': + if len(sys.argv) > 1: + cmd = sys.argv[1] + else: + cmd = None + + domains = live_vms() + + if cmd == 'config': + print """ + graph_title Xen domain network usage + graph_args --base 1000 + graph_vlabel bits in (-) / out (+) per ${graph_period} + graph_info This graph shows how network is utilized by Xen domains. + graph_category network + graph_period second""" + for d in sorted(domains): + for direction in ('down', 'up'): + key = "%s_%s" % (d, direction) + print "%s.label %s" % (key, domains[d]['munin_name']) + print "%s.draw AREASTACK" % key + print "%s.max 10000000000" % key + print "%s.min 0" % key + print "%s.type DERIVE" % key + print "%s.cdef %s,8,*" % (key, key) + if direction == 'down': + print "%s.graph no" % key + else: + print "%s.negative %s_down" % (key, d) + print "%s.info uuid %s" % (key, domains[d]['uuid']) + sys.exit(0) + + net_usage = get_net_usage() + + for d in sorted(domains): + for direction in ('down', 'up'): + print "%s_%s.value %d" % (d, direction, net_usage[domains[d]['domid']][direction]) -- 1.7.9.5