aboutsummaryrefslogtreecommitdiff
path: root/libvirt-ifstat
blob: 1561c6a71d825c2971ae6495fc1d9effd3d03acd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/usr/bin/python3
# vim: set fileencoding=utf-8 :
#
# Munin plugin to show the network traffic of libvirt managed virtual machines
#
# Copyright 2008 Guido Guenther <agx@sigxcpu.org>
#
# License GPLv2
#
# depends: python-libvirt, python-libxml2
#
#%# capabilities=autoconf
#%# family=contrib

from __future__ import print_function
import re, sys, os
import libvirt
import libxml2


def canon(name):
    return re.sub(r"[^a-zA-Z0-9_]", "_", name)


def print_config(uri):
    """print the plugin config, determine the domains"""

    print("""graph_title Virtual Domain Network I/O
graph_vlabel Bytes rx (-)/ tx (+) per ${graph_period}
graph_category Virtual Machines
graph_info This graph shows the network I/O of the virtual machines""")

    conn = libvirt.openReadOnly(uri)
    ids = conn.listDomainsID()
    for id in ids:
        try:
            dom = conn.lookupByID(id)
            name = dom.name()
        except libvirt.libvirtError as err:
            print("Id: %s: %s" % (id, err), file=sys.stderr)
            continue
        if name == "Domain-0":
            continue
        print("%s_rx.label %s" % (canon(name), name))
        print("%s_rx.type DERIVE" % canon(name))
        print("%s_rx.min 0" % canon(name))
        print("%s_rx.graph no" % canon(name))
        print("%s_rx.draw LINE1" % canon(name))
        print("%s_tx.label %s" % (canon(name), name))
        print("%s_tx.type DERIVE" % canon(name))
        print("%s_tx.min 0" % canon(name))
        print("%s_tx.negative %s_rx" % (canon(name), canon(name)))
        print("%s_tx.draw LINE1" % canon(name))


def get_ifaces(dom):
    xml = dom.XMLDesc(0)
    doc = None
    try:
        doc = libxml2.parseDoc(xml)
    except Exception:
        return []
    ctx = doc.xpathNewContext()
    ifaces = []
    try:
        ret = ctx.xpathEval("/domain/devices/interface")
        for node in ret:
            devdst = None
            for child in node.children:
                if child.name == "target":
                    devdst = child.prop("dev")
            if devdst is None:
                continue
            ifaces.append(devdst)
    finally:
        if ctx is not None:
            ctx.xpathFreeContext()
        if doc is not None:
            doc.freeDoc()
    return ifaces


def fetch_values(uri):
    conn = libvirt.openReadOnly(uri)
    ids = conn.listDomainsID()
    for id in ids:
        rd = 0
        wr = 0
        try:
            dom = conn.lookupByID(id)
            name = dom.name()
        except libvirt.libvirtError as err:
            print("Id: %s: %s" % (id, err), file=sys.stderr)
            continue
        if name == "Domain-0":
            continue
        ifaces = get_ifaces(dom)
        for iface in ifaces:
            try:
                stats = dom.interfaceStats(iface)
                rd += stats[0]
                wr += stats[4]
            except TypeError:
                print("Cannot get ifstats for '%s' on '%s'" % (iface, name), file=sys.stderr)
        print("%s_rx.value %d" % (canon(name), rd))
        print("%s_tx.value %d" % (canon(name), wr))


def main(sys):
    uri = os.getenv("uri", "qemu:///system")

    if len(sys) > 1:
        if sys[1] in ['autoconf', 'detect']:
            if libvirt.openReadOnly(uri):
                print("yes")
                return 0
            else:
                print("no")
                return 1
        elif sys[1] == 'config':
            print_config(uri)
            return 0
    fetch_values(uri)
    return 0


if __name__ == "__main__":
    sys.exit(main(sys.argv))

# vim:et:ts=4:sw=4: