Skip to content

Commit

Permalink
mdadm and vms (libvirt) monitoring plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
vfuse committed Feb 26, 2018
1 parent 3ba9555 commit dee6b34
Show file tree
Hide file tree
Showing 4 changed files with 231 additions and 5 deletions.
2 changes: 1 addition & 1 deletion nixstatsagent/nixstatsagent.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import urllib2


__version__ = '1.1.38'
__version__ = '1.1.39'

__FILEABSDIRNAME__ = os.path.dirname(os.path.abspath(__file__))

Expand Down
46 changes: 46 additions & 0 deletions nixstatsagent/plugins/mdstat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import plugins
import json


class Plugin(plugins.BasePlugin):
__name__ = 'mdstat'

def run(self, config):
'''
Monitor software raid status using mdadm
pip install mdstat
'''
data = os.popen('sudo mdjson').read()
results = {}

try:
data = json.loads(data)
except Exception:
return "Could not load mdstat data"

for key, value in data['devices'].items():
device = {}
if(value['active'] is not True):
device['active'] = 0
else:
device['active'] = 1
if(value['read_only'] is not False):
device['read_only'] = 1
else:
device['read_only'] = 0
if(value['resync'] is not None):
device['resync'] = 1
else:
device['resync'] = 0
device['faulty'] = 0
for disk, diskvalue in value['disks'].items():
if diskvalue['faulty'] is not False:
device['faulty'] = device['faulty'] + 1
results[key] = device
return results

if __name__ == '__main__':
Plugin().execute()
8 changes: 4 additions & 4 deletions nixstatsagent/plugins/mysql.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,21 +111,21 @@ def run(self, config):
)
results = dict()
data = dict()
constructors = [int, float, str]
constructors = [str, float]
for key, value in query_result:
key = key.lower()
key = key.lower().strip()
for c in constructors:
try:
value = c(value)
except ValueError:
pass
if key in non_delta:
results[key] = value
elif key in delta_keys:
elif key in delta_keys and type(value) is not str:
results[key] = self.absolute_to_per_second(key, float(value), prev_cache)
data[key] = float(value)
else:
continue
pass
db.close()
data['ts'] = time.time()
self.set_agent_cache(data)
Expand Down
180 changes: 180 additions & 0 deletions nixstatsagent/plugins/vms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import re, sys, os
import libvirt
import libxml2
import time
import plugins

class Plugin(plugins.BasePlugin):
__name__ = 'vms'

def run(self, config):
'''
Using the libvirt API to fetch statistics from guests
running KVM, QEMU, Xen, Virtuozzo, VMWare ESX, LXC,
BHyve and more
'''
results = {}
last_value = {}
prev_cache = self.get_agent_cache() # Get absolute values from previous check
uri = os.getenv("uri", "qemu:///system")
values = self.fetch_values(uri)

for key, value in values.items():
deltas = {}
for subkey, subvalue in value.items():
deltas[key][subkey] = self.absolute_to_per_second('%s_%s' % (key, subkey), float(subvalue), prev_cache)
last_value['%s_%s' % (key, subkey)] = float(value[subkey])
last_value['ts'] = time.time()
self.set_agent_cache(last_value)
return results

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

def get_ifaces(self, dom):
xml = dom.XMLDesc(0)
doc = None
try:
doc = libxml2.parseDoc(xml)
except:
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 == None:
continue
ifaces.append(devdst)
finally:
if ctx != None:
ctx.xpathFreeContext()
if doc != None:
doc.freeDoc()
return ifaces

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

try:
doc = libxml2.parseDoc(xml)
except:
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 != None:
ctx.xpathFreeContext()
if doc != None:
doc.freeDoc()
return memtune

def fetch_values(self, uri):
conn = libvirt.openReadOnly(uri)
ids = conn.listDomainsID()
results = {}
processors = float(conn.getInfo()[2])
data = {}
for id in ids:
data['net_rx'] = 0
data['net_tx'] = 0
try:
dom = conn.lookupByID(id)
name = dom.name()
except libvirt.libvirtError, err:
print >>sys.stderr, "Id: %s: %s" % (id, err)
continue
if name == "Domain-0":
continue
ifaces = self.get_ifaces(dom)
for iface in ifaces:
try:
stats = dom.interfaceStats(iface)
data['net_rx'] += stats[0]
data['net_tx'] += stats[4]
except:
print >>sys.stderr, "Cannot get ifstats for '%s' on '%s'" % (iface, name)

cputime = float(dom.info()[4])
cputime_percentage = 1.0e-7 * cputime / processors
data['cpu'] = cputime_percentage

maxmem, mem = dom.info()[1:3]
mem *= 1024
maxmem *= 1024
data['mem'] = mem
memtune = self.get_memtune(dom)
data['min_guarantee'] = memtune['min_guarantee'] * 1024
data['hard_limit'] = memtune['hard_limit'] * 1024
data['soft_limit'] = memtune['soft_limit'] * 1024

data['disk_rd'] = 0
data['disk_wr'] = 0
data['disk_wr_req'] = 0
data['disk_rd_req'] = 0
try:
dom = conn.lookupByID(id)
name = dom.name()
except libvirt.libvirtError, err:
print >>sys.stderr, "Id: %s: %s" % (id, err)
continue
if name == "Domain-0":
continue
disks = self.get_disks(dom)
for disk in disks:
try:
rd_req, rd_bytes, wr_req, wr_bytes, errs = dom.blockStats(disk)
data['disk_rd'] += rd_bytes
data['disk_wr'] += wr_bytes
data['disk_rd_req'] += rd_req
data['disk_wr_req'] += wr_req
except TypeError:
print >>sys.stderr, "Cannot get blockstats for '%s' on '%s'" % (disk, name)

results[self.canon(name)] = data
return results

def get_disks(self, dom):
xml = dom.XMLDesc(0)
doc = None
try:
doc = libxml2.parseDoc(xml)
except:
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 == None:
continue
disks.append(devdst)
finally:
if ctx != None:
ctx.xpathFreeContext()
if doc != None:
doc.freeDoc()
return disks


if __name__ == '__main__':
Plugin().execute()

0 comments on commit dee6b34

Please sign in to comment.