def test_default_config(self): """ Ensure we have expected default parameters """ app = w.create_app() keys = [ 'ARA_AUTOCREATE_DATABASE', 'ARA_DIR', 'ARA_ENABLE_DEBUG_VIEW', 'ARA_LOG_FILE', 'ARA_LOG_FORMAT', 'ARA_LOG_LEVEL', 'ARA_PLAYBOOK_OVERRIDE', 'ARA_PLAYBOOK_PER_PAGE', 'ARA_RESULT_PER_PAGE', ] for key in keys: self.assertEqual(c.DEFAULTS[key], app.config[key]) self.assertEqual(c.DEFAULTS['ARA_DATABASE'], app.config['SQLALCHEMY_DATABASE_URI']) self.assertEqual(c.DEFAULTS['ARA_SQL_DEBUG'], app.config['SQLALCHEMY_ECHO']) self.assertEqual(c.DEFAULTS['ARA_TMP_DIR'], os.path.split(app.config['ARA_TMP_DIR'])[:-1][0]) self.assertEqual(c.DEFAULTS['ARA_IGNORE_MIMETYPE_WARNINGS'], app.config['FREEZER_IGNORE_MIMETYPE_WARNINGS'])
def application(environ, start_response): global app # Load virtualenv if necessary if (int(environ.get('ARA_WSGI_USE_VIRTUALENV', 0)) == 1 and environ.get('ARA_WSGI_VIRTUALENV_PATH')): # Backwards compatibility, we did not always suffix activate_this.py activate_this = environ.get('ARA_WSGI_VIRTUALENV_PATH') if 'activate_this.py' not in activate_this: activate_this = os.path.join(activate_this, 'bin/activate_this.py') if six.PY2: execfile(activate_this, dict(__file__=activate_this)) # nosec else: exec(open(activate_this).read()) # nosec if 'ANSIBLE_CONFIG' in environ: os.environ['ANSIBLE_CONFIG'] = environ['ANSIBLE_CONFIG'] else: if 'ANSIBLE_CONFIG' not in os.environ: log.warning('ANSIBLE_CONFIG environment variable not found.') from ara.webapp import create_app # flake8: noqa from flask import current_app # flake8: noqa with app_making_lock: if app is None: app = create_app() with app.app_context(): return current_app(environ, start_response)
def application(environ, start_response): request = environ['REQUEST_URI'] match = re.search('/(?P<path>.*/{}/)'.format(DATABASE_DIRECTORY), request) if not match: return bad_request(environ, start_response, 'No "/{}/" in URL.'.format(DATABASE_DIRECTORY)) path = os.path.abspath(os.path.join(LOG_ROOT, match.group('path'))) # Ensure we don't escape outside LOG_ROOT and we are looking at a # valid directory if not path.startswith(LOG_ROOT) or not os.path.isdir(path): logger.error('Directory access violation: %s' % path) return bad_request(environ, start_response, 'No directory found.') database = os.path.join(path, 'ansible.sqlite') if not os.path.isfile(database): return bad_request(environ, start_response, 'No ARA database found.') # ARA and Ansible (when loading configuration) both expect a directory # they are able to write to, this can be safely discarded. # Nothing is read from here and there is therefore no security risks. # It needs to be at a known location in order to be able to clean it up # so it doesn't accumulate needless directories and files. # TODO: ARA 1.0 no longer requires temporary directories, clean this up. tmpdir = '/tmp/ara_wsgi_sqlite' # nosec if os.path.exists(tmpdir): # Periodically delete this directory to avoid accumulating directories # and files endlessly now = time.time() if now - TMPDIR_MAX_AGE > os.path.getmtime(tmpdir): shutil.rmtree(tmpdir, ignore_errors=True) os.environ['ANSIBLE_LOCAL_TEMP'] = os.path.join(tmpdir, '.ansible') os.environ['ARA_DIR'] = os.path.join(tmpdir, '.ara') # Path to the ARA database os.environ['ARA_DATABASE'] = 'sqlite:///{}'.format(database) # The intent is that we are dealing with databases that already exist. # Therefore, we're not really interested in creating the database and # making sure that the SQL migrations are done. Toggle that off. # This needs to be a string, we're setting an environment variable os.environ['ARA_AUTOCREATE_DATABASE'] = 'false' msg = 'Request {request} mapped to {database} with root {root}'.format( request=request, database='sqlite:///{}'.format(database), root=match.group('path')) logger.debug(msg) from ara.webapp import create_app try: app = create_app() app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///{}'.format(database) app.config['APPLICATION_ROOT'] = match.group('path') return app(environ, start_response) except Exception as e: # We're staying relatively vague on purpose to avoid disclosure logger.error('ARA bootstrap failure for %s: %s' % (database, str(e))) return bad_request(environ, start_response, 'ARA bootstrap failure.')
def run(self, tmp=None, task_vars=None): if task_vars is None: task_vars = dict() if not HAS_ARA: result = { 'failed': True, 'msg': 'ARA is required to run this module.' } return result for arg in self._task.args: if arg not in self.VALID_ARGS: result = { 'failed': True, 'msg': '{0} is not a valid option.'.format(arg) } return result result = super(ActionModule, self).run(tmp, task_vars) playbook_id = self._task.args.get('playbook', None) key = self._task.args.get('key', None) required = ['key'] for parameter in required: if not self._task.args.get(parameter): result['failed'] = True 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 playbook_id from the cached context playbook_id = current_app._cache['playbook'] try: data = self.get_key(playbook_id, key) if data: result['key'] = data.key result['value'] = data.value result['type'] = data.type result['playbook_id'] = data.playbook_id msg = 'Sucessfully read data for the key {0}'.format(data.key) result['msg'] = msg # TODO: Do a better job for handling exception except Exception as e: result['key'] = None result['value'] = None result['type'] = None result['playbook_id'] = None result['failed'] = True msg = 'Could not read data for key {0}: {1}'.format(key, str(e)) result['msg'] = msg return result
def prepare_to_run_command(self, cmd): log.debug('prepare_to_run_command: %s', cmd.__class__.__name__) # Note: cliff uses self.app for itself, this gets folded back into # self.app.ara self.ara = create_app() if not current_app: self.ara_context = self.ara.app_context() self.ara_context.push()
def prepare_to_run_command(self, cmd): self.LOG.debug('prepare_to_run_command %s', cmd.__class__.__name__) # Note: cliff uses self.app for itself, this gets folded back into # self.app.ara self.ara = create_app() if not current_app: self.ara_context = self.ara.app_context() self.ara_context.push()
def setUp(self): self.config = {'SQLALCHEMY_DATABASE_URI': 'sqlite://', 'TESTING': True} self.app = w.create_app(self) self.app_context = self.app.app_context() self.app_context.push() self.client = self.app.test_client() m.db.create_all()
def application(environ, start_response): if 'ANSIBLE_CONFIG' in environ: os.environ['ANSIBLE_CONFIG'] = environ['ANSIBLE_CONFIG'] else: if 'ANSIBLE_CONFIG' not in os.environ: log.warn('ANSIBLE_CONFIG environment variable not found.') from ara.webapp import create_app app = create_app() return app(environ, start_response)
def application(environ, start_response): if 'ANSIBLE_CONFIG' in environ: os.environ['ANSIBLE_CONFIG'] = environ['ANSIBLE_CONFIG'] else: if 'ANSIBLE_CONFIG' not in os.environ: log.warn('ANSIBLE_CONFIG environment variable not found.') with app_making_lock: if app is None: app = create_app() with app.app_context(): return current_app(environ, start_response)
def setUp(self): self.config = {"SQLALCHEMY_DATABASE_URI": "sqlite://", "TESTING": True} self.app = w.create_app(self) self.client = self.app.test_client() if not flask.current_app: ctx = self.app.app_context() ctx.push() m.db.create_all()
def setUp(self): # TODO: Fix this, it's not used in create_app() and makes the databases # live on the filesystem rather than memory. self.config = {'SQLALCHEMY_DATABASE_URI': 'sqlite://', 'TESTING': True} self.app = w.create_app() self.app_context = self.app.app_context() self.app_context.push() self.client = self.app.test_client() m.db.create_all()
def application(environ, start_response): if 'ANSIBLE_CONFIG' in environ: os.environ['ANSIBLE_CONFIG'] = environ['ANSIBLE_CONFIG'] else: if 'ANSIBLE_CONFIG' not in os.environ: log.warn('ANSIBLE_CONFIG environment variable not found.') app = create_app() if not current_app: ctx = app.app_context() ctx.push() return app(environ, start_response) else: return current_app(environ, start_response)
def setUp(self): # TODO: Fix this, it's not used in create_app() and makes the databases # live on the filesystem rather than memory. self.config = { 'SQLALCHEMY_DATABASE_URI': 'sqlite://', 'TESTING': True } self.app = w.create_app() self.app_context = self.app.app_context() self.app_context.push() self.client = self.app.test_client() m.db.create_all()
def test_default_config(self): """ Ensure we have expected default parameters """ app = w.create_app() self.assertEqual(app.config['ARA_DIR'], c.DEFAULT_ARA_DIR) self.assertEqual( os.path.split(app.config['ARA_TMP_DIR'])[:-1][0], c.DEFAULT_ARA_TMP_DIR) self.assertEqual(app.config['ARA_LOG_FILE'], c.DEFAULT_ARA_LOG_FILE) self.assertEqual(app.config['ARA_LOG_LEVEL'], c.DEFAULT_ARA_LOG_LEVEL) self.assertEqual(app.config['ARA_LOG_FORMAT'], c.DEFAULT_ARA_LOG_FORMAT) self.assertEqual(app.config['ARA_PATH_MAX'], c.DEFAULT_ARA_PATH_MAX) self.assertEqual(app.config['SQLALCHEMY_ECHO'], c.DEFAULT_ARA_SQL_DEBUG) self.assertEqual(app.config['SQLALCHEMY_DATABASE_URI'], c.DEFAULT_DATABASE) self.assertEqual(app.config['FREEZER_IGNORE_MIMETYPE_WARNINGS'], c.DEFAULT_ARA_IGNORE_MIMETYPE_WARNINGS) self.assertEqual(app.config['ARA_ENABLE_DEBUG_VIEW'], False) self.assertEqual(app.config['ARA_AUTOCREATE_DATABASE'], True)
def application(environ, start_response): # Apache SetEnv variables are passed only in environ variable if (int(environ.get('ARA_WSGI_USE_VIRTUALENV', 0)) == 1 and environ.get('ARA_WSGI_VIRTUALENV_PATH')): # Backwards compatibility, we did not always suffix activate_this.py activate_this = environ.get('ARA_WSGI_VIRTUALENV_PATH') if 'activate_this.py' not in activate_this: activate_this = os.path.join(activate_this, 'bin/activate_this.py') if six.PY2: execfile(activate_this, dict(__file__=activate_this)) # nosec else: exec(open(activate_this).read()) # nosec TMPDIR_MAX_AGE = int(environ.get('ARA_WSGI_TMPDIR_MAX_AGE', 3600)) LOG_ROOT = environ.get('ARA_WSGI_LOG_ROOT', '/srv/static/logs') DATABASE_DIRECTORY = environ.get( 'ARA_WSGI_DATABASE_DIRECTORY', 'ara-report' ) request = environ['REQUEST_URI'] match = re.search('/(?P<path>.*/{}/)'.format(DATABASE_DIRECTORY), request) if not match: return bad_request(environ, start_response, 'No "/{}/" in URL.'.format(DATABASE_DIRECTORY)) path = os.path.abspath(os.path.join(LOG_ROOT, match.group('path'))) # Ensure we don't escape outside LOG_ROOT and we are looking at a # valid directory if not path.startswith(LOG_ROOT) or not os.path.isdir(path): logger.error('Directory access violation: %s' % path) return bad_request(environ, start_response, 'No directory found.') database = os.path.join(path, 'ansible.sqlite') if not os.path.isfile(database): return bad_request(environ, start_response, 'No ARA database found.') # ARA and Ansible (when loading configuration) both expect a directory # they are able to write to, this can be safely discarded. # Nothing is read from here and there is therefore no security risks. # It needs to be at a known location in order to be able to clean it up # so it doesn't accumulate needless directories and files. # TODO: ARA 1.0 no longer requires temporary directories, clean this up. tmpdir = '/tmp/ara_wsgi_sqlite' # nosec if os.path.exists(tmpdir): # Periodically delete this directory to avoid accumulating directories # and files endlessly now = time.time() if now - TMPDIR_MAX_AGE > os.path.getmtime(tmpdir): shutil.rmtree(tmpdir, ignore_errors=True) os.environ['ANSIBLE_LOCAL_TEMP'] = os.path.join(tmpdir, '.ansible') os.environ['ARA_DIR'] = os.path.join(tmpdir, '.ara') # Path to the ARA database os.environ['ARA_DATABASE'] = 'sqlite:///{}'.format(database) # The intent is that we are dealing with databases that already exist. # Therefore, we're not really interested in creating the database and # making sure that the SQL migrations are done. Toggle that off. # This needs to be a string, we're setting an environment variable os.environ['ARA_AUTOCREATE_DATABASE'] = 'false' msg = 'Request {request} mapped to {database} with root {root}'.format( request=request, database='sqlite:///{}'.format(database), root=match.group('path') ) logger.debug(msg) from ara.webapp import create_app try: app = create_app() app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///{}'.format(database) app.config['APPLICATION_ROOT'] = match.group('path') return app(environ, start_response) except Exception as e: # We're staying relatively vague on purpose to avoid disclosure logger.error('ARA bootstrap failure for %s: %s' % (database, str(e))) return bad_request(environ, start_response, 'ARA bootstrap failure.')
def create_app(self): return w.create_app(self)
def run(self, tmp=None, task_vars=None): if task_vars is None: task_vars = dict() if not HAS_ARA: result = { 'failed': True, 'msg': 'ARA is required to run this module.' } return result for arg in self._task.args: if arg not in self.VALID_ARGS: result = { "failed": True, "msg": '{0} is not a valid option.'.format(arg) } return result result = super(ActionModule, self).run(tmp, task_vars) playbook_id = self._task.args.get('playbook', None) key = self._task.args.get('key', None) value = self._task.args.get('value', None) type = self._task.args.get('type', 'text') required = ['key', 'value'] for parameter in required: if not self._task.args.get(parameter): result['failed'] = True result['msg'] = "Parameter '{0}' is required".format(parameter) return result if type not in self.VALID_TYPES: result['failed'] = True msg = "Type '{0}' is not supported, choose one of: {1}".format( type, ", ".join(self.VALID_TYPES) ) result['msg'] = msg return result app = create_app() if not current_app: context = app.app_context() context.push() if playbook_id is None: # Retrieve playbook_id from the cached context playbook_id = current_app._cache['playbook'] try: self.create_or_update_key(playbook_id, key, value, type) result['key'] = key result['value'] = value result['type'] = type result['playbook_id'] = playbook_id result['msg'] = 'Data recorded in ARA for this playbook.' except Exception as e: result['failed'] = True result['msg'] = 'Data not recorded in ARA: {0}'.format(str(e)) return result
def run(self, tmp=None, task_vars=None): if task_vars is None: task_vars = dict() if not HAS_ARA: result = { 'failed': True, 'msg': 'ARA is required to run this module.' } 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 = { "failed": True, "msg": '{0} is not a valid option.'.format(arg) } return result result = super(ActionModule, self).run(tmp, task_vars) playbook_id = self._task.args.get('playbook', None) key = self._task.args.get('key', None) value = self._task.args.get('value', None) type = self._task.args.get('type', 'text') required = ['key', 'value'] for parameter in required: if not self._task.args.get(parameter): result['failed'] = True result['msg'] = "Parameter '{0}' is required".format(parameter) return result if type not in self.VALID_TYPES: result['failed'] = True msg = "Type '{0}' is not supported, choose one of: {1}".format( type, ", ".join(self.VALID_TYPES) ) result['msg'] = msg return result 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'] try: self.create_or_update_key(playbook_id, key, value, type) result['key'] = key result['value'] = value result['type'] = type result['playbook_id'] = playbook_id result['msg'] = 'Data recorded in ARA for this playbook.' except Exception as e: result['failed'] = True result['msg'] = 'Data not recorded in ARA: {0}'.format(str(e)) return result
# 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 json import os from ansible.plugins.action import ActionBase try: from ara import models from ara.models import db from ara.webapp import create_app app = create_app() HAS_ARA = True except ImportError: HAS_ARA = False 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: key: description:
def application(environ, start_response): os.environ['ANSIBLE_CONFIG'] = environ['ANSIBLE_CONFIG'] from ara.webapp import create_app app = create_app() return app(environ, start_response)
# under the License. from collections import defaultdict import random import os import json from ara.webapp import create_app import ara.models as m import ara.utils as u import ara.plugins.callbacks.log_ara as l from ara.tests.unit.common import TestAra from ara.tests.unit import fakes a = create_app() class TestCallback(TestAra): """ Tests for the Ansible callback module """ def setUp(self): super(TestCallback, self).setUp() self.cb = l.CallbackModule() self.tag = '%04d' % random.randint(0, 9999) self.ansible_run() def tearDown(self): super(TestCallback, self).tearDown()
def application(environ, start_response): # Environment variables passed by mod_wsgi land in environ while environment # variables passed through gunicorn land in os.environ. config_variables = [ "ARA_WSGI_USE_VIRTUALENV", "ARA_WSGI_VIRTUALENV_PATH", "ARA_WSGI_TMPDIR_MAX_AGE", "ARA_WSGI_LOG_ROOT", "ARA_WSGI_DATABASE_DIRECTORY" ] for variable in config_variables: if variable in os.environ: environ[variable] = os.environ[variable] if (int(environ.get('ARA_WSGI_USE_VIRTUALENV', 0)) == 1 and environ.get('ARA_WSGI_VIRTUALENV_PATH')): # Backwards compatibility, we did not always suffix activate_this.py activate_this = environ.get('ARA_WSGI_VIRTUALENV_PATH') if 'activate_this.py' not in activate_this: activate_this = os.path.join(activate_this, 'bin/activate_this.py') if six.PY2: execfile(activate_this, dict(__file__=activate_this)) # nosec else: exec(open(activate_this).read()) # nosec TMPDIR_MAX_AGE = int(environ.get('ARA_WSGI_TMPDIR_MAX_AGE', 3600)) LOG_ROOT = environ.get('ARA_WSGI_LOG_ROOT', '/srv/static/logs') DATABASE_DIRECTORY = environ.get( 'ARA_WSGI_DATABASE_DIRECTORY', 'ara-report' ) # mod_wsgi uses REQUEST_URI, standardize on PATH_INFO instead if 'REQUEST_URI' in environ: environ['PATH_INFO'] = environ['SCRIPT_URL'] request = environ['PATH_INFO'] match = re.search('/(?P<path>.*/{}/)'.format(DATABASE_DIRECTORY), request) if not match: return bad_request(environ, start_response, 'No "/{}/" in URL.'.format(DATABASE_DIRECTORY)) # It is not sufficient to set Flask's APPLICATION_ROOT, we must also set # the SCRIPT_NAME variable to define the directory out of which the # application should be served. # See issues: # - https://github.com/pallets/flask/issues/1714 # - https://github.com/pallets/flask/issues/2759 if not environ['SCRIPT_NAME']: environ['SCRIPT_NAME'] = "/%s" % match.group('path') # When SCRIPT_NAME is set, remove it from PATH_INFO if environ['PATH_INFO'].startswith(environ['SCRIPT_NAME']): environ['PATH_INFO'] = environ['PATH_INFO'][len(environ['SCRIPT_NAME']):] if not environ['PATH_INFO']: environ['PATH_INFO'] = '/' path = os.path.abspath(os.path.join(LOG_ROOT, match.group('path'))) # Ensure we don't escape outside LOG_ROOT and we are looking at a # valid directory if not path.startswith(LOG_ROOT) or not os.path.isdir(path): logger.error('Directory access violation: %s' % path) return bad_request(environ, start_response, 'No directory found.') database = os.path.join(path, 'ansible.sqlite') if not os.path.isfile(database): return bad_request(environ, start_response, 'No ARA database found.') # ARA and Ansible (when loading configuration) both expect a directory # they are able to write to, this can be safely discarded. # Nothing is read from here and there is therefore no security risks. # It needs to be at a known location in order to be able to clean it up # so it doesn't accumulate needless directories and files. # TODO: ARA 1.0 no longer requires temporary directories, clean this up. tmpdir = '/tmp/ara_wsgi_sqlite' # nosec if os.path.exists(tmpdir): # Periodically delete this directory to avoid accumulating directories # and files endlessly now = time.time() if now - TMPDIR_MAX_AGE > os.path.getmtime(tmpdir): shutil.rmtree(tmpdir, ignore_errors=True) os.environ['ANSIBLE_LOCAL_TEMP'] = os.path.join(tmpdir, '.ansible') os.environ['ARA_DIR'] = os.path.join(tmpdir, '.ara') # The intent is that we are dealing with databases that already exist. # Therefore, we're not really interested in creating the database and # making sure that the SQL migrations are done. Toggle that off. # This needs to be a string, we're setting an environment variable os.environ['ARA_AUTOCREATE_DATABASE'] = 'false' msg = 'Request {request} mapped to {database} with root {root}'.format( request=request, database='sqlite:///{}'.format(database), root=match.group('path') ) logger.debug(msg) from ara.webapp import create_app try: app = create_app() app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///{}'.format(database) app.config['APPLICATION_ROOT'] = environ['PATH_INFO'] return app(environ, start_response) except Exception as e: # We're staying relatively vague on purpose to avoid disclosure logger.error('ARA bootstrap failure for %s: %s' % (database, str(e))) return bad_request(environ, start_response, 'ARA bootstrap failure.')
# 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/>. from flask_script import commands from flask_script import Manager from flask_script import prompt_bool from flask_migrate import Migrate from flask_migrate import MigrateCommand from ara.webapp import create_app from ara.models import db app = create_app() manager = Manager(app) manager.add_command('db', MigrateCommand) migrate = Migrate(app, db, directory=app.config['DB_MIGRATIONS']) # Overwrite the default runserver command to be able to pass a custom host # and port from the config as the defaults manager.add_command( "runserver", commands.Server(host=app.config['ARA_HOST'], port=app.config['ARA_PORT'], processes=8, threaded=False) )