libvirt: rewrite the error handling

Error handling of libvirt driver work 'sometimes'.
Some error are catched only with we lookup for a instance
uuid, but not for other libvirt operation.

This change rewrites the logic to catch libvirt error on
each inpector method. This ensures we catch all errors whatever
which libvirt method raises it.

We also leverage tenacity instead of the custom retry code.

Change-Id: Idd54c18ece42c2dce3baf82626d30d5c2e5a49d6
This commit is contained in:
Mehdi Abaakouk 2016-11-16 12:23:01 +01:00
parent 30fec85a03
commit 66179f89a0
8 changed files with 283 additions and 353 deletions

View File

@ -107,7 +107,6 @@ class InstanceDiscovery(plugin_base.DiscoveryBase):
self.expiration_time = conf.compute.resource_update_interval
self.cache_expiry = conf.compute.resource_cache_expiry
if self.method == "libvirt_metadata":
self._connection = None
# 4096 instances on a compute should be enough :)
self._flavor_cache = cachetools.LRUCache(4096)
else:
@ -117,9 +116,7 @@ class InstanceDiscovery(plugin_base.DiscoveryBase):
@property
def connection(self):
if not self._connection:
self._connection = libvirt_utils.get_libvirt_connection(self.conf)
return self._connection
return libvirt_utils.refresh_libvirt_connection(self.conf, self)
def discover(self, manager, param=None):
"""Discover resources to monitor."""

View File

@ -25,13 +25,18 @@ from ceilometer.compute.virt import inspector as virt_inspector
@six.add_metaclass(abc.ABCMeta)
class BaseComputePollster(plugin_base.PollsterBase):
@property
def inspector(self):
def setup_environment(self):
super(BaseComputePollster, self).setup_environment()
self.inspector = self._get_inspector(self.conf)
@classmethod
def _get_inspector(cls, conf):
# FIXME(sileht): This doesn't looks threadsafe...
try:
inspector = self._inspector
inspector = cls._inspector
except AttributeError:
inspector = virt_inspector.get_hypervisor_inspector(self.conf)
BaseComputePollster._inspector = inspector
inspector = virt_inspector.get_hypervisor_inspector(conf)
cls._inspector = inspector
return inspector
@property

View File

@ -27,7 +27,7 @@ except ImportError:
from ceilometer.compute.pollsters import util
from ceilometer.compute.virt import inspector as virt_inspector
from ceilometer.compute.virt.libvirt import utils as libvirt_utils
from ceilometer.i18n import _LW, _LE, _
from ceilometer.i18n import _LW, _
LOG = logging.getLogger(__name__)
@ -36,37 +36,32 @@ class LibvirtInspector(virt_inspector.Inspector):
def __init__(self, conf):
super(LibvirtInspector, self).__init__(conf)
self._connection = None
# NOTE(sileht): create a connection on startup
self.connection
@property
def connection(self):
if not self._connection:
self._connection = libvirt_utils.get_libvirt_connection(self.conf)
return self._connection
return libvirt_utils.refresh_libvirt_connection(self.conf, self)
@libvirt_utils.retry_on_disconnect
def _lookup_by_uuid(self, instance):
instance_name = util.instance_name(instance)
try:
return self.connection.lookupByUUIDString(instance.id)
except Exception as ex:
if not libvirt or not isinstance(ex, libvirt.libvirtError):
raise virt_inspector.InspectorException(six.text_type(ex))
error_code = ex.get_error_code()
if (error_code in (libvirt.VIR_ERR_SYSTEM_ERROR,
libvirt.VIR_ERR_INTERNAL_ERROR) and
ex.get_error_domain() in (libvirt.VIR_FROM_REMOTE,
libvirt.VIR_FROM_RPC)):
except libvirt.libvirtError as ex:
if libvirt_utils.is_disconnection_exception(ex):
raise
msg = _("Error from libvirt while looking up instance "
"<name=%(name)s, id=%(id)s>: "
"[Error Code %(error_code)s] "
"%(ex)s") % {'name': instance_name,
'id': instance.id,
'error_code': error_code,
'error_code': ex.get_error_code(),
'ex': ex}
raise virt_inspector.InstanceNotFoundException(msg)
except Exception as ex:
raise virt_inspector.InspectorException(six.text_type(ex))
@libvirt_utils.retry_on_disconnect
def inspect_cpus(self, instance):
domain = self._get_domain_not_shut_off_or_raise(instance)
# TODO(gordc): this can probably be cached since it can be used to get
@ -76,31 +71,15 @@ class LibvirtInspector(virt_inspector.Inspector):
return virt_inspector.CPUStats(number=dom_stat['vcpu.current'],
time=dom_stat['cpu.time'])
@libvirt_utils.raise_nodata_if_unsupported("l3 cache usage")
@libvirt_utils.retry_on_disconnect
def inspect_cpu_l3_cache(self, instance):
domain = self._lookup_by_uuid(instance)
try:
stats = self.connection.domainListGetStats(
[domain], libvirt.VIR_DOMAIN_STATS_PERF)
perf = stats[0][1]
usage = perf["perf.cmt"]
return virt_inspector.CPUL3CacheUsageStats(l3_cache_usage=usage)
except (KeyError, AttributeError) as e:
# NOTE(sileht): KeyError if for libvirt >=2.0.0,<2.3.0, the perf
# subsystem ws existing but not these attributes
# https://github.com/libvirt/libvirt/commit/bae660869de0612bee2a740083fb494c27e3f80c
msg = _('Perf is not supported by current version of libvirt, and '
'failed to inspect l3 cache usage of %(instance_uuid)s, '
'can not get info from libvirt: %(error)s') % {
'instance_uuid': instance.id, 'error': e}
raise virt_inspector.NoDataException(msg)
# domainListGetStats might launch an exception if the method or
# cmt perf event is not supported by the underlying hypervisor
# being used by libvirt.
except libvirt.libvirtError as e:
msg = _('Failed to inspect l3 cache usage of %(instance_uuid)s, '
'can not get info from libvirt: %(error)s') % {
'instance_uuid': instance.id, 'error': e}
raise virt_inspector.NoDataException(msg)
stats = self.connection.domainListGetStats(
[domain], libvirt.VIR_DOMAIN_STATS_PERF)
perf = stats[0][1]
usage = perf["perf.cmt"]
return virt_inspector.CPUL3CacheUsageStats(l3_cache_usage=usage)
def _get_domain_not_shut_off_or_raise(self, instance):
instance_name = util.instance_name(instance)
@ -116,6 +95,7 @@ class LibvirtInspector(virt_inspector.Inspector):
return domain
@libvirt_utils.retry_on_disconnect
def inspect_vnics(self, instance):
domain = self._get_domain_not_shut_off_or_raise(instance)
@ -150,6 +130,7 @@ class LibvirtInspector(virt_inspector.Inspector):
tx_errors=dom_stats[7])
yield (interface, stats)
@libvirt_utils.retry_on_disconnect
def inspect_disks(self, instance):
domain = self._get_domain_not_shut_off_or_raise(instance)
@ -167,34 +148,19 @@ class LibvirtInspector(virt_inspector.Inspector):
errors=block_stats[4])
yield (disk, stats)
@libvirt_utils.raise_nodata_if_unsupported("memory usge", False)
@libvirt_utils.retry_on_disconnect
def inspect_memory_usage(self, instance, duration=None):
instance_name = util.instance_name(instance)
domain = self._get_domain_not_shut_off_or_raise(instance)
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:
msg = _('Failed to inspect memory usage of instance '
'<name=%(name)s, id=%(id)s>, '
'can not get info from libvirt.') % {
'name': instance_name, 'id': instance.id}
raise virt_inspector.InstanceNoDataException(msg)
# memoryStats might launch an exception if the method is not supported
# by the underlying hypervisor being used by libvirt.
except libvirt.libvirtError as e:
msg = _('Failed to inspect memory usage of %(instance_uuid)s, '
'can not get info from libvirt: %(error)s') % {
'instance_uuid': instance.id, 'error': e}
raise virt_inspector.NoDataException(msg)
memory_stats = domain.memoryStats()
memory_used = (memory_stats['available'] -
memory_stats['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)
@libvirt_utils.retry_on_disconnect
def inspect_disk_info(self, instance):
domain = self._get_domain_not_shut_off_or_raise(instance)
tree = etree.fromstring(domain.XMLDesc(0))
@ -222,65 +188,32 @@ class LibvirtInspector(virt_inspector.Inspector):
physical=block_info[2])
yield (dsk, info)
@libvirt_utils.retry_on_disconnect
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)
@libvirt_utils.raise_nodata_if_unsupported("memory bandwidth")
@libvirt_utils.retry_on_disconnect
def inspect_memory_bandwidth(self, instance, duration=None):
domain = self._get_domain_not_shut_off_or_raise(instance)
stats = self.connection.domainListGetStats(
[domain], libvirt.VIR_DOMAIN_STATS_PERF)
perf = stats[0][1]
return virt_inspector.MemoryBandwidthStats(total=perf["perf.mbmt"],
local=perf["perf.mbml"])
try:
stats = self.connection.domainListGetStats(
[domain], libvirt.VIR_DOMAIN_STATS_PERF)
perf = stats[0][1]
return virt_inspector.MemoryBandwidthStats(total=perf["perf.mbmt"],
local=perf["perf.mbml"])
except (KeyError, AttributeError) as e:
# NOTE(sileht): KeyError if for libvirt >=2.0.0,<2.3.0, the perf
# subsystem ws existing but not these attributes
# https://github.com/libvirt/libvirt/commit/bae660869de0612bee2a740083fb494c27e3f80c
msg = _('Perf is not supported by current version of libvirt, and '
'failed to inspect memory bandwidth of %(instance_uuid)s, '
'can not get info from libvirt: %(error)s') % {
'instance_uuid': instance.id, 'error': e}
raise virt_inspector.NoDataException(msg)
# domainListGetStats might launch an exception if the method or
# mbmt/mbml perf event is not supported by the underlying hypervisor
# being used by libvirt.
except libvirt.libvirtError as e:
msg = _('Failed to inspect memory bandwidth of %(instance_uuid)s, '
'can not get info from libvirt: %(error)s') % {
'instance_uuid': instance.id, 'error': e}
raise virt_inspector.NoDataException(msg)
@libvirt_utils.raise_nodata_if_unsupported("perf events")
@libvirt_utils.retry_on_disconnect
def inspect_perf_events(self, instance, duration=None):
domain = self._get_domain_not_shut_off_or_raise(instance)
try:
stats = self.connection.domainListGetStats(
[domain], libvirt.VIR_DOMAIN_STATS_PERF)
perf = stats[0][1]
return virt_inspector.PerfEventsStats(
cpu_cycles=perf["perf.cpu_cycles"],
instructions=perf["perf.instructions"],
cache_references=perf["perf.cache_references"],
cache_misses=perf["perf.cache_misses"])
# NOTE(sileht): KeyError if for libvirt >=2.0.0,<2.3.0, the perf
# subsystem ws existing but not these attributes
# https://github.com/libvirt/libvirt/commit/bae660869de0612bee2a740083fb494c27e3f80c
except (AttributeError, KeyError) as e:
msg = _LE('Perf is not supported by current version of libvirt, '
'and failed to inspect perf events of '
'%(instance_uuid)s, can not get info from libvirt: '
'%(error)s') % {
'instance_uuid': instance.id, 'error': e}
raise virt_inspector.NoDataException(msg)
# domainListGetStats might launch an exception if the method or
# mbmt/mbml perf event is not supported by the underlying hypervisor
# being used by libvirt.
except libvirt.libvirtError as e:
msg = _LE('Failed to inspect perf events of %(instance_uuid)s, '
'can not get info from libvirt: %(error)s') % {
'instance_uuid': instance.id, 'error': e}
raise virt_inspector.NoDataException(msg)
stats = self.connection.domainListGetStats(
[domain], libvirt.VIR_DOMAIN_STATS_PERF)
perf = stats[0][1]
return virt_inspector.PerfEventsStats(
cpu_cycles=perf["perf.cpu_cycles"],
instructions=perf["perf.instructions"],
cache_references=perf["perf.cache_references"],
cache_misses=perf["perf.cache_misses"])

View File

@ -15,12 +15,16 @@
from oslo_config import cfg
from oslo_log import log as logging
import tenacity
try:
import libvirt
except ImportError:
libvirt = None
from ceilometer.compute.virt import inspector as virt_inspector
from ceilometer.i18n import _LE
LOG = logging.getLogger(__name__)
OPTS = [
@ -75,7 +79,7 @@ LIBVIRT_STATUS = {
}
def get_libvirt_connection(conf):
def new_libvirt_connection(conf):
if not libvirt:
raise ImportError("python-libvirt module is missing")
uri = (conf.libvirt_uri or LIBVIRT_PER_TYPE_URIS.get(conf.libvirt_type,
@ -84,21 +88,46 @@ def get_libvirt_connection(conf):
return libvirt.openReadOnly(uri)
def retry_on_disconnect(function):
def decorator(self, *args, **kwargs):
try:
return function(self, *args, **kwargs)
except ImportError:
# NOTE(sileht): in case of libvirt failed to be imported
raise
except libvirt.libvirtError as e:
if (e.get_error_code() in (libvirt.VIR_ERR_SYSTEM_ERROR,
libvirt.VIR_ERR_INTERNAL_ERROR) and
e.get_error_domain() in (libvirt.VIR_FROM_REMOTE,
libvirt.VIR_FROM_RPC)):
LOG.debug('Connection to libvirt broken')
self.connection = None
return function(self, *args, **kwargs)
else:
raise
return decorator
def refresh_libvirt_connection(conf, klass):
connection = getattr(klass, '_libvirt_connection', None)
if not connection or not connection.isAlive():
connection = new_libvirt_connection(conf)
setattr(klass, '_libvirt_connection', connection)
return connection
def is_disconnection_exception(e):
return (isinstance(e, libvirt.libvirtError)
and e.get_error_code() in (libvirt.VIR_ERR_SYSTEM_ERROR,
libvirt.VIR_ERR_INTERNAL_ERROR)
and e.get_error_domain() in (libvirt.VIR_FROM_REMOTE,
libvirt.VIR_FROM_RPC))
retry_on_disconnect = tenacity.retry(
retry=tenacity.retry_if_exception(is_disconnection_exception),
stop=tenacity.stop_after_attempt(2))
class raise_nodata_if_unsupported(object):
def __init__(self, meter, permanent=True):
self.meter = meter
self.permanent = permanent
def __call__(self, method):
def inner(in_self, instance, *args, **kwargs):
try:
return method(in_self, instance, *args, **kwargs)
except (libvirt.libvirtError, KeyError, AttributeError) as e:
# NOTE(sileht): At this point libvirt connection error
# have been reraise as tenacity.RetryError()
msg = _LE('Failed to inspect %(meter)s of %(instance_uuid)s, '
'can not get info from libvirt: %(error)s') % {
"meter": self.meter,
"instance_uuid": instance.id,
"error": e}
if self.permanent:
raise virt_inspector.NoDataException(msg)
else:
raise virt_inspector.InstanceNoDataException(msg)
return inner

View File

@ -46,16 +46,14 @@ class TestPollsterBase(base.BaseTestCase):
'metering.stack': '2cadc4b4-8789-123c-b4eg-edd2f0a9c128',
'project_cos': 'dev'}
patch_virt = mockpatch.Patch(
self.useFixture(mockpatch.Patch(
'ceilometer.compute.virt.inspector.get_hypervisor_inspector',
new=mock.Mock(return_value=self.inspector))
self.useFixture(patch_virt)
new=mock.Mock(return_value=self.inspector)))
# as we're having lazy hypervisor inspector singleton object in the
# base compute pollster class, that leads to the fact that we
# need to mock all this class property to avoid context sharing between
# the tests
patch_inspector = mockpatch.Patch(
'ceilometer.compute.pollsters.BaseComputePollster.inspector',
self.inspector)
self.useFixture(patch_inspector)
self.useFixture(mockpatch.Patch(
'ceilometer.compute.pollsters.BaseComputePollster._get_inspector',
return_value=self.inspector))

View File

@ -14,11 +14,6 @@
"""Tests for libvirt inspector.
"""
try:
import contextlib2 as contextlib # for Python < 3.3
except ImportError:
import contextlib
import fixtures
import mock
from oslo_config import fixture as fixture_config
@ -30,64 +25,66 @@ from ceilometer.compute.virt.libvirt import inspector as libvirt_inspector
from ceilometer.compute.virt.libvirt import utils
class TestLibvirtInspection(base.BaseTestCase):
class FakeLibvirtError(Exception):
pass
class fakeLibvirtError(Exception):
pass
class VMInstance(object):
id = 'ff58e738-12f4-4c58-acde-77617b68da56'
name = 'instance-00000001'
class TestLibvirtInspection(base.BaseTestCase):
def setUp(self):
super(TestLibvirtInspection, self).setUp()
self.CONF = self.useFixture(fixture_config.Config()).conf
class VMInstance(object):
id = 'ff58e738-12f4-4c58-acde-77617b68da56'
name = 'instance-00000001'
self.instance = VMInstance
self.inspector = libvirt_inspector.LibvirtInspector(self.CONF)
self.instance = VMInstance()
libvirt_inspector.libvirt = mock.Mock()
libvirt_inspector.libvirt.VIR_DOMAIN_SHUTOFF = 5
libvirt_inspector.libvirt.libvirtError = self.fakeLibvirtError
libvirt_inspector.libvirt.libvirtError = FakeLibvirtError
utils.libvirt = libvirt_inspector.libvirt
with mock.patch('ceilometer.compute.virt.libvirt.utils.'
'refresh_libvirt_connection', return_value=None):
self.inspector = libvirt_inspector.LibvirtInspector(self.CONF)
self.domain = mock.Mock()
self.addCleanup(mock.patch.stopall)
def test_inspect_cpus(self):
fake_stats = [({}, {'cpu.time': 999999, 'vcpu.current': 2})]
with contextlib.ExitStack() as stack:
stack.enter_context(mock.patch.object(self.inspector.connection,
'lookupByUUIDString',
return_value=self.domain))
stack.enter_context(mock.patch.object(self.domain, 'info',
return_value=(0, 0, 0,
None, None)))
stack.enter_context(mock.patch.object(self.inspector.connection,
'domainListGetStats',
return_value=fake_stats))
domain = mock.Mock()
domain.info.return_value = (0, 0, 0, None, None)
conn = mock.Mock()
conn.lookupByUUIDString.return_value = domain
conn.domainListGetStats.return_value = [({}, {'cpu.time': 999999,
'vcpu.current': 2})]
with mock.patch('ceilometer.compute.virt.libvirt.utils.'
'refresh_libvirt_connection', return_value=conn):
cpu_info = self.inspector.inspect_cpus(self.instance)
self.assertEqual(2, cpu_info.number)
self.assertEqual(999999, cpu_info.time)
def test_inspect_cpus_with_domain_shutoff(self):
connection = self.inspector.connection
with mock.patch.object(connection, 'lookupByUUIDString',
return_value=self.domain):
with mock.patch.object(self.domain, 'info',
return_value=(5, 0, 0,
2, 999999)):
self.assertRaises(virt_inspector.InstanceShutOffException,
self.inspector.inspect_cpus,
self.instance)
domain = mock.Mock()
domain.info.return_value = (5, 0, 0, 2, 999999)
conn = mock.Mock()
conn.lookupByUUIDString.return_value = domain
with mock.patch('ceilometer.compute.virt.libvirt.utils.'
'refresh_libvirt_connection', return_value=conn):
self.assertRaises(virt_inspector.InstanceShutOffException,
self.inspector.inspect_cpus,
self.instance)
def test_inspect_cpu_l3_cache(self):
fake_stats = [({}, {'perf.cmt': 90112})]
connection = self.inspector.connection
with contextlib.ExitStack() as stack:
stack.enter_context(mock.patch.object(connection,
'lookupByUUIDString',
return_value=self.domain))
stack.enter_context(mock.patch.object(connection,
'domainListGetStats',
return_value=fake_stats))
domain = mock.Mock()
domain.info.return_value = (0, 0, 0, 2, 999999)
conn = mock.Mock()
conn.domainListGetStats.return_value = [({}, {'perf.cmt': 90112})]
conn.lookupByUUIDString.return_value = domain
with mock.patch('ceilometer.compute.virt.libvirt.utils.'
'refresh_libvirt_connection', return_value=conn):
cpu_info = self.inspector.inspect_cpu_l3_cache(self.instance)
self.assertEqual(90112, cpu_info.l3_cache_usage)
@ -156,19 +153,15 @@ class TestLibvirtInspection(base.BaseTestCase):
}
interfaceStats = interface_stats.__getitem__
connection = self.inspector.connection
with contextlib.ExitStack() as stack:
stack.enter_context(mock.patch.object(connection,
'lookupByUUIDString',
return_value=self.domain))
stack.enter_context(mock.patch.object(self.domain, 'XMLDesc',
return_value=dom_xml))
stack.enter_context(mock.patch.object(self.domain,
'interfaceStats',
side_effect=interfaceStats))
stack.enter_context(mock.patch.object(self.domain, 'info',
return_value=(0, 0, 0,
2, 999999)))
domain = mock.Mock()
domain.XMLDesc.return_value = dom_xml
domain.info.return_value = (0, 0, 0, 2, 999999)
domain.interfaceStats.side_effect = interfaceStats
conn = mock.Mock()
conn.lookupByUUIDString.return_value = domain
with mock.patch('ceilometer.compute.virt.libvirt.utils.'
'refresh_libvirt_connection', return_value=conn):
interfaces = list(self.inspector.inspect_vnics(self.instance))
self.assertEqual(3, len(interfaces))
@ -209,14 +202,13 @@ class TestLibvirtInspection(base.BaseTestCase):
self.assertEqual(12, info2.tx_packets)
def test_inspect_vnics_with_domain_shutoff(self):
connection = self.inspector.connection
with contextlib.ExitStack() as stack:
stack.enter_context(mock.patch.object(connection,
'lookupByUUIDString',
return_value=self.domain))
stack.enter_context(mock.patch.object(self.domain, 'info',
return_value=(5, 0, 0,
2, 999999)))
domain = mock.Mock()
domain.info.return_value = (5, 0, 0, 2, 999999)
conn = mock.Mock()
conn.lookupByUUIDString.return_value = domain
with mock.patch('ceilometer.compute.virt.libvirt.utils.'
'refresh_libvirt_connection', return_value=conn):
inspect = self.inspector.inspect_vnics
self.assertRaises(virt_inspector.InstanceShutOffException,
list, inspect(self.instance))
@ -236,19 +228,15 @@ class TestLibvirtInspection(base.BaseTestCase):
</devices>
</domain>
"""
domain = mock.Mock()
domain.XMLDesc.return_value = dom_xml
domain.info.return_value = (0, 0, 0, 2, 999999)
domain.blockStats.return_value = (1, 2, 3, 4, -1)
conn = mock.Mock()
conn.lookupByUUIDString.return_value = domain
with contextlib.ExitStack() as stack:
stack.enter_context(mock.patch.object(self.inspector.connection,
'lookupByUUIDString',
return_value=self.domain))
stack.enter_context(mock.patch.object(self.domain, 'XMLDesc',
return_value=dom_xml))
stack.enter_context(mock.patch.object(self.domain, 'blockStats',
return_value=(1, 2, 3,
4, -1)))
stack.enter_context(mock.patch.object(self.domain, 'info',
return_value=(0, 0, 0,
2, 999999)))
with mock.patch('ceilometer.compute.virt.libvirt.utils.'
'refresh_libvirt_connection', return_value=conn):
disks = list(self.inspector.inspect_disks(self.instance))
self.assertEqual(1, len(disks))
@ -260,31 +248,28 @@ class TestLibvirtInspection(base.BaseTestCase):
self.assertEqual(4, info0.write_bytes)
def test_inspect_disks_with_domain_shutoff(self):
connection = self.inspector.connection
with contextlib.ExitStack() as stack:
stack.enter_context(mock.patch.object(connection,
'lookupByUUIDString',
return_value=self.domain))
stack.enter_context(mock.patch.object(self.domain, 'info',
return_value=(5, 0, 0,
2, 999999)))
domain = mock.Mock()
domain.info.return_value = (5, 0, 0, 2, 999999)
conn = mock.Mock()
conn.lookupByUUIDString.return_value = domain
with mock.patch('ceilometer.compute.virt.libvirt.utils.'
'refresh_libvirt_connection', return_value=conn):
inspect = self.inspector.inspect_disks
self.assertRaises(virt_inspector.InstanceShutOffException,
list, inspect(self.instance))
def test_inspect_memory_usage(self):
fake_memory_stats = {'available': 51200, 'unused': 25600}
connection = self.inspector.connection
with mock.patch.object(connection, 'lookupByUUIDString',
return_value=self.domain):
with mock.patch.object(self.domain, 'info',
return_value=(0, 0, 51200,
2, 999999)):
with mock.patch.object(self.domain, 'memoryStats',
return_value=fake_memory_stats):
memory = self.inspector.inspect_memory_usage(
self.instance)
self.assertEqual(25600 / units.Ki, memory.usage)
domain = mock.Mock()
domain.info.return_value = (0, 0, 0, 2, 999999)
domain.memoryStats.return_value = {'available': 51200, 'unused': 25600}
conn = mock.Mock()
conn.lookupByUUIDString.return_value = domain
with mock.patch('ceilometer.compute.virt.libvirt.utils.'
'refresh_libvirt_connection', return_value=conn):
memory = self.inspector.inspect_memory_usage(self.instance)
self.assertEqual(25600 / units.Ki, memory.usage)
def test_inspect_disk_info(self):
dom_xml = """
@ -301,19 +286,15 @@ class TestLibvirtInspection(base.BaseTestCase):
</devices>
</domain>
"""
domain = mock.Mock()
domain.XMLDesc.return_value = dom_xml
domain.blockInfo.return_value = (1, 2, 3, -1)
domain.info.return_value = (0, 0, 0, 2, 999999)
conn = mock.Mock()
conn.lookupByUUIDString.return_value = domain
with contextlib.ExitStack() as stack:
stack.enter_context(mock.patch.object(self.inspector.connection,
'lookupByUUIDString',
return_value=self.domain))
stack.enter_context(mock.patch.object(self.domain, 'XMLDesc',
return_value=dom_xml))
stack.enter_context(mock.patch.object(self.domain, 'blockInfo',
return_value=(1, 2, 3,
-1)))
stack.enter_context(mock.patch.object(self.domain, 'info',
return_value=(0, 0, 0,
2, 999999)))
with mock.patch('ceilometer.compute.virt.libvirt.utils.'
'refresh_libvirt_connection', return_value=conn):
disks = list(self.inspector.inspect_disk_info(self.instance))
self.assertEqual(1, len(disks))
@ -338,21 +319,16 @@ class TestLibvirtInspection(base.BaseTestCase):
</devices>
</domain>
"""
domain = mock.Mock()
domain.XMLDesc.return_value = dom_xml
domain.blockInfo.return_value = (1, 2, 3, -1)
domain.info.return_value = (0, 0, 0, 2, 999999)
conn = mock.Mock()
conn.lookupByUUIDString.return_value = domain
with contextlib.ExitStack() as stack:
stack.enter_context(mock.patch.object(self.inspector.connection,
'lookupByUUIDString',
return_value=self.domain))
stack.enter_context(mock.patch.object(self.domain, 'XMLDesc',
return_value=dom_xml))
stack.enter_context(mock.patch.object(self.domain, 'blockInfo',
return_value=(1, 2, 3,
-1)))
stack.enter_context(mock.patch.object(self.domain, 'info',
return_value=(0, 0, 0,
2, 999999)))
with mock.patch('ceilometer.compute.virt.libvirt.utils.'
'refresh_libvirt_connection', return_value=conn):
disks = list(self.inspector.inspect_disk_info(self.instance))
self.assertEqual(0, len(disks))
def test_inspect_disk_info_without_source_element(self):
@ -371,111 +347,103 @@ class TestLibvirtInspection(base.BaseTestCase):
</devices>
</domain>
"""
domain = mock.Mock()
domain.XMLDesc.return_value = dom_xml
domain.blockInfo.return_value = (1, 2, 3, -1)
domain.info.return_value = (0, 0, 0, 2, 999999)
conn = mock.Mock()
conn.lookupByUUIDString.return_value = domain
with contextlib.ExitStack() as stack:
stack.enter_context(mock.patch.object(self.inspector.connection,
'lookupByUUIDString',
return_value=self.domain))
stack.enter_context(mock.patch.object(self.domain, 'XMLDesc',
return_value=dom_xml))
stack.enter_context(mock.patch.object(self.domain, 'blockInfo',
return_value=(1, 2, 3,
-1)))
stack.enter_context(mock.patch.object(self.domain, 'info',
return_value=(0, 0, 0,
2, 999999)))
with mock.patch('ceilometer.compute.virt.libvirt.utils.'
'refresh_libvirt_connection', return_value=conn):
disks = list(self.inspector.inspect_disk_info(self.instance))
self.assertEqual(0, len(disks))
def test_inspect_memory_usage_with_domain_shutoff(self):
connection = self.inspector.connection
with mock.patch.object(connection, 'lookupByUUIDString',
return_value=self.domain):
with mock.patch.object(self.domain, 'info',
return_value=(5, 0, 0,
2, 999999)):
self.assertRaises(virt_inspector.InstanceShutOffException,
self.inspector.inspect_memory_usage,
self.instance)
domain = mock.Mock()
domain.info.return_value = (5, 0, 51200, 2, 999999)
conn = mock.Mock()
conn.lookupByUUIDString.return_value = domain
with mock.patch('ceilometer.compute.virt.libvirt.utils.'
'refresh_libvirt_connection', return_value=conn):
self.assertRaises(virt_inspector.InstanceShutOffException,
self.inspector.inspect_memory_usage,
self.instance)
def test_inspect_memory_usage_with_empty_stats(self):
connection = self.inspector.connection
with mock.patch.object(connection, 'lookupByUUIDString',
return_value=self.domain):
with mock.patch.object(self.domain, 'info',
return_value=(0, 0, 51200,
2, 999999)):
with mock.patch.object(self.domain, 'memoryStats',
return_value={}):
self.assertRaises(virt_inspector.InstanceNoDataException,
self.inspector.inspect_memory_usage,
self.instance)
domain = mock.Mock()
domain.info.return_value = (0, 0, 51200, 2, 999999)
domain.memoryStats.return_value = {}
conn = mock.Mock()
conn.lookupByUUIDString.return_value = domain
with mock.patch('ceilometer.compute.virt.libvirt.utils.'
'refresh_libvirt_connection', return_value=conn):
self.assertRaises(virt_inspector.InstanceNoDataException,
self.inspector.inspect_memory_usage,
self.instance)
def test_inspect_memory_bandwidth(self):
fake_stats = [({}, {'perf.mbmt': 1892352, 'perf.mbml': 1802240})]
connection = self.inspector.connection
with mock.patch.object(connection, 'lookupByUUIDString',
return_value=self.domain):
with mock.patch.object(self.domain, 'info',
return_value=(0, 0, 51200,
2, 999999)):
with mock.patch.object(connection, 'domainListGetStats',
return_value=fake_stats):
mb = self.inspector.inspect_memory_bandwidth(self.instance)
self.assertEqual(1892352, mb.total)
self.assertEqual(1802240, mb.local)
domain = mock.Mock()
domain.info.return_value = (0, 0, 51200, 2, 999999)
conn = mock.Mock()
conn.domainListGetStats.return_value = [
({}, {'perf.mbmt': 1892352, 'perf.mbml': 1802240})]
conn.lookupByUUIDString.return_value = domain
with mock.patch('ceilometer.compute.virt.libvirt.utils.'
'refresh_libvirt_connection', return_value=conn):
mb = self.inspector.inspect_memory_bandwidth(self.instance)
self.assertEqual(1892352, mb.total)
self.assertEqual(1802240, mb.local)
def test_inspect_perf_events(self):
fake_stats = [({}, {'perf.cpu_cycles': 7259361,
'perf.instructions': 8815623,
'perf.cache_references': 74184,
'perf.cache_misses': 16737})]
connection = self.inspector.connection
with mock.patch.object(connection, 'lookupByUUIDString',
return_value=self.domain):
with mock.patch.object(self.domain, 'info',
return_value=(0, 0, 51200,
2, 999999)):
with mock.patch.object(connection, 'domainListGetStats',
return_value=fake_stats):
pe = self.inspector.inspect_perf_events(self.instance)
self.assertEqual(7259361, pe.cpu_cycles)
self.assertEqual(8815623, pe.instructions)
self.assertEqual(74184, pe.cache_references)
self.assertEqual(16737, pe.cache_misses)
domain = mock.Mock()
domain.info.return_value = (0, 0, 51200, 2, 999999)
conn = mock.Mock()
conn.domainListGetStats.return_value = [
({}, {'perf.cpu_cycles': 7259361,
'perf.instructions': 8815623,
'perf.cache_references': 74184,
'perf.cache_misses': 16737})]
conn.lookupByUUIDString.return_value = domain
with mock.patch('ceilometer.compute.virt.libvirt.utils.'
'refresh_libvirt_connection', return_value=conn):
pe = self.inspector.inspect_perf_events(self.instance)
self.assertEqual(7259361, pe.cpu_cycles)
self.assertEqual(8815623, pe.instructions)
self.assertEqual(74184, pe.cache_references)
self.assertEqual(16737, pe.cache_misses)
def test_inspect_perf_events_libvirt_less_than_2_3_0(self):
fake_stats = [({}, {})]
connection = self.inspector.connection
with mock.patch.object(connection, 'lookupByUUIDString',
return_value=self.domain):
with mock.patch.object(self.domain, 'info',
return_value=(0, 0, 51200,
2, 999999)):
with mock.patch.object(connection, 'domainListGetStats',
return_value=fake_stats):
self.assertRaises(virt_inspector.NoDataException,
self.inspector.inspect_perf_events,
self.instance)
domain = mock.Mock()
domain.info.return_value = (0, 0, 51200, 2, 999999)
conn = mock.Mock()
conn.domainListGetStats.return_value = [({}, {})]
conn.lookupByUUIDString.return_value = domain
with mock.patch('ceilometer.compute.virt.libvirt.utils.'
'refresh_libvirt_connection', return_value=conn):
self.assertRaises(virt_inspector.NoDataException,
self.inspector.inspect_perf_events,
self.instance)
class TestLibvirtInspectionWithError(base.BaseTestCase):
class fakeLibvirtError(Exception):
pass
def setUp(self):
super(TestLibvirtInspectionWithError, self).setUp()
self.CONF = self.useFixture(fixture_config.Config()).conf
self.inspector = libvirt_inspector.LibvirtInspector(self.CONF)
self.useFixture(fixtures.MonkeyPatch(
'ceilometer.compute.virt.libvirt.inspector.'
'LibvirtInspector.connection',
mock.MagicMock(side_effect=Exception('dummy'))))
'ceilometer.compute.virt.libvirt.utils.'
'refresh_libvirt_connection',
mock.MagicMock(side_effect=[None, Exception('dummy')])))
libvirt_inspector.libvirt = mock.Mock()
libvirt_inspector.libvirt.libvirtError = self.fakeLibvirtError
libvirt_inspector.libvirt.libvirtError = FakeLibvirtError
utils.libvirt = libvirt_inspector.libvirt
self.inspector = libvirt_inspector.LibvirtInspector(self.CONF)
def test_inspect_unknown_error(self):
self.assertRaises(virt_inspector.InspectorException,

View File

@ -43,6 +43,7 @@ six>=1.9.0 # MIT
SQLAlchemy<1.1.0,>=1.0.10 # MIT
sqlalchemy-migrate>=0.9.6 # Apache-2.0
stevedore>=1.9.0 # Apache-2.0
tenacity>=3.2.1 # Apache-2.0
tooz>=1.47.0 # Apache-2.0
WebOb>=1.5.0 # MIT
WSME>=0.8 # MIT

View File

@ -2,7 +2,6 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
contextlib2>=0.4.0 # PSF License
coverage>=3.6 # Apache-2.0
fixtures<2.0,>=1.3.1 # Apache-2.0/BSD
happybase!=0.7,>=0.5,<1.0.0;python_version=='2.7' # MIT