-
Notifications
You must be signed in to change notification settings - Fork 16.5k
Allow using Airflow with Flask CLI #9030
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6dc4690
1963033
9574677
33851e3
9e30431
77b1800
db582c6
cccb504
5a22fa0
38a5bf2
274a71e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,7 +20,7 @@ | |
| import logging | ||
| import socket | ||
| from datetime import timedelta | ||
| from typing import Any, Optional | ||
| from typing import Optional | ||
| from urllib.parse import urlparse | ||
|
|
||
| import flask | ||
|
|
@@ -39,15 +39,18 @@ | |
| from airflow.utils.json import AirflowJsonEncoder | ||
| from airflow.www.static_config import configure_manifest_files | ||
|
|
||
| app = None # type: Any | ||
| appbuilder = None # type: Optional[AppBuilder] | ||
| app: Optional[Flask] = None | ||
| csrf = CSRFProtect() | ||
|
|
||
| log = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| def root_app(env, resp): | ||
| resp(b'404 Not Found', [('Content-Type', 'text/plain')]) | ||
| return [b'Apache Airflow is not at this location'] | ||
|
|
||
|
|
||
| def create_app(config=None, testing=False, app_name="Airflow"): | ||
| global app, appbuilder | ||
| app = Flask(__name__) | ||
| app.secret_key = conf.get('webserver', 'SECRET_KEY') | ||
|
|
||
|
|
@@ -70,6 +73,31 @@ def create_app(config=None, testing=False, app_name="Airflow"): | |
| app.json_encoder = AirflowJsonEncoder | ||
|
|
||
| csrf.init_app(app) | ||
|
|
||
| def apply_middlewares(flask_app: Flask): | ||
| # Apply DispatcherMiddleware | ||
| base_url = urlparse(conf.get('webserver', 'base_url'))[2] | ||
| if not base_url or base_url == '/': | ||
| base_url = "" | ||
| if base_url: | ||
| flask_app.wsgi_app = DispatcherMiddleware( # type: ignore | ||
|
||
| root_app, | ||
| mounts={base_url: flask_app.wsgi_app} | ||
| ) | ||
|
|
||
| # Apply ProxyFix middleware | ||
| if conf.getboolean('webserver', 'ENABLE_PROXY_FIX'): | ||
| flask_app.wsgi_app = ProxyFix( # type: ignore | ||
| flask_app.wsgi_app, | ||
| x_for=conf.getint("webserver", "PROXY_FIX_X_FOR", fallback=1), | ||
| x_proto=conf.getint("webserver", "PROXY_FIX_X_PROTO", fallback=1), | ||
| x_host=conf.getint("webserver", "PROXY_FIX_X_HOST", fallback=1), | ||
| x_port=conf.getint("webserver", "PROXY_FIX_X_PORT", fallback=1), | ||
| x_prefix=conf.getint("webserver", "PROXY_FIX_X_PREFIX", fallback=1) | ||
| ) | ||
|
|
||
| apply_middlewares(app) | ||
|
|
||
| db = SQLA() | ||
| db.session = settings.Session | ||
| db.init_app(app) | ||
|
|
@@ -286,36 +314,11 @@ def apply_caching(response): | |
| def make_session_permanent(): | ||
| flask_session.permanent = True | ||
|
|
||
| return app, appbuilder | ||
|
|
||
|
|
||
| def root_app(env, resp): | ||
| resp(b'404 Not Found', [('Content-Type', 'text/plain')]) | ||
| return [b'Apache Airflow is not at this location'] | ||
| return app | ||
|
|
||
|
|
||
| def cached_app(config=None, testing=False): | ||
| global app, appbuilder | ||
| if not app or not appbuilder: | ||
| base_url = urlparse(conf.get('webserver', 'base_url'))[2] | ||
| if not base_url or base_url == '/': | ||
| base_url = "" | ||
|
|
||
| app, _ = create_app(config=config, testing=testing) | ||
| app = DispatcherMiddleware(root_app, {base_url: app}) | ||
| if conf.getboolean('webserver', 'ENABLE_PROXY_FIX'): | ||
| app = ProxyFix( | ||
| app, | ||
| x_for=conf.getint("webserver", "PROXY_FIX_X_FOR", fallback=1), | ||
| x_proto=conf.getint("webserver", "PROXY_FIX_X_PROTO", fallback=1), | ||
| x_host=conf.getint("webserver", "PROXY_FIX_X_HOST", fallback=1), | ||
| x_port=conf.getint("webserver", "PROXY_FIX_X_PORT", fallback=1), | ||
| x_prefix=conf.getint("webserver", "PROXY_FIX_X_PREFIX", fallback=1) | ||
| ) | ||
| global app | ||
| if not app: | ||
| app = create_app(config=config, testing=testing) | ||
| return app | ||
|
|
||
|
|
||
| def cached_appbuilder(config=None, testing=False): | ||
| global appbuilder | ||
| cached_app(config=config, testing=testing) | ||
| return appbuilder | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,9 +29,6 @@ | |
| from airflow.configuration import conf | ||
| from tests.test_utils.config import conf_vars | ||
|
|
||
| mock.patch('airflow.utils.cli.action_logging', lambda x: x).start() | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This caused a side effect. I don't know why it affected this change. Probably some session is now saving properly. |
||
| mock_args = Namespace(queues=1, concurrency=1) | ||
|
|
||
|
|
||
| class TestWorkerPrecheck(unittest.TestCase): | ||
| @mock.patch('airflow.settings.validate_session') | ||
|
|
@@ -42,7 +39,7 @@ def test_error(self, mock_validate_session): | |
| """ | ||
| mock_validate_session.return_value = False | ||
| with self.assertRaises(SystemExit) as cm: | ||
| celery_command.worker(mock_args) | ||
| celery_command.worker(Namespace(queues=1, concurrency=1)) | ||
| self.assertEqual(cm.exception.code, 1) | ||
|
|
||
| @conf_vars({('core', 'worker_precheck'): 'False'}) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This causes a side effect. We want the cache to be modified only by the cached_app method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great!