199 lines
7.3 KiB
Python
199 lines
7.3 KiB
Python
from datetime import datetime
|
|
from ansible.plugins.callback import CallbackBase
|
|
|
|
# A custom object to store to the database
|
|
from some_project.storage import Logs
|
|
|
|
|
|
class PlayLogger:
|
|
"""Store log output in a single object.
|
|
We create a new object per Ansible run
|
|
"""
|
|
|
|
def __init__(self):
|
|
self.log = ''
|
|
self.runtime = 0
|
|
|
|
def append(self, log_line):
|
|
"""append to log"""
|
|
self.log += log_line+"\n\n"
|
|
|
|
def banner(self, msg):
|
|
"""Output Trailing Stars"""
|
|
width = 78 - len(msg)
|
|
if width < 3:
|
|
width = 3
|
|
filler = "*" * width
|
|
return "\n%s %s " % (msg, filler)
|
|
|
|
|
|
class CallbackModule(CallbackBase):
|
|
"""
|
|
Reference: https://github.com/ansible/ansible/blob/v2.0.0.2-1/lib/ansible/plugins/callback/default.py
|
|
"""
|
|
|
|
CALLBACK_VERSION = 2.0
|
|
CALLBACK_TYPE = 'stored'
|
|
CALLBACK_NAME = 'database'
|
|
|
|
def __init__(self):
|
|
super(CallbackModule, self).__init__()
|
|
self.logger = PlayLogger()
|
|
self.start_time = datetime.now()
|
|
|
|
def v2_runner_on_failed(self, result, ignore_errors=False):
|
|
delegated_vars = result._result.get('_ansible_delegated_vars', None)
|
|
|
|
# Catch an exception
|
|
# This may never be called because default handler deletes
|
|
# the exception, since Ansible thinks it knows better
|
|
if 'exception' in result._result:
|
|
# Extract the error message and log it
|
|
error = result._result['exception'].strip().split('\n')[-1]
|
|
self.logger.append(error)
|
|
|
|
# Remove the exception from the result so it's not shown every time
|
|
del result._result['exception']
|
|
|
|
# Else log the reason for the failure
|
|
if result._task.loop and 'results' in result._result:
|
|
# item_on_failed, item_on_skipped, item_on_ok
|
|
self._process_items(result)
|
|
else:
|
|
if delegated_vars:
|
|
self.logger.append("fatal: [%s -> %s]: FAILED! => %s" % (result._host.get_name(
|
|
), delegated_vars['ansible_host'], self._dump_results(result._result)))
|
|
else:
|
|
self.logger.append("fatal: [%s]: FAILED! => %s" % (
|
|
result._host.get_name(), self._dump_results(result._result)))
|
|
|
|
def v2_runner_on_ok(self, result):
|
|
self._clean_results(result._result, result._task.action)
|
|
delegated_vars = result._result.get('_ansible_delegated_vars', None)
|
|
if result._task.action == 'include':
|
|
return
|
|
elif result._result.get('changed', False):
|
|
if delegated_vars:
|
|
msg = "changed: [%s -> %s]" % (result._host.get_name(),
|
|
delegated_vars['ansible_host'])
|
|
else:
|
|
msg = "changed: [%s]" % result._host.get_name()
|
|
else:
|
|
if delegated_vars:
|
|
msg = "ok: [%s -> %s]" % (result._host.get_name(),
|
|
delegated_vars['ansible_host'])
|
|
else:
|
|
msg = "ok: [%s]" % result._host.get_name()
|
|
|
|
if result._task.loop and 'results' in result._result:
|
|
# item_on_failed, item_on_skipped, item_on_ok
|
|
self._process_items(result)
|
|
else:
|
|
self.logger.append(msg)
|
|
|
|
def v2_runner_on_skipped(self, result):
|
|
if result._task.loop and 'results' in result._result:
|
|
# item_on_failed, item_on_skipped, item_on_ok
|
|
self._process_items(result)
|
|
else:
|
|
msg = "skipping: [%s]" % result._host.get_name()
|
|
self.logger.append(msg)
|
|
|
|
def v2_runner_on_unreachable(self, result):
|
|
delegated_vars = result._result.get('_ansible_delegated_vars', None)
|
|
if delegated_vars:
|
|
self.logger.append("fatal: [%s -> %s]: UNREACHABLE! => %s" % (result._host.get_name(
|
|
), delegated_vars['ansible_host'], self._dump_results(result._result)))
|
|
else:
|
|
self.logger.append("fatal: [%s]: UNREACHABLE! => %s" % (
|
|
result._host.get_name(), self._dump_results(result._result)))
|
|
|
|
def v2_runner_on_no_hosts(self, task):
|
|
self.logger.append("skipping: no hosts matched")
|
|
|
|
def v2_playbook_on_task_start(self, task, is_conditional):
|
|
self.logger.append("TASK [%s]" % task.get_name().strip())
|
|
|
|
def v2_playbook_on_play_start(self, play):
|
|
name = play.get_name().strip()
|
|
if not name:
|
|
msg = "PLAY"
|
|
else:
|
|
msg = "PLAY [%s]" % name
|
|
|
|
self.logger.append(msg)
|
|
|
|
def v2_playbook_item_on_ok(self, result):
|
|
delegated_vars = result._result.get('_ansible_delegated_vars', None)
|
|
if result._task.action == 'include':
|
|
return
|
|
elif result._result.get('changed', False):
|
|
if delegated_vars:
|
|
msg = "changed: [%s -> %s]" % (result._host.get_name(),
|
|
delegated_vars['ansible_host'])
|
|
else:
|
|
msg = "changed: [%s]" % result._host.get_name()
|
|
else:
|
|
if delegated_vars:
|
|
msg = "ok: [%s -> %s]" % (result._host.get_name(),
|
|
delegated_vars['ansible_host'])
|
|
else:
|
|
msg = "ok: [%s]" % result._host.get_name()
|
|
|
|
msg += " => (item=%s)" % (result._result['item'])
|
|
|
|
self.logger.append(msg)
|
|
|
|
def v2_playbook_item_on_failed(self, result):
|
|
delegated_vars = result._result.get('_ansible_delegated_vars', None)
|
|
if 'exception' in result._result:
|
|
# Extract the error message and log it
|
|
error = result._result['exception'].strip().split('\n')[-1]
|
|
self.logger.append(error)
|
|
|
|
# Remove the exception from the result so it's not shown every time
|
|
del result._result['exception']
|
|
|
|
if delegated_vars:
|
|
self.logger.append("failed: [%s -> %s] => (item=%s) => %s" % (result._host.get_name(
|
|
), delegated_vars['ansible_host'], result._result['item'], self._dump_results(result._result)))
|
|
else:
|
|
self.logger.append("failed: [%s] => (item=%s) => %s" % (result._host.get_name(
|
|
), result._result['item'], self._dump_results(result._result)))
|
|
|
|
def v2_playbook_item_on_skipped(self, result):
|
|
msg = "skipping: [%s] => (item=%s) " % (
|
|
result._host.get_name(), result._result['item'])
|
|
self.logger.append(msg)
|
|
|
|
def v2_playbook_on_stats(self, stats):
|
|
run_time = datetime.now() - self.start_time
|
|
# returns an int, unlike run_time.total_seconds()
|
|
self.logger.runtime = run_time.seconds
|
|
|
|
hosts = sorted(stats.processed.keys())
|
|
for h in hosts:
|
|
t = stats.summarize(h)
|
|
|
|
msg = "PLAY RECAP [%s] : %s %s %s %s %s" % (
|
|
h,
|
|
"ok: %s" % (t['ok']),
|
|
"changed: %s" % (t['changed']),
|
|
"unreachable: %s" % (t['unreachable']),
|
|
"skipped: %s" % (t['skipped']),
|
|
"failed: %s" % (t['failures']),
|
|
)
|
|
|
|
self.logger.append(msg)
|
|
|
|
def record_logs(self, user_id, success=False):
|
|
"""
|
|
Special callback added to this callback plugin
|
|
Called by Runner objet
|
|
:param user_id:
|
|
:return:
|
|
"""
|
|
|
|
log_storage = Logs()
|
|
return log_storage.save_log(user_id, self.logger.log, self.logger.runtime, success)
|