Created
August 10, 2017 16:39
-
-
Save logan2211/8acd19670dabf3c24fa2990bbb207099 to your computer and use it in GitHub Desktop.
Diamond Openstack libvirt plugin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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