diff --git a/ceilometer/compute/virt/libvirt/inspector.py b/ceilometer/compute/virt/libvirt/inspector.py index d23a7d066..40c767bb9 100644 --- a/ceilometer/compute/virt/libvirt/inspector.py +++ b/ceilometer/compute/virt/libvirt/inspector.py @@ -18,8 +18,10 @@ from lxml import etree from oslo.config import cfg +from oslo.utils import units import six +from ceilometer.compute.pollsters import util from ceilometer.compute.virt import inspector as virt_inspector from ceilometer.openstack.common.gettextutils import _ from ceilometer.openstack.common import log as logging @@ -178,3 +180,35 @@ class LibvirtInspector(virt_inspector.Inspector): write_bytes=block_stats[3], errors=block_stats[4]) yield (disk, stats) + + def inspect_memory_usage(self, instance, duration=None): + instance_name = util.instance_name(instance) + domain = self._lookup_by_name(instance_name) + state = domain.info()[0] + if state == libvirt.VIR_DOMAIN_SHUTOFF: + LOG.warn(_('Failed to inspect memory usage of %(instance_name)s, ' + 'domain is in state of SHUTOFF'), + {'instance_name': instance_name}) + return + + try: + memory_stats = domain.memoryStats() + if (memory_stats and + memory_stats.get('available') and + memory_stats.get('unused')): + memory_used = (memory_stats.get('available') - + memory_stats.get('unused')) + # Stat provided from libvirt is in KB, converting it to MB. + memory_used = memory_used / units.Ki + return virt_inspector.MemoryUsageStats(usage=memory_used) + else: + LOG.warn(_('Failed to inspect memory usage of ' + '%(instance_name)s, can not get info from libvirt'), + {'instance_name': instance_name}) + # memoryStats might launch an exception if the method + # is not supported by the underlying hypervisor being + # used by libvirt + except libvirt.libvirtError as e: + LOG.warn(_('Failed to inspect memory usage of %(instance_name)s, ' + 'can not get info from libvirt: %(error)s'), + {'instance_name': instance_name, 'error': e}) diff --git a/ceilometer/tests/compute/virt/libvirt/test_inspector.py b/ceilometer/tests/compute/virt/libvirt/test_inspector.py index 7162a1c18..429cc741e 100644 --- a/ceilometer/tests/compute/virt/libvirt/test_inspector.py +++ b/ceilometer/tests/compute/virt/libvirt/test_inspector.py @@ -22,6 +22,7 @@ import contextlib import fixtures import mock +from oslo.utils import units from oslotest import base from ceilometer.compute.virt import inspector as virt_inspector @@ -245,6 +246,44 @@ class TestLibvirtInspection(base.BaseTestCase): disks = list(self.inspector.inspect_disks(self.instance_name)) self.assertEqual(disks, []) + def test_inspect_memory_usage(self): + fake_memory_stats = {'available': 51200L, 'unused': 25600L} + connection = self.inspector.connection + with mock.patch.object(connection, 'lookupByName', + return_value=self.domain): + with mock.patch.object(self.domain, 'info', + return_value=(0L, 0L, 51200L, + 2L, 999999L)): + with mock.patch.object(self.domain, 'memoryStats', + return_value=fake_memory_stats): + memory = self.inspector.inspect_memory_usage( + self.instance_name) + self.assertEqual(25600L / units.Ki, memory.usage) + + def test_inspect_memory_usage_with_domain_shutoff(self): + connection = self.inspector.connection + with mock.patch.object(connection, 'lookupByName', + return_value=self.domain): + with mock.patch.object(self.domain, 'info', + return_value=(5L, 0L, 0L, + 2L, 999999L)): + memory = self.inspector.inspect_memory_usage( + self.instance_name) + self.assertIsNone(memory) + + def test_inspect_memory_usage_with_empty_stats(self): + connection = self.inspector.connection + with mock.patch.object(connection, 'lookupByName', + return_value=self.domain): + with mock.patch.object(self.domain, 'info', + return_value=(0L, 0L, 51200L, + 2L, 999999L)): + with mock.patch.object(self.domain, 'memoryStats', + return_value={}): + memory = self.inspector.inspect_memory_usage( + self.instance_name) + self.assertIsNone(memory) + class TestLibvirtInspectionWithError(base.BaseTestCase): diff --git a/doc/source/measurements.rst b/doc/source/measurements.rst index df86b6331..70d8bd607 100644 --- a/doc/source/measurements.rst +++ b/doc/source/measurements.rst @@ -71,7 +71,7 @@ Name Type* Unit Resource Origin** Support** instance g instance inst ID both 1, 2, 3, 4 Existence of instance instance: g instance inst ID both 1, 2, 3, 4 Existence of instance (openstack types) memory g MB inst ID n 1, 2 Volume of RAM allocated in MB -memory.usage g MB inst ID p 3, 4 Volume of RAM used in MB +memory.usage g MB inst ID p 1, 3, 4 Volume of RAM used in MB cpu c ns inst ID p 1, 2 CPU time used cpu_util g % inst ID p 1, 2, 3, 4 Average CPU utilisation vcpus g vcpu inst ID n 1, 2 Number of VCPUs @@ -118,6 +118,12 @@ network.outgoing.packets.rate g packet/s iface ID p 1, 2, 3, [3]: Vsphere support [4]: XenAPI support +.. note:: To enable the libvirt memory.usage supporting, you need libvirt + version 1.1.1+, qemu version 1.5+, and you need to prepare suitable balloon + driver in the image, particularly for Windows guests, most modern Linuxes + have it built in. The memory.usage meters can't be fetched without image + balloon driver. + Contributors are welcome to extend other virtualization backends' meters or complete the existing ones.