diff options
-rw-r--r-- | cloudinit/reporting/events.py | 58 | ||||
-rw-r--r-- | tests/unittests/test_reporting.py | 15 |
2 files changed, 56 insertions, 17 deletions
diff --git a/cloudinit/reporting/events.py b/cloudinit/reporting/events.py index e35e41dd..2f767f64 100644 --- a/cloudinit/reporting/events.py +++ b/cloudinit/reporting/events.py @@ -2,17 +2,22 @@ # This file is part of cloud-init. See LICENCE file for license information. # """ -cloud-init events +events for reporting. -Report events in a structured manner. -The events here are most likely used via reporting. +The events here are designed to be used with reporting. +They can be published to registered handlers with report_event. """ +import base64 +import os.path +import time from . import instantiated_handler_registry FINISH_EVENT_TYPE = 'finish' START_EVENT_TYPE = 'start' +DEFAULT_EVENT_ORIGIN = 'cloudinit' + class _nameset(set): def __getattr__(self, name): @@ -27,10 +32,13 @@ status = _nameset(("SUCCESS", "WARN", "FAIL")) class ReportingEvent(object): """Encapsulation of event formatting.""" - def __init__(self, event_type, name, description): + def __init__(self, event_type, name, description, + origin=DEFAULT_EVENT_ORIGIN, timestamp=time.time()): self.event_type = event_type self.name = name self.description = description + self.origin = origin + self.timestamp = timestamp def as_string(self): """The event represented as a string.""" @@ -40,15 +48,20 @@ class ReportingEvent(object): def as_dict(self): """The event represented as a dictionary.""" return {'name': self.name, 'description': self.description, - 'event_type': self.event_type} + 'event_type': self.event_type, 'origin': self.origin, + 'timestamp': self.timestamp} class FinishReportingEvent(ReportingEvent): - def __init__(self, name, description, result=status.SUCCESS): + def __init__(self, name, description, result=status.SUCCESS, + post_files=None): super(FinishReportingEvent, self).__init__( FINISH_EVENT_TYPE, name, description) self.result = result + if post_files is None: + post_files = [] + self.post_files = post_files if result not in status: raise ValueError("Invalid result: %s" % result) @@ -60,6 +73,8 @@ class FinishReportingEvent(ReportingEvent): """The event represented as json friendly.""" data = super(FinishReportingEvent, self).as_dict() data['result'] = self.result + if self.post_files: + data['files'] = _collect_file_info(self.post_files) return data @@ -78,12 +93,13 @@ def report_event(event): def report_finish_event(event_name, event_description, - result=status.SUCCESS): + result=status.SUCCESS, post_files=None): """Report a "finish" event. See :py:func:`.report_event` for parameter details. """ - event = FinishReportingEvent(event_name, event_description, result) + event = FinishReportingEvent(event_name, event_description, result, + post_files=post_files) return report_event(event) @@ -133,13 +149,17 @@ class ReportEventStack(object): value is FAIL. """ def __init__(self, name, description, message=None, parent=None, - reporting_enabled=None, result_on_exception=status.FAIL): + reporting_enabled=None, result_on_exception=status.FAIL, + post_files=None): self.parent = parent self.name = name self.description = description self.message = message self.result_on_exception = result_on_exception self.result = status.SUCCESS + if post_files is None: + post_files = [] + self.post_files = post_files # use parents reporting value if not provided if reporting_enabled is None: @@ -205,6 +225,22 @@ class ReportEventStack(object): if self.parent: self.parent.children[self.name] = (result, msg) if self.reporting_enabled: - report_finish_event(self.fullname, msg, result) + report_finish_event(self.fullname, msg, result, + post_files=self.post_files) + + +def _collect_file_info(files): + if not files: + return None + ret = [] + for fname in files: + if not os.path.isfile(fname): + content = None + else: + with open(fname, "rb") as fp: + content = base64.b64encode(fp.read()).decode() + ret.append({'path': fname, 'content': content, + 'encoding': 'base64'}) + return ret -# vi: ts=4 expandtab +# vi: ts=4 expandtab syntax=python diff --git a/tests/unittests/test_reporting.py b/tests/unittests/test_reporting.py index bb67ef73..0a441adf 100644 --- a/tests/unittests/test_reporting.py +++ b/tests/unittests/test_reporting.py @@ -241,7 +241,8 @@ class TestReportingEventStack(TestCase): self.assertEqual( [mock.call('myname', 'mydesc')], report_start.call_args_list) self.assertEqual( - [mock.call('myname', 'mydesc', events.status.SUCCESS)], + [mock.call('myname', 'mydesc', events.status.SUCCESS, + post_files=[])], report_finish.call_args_list) @mock.patch('cloudinit.reporting.events.report_finish_event') @@ -256,7 +257,7 @@ class TestReportingEventStack(TestCase): pass self.assertEqual([mock.call(name, desc)], report_start.call_args_list) self.assertEqual( - [mock.call(name, desc, events.status.FAIL)], + [mock.call(name, desc, events.status.FAIL, post_files=[])], report_finish.call_args_list) @mock.patch('cloudinit.reporting.events.report_finish_event') @@ -272,7 +273,7 @@ class TestReportingEventStack(TestCase): pass self.assertEqual([mock.call(name, desc)], report_start.call_args_list) self.assertEqual( - [mock.call(name, desc, events.status.WARN)], + [mock.call(name, desc, events.status.WARN, post_files=[])], report_finish.call_args_list) @mock.patch('cloudinit.reporting.events.report_start_event') @@ -301,7 +302,7 @@ class TestReportingEventStack(TestCase): child.result = events.status.WARN report_finish.assert_called_with( - "topname", "topdesc", events.status.WARN) + "topname", "topdesc", events.status.WARN, post_files=[]) @mock.patch('cloudinit.reporting.events.report_finish_event') def test_message_used_in_finish(self, report_finish): @@ -309,7 +310,8 @@ class TestReportingEventStack(TestCase): message="mymessage"): pass self.assertEqual( - [mock.call("myname", "mymessage", events.status.SUCCESS)], + [mock.call("myname", "mymessage", events.status.SUCCESS, + post_files=[])], report_finish.call_args_list) @mock.patch('cloudinit.reporting.events.report_finish_event') @@ -317,7 +319,8 @@ class TestReportingEventStack(TestCase): with events.ReportEventStack("myname", "mydesc") as c: c.message = "all good" self.assertEqual( - [mock.call("myname", "all good", events.status.SUCCESS)], + [mock.call("myname", "all good", events.status.SUCCESS, + post_files=[])], report_finish.call_args_list) @mock.patch('cloudinit.reporting.events.report_start_event') |