Add memory.resident libvirt meter for Ceilometer

The 'memory.resident' metric will expose the
physical hosts view of the amount of host memory that is actually used to
run the VM process

DocImpact: https://review.openstack.org/#/c/164724

Change-Id: I9f2ad784479f234679e1145efd96d9d707dd19d0
Implements: blueprint memory-resident
This commit is contained in:
vivek.nandavanam 2015-03-13 11:00:37 -07:00
parent b5cfcb620c
commit a2c650b478
5 changed files with 106 additions and 1 deletions

View File

@ -16,7 +16,7 @@ import ceilometer
from ceilometer.compute import pollsters
from ceilometer.compute.pollsters import util
from ceilometer.compute.virt import inspector as virt_inspector
from ceilometer.i18n import _, _LW
from ceilometer.i18n import _, _LW, _LE
from ceilometer.openstack.common import log
from ceilometer import sample
@ -63,3 +63,46 @@ class MemoryUsagePollster(pollsters.BaseComputePollster):
LOG.exception(_('Could not get Memory Usage for '
'%(id)s: %(e)s'), {'id': instance.id,
'e': err})
class MemoryResidentPollster(pollsters.BaseComputePollster):
def get_samples(self, manager, cache, resources):
self._inspection_duration = self._record_poll_time()
for instance in resources:
LOG.debug(_('Checking resident memory for instance %s'),
instance.id)
try:
memory_info = self.inspector.inspect_memory_resident(
instance, self._inspection_duration)
LOG.debug(_("RESIDENT MEMORY: %(instance)s %(resident)f"),
({'instance': instance.__dict__,
'resident': memory_info.resident}))
yield util.make_sample_from_instance(
instance,
name='memory.resident',
type=sample.TYPE_GAUGE,
unit='MB',
volume=memory_info.resident,
)
except virt_inspector.InstanceNotFoundException as err:
# Instance was deleted while getting samples. Ignore it.
LOG.debug(_('Exception while getting samples %s'), err)
except virt_inspector.InstanceShutOffException as e:
LOG.warn(_LW('Instance %(instance_id)s was shut off while '
'getting samples of %(pollster)s: %(exc)s'),
{'instance_id': instance.id,
'pollster': self.__class__.__name__, 'exc': e})
except virt_inspector.NoDataException as e:
LOG.warn(_LW('Cannot inspect data of %(pollster)s for '
'%(instance_id)s, non-fatal reason: %(exc)s'),
{'pollster': self.__class__.__name__,
'instance_id': instance.id, 'exc': e})
except ceilometer.NotImplementedError:
# Selected inspector does not implement this pollster.
LOG.debug(_('Obtaining Resident Memory is not implemented'
' for %s'), self.inspector.__class__.__name__)
except Exception as err:
LOG.exception(_LE('Could not get Resident Memory Usage for '
'%(id)s: %(e)s'), {'id': instance.id,
'e': err})

View File

@ -63,6 +63,14 @@ CPUUtilStats = collections.namedtuple('CPUUtilStats', ['util'])
MemoryUsageStats = collections.namedtuple('MemoryUsageStats', ['usage'])
# Named tuple representing Resident Memory usage statistics.
#
# resident: Amount of resident memory
#
MemoryResidentStats = collections.namedtuple('MemoryResidentStats',
['resident'])
# Named tuple representing vNICs.
#
# name: the name of the vNIC

View File

@ -212,3 +212,8 @@ class LibvirtInspector(virt_inspector.Inspector):
physical=block_info[2])
yield (disk, info)
def inspect_memory_resident(self, instance, duration=None):
domain = self._get_domain_not_shut_off_or_raise(instance)
memory = domain.memoryStats()['rss'] / units.Ki
return virt_inspector.MemoryResidentStats(resident=memory)

View File

@ -64,3 +64,51 @@ class TestMemoryPollster(base.TestPollsterBase):
_verify_memory_metering(1, 2.0)
_verify_memory_metering(0, 0)
_verify_memory_metering(0, 0)
class TestResidentMemoryPollster(base.TestPollsterBase):
def setUp(self):
super(TestResidentMemoryPollster, self).setUp()
@mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock())
def test_get_samples(self):
next_value = iter((
virt_inspector.MemoryResidentStats(resident=1.0),
virt_inspector.MemoryResidentStats(resident=2.0),
virt_inspector.NoDataException(),
virt_inspector.InstanceShutOffException(),
))
def inspect_memory_resident(instance, duration):
value = next(next_value)
if isinstance(value, virt_inspector.MemoryResidentStats):
return value
else:
raise value
self.inspector.inspect_memory_resident = mock.Mock(
side_effect=inspect_memory_resident)
mgr = manager.AgentManager()
pollster = memory.MemoryResidentPollster()
@mock.patch('ceilometer.compute.pollsters.memory.LOG')
def _verify_resident_memory_metering(expected_count,
expected_resident_memory_mb,
mylog):
samples = list(pollster.get_samples(mgr, {}, [self.instance]))
self.assertEqual(expected_count, len(samples))
if expected_count > 0:
self.assertEqual(set(['memory.resident']),
set([s.name for s in samples]))
self.assertEqual(expected_resident_memory_mb,
samples[0].volume)
else:
self.assertEqual(1, mylog.warn.call_count)
self.assertEqual(0, mylog.exception.call_count)
_verify_resident_memory_metering(1, 1.0)
_verify_resident_memory_metering(1, 2.0)
_verify_resident_memory_metering(0, 0)
_verify_resident_memory_metering(0, 0)

View File

@ -142,6 +142,7 @@ ceilometer.poll.compute =
instance = ceilometer.compute.pollsters.instance:InstancePollster
instance_flavor = ceilometer.compute.pollsters.instance:InstanceFlavorPollster
memory.usage = ceilometer.compute.pollsters.memory:MemoryUsagePollster
memory.resident = ceilometer.compute.pollsters.memory:MemoryResidentPollster
disk.capacity = ceilometer.compute.pollsters.disk:CapacityPollster
disk.allocation = ceilometer.compute.pollsters.disk:AllocationPollster
disk.usage = ceilometer.compute.pollsters.disk:PhysicalPollster