hyper-v: Converts all os-win exceptions
When os-win was first introduced, a decorator which converts all os-win exceptions to virt inspector exceptions has been added to the HyperVInspector. However, the decorator works as intended for methods that return values, and not for the ones that yield (they return a generator). This patch makes sure that exceptions are converted properly for yielding methods as well. Closes-Bug #1751088 Change-Id: I7d09e1860c6940758f0d0965fedfe4dd285e0cae
This commit is contained in:
parent
01670dfcb4
commit
e2a3542fe8
|
@ -26,39 +26,45 @@ from ceilometer.compute.pollsters import util
|
|||
from ceilometer.compute.virt import inspector as virt_inspector
|
||||
|
||||
|
||||
def convert_exceptions(function, exception_map):
|
||||
def convert_exceptions(exception_map, yields=True):
|
||||
expected_exceptions = tuple(exception_map.keys())
|
||||
|
||||
@functools.wraps(function)
|
||||
def wrapper(*args, **kwargs):
|
||||
try:
|
||||
return function(*args, **kwargs)
|
||||
except expected_exceptions as ex:
|
||||
# exception might be a subclass of an expected exception.
|
||||
for expected in expected_exceptions:
|
||||
if isinstance(ex, expected):
|
||||
raised_exception = exception_map[expected]
|
||||
break
|
||||
def _reraise_exception(exc):
|
||||
# exception might be a subclass of an expected exception.
|
||||
for expected in expected_exceptions:
|
||||
if isinstance(exc, expected):
|
||||
raised_exception = exception_map[expected]
|
||||
break
|
||||
|
||||
exc_info = sys.exc_info()
|
||||
# NOTE(claudiub): Python 3 raises the exception object given as
|
||||
# the second argument in six.reraise.
|
||||
# The original message will be maintained by passing the original
|
||||
# exception.
|
||||
exc = raised_exception(six.text_type(exc_info[1]))
|
||||
six.reraise(raised_exception, exc, exc_info[2])
|
||||
return wrapper
|
||||
exc_info = sys.exc_info()
|
||||
# NOTE(claudiub): Python 3 raises the exception object given as
|
||||
# the second argument in six.reraise.
|
||||
# The original message will be maintained by passing the
|
||||
# original exception.
|
||||
exc = raised_exception(six.text_type(exc_info[1]))
|
||||
six.reraise(raised_exception, exc, exc_info[2])
|
||||
|
||||
def decorator(function):
|
||||
if yields:
|
||||
@functools.wraps(function)
|
||||
def wrapper(*args, **kwargs):
|
||||
try:
|
||||
# NOTE(claudiub): We're consuming the function's yield in
|
||||
# order to avoid yielding a generator.
|
||||
for item in function(*args, **kwargs):
|
||||
yield item
|
||||
except expected_exceptions as ex:
|
||||
_reraise_exception(ex)
|
||||
else:
|
||||
@functools.wraps(function)
|
||||
def wrapper(*args, **kwargs):
|
||||
try:
|
||||
return function(*args, **kwargs)
|
||||
except expected_exceptions as ex:
|
||||
_reraise_exception(ex)
|
||||
|
||||
def decorate_all_methods(decorator, *args, **kwargs):
|
||||
def decorate(cls):
|
||||
for attr in cls.__dict__:
|
||||
class_member = getattr(cls, attr)
|
||||
if callable(class_member):
|
||||
setattr(cls, attr, decorator(class_member, *args, **kwargs))
|
||||
return cls
|
||||
|
||||
return decorate
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
|
||||
exception_conversion_map = collections.OrderedDict([
|
||||
|
@ -69,12 +75,11 @@ exception_conversion_map = collections.OrderedDict([
|
|||
(os_win_exc.OSWinException, virt_inspector.InspectorException),
|
||||
])
|
||||
|
||||
# NOTE(claudiub): the purpose of the decorator below is to prevent any
|
||||
# NOTE(claudiub): the purpose of the decorators below is to prevent any
|
||||
# os_win exceptions (subclasses of OSWinException) to leak outside of the
|
||||
# HyperVInspector.
|
||||
|
||||
|
||||
@decorate_all_methods(convert_exceptions, exception_conversion_map)
|
||||
class HyperVInspector(virt_inspector.Inspector):
|
||||
|
||||
def __init__(self, conf):
|
||||
|
@ -91,6 +96,7 @@ class HyperVInspector(virt_inspector.Inspector):
|
|||
|
||||
return float(host_cpu_clock * host_cpu_count)
|
||||
|
||||
@convert_exceptions(exception_conversion_map, yields=False)
|
||||
def inspect_instance(self, instance, duration):
|
||||
instance_name = util.instance_name(instance)
|
||||
(cpu_clock_used,
|
||||
|
@ -105,6 +111,7 @@ class HyperVInspector(virt_inspector.Inspector):
|
|||
cpu_time=cpu_time,
|
||||
memory_usage=memory_usage)
|
||||
|
||||
@convert_exceptions(exception_conversion_map)
|
||||
def inspect_vnics(self, instance, duration):
|
||||
instance_name = util.instance_name(instance)
|
||||
for vnic_metrics in self._utils.get_vnic_metrics(instance_name):
|
||||
|
@ -122,6 +129,7 @@ class HyperVInspector(virt_inspector.Inspector):
|
|||
tx_drop=0,
|
||||
tx_errors=0)
|
||||
|
||||
@convert_exceptions(exception_conversion_map)
|
||||
def inspect_disks(self, instance, duration):
|
||||
instance_name = util.instance_name(instance)
|
||||
for disk_metrics in self._utils.get_disk_metrics(instance_name):
|
||||
|
@ -134,6 +142,7 @@ class HyperVInspector(virt_inspector.Inspector):
|
|||
write_bytes=disk_metrics['write_mb'] * units.Mi,
|
||||
errors=0, wr_total_times=0, rd_total_times=0)
|
||||
|
||||
@convert_exceptions(exception_conversion_map)
|
||||
def inspect_disk_latency(self, instance, duration):
|
||||
instance_name = util.instance_name(instance)
|
||||
for disk_metrics in self._utils.get_disk_latency_metrics(
|
||||
|
@ -142,6 +151,7 @@ class HyperVInspector(virt_inspector.Inspector):
|
|||
device=disk_metrics['instance_id'],
|
||||
disk_latency=disk_metrics['disk_latency'] / 1000)
|
||||
|
||||
@convert_exceptions(exception_conversion_map)
|
||||
def inspect_disk_iops(self, instance, duration):
|
||||
instance_name = util.instance_name(instance)
|
||||
for disk_metrics in self._utils.get_disk_iops_count(instance_name):
|
||||
|
|
|
@ -58,6 +58,27 @@ class TestHyperVInspection(base.BaseTestCase):
|
|||
self._inspector.inspect_instance,
|
||||
mock.sentinel.instance, None)
|
||||
|
||||
def _yield_consumer(generator_method, *args, **kwargs):
|
||||
list(generator_method(*args, **kwargs))
|
||||
|
||||
self._inspector._utils.get_vnic_metrics.side_effect = (
|
||||
os_win_exc.OSWinException)
|
||||
self.assertRaises(virt_inspector.InspectorException,
|
||||
_yield_consumer, self._inspector.inspect_vnics,
|
||||
mock.sentinel.instance, None)
|
||||
|
||||
self._inspector._utils.get_vnic_metrics.side_effect = (
|
||||
os_win_exc.HyperVException)
|
||||
self.assertRaises(virt_inspector.InspectorException,
|
||||
_yield_consumer, self._inspector.inspect_vnics,
|
||||
mock.sentinel.instance, None)
|
||||
|
||||
self._inspector._utils.get_vnic_metrics.side_effect = (
|
||||
os_win_exc.NotFound(resource='foofoo'))
|
||||
self.assertRaises(virt_inspector.InstanceNotFoundException,
|
||||
_yield_consumer, self._inspector.inspect_vnics,
|
||||
mock.sentinel.instance, None)
|
||||
|
||||
def test_assert_original_traceback_maintained(self):
|
||||
def bar(self):
|
||||
foo = "foofoo"
|
||||
|
|
Loading…
Reference in New Issue