import logging import os import json import yaml from flask import Flask as BaseFlask, Config as BaseConfig, request, Request from flask.ext.principal import Principal from flask.ext.login import LoginManager, UserMixin from flask.ext.mail import Mail import features from storage import Storage from data import model from data import database from data.userfiles import Userfiles from data.users import UserAuthentication from util.analytics import Analytics from util.exceptionlog import Sentry from util.names import urn_generator from util.oauth import GoogleOAuthConfig, GithubOAuthConfig from data.billing import Billing from data.buildlogs import BuildLogs from data.archivedlogs import LogArchive from data.userevent import UserEventsBuilderModule from avatars.avatars import Avatar from util.queuemetrics import QueueMetrics from data.queue import WorkQueue class Config(BaseConfig): """ Flask config enhanced with a `from_yamlfile` method """ def from_yamlfile(self, config_file): with open(config_file) as f: c = yaml.load(f) if not c: logger.debug('Empty YAML config file') return if isinstance(c, str): raise Exception('Invalid YAML config file: ' + str(c)) for key in c.iterkeys(): if key.isupper(): self[key] = c[key] class Flask(BaseFlask): """ Extends the Flask class to implement our custom Config class. """ def make_config(self, instance_relative=False): root_path = self.instance_path if instance_relative else self.root_path return Config(root_path, self.default_config) OVERRIDE_CONFIG_YAML_FILENAME = 'conf/stack/config.yaml' OVERRIDE_CONFIG_PY_FILENAME = 'conf/stack/config.py' OVERRIDE_CONFIG_KEY = 'QUAY_OVERRIDE_CONFIG' LICENSE_FILENAME = 'conf/stack/license.enc' app = Flask(__name__) logger = logging.getLogger(__name__) profile = logging.getLogger('profile') if 'TEST' in os.environ: from test.testconfig import TestConfig logger.debug('Loading test config.') app.config.from_object(TestConfig()) else: from config import DefaultConfig logger.debug('Loading default config.') app.config.from_object(DefaultConfig()) if os.path.exists(OVERRIDE_CONFIG_PY_FILENAME): logger.debug('Applying config file: %s', OVERRIDE_CONFIG_PY_FILENAME) app.config.from_pyfile(OVERRIDE_CONFIG_PY_FILENAME) if os.path.exists(OVERRIDE_CONFIG_YAML_FILENAME): logger.debug('Applying config file: %s', OVERRIDE_CONFIG_YAML_FILENAME) app.config.from_yamlfile(OVERRIDE_CONFIG_YAML_FILENAME) environ_config = json.loads(os.environ.get(OVERRIDE_CONFIG_KEY, '{}')) app.config.update(environ_config) app.teardown_request(database.close_db_filter) class RequestWithId(Request): request_gen = staticmethod(urn_generator(['request'])) def __init__(self, *args, **kwargs): super(RequestWithId, self).__init__(*args, **kwargs) self.request_id = self.request_gen() @app.before_request def _request_start(): profile.debug('Starting request: %s', request.path) @app.after_request def _request_end(r): profile.debug('Ending request: %s', request.path) return r class InjectingFilter(logging.Filter): def filter(self, record): record.msg = '[%s] %s' % (request.request_id, record.msg) return True profile.addFilter(InjectingFilter()) app.request_class = RequestWithId features.import_features(app.config) Principal(app, use_sessions=False) avatar = Avatar(app) login_manager = LoginManager(app) mail = Mail(app) storage = Storage(app) userfiles = Userfiles(app, storage) log_archive = LogArchive(app, storage) analytics = Analytics(app) billing = Billing(app) sentry = Sentry(app) build_logs = BuildLogs(app) authentication = UserAuthentication(app) userevents = UserEventsBuilderModule(app) queue_metrics = QueueMetrics(app) tf = app.config['DB_TRANSACTION_FACTORY'] github_login = GithubOAuthConfig(app, 'GITHUB_LOGIN_CONFIG') github_trigger = GithubOAuthConfig(app, 'GITHUB_TRIGGER_CONFIG') google_login = GoogleOAuthConfig(app, 'GOOGLE_LOGIN_CONFIG') oauth_apps = [github_login, github_trigger, google_login] image_diff_queue = WorkQueue(app.config['DIFFS_QUEUE_NAME'], tf) dockerfile_build_queue = WorkQueue(app.config['DOCKERFILE_BUILD_QUEUE_NAME'], tf, reporter=queue_metrics.report) notification_queue = WorkQueue(app.config['NOTIFICATION_QUEUE_NAME'], tf) database.configure(app.config) model.config.app_config = app.config model.config.store = storage @login_manager.user_loader def load_user(user_uuid): logger.debug('User loader loading deferred user with uuid: %s' % user_uuid) return LoginWrappedDBUser(user_uuid) class LoginWrappedDBUser(UserMixin): def __init__(self, user_uuid, db_user=None): self._uuid = user_uuid self._db_user = db_user def db_user(self): if not self._db_user: self._db_user = model.get_user_by_uuid(self._uuid) return self._db_user def is_authenticated(self): return self.db_user() is not None def is_active(self): return self.db_user().verified def get_id(self): return unicode(self._uuid) def get_app_url(): return '%s://%s' % (app.config['PREFERRED_URL_SCHEME'], app.config['SERVER_HOSTNAME'])