Add support for Host header in REST queries
Can use host request headers if enable_host_header is set to true in config file. If host header is not specified or host header is turned off, it will use the default api_base_uri. Also added unit tests. Change-Id: Ia353c116485f3e7112bcfde11457cdf7fe006422 Closes-bug: 1446387
This commit is contained in:
parent
1175e59d46
commit
1e266b1634
@ -25,6 +25,8 @@ cfg.CONF.register_opts([
|
|||||||
help='Number of api worker processes to spawn'),
|
help='Number of api worker processes to spawn'),
|
||||||
cfg.IntOpt('threads', default=1000,
|
cfg.IntOpt('threads', default=1000,
|
||||||
help='Number of api greenthreads to spawn'),
|
help='Number of api greenthreads to spawn'),
|
||||||
|
cfg.BoolOpt('enable-host-header', default=False,
|
||||||
|
help='Enable host request headers'),
|
||||||
cfg.StrOpt('api-base-uri', default='http://127.0.0.1:9001/'),
|
cfg.StrOpt('api-base-uri', default='http://127.0.0.1:9001/'),
|
||||||
cfg.StrOpt('api_host', default='0.0.0.0',
|
cfg.StrOpt('api_host', default='0.0.0.0',
|
||||||
help='API Host'),
|
help='API Host'),
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
import flask
|
import flask
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
cfg.CONF.import_opt('enable_host_header', 'designate.api', group='service:api')
|
||||||
|
|
||||||
|
|
||||||
def factory(global_config, **local_conf):
|
def factory(global_config, **local_conf):
|
||||||
app = flask.Flask('designate.api.versions')
|
app = flask.Flask('designate.api.versions')
|
||||||
@ -24,24 +26,32 @@ def factory(global_config, **local_conf):
|
|||||||
|
|
||||||
base = cfg.CONF['service:api'].api_base_uri.rstrip('/')
|
base = cfg.CONF['service:api'].api_base_uri.rstrip('/')
|
||||||
|
|
||||||
def _version(version, status):
|
def _host_header_links():
|
||||||
|
del versions[:]
|
||||||
|
host_url = flask.request.host_url
|
||||||
|
_version('v1', 'DEPRECATED', host_url)
|
||||||
|
_version('v2', 'CURRENT', host_url)
|
||||||
|
|
||||||
|
def _version(version, status, base_uri):
|
||||||
versions.append({
|
versions.append({
|
||||||
'id': '%s' % version,
|
'id': '%s' % version,
|
||||||
'status': status,
|
'status': status,
|
||||||
'links': [{
|
'links': [{
|
||||||
'href': base + '/' + version,
|
'href': base_uri + '/' + version,
|
||||||
'rel': 'self'
|
'rel': 'self'
|
||||||
}]
|
}]
|
||||||
})
|
})
|
||||||
|
|
||||||
if cfg.CONF['service:api'].enable_api_v1:
|
if cfg.CONF['service:api'].enable_api_v1:
|
||||||
_version('v1', 'DEPRECATED')
|
_version('v1', 'DEPRECATED', base)
|
||||||
|
|
||||||
if cfg.CONF['service:api'].enable_api_v2:
|
if cfg.CONF['service:api'].enable_api_v2:
|
||||||
_version('v2', 'CURRENT')
|
_version('v2', 'CURRENT', base)
|
||||||
|
|
||||||
@app.route('/', methods=['GET'])
|
@app.route('/', methods=['GET'])
|
||||||
def version_list():
|
def version_list():
|
||||||
|
if cfg.CONF['service:api'].enable_host_header:
|
||||||
|
_host_header_links()
|
||||||
|
|
||||||
return flask.jsonify({
|
return flask.jsonify({
|
||||||
"versions": {
|
"versions": {
|
||||||
|
@ -21,6 +21,7 @@ from designate.objects import base as obj_base
|
|||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
cfg.CONF.import_opt('api_base_uri', 'designate.api', group='service:api')
|
cfg.CONF.import_opt('api_base_uri', 'designate.api', group='service:api')
|
||||||
|
cfg.CONF.import_opt('enable_host_header', 'designate.api', group='service:api')
|
||||||
|
|
||||||
|
|
||||||
class APIv2Adapter(base.DesignateAdapter):
|
class APIv2Adapter(base.DesignateAdapter):
|
||||||
@ -77,8 +78,16 @@ class APIv2Adapter(base.DesignateAdapter):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _get_resource_links(cls, object, request):
|
def _get_resource_links(cls, object, request):
|
||||||
|
if cfg.CONF['service:api'].enable_host_header:
|
||||||
|
try:
|
||||||
|
base_uri = request.host_url
|
||||||
|
except Exception:
|
||||||
|
base_uri = cls.BASE_URI
|
||||||
|
else:
|
||||||
|
base_uri = cls.BASE_URI
|
||||||
|
|
||||||
return {'self': '%s%s/%s' %
|
return {'self': '%s%s/%s' %
|
||||||
(cls.BASE_URI, cls._get_path(request), object.id)}
|
(base_uri, cls._get_path(request), object.id)}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _get_path(cls, request):
|
def _get_path(cls, request):
|
||||||
@ -119,8 +128,16 @@ class APIv2Adapter(base.DesignateAdapter):
|
|||||||
if extra_params is not None:
|
if extra_params is not None:
|
||||||
params.update(extra_params)
|
params.update(extra_params)
|
||||||
|
|
||||||
|
if cfg.CONF['service:api'].enable_host_header:
|
||||||
|
try:
|
||||||
|
base_uri = request.host_url
|
||||||
|
except Exception:
|
||||||
|
base_uri = cls.BASE_URI
|
||||||
|
else:
|
||||||
|
base_uri = cls.BASE_URI
|
||||||
|
|
||||||
href = "%s%s?%s" % (
|
href = "%s%s?%s" % (
|
||||||
cls.BASE_URI,
|
base_uri,
|
||||||
cls._get_path(request),
|
cls._get_path(request),
|
||||||
parse.urlencode(params))
|
parse.urlencode(params))
|
||||||
|
|
||||||
|
52
designate/tests/test_api/test_v2/test_hostheaders.py
Normal file
52
designate/tests/test_api/test_v2/test_hostheaders.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Copyright (c) 2015 Rackspace Hosting
|
||||||
|
#
|
||||||
|
# Author: Mimi Lee <mimi.lee@rackspace.com>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from designate.tests.test_api.test_v2 import ApiV2TestCase
|
||||||
|
|
||||||
|
|
||||||
|
class ApiV2HostHeadersTest(ApiV2TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(ApiV2HostHeadersTest, self).setUp()
|
||||||
|
|
||||||
|
# Ensure v2 API and host headers are enabled
|
||||||
|
self.config(enable_api_v2=True, group='service:api')
|
||||||
|
self.config(enable_host_header=True, group='service:api')
|
||||||
|
|
||||||
|
def test_host_header(self):
|
||||||
|
# Create a zone with host header
|
||||||
|
fixture = self.get_domain_fixture(fixture=0)
|
||||||
|
response = self.client.post_json('/zones/',
|
||||||
|
fixture,
|
||||||
|
headers={'Host': 'testhost.com'})
|
||||||
|
# Check the headers are what we expect
|
||||||
|
self.assertEqual(202, response.status_int)
|
||||||
|
self.assertEqual('application/json', response.content_type)
|
||||||
|
|
||||||
|
# Check the host request header url
|
||||||
|
self.assertTrue('http://testhost.com/zones/' in
|
||||||
|
response.json_body['links']['self'])
|
||||||
|
|
||||||
|
# Get zone with host header
|
||||||
|
response = self.client.get('/zones/',
|
||||||
|
headers={'Host': 'testhost.com'})
|
||||||
|
|
||||||
|
# Check the headers are what we expect
|
||||||
|
self.assertEqual(200, response.status_int)
|
||||||
|
self.assertEqual('application/json', response.content_type)
|
||||||
|
|
||||||
|
# Check the host request header url
|
||||||
|
self.assertTrue('http://testhost.com/zones' in
|
||||||
|
response.json_body['links']['self'])
|
@ -84,6 +84,9 @@ debug = False
|
|||||||
# Number of api greenthreads to spawn
|
# Number of api greenthreads to spawn
|
||||||
#threads = 1000
|
#threads = 1000
|
||||||
|
|
||||||
|
# Enable host request headers
|
||||||
|
#enable_host_header = False
|
||||||
|
|
||||||
# The base uri used in responses
|
# The base uri used in responses
|
||||||
#api_base_uri = 'http://127.0.0.1:9001/'
|
#api_base_uri = 'http://127.0.0.1:9001/'
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user