From ad54ed53cf6a475ad0f8042f8b95454a8c0b35a4 Mon Sep 17 00:00:00 2001 From: Leander Bessa Beernaert Date: Fri, 22 Jun 2012 12:08:08 +0100 Subject: Adds diagnostics command for the libvirt driver. This code provides an implementation of the get_diagnostics API for the libvirt driver. This API is invoked by the 'nova diagnostic' command. There is no existing formal specification for what data items to expose from the 'get_diagnostics' API, so the XenAPI driver is used as an informal guide. The Xen implementation currently produces the following output: +----------------+-----------------+ | Property | Value | +----------------+-----------------+ | cpu0 | 4.3627 | | memory | 1171088064.0000 | | memory_target | 1171088064.0000 | | vbd_xvda_read | 0.0 | | vbd_xvda_write | 0.0 | | vif_0_rx | 3223.6870 | | vif_0_tx | 0.0 | | vif_1_rx | 104.4955 | | vif_1_tx | 0.0 | +----------------+-----------------+ The new libvirt implementation will return a similar set of stats for guest CPUs, memory, disks and network interfaces, resulting in the following output: +------------------+------------+ | Property | Value | +------------------+------------+ | cpu0_time | 2870000000 | | memory | 524288 | | vda_errors | -1 | | vda_read | 262144 | | vda_read_req | 112 | | vda_write | 5606400 | | vda_write_req | 376 | | vnet0_rx | 63343 | | vnet0_rx_drop | 0 | | vnet0_rx_errors | 0 | | vnet0_rx_packets | 431 | | vnet0_tx | 4905 | | vnet0_tx_drop | 0 | | vnet0_tx_errors | 0 | | vnet0_tx_packets | 45 | +------------------+------------+ The implementation has only been tested with the libvirt KVM driver. In a future a formal specification for the required data format should be written and all virt drivers made to comply. Finally, the fakelibvirt driver has been updated in order to support the methods required by the get_diagnostics method. For those interested, below is the formula to extract the CPU usage based on the CPU time. I've added it here for reference since it's not used at the moment and it took quite a while to locate it in the libvirt documentation. usage = 100 * (current_cpu_time - last_cpu_time) / (measurement_interval * (10 ** 9)) Fixes bug 986200. Change-Id: I92da392f43d0840ed31cfd88f54570ea5830bb4a --- nova/virt/libvirt/driver.py | 75 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) (limited to 'nova/virt') diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 14f5620c9..96bcecdf8 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -5,6 +5,7 @@ # All Rights Reserved. # Copyright (c) 2010 Citrix Systems, Inc. # Copyright (c) 2011 Piston Cloud Computing, Inc +# Copyright (c) 2012 University Of Minho # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -2715,6 +2716,80 @@ class LibvirtDriver(driver.ComputeDriver): """Confirms a resize, destroying the source VM""" self._cleanup_resize(instance) + def get_diagnostics(self, instance): + def get_io_devices(xml_doc): + """ get the list of io devices from the + xml document.""" + result = {"volumes": [], "ifaces": []} + try: + doc = etree.fromstring(xml_doc) + except Exception: + return result + blocks = [('./devices/disk', 'volumes'), + ('./devices/interface', 'ifaces')] + for block, key in blocks: + section = doc.findall(block) + for node in section: + for child in node.getchildren(): + if child.tag == 'target' and child.get('dev'): + result[key].append(child.get('dev')) + return result + + domain = self._lookup_by_name(instance['name']) + output = {} + # get cpu time, might launch an exception if the method + # is not supported by the underlying hypervisor being + # used by libvirt + try: + cputime = domain.vcpus()[0] + for i in range(len(cputime)): + output["cpu" + str(i) + "_time"] = cputime[i][2] + except libvirt.libvirtError: + pass + # get io status + xml = domain.XMLDesc(0) + dom_io = get_io_devices(xml) + for disk in dom_io["volumes"]: + try: + # blockStats might launch an exception if the method + # is not supported by the underlying hypervisor being + # used by libvirt + stats = domain.blockStats(disk) + output[disk + "_read_req"] = stats[0] + output[disk + "_read"] = stats[1] + output[disk + "_write_req"] = stats[2] + output[disk + "_write"] = stats[3] + output[disk + "_errors"] = stats[4] + except libvirt.libvirtError: + pass + for interface in dom_io["ifaces"]: + try: + # interfaceStats might launch an exception if the method + # is not supported by the underlying hypervisor being + # used by libvirt + stats = domain.interfaceStats(interface) + output[interface + "_rx"] = stats[0] + output[interface + "_rx_packets"] = stats[1] + output[interface + "_rx_errors"] = stats[2] + output[interface + "_rx_drop"] = stats[3] + output[interface + "_tx"] = stats[4] + output[interface + "_tx_packets"] = stats[5] + output[interface + "_tx_errors"] = stats[6] + output[interface + "_tx_drop"] = stats[7] + except libvirt.libvirtError: + pass + output["memory"] = domain.maxMemory() + # memoryStats might launch an exception if the method + # is not supported by the underlying hypervisor being + # used by libvirt + try: + mem = domain.memoryStats() + for key in mem.keys(): + output["memory-" + key] = mem[key] + except libvirt.libvirtError: + pass + return output + class HostState(object): """Manages information about the compute node through libvirt""" -- cgit