Makes deployed APIs configurable

Uses config options enable_v1_api and enable_v2_api
to control which APIs have been deployed.
(Thanks markwash for all the help)

Fixes bug 1043497

Change-Id: I42dc1d88f94e61b9550c5f114ffc1abad25be7ff
This commit is contained in:
isethi 2012-08-31 17:53:32 +00:00
parent 3d4e962dac
commit 39700637e3
10 changed files with 182 additions and 10 deletions

View File

@ -23,7 +23,7 @@ pipeline = versionnegotiation authtoken context cache rootapp
pipeline = versionnegotiation authtoken context cache cachemanage rootapp
[composite:rootapp]
use = egg:Paste#urlmap
paste.composite_factory = glance.api:root_app_factory
/: apiversions
/v1: apiv1app
/v2: apiv2app

View File

@ -71,6 +71,12 @@ workers = 0
# privileges. This only applies when using ContextMiddleware.
#allow_anonymous_access = False
# Allow access to version 1 of glance api
# enable_v1_api = True
# Allow access to version 2 of glance api
# enable_v2_api = True
# ================= Syslog Options ============================
# Send logs to syslog (/dev/log) instead of to file specified

View File

@ -1,6 +1,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 OpenStack LLC.
# Copyright 2011-2012 OpenStack LLC.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -14,3 +14,18 @@
# 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 paste.urlmap
from glance.openstack.common import cfg
CONF = cfg.CONF
def root_app_factory(loader, global_conf, **local_conf):
if not CONF.enable_v1_api:
del local_conf['/v1']
if not CONF.enable_v2_api:
del local_conf['/v2']
return paste.urlmap.urlmap_factory(loader, global_conf, **local_conf)

View File

@ -24,6 +24,9 @@ return
from glance.api import versions
from glance.common import wsgi
import glance.openstack.common.log as logging
from glance.openstack.common import cfg
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
@ -77,9 +80,9 @@ class VersionNegotiationFilter(wsgi.Middleware):
:returns version found in the subject
:raises ValueError if no acceptable version could be found
"""
if subject in ('v1', 'v1.0', 'v1.1'):
if subject in ('v1', 'v1.0', 'v1.1') and CONF.enable_v1_api:
major_version = 1
elif subject in ('v2', 'v2.0'):
elif subject in ('v2', 'v2.0') and CONF.enable_v2_api:
major_version = 2
else:
raise ValueError()

View File

@ -21,6 +21,10 @@ import json
import webob.dec
from glance.common import wsgi
from glance.openstack.common import cfg
CONF = cfg.CONF
class Controller(object):
@ -41,11 +45,15 @@ class Controller(object):
],
}
version_objs = [
build_version_object(2.0, 'v2', 'EXPERIMENTAL'),
build_version_object(1.1, 'v1', 'CURRENT'),
build_version_object(1.0, 'v1', 'SUPPORTED'),
]
version_objs = []
if CONF.enable_v2_api:
version_objs.append(
build_version_object(2.0, 'v2', 'EXPERIMENTAL'))
if CONF.enable_v1_api:
version_objs.append(
build_version_object(1.1, 'v1', 'CURRENT'))
version_objs.append(
build_version_object(1.0, 'v1', 'SUPPORTED'))
response = webob.Response(request=req,
status=httplib.MULTIPLE_CHOICES,

View File

@ -54,6 +54,10 @@ common_opts = [
cfg.IntOpt('image_size_cap', default=1099511627776,
help=_("Maximum size of image a user can upload in bytes. "
"Defaults to 1099511627776 bytes (1 TB).")),
cfg.BoolOpt('enable_v1_api', default=True,
help=_("Deploy the v1 OpenStack Images API. ")),
cfg.BoolOpt('enable_v2_api', default=True,
help=_("Deploy the v2 OpenStack Images API. ")),
]
CONF = cfg.CONF

View File

@ -67,6 +67,8 @@ class Server(object):
self.exec_env = None
self.deployment_flavor = ''
self.show_image_direct_url = False
self.enable_v1_api = True
self.enable_v2_api = True
self.server_control_options = ''
self.needs_database = False
@ -276,6 +278,8 @@ policy_default_rule = %(policy_default_rule)s
db_auto_create = False
sql_connection = %(sql_connection)s
show_image_direct_url = %(show_image_direct_url)s
enable_v1_api = %(enable_v1_api)s
enable_v2_api= %(enable_v2_api)s
[paste_deploy]
flavor = %(deployment_flavor)s
"""
@ -300,7 +304,7 @@ pipeline = versionnegotiation fakeauth context rootapp
pipeline = versionnegotiation context rootapp
[composite:rootapp]
use = egg:Paste#urlmap
paste.composite_factory = glance.api:root_app_factory
/: apiversions
/v1: apiv1app
/v2: apiv2app

View File

@ -25,6 +25,100 @@ from glance.tests import functional
class TestRootApi(functional.FunctionalTest):
def test_version_configurations(self):
"""Test that versioning is handled properly through all channels"""
#v1 and v2 api enabled
self.cleanup()
self.start_servers(**self.__dict__.copy())
url = 'http://127.0.0.1:%d/v%%s/' % self.api_port
versions = {'versions': [
{
'id': 'v2.0',
'status': 'EXPERIMENTAL',
'links': [{'rel': 'self', 'href': url % '2'}],
},
{
'id': 'v1.1',
'status': 'CURRENT',
'links': [{'rel': 'self', 'href': url % '1'}],
},
{
'id': 'v1.0',
'status': 'SUPPORTED',
'links': [{'rel': 'self', 'href': url % '1'}],
},
]}
versions_json = json.dumps(versions)
images = {'images': []}
images_json = json.dumps(images)
# Verify version choices returned.
path = 'http://%s:%d' % ('127.0.0.1', self.api_port)
http = httplib2.Http()
response, content = http.request(path, 'GET')
self.assertEqual(response.status, 300)
self.assertEqual(content, versions_json)
self.stop_servers()
#v2 api enabled
self.cleanup()
self.api_server.enable_v1_api = False
self.api_server.enable_v2_api = True
self.start_servers(**self.__dict__.copy())
url = 'http://127.0.0.1:%d/v%%s/' % self.api_port
versions = {'versions': [
{
'id': 'v2.0',
'status': 'EXPERIMENTAL',
'links': [{'rel': 'self', 'href': url % '2'}],
},
]}
versions_json = json.dumps(versions)
images = {'images': []}
images_json = json.dumps(images)
# Verify version choices returned.
path = 'http://%s:%d' % ('127.0.0.1', self.api_port)
http = httplib2.Http()
response, content = http.request(path, 'GET')
self.assertEqual(response.status, 300)
self.assertEqual(content, versions_json)
self.stop_servers()
#v1 api enabled
self.cleanup()
self.api_server.enable_v1_api = True
self.api_server.enable_v2_api = False
self.start_servers(**self.__dict__.copy())
url = 'http://127.0.0.1:%d/v%%s/' % self.api_port
versions = {'versions': [
{
'id': 'v1.1',
'status': 'CURRENT',
'links': [{'rel': 'self', 'href': url % '1'}],
},
{
'id': 'v1.0',
'status': 'SUPPORTED',
'links': [{'rel': 'self', 'href': url % '1'}],
},
]}
versions_json = json.dumps(versions)
images = {'images': []}
images_json = json.dumps(images)
# Verify version choices returned.
path = 'http://%s:%d' % ('127.0.0.1', self.api_port)
http = httplib2.Http()
response, content = http.request(path, 'GET')
self.assertEqual(response.status, 300)
self.assertEqual(content, versions_json)
self.stop_servers()
def test_version_variations(self):
"""Test that versioning is handled properly through all channels"""

View File

@ -446,6 +446,28 @@ class TestApi(functional.FunctionalTest):
self.stop_servers()
@skip_if_disabled
def test_v1_not_enabled(self):
self.cleanup()
self.api_server.enable_v1_api = False
self.start_servers(**self.__dict__.copy())
path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
http = httplib2.Http()
response, content = http.request(path, 'GET')
self.assertEqual(response.status, 300)
self.stop_servers()
@skip_if_disabled
def test_v1_enabled(self):
self.cleanup()
self.api_server.enable_v1_api = True
self.start_servers(**self.__dict__.copy())
path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
http = httplib2.Http()
response, content = http.request(path, 'GET')
self.assertEqual(response.status, 200)
self.stop_servers()
@skip_if_disabled
def test_zero_initial_size(self):
"""

View File

@ -472,6 +472,22 @@ class TestImageDirectURLVisibility(functional.FunctionalTest):
base_headers.update(custom_headers or {})
return base_headers
def test_v2_not_enabled(self):
self.api_server.enable_v2_api = False
self.start_servers(**self.__dict__.copy())
path = self._url('/v2/images')
response = requests.get(path, headers=self._headers())
self.assertEqual(300, response.status_code)
self.stop_servers()
def test_v2_enabled(self):
self.api_server.enable_v2_api = True
self.start_servers(**self.__dict__.copy())
path = self._url('/v2/images')
response = requests.get(path, headers=self._headers())
self.assertEqual(200, response.status_code)
self.stop_servers()
def test_image_direct_url_visible(self):
self.api_server.show_image_direct_url = True