Changes versioned URIs to be /v1/ instead of /v1.0/
Adds middleware that detects versioned URIs and also detects media types in the Accept: header and attempts to determine the API controller to return for the client request. Adds a bunch of functional test cases for variations of calling the versioned and unversioned URIs with and without Accept: headers.
This commit is contained in:
parent
7f6944c816
commit
77054d402c
@ -51,19 +51,17 @@ swift_store_container = glance
|
||||
# Do we create the container if it does not exist?
|
||||
swift_store_create_container_on_put = False
|
||||
|
||||
[composite:glance-api]
|
||||
use = egg:Paste#urlmap
|
||||
/: versions
|
||||
/v1.0: api_1_0
|
||||
|
||||
[pipeline:api_1_0]
|
||||
pipeline = api_1_0_app
|
||||
[pipeline:glance-api]
|
||||
pipeline = versionnegotiation apiv1app
|
||||
|
||||
[pipeline:versions]
|
||||
pipeline = versions_app
|
||||
pipeline = versionsapp
|
||||
|
||||
[app:versions_app]
|
||||
[app:versionsapp]
|
||||
paste.app_factory = glance.api.versions:app_factory
|
||||
|
||||
[app:api_1_0_app]
|
||||
paste.app_factory = glance.api.v1_0:app_factory
|
||||
[app:apiv1app]
|
||||
paste.app_factory = glance.api.v1:app_factory
|
||||
|
||||
[filter:versionnegotiation]
|
||||
paste.filter_factory = glance.api.middleware.version_negotiation:filter_factory
|
||||
|
16
glance/api/middleware/__init__.py
Normal file
16
glance/api/middleware/__init__.py
Normal file
@ -0,0 +1,16 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2011 OpenStack LLC.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
118
glance/api/middleware/version_negotiation.py
Normal file
118
glance/api/middleware/version_negotiation.py
Normal file
@ -0,0 +1,118 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2011 OpenStack LLC.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
A filter middleware that inspects the requested URI for a version string
|
||||
and/or Accept headers and attempts to negotiate an API controller to
|
||||
return
|
||||
"""
|
||||
|
||||
import logging
|
||||
import re
|
||||
|
||||
import routes
|
||||
|
||||
from glance.api import v1
|
||||
from glance.api import versions
|
||||
from glance.common import wsgi
|
||||
|
||||
logger = logging.getLogger('glance.api.middleware.version_negotiation')
|
||||
|
||||
|
||||
class VersionNegotiationFilter(wsgi.Middleware):
|
||||
|
||||
def __init__(self, app, options):
|
||||
self.versions_app = versions.Controller(options)
|
||||
self.version_uri_regex = re.compile(r"^v(\d+)\.?(\d+)?")
|
||||
self.options = options
|
||||
super(VersionNegotiationFilter, self).__init__(app)
|
||||
|
||||
def process_request(self, req):
|
||||
"""
|
||||
If there is a version identifier in the URI, simply
|
||||
return the correct API controller, otherwise, if we
|
||||
find an Accept: header, process it
|
||||
"""
|
||||
# See if a version identifier is in the URI passed to
|
||||
# us already. If so, simply return the right version
|
||||
# API controller
|
||||
logger.debug("Processing request: %s %s Accept: %s",
|
||||
req.method, req.path, req.accept)
|
||||
match = self._match_version_string(req.path_info_peek(), req)
|
||||
if match:
|
||||
logger.debug("Matched versioned URI. Version: %d.%d",
|
||||
req.environ['api.major_version'],
|
||||
req.environ['api.minor_version'])
|
||||
if req.environ['api.major_version'] == 1:
|
||||
# Strip the version from the path
|
||||
req.path_info_pop()
|
||||
return None
|
||||
else:
|
||||
return self.versions_app
|
||||
|
||||
accept = req.headers['Accept']
|
||||
if accept.startswith('application/vnd.openstack.images'):
|
||||
token_loc = len('application/vnd.openstack.images')
|
||||
accept_version = accept[token_loc:]
|
||||
match = self._match_version_string(accept_version, req)
|
||||
if match:
|
||||
logger.debug("Matched versioned media type. Version: %d.%d",
|
||||
req.environ['api.major_version'],
|
||||
req.environ['api.minor_version'])
|
||||
if req.environ['api.major_version'] == 1:
|
||||
return None
|
||||
else:
|
||||
return self.versions_app
|
||||
else:
|
||||
if req.accept not in ('*/*', ''):
|
||||
logger.debug("Unknown accept header: %s..."
|
||||
"returning version choices.", req.accept)
|
||||
return self.versions_app
|
||||
return None
|
||||
|
||||
def _match_version_string(self, subject, req):
|
||||
"""
|
||||
Given a subject string, tries to match a major and/or
|
||||
minor version number. If found, sets the api.major_version
|
||||
and api.minor_version environ variables.
|
||||
|
||||
Returns True if there was a match, false otherwise.
|
||||
|
||||
:param subject: The string to check
|
||||
:param req: Webob.Request object
|
||||
"""
|
||||
match = self.version_uri_regex.match(subject)
|
||||
if match:
|
||||
major_version, minor_version = match.groups(0)
|
||||
major_version = int(major_version)
|
||||
minor_version = int(minor_version)
|
||||
req.environ['api.major_version'] = major_version
|
||||
req.environ['api.minor_version'] = minor_version
|
||||
return match is not None
|
||||
|
||||
|
||||
def filter_factory(global_conf, **local_conf):
|
||||
"""
|
||||
Factory method for paste.deploy
|
||||
"""
|
||||
conf = global_conf.copy()
|
||||
conf.update(local_conf)
|
||||
|
||||
def filter(app):
|
||||
return VersionNegotiationFilter(app, conf)
|
||||
|
||||
return filter
|
@ -19,15 +19,15 @@ import logging
|
||||
|
||||
import routes
|
||||
|
||||
from glance.api.v1_0 import images
|
||||
from glance.api.v1 import images
|
||||
from glance.common import wsgi
|
||||
|
||||
logger = logging.getLogger('glance.api.v1_0')
|
||||
logger = logging.getLogger('glance.api.v1')
|
||||
|
||||
|
||||
class API(wsgi.Router):
|
||||
|
||||
"""WSGI router for Glance v1.0 API requests."""
|
||||
"""WSGI router for Glance v1 API requests."""
|
||||
|
||||
def __init__(self, options):
|
||||
self.options = options
|
@ -16,7 +16,7 @@
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
/images endpoint for Glance v1.0 API
|
||||
/images endpoint for Glance v1 API
|
||||
"""
|
||||
|
||||
import httplib
|
||||
@ -40,13 +40,13 @@ from glance import registry
|
||||
from glance import utils
|
||||
|
||||
|
||||
logger = logging.getLogger('glance.api.v1_0.images')
|
||||
logger = logging.getLogger('glance.api.v1.images')
|
||||
|
||||
|
||||
class Controller(wsgi.Controller):
|
||||
|
||||
"""
|
||||
WSGI controller for images resource in Glance v1.0 API
|
||||
WSGI controller for images resource in Glance v1 API
|
||||
|
||||
The images resource API is a RESTful web service for image data. The API
|
||||
is as follows::
|
||||
@ -131,7 +131,7 @@ class Controller(wsgi.Controller):
|
||||
|
||||
res = Response(request=req)
|
||||
utils.inject_image_meta_into_headers(res, image)
|
||||
res.headers.add('Location', "/v1.0/images/%s" % id)
|
||||
res.headers.add('Location', "/v1/images/%s" % id)
|
||||
res.headers.add('ETag', image['checksum'])
|
||||
|
||||
return req.get_response(res)
|
||||
@ -164,7 +164,7 @@ class Controller(wsgi.Controller):
|
||||
# Using app_iter blanks content-length, so we set it here...
|
||||
res.headers.add('Content-Length', image['size'])
|
||||
utils.inject_image_meta_into_headers(res, image)
|
||||
res.headers.add('Location', "/v1.0/images/%s" % id)
|
||||
res.headers.add('Location', "/v1/images/%s" % id)
|
||||
res.headers.add('ETag', image['checksum'])
|
||||
return req.get_response(res)
|
||||
|
||||
@ -386,7 +386,7 @@ class Controller(wsgi.Controller):
|
||||
# URI of the resource newly-created.
|
||||
res = Response(request=req, body=json.dumps(dict(image=image_meta)),
|
||||
status=httplib.CREATED, content_type="text/plain")
|
||||
res.headers.add('Location', "/v1.0/images/%s" % image_id)
|
||||
res.headers.add('Location', "/v1/images/%s" % image_id)
|
||||
res.headers.add('ETag', image_meta['checksum'])
|
||||
|
||||
return req.get_response(res)
|
@ -56,7 +56,7 @@ class Controller(object):
|
||||
return response
|
||||
|
||||
def get_href(self):
|
||||
return "http://%s:%s/v1.0" % (self.options['bind_host'],
|
||||
return "http://%s:%s/v1/" % (self.options['bind_host'],
|
||||
self.options['bind_port'])
|
||||
|
||||
|
||||
|
@ -177,13 +177,13 @@ class BaseClient(object):
|
||||
return response.status
|
||||
|
||||
|
||||
class V1_0_Client(BaseClient):
|
||||
class V1Client(BaseClient):
|
||||
|
||||
"""Main client class for accessing Glance resources"""
|
||||
|
||||
DEFAULT_PORT = 9292
|
||||
|
||||
def __init__(self, host, port=None, use_ssl=False, doc_root="/v1.0"):
|
||||
def __init__(self, host, port=None, use_ssl=False, doc_root="/v1"):
|
||||
"""
|
||||
Creates a new client to a Glance API service.
|
||||
|
||||
@ -199,7 +199,7 @@ class V1_0_Client(BaseClient):
|
||||
|
||||
def do_request(self, method, action, body=None, headers=None):
|
||||
action = "%s/%s" % (self.doc_root, action.lstrip("/"))
|
||||
return super(V1_0_Client, self).do_request(method, action,
|
||||
return super(V1Client, self).do_request(method, action,
|
||||
body, headers)
|
||||
|
||||
def get_images(self):
|
||||
@ -297,4 +297,4 @@ class V1_0_Client(BaseClient):
|
||||
return True
|
||||
|
||||
|
||||
Client = V1_0_Client
|
||||
Client = V1Client
|
||||
|
@ -148,22 +148,20 @@ registry_host = 0.0.0.0
|
||||
registry_port = %(registry_port)s
|
||||
log_file = %(log_file)s
|
||||
|
||||
[composite:glance-api]
|
||||
use = egg:Paste#urlmap
|
||||
/: versions
|
||||
/v1.0: api_1_0
|
||||
|
||||
[pipeline:api_1_0]
|
||||
pipeline = api_1_0_app
|
||||
[pipeline:glance-api]
|
||||
pipeline = versionnegotiation apiv1app
|
||||
|
||||
[pipeline:versions]
|
||||
pipeline = versions_app
|
||||
pipeline = versionsapp
|
||||
|
||||
[app:versions_app]
|
||||
[app:versionsapp]
|
||||
paste.app_factory = glance.api.versions:app_factory
|
||||
|
||||
[app:api_1_0_app]
|
||||
paste.app_factory = glance.api.v1_0:app_factory
|
||||
[app:apiv1app]
|
||||
paste.app_factory = glance.api.v1:app_factory
|
||||
|
||||
[filter:versionnegotiation]
|
||||
paste.filter_factory = glance.api.middleware.version_negotiation:filter_factory
|
||||
"""
|
||||
|
||||
|
||||
|
@ -72,7 +72,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
|
||||
# 0. GET /images
|
||||
# Verify no public images
|
||||
cmd = "curl -g http://0.0.0.0:%d/v1.0/images" % api_port
|
||||
cmd = "curl http://0.0.0.0:%d/v1/images" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
@ -81,7 +81,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
|
||||
# 1. GET /images/detail
|
||||
# Verify no public images
|
||||
cmd = "curl -g http://0.0.0.0:%d/v1.0/images/detail" % api_port
|
||||
cmd = "curl http://0.0.0.0:%d/v1/images/detail" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
@ -90,7 +90,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
|
||||
# 2. HEAD /images/1
|
||||
# Verify 404 returned
|
||||
cmd = "curl -i -X HEAD http://0.0.0.0:%d/v1.0/images/1" % api_port
|
||||
cmd = "curl -i -X HEAD http://0.0.0.0:%d/v1/images/1" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
@ -111,7 +111,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
"-H 'X-Image-Meta-Name: Image1' "
|
||||
"-H 'X-Image-Meta-Is-Public: True' "
|
||||
"--data-binary \"%s\" "
|
||||
"http://0.0.0.0:%d/v1.0/images") % (image_data, api_port)
|
||||
"http://0.0.0.0:%d/v1/images") % (image_data, api_port)
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
self.assertEqual(0, exitcode)
|
||||
@ -123,7 +123,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
|
||||
# 4. HEAD /images
|
||||
# Verify image found now
|
||||
cmd = "curl -i -X HEAD http://0.0.0.0:%d/v1.0/images/1" % api_port
|
||||
cmd = "curl -i -X HEAD http://0.0.0.0:%d/v1/images/1" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
@ -138,7 +138,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
# 5. GET /images/1
|
||||
# Verify all information on image we just added is correct
|
||||
|
||||
cmd = "curl -i -g http://0.0.0.0:%d/v1.0/images/1" % api_port
|
||||
cmd = "curl -i http://0.0.0.0:%d/v1/images/1" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
@ -212,7 +212,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
|
||||
# 6. GET /images
|
||||
# Verify no public images
|
||||
cmd = "curl -g http://0.0.0.0:%d/v1.0/images" % api_port
|
||||
cmd = "curl http://0.0.0.0:%d/v1/images" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
@ -229,7 +229,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
|
||||
# 7. GET /images/detail
|
||||
# Verify image and all its metadata
|
||||
cmd = "curl -g http://0.0.0.0:%d/v1.0/images/detail" % api_port
|
||||
cmd = "curl http://0.0.0.0:%d/v1/images/detail" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
@ -266,7 +266,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
cmd = ("curl -i -X PUT "
|
||||
"-H 'X-Image-Meta-Property-Distro: Ubuntu' "
|
||||
"-H 'X-Image-Meta-Property-Arch: x86_64' "
|
||||
"http://0.0.0.0:%d/v1.0/images/1") % api_port
|
||||
"http://0.0.0.0:%d/v1/images/1") % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
self.assertEqual(0, exitcode)
|
||||
@ -278,7 +278,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
|
||||
# 9. GET /images/detail
|
||||
# Verify image and all its metadata
|
||||
cmd = "curl -g http://0.0.0.0:%d/v1.0/images/detail" % api_port
|
||||
cmd = "curl http://0.0.0.0:%d/v1/images/detail" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
@ -312,7 +312,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
# 10. PUT /images/1 and remove a previously existing property.
|
||||
cmd = ("curl -i -X PUT "
|
||||
"-H 'X-Image-Meta-Property-Arch: x86_64' "
|
||||
"http://0.0.0.0:%d/v1.0/images/1") % api_port
|
||||
"http://0.0.0.0:%d/v1/images/1") % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
self.assertEqual(0, exitcode)
|
||||
@ -322,7 +322,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
|
||||
self.assertEqual("HTTP/1.1 200 OK", status_line)
|
||||
|
||||
cmd = "curl -g http://0.0.0.0:%d/v1.0/images/detail" % api_port
|
||||
cmd = "curl http://0.0.0.0:%d/v1/images/detail" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
@ -336,7 +336,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
cmd = ("curl -i -X PUT "
|
||||
"-H 'X-Image-Meta-Property-Distro: Ubuntu' "
|
||||
"-H 'X-Image-Meta-Property-Arch: x86_64' "
|
||||
"http://0.0.0.0:%d/v1.0/images/1") % api_port
|
||||
"http://0.0.0.0:%d/v1/images/1") % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
self.assertEqual(0, exitcode)
|
||||
@ -346,7 +346,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
|
||||
self.assertEqual("HTTP/1.1 200 OK", status_line)
|
||||
|
||||
cmd = "curl -g http://0.0.0.0:%d/v1.0/images/detail" % api_port
|
||||
cmd = "curl http://0.0.0.0:%d/v1/images/detail" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
@ -391,7 +391,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
|
||||
# 0. GET /images
|
||||
# Verify no public images
|
||||
cmd = "curl -g http://0.0.0.0:%d/v1.0/images" % api_port
|
||||
cmd = "curl http://0.0.0.0:%d/v1/images" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
@ -405,7 +405,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
"-H 'Expect: ' " # Necessary otherwise sends 100 Continue
|
||||
"-H 'X-Image-Meta-Name: Image1' "
|
||||
"-H 'X-Image-Meta-Is-Public: True' "
|
||||
"http://0.0.0.0:%d/v1.0/images") % api_port
|
||||
"http://0.0.0.0:%d/v1/images") % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
self.assertEqual(0, exitcode)
|
||||
@ -417,7 +417,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
|
||||
# 2. GET /images
|
||||
# Verify 1 public image
|
||||
cmd = "curl -g http://0.0.0.0:%d/v1.0/images" % api_port
|
||||
cmd = "curl http://0.0.0.0:%d/v1/images" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
@ -433,7 +433,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
|
||||
# 3. HEAD /images
|
||||
# Verify status is in queued
|
||||
cmd = "curl -i -X HEAD http://0.0.0.0:%d/v1.0/images/1" % api_port
|
||||
cmd = "curl -i -X HEAD http://0.0.0.0:%d/v1/images/1" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
@ -453,7 +453,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
"-H 'Expect: ' " # Necessary otherwise sends 100 Continue
|
||||
"-H 'Content-Type: application/octet-stream' "
|
||||
"--data-binary \"%s\" "
|
||||
"http://0.0.0.0:%d/v1.0/images/1") % (image_data, api_port)
|
||||
"http://0.0.0.0:%d/v1/images/1") % (image_data, api_port)
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
self.assertEqual(0, exitcode)
|
||||
@ -465,7 +465,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
|
||||
# 5. HEAD /images
|
||||
# Verify status is in active
|
||||
cmd = "curl -i -X HEAD http://0.0.0.0:%d/v1.0/images/1" % api_port
|
||||
cmd = "curl -i -X HEAD http://0.0.0.0:%d/v1/images/1" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
@ -480,7 +480,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
|
||||
# 6. GET /images
|
||||
# Verify 1 public image still...
|
||||
cmd = "curl -g http://0.0.0.0:%d/v1.0/images" % api_port
|
||||
cmd = "curl http://0.0.0.0:%d/v1/images" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
@ -494,6 +494,139 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
"size": 5120}
|
||||
self.assertEqual(expected, image)
|
||||
|
||||
def test_version_variations(self):
|
||||
"""
|
||||
We test that various calls to the images and root endpoints are
|
||||
handled properly, and that usage of the Accept: header does
|
||||
content negotiation properly.
|
||||
|
||||
0. GET / with no Accept: header
|
||||
Verify version choices returned.
|
||||
1. GET /images with no Accept: header
|
||||
Verify version choices returned.
|
||||
2. GET /v1/images with no Accept: header
|
||||
Verify empty image list returned.
|
||||
3. GET / with an Accept: unknown header
|
||||
Verify version choices returned. Verify message in API log about
|
||||
unknown accept header.
|
||||
4. GET / with an Accept: application/vnd.openstack.images-v1
|
||||
Verify empty image list returned
|
||||
5. GET /images with a Accept: application/vnd.openstack.compute-v1
|
||||
header. Verify version choices returned. Verify message in API log
|
||||
about unknown accept header.
|
||||
6. GET /v1.0/images with no Accept: header
|
||||
Verify empty image list returned
|
||||
7. GET /v1.a/images with no Accept: header
|
||||
Verify empty image list returned
|
||||
8. GET /va.1/images with no Accept: header
|
||||
Verify version choices returned.
|
||||
"""
|
||||
|
||||
self.cleanup()
|
||||
self.start_servers()
|
||||
|
||||
api_port = self.api_port
|
||||
registry_port = self.registry_port
|
||||
|
||||
versions = {'versions': [{
|
||||
"id": "v1.0",
|
||||
"status": "CURRENT",
|
||||
"links": [{
|
||||
"rel": "self",
|
||||
"href": "http://0.0.0.0:%d/v1/" % api_port}]}]}
|
||||
versions_json = json.dumps(versions)
|
||||
images = {'images': []}
|
||||
images_json = json.dumps(images)
|
||||
|
||||
# 0. GET / with no Accept: header
|
||||
# Verify version choices returned.
|
||||
cmd = "curl http://0.0.0.0:%d/" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
self.assertEqual(0, exitcode)
|
||||
self.assertEqual(versions_json, out.strip())
|
||||
|
||||
# 1. GET /images with no Accept: header
|
||||
# Verify version choices returned.
|
||||
cmd = "curl http://0.0.0.0:%d/images" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
self.assertEqual(0, exitcode)
|
||||
self.assertEqual(versions_json, out.strip())
|
||||
|
||||
# 2. GET /v1/images with no Accept: header
|
||||
# Verify empty images list returned.
|
||||
cmd = "curl http://0.0.0.0:%d/v1/images" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
self.assertEqual(0, exitcode)
|
||||
self.assertEqual(images_json, out.strip())
|
||||
|
||||
# 3. GET / with Accept: unknown header
|
||||
# Verify version choices returned. Verify message in API log about
|
||||
# unknown accept header.
|
||||
cmd = "curl -H 'Accept: unknown' http://0.0.0.0:%d/" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
self.assertEqual(0, exitcode)
|
||||
self.assertEqual(versions_json, out.strip())
|
||||
self.assertTrue('Unknown accept header'
|
||||
in open(self.api_server.log_file).read())
|
||||
|
||||
# 5. GET / with an Accept: application/vnd.openstack.images-v1
|
||||
# Verify empty image list returned
|
||||
cmd = ("curl -H 'Accept: application/vnd.openstack.images-v1' "
|
||||
"http://0.0.0.0:%d/images") % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
self.assertEqual(0, exitcode)
|
||||
self.assertEqual(images_json, out.strip())
|
||||
|
||||
# 5. GET /images with a Accept: application/vnd.openstack.compute-v1
|
||||
# header. Verify version choices returned. Verify message in API log
|
||||
# about unknown accept header.
|
||||
cmd = ("curl -H 'Accept: application/vnd.openstack.compute-v1' "
|
||||
"http://0.0.0.0:%d/images") % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
self.assertEqual(0, exitcode)
|
||||
self.assertEqual(versions_json, out.strip())
|
||||
self.assertTrue('Unknown accept header'
|
||||
in open(self.api_server.log_file).read())
|
||||
|
||||
# 6. GET /v1.0/images with no Accept: header
|
||||
# Verify empty image list returned
|
||||
cmd = "curl http://0.0.0.0:%d/v1.0/images" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
self.assertEqual(0, exitcode)
|
||||
self.assertEqual(images_json, out.strip())
|
||||
|
||||
# 7. GET /v1.a/images with no Accept: header
|
||||
# Verify empty image list returned
|
||||
cmd = "curl http://0.0.0.0:%d/v1.a/images" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
self.assertEqual(0, exitcode)
|
||||
self.assertEqual(images_json, out.strip())
|
||||
|
||||
# 8. GET /va.1/images with no Accept: header
|
||||
# Verify version choices returned
|
||||
cmd = "curl http://0.0.0.0:%d/va.1/images" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
self.assertEqual(0, exitcode)
|
||||
self.assertEqual(versions_json, out.strip())
|
||||
|
||||
def test_size_greater_2G_mysql(self):
|
||||
"""
|
||||
A test against the actual datastore backend for the registry
|
||||
@ -519,7 +652,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
"-H 'X-Image-Meta-Size: %d' "
|
||||
"-H 'X-Image-Meta-Name: Image1' "
|
||||
"-H 'X-Image-Meta-Is-Public: True' "
|
||||
"http://0.0.0.0:%d/v1.0/images") % (FIVE_GB, api_port)
|
||||
"http://0.0.0.0:%d/v1/images") % (FIVE_GB, api_port)
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
self.assertEqual(0, exitcode)
|
||||
@ -539,8 +672,8 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
|
||||
self.assertTrue(new_image_uri is not None,
|
||||
"Could not find a new image URI!")
|
||||
self.assertTrue("v1.0/images" in new_image_uri,
|
||||
"v1.0/images not in %s" % new_image_uri)
|
||||
self.assertTrue("v1/images" in new_image_uri,
|
||||
"v1/images not in %s" % new_image_uri)
|
||||
|
||||
# 2. HEAD /images
|
||||
# Verify image size is what was passed in, and not truncated
|
||||
@ -582,7 +715,7 @@ class TestCurlApi(functional.FunctionalTest):
|
||||
test_data_file.write("XXX")
|
||||
test_data_file.flush()
|
||||
cmd = ("curl -i -X POST --upload-file %s "
|
||||
"http://0.0.0.0:%d/v1.0/images") % (test_data_file.name,
|
||||
"http://0.0.0.0:%d/v1/images") % (test_data_file.name,
|
||||
api_port)
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
@ -46,7 +46,7 @@ class TestMiscellaneous(functional.FunctionalTest):
|
||||
api_port = self.api_port
|
||||
registry_port = self.registry_port
|
||||
|
||||
cmd = "curl -g http://0.0.0.0:%d/v1.0/images" % api_port
|
||||
cmd = "curl -g http://0.0.0.0:%d/v1/images" % api_port
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
@ -56,7 +56,7 @@ class TestMiscellaneous(functional.FunctionalTest):
|
||||
cmd = "curl -X POST -H 'Content-Type: application/octet-stream' "\
|
||||
"-H 'X-Image-Meta-Name: ImageName' "\
|
||||
"-H 'X-Image-Meta-Disk-Format: Invalid' "\
|
||||
"http://0.0.0.0:%d/v1.0/images" % api_port
|
||||
"http://0.0.0.0:%d/v1/images" % api_port
|
||||
ignored, out, err = execute(cmd)
|
||||
|
||||
self.assertTrue('Invalid disk format' in out,
|
||||
|
@ -29,7 +29,7 @@ import webob
|
||||
|
||||
from glance.common import exception
|
||||
from glance.registry import server as rserver
|
||||
from glance.api import v1_0 as server
|
||||
from glance.api import v1 as server
|
||||
import glance.store
|
||||
import glance.store.filesystem
|
||||
import glance.store.http
|
||||
|
@ -24,7 +24,7 @@ import unittest
|
||||
import stubout
|
||||
import webob
|
||||
|
||||
from glance.api import v1_0 as server
|
||||
from glance.api import v1 as server
|
||||
from glance.registry import server as rserver
|
||||
from tests import stubs
|
||||
|
||||
|
@ -46,5 +46,5 @@ class VersionsTest(unittest.TestCase):
|
||||
"links": [
|
||||
{
|
||||
"rel": "self",
|
||||
"href": "http://0.0.0.0:9292/v1.0"}]}]
|
||||
"href": "http://0.0.0.0:9292/v1/"}]}]
|
||||
self.assertEqual(results, expected)
|
||||
|
@ -4,7 +4,6 @@ pep8==0.5.0
|
||||
pylint==0.19
|
||||
anyjson
|
||||
eventlet>=0.9.12
|
||||
Paste
|
||||
PasteDeploy
|
||||
routes
|
||||
webob
|
||||
|
Loading…
Reference in New Issue
Block a user