diff --git a/ceilometer/compute/virt/xenapi/inspector.py b/ceilometer/compute/virt/xenapi/inspector.py index 62960da3d9..9632cbaec9 100644 --- a/ceilometer/compute/virt/xenapi/inspector.py +++ b/ceilometer/compute/virt/xenapi/inspector.py @@ -135,12 +135,23 @@ class XenapiInspector(virt_inspector.Inspector): def inspect_memory_usage(self, instance, duration=None): instance_name = util.instance_name(instance) vm_ref = self._lookup_by_name(instance_name) - metrics_ref = self._call_xenapi("VM.get_metrics", vm_ref) - metrics_rec = self._call_xenapi("VM_metrics.get_record", - metrics_ref) - # Stat provided from XenServer is in B, converting it to MB. - memory = int(metrics_rec['memory_actual']) / units.Mi - return virt_inspector.MemoryUsageStats(usage=memory) + total_mem = float(self._call_xenapi("VM.query_data_source", + vm_ref, + "memory")) + try: + free_mem = float(self._call_xenapi("VM.query_data_source", + vm_ref, + "memory_internal_free")) + except api.Failure: + # If PV tools is not installed in the guest instance, it's + # impossible to get free memory. So give it a default value + # as 0. + free_mem = 0 + # memory provided from XenServer is in Bytes; + # memory_internal_free provided from XenServer is in KB, + # converting it to MB. + memory_usage = (total_mem - free_mem * units.Ki) / units.Mi + return virt_inspector.MemoryUsageStats(usage=memory_usage) def inspect_vnic_rates(self, instance, duration=None): instance_name = util.instance_name(instance) diff --git a/ceilometer/tests/unit/compute/virt/xenapi/fake_XenAPI.py b/ceilometer/tests/unit/compute/virt/xenapi/fake_XenAPI.py new file mode 100644 index 0000000000..1f33f78489 --- /dev/null +++ b/ceilometer/tests/unit/compute/virt/xenapi/fake_XenAPI.py @@ -0,0 +1,19 @@ +# Copyright 2016 Citrix +# +# 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 +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +"""fake XenAPI for testing in case XenAPI doesn't exist in the test env""" + + +class Failure(Exception): + def __init__(self, details): + self.details = details diff --git a/ceilometer/tests/unit/compute/virt/xenapi/test_inspector.py b/ceilometer/tests/unit/compute/virt/xenapi/test_inspector.py index d84853babc..caa1c93793 100644 --- a/ceilometer/tests/unit/compute/virt/xenapi/test_inspector.py +++ b/ceilometer/tests/unit/compute/virt/xenapi/test_inspector.py @@ -19,6 +19,7 @@ from oslotest import base from ceilometer.compute.virt import inspector as virt_inspector from ceilometer.compute.virt.xenapi import inspector as xenapi_inspector +from ceilometer.tests.unit.compute.virt.xenapi import fake_XenAPI class TestSwapXapiHost(base.BaseTestCase): @@ -81,25 +82,59 @@ class TestXenapiInspection(base.BaseTestCase): def test_inspect_memory_usage(self): fake_instance = {'OS-EXT-SRV-ATTR:instance_name': 'fake_instance_name', 'id': 'fake_instance_id'} - fake_stat = virt_inspector.MemoryUsageStats(usage=128) + fake_stat = virt_inspector.MemoryUsageStats(usage=64) - def fake_xenapi_request(method, args): - metrics_rec = { - 'memory_actual': '134217728', - } + def _fake_xenapi_request(method, args): + fake_total_mem = 134217728.0 + fake_free_mem = 65536.0 if method == 'VM.get_by_name_label': return ['vm_ref'] - elif method == 'VM.get_metrics': - return 'metrics_ref' - elif method == 'VM_metrics.get_record': - return metrics_rec + elif method == 'VM.query_data_source': + if 'memory' in args: + return fake_total_mem + elif 'memory_internal_free' in args: + return fake_free_mem + else: + return None else: return None session = self.inspector.session with mock.patch.object(session, 'xenapi_request', - side_effect=fake_xenapi_request): + side_effect=_fake_xenapi_request): + memory_stat = self.inspector.inspect_memory_usage(fake_instance) + self.assertEqual(fake_stat, memory_stat) + + def test_inspect_memory_usage_without_freeMem(self): + fake_instance = {'OS-EXT-SRV-ATTR:instance_name': 'fake_instance_name', + 'id': 'fake_instance_id'} + fake_stat = virt_inspector.MemoryUsageStats(usage=128) + + def _fake_xenapi_request(method, args): + if xenapi_inspector.api is None: + # the XenAPI may not exist in the test environment. + # In that case, we use the fake XenAPI for testing. + xenapi_inspector.api = fake_XenAPI + fake_total_mem = 134217728.0 + fake_details = ['INTERNAL_ERROR', + 'Rrd.Invalid_data_source("memory_internal_free")'] + + if method == 'VM.get_by_name_label': + return ['vm_ref'] + elif method == 'VM.query_data_source': + if 'memory' in args: + return fake_total_mem + elif 'memory_internal_free' in args: + raise xenapi_inspector.api.Failure(fake_details) + else: + return None + else: + return None + + session = self.inspector.session + with mock.patch.object(session, 'xenapi_request', + side_effect=_fake_xenapi_request): memory_stat = self.inspector.inspect_memory_usage(fake_instance) self.assertEqual(fake_stat, memory_stat)