Add result and host facts logging to the default callback

This is the first iteration that allows us to save results
and host facts using the API in the callback.

Change-Id: I9d6450c7721887e7893dc966055a89787d9bd228
This commit is contained in:
David Moreau Simard 2018-06-21 18:27:28 -04:00
parent 8908f9df48
commit 98d302ec8f
No known key found for this signature in database
GPG Key ID: 33A07694CBB71ECC
1 changed files with 78 additions and 0 deletions

View File

@ -18,6 +18,7 @@
from __future__ import (absolute_import, division, print_function)
import datetime
import json
import logging
import os
import six
@ -143,6 +144,18 @@ class CallbackModule(CallbackBase):
return self.task
def v2_runner_on_ok(self, result, **kwargs):
self._load_result(result, 'ok', **kwargs)
def v2_runner_on_unreachable(self, result, **kwargs):
self._load_result(result, 'unreachable', **kwargs)
def v2_runner_on_failed(self, result, **kwargs):
self._load_result(result, 'failed', **kwargs)
def v2_runner_on_skipped(self, result, **kwargs):
self._load_result(result, 'skipped', **kwargs)
def v2_playbook_on_stats(self, stats):
self.log.debug('v2_playbook_on_stats')
@ -187,6 +200,24 @@ class CallbackModule(CallbackBase):
content=self._read_file(file)
)
def _get_or_create_play_host(self, host):
self.log.debug('Getting or creating play host: %s' % host)
# Don't query the API if we already have this host
for play_host in self.play['hosts']:
if host == play_host['name']:
return play_host
play_host = self.client.post(
'/api/v1/hosts/',
name=host,
play=self.play['id']
)
# Refresh cached play
self.play = self.client.get('/api/v1/plays/%s/' % self.play['id'])
return play_host
def _load_hosts(self, hosts):
self.log.debug('Loading %s hosts(s)...' % len(hosts))
play_hosts = [host['name'] for host in self.play['hosts']]
@ -198,6 +229,53 @@ class CallbackModule(CallbackBase):
play=self.play['id']
)
# Refresh cached play
self.play = self.client.get('/api/v1/plays/%s/' % self.play['id'])
def _load_result(self, result, status, **kwargs):
"""
This method is called when an individual task instance on a single
host completes. It is responsible for logging a single result to the
database.
"""
host = self._get_or_create_play_host(result._host.get_name())
# Use Ansible's CallbackBase._dump_results in order to strip internal
# keys, respect no_log directive, etc.
if self.loop_items:
# NOTE (dmsimard): There is a known issue in which Ansible can send
# callback hooks out of order and "exit" the task before all items
# have returned, this can cause one of the items to be missing
# from the task result in ARA.
# https://github.com/ansible/ansible/issues/24207
results = [self._dump_results(result._result)]
for item in self.loop_items:
results.append(self._dump_results(item._result))
results = json.loads(json.dumps(results))
else:
results = json.loads(self._dump_results(result._result))
self.result = self.client.post(
'/api/v1/results/',
task=self.task['id'],
host=host['id'],
content=results,
status=status,
started=self.task['started'],
ended=datetime.datetime.now().isoformat(),
changed=result._result.get('changed', False),
failed=result._result.get('failed', False),
skipped=result._result.get('skipped', False),
unreachable=result._result.get('unreachable', False),
ignore_errors=kwargs.get('ignore_errors', False)
)
if self.task['action'] == 'setup' and 'ansible_facts' in result._result:
self.client.patch(
'/api/v1/hosts/%s/' % host['id'],
facts=result._result['ansible_facts']
)
def _read_file(self, path):
try:
with open(path, 'r') as fd: