Add a command for generating a static version of the ARA webapp
Closes: #3
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
language: python
|
||||
python:
|
||||
- "2.7"
|
||||
before_install:
|
||||
- sudo apt-get -qq update
|
||||
- sudo apt-get install -y tree
|
||||
install: "pip install tox"
|
||||
script: bash run_tests.sh
|
||||
|
||||
47
ara/cli/static.py
Normal file
47
ara/cli/static.py
Normal file
@@ -0,0 +1,47 @@
|
||||
# Copyright Red Hat, Inc. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
import logging
|
||||
|
||||
from cliff.command import Command
|
||||
from ara import app, static
|
||||
|
||||
|
||||
class Generate(Command):
|
||||
"""Generates a static tree of the web application"""
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(Generate, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--path', '-p',
|
||||
metavar='<path>',
|
||||
required=True,
|
||||
help='Path where the static files will be built in',
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
app.config['FREEZER_DESTINATION'] = parsed_args.path
|
||||
try:
|
||||
print('Generating static files at {}...'.format(parsed_args.path))
|
||||
static.freezer.freeze()
|
||||
except Exception as e:
|
||||
# TODO: (dmsimard) do some proper exception handling
|
||||
print('Could not successfully generate files: {}'.format(str(e)))
|
||||
return False
|
||||
|
||||
print('Done.')
|
||||
return True
|
||||
@@ -57,3 +57,6 @@ SQLALCHEMY_DATABASE_URI = get_config(config, 'ara', 'database',
|
||||
SQLALCHEMY_ECHO = get_config(config, 'ara', 'sqldebug',
|
||||
'ARA_SQL_DEBUG',
|
||||
DEFAULT_ARA_SQL_DEBUG)
|
||||
# Static generation
|
||||
FREEZER_RELATIVE_URLS = True
|
||||
FREEZER_DEFAULT_MIMETYPE = 'text/html'
|
||||
|
||||
18
ara/static.py
Normal file
18
ara/static.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Copyright 2016 Red Hat, Inc. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from flask_frozen import Freezer
|
||||
from ara import app
|
||||
|
||||
freezer = Freezer(app)
|
||||
@@ -14,7 +14,7 @@ def playbook_summary():
|
||||
stats=stats)
|
||||
|
||||
|
||||
@playbook.route('/<playbook>')
|
||||
@playbook.route('/<playbook>/')
|
||||
def show_playbook(playbook):
|
||||
playbook = models.Playbook.query.get(playbook)
|
||||
if playbook is None:
|
||||
@@ -34,8 +34,10 @@ def show_playbook(playbook):
|
||||
tasks=tasks)
|
||||
|
||||
|
||||
@playbook.route('/<playbook>/results')
|
||||
def playbook_results(playbook):
|
||||
@playbook.route('/<playbook>/results/')
|
||||
@playbook.route('/<playbook>/results/<host>/')
|
||||
@playbook.route('/<playbook>/results/<host>/<status>')
|
||||
def playbook_results(playbook, host=None, status=None):
|
||||
playbook = models.Playbook.query.get(playbook)
|
||||
if playbook is None:
|
||||
abort(404)
|
||||
@@ -47,15 +49,17 @@ def playbook_results(playbook):
|
||||
.filter(models.Playbook.id == playbook.id)
|
||||
.order_by(models.TaskResult.time_start))
|
||||
|
||||
if request.args.get('host'):
|
||||
hosts = [str(host) for host in request.args.get('host').split(',')]
|
||||
host = host or request.args.get('host')
|
||||
if host is not None:
|
||||
hosts = [str(h) for h in host.split(',')]
|
||||
task_results = (task_results
|
||||
.filter(models.Host.name.in_(hosts)))
|
||||
|
||||
# LKS: We're filtering this with Python rather than SQL. This
|
||||
# may become relevant if we implement result paging.
|
||||
if request.args.get('status'):
|
||||
status = request.args.get('status').split(',')
|
||||
status = status or request.args.get('status')
|
||||
if status is not None:
|
||||
status = status.split(',')
|
||||
task_results = (res for res in task_results
|
||||
if res.derived_status in status)
|
||||
|
||||
|
||||
@@ -172,3 +172,70 @@ bundled with ARA::
|
||||
* Running on http://0.0.0.0:8080/ (Press CTRL+C to quit)
|
||||
|
||||
.. _any other Flask application: http://flask.pocoo.org/docs/0.10/deploying/uwsgi/
|
||||
|
||||
Generating a static version of the web application
|
||||
--------------------------------------------------
|
||||
ARA is able to generate a static html version of it's dynamic, database-driven
|
||||
web application.
|
||||
|
||||
This can be useful if you need to browse the results of playbook runs without
|
||||
having to rely on the database backend configured.
|
||||
|
||||
For example, in the context of continuous integration, you could run an Ansible
|
||||
job with ARA, generate a static version and then recover the resulting build as
|
||||
artifacts of the jobs, allowing you to browse the results in-place.
|
||||
|
||||
The ARA CLI client provides a command to generate a static version::
|
||||
|
||||
$ ara help generate
|
||||
usage: ara generate [-h] --path <path>
|
||||
|
||||
Generates a static tree of the web application
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--path <path>, -p <path>
|
||||
Path where the static files will be built in
|
||||
|
||||
$ ara generate --path /tmp/build/
|
||||
Generating static files at /tmp/build/...
|
||||
Done.
|
||||
$ tree /tmp/build/
|
||||
/tmp/build/
|
||||
├── host
|
||||
│ ├── anotherhost
|
||||
│ ├── index.html
|
||||
│ └── localhost
|
||||
├── index.html
|
||||
├── play
|
||||
│ └── play
|
||||
│ └── 6ec9ef1d-dd73-4378-8347-1242f6be8f1e
|
||||
├── playbook
|
||||
│ ├── bf81a7db-b549-49d9-b10e-19918225ec60
|
||||
│ │ ├── index.html
|
||||
│ │ └── results
|
||||
│ │ ├── anotherhost
|
||||
│ │ │ ├── index.html
|
||||
│ │ │ └── ok
|
||||
│ │ └── localhost
|
||||
│ │ ├── index.html
|
||||
│ │ └── ok
|
||||
│ └── index.html
|
||||
├── result
|
||||
│ ├── 136100f7-fba7-44ba-83fc-1194509ad2dd
|
||||
│ ├── 37532523-b2ec-4931-bb73-3c7e5c6fa7bf
|
||||
│ ├── 3cef2a10-8f41-4f01-bc49-12bed179d7e9
|
||||
│ └── e3b7e172-c6e4-4ee4-b4bc-9a51ff84decb
|
||||
├── static
|
||||
│ ├── css
|
||||
│ │ ├── ara.css
|
||||
│ │ ├── bootstrap.min.css
|
||||
│ │ └── bootstrap-theme.min.css
|
||||
│ └── js
|
||||
│ ├── bootstrap.min.js
|
||||
│ └── jquery-2.2.3.min.js
|
||||
└── task
|
||||
├── 570fe763-69bb-4141-80d4-578189c5938b
|
||||
└── 946e1bc6-28b9-4f2f-ad4f-75b3c6c9032d
|
||||
|
||||
13 directories, 22 files
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
Flask
|
||||
Flask-SQLAlchemy
|
||||
Flask-Script
|
||||
Frozen-Flask
|
||||
pbr>=1.6
|
||||
decorator
|
||||
cliff
|
||||
|
||||
@@ -60,3 +60,4 @@ ara.cli =
|
||||
host show = ara.cli.host:HostShow
|
||||
stats list = ara.cli.stats:StatsList
|
||||
stats show = ara.cli.stats:StatsShow
|
||||
generate = ara.cli.static:Generate
|
||||
|
||||
@@ -93,14 +93,14 @@ class TestApp(TestCase):
|
||||
@pytest.mark.complete
|
||||
def test_show_playbook(self):
|
||||
self.ansible_run()
|
||||
res = self.client.get('/playbook/{}'.format(
|
||||
res = self.client.get('/playbook/{}/'.format(
|
||||
self.ctx['playbook'].id))
|
||||
self.assertEqual(res.status_code, 200)
|
||||
|
||||
@pytest.mark.incomplete
|
||||
def test_show_playbook_incomplete(self):
|
||||
self.ansible_run(complete=False)
|
||||
res = self.client.get('/playbook/{}'.format(
|
||||
res = self.client.get('/playbook/{}/'.format(
|
||||
self.ctx['playbook'].id))
|
||||
self.assertEqual(res.status_code, 200)
|
||||
|
||||
|
||||
2
tox.ini
2
tox.ini
@@ -25,6 +25,7 @@ whitelist_externals = bash
|
||||
rm
|
||||
commands =
|
||||
rm -f "{toxinidir}/tests/integration/ansible.sqlite"
|
||||
rm -rf "{toxinidir}/tests/integration/build"
|
||||
ansible-playbook -vv {toxinidir}/tests/integration/playbook.yml
|
||||
bash -c "ara host show $(ara host list -c ID -f value |head -n1)"
|
||||
bash -c "ara play show $(ara play list -c ID -f value |head -n1)"
|
||||
@@ -32,6 +33,7 @@ commands =
|
||||
bash -c "ara result show $(ara result list -c ID -f value |head -n1) --long"
|
||||
bash -c "ara stats show $(ara stats list -c ID -f value |head -n1)"
|
||||
bash -c "ara task show $(ara task list -c ID -f value |head -n1)"
|
||||
bash -c "ara generate --path {toxinidir}/tests/integration/build && tree {toxinidir}/tests/integration/build"
|
||||
setenv =
|
||||
ANSIBLE_CALLBACK_PLUGINS = {toxinidir}/ara/callback
|
||||
ARA_DATABASE = sqlite:////{toxinidir}/tests/integration/ansible.sqlite
|
||||
|
||||
Reference in New Issue
Block a user