Skip to content

Instantly share code, notes, and snippets.

@logan2211
Created August 10, 2017 16:39
Show Gist options
  • Save logan2211/8acd19670dabf3c24fa2990bbb207099 to your computer and use it in GitHub Desktop.
Save logan2211/8acd19670dabf3c24fa2990bbb207099 to your computer and use it in GitHub Desktop.
Diamond Openstack libvirt plugin
# coding=utf-8
"""
Rewritten Libvirt centered around collecting Openstack
Nova VM statistics on a KVM hypervisor.
#### Dependencies
* python-libvirt, xml
"""
import diamond.collector
try:
from xml.etree import ElementTree
except ImportError:
import cElementTree as ElementTree
try:
import libvirt
except ImportError:
libvirt = None
class OpenstackLibvirtCollector(diamond.collector.Collector):
blockStats = {
'read_reqs': 0,
'read_bytes': 1,
'write_reqs': 2,
'write_bytes': 3,
'errors': 4
}
vifStats = {
'rx_bytes': 0,
'rx_packets': 1,
'rx_errors': 2,
'rx_drops': 3,
'tx_bytes': 4,
'tx_packets': 5,
'tx_errors': 6,
'tx_drops': 7
}
def get_default_config_help(self):
config_help = super(OpenstackLibvirtCollector, self).get_default_config_help()
config_help.update({
'uri': """The libvirt connection URI. By default it's
'qemu:///system'. One decent option is
'qemu+unix:///system?socket=/var/run/libvirt/libvit-sock-ro'."""
})
return config_help
def get_default_config(self):
"""
Returns the default collector settings
"""
config = super(OpenstackLibvirtCollector, self).get_default_config()
config.update({
'path': 'libvirt',
'uri': 'qemu:///system',
})
return config
def get_devices(self, dom, type):
devices = []
# Create a XML tree from the domain XML description.
tree = ElementTree.fromstring(dom.XMLDesc(0))
for target in tree.findall("devices/%s/target" % type):
dev = target.get("dev")
if dev not in devices:
devices.append(dev)
return devices
def nova_metadata(self, dom):
metadata = ElementTree.fromstring(
dom.metadata(libvirt.VIR_DOMAIN_METADATA_ELEMENT,
"http://openstack.org/xmlns/libvirt/nova/1.0"))
return {
"name": metadata.find("name").text,
"project": {
"uuid": metadata.find("owner/project").get("uuid"),
"name": metadata.find("owner/project").text
}
}
def get_disk_devices(self, dom):
return self.get_devices(dom, 'disk')
def get_network_devices(self, dom):
return self.get_devices(dom, 'interface')
def collect(self):
if libvirt is None:
self.log.error('Unable to import libvirt')
return {}
conn = libvirt.openReadOnly(self.config['uri'])
for dom in [conn.lookupByID(n) for n in conn.listDomainsID()]:
name = dom.UUIDString()
project_id = self.nova_metadata(dom)['project']['uuid'] or ''
# CPU stats
vcpus = dom.vcpus()[0]
total_cpu_time = 0
for vcpu in dom.vcpus()[0]:
'''
States are:
libvirt.VIR_VCPU_OFFLINE (0)
libvirt.VIR_VCPU_RUNNING (1)
libvirt.VIR_VCPU_BLOCKED (2)
'''
state = vcpu[1]
cpu_time = vcpu[2]
total_cpu_time += cpu_time
cpu_number = vcpu[3]
self.publish('%s.vcpu.%s.state' % (project_id, cpu_number),
state, instance=name)
self.publish('%s.vcpu.%s.cputime' % (project_id, cpu_number),
cpu_time, instance=name)
self.publish('%s.vcpu.total.cputime' % project_id, total_cpu_time,
instance=name)
# Disk stats
disks = self.get_disk_devices(dom)
accum = {}
for stat in self.blockStats.keys():
accum[stat] = 0
for disk in disks:
stats = dom.blockStats(disk)
for stat in self.blockStats.keys():
idx = self.blockStats[stat]
val = stats[idx]
accum[stat] += val
self.publish('%s.block.%s.%s' % (project_id, disk, stat),
val, instance=name)
for stat in self.blockStats.keys():
self.publish('%s.block.total.%s' % (project_id, stat),
accum[stat], instance=name)
# Network stats
vifs = self.get_network_devices(dom)
accum = {}
for stat in self.vifStats.keys():
accum[stat] = 0
for vif in vifs:
stats = dom.interfaceStats(vif)
for stat in self.vifStats.keys():
idx = self.vifStats[stat]
val = stats[idx]
accum[stat] += val
self.publish('%s.net.%s.%s' % (project_id, vif, stat),
val, instance=name)
for stat in self.vifStats.keys():
self.publish('%s.net.total.%s' % (project_id, stat),
accum[stat], instance=name)
# Memory stats
mem = dom.memoryStats()
self.publish('%s.memory.nominal' % project_id, mem['actual'] * 1024,
instance=name)
self.publish('%s.memory.rss' % project_id, mem['rss'] * 1024,
instance=name)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment