from ConfigParser import ConfigParser import imp import json import os import uuid from dogapi import dog_http_api as datadog ROOT = os.path.dirname(__file__) aggregation_key = uuid.uuid4().hex parser = ConfigParser() parser.read(os.path.join(ROOT, 'datadog.ini')) def section(name): return dict(parser.items(name)) config = section('api') datadog.api_key = config['api_key'] datadog.application_key = config['application_key'] if 'timeout' in config: datadog.timeout = int(config['timeout']) events = section('events') hooks = None if 'hooks' in events: hooks_path = os.path.join(ROOT, events['hooks']) if os.path.isfile(hooks_path): with open(hooks_path) as f: hooks_name = os.path.basename(events['hooks']) parts = hooks_name.rpartition('.') module_name, suffix = (parts[0], '.'+parts[2]) if '.' in hooks_name else (module_name, '') hooks = imp.load_module(module_name, f, hooks_name, ('.py', 'r', imp.PY_SOURCE)) def event(title, tag, alert_type, text='', host=None): if hooks is None or hooks.enabled(): tags = ['ansible:%s' % tag] if host is not None: if hasattr(hooks, 'get_host'): host = hooks.get_host(host) tags.append('host:%s' % host) datadog.event( title=title, text=text, tags=tags, alert_type=alert_type, aggregation_key=aggregation_key, source_type_name='ansible') def pretty_print(data): return json.dumps(data, sort_keys=True, indent=4) # TODO get priority, alert type via config/hooks # TODO suppress events via config # TODO events for rest of callbacks class CallbackModule(object): def runner_on_failed(self, host, res, ignore_errors=False): # TODO don't swallow if not ignore_errors: event( title='Ansible task failed: %s' % res['invocation']['module_name'], text=pretty_print(res), host=host, alert_type='error', tag='failed') def runner_on_ok(self, host, res): changed = 'changed' if res.pop('changed', False) else 'ok' event( title='Ansible task %s: %s' % (changed, res['invocation']['module_name']), text=pretty_print(res), host=host, alert_type='info', tag=changed) def runner_on_error(self, host, msg): event( title='Ansible task errored', text=msg, host=host, alert_type='error', tag='errored') def runner_on_skipped(self, host, item=None): event( title='Ansible task skipped', text="Item: '%s'" % item, host=host, alert_type='info', tag='skipped') def runner_on_unreachable(self, host, res): event( title='Ansible task host unreachable: %s' % host, text=pretty_print(res), host=host, alert_type='error', tag='unreachable') def runner_on_no_hosts(self): pass def runner_on_async_poll(self, host, res, jid, clock): pass def runner_on_async_ok(self, host, res, jid): pass def runner_on_async_failed(self, host, res, jid): pass def playbook_on_start(self): event( title="Ansible playbook started", alert_type='info', tag='playbook_start') def playbook_on_notify(self, host, handler): pass def playbook_on_no_hosts_matched(self): pass def playbook_on_no_hosts_remaining(self): pass def playbook_on_task_start(self, name, is_conditional, skipped): if not skipped: event( title="Ansible task started%s: '%s'" % (' (conditional)' if is_conditional else '', name), alert_type='info', tag='task_start') def playbook_on_vars_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None): pass def playbook_on_setup(self): pass def playbook_on_import_for_host(self, host, imported_file): pass def playbook_on_not_import_for_host(self, host, missing_file): pass def playbook_on_play_start(self, pattern): event( title="Ansible play started: '%s'" % pattern, alert_type='info', tag='play_start') def playbook_on_stats(self, stats): event( title="Ansible play complete", text="""total: {0} ok: {1} changed: {2} unreachable: {3} failed: {4} skipped: {5}""".format(stats.processed, stats.ok, stats.changed, stats.dark, stats.failures, stats.skipped), alert_type='info', tag='play_complete')