api: Add new, simpler api_version decorator
Get rid of the whole API version switching madness and make our schema generation _significantly_ simpler. This looks a lot larger than it actually is. In most cases, this is simply 's/wsgi.Controller.api_version/wsgi.api_version/'. Change-Id: I180bfad84c38653709c216282099d9b3fb64c5a7 Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
@@ -240,9 +240,9 @@ Adding a new API method
|
||||
|
||||
In the controller class::
|
||||
|
||||
@wsgi.Controller.api_version("2.4")
|
||||
@wsgi.api_version("2.4")
|
||||
def my_api_method(self, req, id):
|
||||
....
|
||||
...
|
||||
|
||||
This method would only be available if the caller had specified an
|
||||
``OpenStack-API-Version`` of >= ``2.4``. If they had specified a
|
||||
@@ -254,36 +254,14 @@ Removing an API method
|
||||
|
||||
In the controller class::
|
||||
|
||||
@wsgi.Controller.api_version("2.1", "2.4")
|
||||
@wsgi.api_version("2.1", "2.4")
|
||||
def my_api_method(self, req, id):
|
||||
....
|
||||
...
|
||||
|
||||
This method would only be available if the caller had specified an
|
||||
``OpenStack-API-Version`` of <= ``2.4``. If ``2.5`` or later
|
||||
is specified the server will respond with ``HTTP/404``.
|
||||
|
||||
Changing a method's behavior
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In the controller class::
|
||||
|
||||
@wsgi.Controller.api_version("2.1", "2.3")
|
||||
def my_api_method(self, req, id):
|
||||
.... method_1 ...
|
||||
|
||||
@wsgi.Controller.api_version("2.4") # noqa
|
||||
def my_api_method(self, req, id):
|
||||
.... method_2 ...
|
||||
|
||||
If a caller specified ``2.1``, ``2.2`` or ``2.3`` (or received the
|
||||
default of ``2.1``) they would see the result from ``method_1``,
|
||||
``2.4`` or later ``method_2``.
|
||||
|
||||
It is vital that the two methods have the same name, so the second of
|
||||
them will need ``# noqa`` to avoid failing flake8's ``F811`` rule. The
|
||||
two methods may be different in any kind of semantics (schema
|
||||
validation, return values, response codes, etc)
|
||||
|
||||
A change in schema only
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -291,26 +269,23 @@ If there is no change to the method, only to the schema that is used for
|
||||
validation, you can add a version range to the ``validation.schema``
|
||||
decorator::
|
||||
|
||||
@wsgi.Controller.api_version("2.1")
|
||||
@wsgi.api_version("2.1")
|
||||
@validation.schema(dummy_schema.dummy, "2.3", "2.8")
|
||||
@validation.schema(dummy_schema.dummy2, "2.9")
|
||||
def update(self, req, id, body):
|
||||
....
|
||||
...
|
||||
|
||||
This method will be available from version ``2.1``, validated according to
|
||||
``dummy_schema.dummy`` from ``2.3`` to ``2.8``, and validated according to
|
||||
``dummy_schema.dummy2`` from ``2.9`` onward.
|
||||
|
||||
Other API method changes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When not using decorators
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When you don't want to use the ``@api_version`` decorator on a method
|
||||
or you want to change behavior within a method (say it leads to
|
||||
simpler or simply a lot less code) you can directly test for the
|
||||
requested version with a method as long as you have access to the api
|
||||
request object (commonly called ``req``). Every API method has an
|
||||
api_version_request object attached to the req object and that can be
|
||||
When you want to change more than the API request or response schema, you can
|
||||
directly test for the requested version with a method as long as you have
|
||||
access to the api request object (commonly called ``req``). Every API method
|
||||
has an api_version_request object attached to the req object and that can be
|
||||
used to modify behavior based on its value::
|
||||
|
||||
def index(self, req):
|
||||
|
@@ -287,7 +287,7 @@ class AggregateController(wsgi.Controller):
|
||||
(show_uuid or key != 'uuid')):
|
||||
yield key, getattr(aggregate, key)
|
||||
|
||||
@wsgi.Controller.api_version('2.81')
|
||||
@wsgi.api_version('2.81')
|
||||
@wsgi.response(202)
|
||||
@wsgi.expected_errors((400, 404))
|
||||
@validation.schema(aggregate_images.aggregate_images)
|
||||
|
@@ -61,7 +61,7 @@ class BareMetalNodeController(wsgi.Controller):
|
||||
)
|
||||
return self._ironic_connection
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors((404, 501))
|
||||
@validation.query_schema(schema.index_query)
|
||||
@validation.response_body_schema(schema.index_response)
|
||||
@@ -86,7 +86,7 @@ class BareMetalNodeController(wsgi.Controller):
|
||||
|
||||
return {'nodes': nodes}
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors((404, 501))
|
||||
@validation.query_schema(schema.show_query)
|
||||
@validation.response_body_schema(schema.show_response)
|
||||
@@ -117,20 +117,20 @@ class BareMetalNodeController(wsgi.Controller):
|
||||
|
||||
return {'node': node}
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors(400)
|
||||
@validation.schema(schema.create)
|
||||
@validation.response_body_schema(schema.create_response)
|
||||
def create(self, req, body):
|
||||
_no_ironic_proxy("node-create")
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors(400)
|
||||
@validation.response_body_schema(schema.delete_response)
|
||||
def delete(self, req, id):
|
||||
_no_ironic_proxy("node-delete")
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.action('add_interface')
|
||||
@wsgi.expected_errors(400)
|
||||
@validation.schema(schema.add_interface)
|
||||
@@ -138,7 +138,7 @@ class BareMetalNodeController(wsgi.Controller):
|
||||
def _add_interface(self, req, id, body):
|
||||
_no_ironic_proxy("port-create")
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.action('remove_interface')
|
||||
@wsgi.expected_errors(400)
|
||||
@validation.schema(schema.remove_interface)
|
||||
|
@@ -108,7 +108,7 @@ class FlavorsController(wsgi.Controller):
|
||||
return self._view_builder.show(req, flavor, include_description,
|
||||
include_extra_specs=include_extra_specs)
|
||||
|
||||
@wsgi.Controller.api_version('2.55')
|
||||
@wsgi.api_version('2.55')
|
||||
@wsgi.expected_errors((400, 404))
|
||||
@validation.schema(schema.update, '2.55')
|
||||
@validation.response_body_schema(schema.update_response, '2.55', '2.60')
|
||||
|
@@ -41,7 +41,7 @@ class FloatingIPPoolsController(wsgi.Controller):
|
||||
super(FloatingIPPoolsController, self).__init__()
|
||||
self.network_api = neutron.API()
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors(())
|
||||
@validation.query_schema(schema.index_query)
|
||||
@validation.response_body_schema(schema.index_response)
|
||||
|
@@ -82,7 +82,7 @@ class FloatingIPController(wsgi.Controller):
|
||||
self.compute_api = compute.API()
|
||||
self.network_api = neutron.API()
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors((400, 404))
|
||||
@validation.query_schema(schema.show_query)
|
||||
def show(self, req, id):
|
||||
@@ -101,7 +101,7 @@ class FloatingIPController(wsgi.Controller):
|
||||
|
||||
return _translate_floating_ip_view(floating_ip)
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors(())
|
||||
@validation.query_schema(schema.index_query)
|
||||
def index(self, req):
|
||||
@@ -115,7 +115,7 @@ class FloatingIPController(wsgi.Controller):
|
||||
return {'floating_ips': [_translate_floating_ip_view(ip)['floating_ip']
|
||||
for ip in floating_ips]}
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors((400, 403, 404))
|
||||
@validation.schema(schema.create)
|
||||
def create(self, req, body=None):
|
||||
@@ -148,7 +148,7 @@ class FloatingIPController(wsgi.Controller):
|
||||
|
||||
return _translate_floating_ip_view(ip)
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.response(202)
|
||||
@wsgi.expected_errors((400, 403, 404, 409))
|
||||
def delete(self, req, id):
|
||||
@@ -186,7 +186,7 @@ class FloatingIPActionController(wsgi.Controller):
|
||||
self.compute_api = compute.API()
|
||||
self.network_api = neutron.API()
|
||||
|
||||
@wsgi.Controller.api_version("2.1", "2.43")
|
||||
@wsgi.api_version("2.1", "2.43")
|
||||
@wsgi.expected_errors((400, 403, 404))
|
||||
@wsgi.action('addFloatingIp')
|
||||
@validation.schema(schema.add_floating_ip)
|
||||
@@ -267,7 +267,7 @@ class FloatingIPActionController(wsgi.Controller):
|
||||
|
||||
return webob.Response(status_int=202)
|
||||
|
||||
@wsgi.Controller.api_version("2.1", "2.43")
|
||||
@wsgi.api_version("2.1", "2.43")
|
||||
@wsgi.expected_errors((400, 403, 404, 409))
|
||||
@wsgi.action('removeFloatingIp')
|
||||
@validation.schema(schema.remove_floating_ip)
|
||||
|
@@ -38,7 +38,7 @@ class HostController(wsgi.Controller):
|
||||
super(HostController, self).__init__()
|
||||
self.api = compute.HostAPI()
|
||||
|
||||
@wsgi.Controller.api_version("2.1", "2.42")
|
||||
@wsgi.api_version("2.1", "2.42")
|
||||
@validation.query_schema(hosts.index_query)
|
||||
@wsgi.expected_errors(())
|
||||
def index(self, req):
|
||||
@@ -88,7 +88,7 @@ class HostController(wsgi.Controller):
|
||||
'zone': service['availability_zone']})
|
||||
return {'hosts': hosts}
|
||||
|
||||
@wsgi.Controller.api_version("2.1", "2.42")
|
||||
@wsgi.api_version("2.1", "2.42")
|
||||
@wsgi.expected_errors((400, 404, 501))
|
||||
@validation.schema(hosts.update)
|
||||
def update(self, req, id, body):
|
||||
@@ -180,7 +180,7 @@ class HostController(wsgi.Controller):
|
||||
raise webob.exc.HTTPBadRequest(explanation=e.format_message())
|
||||
return {"host": host_name, "power_action": result}
|
||||
|
||||
@wsgi.Controller.api_version("2.1", "2.42")
|
||||
@wsgi.api_version("2.1", "2.42")
|
||||
@wsgi.expected_errors((400, 404, 501))
|
||||
@validation.query_schema(hosts.startup_query)
|
||||
def startup(self, req, id):
|
||||
@@ -189,7 +189,7 @@ class HostController(wsgi.Controller):
|
||||
target={})
|
||||
return self._host_power_action(req, host_name=id, action="startup")
|
||||
|
||||
@wsgi.Controller.api_version("2.1", "2.42")
|
||||
@wsgi.api_version("2.1", "2.42")
|
||||
@wsgi.expected_errors((400, 404, 501))
|
||||
@validation.query_schema(hosts.shutdown_query)
|
||||
def shutdown(self, req, id):
|
||||
@@ -198,7 +198,7 @@ class HostController(wsgi.Controller):
|
||||
target={})
|
||||
return self._host_power_action(req, host_name=id, action="shutdown")
|
||||
|
||||
@wsgi.Controller.api_version("2.1", "2.42")
|
||||
@wsgi.api_version("2.1", "2.42")
|
||||
@wsgi.expected_errors((400, 404, 501))
|
||||
@validation.query_schema(hosts.reboot_query)
|
||||
def reboot(self, req, id):
|
||||
@@ -256,7 +256,7 @@ class HostController(wsgi.Controller):
|
||||
instance['ephemeral_gb'])
|
||||
return project_map
|
||||
|
||||
@wsgi.Controller.api_version("2.1", "2.42")
|
||||
@wsgi.api_version("2.1", "2.42")
|
||||
@wsgi.expected_errors(404)
|
||||
@validation.query_schema(hosts.show_query)
|
||||
def show(self, req, id):
|
||||
|
@@ -359,7 +359,7 @@ class HypervisorsController(wsgi.Controller):
|
||||
),
|
||||
}
|
||||
|
||||
@wsgi.Controller.api_version('2.1', '2.87')
|
||||
@wsgi.api_version('2.1', '2.87')
|
||||
@wsgi.expected_errors((400, 404, 501))
|
||||
@validation.query_schema(schema.uptime_query)
|
||||
def uptime(self, req, id):
|
||||
@@ -412,7 +412,7 @@ class HypervisorsController(wsgi.Controller):
|
||||
|
||||
return {'hypervisor': hypervisor}
|
||||
|
||||
@wsgi.Controller.api_version('2.1', '2.52')
|
||||
@wsgi.api_version('2.1', '2.52')
|
||||
@wsgi.expected_errors(404)
|
||||
@validation.query_schema(schema.search_query)
|
||||
def search(self, req, id):
|
||||
@@ -451,7 +451,7 @@ class HypervisorsController(wsgi.Controller):
|
||||
|
||||
return {'hypervisors': hypervisors}
|
||||
|
||||
@wsgi.Controller.api_version('2.1', '2.52')
|
||||
@wsgi.api_version('2.1', '2.52')
|
||||
@wsgi.expected_errors(404)
|
||||
@validation.query_schema(schema.servers_query)
|
||||
def servers(self, req, id):
|
||||
@@ -497,7 +497,7 @@ class HypervisorsController(wsgi.Controller):
|
||||
|
||||
return {'hypervisors': hypervisors}
|
||||
|
||||
@wsgi.Controller.api_version('2.1', '2.87')
|
||||
@wsgi.api_version('2.1', '2.87')
|
||||
@wsgi.expected_errors(())
|
||||
@validation.query_schema(schema.statistics_query)
|
||||
def statistics(self, req):
|
||||
|
@@ -43,7 +43,7 @@ class ImageMetadataController(wsgi.Controller):
|
||||
msg = _("Image not found.")
|
||||
raise exc.HTTPNotFound(explanation=msg)
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
|
||||
@wsgi.expected_errors((403, 404))
|
||||
@validation.query_schema(image_metadata.index_query)
|
||||
def index(self, req, image_id):
|
||||
@@ -52,7 +52,7 @@ class ImageMetadataController(wsgi.Controller):
|
||||
metadata = self._get_image(context, image_id)['properties']
|
||||
return dict(metadata=metadata)
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
|
||||
@wsgi.expected_errors((403, 404))
|
||||
@validation.query_schema(image_metadata.show_query)
|
||||
def show(self, req, image_id, id):
|
||||
@@ -63,7 +63,7 @@ class ImageMetadataController(wsgi.Controller):
|
||||
else:
|
||||
raise exc.HTTPNotFound()
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
|
||||
@wsgi.expected_errors((400, 403, 404))
|
||||
@validation.schema(image_metadata.create)
|
||||
def create(self, req, image_id, body):
|
||||
@@ -80,7 +80,7 @@ class ImageMetadataController(wsgi.Controller):
|
||||
raise exc.HTTPForbidden(explanation=e.format_message())
|
||||
return dict(metadata=image['properties'])
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
|
||||
@wsgi.expected_errors((400, 403, 404))
|
||||
@validation.schema(image_metadata.update)
|
||||
def update(self, req, image_id, id, body):
|
||||
@@ -103,7 +103,7 @@ class ImageMetadataController(wsgi.Controller):
|
||||
raise exc.HTTPForbidden(explanation=e.format_message())
|
||||
return dict(meta=meta)
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
|
||||
@wsgi.expected_errors((400, 403, 404))
|
||||
@validation.schema(image_metadata.update_all)
|
||||
def update_all(self, req, image_id, body):
|
||||
@@ -119,7 +119,7 @@ class ImageMetadataController(wsgi.Controller):
|
||||
raise exc.HTTPForbidden(explanation=e.format_message())
|
||||
return dict(metadata=metadata)
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
|
||||
@wsgi.expected_errors((403, 404))
|
||||
@wsgi.response(204)
|
||||
def delete(self, req, image_id, id):
|
||||
|
@@ -74,7 +74,7 @@ class ImagesController(wsgi.Controller):
|
||||
|
||||
return filters
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors(404)
|
||||
@validation.query_schema(schema.show_query)
|
||||
def show(self, req, id):
|
||||
@@ -93,7 +93,7 @@ class ImagesController(wsgi.Controller):
|
||||
|
||||
return self._view_builder.show(req, image)
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors((403, 404))
|
||||
@wsgi.response(204)
|
||||
def delete(self, req, id):
|
||||
@@ -114,7 +114,7 @@ class ImagesController(wsgi.Controller):
|
||||
explanation = _("You are not allowed to delete the image.")
|
||||
raise webob.exc.HTTPForbidden(explanation=explanation)
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors(400)
|
||||
@validation.query_schema(schema.index_query)
|
||||
def index(self, req):
|
||||
@@ -134,7 +134,7 @@ class ImagesController(wsgi.Controller):
|
||||
raise webob.exc.HTTPBadRequest(explanation=e.format_message())
|
||||
return self._view_builder.index(req, images)
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors(400)
|
||||
@validation.query_schema(schema.detail_query)
|
||||
def detail(self, req):
|
||||
|
@@ -33,7 +33,7 @@ class MultinicController(wsgi.Controller):
|
||||
super(MultinicController, self).__init__()
|
||||
self.compute_api = compute.API()
|
||||
|
||||
@wsgi.Controller.api_version("2.1", "2.43")
|
||||
@wsgi.api_version("2.1", "2.43")
|
||||
@wsgi.response(202)
|
||||
@wsgi.action('addFixedIp')
|
||||
@wsgi.expected_errors((400, 404))
|
||||
@@ -52,7 +52,7 @@ class MultinicController(wsgi.Controller):
|
||||
except exception.NoMoreFixedIps as e:
|
||||
raise exc.HTTPBadRequest(explanation=e.format_message())
|
||||
|
||||
@wsgi.Controller.api_version("2.1", "2.43")
|
||||
@wsgi.api_version("2.1", "2.43")
|
||||
@wsgi.response(202)
|
||||
@wsgi.action('removeFixedIp')
|
||||
@wsgi.expected_errors((400, 404))
|
||||
|
@@ -77,7 +77,7 @@ class NetworkController(wsgi.Controller):
|
||||
# TODO(stephenfin): 'network_api' is only being passed for use by tests
|
||||
self.network_api = network_api or neutron.API()
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors(())
|
||||
@validation.query_schema(schema.index_query)
|
||||
def index(self, req):
|
||||
@@ -88,7 +88,7 @@ class NetworkController(wsgi.Controller):
|
||||
result = [network_dict(context, net_ref) for net_ref in networks]
|
||||
return {'networks': result}
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors(404)
|
||||
@validation.query_schema(schema.show_query)
|
||||
def show(self, req, id):
|
||||
|
@@ -110,7 +110,7 @@ class QuotaSetsController(wsgi.Controller):
|
||||
else:
|
||||
return []
|
||||
|
||||
@wsgi.Controller.api_version('2.1')
|
||||
@wsgi.api_version('2.1')
|
||||
@wsgi.expected_errors(400)
|
||||
@validation.query_schema(quota_sets.show_query, '2.0', '2.74')
|
||||
@validation.query_schema(quota_sets.show_query_v275, '2.75')
|
||||
@@ -148,7 +148,7 @@ class QuotaSetsController(wsgi.Controller):
|
||||
self._get_quotas(context, id, user_id=user_id, usages=True),
|
||||
filtered_quotas=filtered_quotas)
|
||||
|
||||
@wsgi.Controller.api_version('2.1')
|
||||
@wsgi.api_version('2.1')
|
||||
@wsgi.expected_errors(400)
|
||||
@validation.schema(quota_sets.update, '2.0', '2.35')
|
||||
@validation.schema(quota_sets.update_v236, '2.36', '2.56')
|
||||
@@ -221,7 +221,7 @@ class QuotaSetsController(wsgi.Controller):
|
||||
self._get_quotas(context, id, user_id=user_id),
|
||||
filtered_quotas=filtered_quotas)
|
||||
|
||||
@wsgi.Controller.api_version('2.0')
|
||||
@wsgi.api_version('2.0')
|
||||
@wsgi.expected_errors(400)
|
||||
@validation.query_schema(quota_sets.defaults_query)
|
||||
def defaults(self, req, id):
|
||||
|
@@ -37,7 +37,7 @@ class RemoteConsolesController(wsgi.Controller):
|
||||
'serial': self.compute_api.get_serial_console,
|
||||
'mks': self.compute_api.get_mks_console}
|
||||
|
||||
@wsgi.Controller.api_version("2.1", "2.5")
|
||||
@wsgi.api_version("2.1", "2.5")
|
||||
@wsgi.expected_errors((400, 404, 409, 501))
|
||||
@wsgi.action('os-getVNCConsole')
|
||||
@validation.schema(schema.get_vnc_console)
|
||||
@@ -69,7 +69,7 @@ class RemoteConsolesController(wsgi.Controller):
|
||||
|
||||
return {'console': {'type': console_type, 'url': output['url']}}
|
||||
|
||||
@wsgi.Controller.api_version("2.1", "2.5")
|
||||
@wsgi.api_version("2.1", "2.5")
|
||||
@wsgi.expected_errors((400, 404, 409, 501))
|
||||
@wsgi.action('os-getSPICEConsole')
|
||||
@validation.schema(schema.get_spice_console)
|
||||
@@ -98,7 +98,7 @@ class RemoteConsolesController(wsgi.Controller):
|
||||
|
||||
return {'console': {'type': console_type, 'url': output['url']}}
|
||||
|
||||
@wsgi.Controller.api_version("2.1", "2.5")
|
||||
@wsgi.api_version("2.1", "2.5")
|
||||
@wsgi.expected_errors((400, 404, 409, 501))
|
||||
@wsgi.action('os-getRDPConsole')
|
||||
@wsgi.removed('29.0.0', _rdp_console_removal_reason)
|
||||
@@ -109,7 +109,7 @@ class RemoteConsolesController(wsgi.Controller):
|
||||
"""
|
||||
raise webob.exc.HTTPBadRequest()
|
||||
|
||||
@wsgi.Controller.api_version("2.1", "2.5")
|
||||
@wsgi.api_version("2.1", "2.5")
|
||||
@wsgi.expected_errors((400, 404, 409, 501))
|
||||
@wsgi.action('os-getSerialConsole')
|
||||
@validation.schema(schema.get_serial_console)
|
||||
@@ -140,7 +140,7 @@ class RemoteConsolesController(wsgi.Controller):
|
||||
|
||||
return {'console': {'type': console_type, 'url': output['url']}}
|
||||
|
||||
@wsgi.Controller.api_version("2.6")
|
||||
@wsgi.api_version("2.6")
|
||||
@wsgi.expected_errors((400, 404, 409, 501))
|
||||
@validation.schema(schema.create_v26, "2.6", "2.7")
|
||||
@validation.schema(schema.create_v28, "2.8", "2.98")
|
||||
|
@@ -134,7 +134,7 @@ class SecurityGroupControllerBase(object):
|
||||
class SecurityGroupController(SecurityGroupControllerBase, wsgi.Controller):
|
||||
"""The Security group API controller for the OpenStack API."""
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors((400, 404))
|
||||
@validation.query_schema(schema.show_query)
|
||||
def show(self, req, id):
|
||||
@@ -154,7 +154,7 @@ class SecurityGroupController(SecurityGroupControllerBase, wsgi.Controller):
|
||||
return {'security_group': self._format_security_group(context,
|
||||
security_group)}
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors((400, 404))
|
||||
@wsgi.response(202)
|
||||
def delete(self, req, id):
|
||||
@@ -172,7 +172,7 @@ class SecurityGroupController(SecurityGroupControllerBase, wsgi.Controller):
|
||||
except exception.Invalid as exp:
|
||||
raise exc.HTTPBadRequest(explanation=exp.format_message())
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@validation.query_schema(schema.index_query)
|
||||
@wsgi.expected_errors(404)
|
||||
def index(self, req):
|
||||
@@ -196,7 +196,7 @@ class SecurityGroupController(SecurityGroupControllerBase, wsgi.Controller):
|
||||
list(sorted(result,
|
||||
key=lambda k: (k['tenant_id'], k['name'])))}
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors((400, 403))
|
||||
@validation.schema(schema.create)
|
||||
def create(self, req, body):
|
||||
@@ -219,7 +219,7 @@ class SecurityGroupController(SecurityGroupControllerBase, wsgi.Controller):
|
||||
return {'security_group': self._format_security_group(context,
|
||||
group_ref)}
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors((400, 404))
|
||||
@validation.schema(schema.update)
|
||||
def update(self, req, id, body):
|
||||
@@ -254,7 +254,7 @@ class SecurityGroupController(SecurityGroupControllerBase, wsgi.Controller):
|
||||
class SecurityGroupRulesController(SecurityGroupControllerBase,
|
||||
wsgi.Controller):
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors((400, 403, 404))
|
||||
@validation.schema(schema.create_rules)
|
||||
def create(self, req, body):
|
||||
@@ -327,7 +327,7 @@ class SecurityGroupRulesController(SecurityGroupControllerBase,
|
||||
return security_group_api.new_cidr_ingress_rule(
|
||||
cidr, ip_protocol, from_port, to_port)
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors((400, 404, 409))
|
||||
@wsgi.response(202)
|
||||
def delete(self, req, id):
|
||||
|
@@ -175,7 +175,7 @@ class ServerGroupController(wsgi.Controller):
|
||||
for group in limited_list]
|
||||
return {'server_groups': result}
|
||||
|
||||
@wsgi.Controller.api_version("2.1")
|
||||
@wsgi.api_version("2.1")
|
||||
@wsgi.expected_errors((400, 403, 409))
|
||||
@validation.schema(schema.create, "2.0", "2.14")
|
||||
@validation.schema(schema.create_v215, "2.15", "2.63")
|
||||
|
@@ -65,7 +65,7 @@ class ServerMigrationsController(wsgi.Controller):
|
||||
super(ServerMigrationsController, self).__init__()
|
||||
self.compute_api = compute.API()
|
||||
|
||||
@wsgi.Controller.api_version("2.22")
|
||||
@wsgi.api_version("2.22")
|
||||
@wsgi.response(202)
|
||||
@wsgi.expected_errors((400, 403, 404, 409))
|
||||
@wsgi.action('force_complete')
|
||||
@@ -91,7 +91,7 @@ class ServerMigrationsController(wsgi.Controller):
|
||||
common.raise_http_conflict_for_instance_invalid_state(
|
||||
state_error, 'force_complete', server_id)
|
||||
|
||||
@wsgi.Controller.api_version("2.23")
|
||||
@wsgi.api_version("2.23")
|
||||
@wsgi.expected_errors(404)
|
||||
@validation.query_schema(schema.index_query)
|
||||
def index(self, req, server_id):
|
||||
@@ -114,7 +114,7 @@ class ServerMigrationsController(wsgi.Controller):
|
||||
output(migration, include_uuid, include_user_project)
|
||||
for migration in migrations]}
|
||||
|
||||
@wsgi.Controller.api_version("2.23")
|
||||
@wsgi.api_version("2.23")
|
||||
@wsgi.expected_errors(404)
|
||||
@validation.query_schema(schema.show_query)
|
||||
def show(self, req, server_id, id):
|
||||
@@ -153,7 +153,7 @@ class ServerMigrationsController(wsgi.Controller):
|
||||
return {'migration': output(migration, include_uuid,
|
||||
include_user_project)}
|
||||
|
||||
@wsgi.Controller.api_version("2.24")
|
||||
@wsgi.api_version("2.24")
|
||||
@wsgi.response(202)
|
||||
@wsgi.expected_errors((400, 404, 409))
|
||||
def delete(self, req, server_id, id):
|
||||
|
@@ -70,7 +70,7 @@ class ServerSharesController(wsgi.Controller):
|
||||
)
|
||||
return instance
|
||||
|
||||
@wsgi.Controller.api_version("2.97")
|
||||
@wsgi.api_version("2.97")
|
||||
@wsgi.response(200)
|
||||
@wsgi.expected_errors((400, 403, 404))
|
||||
@validation.query_schema(schema.index_query)
|
||||
@@ -91,7 +91,7 @@ class ServerSharesController(wsgi.Controller):
|
||||
|
||||
return self._view_builder._list_view(db_shares)
|
||||
|
||||
@wsgi.Controller.api_version("2.97")
|
||||
@wsgi.api_version("2.97")
|
||||
@wsgi.response(201)
|
||||
@wsgi.expected_errors((400, 403, 404, 409))
|
||||
@validation.schema(schema.create, '2.97')
|
||||
@@ -104,7 +104,8 @@ class ServerSharesController(wsgi.Controller):
|
||||
Prevent user from using the same tag twice on the same instance.
|
||||
"""
|
||||
try:
|
||||
objects.ShareMapping.get_by_instance_uuid_and_share_id(context,
|
||||
objects.ShareMapping.get_by_instance_uuid_and_share_id(
|
||||
context,
|
||||
share_mapping.instance_uuid, share_mapping.share_id
|
||||
)
|
||||
raise exception.ShareMappingAlreadyExists(
|
||||
@@ -196,7 +197,7 @@ class ServerSharesController(wsgi.Controller):
|
||||
|
||||
return view
|
||||
|
||||
@wsgi.Controller.api_version("2.97")
|
||||
@wsgi.api_version("2.97")
|
||||
@wsgi.response(200)
|
||||
@wsgi.expected_errors((400, 403, 404))
|
||||
@validation.query_schema(schema.show_query)
|
||||
@@ -227,7 +228,7 @@ class ServerSharesController(wsgi.Controller):
|
||||
|
||||
return view
|
||||
|
||||
@wsgi.Controller.api_version("2.97")
|
||||
@wsgi.api_version("2.97")
|
||||
@wsgi.response(200)
|
||||
@wsgi.expected_errors((400, 403, 404, 409))
|
||||
def delete(self, req, server_id, id):
|
||||
|
@@ -60,7 +60,7 @@ class ServerTagsController(wsgi.Controller):
|
||||
server_id)
|
||||
return instance
|
||||
|
||||
@wsgi.Controller.api_version("2.26")
|
||||
@wsgi.api_version("2.26")
|
||||
@wsgi.response(204)
|
||||
@wsgi.expected_errors(404)
|
||||
@validation.query_schema(schema.show_query)
|
||||
@@ -81,7 +81,7 @@ class ServerTagsController(wsgi.Controller):
|
||||
% {'server_id': server_id, 'tag': id})
|
||||
raise webob.exc.HTTPNotFound(explanation=msg)
|
||||
|
||||
@wsgi.Controller.api_version("2.26")
|
||||
@wsgi.api_version("2.26")
|
||||
@wsgi.expected_errors(404)
|
||||
@validation.query_schema(schema.index_query)
|
||||
def index(self, req, server_id):
|
||||
@@ -98,7 +98,7 @@ class ServerTagsController(wsgi.Controller):
|
||||
|
||||
return {'tags': _get_tags_names(tags)}
|
||||
|
||||
@wsgi.Controller.api_version("2.26")
|
||||
@wsgi.api_version("2.26")
|
||||
@wsgi.expected_errors((400, 404, 409))
|
||||
@validation.schema(schema.update)
|
||||
def update(self, req, server_id, id, body):
|
||||
@@ -151,7 +151,7 @@ class ServerTagsController(wsgi.Controller):
|
||||
req, server_id, id)
|
||||
return response
|
||||
|
||||
@wsgi.Controller.api_version("2.26")
|
||||
@wsgi.api_version("2.26")
|
||||
@wsgi.expected_errors((404, 409))
|
||||
@validation.schema(schema.update_all)
|
||||
def update_all(self, req, server_id, body):
|
||||
@@ -176,7 +176,7 @@ class ServerTagsController(wsgi.Controller):
|
||||
|
||||
return {'tags': _get_tags_names(tags)}
|
||||
|
||||
@wsgi.Controller.api_version("2.26")
|
||||
@wsgi.api_version("2.26")
|
||||
@wsgi.response(204)
|
||||
@wsgi.expected_errors((404, 409))
|
||||
def delete(self, req, server_id, id):
|
||||
@@ -201,7 +201,7 @@ class ServerTagsController(wsgi.Controller):
|
||||
notifications_base.send_instance_update_notification(
|
||||
context, instance, service="nova-api")
|
||||
|
||||
@wsgi.Controller.api_version("2.26")
|
||||
@wsgi.api_version("2.26")
|
||||
@wsgi.response(204)
|
||||
@wsgi.expected_errors((404, 409))
|
||||
def delete_all(self, req, server_id):
|
||||
|
@@ -25,7 +25,7 @@ class ServerTopologyController(wsgi.Controller):
|
||||
super(ServerTopologyController, self).__init__(*args, **kwargs)
|
||||
self.compute_api = compute.API()
|
||||
|
||||
@wsgi.Controller.api_version("2.78")
|
||||
@wsgi.api_version("2.78")
|
||||
@wsgi.expected_errors(404)
|
||||
@validation.query_schema(schema.query_params_v21)
|
||||
def index(self, req, server_id):
|
||||
|
@@ -1502,7 +1502,7 @@ class ServersController(wsgi.Controller):
|
||||
state_error, 'stop', id
|
||||
)
|
||||
|
||||
@wsgi.Controller.api_version("2.17")
|
||||
@wsgi.api_version("2.17")
|
||||
@wsgi.response(202)
|
||||
@wsgi.expected_errors((400, 404, 409))
|
||||
@wsgi.action('trigger_crash_dump')
|
||||
|
@@ -74,7 +74,7 @@ class TenantNetworkController(wsgi.Controller):
|
||||
project_id=project_id)
|
||||
return self.network_api.get_all(ctx)
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors(())
|
||||
@validation.query_schema(schema.index_query)
|
||||
def index(self, req):
|
||||
@@ -87,7 +87,7 @@ class TenantNetworkController(wsgi.Controller):
|
||||
networks.extend(self._default_networks)
|
||||
return {'networks': [network_dict(n) for n in networks]}
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors(404)
|
||||
@validation.query_schema(schema.show_query)
|
||||
def show(self, req, id):
|
||||
|
@@ -109,7 +109,7 @@ class VolumeController(wsgi.Controller):
|
||||
super(VolumeController, self).__init__()
|
||||
self.volume_api = cinder.API()
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors(404)
|
||||
@validation.query_schema(volumes_schema.show_query)
|
||||
def show(self, req, id):
|
||||
@@ -125,7 +125,7 @@ class VolumeController(wsgi.Controller):
|
||||
|
||||
return {'volume': _translate_volume_detail_view(context, vol)}
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.response(202)
|
||||
@wsgi.expected_errors((400, 404))
|
||||
def delete(self, req, id):
|
||||
@@ -141,7 +141,7 @@ class VolumeController(wsgi.Controller):
|
||||
except exception.VolumeNotFound as e:
|
||||
raise exc.HTTPNotFound(explanation=e.format_message())
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors(())
|
||||
@validation.query_schema(volumes_schema.index_query)
|
||||
def index(self, req):
|
||||
@@ -151,7 +151,7 @@ class VolumeController(wsgi.Controller):
|
||||
target={'project_id': context.project_id})
|
||||
return self._items(req, entity_maker=_translate_volume_summary_view)
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors(())
|
||||
@validation.query_schema(volumes_schema.detail_query)
|
||||
def detail(self, req):
|
||||
@@ -170,7 +170,7 @@ class VolumeController(wsgi.Controller):
|
||||
res = [entity_maker(context, vol) for vol in limited_list]
|
||||
return {'volumes': res}
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors((400, 403, 404))
|
||||
@validation.schema(volumes_schema.create)
|
||||
def create(self, req, body):
|
||||
@@ -607,7 +607,7 @@ class SnapshotController(wsgi.Controller):
|
||||
self.volume_api = cinder.API()
|
||||
super(SnapshotController, self).__init__()
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors(404)
|
||||
@validation.query_schema(volumes_schema.snapshot_show_query)
|
||||
def show(self, req, id):
|
||||
@@ -623,7 +623,7 @@ class SnapshotController(wsgi.Controller):
|
||||
|
||||
return {'snapshot': _translate_snapshot_detail_view(context, vol)}
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.response(202)
|
||||
@wsgi.expected_errors(404)
|
||||
def delete(self, req, id):
|
||||
@@ -637,7 +637,7 @@ class SnapshotController(wsgi.Controller):
|
||||
except exception.SnapshotNotFound as e:
|
||||
raise exc.HTTPNotFound(explanation=e.format_message())
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors(())
|
||||
@validation.query_schema(volumes_schema.index_query)
|
||||
def index(self, req):
|
||||
@@ -647,7 +647,7 @@ class SnapshotController(wsgi.Controller):
|
||||
target={'project_id': context.project_id})
|
||||
return self._items(req, entity_maker=_translate_snapshot_summary_view)
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors(())
|
||||
@validation.query_schema(volumes_schema.detail_query)
|
||||
def detail(self, req):
|
||||
@@ -666,7 +666,7 @@ class SnapshotController(wsgi.Controller):
|
||||
res = [entity_maker(context, snapshot) for snapshot in limited_list]
|
||||
return {'snapshots': res}
|
||||
|
||||
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
|
||||
@wsgi.expected_errors((400, 403))
|
||||
@validation.schema(volumes_schema.snapshot_create)
|
||||
def create(self, req, body):
|
||||
|
@@ -1,35 +0,0 @@
|
||||
# Copyright 2014 IBM Corp.
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
class VersionedMethod(object):
|
||||
|
||||
def __init__(self, name, start_version, end_version, func):
|
||||
"""Versioning information for a single method
|
||||
|
||||
@name: Name of the method
|
||||
@start_version: Minimum acceptable version
|
||||
@end_version: Maximum acceptable_version
|
||||
@func: Method to call
|
||||
|
||||
Minimum and maximums are inclusive
|
||||
"""
|
||||
self.name = name
|
||||
self.start_version = start_version
|
||||
self.end_version = end_version
|
||||
self.func = func
|
||||
|
||||
def __str__(self):
|
||||
return ("Version Method %s: min: %s, max: %s"
|
||||
% (self.name, self.start_version, self.end_version))
|
@@ -24,8 +24,7 @@ from oslo_utils import encodeutils
|
||||
from oslo_utils import strutils
|
||||
import webob
|
||||
|
||||
from nova.api.openstack import api_version_request as api_version
|
||||
from nova.api.openstack import versioned_method
|
||||
from nova.api.openstack import api_version_request
|
||||
from nova.api import wsgi
|
||||
from nova import exception
|
||||
from nova import i18n
|
||||
@@ -59,9 +58,6 @@ _METHODS_WITH_BODY = [
|
||||
# support is fully merged. It does not affect the V2 API.
|
||||
DEFAULT_API_VERSION = "2.1"
|
||||
|
||||
# name of attribute to keep version method information
|
||||
VER_METHOD_ATTR = 'versioned_methods'
|
||||
|
||||
# Names of headers used by clients to request a specific version
|
||||
# of the REST API
|
||||
API_VERSION_REQUEST_HEADER = 'OpenStack-API-Version'
|
||||
@@ -81,7 +77,7 @@ class Request(wsgi.Request):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Request, self).__init__(*args, **kwargs)
|
||||
if not hasattr(self, 'api_version_request'):
|
||||
self.api_version_request = api_version.APIVersionRequest()
|
||||
self.api_version_request = api_version_request.APIVersionRequest()
|
||||
|
||||
def best_match_content_type(self):
|
||||
"""Determine the requested response content-type."""
|
||||
@@ -158,25 +154,25 @@ class Request(wsgi.Request):
|
||||
legacy_headers=[LEGACY_API_VERSION_REQUEST_HEADER])
|
||||
|
||||
if hdr_string is None:
|
||||
self.api_version_request = api_version.APIVersionRequest(
|
||||
api_version.DEFAULT_API_VERSION)
|
||||
self.api_version_request = api_version_request.APIVersionRequest(
|
||||
api_version_request.DEFAULT_API_VERSION)
|
||||
elif hdr_string == 'latest':
|
||||
# 'latest' is a special keyword which is equivalent to
|
||||
# requesting the maximum version of the API supported
|
||||
self.api_version_request = api_version.max_api_version()
|
||||
self.api_version_request = api_version_request.max_api_version()
|
||||
else:
|
||||
self.api_version_request = api_version.APIVersionRequest(
|
||||
self.api_version_request = api_version_request.APIVersionRequest(
|
||||
hdr_string)
|
||||
|
||||
# Check that the version requested is within the global
|
||||
# minimum/maximum of supported API versions
|
||||
if not self.api_version_request.matches(
|
||||
api_version.min_api_version(),
|
||||
api_version.max_api_version()):
|
||||
api_version_request.min_api_version(),
|
||||
api_version_request.max_api_version()):
|
||||
raise exception.InvalidGlobalAPIVersion(
|
||||
req_ver=self.api_version_request.get_string(),
|
||||
min_ver=api_version.min_api_version().get_string(),
|
||||
max_ver=api_version.max_api_version().get_string())
|
||||
min_ver=api_version_request.min_api_version().get_string(),
|
||||
max_ver=api_version_request.max_api_version().get_string())
|
||||
|
||||
def set_legacy_v2(self):
|
||||
self.environ[ENV_LEGACY_V2] = True
|
||||
@@ -243,8 +239,8 @@ class WSGICodes:
|
||||
ver = req.api_version_request
|
||||
|
||||
for code, min_version, max_version in self._codes:
|
||||
min_ver = api_version.APIVersionRequest(min_version)
|
||||
max_ver = api_version.APIVersionRequest(max_version)
|
||||
min_ver = api_version_request.APIVersionRequest(min_version)
|
||||
max_ver = api_version_request.APIVersionRequest(max_version)
|
||||
if ver.matches(min_ver, max_ver):
|
||||
return code
|
||||
|
||||
@@ -700,6 +696,46 @@ def removed(version: str, reason: str):
|
||||
return decorator
|
||||
|
||||
|
||||
def api_version(
|
||||
min_version: ty.Optional[str] = None,
|
||||
max_version: ty.Optional[str] = None,
|
||||
):
|
||||
"""Mark an API as supporting lower and upper version bounds.
|
||||
|
||||
:param min_version: A string of two numerals. X.Y indicating the minimum
|
||||
version of the JSON-Schema to validate against.
|
||||
:param max_version: A string of two numerals. X.Y indicating the maximum
|
||||
version of the JSON-Schema against to.
|
||||
"""
|
||||
def decorator(f):
|
||||
@functools.wraps(f)
|
||||
def wrapped(*args, **kwargs):
|
||||
min_ver = api_version_request.APIVersionRequest(min_version)
|
||||
max_ver = api_version_request.APIVersionRequest(max_version)
|
||||
|
||||
# The request object is always the second argument.
|
||||
# However numerous unittests pass in the request object
|
||||
# via kwargs instead so we handle that as well.
|
||||
# TODO(cyeoh): cleanup unittests so we don't have to
|
||||
# to do this
|
||||
if 'req' in kwargs:
|
||||
ver = kwargs['req'].api_version_request
|
||||
else:
|
||||
ver = args[1].api_version_request
|
||||
|
||||
if not ver.matches(min_ver, max_ver):
|
||||
raise exception.VersionNotFoundForAPIMethod(version=ver)
|
||||
|
||||
return f(*args, **kwargs)
|
||||
|
||||
wrapped.min_version = min_version
|
||||
wrapped.max_version = max_version
|
||||
|
||||
return wrapped
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
def expected_errors(
|
||||
errors: ty.Union[int, tuple[int, ...]],
|
||||
min_version: ty.Optional[str] = None,
|
||||
@@ -714,8 +750,8 @@ def expected_errors(
|
||||
def decorator(f):
|
||||
@functools.wraps(f)
|
||||
def wrapped(*args, **kwargs):
|
||||
min_ver = api_version.APIVersionRequest(min_version)
|
||||
max_ver = api_version.APIVersionRequest(max_version)
|
||||
min_ver = api_version_request.APIVersionRequest(min_version)
|
||||
max_ver = api_version_request.APIVersionRequest(max_version)
|
||||
|
||||
# The request object is always the second argument.
|
||||
# However numerous unittests pass in the request object
|
||||
@@ -791,36 +827,22 @@ class ControllerMetaclass(type):
|
||||
|
||||
def __new__(mcs, name, bases, cls_dict):
|
||||
"""Adds the wsgi_actions dictionary to the class."""
|
||||
|
||||
# Find all actions
|
||||
actions = {}
|
||||
versioned_methods = None
|
||||
|
||||
# start with wsgi actions from base classes
|
||||
for base in bases:
|
||||
actions.update(getattr(base, 'wsgi_actions', {}))
|
||||
|
||||
if base.__name__ == "Controller":
|
||||
# NOTE(cyeoh): This resets the VER_METHOD_ATTR attribute
|
||||
# between API controller class creations. This allows us
|
||||
# to use a class decorator on the API methods that doesn't
|
||||
# require naming explicitly what method is being versioned as
|
||||
# it can be implicit based on the method decorated. It is a bit
|
||||
# ugly.
|
||||
if VER_METHOD_ATTR in base.__dict__:
|
||||
versioned_methods = getattr(base, VER_METHOD_ATTR)
|
||||
delattr(base, VER_METHOD_ATTR)
|
||||
|
||||
for key, value in cls_dict.items():
|
||||
if not callable(value):
|
||||
continue
|
||||
|
||||
if getattr(value, 'wsgi_action', None):
|
||||
actions[value.wsgi_action] = key
|
||||
|
||||
# Add the actions to the class dict
|
||||
cls_dict['wsgi_actions'] = actions
|
||||
if versioned_methods:
|
||||
cls_dict[VER_METHOD_ATTR] = versioned_methods
|
||||
|
||||
return super(ControllerMetaclass, mcs).__new__(mcs, name, bases,
|
||||
cls_dict)
|
||||
|
||||
@@ -837,103 +859,6 @@ class Controller(metaclass=ControllerMetaclass):
|
||||
else:
|
||||
self._view_builder = None
|
||||
|
||||
def __getattribute__(self, key):
|
||||
|
||||
def version_select(*args, **kwargs):
|
||||
"""Look for the method which matches the name supplied and version
|
||||
constraints and calls it with the supplied arguments.
|
||||
|
||||
@return: Returns the result of the method called
|
||||
@raises: VersionNotFoundForAPIMethod if there is no method which
|
||||
matches the name and version constraints
|
||||
"""
|
||||
|
||||
# The first arg to all versioned methods is always the request
|
||||
# object. The version for the request is attached to the
|
||||
# request object
|
||||
if len(args) == 0:
|
||||
ver = kwargs['req'].api_version_request
|
||||
else:
|
||||
ver = args[0].api_version_request
|
||||
|
||||
func_list = self.versioned_methods[key]
|
||||
for func in func_list:
|
||||
if ver.matches(func.start_version, func.end_version):
|
||||
# Update the version_select wrapper function so
|
||||
# other decorator attributes like wsgi.response
|
||||
# are still respected.
|
||||
functools.update_wrapper(version_select, func.func)
|
||||
return func.func(self, *args, **kwargs)
|
||||
|
||||
# No version match
|
||||
raise exception.VersionNotFoundForAPIMethod(version=ver)
|
||||
|
||||
try:
|
||||
version_meth_dict = object.__getattribute__(self, VER_METHOD_ATTR)
|
||||
except AttributeError:
|
||||
# No versioning on this class
|
||||
return object.__getattribute__(self, key)
|
||||
|
||||
if version_meth_dict and \
|
||||
key in object.__getattribute__(self, VER_METHOD_ATTR):
|
||||
return version_select
|
||||
|
||||
return object.__getattribute__(self, key)
|
||||
|
||||
# NOTE(cyeoh): This decorator MUST appear first (the outermost
|
||||
# decorator) on an API method for it to work correctly
|
||||
@classmethod
|
||||
def api_version(cls, min_ver, max_ver=None):
|
||||
"""Decorator for versioning api methods.
|
||||
|
||||
Add the decorator to any method which takes a request object
|
||||
as the first parameter and belongs to a class which inherits from
|
||||
wsgi.Controller.
|
||||
|
||||
@min_ver: string representing minimum version
|
||||
@max_ver: optional string representing maximum version
|
||||
"""
|
||||
|
||||
def decorator(f):
|
||||
obj_min_ver = api_version.APIVersionRequest(min_ver)
|
||||
if max_ver:
|
||||
obj_max_ver = api_version.APIVersionRequest(max_ver)
|
||||
else:
|
||||
obj_max_ver = api_version.APIVersionRequest()
|
||||
|
||||
# Add to list of versioned methods registered
|
||||
func_name = f.__name__
|
||||
new_func = versioned_method.VersionedMethod(
|
||||
func_name, obj_min_ver, obj_max_ver, f)
|
||||
|
||||
func_dict = getattr(cls, VER_METHOD_ATTR, {})
|
||||
if not func_dict:
|
||||
setattr(cls, VER_METHOD_ATTR, func_dict)
|
||||
|
||||
func_list = func_dict.get(func_name, [])
|
||||
if not func_list:
|
||||
func_dict[func_name] = func_list
|
||||
func_list.append(new_func)
|
||||
# Ensure the list is sorted by minimum version (reversed)
|
||||
# so later when we work through the list in order we find
|
||||
# the method which has the latest version which supports
|
||||
# the version requested.
|
||||
is_intersect = Controller.check_for_versions_intersection(
|
||||
func_list)
|
||||
|
||||
if is_intersect:
|
||||
raise exception.ApiVersionsIntersect(
|
||||
name=new_func.name,
|
||||
min_ver=new_func.start_version,
|
||||
max_ver=new_func.end_version,
|
||||
)
|
||||
|
||||
func_list.sort(key=lambda f: f.start_version, reverse=True)
|
||||
|
||||
return f
|
||||
|
||||
return decorator
|
||||
|
||||
@staticmethod
|
||||
def is_valid_body(body, entity_name):
|
||||
if not (body and entity_name in body):
|
||||
@@ -948,36 +873,6 @@ class Controller(metaclass=ControllerMetaclass):
|
||||
|
||||
return is_dict(body[entity_name])
|
||||
|
||||
@staticmethod
|
||||
def check_for_versions_intersection(func_list):
|
||||
"""Determines whether function list contains version intervals
|
||||
intersections or not. General algorithm:
|
||||
|
||||
https://en.wikipedia.org/wiki/Intersection_algorithm
|
||||
|
||||
:param func_list: list of VersionedMethod objects
|
||||
:return: boolean
|
||||
"""
|
||||
pairs = []
|
||||
counter = 0
|
||||
|
||||
for f in func_list:
|
||||
pairs.append((f.start_version, 1, f))
|
||||
pairs.append((f.end_version, -1, f))
|
||||
|
||||
def compare(x):
|
||||
return x[0]
|
||||
|
||||
pairs.sort(key=compare)
|
||||
|
||||
for p in pairs:
|
||||
counter += p[1]
|
||||
|
||||
if counter > 1:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class Fault(webob.exc.HTTPException):
|
||||
"""Wrap webob.exc.HTTPException to provide API friendly response."""
|
||||
|
@@ -17,6 +17,7 @@ import functools
|
||||
|
||||
import webob
|
||||
|
||||
from nova.api.openstack import api_version_request
|
||||
from nova.api.openstack.compute import routes
|
||||
from nova.api.openstack import wsgi
|
||||
from nova.api import validation
|
||||
@@ -25,54 +26,50 @@ from nova.tests.unit.api.openstack.compute import dummy_schema
|
||||
|
||||
class MicroversionsController(wsgi.Controller):
|
||||
|
||||
@wsgi.Controller.api_version("2.1")
|
||||
@wsgi.api_version("2.1")
|
||||
def index(self, req):
|
||||
data = {'param': 'val'}
|
||||
return data
|
||||
if api_version_request.is_supported(req, '3.0'):
|
||||
raise webob.exc.HTTPBadRequest()
|
||||
|
||||
@wsgi.Controller.api_version("2.2") # noqa
|
||||
def index(self, req): # noqa
|
||||
data = {'param': 'val2'}
|
||||
if api_version_request.is_supported(req, '2.2'):
|
||||
data = {'param': 'val2'}
|
||||
else:
|
||||
data = {'param': 'val'}
|
||||
return data
|
||||
|
||||
@wsgi.Controller.api_version("3.0") # noqa
|
||||
def index(self, req): # noqa
|
||||
raise webob.exc.HTTPBadRequest()
|
||||
|
||||
|
||||
# We have a second example controller here to help check
|
||||
# for accidental dependencies between API controllers
|
||||
# due to base class changes
|
||||
class MicroversionsController2(wsgi.Controller):
|
||||
|
||||
@wsgi.Controller.api_version("2.2", "2.5")
|
||||
@wsgi.api_version("2.2", "3.1")
|
||||
@wsgi.response(200, "2.2", "2.5")
|
||||
@wsgi.response(202, "2.5", "3.1")
|
||||
def index(self, req):
|
||||
data = {'param': 'controller2_val1'}
|
||||
return data
|
||||
|
||||
@wsgi.Controller.api_version("2.5", "3.1") # noqa
|
||||
@wsgi.response(202)
|
||||
def index(self, req): # noqa
|
||||
data = {'param': 'controller2_val2'}
|
||||
if api_version_request.is_supported(req, '2.5'):
|
||||
data = {'param': 'controller2_val2'}
|
||||
else:
|
||||
data = {'param': 'controller2_val1'}
|
||||
return data
|
||||
|
||||
|
||||
class MicroversionsController3(wsgi.Controller):
|
||||
|
||||
@wsgi.Controller.api_version("2.1")
|
||||
@wsgi.api_version("2.1")
|
||||
@validation.schema(dummy_schema.dummy)
|
||||
def create(self, req, body):
|
||||
data = {'param': 'create_val1'}
|
||||
return data
|
||||
|
||||
@wsgi.Controller.api_version("2.1")
|
||||
@wsgi.api_version("2.1")
|
||||
@validation.schema(dummy_schema.dummy, "2.3", "2.8")
|
||||
@validation.schema(dummy_schema.dummy2, "2.9")
|
||||
def update(self, req, id, body):
|
||||
data = {'param': 'update_val1'}
|
||||
return data
|
||||
|
||||
@wsgi.Controller.api_version("2.1", "2.2")
|
||||
@wsgi.api_version("2.1", "2.2")
|
||||
@wsgi.response(202)
|
||||
@wsgi.action('foo')
|
||||
def _foo(self, req, id, body):
|
||||
@@ -80,24 +77,8 @@ class MicroversionsController3(wsgi.Controller):
|
||||
return data
|
||||
|
||||
|
||||
class MicroversionsController4(wsgi.Controller):
|
||||
|
||||
@wsgi.Controller.api_version("2.1")
|
||||
def _create(self, req):
|
||||
data = {'param': 'controller4_val1'}
|
||||
return data
|
||||
|
||||
@wsgi.Controller.api_version("2.2") # noqa
|
||||
def _create(self, req): # noqa
|
||||
data = {'param': 'controller4_val2'}
|
||||
return data
|
||||
|
||||
def create(self, req, body):
|
||||
return self._create(req)
|
||||
|
||||
|
||||
class MicroversionsExtendsBaseController(wsgi.Controller):
|
||||
@wsgi.Controller.api_version("2.1")
|
||||
@wsgi.api_version("2.1")
|
||||
def show(self, req, id):
|
||||
return {'base_param': 'base_val'}
|
||||
|
||||
@@ -114,10 +95,6 @@ mv3_controller = functools.partial(routes._create_controller,
|
||||
MicroversionsController3, [])
|
||||
|
||||
|
||||
mv4_controller = functools.partial(routes._create_controller,
|
||||
MicroversionsController4, [])
|
||||
|
||||
|
||||
mv5_controller = functools.partial(routes._create_controller,
|
||||
MicroversionsExtendsBaseController, [])
|
||||
|
||||
@@ -138,9 +115,6 @@ ROUTES = (
|
||||
('/microversions3/{id}/action', {
|
||||
'POST': [mv3_controller, 'action']
|
||||
}),
|
||||
('/microversions4', {
|
||||
'POST': [mv4_controller, 'create']
|
||||
}),
|
||||
('/microversions5/{id}', {
|
||||
'GET': [mv5_controller, 'show']
|
||||
}),
|
||||
|
@@ -72,8 +72,7 @@ class LegacyMicroversionsTest(test.NoDBTestCase):
|
||||
self.assertIn(self.header_name, res.headers.getall('Vary'))
|
||||
|
||||
@mock.patch("nova.api.openstack.api_version_request.max_api_version")
|
||||
def test_microversions_return_header_non_default(self,
|
||||
mock_maxver):
|
||||
def test_microversions_return_header_non_default(self, mock_maxver):
|
||||
mock_maxver.return_value = api_version.APIVersionRequest("2.3")
|
||||
|
||||
req = fakes.HTTPRequest.blank(
|
||||
@@ -255,31 +254,6 @@ class LegacyMicroversionsTest(test.NoDBTestCase):
|
||||
else:
|
||||
self.assertEqual("compute 2.10", res.headers[self.header_name])
|
||||
|
||||
@mock.patch("nova.api.openstack.api_version_request.max_api_version")
|
||||
def _test_microversions_inner_function(self, version, expected_resp,
|
||||
mock_maxver):
|
||||
mock_maxver.return_value = api_version.APIVersionRequest("2.2")
|
||||
req = fakes.HTTPRequest.blank(
|
||||
'/v2/%s/microversions4' % fakes.FAKE_PROJECT_ID)
|
||||
req.headers = self._make_header(version)
|
||||
req.environ['CONTENT_TYPE'] = "application/json"
|
||||
req.method = 'POST'
|
||||
req.body = b''
|
||||
|
||||
res = req.get_response(self.app)
|
||||
self.assertEqual(200, res.status_int)
|
||||
resp_json = jsonutils.loads(res.body)
|
||||
self.assertEqual(expected_resp, resp_json['param'])
|
||||
if 'nova' not in self.header_name.lower():
|
||||
version = 'compute %s' % version
|
||||
self.assertEqual(version, res.headers[self.header_name])
|
||||
|
||||
def test_microversions_inner_function_v22(self):
|
||||
self._test_microversions_inner_function('2.2', 'controller4_val2')
|
||||
|
||||
def test_microversions_inner_function_v21(self):
|
||||
self._test_microversions_inner_function('2.1', 'controller4_val1')
|
||||
|
||||
@mock.patch("nova.api.openstack.api_version_request.max_api_version")
|
||||
def _test_microversions_actions(self, ret_code, ret_header, req_header,
|
||||
mock_maxver):
|
||||
|
@@ -116,37 +116,12 @@ class SchemaTest(test.NoDBTestCase):
|
||||
wsgi_action, wsgi_method, action_controller
|
||||
) in wsgi_actions:
|
||||
func = controller.wsgi_actions[wsgi_action]
|
||||
|
||||
if hasattr(action_controller, 'versioned_methods'):
|
||||
if wsgi_method in action_controller.versioned_methods:
|
||||
# currently all our actions are unversioned and if
|
||||
# this changes then we need to fix this
|
||||
funcs = action_controller.versioned_methods[
|
||||
wsgi_method
|
||||
]
|
||||
assert len(funcs) == 1
|
||||
func = funcs[0].func
|
||||
|
||||
# method will always be POST for actions
|
||||
_validate_func(func, method)
|
||||
else:
|
||||
# body validation
|
||||
versioned_methods = getattr(
|
||||
controller.controller, 'versioned_methods', {}
|
||||
)
|
||||
if action in versioned_methods:
|
||||
# versioned method
|
||||
for versioned_method in sorted(
|
||||
versioned_methods[action],
|
||||
key=lambda v: v.start_version
|
||||
):
|
||||
func = versioned_method.func
|
||||
|
||||
_validate_func(func, method)
|
||||
else:
|
||||
# unversioned method
|
||||
func = getattr(controller.controller, action)
|
||||
_validate_func(func, method)
|
||||
func = getattr(controller.controller, action)
|
||||
_validate_func(func, method)
|
||||
|
||||
if missing_request_schemas:
|
||||
raise test.TestingException(
|
||||
|
@@ -17,7 +17,6 @@ import testscenarios
|
||||
import webob
|
||||
|
||||
from nova.api.openstack import api_version_request as api_version
|
||||
from nova.api.openstack import versioned_method
|
||||
from nova.api.openstack import wsgi
|
||||
from nova import exception
|
||||
from nova import test
|
||||
@@ -854,77 +853,42 @@ class ValidBodyTest(test.NoDBTestCase):
|
||||
self.assertFalse(self.controller.is_valid_body(body, 'foo'))
|
||||
|
||||
|
||||
class TestController(test.NoDBTestCase):
|
||||
def test_check_for_versions_intersection_negative(self):
|
||||
func_list = \
|
||||
[versioned_method.VersionedMethod('foo',
|
||||
api_version.APIVersionRequest(
|
||||
'2.1'),
|
||||
api_version.APIVersionRequest(
|
||||
'2.4'),
|
||||
None),
|
||||
versioned_method.VersionedMethod('foo',
|
||||
api_version.APIVersionRequest(
|
||||
'2.11'),
|
||||
api_version.APIVersionRequest(
|
||||
'3.1'),
|
||||
None),
|
||||
versioned_method.VersionedMethod('foo',
|
||||
api_version.APIVersionRequest(
|
||||
'2.8'),
|
||||
api_version.APIVersionRequest(
|
||||
'2.9'),
|
||||
None),
|
||||
]
|
||||
class APIVersionTestCase(test.NoDBTestCase):
|
||||
|
||||
result = wsgi.Controller.check_for_versions_intersection(func_list=
|
||||
func_list)
|
||||
self.assertFalse(result)
|
||||
def test_api_version(self):
|
||||
class FakeController(wsgi.Controller):
|
||||
@wsgi.api_version('2.10', '2.19')
|
||||
def fake_func(self, req):
|
||||
return {'resources': []}
|
||||
|
||||
func_list = \
|
||||
[versioned_method.VersionedMethod('foo',
|
||||
api_version.APIVersionRequest(
|
||||
'2.12'),
|
||||
api_version.APIVersionRequest(
|
||||
'2.14'),
|
||||
None),
|
||||
versioned_method.VersionedMethod('foo',
|
||||
api_version.APIVersionRequest(
|
||||
'3.0'),
|
||||
api_version.APIVersionRequest(
|
||||
'3.4'),
|
||||
None)
|
||||
]
|
||||
controller = FakeController()
|
||||
|
||||
result = wsgi.Controller.check_for_versions_intersection(func_list=
|
||||
func_list)
|
||||
self.assertFalse(result)
|
||||
req = fakes.HTTPRequest.blank('', version='2.10')
|
||||
self.assertEqual({'resources': []}, controller.fake_func(req))
|
||||
|
||||
def test_check_for_versions_intersection_positive(self):
|
||||
func_list = \
|
||||
[versioned_method.VersionedMethod('foo',
|
||||
api_version.APIVersionRequest(
|
||||
'2.1'),
|
||||
api_version.APIVersionRequest(
|
||||
'2.4'),
|
||||
None),
|
||||
versioned_method.VersionedMethod('foo',
|
||||
api_version.APIVersionRequest(
|
||||
'2.3'),
|
||||
api_version.APIVersionRequest(
|
||||
'3.0'),
|
||||
None),
|
||||
versioned_method.VersionedMethod('foo',
|
||||
api_version.APIVersionRequest(
|
||||
'2.8'),
|
||||
api_version.APIVersionRequest(
|
||||
'2.9'),
|
||||
None),
|
||||
]
|
||||
req = fakes.HTTPRequest.blank('', version='2.19')
|
||||
self.assertEqual({'resources': []}, controller.fake_func(req))
|
||||
|
||||
result = wsgi.Controller.check_for_versions_intersection(func_list=
|
||||
func_list)
|
||||
self.assertTrue(result)
|
||||
req = fakes.HTTPRequest.blank('', version='2.9')
|
||||
self.assertRaises(
|
||||
exception.VersionNotFoundForAPIMethod, controller.fake_func, req
|
||||
)
|
||||
|
||||
req = fakes.HTTPRequest.blank('', version='2.20')
|
||||
self.assertRaises(
|
||||
exception.VersionNotFoundForAPIMethod, controller.fake_func, req
|
||||
)
|
||||
|
||||
def test_api_version_legacy(self):
|
||||
class FakeController(wsgi.Controller):
|
||||
@wsgi.api_version('2.0', '2.10')
|
||||
def fake_func(self, req):
|
||||
return {'resources': []}
|
||||
|
||||
controller = FakeController()
|
||||
req = fakes.HTTPRequest.blank('')
|
||||
req.set_legacy_v2()
|
||||
self.assertEqual({'resources': []}, controller.fake_func(req))
|
||||
|
||||
|
||||
class ExpectedErrorTestCase(test.NoDBTestCase):
|
||||
|
Reference in New Issue
Block a user