diff options
| -rwxr-xr-x | bin/cloud-init | 9 | ||||
| -rw-r--r-- | cloudinit/cloud.py | 8 | ||||
| -rw-r--r-- | cloudinit/reporting.py | 32 | ||||
| -rw-r--r-- | cloudinit/sources/__init__.py | 32 | ||||
| -rw-r--r-- | cloudinit/stages.py | 29 | 
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)) | 
