Add unregister and reset to DictRegistry and use

unregister allows us to unregister things, so that applying
configuration changes will affect the reporting.

Change-Id: I35932c95784060349c60a11b523bf6897fb80090
This commit is contained in:
Scott Moser 2015-08-05 17:21:39 -05:00 committed by Daniel Watkins
parent 735f0ac4ad
commit fe616bf41b
3 changed files with 76 additions and 8 deletions

View File

@ -1,3 +1,7 @@
# Copyright 2015 Canonical Ltd.
# This file is part of cloud-init. See LICENCE file for license information.
#
# vi: ts=4 expandtab
import copy
@ -5,6 +9,9 @@ class DictRegistry(object):
"""A simple registry for a mapping of objects."""
def __init__(self):
self.reset()
def reset(self):
self._items = {}
def register_item(self, key, item):
@ -14,6 +21,13 @@ class DictRegistry(object):
'Item already registered with key {0}'.format(key))
self._items[key] = item
def unregister_item(self, key, force=True):
"""Remove item from the registry."""
if key in self._items:
del self._items[key]
elif not force:
raise KeyError("%s: key not present to unregister" % key)
@property
def registered_items(self):
"""All the items that have been registered.

View File

@ -20,8 +20,6 @@ DEFAULT_CONFIG = {
'logging': {'type': 'log'},
}
instantiated_handler_registry = DictRegistry()
class _nameset(set):
def __getattr__(self, name):
@ -46,6 +44,11 @@ class ReportingEvent(object):
return '{0}: {1}: {2}'.format(
self.event_type, self.name, self.description)
def as_dict(self):
"""The event represented as a dictionary."""
return {'name': self.name, 'description': self.description,
'event_type': self.event_type}
class FinishReportingEvent(ReportingEvent):
@ -60,9 +63,26 @@ class FinishReportingEvent(ReportingEvent):
return '{0}: {1}: {2}: {3}'.format(
self.event_type, self.name, self.result, self.description)
def as_dict(self):
"""The event represented as json friendly."""
data = super(FinishReportingEvent, self).as_dict()
data['result'] = self.result
return data
def add_configuration(config):
def update_configuration(config):
"""Update the instanciated_handler_registry.
:param config:
The dictionary containing changes to apply. If a key is given
with a False-ish value, the registered handler matching that name
will be unregistered.
"""
for handler_name, handler_config in config.items():
if not handler_config:
instantiated_handler_registry.unregister_item(
handler_name, force=True)
continue
handler_config = handler_config.copy()
cls = available_handlers.registered_items[handler_config.pop('type')]
instance = cls(**handler_config)
@ -214,4 +234,5 @@ class ReportEventStack(object):
report_finish_event(self.fullname, msg, result)
add_configuration(DEFAULT_CONFIG)
instantiated_handler_registry = DictRegistry()
update_configuration(DEFAULT_CONFIG)

View File

@ -96,6 +96,23 @@ class TestReportingEvent(TestCase):
[event_type, name, description])
self.assertEqual(expected_string_representation, event.as_string())
def test_as_dict(self):
event_type, name, desc = 'test_type', 'test_name', 'test_desc'
event = reporting.ReportingEvent(event_type, name, desc)
self.assertEqual(
{'event_type': event_type, 'name': name, 'description': desc},
event.as_dict())
class TestFinishReportingEvent(TestCase):
def test_as_has_result(self):
result = reporting.status.SUCCESS
name, desc = 'test_name', 'test_desc'
event = reporting.FinishReportingEvent(name, desc, result)
ret = event.as_dict()
self.assertTrue('result' in ret)
self.assertEqual(ret['result'], result)
class TestBaseReportingHandler(TestCase):
@ -148,7 +165,7 @@ class TestReportingConfiguration(TestCase):
@mock.patch.object(reporting, 'instantiated_handler_registry')
def test_empty_configuration_doesnt_add_handlers(
self, instantiated_handler_registry):
reporting.add_configuration({})
reporting.update_configuration({})
self.assertEqual(
0, instantiated_handler_registry.register_item.call_count)
@ -160,7 +177,7 @@ class TestReportingConfiguration(TestCase):
handler_cls = mock.Mock()
available_handlers.registered_items = {handler_type_name: handler_cls}
handler_name = 'my_test_handler'
reporting.add_configuration(
reporting.update_configuration(
{handler_name: {'type': handler_type_name}})
self.assertEqual(
{handler_name: handler_cls.return_value},
@ -178,7 +195,7 @@ class TestReportingConfiguration(TestCase):
handler_config = extra_kwargs.copy()
handler_config.update({'type': handler_type_name})
handler_name = 'my_test_handler'
reporting.add_configuration({handler_name: handler_config})
reporting.update_configuration({handler_name: handler_config})
self.assertEqual(
handler_cls.return_value,
reporting.instantiated_handler_registry.registered_items[
@ -195,9 +212,25 @@ class TestReportingConfiguration(TestCase):
available_handlers.registered_items = {handler_type_name: handler_cls}
handler_config = {'type': handler_type_name, 'foo': 'bar'}
expected_handler_config = handler_config.copy()
reporting.add_configuration({'my_test_handler': handler_config})
reporting.update_configuration({'my_test_handler': handler_config})
self.assertEqual(expected_handler_config, handler_config)
@mock.patch.object(
reporting, 'instantiated_handler_registry', reporting.DictRegistry())
@mock.patch.object(reporting, 'available_handlers')
def test_handlers_removed_if_falseish_specified(self, available_handlers):
handler_type_name = 'test_handler'
handler_cls = mock.Mock()
available_handlers.registered_items = {handler_type_name: handler_cls}
handler_name = 'my_test_handler'
reporting.update_configuration(
{handler_name: {'type': handler_type_name}})
self.assertEqual(
1, len(reporting.instantiated_handler_registry.registered_items))
reporting.update_configuration({handler_name: None})
self.assertEqual(
0, len(reporting.instantiated_handler_registry.registered_items))
class TestReportingEventStack(TestCase):
@mock.patch('cloudinit.reporting.report_finish_event')