ara/ara/views/reports.py

239 lines
8.0 KiB
Python

# Copyright (c) 2018 Red Hat, Inc.
#
# This file is part of ARA Records Ansible.
#
# ARA is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ARA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with ARA. If not, see <http://www.gnu.org/licenses/>.
import logging
from ara import models
from ara import utils
from flask import abort
from flask import Blueprint
from flask import current_app
from flask import jsonify
from flask import redirect
from flask import render_template
from flask import url_for
reports = Blueprint('reports', __name__)
log = logging.getLogger(__name__)
# This is a flask-frozen workaround in order to generate an index.html
# at the root of the generated report.
@reports.route('/index.html')
def main():
return redirect('/')
@reports.route('/')
@reports.route('/reports/')
@reports.route('/reports/list/<int:page>.html')
def report_list(page=1):
if current_app.config['ARA_PLAYBOOK_OVERRIDE'] is not None:
override = current_app.config['ARA_PLAYBOOK_OVERRIDE']
playbooks = (models.Playbook.query
.filter(models.Playbook.id.in_(override))
.order_by(models.Playbook.time_start.desc()))
else:
playbooks = (models.Playbook.query
.order_by(models.Playbook.time_start.desc()))
if not utils.fast_count(playbooks):
return redirect(url_for('about.main'))
playbook_per_page = current_app.config['ARA_PLAYBOOK_PER_PAGE']
# Paginate unless playbook_per_page is set to 0
if playbook_per_page >= 1:
playbooks = playbooks.paginate(page, playbook_per_page, False)
else:
playbooks = playbooks.paginate(page, None, False)
stats = utils.get_summary_stats(playbooks.items, 'playbook_id')
result_per_page = current_app.config['ARA_RESULT_PER_PAGE']
return render_template('report_list.html',
active='reports',
result_per_page=result_per_page,
playbooks=playbooks,
stats=stats)
@reports.route('/reports/<playbook_id>.html')
def report(playbook_id):
playbook = models.Playbook.query.get(playbook_id)
if playbook is None:
abort(404)
stats = utils.get_summary_stats([playbook], 'playbook_id')
result_per_page = current_app.config['ARA_RESULT_PER_PAGE']
return render_template('report_single.html',
active='reports',
result_per_page=result_per_page,
playbook=playbook,
stats=stats)
# Note (dmsimard)
# We defer the loading of the different data tables and render them
# asynchronously for performance purposes.
# Because of this, we need to prepare some JSON data so data tables can
# retrieve it through AJAX:
# https://datatables.net/examples/ajax/defer_render.html
# The following routes are there to support this mechanism.
# The routes have a text extension for proper mimetype detection.
@reports.route('/reports/ajax/parameters/<playbook>.txt')
def ajax_parameters(playbook):
playbook = models.Playbook.query.get(playbook)
if playbook is None:
abort(404)
results = dict()
results['data'] = list()
results['data'].append(['playbook_path', playbook.path])
results['data'].append(['ansible_version', playbook.ansible_version])
log.debug('Loading playbook parameters')
if playbook.options:
for option in playbook.options:
results['data'].append([option, playbook.options[option]])
log.debug('%s playbook parameters loaded' % len(results['data']))
return jsonify(results)
@reports.route('/reports/ajax/plays/<playbook>.txt')
def ajax_plays(playbook):
plays = (models.Play.query
.filter(models.Play.playbook_id == playbook))
if not utils.fast_count(plays):
abort(404)
jinja = current_app.jinja_env
date = jinja.from_string('{{ date | datefmt }}')
time = jinja.from_string('{{ time | timefmt }}')
results = dict()
results['data'] = list()
log.debug('Loading plays')
for play in plays:
name = u"<span class='pull-left'>{0}</span>".format(play.name)
start = date.render(date=play.time_start)
end = date.render(date=play.time_end)
duration = time.render(time=play.duration)
results['data'].append([name, start, end, duration])
log.debug('%s plays loaded' % len(results['data']))
return jsonify(results)
@reports.route('/reports/ajax/records/<playbook>.txt')
def ajax_records(playbook):
records = (models.Data.query
.filter(models.Data.playbook_id == playbook))
if not utils.fast_count(records):
abort(404)
jinja = current_app.jinja_env
record_key = jinja.get_template('ajax/record_key.html')
record_value = jinja.get_template('ajax/record_value.html')
results = dict()
results['data'] = list()
log.debug('Loading records')
for record in records:
key = record_key.render(record=record)
value = record_value.render(record=record)
results['data'].append([key, value])
log.debug('%s records loaded' % len(results['data']))
return jsonify(results)
@reports.route('/reports/ajax/results/<playbook>.txt')
def ajax_results(playbook):
tasks_in_playbook = models.Task.query.filter(
models.Task.playbook_id == playbook)
if not utils.fast_count(tasks_in_playbook):
abort(404)
jinja = current_app.jinja_env
time = jinja.from_string('{{ time | timefmt }}')
action_link = jinja.get_template('ajax/action.html')
name_cell = jinja.get_template('ajax/task_name.html')
task_status_link = jinja.get_template('ajax/task_status.html')
results = dict()
results['data'] = list()
log.debug('Loading results')
for task in tasks_in_playbook:
task_results = task.task_results
for result in task_results:
name = name_cell.render(tags=result.task.tags,
name=result.task.name)
host = result.host.name
action = action_link.render(file=result.task.file,
lineno=result.task.lineno,
action=result.task.action)
elapsed = time.render(time=result.task.offset_from_playbook)
duration = time.render(time=result.duration)
status = task_status_link.render(
id=result.id, derived_status=result.derived_status)
results['data'].append([name, host, action,
elapsed, duration, status])
del task_results
del task
log.debug('%s results loaded' % len(results['data']))
return jsonify(results)
@reports.route('/reports/ajax/stats/<playbook>.txt')
def ajax_stats(playbook):
stats = (models.Stats.query
.filter(models.Stats.playbook_id == playbook))
if not utils.fast_count(stats):
abort(404)
jinja = current_app.jinja_env
host_link = jinja.get_template('ajax/stats.html')
results = dict()
results['data'] = list()
log.debug('Loading host statistics and facts')
for stat in stats:
host = host_link.render(host=stat.host)
ok = stat.ok if stat.ok >= 1 else 0
changed = stat.changed if stat.changed >= 1 else 0
failed = stat.failed if stat.failed >= 1 else 0
skipped = stat.skipped if stat.skipped >= 1 else 0
unreachable = stat.unreachable if stat.unreachable >= 1 else 0
data = [host, ok, changed, failed, skipped, unreachable]
results['data'].append(data)
log.debug('%s host stats and facts loaded' % len(results['data']))
return jsonify(results)