diff --git a/ara/config.py b/ara/config.py deleted file mode 100644 index e8d7587d..00000000 --- a/ara/config.py +++ /dev/null @@ -1,171 +0,0 @@ -# Copyright (c) 2017 Red Hat, Inc. -# -# This file is part of ARA: Ansible Run Analysis. -# -# 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 . - -import os -import xstatic.main -import xstatic.pkg.bootstrap_scss -import xstatic.pkg.datatables -import xstatic.pkg.jquery -import xstatic.pkg.patternfly -import xstatic.pkg.patternfly_bootstrap_treeview - -from ansible import __version__ as ansible_version -from ansible.constants import get_config -try: - from ansible.constants import load_config_file -except ImportError: - # Ansible 2.4 no longer provides load_config_file, this is handled further - # down - from ansible.config.manager import find_ini_config_file - # Also, don't scream deprecated things at us - import ansible.constants - ansible.constants._deprecated = lambda *args: None -from distutils.version import LooseVersion -from six.moves import configparser - - -def _ara_config(config, key, env_var, default=None, section='ara', - value_type=None): - """ - Wrapper around Ansible's get_config backward/forward compatibility - """ - if default is None: - try: - # We're using env_var as keys in the DEFAULTS dict - default = DEFAULTS.get(env_var) - except KeyError as e: - msg = 'There is no default value for {0}: {1}'.format(key, str(e)) - raise KeyError(msg) - - # >= 2.3.0.0 (NOTE: Ansible trunk versioning scheme has 3 digits, not 4) - if LooseVersion(ansible_version) >= LooseVersion('2.3.0'): - return get_config(config, section, key, env_var, default, - value_type=value_type) - - # < 2.3.0.0 compatibility - if value_type is None: - return get_config(config, section, key, env_var, default) - - args = { - 'boolean': dict(boolean=True), - 'integer': dict(integer=True), - 'list': dict(islist=True), - 'tmppath': dict(istmppath=True) - } - return get_config(config, section, key, env_var, default, - **args[value_type]) - - -DEFAULTS = { - 'ARA_AUTOCREATE_DATABASE': True, - 'ARA_DIR': os.path.expanduser('~/.ara'), - 'ARA_ENABLE_DEBUG_VIEW': False, - 'ARA_HOST': '127.0.0.1', - 'ARA_IGNORE_EMPTY_GENERATION': True, - 'ARA_IGNORE_MIMETYPE_WARNINGS': True, - 'ARA_IGNORE_PARAMETERS': ['extra_vars'], - 'ARA_LOG_CONFIG': None, - 'ARA_LOG_FORMAT': '%(asctime)s - %(name)s - %(levelname)s - %(message)s', - 'ARA_LOG_LEVEL': 'INFO', - 'ARA_PATH_MAX': 40, - 'ARA_PLAYBOOK_OVERRIDE': None, - 'ARA_PLAYBOOK_PER_PAGE': 10, - 'ARA_PORT': '9191', - 'ARA_RESULT_PER_PAGE': 25, - 'ARA_SQL_DEBUG': False, - 'ARA_TMP_DIR': os.path.expanduser('~/.ansible/tmp') -} - -# Bootstrap Ansible configuration -# Ansible >=2.4 takes care of loading the configuration file itself -if LooseVersion(ansible_version) < LooseVersion('2.4.0'): - config, path = load_config_file() -else: - path = find_ini_config_file() - config = configparser.ConfigParser() - if path is not None: - config.read(path) - -# Some defaults need to be based on top of a "processed" ARA_DIR -ARA_DIR = _ara_config(config, 'dir', 'ARA_DIR') -database_path = os.path.join(ARA_DIR, 'ansible.sqlite') -DEFAULTS.update({ - 'ARA_LOG_FILE': os.path.join(ARA_DIR, 'ara.log'), - 'ARA_DATABASE': 'sqlite:///{}'.format(database_path) -}) - -ARA_AUTOCREATE_DATABASE = _ara_config(config, 'autocreate_database', - 'ARA_AUTOCREATE_DATABASE', - value_type='boolean') -ARA_ENABLE_DEBUG_VIEW = _ara_config(config, 'enable_debug_view', - 'ARA_ENABLE_DEBUG_VIEW', - value_type='boolean') -ARA_HOST = _ara_config(config, 'host', 'ARA_HOST') -ARA_IGNORE_PARAMETERS = _ara_config(config, 'ignore_parameters', - 'ARA_IGNORE_PARAMETERS', - value_type='list') -ARA_LOG_CONFIG = _ara_config(config, 'logconfig', 'ARA_LOG_CONFIG') -ARA_LOG_FILE = _ara_config(config, 'logfile', 'ARA_LOG_FILE') -ARA_LOG_FORMAT = _ara_config(config, 'logformat', 'ARA_LOG_FORMAT') -ARA_LOG_LEVEL = _ara_config(config, 'loglevel', 'ARA_LOG_LEVEL') -ARA_PLAYBOOK_OVERRIDE = _ara_config(config, 'playbook_override', - 'ARA_PLAYBOOK_OVERRIDE', - value_type='list') -ARA_PLAYBOOK_PER_PAGE = _ara_config(config, 'playbook_per_page', - 'ARA_PLAYBOOK_PER_PAGE', - value_type='integer') -ARA_PORT = _ara_config(config, 'port', 'ARA_PORT') -ARA_RESULT_PER_PAGE = _ara_config(config, 'result_per_page', - 'ARA_RESULT_PER_PAGE', - value_type='integer') -ARA_TMP_DIR = _ara_config(config, 'local_tmp', 'ANSIBLE_LOCAL_TEMP', - default=DEFAULTS['ARA_TMP_DIR'], - section='defaults', - value_type='tmppath') - -# Static generation with flask-frozen -ARA_IGNORE_EMPTY_GENERATION = _ara_config(config, - 'ignore_empty_generation', - 'ARA_IGNORE_EMPTY_GENERATION', - value_type='boolean') -FREEZER_DEFAULT_MIMETYPE = 'text/html' -FREEZER_IGNORE_MIMETYPE_WARNINGS = _ara_config(config, - 'ignore_mimetype_warnings', - 'ARA_IGNORE_MIMETYPE_WARNINGS', - value_type='boolean') -FREEZER_RELATIVE_URLS = True -FREEZER_IGNORE_404_NOT_FOUND = True - -# SQLAlchemy/Alembic settings -SQLALCHEMY_DATABASE_URI = _ara_config(config, 'database', 'ARA_DATABASE') -SQLALCHEMY_ECHO = _ara_config(config, 'sqldebug', - 'ARA_SQL_DEBUG', - value_type='boolean') -SQLALCHEMY_TRACK_MODIFICATIONS = False - -INSTALL_PATH = os.path.dirname(os.path.realpath(__file__)) -DB_MIGRATIONS = os.path.join(INSTALL_PATH, 'db') - -# Xstatic configuration -treeview = xstatic.pkg.patternfly_bootstrap_treeview -XSTATIC = dict( - bootstrap=xstatic.main.XStatic(xstatic.pkg.bootstrap_scss).base_dir, - datatables=xstatic.main.XStatic(xstatic.pkg.datatables).base_dir, - jquery=xstatic.main.XStatic(xstatic.pkg.jquery).base_dir, - patternfly=xstatic.main.XStatic(xstatic.pkg.patternfly).base_dir, - patternfly_bootstrap_treeview=xstatic.main.XStatic(treeview).base_dir, -) diff --git a/ara/plugins/modules/__init__.py b/ara/config/__init__.py similarity index 100% rename from ara/plugins/modules/__init__.py rename to ara/config/__init__.py diff --git a/ara/config/base.py b/ara/config/base.py new file mode 100644 index 00000000..c5986335 --- /dev/null +++ b/ara/config/base.py @@ -0,0 +1,79 @@ +# Copyright (c) 2017 Red Hat, Inc. +# +# This file is part of ARA: Ansible Run Analysis. +# +# 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 . + +import os +from ara.config.compat import ara_config +from ara.setup import path as ara_location + + +class BaseConfig(object): + def __init__(self): + self.ARA_DIR = ara_config( + 'dir', + 'ARA_DIR', + os.path.expanduser('~/.ara') + ) + database_path = os.path.join(self.ARA_DIR, 'ansible.sqlite') + self.ARA_DATABASE = ara_config( + 'database', + 'ARA_DATABASE', + 'sqlite:///%s' % database_path + ) + self.ARA_AUTOCREATE_DATABASE = ara_config( + 'autocreate_database', + 'ARA_AUTOCREATE_DATABASE', + True, + value_type='boolean' + ) + self.SQLALCHEMY_DATABASE_URI = self.ARA_DATABASE + self.SQLALCHEMY_TRACK_MODIFICATIONS = False + self.DB_MIGRATIONS = os.path.join(ara_location, 'db') + + self.ARA_HOST = ara_config('host', 'ARA_HOST', '127.0.0.1') + self.ARA_PORT = ara_config('port', 'ARA_PORT', '9191') + self.ARA_IGNORE_PARAMETERS = ara_config( + 'ignore_parameters', + 'ARA_IGNORE_PARAMETERS', + ['extra_vars'], + value_type='list' + ) + + # Static generation with flask-frozen + self.ARA_IGNORE_EMPTY_GENERATION = ara_config( + 'ignore_empty_generation', + 'ARA_IGNORE_EMPTY_GENERATION', + True, + value_type='boolean' + ) + self.FREEZER_DEFAULT_MIMETYPE = 'text/html' + self.FREEZER_IGNORE_MIMETYPE_WARNINGS = ara_config( + 'ignore_mimetype_warnings', + 'ARA_IGNORE_MIMETYPE_WARNINGS', + True, + value_type='boolean' + ) + self.FREEZER_RELATIVE_URLS = True + self.FREEZER_IGNORE_404_NOT_FOUND = True + + @property + def config(self): + """ Returns a dictionary for the loaded configuration """ + return { + key: self.__dict__[key] + for key in dir(self) + if key.isupper() + } diff --git a/ara/config/compat.py b/ara/config/compat.py new file mode 100644 index 00000000..0708aaca --- /dev/null +++ b/ara/config/compat.py @@ -0,0 +1,65 @@ +# Copyright (c) 2017 Red Hat, Inc. +# +# This file is part of ARA: Ansible Run Analysis. +# +# 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 . + +# Compatibility layer between ARA and the different version of Ansible + +from ansible import __version__ as ansible_version +from ansible.constants import get_config +try: + from ansible.constants import load_config_file +except ImportError: + # Ansible 2.4 no longer provides load_config_file, this is handled further + # down + from ansible.config.manager import find_ini_config_file + # Also, don't scream deprecated things at us + import ansible.constants + ansible.constants._deprecated = lambda *args: None +from distutils.version import LooseVersion +from six.moves import configparser + + +def ara_config(key, env_var, default, section='ara', value_type=None): + """ + Wrapper around Ansible's get_config backward/forward compatibility + """ + # Bootstrap Ansible configuration + # Ansible >=2.4 takes care of loading the configuration file itself + if LooseVersion(ansible_version) < LooseVersion('2.4.0'): + config, path = load_config_file() + else: + path = find_ini_config_file() + config = configparser.ConfigParser() + if path is not None: + config.read(path) + + # >= 2.3.0.0 (NOTE: Ansible trunk versioning scheme has 3 digits, not 4) + if LooseVersion(ansible_version) >= LooseVersion('2.3.0'): + return get_config(config, section, key, env_var, default, + value_type=value_type) + + # < 2.3.0.0 compatibility + if value_type is None: + return get_config(config, section, key, env_var, default) + + args = { + 'boolean': dict(boolean=True), + 'integer': dict(integer=True), + 'list': dict(islist=True), + 'tmppath': dict(istmppath=True) + } + return get_config(config, section, key, env_var, default, + **args[value_type]) diff --git a/ara/config/logger.py b/ara/config/logger.py new file mode 100644 index 00000000..23759e90 --- /dev/null +++ b/ara/config/logger.py @@ -0,0 +1,142 @@ +# Copyright (c) 2017 Red Hat, Inc. +# +# This file is part of ARA: Ansible Run Analysis. +# +# 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 . + +# Note: This file tries to import itself if it's named logging, thus, logger. + +import logging +import logging.config +import os +import yaml +from ara.config.compat import ara_config + + +DEFAULT_LOG_CONFIG = """ +--- +version: 1 +formatters: + normal: + format: '%(asctime)s %(levelname)s %(name)s: %(message)s' + console: + format: '%(asctime)s %(levelname)s %(name)s: %(message)s' +handlers: + console: + class: logging.StreamHandler + formatter: console + level: INFO + stream: ext://sys.stdout + normal: + class: logging.handlers.TimedRotatingFileHandler + formatter: normal + level: DEBUG + filename: '{dir}/{file}' + when: 'midnight' + interval: 1 + backupCount: 30 +loggers: + ara: + handlers: + - console + - normal + level: {level} + propagate: 0 + alembic: + handlers: + - console + - normal + level: WARN + propagate: 0 + sqlalchemy.engine: + handlers: + - console + - normal + level: WARN + propagate: 0 + werkzeug: + handlers: + - console + - normal + level: INFO + propagate: 0 +root: + handlers: + - normal + level: {level} +""" + + +class LogConfig(object): + def __init__(self): + default_dir = ara_config('dir', 'ARA_DIR', + os.path.expanduser('~/.ara')) + self.ARA_LOG_CONFIG = ara_config( + 'logconfig', 'ARA_LOG_CONFIG', os.path.join(default_dir, + 'logging.yml') + ) + self.ARA_LOG_DIR = ara_config('logdir', 'ARA_LOG_DIR', default_dir) + self.ARA_LOG_FILE = ara_config('logfile', 'ARA_LOG_FILE', 'ara.log') + self.ARA_LOG_LEVEL = ara_config('loglevel', 'ARA_LOG_LEVEL', 'INFO') + if self.ARA_LOG_LEVEL == 'DEBUG': + self.SQLALCHEMY_ECHO = True + self.ARA_ENABLE_DEBUG_VIEW = True + else: + self.SQLALCHEMY_ECHO = False + self.ARA_ENABLE_DEBUG_VIEW = False + + @property + def config(self): + """ Returns a dictionary for the loaded configuration """ + return { + key: self.__dict__[key] + for key in dir(self) + if key.isupper() + } + + +def setup_logging(config=None): + if config is None: + config = LogConfig().config + + if not os.path.isdir(config['ARA_LOG_DIR']): + os.makedirs(config['ARA_LOG_DIR'], mode=0o750) + + if not os.path.exists(config['ARA_LOG_CONFIG']): + default_config = DEFAULT_LOG_CONFIG.format( + dir=config['ARA_LOG_DIR'], + file=config['ARA_LOG_FILE'], + level=config['ARA_LOG_LEVEL'] + ) + with open(config['ARA_LOG_CONFIG'], 'w') as log_config: + log_config.write(default_config.lstrip()) + + ext = os.path.splitext(config['ARA_LOG_CONFIG'])[1] + if ext in ('.yml', '.yaml', '.json'): + # yaml.safe_load can load json as well as yaml + logging.config.dictConfig(yaml.safe_load( + open(config['ARA_LOG_CONFIG'], 'r') + )) + else: + logging.config.fileConfig(config['ARA_LOG_CONFIG']) + + logger = logging.getLogger('ara.logging') + msg = 'Logging: Level {level} from {config}, logging to {dir}/{file}' + msg = msg.format( + level=config['ARA_LOG_LEVEL'], + config=config['ARA_LOG_CONFIG'], + dir=config['ARA_LOG_DIR'], + file=config['ARA_LOG_FILE'], + ) + logger.debug(msg) diff --git a/ara/config/webapp.py b/ara/config/webapp.py new file mode 100644 index 00000000..57c4f3cf --- /dev/null +++ b/ara/config/webapp.py @@ -0,0 +1,64 @@ +# Copyright (c) 2017 Red Hat, Inc. +# +# This file is part of ARA: Ansible Run Analysis. +# +# 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 . + +from xstatic import main as xs +import xstatic.pkg.bootstrap_scss +import xstatic.pkg.datatables +import xstatic.pkg.jquery +import xstatic.pkg.patternfly +import xstatic.pkg.patternfly_bootstrap_treeview +from ara.config.compat import ara_config + + +class WebAppConfig(object): + def __init__(self): + self.ARA_PLAYBOOK_PER_PAGE = ara_config( + 'playbook_per_page', + 'ARA_PLAYBOOK_PER_PAGE', + 10, + value_type='integer' + ) + self.ARA_RESULT_PER_PAGE = ara_config( + 'result_per_page', + 'ARA_RESULT_PER_PAGE', + 25, + value_type='integer' + ) + self.ARA_PLAYBOOK_OVERRIDE = ara_config( + 'playbook_override', + 'ARA_PLAYBOOK_OVERRIDE', + None, + value_type='list' + ) + + treeview = xstatic.pkg.patternfly_bootstrap_treeview + self.XSTATIC = dict( + bootstrap=xs.XStatic(xstatic.pkg.bootstrap_scss).base_dir, + datatables=xs.XStatic(xstatic.pkg.datatables).base_dir, + jquery=xs.XStatic(xstatic.pkg.jquery).base_dir, + patternfly=xs.XStatic(xstatic.pkg.patternfly).base_dir, + patternfly_bootstrap_treeview=xs.XStatic(treeview).base_dir, + ) + + @property + def config(self): + """ Returns a dictionary for the loaded configuration """ + return { + key: self.__dict__[key] + for key in dir(self) + if key.isupper() + } diff --git a/ara/context_processors.py b/ara/context_processors.py deleted file mode 100644 index a223e96a..00000000 --- a/ara/context_processors.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (c) 2017 Red Hat, Inc. -# -# This file is part of ARA: Ansible Run Analysis. -# -# 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 . - -import sys - -from ansible import __version__ as ansible_version -from ara import __release__ as ara_release -from ara import models - - -def configure_context_processors(app): - @app.context_processor - def ctx_add_nav_data(): - """ - Returns standard data that will be available in every template view. - """ - try: - models.Playbook.query.one() - empty_database = False - except models.MultipleResultsFound: - empty_database = False - except models.NoResultFound: - empty_database = True - - # Get python version info - major, minor, micro, release, serial = sys.version_info - - return dict(ara_version=ara_release, - ansible_version=ansible_version, - python_version="{0}.{1}".format(major, minor), - empty_database=empty_database) diff --git a/ara/errorhandlers.py b/ara/errorhandlers.py deleted file mode 100644 index 47773a9f..00000000 --- a/ara/errorhandlers.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) 2017 Red Hat, Inc. -# -# This file is part of ARA: Ansible Run Analysis. -# -# 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 . - -from flask import render_template - - -def configure_errorhandlers(app): - @app.errorhandler(404) - def page_not_found(error): - return render_template('errors/404.html', error=error), 404 diff --git a/ara/filters.py b/ara/filters.py deleted file mode 100644 index 80a29cca..00000000 --- a/ara/filters.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright (c) 2017 Red Hat, Inc. -# -# This file is part of ARA: Ansible Run Analysis. -# -# 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 . - -import datetime -import logging -import six - -from ara.utils import fast_count -from ara.utils import playbook_treeview -from jinja2 import Markup -from os import path -from oslo_serialization import jsonutils -from pygments import highlight -from pygments.formatters import HtmlFormatter -from pygments.lexers import YamlLexer -from pygments.lexers import JsonLexer -from pygments.lexers.special import TextLexer - - -def configure_template_filters(app): - log = logging.getLogger('%s.filters' % app.logger_name) - - @app.template_filter('datefmt') - def jinja_date_formatter(timestamp, format='%Y-%m-%d %H:%M:%S'): - """ Reformats a datetime timestamp from str(datetime.datetime) """ - if timestamp is None: - return 'n/a' - else: - return datetime.datetime.strftime(timestamp, format) - - @app.template_filter('timefmt') - def jinja_time_formatter(timestamp): - """ Reformats a datetime timedelta """ - if timestamp is None: - return 'n/a' - else: - date = datetime.timedelta(seconds=int(timestamp.total_seconds())) - return str(date) - - @app.template_filter('to_nice_json') - def jinja_to_nice_json(result): - """ Tries to format a result as a pretty printed JSON. """ - try: - return jsonutils.dumps(jsonutils.loads(result), - indent=4, - sort_keys=True) - except (ValueError, TypeError): - try: - return jsonutils.dumps(result, indent=4, sort_keys=True) - except TypeError as err: - log.error('failed to dump json: %s', err) - return result - - @app.template_filter('from_json') - def jinja_from_json(val): - try: - return jsonutils.loads(val) - except ValueError as err: - log.error('failed to load json: %s', err) - return val - - @app.template_filter('yamlhighlight') - def jinja_yamlhighlight(code): - formatter = HtmlFormatter(linenos='table', - anchorlinenos=True, - lineanchors='line', - linespans='line', - cssclass='codehilite') - - if not code: - code = '' - - return highlight(Markup(code).unescape(), - YamlLexer(stripall=True), - formatter) - - @app.template_filter('pygments_formatter') - def jinja_pygments_formatter(data): - formatter = HtmlFormatter(cssclass='codehilite') - - if isinstance(data, dict) or isinstance(data, list): - data = jsonutils.dumps(data, indent=4, sort_keys=True) - lexer = JsonLexer() - elif six.string_types or six.text_type: - try: - data = jsonutils.dumps(jsonutils.loads(data), - indent=4, - sort_keys=True) - lexer = JsonLexer() - except (ValueError, TypeError): - lexer = TextLexer() - else: - lexer = TextLexer() - - lexer.stripall = True - return highlight(Markup(data).unescape(), lexer, formatter) - - @app.template_filter('fast_count') - def jinja_fast_count(query): - return fast_count(query) - - @app.template_filter('basename') - def jinja_basename(pathname): - return path.basename(pathname) - - @app.template_filter('treeview') - def jinja_treeview(playbook): - return playbook_treeview(playbook) diff --git a/ara/plugins/actions/ara_read.py b/ara/plugins/actions/ara_read.py index 870991f0..d90ee348 100644 --- a/ara/plugins/actions/ara_read.py +++ b/ara/plugins/actions/ara_read.py @@ -15,10 +15,7 @@ # You should have received a copy of the GNU General Public License # along with ARA. If not, see . -import os - from ansible.plugins.action import ActionBase -from oslo_serialization import jsonutils try: from ara import models @@ -109,11 +106,6 @@ class ActionModule(ActionBase): } return result - app = create_app() - if not current_app: - context = app.app_context() - context.push() - for arg in self._task.args: if arg not in self.VALID_ARGS: result = { @@ -134,12 +126,14 @@ class ActionModule(ActionBase): result['msg'] = '{0} parameter is required'.format(parameter) return result + app = create_app() + if not current_app: + context = app.app_context() + context.push() + if playbook_id is None: - # Retrieve the persisted playbook_id from tmpfile - tmpfile = os.path.join(app.config['ARA_TMP_DIR'], 'ara.json') - with open(tmpfile, 'rb') as file: - data = jsonutils.load(file) - playbook_id = data['playbook']['id'] + # Retrieve playbook_id from the cached context + playbook_id = current_app._cache['playbook'] try: data = self.get_key(playbook_id, key) diff --git a/ara/plugins/actions/ara_record.py b/ara/plugins/actions/ara_record.py index 1c20e4c6..e95b94d5 100644 --- a/ara/plugins/actions/ara_record.py +++ b/ara/plugins/actions/ara_record.py @@ -15,10 +15,7 @@ # You should have received a copy of the GNU General Public License # along with ARA. If not, see . -import os - from ansible.plugins.action import ActionBase -from oslo_serialization import jsonutils try: from ara import models @@ -143,11 +140,6 @@ class ActionModule(ActionBase): } return result - app = create_app() - if not current_app: - context = app.app_context() - context.push() - for arg in self._task.args: if arg not in self.VALID_ARGS: result = { @@ -178,12 +170,14 @@ class ActionModule(ActionBase): result['msg'] = msg return result + app = create_app() + if not current_app: + context = app.app_context() + context.push() + if playbook_id is None: - # Retrieve the persisted playbook_id from tmpfile - tmpfile = os.path.join(app.config['ARA_TMP_DIR'], 'ara.json') - with open(tmpfile, 'rb') as file: - data = jsonutils.load(file) - playbook_id = data['playbook']['id'] + # Retrieve playbook_id from the cached context + playbook_id = current_app._cache['playbook'] try: self.create_or_update_key(playbook_id, key, value, type) diff --git a/ara/plugins/callbacks/log_ara.py b/ara/plugins/callbacks/log_ara.py index 95b9154d..bf3237b5 100644 --- a/ara/plugins/callbacks/log_ara.py +++ b/ara/plugins/callbacks/log_ara.py @@ -17,7 +17,6 @@ from __future__ import (absolute_import, division, print_function) -import flask import itertools import logging import os @@ -29,6 +28,7 @@ from ara.models import db from ara.webapp import create_app from datetime import datetime from distutils.version import LooseVersion +from flask import current_app from oslo_serialization import jsonutils # To retrieve Ansible CLI options @@ -62,7 +62,7 @@ class CallbackModule(CallbackBase): def __init__(self): super(CallbackModule, self).__init__() - if not flask.current_app: + if not current_app: ctx = app.app_context() ctx.push() @@ -333,15 +333,8 @@ class CallbackModule(CallbackBase): file_ = self.get_or_create_file(path) file_.is_playbook = True - # We need to persist the playbook id so it can be used by the modules - data = { - 'playbook': { - 'id': self.playbook.id - } - } - tmpfile = os.path.join(app.config['ARA_TMP_DIR'], 'ara.json') - with open(tmpfile, 'w') as file: - file.write(jsonutils.dumps(data)) + # Cache the playbook data in memory for ara_record/ara_read + current_app._cache['playbook'] = self.playbook.id def v2_playbook_on_play_start(self, play): self.close_task() diff --git a/ara/plugins/modules/ara_read.py b/ara/plugins/modules/ara_read.py deleted file mode 100644 index 7adf7150..00000000 --- a/ara/plugins/modules/ara_read.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright (c) 2017 Red Hat, Inc. -# -# This file is part of ARA: Ansible Run Analysis. -# -# 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 . - -# This file is purposefully left empty due to an Ansible issue -# Details at: https://github.com/ansible/ansible/pull/18208 - -# TODO: Remove this file and update the documentation when the issue is fixed, -# released and present in all supported versions. - -DOCUMENTATION = """ ---- -module: ara_read -short_description: Ansible module to read recorded persistent data with ARA. -version_added: "2.0" -author: "RDO Community " -description: - - Ansible module to read recorded persistent data with ARA. -options: - playbook: - description: - - uuid of the playbook to read the key from - required: false - version_added: 0.13.2 - key: - description: - - Name of the key to read from - required: true - -requirements: - - "python >= 2.6" - - "ara >= 0.10.0" -""" - -EXAMPLES = """ -# Write data -- ara_record: - key: "foo" - value: "bar" - -# Read data -- ara_read: - key: "foo" - register: foo - -# Read data from a specific playbook -# (Retrieve playbook uuid's with 'ara playbook list') -- ara_read: - playbook: uuuu-iiii-dddd-0000 - key: logs - register: logs - -# Use data -- debug: - msg: "{{ item }}" - with_items: - - foo.key - - foo.value - - foo.type - - foo.playbook_id -""" diff --git a/ara/plugins/modules/ara_record.py b/ara/plugins/modules/ara_record.py deleted file mode 100644 index 20a30d9b..00000000 --- a/ara/plugins/modules/ara_record.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright (c) 2017 Red Hat, Inc. -# -# This file is part of ARA: Ansible Run Analysis. -# -# 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 . - -# This file is purposefully left empty due to an Ansible issue -# Details at: https://github.com/ansible/ansible/pull/18208 - -# TODO: Remove this file and update the documentation when the issue is fixed, -# released and present in all supported versions. - -DOCUMENTATION = """ ---- -module: ara_record -short_description: Ansible module to record persistent data with ARA. -version_added: "2.0" -author: "RDO Community " -description: - - Ansible module to record persistent data with ARA. -options: - playbook: - description: - - uuid of the playbook to write the key to - required: false - version_added: 0.13.2 - key: - description: - - Name of the key to write data to - required: true - value: - description: - - Value of the key written to - required: true - type: - description: - - Type of the key - choices: [text, url, json, list, dict] - default: text - -requirements: - - "python >= 2.6" - - "ara >= 0.10.0" -""" - -EXAMPLES = """ -# Write static data -- ara_record: - key: "foo" - value: "bar" - -# Write data to a specific (previously run) playbook -# (Retrieve playbook uuid's with 'ara playbook list') -- ara_record: - playbook: uuuu-iiii-dddd-0000 - key: logs - value: "{{ lookup('file', '/var/log/ansible.log') }}" - type: text - -# Write dynamic data -- shell: cd dev && git rev-parse HEAD - register: git_version - delegate_to: localhost - -- ara_record: - key: "git_version" - value: "{{ git_version.stdout }}" - -# Write data with a type (otherwise defaults to "text") -# This changes the behavior on how the value is presented in the web interface -- ara_record: - key: "{{ item.key }}" - value: "{{ item.value }}" - type: "{{ item.type }}" - with_items: - - { key: "log", value: "error", type: "text" } - - { key: "website", value: "http://domain.tld", type: "url" } - - { key: "data", value: "{ 'key': 'value' }", type: "json" } - - { key: "somelist", value: ['one', 'two'], type: "list" } - - { key: "somedict", value: {'key': 'value' }, type: "dict" } -""" diff --git a/ara/templates/about.html b/ara/templates/about.html index d4c94bb3..f0666462 100644 --- a/ara/templates/about.html +++ b/ara/templates/about.html @@ -33,7 +33,7 @@ Tasks