Add simple Maintenance Mode WSGI middleware.
Additionally, this commit moves the auth middware to a common middleware module. Change-Id: Ieddc8ebca25b99483232cb4b0203871454789ad4
This commit is contained in:
parent
09fdf2a250
commit
9a107daf07
@ -13,6 +13,7 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import flask
|
||||
from designate.openstack.common import cfg
|
||||
from designate.openstack.common import local
|
||||
from designate.openstack.common import log as logging
|
||||
@ -22,8 +23,38 @@ from designate.context import DesignateContext
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
cfg.CONF.register_opts([
|
||||
cfg.BoolOpt('maintenance-mode', default=False,
|
||||
help='Enable API Maintenance Mode'),
|
||||
cfg.StrOpt('maintenance-mode-role', default='admin',
|
||||
help='Role allowed to bypass maintaince mode'),
|
||||
], group='service:api')
|
||||
|
||||
def pipeline_factory(loader, global_conf, **local_conf):
|
||||
|
||||
class MaintenanceMiddleware(wsgi.Middleware):
|
||||
def __init__(self, application):
|
||||
super(MaintenanceMiddleware, self).__init__(application)
|
||||
|
||||
self.enabled = cfg.CONF['service:api'].maintenance_mode
|
||||
self.role = cfg.CONF['service:api'].maintenance_mode_role
|
||||
|
||||
def process_request(self, request):
|
||||
# If maintaince mode is not enabled, pass the request on as soon as
|
||||
# possible
|
||||
if not self.enabled:
|
||||
return None
|
||||
|
||||
# If the caller has the bypass role, let them through
|
||||
if ('context' in request.environ
|
||||
and self.role in request.environ['context'].roles):
|
||||
LOG.warning('Request authorized to bypass maintenance mode')
|
||||
return None
|
||||
|
||||
# Otherwise, reject the request with a 503 Service Unavailable
|
||||
return flask.Response(status=503, headers={'Retry-After': 60})
|
||||
|
||||
|
||||
def auth_pipeline_factory(loader, global_conf, **local_conf):
|
||||
"""
|
||||
A paste pipeline replica that keys off of auth_strategy.
|
||||
|
@ -1,4 +1,5 @@
|
||||
# Copyright 2012 Managed I.T.
|
||||
# Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Author: Kiall Mac Innes <kiall@managedit.ie>
|
||||
#
|
||||
@ -14,20 +15,102 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
from designate.tests.test_api import ApiTestCase
|
||||
from designate.api import auth
|
||||
from designate.api import middleware
|
||||
|
||||
|
||||
class FakeContext(object):
|
||||
def __init__(self, roles=[]):
|
||||
self.roles = roles
|
||||
|
||||
|
||||
class FakeRequest(object):
|
||||
headers = {}
|
||||
environ = {}
|
||||
def __init__(self):
|
||||
self.headers = {}
|
||||
self.environ = {}
|
||||
|
||||
def get_response(self, app):
|
||||
return "FakeResponse"
|
||||
|
||||
|
||||
class MaintenanceMiddlewareTest(ApiTestCase):
|
||||
__test__ = True
|
||||
|
||||
def test_process_request_disabled(self):
|
||||
self.config(maintenance_mode=False, group='service:api')
|
||||
|
||||
request = FakeRequest()
|
||||
app = middleware.MaintenanceMiddleware({})
|
||||
|
||||
# Process the request
|
||||
response = app(request)
|
||||
|
||||
# Ensure request was not blocked
|
||||
self.assertEqual(response, 'FakeResponse')
|
||||
|
||||
def test_process_request_enabled_reject(self):
|
||||
self.config(maintenance_mode=True, maintenance_mode_role='admin',
|
||||
group='service:api')
|
||||
|
||||
request = FakeRequest()
|
||||
request.environ['context'] = FakeContext(roles=['user'])
|
||||
|
||||
app = middleware.MaintenanceMiddleware({})
|
||||
|
||||
# Process the request
|
||||
response = app(request)
|
||||
|
||||
# Ensure request was blocked
|
||||
self.assertEqual(response.status_code, 503)
|
||||
|
||||
def test_process_request_enabled_reject_no_roles(self):
|
||||
self.config(maintenance_mode=True, maintenance_mode_role='admin',
|
||||
group='service:api')
|
||||
|
||||
request = FakeRequest()
|
||||
request.environ['context'] = FakeContext(roles=[])
|
||||
|
||||
app = middleware.MaintenanceMiddleware({})
|
||||
|
||||
# Process the request
|
||||
response = app(request)
|
||||
|
||||
# Ensure request was blocked
|
||||
self.assertEqual(response.status_code, 503)
|
||||
|
||||
def test_process_request_enabled_reject_no_context(self):
|
||||
self.config(maintenance_mode=True, maintenance_mode_role='admin',
|
||||
group='service:api')
|
||||
|
||||
request = FakeRequest()
|
||||
app = middleware.MaintenanceMiddleware({})
|
||||
|
||||
# Process the request
|
||||
response = app(request)
|
||||
|
||||
# Ensure request was blocked
|
||||
self.assertEqual(response.status_code, 503)
|
||||
|
||||
def test_process_request_enabled_bypass(self):
|
||||
self.config(maintenance_mode=True, maintenance_mode_role='admin',
|
||||
group='service:api')
|
||||
|
||||
request = FakeRequest()
|
||||
request.environ['context'] = FakeContext(roles=['admin'])
|
||||
|
||||
app = middleware.MaintenanceMiddleware({})
|
||||
|
||||
# Process the request
|
||||
response = app(request)
|
||||
|
||||
# Ensure request was not blocked
|
||||
self.assertEqual(response, 'FakeResponse')
|
||||
|
||||
|
||||
class KeystoneContextMiddlewareTest(ApiTestCase):
|
||||
__test__ = True
|
||||
|
||||
def test_process_request(self):
|
||||
app = {}
|
||||
middleware = auth.KeystoneContextMiddleware(app)
|
||||
app = middleware.KeystoneContextMiddleware({})
|
||||
|
||||
request = FakeRequest()
|
||||
|
||||
@ -39,7 +122,7 @@ class KeystoneContextMiddlewareTest(ApiTestCase):
|
||||
}
|
||||
|
||||
# Process the request
|
||||
middleware.process_request(request)
|
||||
app.process_request(request)
|
||||
|
||||
self.assertIn('context', request.environ)
|
||||
|
||||
@ -55,8 +138,7 @@ class KeystoneContextMiddlewareTest(ApiTestCase):
|
||||
# Set the policy to accept the authz
|
||||
self.policy({'use_sudo': '@'})
|
||||
|
||||
app = {}
|
||||
middleware = auth.KeystoneContextMiddleware(app)
|
||||
app = middleware.KeystoneContextMiddleware({})
|
||||
|
||||
request = FakeRequest()
|
||||
|
||||
@ -70,7 +152,7 @@ class KeystoneContextMiddlewareTest(ApiTestCase):
|
||||
}
|
||||
|
||||
# Process the request
|
||||
middleware.process_request(request)
|
||||
app.process_request(request)
|
||||
|
||||
self.assertIn('context', request.environ)
|
||||
|
||||
@ -89,13 +171,12 @@ class NoAuthContextMiddlewareTest(ApiTestCase):
|
||||
__test__ = True
|
||||
|
||||
def test_process_request(self):
|
||||
app = {}
|
||||
middleware = auth.NoAuthContextMiddleware(app)
|
||||
app = middleware.NoAuthContextMiddleware({})
|
||||
|
||||
request = FakeRequest()
|
||||
|
||||
# Process the request
|
||||
middleware.process_request(request)
|
||||
app.process_request(request)
|
||||
|
||||
self.assertIn('context', request.environ)
|
||||
|
@ -15,7 +15,7 @@
|
||||
# under the License.
|
||||
from designate.openstack.common import log as logging
|
||||
from designate.api import v1 as api_v1
|
||||
from designate.api import auth
|
||||
from designate.api import middleware
|
||||
from designate.tests.test_api import ApiTestCase
|
||||
|
||||
|
||||
@ -35,7 +35,8 @@ class ApiV1Test(ApiTestCase):
|
||||
self.app.wsgi_app = api_v1.FaultWrapperMiddleware(self.app.wsgi_app)
|
||||
|
||||
# Inject the NoAuth middleware
|
||||
self.app.wsgi_app = auth.NoAuthContextMiddleware(self.app.wsgi_app)
|
||||
self.app.wsgi_app = middleware.NoAuthContextMiddleware(
|
||||
self.app.wsgi_app)
|
||||
|
||||
# Obtain a test client
|
||||
self.client = self.app.test_client()
|
||||
|
@ -7,9 +7,9 @@ use = egg:Paste#urlmap
|
||||
paste.app_factory = designate.api.versions:factory
|
||||
|
||||
[composite:osapi_dns_v1]
|
||||
use = call:designate.api.auth:pipeline_factory
|
||||
noauth = noauthcontext faultwrapper_v1 osapi_dns_app_v1
|
||||
keystone = authtoken keystonecontext faultwrapper_v1 osapi_dns_app_v1
|
||||
use = call:designate.api.middleware:auth_pipeline_factory
|
||||
noauth = noauthcontext maintenance faultwrapper_v1 osapi_dns_app_v1
|
||||
keystone = authtoken keystonecontext maintenance faultwrapper_v1 osapi_dns_app_v1
|
||||
|
||||
[app:osapi_dns_app_v1]
|
||||
paste.app_factory = designate.api.v1:factory
|
||||
@ -17,11 +17,14 @@ paste.app_factory = designate.api.v1:factory
|
||||
[filter:faultwrapper_v1]
|
||||
paste.filter_factory = designate.api.v1:FaultWrapperMiddleware.factory
|
||||
|
||||
[filter:maintenance]
|
||||
paste.filter_factory = designate.api.middleware:MaintenanceMiddleware.factory
|
||||
|
||||
[filter:noauthcontext]
|
||||
paste.filter_factory = designate.api.auth:NoAuthContextMiddleware.factory
|
||||
paste.filter_factory = designate.api.middleware:NoAuthContextMiddleware.factory
|
||||
|
||||
[filter:keystonecontext]
|
||||
paste.filter_factory = designate.api.auth:KeystoneContextMiddleware.factory
|
||||
paste.filter_factory = designate.api.middleware:KeystoneContextMiddleware.factory
|
||||
|
||||
[filter:authtoken]
|
||||
paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory
|
||||
|
Loading…
Reference in New Issue
Block a user