diff --git a/redash/__init__.py b/redash/__init__.py index cc50844c89..1abf9c3413 100644 --- a/redash/__init__.py +++ b/redash/__init__.py @@ -1,27 +1,22 @@ -import sys import logging -import urlparse +import os +import sys import urllib +import urlparse import redis -from flask import Flask, current_app -from werkzeug.contrib.fixers import ProxyFix -from werkzeug.routing import BaseConverter -from statsd import StatsClient from flask_mail import Mail from flask_limiter import Limiter from flask_limiter.util import get_ipaddr from flask_migrate import Migrate +from statsd import StatsClient -from redash import settings -from redash.query_runner import import_query_runners -from redash.destinations import import_destinations - +from . import settings +from .app import create_app # noqa __version__ = '7.0.0' -import os if os.environ.get("REMOTE_DEBUG"): import ptvsd ptvsd.enable_attach(address=('0.0.0.0', 5678)) @@ -36,10 +31,8 @@ def setup_logging(): # Make noisy libraries less noisy if settings.LOG_LEVEL != "DEBUG": - logging.getLogger("passlib").setLevel("ERROR") - logging.getLogger("requests.packages.urllib3").setLevel("ERROR") - logging.getLogger("snowflake.connector").setLevel("ERROR") - logging.getLogger('apiclient').setLevel("ERROR") + for name in ["passlib", "requests.packages.urllib3", "snowflake.connector", "apiclient"]: + logging.getLogger(name).setLevel("ERROR") def create_redis_connection(): @@ -67,69 +60,13 @@ def create_redis_connection(): setup_logging() + redis_connection = create_redis_connection() mail = Mail() -migrate = Migrate() -mail.init_mail(settings.all_settings()) -statsd_client = StatsClient(host=settings.STATSD_HOST, port=settings.STATSD_PORT, prefix=settings.STATSD_PREFIX) -limiter = Limiter(key_func=get_ipaddr, storage_uri=settings.LIMITER_STORAGE) - -import_query_runners(settings.QUERY_RUNNERS) -import_destinations(settings.DESTINATIONS) -from redash.version_check import reset_new_version_status -reset_new_version_status() - - -class SlugConverter(BaseConverter): - def to_python(self, value): - # This is ay workaround for when we enable multi-org and some files are being called by the index rule: - # for path in settings.STATIC_ASSETS_PATHS: - # full_path = safe_join(path, value) - # if os.path.isfile(full_path): - # raise ValidationError() - - return value - - def to_url(self, value): - return value - - -def create_app(): - from redash import authentication, extensions, handlers, security - from redash.handlers.webpack import configure_webpack - from redash.handlers import chrome_logger - from redash.models import db, users - from redash.metrics import request as request_metrics - from redash.utils import sentry - - sentry.init() - - app = Flask(__name__, - template_folder=settings.STATIC_ASSETS_PATH, - static_folder=settings.STATIC_ASSETS_PATH, - static_url_path='/static') - - # Make sure we get the right referral address even behind proxies like nginx. - app.wsgi_app = ProxyFix(app.wsgi_app, settings.PROXIES_COUNT) - app.url_map.converters['org_slug'] = SlugConverter - - # configure our database - app.config['SQLALCHEMY_DATABASE_URI'] = settings.SQLALCHEMY_DATABASE_URI - app.config.update(settings.all_settings()) +migrate = Migrate() - security.init_app(app) - request_metrics.init_app(app) - db.init_app(app) - migrate.init_app(app, db) - mail.init_app(app) - authentication.init_app(app) - limiter.init_app(app) - handlers.init_app(app) - configure_webpack(app) - extensions.init_app(app) - chrome_logger.init_app(app) - users.init_app(app) +statsd_client = StatsClient(host=settings.STATSD_HOST, port=settings.STATSD_PORT, prefix=settings.STATSD_PREFIX) - return app +limiter = Limiter(key_func=get_ipaddr, storage_uri=settings.LIMITER_STORAGE) diff --git a/redash/app.py b/redash/app.py new file mode 100644 index 0000000000..ea9e3d5536 --- /dev/null +++ b/redash/app.py @@ -0,0 +1,56 @@ +from flask import Flask +from werkzeug.contrib.fixers import ProxyFix + +from . import settings + + +class Redash(Flask): + """A custom Flask app for Redash""" + def __init__(self, *args, **kwargs): + kwargs.update({ + 'template_folder': settings.STATIC_ASSETS_PATH, + 'static_folder': settings.STATIC_ASSETS_PATH, + 'static_path': '/static', + }) + super(Redash, self).__init__(__name__, *args, **kwargs) + # Make sure we get the right referral address even behind proxies like nginx. + self.wsgi_app = ProxyFix(self.wsgi_app, settings.PROXIES_COUNT) + # Configure Redash using our settings + self.config.from_object('redash.settings') + + +def create_app(): + from . import authentication, extensions, handlers, limiter, mail, migrate, security + from .destinations import import_destinations + from .handlers import chrome_logger + from .handlers.webpack import configure_webpack + from .metrics import request as request_metrics + from .models import db, users + from .query_runner import import_query_runners + from .utils import sentry + from .version_check import reset_new_version_status + + sentry.init() + app = Redash() + + # Check and update the cached version for use by the client + app.before_first_request(reset_new_version_status) + + # Load query runners and destinations + import_query_runners(settings.QUERY_RUNNERS) + import_destinations(settings.DESTINATIONS) + + security.init_app(app) + request_metrics.init_app(app) + db.init_app(app) + migrate.init_app(app, db) + mail.init_app(app) + authentication.init_app(app) + limiter.init_app(app) + handlers.init_app(app) + configure_webpack(app) + extensions.init_app(app) + chrome_logger.init_app(app) + users.init_app(app) + + return app diff --git a/redash/cli/__init__.py b/redash/cli/__init__.py index 316e426d5d..fdf714ad70 100644 --- a/redash/cli/__init__.py +++ b/redash/cli/__init__.py @@ -15,9 +15,11 @@ def create(group): @app.shell_context_processor def shell_context(): - from redash import models - return dict(models=models) - + from redash import models, settings + return { + 'models': models, + 'settings': settings, + } return app @@ -48,7 +50,7 @@ def status(): @manager.command() def check_settings(): """Show the settings as Redash sees them (useful for debugging).""" - for name, item in settings.all_settings().iteritems(): + for name, item in current_app.config.iteritems(): print("{} = {}".format(name, item)) diff --git a/redash/handlers/base.py b/redash/handlers/base.py index 05e82d6c2a..e4bc8e66b2 100644 --- a/redash/handlers/base.py +++ b/redash/handlers/base.py @@ -117,7 +117,7 @@ def paginate(query_set, page, page_size, serializer, **kwargs): def org_scoped_rule(rule): if settings.MULTI_ORG: - return "/{}".format(rule) + return "/{}".format(rule) return rule diff --git a/redash/settings/__init__.py b/redash/settings/__init__.py index 2bb024d8b6..1b260177d4 100644 --- a/redash/settings/__init__.py +++ b/redash/settings/__init__.py @@ -4,19 +4,7 @@ from flask_talisman import talisman from .helpers import fix_assets_path, array_from_string, parse_boolean, int_or_none, set_from_string -from .organization import DATE_FORMAT - - -def all_settings(): - from types import ModuleType - - settings = {} - for name, item in globals().iteritems(): - if not callable(item) and not name.startswith("__") and not isinstance(item, ModuleType): - settings[name] = item - - return settings - +from .organization import DATE_FORMAT # noqa REDIS_URL = os.environ.get('REDASH_REDIS_URL', os.environ.get('REDIS_URL', "redis://localhost:6379/0")) PROXIES_COUNT = int(os.environ.get('REDASH_PROXIES_COUNT', "1")) diff --git a/redash/tasks/queries.py b/redash/tasks/queries.py index ab16209138..6002ccd275 100644 --- a/redash/tasks/queries.py +++ b/redash/tasks/queries.py @@ -11,7 +11,7 @@ from redash import models, redis_connection, settings, statsd_client from redash.query_runner import InterruptException from redash.tasks.alerts import check_alerts_for_query -from redash.utils import gen_query_hash, json_dumps, json_loads, utcnow, mustache_render +from redash.utils import gen_query_hash, json_dumps, utcnow, mustache_render from redash.worker import celery logger = get_task_logger(__name__) diff --git a/redash/worker.py b/redash/worker.py index 23c3d7b6fe..b46db432e2 100644 --- a/redash/worker.py +++ b/redash/worker.py @@ -8,8 +8,10 @@ from celery import Celery from celery.schedules import crontab from celery.signals import worker_process_init + from redash import create_app, settings -from redash.metrics import celery as celery_metrics +from redash.metrics import celery as celery_metrics # noqa + celery = Celery('redash', broker=settings.CELERY_BROKER, diff --git a/tests/__init__.py b/tests/__init__.py index 07a8fe8f85..9d0f0832b2 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -16,8 +16,8 @@ # Make sure rate limit is enabled os.environ['REDASH_RATELIMIT_ENABLED'] = "true" -from redash import create_app, limiter -from redash import redis_connection +from redash import limiter, redis_connection +from redash.app import create_app from redash.models import db from redash.utils import json_dumps, json_loads from tests.factories import Factory, user_factory