Revision 56359d19
b/snf-cyclades-gtools/collectd/README.collectd | ||
---|---|---|
1 |
README |
|
2 |
======= |
|
3 |
snf-cyclades-gtools installs a Python collectd plugin, which collects stats |
|
4 |
about the Ganeti VMs running on the host. |
|
5 |
|
|
6 |
The plugin is installed under /usr/lib/snf-cyclades-gtools/collectd/. |
|
7 |
|
|
8 |
The necessary plugin configuration is performed by |
|
9 |
/etc/collectd/ganeti-stats.conf. |
|
10 |
|
|
11 |
To enable the plugin, add in your original collectd configuration file the |
|
12 |
following line: |
|
13 |
|
|
14 |
Include /etc/collectd/ganeti-stats.conf |
|
15 |
|
|
16 |
An example collectd configuration, which enables the plugin, is also installed |
|
17 |
in /usr/shared/doc/snf-cyclades-gtools/examples/ganeti-stats-collectd.conf. |
b/snf-cyclades-gtools/collectd/conf/ganeti-stats.conf | ||
---|---|---|
1 |
<LoadPlugin python> |
|
2 |
Globals true |
|
3 |
</LoadPlugin> |
|
4 |
<Plugin python> |
|
5 |
ModulePath "/usr/lib/snf-cyclades-gtools/collectd/" |
|
6 |
LogTraces true |
|
7 |
Interactive false |
|
8 |
Import "ganeti-stats" |
|
9 |
</Plugin> |
b/snf-cyclades-gtools/collectd/examples/ganeti-stats-collectd.conf | ||
---|---|---|
1 |
FQDNLookup true |
|
2 |
|
|
3 |
LoadPlugin syslog |
|
4 |
<Plugin syslog> |
|
5 |
LogLevel info |
|
6 |
</Plugin> |
|
7 |
|
|
8 |
LoadPlugin network |
|
9 |
<Plugin network> |
|
10 |
<Server "host" "25826"> |
|
11 |
SecurityLevel "Encrypt" |
|
12 |
Username "user" |
|
13 |
Password "pass" |
|
14 |
</Server> |
|
15 |
TimeToLive 128 |
|
16 |
ReportStats false |
|
17 |
MaxPacketSize 65535 |
|
18 |
CacheFlush 1800 |
|
19 |
</Plugin> |
|
20 |
|
|
21 |
<LoadPlugin python> |
|
22 |
Globals true |
|
23 |
</LoadPlugin> |
|
24 |
<Plugin python> |
|
25 |
ModulePath "/usr/lib/snf-cyclades-gtools/collectd/" |
|
26 |
LogTraces true |
|
27 |
Interactive false |
|
28 |
Import "ganeti-stats" |
|
29 |
</Plugin> |
|
30 |
|
|
31 |
Include "/etc/collectd/filters.conf" |
|
32 |
Include "/etc/collectd/thresholds.conf" |
b/snf-cyclades-gtools/collectd/plugins/ganeti-stats.py | ||
---|---|---|
1 |
#!/usr/bin/env python |
|
2 |
|
|
3 |
import os |
|
4 |
import collectd |
|
5 |
|
|
6 |
from hashlib import md5 |
|
7 |
|
|
8 |
from glob import glob |
|
9 |
|
|
10 |
|
|
11 |
def read_int(file): |
|
12 |
f = open(file, "r") |
|
13 |
try: |
|
14 |
val = int(f.read()) |
|
15 |
except ValueError: |
|
16 |
val = None |
|
17 |
finally: |
|
18 |
f.close() |
|
19 |
|
|
20 |
return val |
|
21 |
|
|
22 |
|
|
23 |
def anonymize_hostname(hostname): |
|
24 |
#return md5(hostname).hexdigest() |
|
25 |
return hostname |
|
26 |
|
|
27 |
|
|
28 |
def get_vcpus(pid): |
|
29 |
"""Get a KVM instance vCPU count by looking at its fd's""" |
|
30 |
vcpus = 0 |
|
31 |
for fd in glob("/proc/%d/fd/*" % pid): |
|
32 |
# XXX: sad but trueeeeeeeeeeee |
|
33 |
if os.readlink(fd) == "anon_inode:kvm-vcpu": |
|
34 |
vcpus += 1 |
|
35 |
return vcpus |
|
36 |
|
|
37 |
|
|
38 |
def netstats(data=None): |
|
39 |
for dir in glob("/var/run/ganeti/kvm-hypervisor/nic/*"): |
|
40 |
if not os.path.isdir(dir): |
|
41 |
continue |
|
42 |
|
|
43 |
hostname = os.path.basename(dir) |
|
44 |
|
|
45 |
for nic in glob(os.path.join(dir, "*")): |
|
46 |
idx = int(os.path.basename(nic)) |
|
47 |
with open(nic) as nicfile: |
|
48 |
try: |
|
49 |
iface = nicfile.readline().strip() |
|
50 |
except EnvironmentError: |
|
51 |
continue |
|
52 |
|
|
53 |
if not os.path.isdir("/sys/class/net/%s" % iface): |
|
54 |
continue |
|
55 |
|
|
56 |
bytes_in = read_int("/sys/class/net/%s/statistics/rx_bytes" % iface) |
|
57 |
bytes_out = read_int("/sys/class/net/%s/statistics/tx_bytes" % iface) |
|
58 |
|
|
59 |
vl = collectd.Values(type="counter") |
|
60 |
vl.host = anonymize_hostname(hostname) |
|
61 |
vl.plugin = "interface" |
|
62 |
vl.type = "if_octets" |
|
63 |
vl.type_instance = "eth%d" % idx |
|
64 |
vl.dispatch(values=[bytes_out, bytes_in]) |
|
65 |
|
|
66 |
|
|
67 |
def cpustats(data=None): |
|
68 |
for file in glob("/var/run/ganeti/kvm-hypervisor/pid/*"): |
|
69 |
instance = os.path.basename(file) |
|
70 |
try: |
|
71 |
pid = int(open(file, "r").read()) |
|
72 |
proc = open("/proc/%d/stat" % pid, "r") |
|
73 |
cputime = [int(proc.readline().split()[42])] |
|
74 |
except EnvironmentError: |
|
75 |
continue |
|
76 |
vcpus = get_vcpus(pid) |
|
77 |
proc.close() |
|
78 |
|
|
79 |
vl = collectd.Values(type="counter") |
|
80 |
vl.host = anonymize_hostname(instance) |
|
81 |
vl.plugin = "cpu" |
|
82 |
vl.type = "virt_cpu_total" |
|
83 |
total = sum(cputime) * 100 / (vcpus * os.sysconf("SC_CLK_TCK")) |
|
84 |
vl.dispatch(values=[total]) |
|
85 |
|
|
86 |
collectd.register_read(netstats) |
|
87 |
collectd.register_read(cpustats) |
|
88 |
|
|
89 |
# vim: set ts=4 sts=4 et sw=4 : |
Also available in: Unified diff