summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbin/cloud-init9
-rw-r--r--cloudinit/cloud.py8
-rw-r--r--cloudinit/reporting.py32
-rw-r--r--cloudinit/sources/__init__.py32
-rw-r--r--cloudinit/stages.py29
5 files changed, 64 insertions, 46 deletions
diff --git a/bin/cloud-init b/bin/cloud-init
index de3b9fbf..d369a806 100755
--- a/bin/cloud-init
+++ b/bin/cloud-init
@@ -284,7 +284,7 @@ def main_init(name, args):
return (init.datasource, ["Consuming user data failed!"])
# Stage 8 - re-read and apply relevant cloud-config to include user-data
- mods = stages.Modules(init, extract_fns(args))
+ mods = stages.Modules(init, extract_fns(args), reporter=args.reporter)
# Stage 9
try:
outfmt_orig = outfmt
@@ -329,7 +329,7 @@ def main_modules(action_name, args):
if not args.force:
return [(msg)]
# Stage 3
- mods = stages.Modules(init, extract_fns(args))
+ mods = stages.Modules(init, extract_fns(args), reporter=args.reporter)
# Stage 4
try:
LOG.debug("Closing stdin")
@@ -384,7 +384,7 @@ def main_single(name, args):
if not args.force:
return 1
# Stage 3
- mods = stages.Modules(init, extract_fns(args))
+ mods = stages.Modules(init, extract_fns(args), reporter=args.reporter)
mod_args = args.module_args
if mod_args:
LOG.debug("Using passed in arguments %s", mod_args)
@@ -630,7 +630,8 @@ def main():
else:
rname, rdesc = ("init-network", "searching for network datasources")
elif name == "modules":
- rname, rdesc = ("modules-%s" % args.mode, "running modules for %s")
+ rname, rdesc = ("modules-%s" % args.mode,
+ "running modules for %s" % args.mode)
elif name == "single":
rname, rdesc = ("single/%s" % args.name,
"running single module %s" % args.name)
diff --git a/cloudinit/cloud.py b/cloudinit/cloud.py
index 95e0cfb2..71eb80eb 100644
--- a/cloudinit/cloud.py
+++ b/cloudinit/cloud.py
@@ -40,12 +40,18 @@ LOG = logging.getLogger(__name__)
class Cloud(object):
- def __init__(self, datasource, paths, cfg, distro, runners):
+ def __init__(self, datasource, paths, cfg, distro, runners, reporter=None):
self.datasource = datasource
self.paths = paths
self.distro = distro
self._cfg = cfg
self._runners = runners
+ if reporter is None:
+ reporter = reporting.ReportStack(
+ name="unnamed-cloud-reporter",
+ description="unnamed-cloud-reporter",
+ reporting_enabled=False)
+ self.reporter = reporter
# If a 'user' manipulates logging or logging services
# it is typically useful to cause the logging to be
diff --git a/cloudinit/reporting.py b/cloudinit/reporting.py
index 154f4e03..08014c70 100644
--- a/cloudinit/reporting.py
+++ b/cloudinit/reporting.py
@@ -86,7 +86,8 @@ class LogHandler(ReportingHandler):
class StderrHandler(ReportingHandler):
def publish_event(self, event):
- sys.stderr.write(event.as_string() + "\n")
+ #sys.stderr.write(event.as_string() + "\n")
+ print(event.as_string())
def add_configuration(config):
@@ -135,12 +136,14 @@ def report_start_event(event_name, event_description):
class ReportStack(object):
- def __init__(self, name, description, parent=None,
+ 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 = None
# use parents reporting value if not provided
if reporting_enabled is None:
@@ -160,28 +163,35 @@ class ReportStack(object):
return ("%s reporting=%s" % (self.fullname, self.reporting_enabled))
def __enter__(self):
+ self.result = None
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, result=None, description=None):
+ 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)
- if result is None:
- result = status.SUCCESS
- if description is None:
- description = self.description
- return (result, description)
-
+ 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:
- # by default, exceptions are fatal
- return (self.result_on_exception, self.description)
+ return (self.result_on_exception, self.message)
return self.childrens_finish_info()
def __exit__(self, exc_type, exc_value, traceback):
diff --git a/cloudinit/sources/__init__.py b/cloudinit/sources/__init__.py
index 6f2d2276..3b48f173 100644
--- a/cloudinit/sources/__init__.py
+++ b/cloudinit/sources/__init__.py
@@ -247,29 +247,6 @@ def normalize_pubkey_data(pubkey_data):
return keys
-class SearchReportStack(reporting.ReportStack):
- def __init__(self, source, mode, parent):
- self.source = source.replace("DataSource", "")
- name = "check-%s" % self.source
- self.found = False
- self.mode = mode
- description = "searching for %s data from %s" % (mode, self.source)
- super(SearchReportStack, self).__init__(
- name=name, description=description, parent=parent,
- result_on_exception=reporting.status.WARN)
-
- def finish_info(self, exc):
- # return tuple of description, and value
- if exc:
- # by default, exceptions are fatal
- return (self.exc_result, self.description)
- if self.found:
- description = "found %s data from %s" % (self.mode, self.source)
- else:
- description = "no %s data found from %s" % (self.mode, self.source)
- return self.childrens_finish_info(description=description)
-
-
def find_source(sys_cfg, distro, paths, ds_deps, cfg_list, pkg_list, reporter):
ds_list = list_sources(cfg_list, ds_deps, pkg_list)
ds_names = [type_utils.obj_name(f) for f in ds_list]
@@ -277,12 +254,17 @@ 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(
+ 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),
+ parent=reporter)
try:
- with SearchReportStack(name, mode, reporter) as rep:
+ with myrep:
LOG.debug("Seeing if we can get any data from %s", cls)
s = cls(sys_cfg, distro, paths)
if s.get_data():
- rep.found = True
+ myrep.message = "found %s data from %s" % (mode, name)
return (s, type_utils.obj_name(cls))
except Exception:
util.logexc(LOG, "Getting data from %s failed", cls)
diff --git a/cloudinit/stages.py b/cloudinit/stages.py
index 79d22538..8c79ae4e 100644
--- a/cloudinit/stages.py
+++ b/cloudinit/stages.py
@@ -341,7 +341,8 @@ class Init(object):
# Form the needed options to cloudify our members
return cloud.Cloud(self.datasource,
self.paths, self.cfg,
- self.distro, helpers.Runners(self.paths))
+ self.distro, helpers.Runners(self.paths),
+ reporter=self.reporter)
def update(self):
if not self._write_to_cache():
@@ -507,8 +508,14 @@ 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)
- self._consume_userdata(frequency)
- self._consume_vendordata(frequency)
+ with reporting.ReportStack(
+ "consume-user-data", "reading and applying user-data",
+ parent=self.reporter):
+ self._consume_userdata(frequency)
+ with reporting.ReportStack(
+ "consume-vendor-data", "reading and applying vendor-data",
+ parent=self.reporter):
+ self._consume_userdata(frequency)
# Perform post-consumption adjustments so that
# modules that run during the init stage reflect
@@ -581,11 +588,12 @@ class Init(object):
class Modules(object):
- def __init__(self, init, cfg_files=None):
+ def __init__(self, init, cfg_files=None, reporter=None):
self.init = init
self.cfg_files = cfg_files
# Created on first use
self._cached_cfg = None
+ self.reporter = reporter
@property
def cfg(self):
@@ -695,7 +703,18 @@ class Modules(object):
which_ran.append(name)
# This name will affect the semaphore name created
run_name = "config-%s" % (name)
- cc.run(run_name, mod.handle, func_args, freq=freq)
+
+ desc="running %s with frequency %s" % (run_name, freq)
+ myrep = reporting.ReportStack(
+ name=run_name, description=desc, parent=self.reporter)
+
+ with myrep:
+ ran, _r = cc.run(run_name, mod.handle, func_args, freq=freq)
+ if ran:
+ myrep.message = "%s ran successfully" % run_name
+ else:
+ myrep.message = "%s previously ran" % run_name
+
except Exception as e:
util.logexc(LOG, "Running module %s (%s) failed", name, mod)
failures.append((name, e))