aboutsummaryrefslogtreecommitdiff
path: root/libvirt-blkstat
blob: 37be14dda0b1530702edbccf03915ea91e1bf408 (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
131
#!/usr/bin/python3
# vim: set fileencoding=utf-8 :
#
# Munin plugin to show the I/O load of libvirt managed virtual machines
#
# Copyright 2008 Guido Guenther <agx@sigxcpu.org>
#
# Licesnse: 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 Block Device I/O
graph_vlabel Bytes read (-)/ written (+) per ${graph_period}
graph_category Virtual Machines
graph_info This graph shows the block device 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_read.label %s" % (canon(name), name))
        print("%s_read.type DERIVE" % canon(name))
        print("%s_read.min 0" % canon(name))
        print("%s_read.graph no" % canon(name))
        print("%s_read.draw LINE1" % canon(name))
        print("%s_write.label %s" % (canon(name), name))
        print("%s_write.type DERIVE" % canon(name))
        print("%s_write.min 0" % canon(name))
        print("%s_write.negative %s_read" % (canon(name), canon(name)))
        print("%s_write.draw LINE1" % canon(name))


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


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
        disks = get_disks(dom)
        for disk in disks:
            try:
                rd_req, rd_bytes, wr_req, wr_bytes, errs = dom.blockStats(disk)

                rd += rd_bytes
                wr += wr_bytes
            except TypeError:
                print("Cannot get blockstats for '%s' on '%s'" % (disk, name), file=sys.stderr)
        print("%s_read.value %d" % (canon(name), rd))
        print("%s_write.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: