From 746a2c1eea7ebb410b3622a1876ced7154512bd0 Mon Sep 17 00:00:00 2001 From: chris meyers Date: Fri, 2 Mar 2018 11:04:18 -0500 Subject: [PATCH 1/2] short-circuit middleware if migration loading url * Had to monkey patch django middleware logic. * Left checks to tell coders to use new middleware behavior in favor of monkey patching. --- awx/main/middleware.py | 4 +++- awx/wsgi.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/awx/main/middleware.py b/awx/main/middleware.py index 94ba7b4c08..8ae8d444e1 100644 --- a/awx/main/middleware.py +++ b/awx/main/middleware.py @@ -20,6 +20,7 @@ from django.shortcuts import get_object_or_404, redirect from django.apps import apps from django.utils.translation import ugettext_lazy as _ from django.core.urlresolvers import reverse +from django.urls import resolve from awx.main.models import ActivityStream from awx.main.utils.named_url_graph import generate_graph, GraphNode @@ -193,5 +194,6 @@ class MigrationRanCheckMiddleware(object): def process_request(self, request): executor = MigrationExecutor(connection) plan = executor.migration_plan(executor.loader.graph.leaf_nodes()) - if bool(plan) and 'migrations_notran' not in request.path: + if bool(plan) and \ + getattr(resolve(request.path), 'url_name', '') != 'migrations_notran': return redirect(reverse("ui:migrations_notran")) diff --git a/awx/wsgi.py b/awx/wsgi.py index 4b2666a409..71bb0f6a92 100644 --- a/awx/wsgi.py +++ b/awx/wsgi.py @@ -8,7 +8,13 @@ from awx import __version__ as tower_version from awx import prepare_env, MODE prepare_env() + +from django.core.handlers.base import BaseHandler # NOQA from django.core.wsgi import get_wsgi_application # NOQA +import django # NOQA +from django.conf import settings # NOQA +from django.urls import resolve # NOQA + """ WSGI config for AWX project. @@ -29,5 +35,33 @@ if MODE == 'production': logger.error("Missing or incorrect metadata for Tower version. Ensure Tower was installed using the setup playbook.") raise Exception("Missing or incorrect metadata for Tower version. Ensure Tower was installed using the setup playbook.") + +if django.__version__ != '1.11.7': + raise RuntimeError("Django version other than 1.11.7 detected {}. \ + Monkey Patch to support short-circuit Django Middelware \ + is known to work for Django 1.11.7 and may not work with other, \ + even minor, versions.".format(django.__version__)) + + +if settings.MIDDLEWARE: + raise RuntimeError("MIDDLEWARE setting detected. \ + The 'migration in progress' view feature short-circuits OLD Django \ + MIDDLEWARE_CLASSES behavior. With the new Django MIDDLEWARE beahvior \ + it's possible to short-ciruit the middleware onion through supported \ + middleware mechanisms. The monkey patch wrapper below should be removed.") + + +def _wrapper_legacy_get_response(self, request): + # short-circuit middleware + if getattr(resolve(request.path), 'url_name', '') == 'migrations_notran': + return self._get_response(request) + # fall through to middle-ware + else: + return self._real_legacy_get_response(request) + + +BaseHandler._real_legacy_get_response = BaseHandler._legacy_get_response +BaseHandler._legacy_get_response = _wrapper_legacy_get_response + # Return the default Django WSGI application. application = get_wsgi_application() From 36d59651af0f383bee674d3fe0f507c8dc846d52 Mon Sep 17 00:00:00 2001 From: chris meyers Date: Fri, 2 Mar 2018 12:37:48 -0500 Subject: [PATCH 2/2] inherit rather than monkey patch * Enable migration in progress page in ALL environments --- awx/settings/defaults.py | 1 + awx/settings/production.py | 2 -- awx/wsgi.py | 33 ++++++++++++++++++--------------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py index 7d23eba0d4..9c012dbbfa 100644 --- a/awx/settings/defaults.py +++ b/awx/settings/defaults.py @@ -239,6 +239,7 @@ TEMPLATES = [ ] MIDDLEWARE_CLASSES = ( # NOQA + 'awx.main.middleware.MigrationRanCheckMiddleware', 'awx.main.middleware.TimingMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.locale.LocaleMiddleware', diff --git a/awx/settings/production.py b/awx/settings/production.py index 9df01dd720..d1d5baa3ad 100644 --- a/awx/settings/production.py +++ b/awx/settings/production.py @@ -89,8 +89,6 @@ settings_files = os.path.join(settings_dir, '*.py') settings_file = os.environ.get('AWX_SETTINGS_FILE', '/etc/tower/settings.py') -MIDDLEWARE_CLASSES = ('awx.main.middleware.MigrationRanCheckMiddleware',) + MIDDLEWARE_CLASSES - # Attempt to load settings from /etc/tower/settings.py first, followed by # /etc/tower/conf.d/*.py. try: diff --git a/awx/wsgi.py b/awx/wsgi.py index 71bb0f6a92..6033d6d54e 100644 --- a/awx/wsgi.py +++ b/awx/wsgi.py @@ -9,8 +9,7 @@ from awx import prepare_env, MODE prepare_env() -from django.core.handlers.base import BaseHandler # NOQA -from django.core.wsgi import get_wsgi_application # NOQA +from django.core.wsgi import WSGIHandler # NOQA import django # NOQA from django.conf import settings # NOQA from django.urls import resolve # NOQA @@ -38,8 +37,8 @@ if MODE == 'production': if django.__version__ != '1.11.7': raise RuntimeError("Django version other than 1.11.7 detected {}. \ - Monkey Patch to support short-circuit Django Middelware \ - is known to work for Django 1.11.7 and may not work with other, \ + Inherit from WSGIHandler to support short-circuit Django Middelware. \ + This is known to work for Django 1.11.7 and may not work with other, \ even minor, versions.".format(django.__version__)) @@ -48,20 +47,24 @@ if settings.MIDDLEWARE: The 'migration in progress' view feature short-circuits OLD Django \ MIDDLEWARE_CLASSES behavior. With the new Django MIDDLEWARE beahvior \ it's possible to short-ciruit the middleware onion through supported \ - middleware mechanisms. The monkey patch wrapper below should be removed.") + middleware mechanisms. Further, from django.core.wsgi.get_wsgi_application() \ + should be called to get an instance of WSGIHandler().") -def _wrapper_legacy_get_response(self, request): - # short-circuit middleware - if getattr(resolve(request.path), 'url_name', '') == 'migrations_notran': - return self._get_response(request) - # fall through to middle-ware - else: - return self._real_legacy_get_response(request) +class AWXWSGIHandler(WSGIHandler): + def _legacy_get_response(self, request): + # short-circuit middleware + if getattr(resolve(request.path), 'url_name', '') == 'migrations_notran': + return self._get_response(request) + # fall through to middle-ware + else: + return super(AWXWSGIHandler, self)._legacy_get_response(request) -BaseHandler._real_legacy_get_response = BaseHandler._legacy_get_response -BaseHandler._legacy_get_response = _wrapper_legacy_get_response - # Return the default Django WSGI application. +def get_wsgi_application(): + django.setup(set_prefix=False) + return AWXWSGIHandler() + + application = get_wsgi_application()