summaryrefslogtreecommitdiff
path: root/cloudinit/reporting
diff options
context:
space:
mode:
authorScott Moser <smoser@ubuntu.com>2016-08-10 09:06:15 -0600
committerScott Moser <smoser@ubuntu.com>2016-08-10 09:06:15 -0600
commitc3c3dc693c14175e110b5fe125d4d5f98ace9700 (patch)
tree8858702c2c8a6ad4bf1bb861a4565e0a9c28e588 /cloudinit/reporting
parent5bd3493d732e5b1902872958e8681f17cbc81ce5 (diff)
downloadcloud-init-trunk.tar.gz
README: Mention move of revision control to git.HEADtrunk
cloud-init development has moved its revision control to git. It is available at https://code.launchpad.net/cloud-init Clone with git clone https://git.launchpad.net/cloud-init or git clone git+ssh://git.launchpad.net/cloud-init For more information see https://git.launchpad.net/cloud-init/tree/HACKING.rst
Diffstat (limited to 'cloudinit/reporting')
-rw-r--r--cloudinit/reporting/__init__.py42
-rw-r--r--cloudinit/reporting/events.py248
-rw-r--r--cloudinit/reporting/handlers.py91
3 files changed, 0 insertions, 381 deletions
diff --git a/cloudinit/reporting/__init__.py b/cloudinit/reporting/__init__.py
deleted file mode 100644
index 6b41ae61..00000000
--- a/cloudinit/reporting/__init__.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-"""
-cloud-init reporting framework
-
-The reporting framework is intended to allow all parts of cloud-init to
-report events in a structured manner.
-"""
-
-from ..registry import DictRegistry
-from .handlers import available_handlers
-
-DEFAULT_CONFIG = {
- 'logging': {'type': 'log'},
-}
-
-
-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')]
- instantiated_handler_registry.unregister_item(handler_name)
- instance = cls(**handler_config)
- instantiated_handler_registry.register_item(handler_name, instance)
-
-
-instantiated_handler_registry = DictRegistry()
-update_configuration(DEFAULT_CONFIG)
-
-# vi: ts=4 expandtab
diff --git a/cloudinit/reporting/events.py b/cloudinit/reporting/events.py
deleted file mode 100644
index df2b9b4a..00000000
--- a/cloudinit/reporting/events.py
+++ /dev/null
@@ -1,248 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-"""
-events for 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):
- 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."""
-
- def __init__(self, event_type, name, description,
- origin=DEFAULT_EVENT_ORIGIN, timestamp=None):
- self.event_type = event_type
- self.name = name
- self.description = description
- self.origin = origin
- if timestamp is None:
- timestamp = time.time()
- self.timestamp = timestamp
-
- def as_string(self):
- """The event represented as a string."""
- 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, 'origin': self.origin,
- 'timestamp': self.timestamp}
-
-
-class FinishReportingEvent(ReportingEvent):
-
- 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)
-
- def as_string(self):
- 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
- if self.post_files:
- data['files'] = _collect_file_info(self.post_files)
- return data
-
-
-def report_event(event):
- """Report an event to all registered event handlers.
-
- This should generally be called via one of the other functions in
- the reporting module.
-
- :param event_type:
- The type of the event; this should be a constant from the
- reporting module.
- """
- for _, handler in instantiated_handler_registry.registered_items.items():
- handler.publish_event(event)
-
-
-def report_finish_event(event_name, event_description,
- 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,
- post_files=post_files)
- return report_event(event)
-
-
-def report_start_event(event_name, event_description):
- """Report a "start" event.
-
- :param event_name:
- The name of the event; this should be a topic which events would
- share (e.g. it will be the same for start and finish events).
-
- :param event_description:
- A human-readable description of the event that has occurred.
- """
- event = ReportingEvent(START_EVENT_TYPE, event_name, event_description)
- return report_event(event)
-
-
-class ReportEventStack(object):
- """Context Manager for using :py:func:`report_event`
-
- This enables calling :py:func:`report_start_event` and
- :py:func:`report_finish_event` through a context manager.
-
- :param name:
- the name of the event
-
- :param description:
- the event's description, passed on to :py:func:`report_start_event`
-
- :param message:
- the description to use for the finish event. defaults to
- :param:description.
-
- :param parent:
- :type parent: :py:class:ReportEventStack or None
- The parent of this event. The parent is populated with
- results of all its children. The name used in reporting
- is <parent.name>/<name>
-
- :param reporting_enabled:
- Indicates if reporting events should be generated.
- If not provided, defaults to the parent's value, or True if no parent
- is provided.
-
- :param result_on_exception:
- The result value to set if an exception is caught. default
- value is FAIL.
- """
- def __init__(self, name, description, message=None, parent=None,
- 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:
- 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 ("ReportEventStack(%s, %s, reporting_enabled=%s)" %
- (self.name, self.description, 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, self.message)
- return (self.result, self.message)
-
- @property
- def result(self):
- return self._result
-
- @result.setter
- def result(self, value):
- if value not in status:
- raise ValueError("'%s' not a valid result" % value)
- self._result = value
-
- @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,
- 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 syntax=python
diff --git a/cloudinit/reporting/handlers.py b/cloudinit/reporting/handlers.py
deleted file mode 100644
index dff20ecb..00000000
--- a/cloudinit/reporting/handlers.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# vi: ts=4 expandtab
-
-import abc
-import json
-import six
-
-from cloudinit import log as logging
-from cloudinit.registry import DictRegistry
-from cloudinit import (url_helper, util)
-
-
-LOG = logging.getLogger(__name__)
-
-
-@six.add_metaclass(abc.ABCMeta)
-class ReportingHandler(object):
- """Base class for report handlers.
-
- Implement :meth:`~publish_event` for controlling what
- the handler does with an event.
- """
-
- @abc.abstractmethod
- def publish_event(self, event):
- """Publish an event."""
-
-
-class LogHandler(ReportingHandler):
- """Publishes events to the cloud-init log at the ``DEBUG`` log level."""
-
- def __init__(self, level="DEBUG"):
- super(LogHandler, self).__init__()
- if isinstance(level, int):
- pass
- else:
- input_level = level
- try:
- level = getattr(logging, level.upper())
- except Exception:
- LOG.warn("invalid level '%s', using WARN", input_level)
- level = logging.WARN
- self.level = level
-
- def publish_event(self, event):
- logger = logging.getLogger(
- '.'.join(['cloudinit', 'reporting', event.event_type, event.name]))
- logger.log(self.level, event.as_string())
-
-
-class PrintHandler(ReportingHandler):
- """Print the event as a string."""
-
- def publish_event(self, event):
- print(event.as_string())
-
-
-class WebHookHandler(ReportingHandler):
- def __init__(self, endpoint, consumer_key=None, token_key=None,
- token_secret=None, consumer_secret=None, timeout=None,
- retries=None):
- super(WebHookHandler, self).__init__()
-
- if any([consumer_key, token_key, token_secret, consumer_secret]):
- self.oauth_helper = url_helper.OauthUrlHelper(
- consumer_key=consumer_key, token_key=token_key,
- token_secret=token_secret, consumer_secret=consumer_secret)
- else:
- self.oauth_helper = None
- self.endpoint = endpoint
- self.timeout = timeout
- self.retries = retries
- self.ssl_details = util.fetch_ssl_details()
-
- def publish_event(self, event):
- if self.oauth_helper:
- readurl = self.oauth_helper.readurl
- else:
- readurl = url_helper.readurl
- try:
- return readurl(
- self.endpoint, data=json.dumps(event.as_dict()),
- timeout=self.timeout,
- retries=self.retries, ssl_details=self.ssl_details)
- except Exception:
- LOG.warn("failed posting event: %s" % event.as_string())
-
-
-available_handlers = DictRegistry()
-available_handlers.register_item('log', LogHandler)
-available_handlers.register_item('print', PrintHandler)
-available_handlers.register_item('webhook', WebHookHandler)