summaryrefslogtreecommitdiff
path: root/cloudinit
diff options
context:
space:
mode:
Diffstat (limited to 'cloudinit')
-rw-r--r--cloudinit/cloud.py2
-rw-r--r--cloudinit/reporting/__init__.py91
-rw-r--r--cloudinit/reporting/handlers.py7
-rw-r--r--cloudinit/sources/__init__.py2
-rw-r--r--cloudinit/stages.py10
5 files changed, 97 insertions, 15 deletions
diff --git a/cloudinit/cloud.py b/cloudinit/cloud.py
index 71eb80eb..a0fb42a3 100644
--- a/cloudinit/cloud.py
+++ b/cloudinit/cloud.py
@@ -47,7 +47,7 @@ class Cloud(object):
self._cfg = cfg
self._runners = runners
if reporter is None:
- reporter = reporting.ReportStack(
+ reporter = reporting.ReportEventStack(
name="unnamed-cloud-reporter",
description="unnamed-cloud-reporter",
reporting_enabled=False)
diff --git a/cloudinit/reporting/__init__.py b/cloudinit/reporting/__init__.py
index b0364eec..78dde715 100644
--- a/cloudinit/reporting/__init__.py
+++ b/cloudinit/reporting/__init__.py
@@ -22,6 +22,15 @@ DEFAULT_CONFIG = {
instantiated_handler_registry = DictRegistry()
+class _nameset(set):
+ def __getattr__(self, name):
+ if name in self:
+ return name
+ raise AttributeError("%s not a valid value" % name)
+
+
+status = _nameset(("SUCCESS", "WARN", "FAIL"))
+
class ReportingEvent(object):
"""Encapsulation of event formatting."""
@@ -39,17 +48,16 @@ class ReportingEvent(object):
class FinishReportingEvent(ReportingEvent):
- def __init__(self, name, description, successful=None):
+ def __init__(self, name, description, result=status.SUCCESS):
super(FinishReportingEvent, self).__init__(
FINISH_EVENT_TYPE, name, description)
- self.successful = successful
+ self.result = result
+ if result not in status:
+ raise ValueError("Invalid result: %s" % result)
def as_string(self):
- if self.successful is None:
- return super(FinishReportingEvent, self).as_string()
- success_string = 'success' if self.successful else 'fail'
return '{0}: {1}: {2}: {3}'.format(
- self.event_type, self.name, success_string, self.description)
+ self.event_type, self.name, self.result, self.description)
def add_configuration(config):
@@ -74,12 +82,13 @@ def report_event(event):
handler.publish_event(event)
-def report_finish_event(event_name, event_description, successful=None):
+def report_finish_event(event_name, event_description,
+ result=status.SUCCESS):
"""Report a "finish" event.
See :py:func:`.report_event` for parameter details.
"""
- event = FinishReportingEvent(event_name, event_description, successful)
+ event = FinishReportingEvent(event_name, event_description, result)
return report_event(event)
@@ -97,4 +106,70 @@ def report_start_event(event_name, event_description):
return report_event(event)
+class ReportEventStack(object):
+ def __init__(self, name, description, message=None, parent=None,
+ reporting_enabled=None, result_on_exception=status.FAIL):
+ self.parent = parent
+ self.name = name
+ self.description = description
+ self.message = message
+ self.result_on_exception = result_on_exception
+ self.result = status.SUCCESS
+
+ # use parents reporting value if not provided
+ if reporting_enabled is None:
+ if parent:
+ reporting_enabled = parent.reporting_enabled
+ else:
+ reporting_enabled = True
+ self.reporting_enabled = reporting_enabled
+
+ if parent:
+ self.fullname = '/'.join((parent.fullname, name,))
+ else:
+ self.fullname = self.name
+ self.children = {}
+
+ def __repr__(self):
+ return ("%s reporting=%s" % (self.fullname, self.reporting_enabled))
+
+ def __enter__(self):
+ self.result = status.SUCCESS
+ if self.reporting_enabled:
+ report_start_event(self.fullname, self.description)
+ if self.parent:
+ self.parent.children[self.name] = (None, None)
+ return self
+
+ def childrens_finish_info(self):
+ for cand_result in (status.FAIL, status.WARN):
+ for name, (value, msg) in self.children.items():
+ if value == cand_result:
+ return (value, "[" + name + "]" + msg)
+ return (self.result, self.message)
+
+ @property
+ def message(self):
+ if self._message is not None:
+ return self._message
+ return self.description
+
+ @message.setter
+ def message(self, value):
+ self._message = value
+
+ def finish_info(self, exc):
+ # return tuple of description, and value
+ if exc:
+ return (self.result_on_exception, self.message)
+ return self.childrens_finish_info()
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ (result, msg) = self.finish_info(exc_value)
+ if self.parent:
+ self.parent.children[self.name] = (result, msg)
+ if self.reporting_enabled:
+ report_finish_event(self.fullname, msg, result)
+
+
add_configuration(DEFAULT_CONFIG)
diff --git a/cloudinit/reporting/handlers.py b/cloudinit/reporting/handlers.py
index be323f53..1d5ca524 100644
--- a/cloudinit/reporting/handlers.py
+++ b/cloudinit/reporting/handlers.py
@@ -21,5 +21,12 @@ class LogHandler(ReportingHandler):
logger.info(event.as_string())
+class StderrHandler(ReportingHandler):
+ def publish_event(self, event):
+ #sys.stderr.write(event.as_string() + "\n")
+ print(event.as_string())
+
+
available_handlers = DictRegistry()
available_handlers.register_item('log', LogHandler)
+available_handlers.register_item('print', StderrHandler)
diff --git a/cloudinit/sources/__init__.py b/cloudinit/sources/__init__.py
index 3b48f173..d07cf1fa 100644
--- a/cloudinit/sources/__init__.py
+++ b/cloudinit/sources/__init__.py
@@ -254,7 +254,7 @@ def find_source(sys_cfg, distro, paths, ds_deps, cfg_list, pkg_list, reporter):
LOG.debug("Searching for %s data source in: %s", mode, ds_names)
for name, cls in zip(ds_names, ds_list):
- myrep = reporting.ReportStack(
+ myrep = reporting.ReportEventStack(
name="search-%s-%s" % (mode, name.replace("DataSource", "")),
description="searching for %s data from %s" % (mode, name),
message = "no %s data found from %s" % (mode, name),
diff --git a/cloudinit/stages.py b/cloudinit/stages.py
index 8c79ae4e..42989bb4 100644
--- a/cloudinit/stages.py
+++ b/cloudinit/stages.py
@@ -67,7 +67,7 @@ class Init(object):
self.datasource = NULL_DATA_SOURCE
if reporter is None:
- reporter = reporting.ReportStack(
+ reporter = reporting.ReportEventStack(
name="init-reporter", description="init-desc",
reporting_enabled=False)
self.reporter = reporter
@@ -242,7 +242,7 @@ class Init(object):
if self.datasource is not NULL_DATA_SOURCE:
return self.datasource
- with reporting.ReportStack(
+ with reporting.ReportEventStack(
name="check-cache", description="attempting to read from cache",
parent=self.reporter) as myrep:
ds = self._restore_from_cache()
@@ -508,11 +508,11 @@ class Init(object):
def consume_data(self, frequency=PER_INSTANCE):
# Consume the userdata first, because we need want to let the part
# handlers run first (for merging stuff)
- with reporting.ReportStack(
+ with reporting.ReportEventStack(
"consume-user-data", "reading and applying user-data",
parent=self.reporter):
self._consume_userdata(frequency)
- with reporting.ReportStack(
+ with reporting.ReportEventStack(
"consume-vendor-data", "reading and applying vendor-data",
parent=self.reporter):
self._consume_userdata(frequency)
@@ -705,7 +705,7 @@ class Modules(object):
run_name = "config-%s" % (name)
desc="running %s with frequency %s" % (run_name, freq)
- myrep = reporting.ReportStack(
+ myrep = reporting.ReportEventStack(
name=run_name, description=desc, parent=self.reporter)
with myrep: