2013-09-23 16:37:40 +00:00
|
|
|
import logging
|
2013-10-01 03:54:12 +00:00
|
|
|
import os
|
2014-06-23 15:24:54 +00:00
|
|
|
import json
|
2014-08-22 00:36:11 +00:00
|
|
|
import yaml
|
2013-09-23 16:37:40 +00:00
|
|
|
|
2014-10-14 17:58:08 +00:00
|
|
|
from flask import Flask as BaseFlask, Config as BaseConfig, request, Request
|
2013-09-20 22:38:17 +00:00
|
|
|
from flask.ext.principal import Principal
|
2015-01-17 03:41:54 +00:00
|
|
|
from flask.ext.login import LoginManager, UserMixin
|
2013-09-27 23:29:01 +00:00
|
|
|
from flask.ext.mail import Mail
|
2013-10-03 20:19:01 +00:00
|
|
|
|
2014-04-03 22:47:17 +00:00
|
|
|
import features
|
|
|
|
|
2015-02-05 20:37:14 +00:00
|
|
|
from avatars.avatars import Avatar
|
2014-04-03 21:31:46 +00:00
|
|
|
from storage import Storage
|
2014-05-13 16:17:26 +00:00
|
|
|
from data import model
|
|
|
|
from data import database
|
2014-04-03 21:31:46 +00:00
|
|
|
from data.userfiles import Userfiles
|
2014-05-09 21:39:43 +00:00
|
|
|
from data.users import UserAuthentication
|
2014-04-10 19:20:16 +00:00
|
|
|
from data.billing import Billing
|
2014-05-09 22:45:11 +00:00
|
|
|
from data.buildlogs import BuildLogs
|
2014-09-08 20:43:17 +00:00
|
|
|
from data.archivedlogs import LogArchive
|
2014-05-30 18:25:29 +00:00
|
|
|
from data.userevent import UserEventsBuilderModule
|
2015-01-16 18:44:29 +00:00
|
|
|
from data.queue import WorkQueue
|
2015-02-05 20:37:14 +00:00
|
|
|
from util.analytics import Analytics
|
|
|
|
from util.exceptionlog import Sentry
|
|
|
|
from util.names import urn_generator
|
|
|
|
from util.oauth import GoogleOAuthConfig, GithubOAuthConfig
|
2015-02-04 20:29:24 +00:00
|
|
|
from util.signing import Signer
|
2015-02-05 20:37:14 +00:00
|
|
|
from util.queuemetrics import QueueMetrics
|
2015-02-02 21:54:23 +00:00
|
|
|
|
2013-09-20 15:55:44 +00:00
|
|
|
|
2015-02-05 20:37:14 +00:00
|
|
|
# pylint: disable=invalid-name,too-many-public-methods,too-few-public-methods,too-many-ancestors
|
2014-08-22 00:36:11 +00:00
|
|
|
class Config(BaseConfig):
|
|
|
|
""" Flask config enhanced with a `from_yamlfile` method """
|
2014-11-24 21:07:38 +00:00
|
|
|
|
2014-08-22 00:36:11 +00:00
|
|
|
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)
|
|
|
|
|
|
|
|
|
2015-02-04 20:29:24 +00:00
|
|
|
OVERRIDE_CONFIG_DIRECTORY = 'conf/stack/'
|
2014-08-22 00:36:11 +00:00
|
|
|
OVERRIDE_CONFIG_YAML_FILENAME = 'conf/stack/config.yaml'
|
|
|
|
OVERRIDE_CONFIG_PY_FILENAME = 'conf/stack/config.py'
|
|
|
|
|
2014-06-23 15:24:54 +00:00
|
|
|
OVERRIDE_CONFIG_KEY = 'QUAY_OVERRIDE_CONFIG'
|
2014-05-28 17:51:52 +00:00
|
|
|
LICENSE_FILENAME = 'conf/stack/license.enc'
|
2014-04-07 20:59:22 +00:00
|
|
|
|
|
|
|
|
2013-09-20 15:55:44 +00:00
|
|
|
app = Flask(__name__)
|
2013-10-03 20:19:01 +00:00
|
|
|
logger = logging.getLogger(__name__)
|
2014-10-14 17:58:08 +00:00
|
|
|
profile = logging.getLogger('profile')
|
2013-10-03 20:19:01 +00:00
|
|
|
|
2013-10-01 03:54:12 +00:00
|
|
|
|
2014-04-07 20:59:22 +00:00
|
|
|
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())
|
2014-04-03 21:31:46 +00:00
|
|
|
|
2014-08-22 00:36:11 +00:00
|
|
|
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)
|
2013-09-27 23:29:01 +00:00
|
|
|
|
2014-06-23 15:24:54 +00:00
|
|
|
environ_config = json.loads(os.environ.get(OVERRIDE_CONFIG_KEY, '{}'))
|
|
|
|
app.config.update(environ_config)
|
|
|
|
|
2014-10-14 17:58:08 +00:00
|
|
|
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
|
|
|
|
|
2014-04-03 22:47:17 +00:00
|
|
|
features.import_features(app.config)
|
|
|
|
|
2014-03-17 16:01:13 +00:00
|
|
|
Principal(app, use_sessions=False)
|
2013-09-20 22:38:17 +00:00
|
|
|
|
2014-11-25 00:25:13 +00:00
|
|
|
avatar = Avatar(app)
|
2014-04-09 03:05:45 +00:00
|
|
|
login_manager = LoginManager(app)
|
|
|
|
mail = Mail(app)
|
|
|
|
storage = Storage(app)
|
2014-09-09 19:54:03 +00:00
|
|
|
userfiles = Userfiles(app, storage)
|
2014-09-11 15:18:28 +00:00
|
|
|
log_archive = LogArchive(app, storage)
|
2014-04-09 03:05:45 +00:00
|
|
|
analytics = Analytics(app)
|
2014-04-10 19:20:16 +00:00
|
|
|
billing = Billing(app)
|
2014-04-28 22:59:22 +00:00
|
|
|
sentry = Sentry(app)
|
2014-05-09 22:45:11 +00:00
|
|
|
build_logs = BuildLogs(app)
|
2014-05-13 16:17:26 +00:00
|
|
|
authentication = UserAuthentication(app)
|
2014-05-30 18:25:29 +00:00
|
|
|
userevents = UserEventsBuilderModule(app)
|
2015-02-04 20:29:24 +00:00
|
|
|
signer = Signer(app, OVERRIDE_CONFIG_DIRECTORY)
|
2015-01-16 18:44:29 +00:00
|
|
|
queue_metrics = QueueMetrics(app)
|
|
|
|
|
|
|
|
tf = app.config['DB_TRANSACTION_FACTORY']
|
2014-05-21 23:50:37 +00:00
|
|
|
|
2014-11-05 21:43:37 +00:00
|
|
|
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]
|
|
|
|
|
2014-05-22 16:13:41 +00:00
|
|
|
image_diff_queue = WorkQueue(app.config['DIFFS_QUEUE_NAME'], tf)
|
|
|
|
dockerfile_build_queue = WorkQueue(app.config['DOCKERFILE_BUILD_QUEUE_NAME'], tf,
|
2014-05-21 23:50:37 +00:00
|
|
|
reporter=queue_metrics.report)
|
2014-07-18 02:51:58 +00:00
|
|
|
notification_queue = WorkQueue(app.config['NOTIFICATION_QUEUE_NAME'], tf)
|
2014-05-22 16:13:41 +00:00
|
|
|
|
2014-05-13 16:17:26 +00:00
|
|
|
database.configure(app.config)
|
|
|
|
model.config.app_config = app.config
|
|
|
|
model.config.store = storage
|
2014-07-29 17:47:54 +00:00
|
|
|
|
2015-01-17 03:41:54 +00:00
|
|
|
@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)
|
|
|
|
|
2014-07-29 17:47:54 +00:00
|
|
|
def get_app_url():
|
|
|
|
return '%s://%s' % (app.config['PREFERRED_URL_SCHEME'], app.config['SERVER_HOSTNAME'])
|