aboutsummaryrefslogtreecommitdiff
path: root/libvirt-mem
blob: a789326a95cec41a5876adab80a2e0803a4aaeaf (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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#!/usr/bin/python3
# vim: set fileencoding=utf-8 :
#
# Munin plugin to show the amount of memory used by libvirt managed virtual
# machines
#
# Copyright 2008,2012 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 libxml2
import libvirt


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


def print_config(uri):
    """print the plugin config, determine the domains"""
    try:
        conn = libvirt.openReadOnly(uri)
    except libvirt.libvirtError as err:
        print("Error opening to %s connection: %s" % (uri, err), file=sys.stderr)
        return 1

    hostname = conn.getHostname()

    print("""graph_title Virtual Domain Memory Usage
graph_vlabel Memory Usage / Bytes
graph_category Virtual Machines
graph_info This graph shows the current amount of memory used by each virtual machine
graph_args --base 1024 -l 0""")

    ids = conn.listDomainsID()
    draw = "AREA"
    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_mem.label %s" % (canon(name), name))
        print("%s_mem.type GAUGE" % canon(name))
        print("%s_mem.min 0" % canon(name))
        print("%s_mem.draw %s" % (canon(name), draw))
        print("%s_mem.info memory used by virtual machine '%s'" % (canon(name), name))
        if draw == "AREA":
            draw = "STACK"

    print("""
host_mem.label %(hostname)s (host)
host_mem.type GAUGE
host_mem.min 0
host_mem.draw LINE1
host_mem.info total memory of host '%(hostname)s'
total.type GAUGE
total.label total memory
total.info total memory used by virtual machines on host '%(hostname)s'
total.graph no
total.min 0
total_pc.type GAUGE
total_pc.label used memory percentage
total_pc.info memory in percent used by virtual machines on host '%(hostname)s'
total_pc.graph no
total_pc.min 0
total_pc.max 100
total_pc.warning 90
total_pc.critical 95
total_max.type GAUGE
total_max.label total max. mem
total_max.info maximum memory virtual machines can balloon to on host '%(hostname)s'
total_max.min 0
total_max_pc.type GAUGE
total_max_pc.label total maximum memory percentage
total_max_pc.graph no
total_max_pc.info maximum memory in percent virtual machines can balloon to on host '%(hostname)s'
total_max_pc.min 0
total_min_guarantee.type GAUGE
total_min_guarantee.label total mem minimum guarantee
total_min_guarantee.info min_guarantee minimum amount of memory guaranteed to all virtual machines on host '%(hostname)s'
total_min_guarantee.min 0
total_min_guarantee_pc.type GAUGE
total_min_guarantee_pc.label total mem minimum guarantee percentage
total_min_guarantee_pc.graph no
total_min_guarantee_pc.info min_guarantee minimum amount of memory in percent guaranteed to all virtual machines on host '%(hostname)s'
total_min_guarantee_pc.min 0
total_hard_limit.type GAUGE
total_hard_limit.label total mem hard limit
total_hard_limit.info memory hard_limit of all virtual machines on host '%(hostname)s'
total_hard_limit.min 0
total_hard_limit_pc.type GAUGE
total_hard_limit_pc.label total mem hard limit percentage
total_hard_limit_pc.graph no
total_hard_limit_pc.info memory hard_limit percentage of all virtual machines on host '%(hostname)s'
total_hard_limit_pc.min 0
total_soft_limit.type GAUGE
total_soft_limit.label total mem soft limit
total_soft_limit.info memory soft_limit of all virtual machines on host '%(hostname)s'
total_soft_limit.min 0
total_soft_limit_pc.type GAUGE
total_soft_limit_pc.label total mem soft limit percentage
total_soft_limit_pc.graph no
total_soft_limit_pc.info memory soft_limit percentage of all virtual machines on host '%(hostname)s'
total_soft_limit_pc.min 0

""" % dict(hostname=hostname))

    return 0


def get_memtune(dom):
    memtune = {'min_guarantee': 0, 'soft_limit': 0, 'hard_limit': 0}
    xml = dom.XMLDesc(0)

    try:
        doc = libxml2.parseDoc(xml)
    except Exception:
        return []

    ctx = doc.xpathNewContext()
    try:
        for key in memtune:
            ret = ctx.xpathEval("/domain/memtune/%s" % key)
            try:
                for child in ret[0].children:
                    memtune[key] = int(child.content)
                    break
            except IndexError:
                # key not found in xml
                pass
    finally:
        if ctx is not None:
            ctx.xpathFreeContext()
        if doc is not None:
            doc.freeDoc()
    return memtune


def fetch_values(uri):
    """Fetch values in the <memtune/> block"""
    total = 0
    total_max = 0
    min_guarantee = 0
    hard_limit = 0
    soft_limit = 0

    try:
        conn = libvirt.openReadOnly(uri)
    except libvirt.libvirtError as err:
        print("Error opening to %s connection: %s" % (uri, err), file=sys.stderr)
        return 1
    ids = conn.listDomainsID()
    hostmem = conn.getInfo()[1] * 1024 * 1024
    print("host_mem.value %d" % hostmem)
    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
        maxmem, mem = dom.info()[1:3]
        mem *= 1024
        maxmem *= 1024
        total += mem
        total_max += maxmem
        print("%s_mem.value %d" % (canon(name), mem))
        memtune = get_memtune(dom)
        min_guarantee += memtune['min_guarantee'] * 1024
        hard_limit += memtune['hard_limit'] * 1024
        soft_limit += memtune['soft_limit'] * 1024

    print("total.value %d" % total)
    print("total_pc.value %.0f" % (100.0 * total / float(hostmem)))
    print("total_max.value %d" % total_max)
    print("total_max_pc.value %.0f" % (100.0 * total_max / float(hostmem)))
    print("total_min_guarantee.value %d" % min_guarantee)
    print("total_min_guarantee_pc.value %.0f" % (100.0 * min_guarantee / float(hostmem)))
    print("total_soft_limit.value %d" % soft_limit)
    print("total_soft_limit_pc.value %.0f" % (100.0 * soft_limit / float(hostmem)))
    print("total_hard_limit.value %d" % hard_limit)
    print("total_hard_limit_pc.value %.0f" % (100.0 * hard_limit / float(hostmem)))
    return 0


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':
            return print_config(uri)
    return fetch_values(uri)


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

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