Add rudimentary CORS support to placement API
If 'cors.allowed_origin' is set in the nova.conf, configure the placement API to use oslo_middleware.CORS. Simple gabbi tests are added which confirm the basic operation of the middleware, modeled on the tests in nova/tests/functional/test_middleware.py, as well as additional tests which confirm that when the middleware is not configured it is not present in the system. The cors config options are registered in deploy.py to ensure that the group is allowed to exist in conf (even if it doesn't). Without that, a deployment that tries to configure cors would not actually cause the middleware to run. Change-Id: I571bc675facaecb523dcf906f4bb44a51102b514
This commit is contained in:
parent
cee14139bd
commit
a598af9de6
@ -12,7 +12,8 @@
|
|||||||
"""Deployment handling for Placmenent API."""
|
"""Deployment handling for Placmenent API."""
|
||||||
|
|
||||||
from keystonemiddleware import auth_token
|
from keystonemiddleware import auth_token
|
||||||
from oslo_middleware import request_id
|
import oslo_middleware
|
||||||
|
from oslo_middleware import cors
|
||||||
|
|
||||||
from nova.api import openstack as common_api
|
from nova.api import openstack as common_api
|
||||||
from nova.api.openstack.placement import auth
|
from nova.api.openstack.placement import auth
|
||||||
@ -41,8 +42,18 @@ def deploy(conf, project_name):
|
|||||||
auth_middleware = auth_token.filter_factory(
|
auth_middleware = auth_token.filter_factory(
|
||||||
{}, oslo_config_project=project_name)
|
{}, oslo_config_project=project_name)
|
||||||
|
|
||||||
|
# Pass in our CORS config, if any, manually as that's a)
|
||||||
|
# explicit, b) makes testing more straightfoward, c) let's
|
||||||
|
# us control the use of cors by the presence of its config.
|
||||||
|
conf.register_opts(cors.CORS_OPTS, 'cors')
|
||||||
|
if conf.cors.allowed_origin:
|
||||||
|
cors_middleware = oslo_middleware.CORS.factory(
|
||||||
|
{}, **conf.cors)
|
||||||
|
else:
|
||||||
|
cors_middleware = None
|
||||||
|
|
||||||
context_middleware = auth.PlacementKeystoneContext
|
context_middleware = auth.PlacementKeystoneContext
|
||||||
req_id_middleware = request_id.RequestId
|
req_id_middleware = oslo_middleware.RequestId
|
||||||
microversion_middleware = microversion.MicroversionMiddleware
|
microversion_middleware = microversion.MicroversionMiddleware
|
||||||
fault_wrap = common_api.FaultWrapper
|
fault_wrap = common_api.FaultWrapper
|
||||||
request_log = requestlog.RequestLog
|
request_log = requestlog.RequestLog
|
||||||
@ -62,9 +73,11 @@ def deploy(conf, project_name):
|
|||||||
request_log,
|
request_log,
|
||||||
context_middleware,
|
context_middleware,
|
||||||
auth_middleware,
|
auth_middleware,
|
||||||
|
cors_middleware,
|
||||||
req_id_middleware,
|
req_id_middleware,
|
||||||
):
|
):
|
||||||
application = middleware(application)
|
if middleware:
|
||||||
|
application = middleware(application)
|
||||||
|
|
||||||
return application
|
return application
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from gabbi import fixture
|
from gabbi import fixture
|
||||||
|
from oslo_middleware import cors
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
from nova.api.openstack.placement import deploy
|
from nova.api.openstack.placement import deploy
|
||||||
@ -55,7 +56,16 @@ class APIFixture(fixture.GabbiFixture):
|
|||||||
group='api_database')
|
group='api_database')
|
||||||
self.conf.set_override('connection', "sqlite://",
|
self.conf.set_override('connection', "sqlite://",
|
||||||
group='placement_database')
|
group='placement_database')
|
||||||
config.parse_args([], default_config_files=None, configure_db=False,
|
|
||||||
|
# Register CORS opts, but do not set config. This has the
|
||||||
|
# effect of exercising the "don't use cors" path in
|
||||||
|
# deploy.py. Without setting some config the group will not
|
||||||
|
# be present.
|
||||||
|
self.conf.register_opts(cors.CORS_OPTS, 'cors')
|
||||||
|
|
||||||
|
# Make sure default_config_files is an empty list, not None.
|
||||||
|
# If None /etc/nova/nova.conf is read and confuses results.
|
||||||
|
config.parse_args([], default_config_files=[], configure_db=False,
|
||||||
init_rpc=False)
|
init_rpc=False)
|
||||||
|
|
||||||
# NOTE(cdent): api and main database are not used but we still need
|
# NOTE(cdent): api and main database are not used but we still need
|
||||||
@ -136,3 +146,15 @@ class AllocationFixture(APIFixture):
|
|||||||
# not been created in the Allocation fixture
|
# not been created in the Allocation fixture
|
||||||
os.environ['ALT_RP_UUID'] = uuidutils.generate_uuid()
|
os.environ['ALT_RP_UUID'] = uuidutils.generate_uuid()
|
||||||
os.environ['ALT_RP_NAME'] = uuidutils.generate_uuid()
|
os.environ['ALT_RP_NAME'] = uuidutils.generate_uuid()
|
||||||
|
|
||||||
|
|
||||||
|
class CORSFixture(APIFixture):
|
||||||
|
"""An APIFixture that turns on CORS."""
|
||||||
|
|
||||||
|
def start_fixture(self):
|
||||||
|
super(CORSFixture, self).start_fixture()
|
||||||
|
# NOTE(cdent): If we remove this override, then the cors
|
||||||
|
# group ends up not existing in the conf, so when deploy.py
|
||||||
|
# wants to load the CORS middleware, it will not.
|
||||||
|
self.conf.set_override('allowed_origin', 'http://valid.example.com',
|
||||||
|
group='cors')
|
||||||
|
@ -52,6 +52,16 @@ tests:
|
|||||||
response_strings:
|
response_strings:
|
||||||
- The method DELETE is not allowed for this resource.
|
- The method DELETE is not allowed for this resource.
|
||||||
|
|
||||||
|
- name: 405 on bad options method on app
|
||||||
|
OPTIONS: /resource_providers
|
||||||
|
status: 405
|
||||||
|
response_headers:
|
||||||
|
allow: /(GET|POST), (POST|GET)/
|
||||||
|
response_json_paths:
|
||||||
|
$.errors[0].title: Method Not Allowed
|
||||||
|
response_strings:
|
||||||
|
- The method OPTIONS is not allowed for this resource.
|
||||||
|
|
||||||
- name: bad accept resource providers
|
- name: bad accept resource providers
|
||||||
GET: /resource_providers
|
GET: /resource_providers
|
||||||
request_headers:
|
request_headers:
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
# Confirm that CORS is present. No complex configuration is done so
|
||||||
|
# this just tests the basics. Borrowed, in spirit, from
|
||||||
|
# nova.tests.functional.test_middleware.
|
||||||
|
|
||||||
|
fixtures:
|
||||||
|
- CORSFixture
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
request_headers:
|
||||||
|
x-auth-token: user
|
||||||
|
|
||||||
|
tests:
|
||||||
|
- name: valid options request
|
||||||
|
OPTIONS: /
|
||||||
|
request_headers:
|
||||||
|
origin: http://valid.example.com
|
||||||
|
access-control-request-method: GET
|
||||||
|
status: 200
|
||||||
|
response_headers:
|
||||||
|
access-control-allow-origin: http://valid.example.com
|
||||||
|
|
||||||
|
- name: invalid options request
|
||||||
|
OPTIONS: /
|
||||||
|
request_headers:
|
||||||
|
origin: http://invalid.example.com
|
||||||
|
access-control-request-method: GET
|
||||||
|
status: 200
|
||||||
|
response_forbidden_headers:
|
||||||
|
- access-control-allow-origin
|
||||||
|
|
||||||
|
- name: valid get request
|
||||||
|
GET: /
|
||||||
|
request_headers:
|
||||||
|
origin: http://valid.example.com
|
||||||
|
access-control-request-method: GET
|
||||||
|
status: 200
|
||||||
|
response_headers:
|
||||||
|
access-control-allow-origin: http://valid.example.com
|
||||||
|
|
||||||
|
- name: invalid get request
|
||||||
|
GET: /
|
||||||
|
request_headers:
|
||||||
|
origin: http://invalid.example.com
|
||||||
|
access-control-request-method: GET
|
||||||
|
status: 200
|
||||||
|
response_forbidden_headers:
|
||||||
|
- access-control-allow-origin
|
@ -0,0 +1,25 @@
|
|||||||
|
# Confirm that things work as intended when CORS is not configured.
|
||||||
|
|
||||||
|
fixtures:
|
||||||
|
- APIFixture
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
request_headers:
|
||||||
|
x-auth-token: user
|
||||||
|
|
||||||
|
tests:
|
||||||
|
- name: options request not allowed
|
||||||
|
OPTIONS: /
|
||||||
|
request_headers:
|
||||||
|
origin: http://valid.example.com
|
||||||
|
access-control-request-method: GET
|
||||||
|
status: 405
|
||||||
|
|
||||||
|
- name: get request no cors headers
|
||||||
|
GET: /
|
||||||
|
request_headers:
|
||||||
|
origin: http://valid.example.com
|
||||||
|
access-control-request-method: GET
|
||||||
|
status: 200
|
||||||
|
response_forbidden_headers:
|
||||||
|
- access-control-allow-origin
|
9
releasenotes/notes/placement-cors-c7a83e8c63787736.yaml
Normal file
9
releasenotes/notes/placement-cors-c7a83e8c63787736.yaml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
The placement API service can now be configured to support
|
||||||
|
`CORS <http://docs.openstack.org/developer/oslo.middleware/cors.html>`_.
|
||||||
|
If a `cors` configuration group is present in the service's configuration
|
||||||
|
file (currently `nova.conf`), with `allowed_origin` configured, the values
|
||||||
|
within will be used to configure the middleware. If `cors.allowed_origin`
|
||||||
|
is not set, the middleware will not be used.
|
Loading…
Reference in New Issue
Block a user