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::
|
In the controller class::
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.4")
|
@wsgi.api_version("2.4")
|
||||||
def my_api_method(self, req, id):
|
def my_api_method(self, req, id):
|
||||||
....
|
...
|
||||||
|
|
||||||
This method would only be available if the caller had specified an
|
This method would only be available if the caller had specified an
|
||||||
``OpenStack-API-Version`` of >= ``2.4``. If they had specified a
|
``OpenStack-API-Version`` of >= ``2.4``. If they had specified a
|
||||||
@@ -254,36 +254,14 @@ Removing an API method
|
|||||||
|
|
||||||
In the controller class::
|
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):
|
def my_api_method(self, req, id):
|
||||||
....
|
...
|
||||||
|
|
||||||
This method would only be available if the caller had specified an
|
This method would only be available if the caller had specified an
|
||||||
``OpenStack-API-Version`` of <= ``2.4``. If ``2.5`` or later
|
``OpenStack-API-Version`` of <= ``2.4``. If ``2.5`` or later
|
||||||
is specified the server will respond with ``HTTP/404``.
|
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
|
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``
|
validation, you can add a version range to the ``validation.schema``
|
||||||
decorator::
|
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.dummy, "2.3", "2.8")
|
||||||
@validation.schema(dummy_schema.dummy2, "2.9")
|
@validation.schema(dummy_schema.dummy2, "2.9")
|
||||||
def update(self, req, id, body):
|
def update(self, req, id, body):
|
||||||
....
|
...
|
||||||
|
|
||||||
This method will be available from version ``2.1``, validated according to
|
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.dummy`` from ``2.3`` to ``2.8``, and validated according to
|
||||||
``dummy_schema.dummy2`` from ``2.9`` onward.
|
``dummy_schema.dummy2`` from ``2.9`` onward.
|
||||||
|
|
||||||
|
Other API method changes
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
When not using decorators
|
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
|
||||||
When you don't want to use the ``@api_version`` decorator on a method
|
has an api_version_request object attached to the req object and that can be
|
||||||
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
|
|
||||||
used to modify behavior based on its value::
|
used to modify behavior based on its value::
|
||||||
|
|
||||||
def index(self, req):
|
def index(self, req):
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ class AggregateController(wsgi.Controller):
|
|||||||
(show_uuid or key != 'uuid')):
|
(show_uuid or key != 'uuid')):
|
||||||
yield key, getattr(aggregate, key)
|
yield key, getattr(aggregate, key)
|
||||||
|
|
||||||
@wsgi.Controller.api_version('2.81')
|
@wsgi.api_version('2.81')
|
||||||
@wsgi.response(202)
|
@wsgi.response(202)
|
||||||
@wsgi.expected_errors((400, 404))
|
@wsgi.expected_errors((400, 404))
|
||||||
@validation.schema(aggregate_images.aggregate_images)
|
@validation.schema(aggregate_images.aggregate_images)
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class BareMetalNodeController(wsgi.Controller):
|
|||||||
)
|
)
|
||||||
return self._ironic_connection
|
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))
|
@wsgi.expected_errors((404, 501))
|
||||||
@validation.query_schema(schema.index_query)
|
@validation.query_schema(schema.index_query)
|
||||||
@validation.response_body_schema(schema.index_response)
|
@validation.response_body_schema(schema.index_response)
|
||||||
@@ -86,7 +86,7 @@ class BareMetalNodeController(wsgi.Controller):
|
|||||||
|
|
||||||
return {'nodes': nodes}
|
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))
|
@wsgi.expected_errors((404, 501))
|
||||||
@validation.query_schema(schema.show_query)
|
@validation.query_schema(schema.show_query)
|
||||||
@validation.response_body_schema(schema.show_response)
|
@validation.response_body_schema(schema.show_response)
|
||||||
@@ -117,20 +117,20 @@ class BareMetalNodeController(wsgi.Controller):
|
|||||||
|
|
||||||
return {'node': node}
|
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)
|
@wsgi.expected_errors(400)
|
||||||
@validation.schema(schema.create)
|
@validation.schema(schema.create)
|
||||||
@validation.response_body_schema(schema.create_response)
|
@validation.response_body_schema(schema.create_response)
|
||||||
def create(self, req, body):
|
def create(self, req, body):
|
||||||
_no_ironic_proxy("node-create")
|
_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)
|
@wsgi.expected_errors(400)
|
||||||
@validation.response_body_schema(schema.delete_response)
|
@validation.response_body_schema(schema.delete_response)
|
||||||
def delete(self, req, id):
|
def delete(self, req, id):
|
||||||
_no_ironic_proxy("node-delete")
|
_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.action('add_interface')
|
||||||
@wsgi.expected_errors(400)
|
@wsgi.expected_errors(400)
|
||||||
@validation.schema(schema.add_interface)
|
@validation.schema(schema.add_interface)
|
||||||
@@ -138,7 +138,7 @@ class BareMetalNodeController(wsgi.Controller):
|
|||||||
def _add_interface(self, req, id, body):
|
def _add_interface(self, req, id, body):
|
||||||
_no_ironic_proxy("port-create")
|
_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.action('remove_interface')
|
||||||
@wsgi.expected_errors(400)
|
@wsgi.expected_errors(400)
|
||||||
@validation.schema(schema.remove_interface)
|
@validation.schema(schema.remove_interface)
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ class FlavorsController(wsgi.Controller):
|
|||||||
return self._view_builder.show(req, flavor, include_description,
|
return self._view_builder.show(req, flavor, include_description,
|
||||||
include_extra_specs=include_extra_specs)
|
include_extra_specs=include_extra_specs)
|
||||||
|
|
||||||
@wsgi.Controller.api_version('2.55')
|
@wsgi.api_version('2.55')
|
||||||
@wsgi.expected_errors((400, 404))
|
@wsgi.expected_errors((400, 404))
|
||||||
@validation.schema(schema.update, '2.55')
|
@validation.schema(schema.update, '2.55')
|
||||||
@validation.response_body_schema(schema.update_response, '2.55', '2.60')
|
@validation.response_body_schema(schema.update_response, '2.55', '2.60')
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class FloatingIPPoolsController(wsgi.Controller):
|
|||||||
super(FloatingIPPoolsController, self).__init__()
|
super(FloatingIPPoolsController, self).__init__()
|
||||||
self.network_api = neutron.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(())
|
@wsgi.expected_errors(())
|
||||||
@validation.query_schema(schema.index_query)
|
@validation.query_schema(schema.index_query)
|
||||||
@validation.response_body_schema(schema.index_response)
|
@validation.response_body_schema(schema.index_response)
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ class FloatingIPController(wsgi.Controller):
|
|||||||
self.compute_api = compute.API()
|
self.compute_api = compute.API()
|
||||||
self.network_api = neutron.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))
|
@wsgi.expected_errors((400, 404))
|
||||||
@validation.query_schema(schema.show_query)
|
@validation.query_schema(schema.show_query)
|
||||||
def show(self, req, id):
|
def show(self, req, id):
|
||||||
@@ -101,7 +101,7 @@ class FloatingIPController(wsgi.Controller):
|
|||||||
|
|
||||||
return _translate_floating_ip_view(floating_ip)
|
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(())
|
@wsgi.expected_errors(())
|
||||||
@validation.query_schema(schema.index_query)
|
@validation.query_schema(schema.index_query)
|
||||||
def index(self, req):
|
def index(self, req):
|
||||||
@@ -115,7 +115,7 @@ class FloatingIPController(wsgi.Controller):
|
|||||||
return {'floating_ips': [_translate_floating_ip_view(ip)['floating_ip']
|
return {'floating_ips': [_translate_floating_ip_view(ip)['floating_ip']
|
||||||
for ip in floating_ips]}
|
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))
|
@wsgi.expected_errors((400, 403, 404))
|
||||||
@validation.schema(schema.create)
|
@validation.schema(schema.create)
|
||||||
def create(self, req, body=None):
|
def create(self, req, body=None):
|
||||||
@@ -148,7 +148,7 @@ class FloatingIPController(wsgi.Controller):
|
|||||||
|
|
||||||
return _translate_floating_ip_view(ip)
|
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.response(202)
|
||||||
@wsgi.expected_errors((400, 403, 404, 409))
|
@wsgi.expected_errors((400, 403, 404, 409))
|
||||||
def delete(self, req, id):
|
def delete(self, req, id):
|
||||||
@@ -186,7 +186,7 @@ class FloatingIPActionController(wsgi.Controller):
|
|||||||
self.compute_api = compute.API()
|
self.compute_api = compute.API()
|
||||||
self.network_api = neutron.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.expected_errors((400, 403, 404))
|
||||||
@wsgi.action('addFloatingIp')
|
@wsgi.action('addFloatingIp')
|
||||||
@validation.schema(schema.add_floating_ip)
|
@validation.schema(schema.add_floating_ip)
|
||||||
@@ -267,7 +267,7 @@ class FloatingIPActionController(wsgi.Controller):
|
|||||||
|
|
||||||
return webob.Response(status_int=202)
|
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.expected_errors((400, 403, 404, 409))
|
||||||
@wsgi.action('removeFloatingIp')
|
@wsgi.action('removeFloatingIp')
|
||||||
@validation.schema(schema.remove_floating_ip)
|
@validation.schema(schema.remove_floating_ip)
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class HostController(wsgi.Controller):
|
|||||||
super(HostController, self).__init__()
|
super(HostController, self).__init__()
|
||||||
self.api = compute.HostAPI()
|
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)
|
@validation.query_schema(hosts.index_query)
|
||||||
@wsgi.expected_errors(())
|
@wsgi.expected_errors(())
|
||||||
def index(self, req):
|
def index(self, req):
|
||||||
@@ -88,7 +88,7 @@ class HostController(wsgi.Controller):
|
|||||||
'zone': service['availability_zone']})
|
'zone': service['availability_zone']})
|
||||||
return {'hosts': hosts}
|
return {'hosts': hosts}
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.1", "2.42")
|
@wsgi.api_version("2.1", "2.42")
|
||||||
@wsgi.expected_errors((400, 404, 501))
|
@wsgi.expected_errors((400, 404, 501))
|
||||||
@validation.schema(hosts.update)
|
@validation.schema(hosts.update)
|
||||||
def update(self, req, id, body):
|
def update(self, req, id, body):
|
||||||
@@ -180,7 +180,7 @@ class HostController(wsgi.Controller):
|
|||||||
raise webob.exc.HTTPBadRequest(explanation=e.format_message())
|
raise webob.exc.HTTPBadRequest(explanation=e.format_message())
|
||||||
return {"host": host_name, "power_action": result}
|
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))
|
@wsgi.expected_errors((400, 404, 501))
|
||||||
@validation.query_schema(hosts.startup_query)
|
@validation.query_schema(hosts.startup_query)
|
||||||
def startup(self, req, id):
|
def startup(self, req, id):
|
||||||
@@ -189,7 +189,7 @@ class HostController(wsgi.Controller):
|
|||||||
target={})
|
target={})
|
||||||
return self._host_power_action(req, host_name=id, action="startup")
|
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))
|
@wsgi.expected_errors((400, 404, 501))
|
||||||
@validation.query_schema(hosts.shutdown_query)
|
@validation.query_schema(hosts.shutdown_query)
|
||||||
def shutdown(self, req, id):
|
def shutdown(self, req, id):
|
||||||
@@ -198,7 +198,7 @@ class HostController(wsgi.Controller):
|
|||||||
target={})
|
target={})
|
||||||
return self._host_power_action(req, host_name=id, action="shutdown")
|
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))
|
@wsgi.expected_errors((400, 404, 501))
|
||||||
@validation.query_schema(hosts.reboot_query)
|
@validation.query_schema(hosts.reboot_query)
|
||||||
def reboot(self, req, id):
|
def reboot(self, req, id):
|
||||||
@@ -256,7 +256,7 @@ class HostController(wsgi.Controller):
|
|||||||
instance['ephemeral_gb'])
|
instance['ephemeral_gb'])
|
||||||
return project_map
|
return project_map
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.1", "2.42")
|
@wsgi.api_version("2.1", "2.42")
|
||||||
@wsgi.expected_errors(404)
|
@wsgi.expected_errors(404)
|
||||||
@validation.query_schema(hosts.show_query)
|
@validation.query_schema(hosts.show_query)
|
||||||
def show(self, req, id):
|
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))
|
@wsgi.expected_errors((400, 404, 501))
|
||||||
@validation.query_schema(schema.uptime_query)
|
@validation.query_schema(schema.uptime_query)
|
||||||
def uptime(self, req, id):
|
def uptime(self, req, id):
|
||||||
@@ -412,7 +412,7 @@ class HypervisorsController(wsgi.Controller):
|
|||||||
|
|
||||||
return {'hypervisor': hypervisor}
|
return {'hypervisor': hypervisor}
|
||||||
|
|
||||||
@wsgi.Controller.api_version('2.1', '2.52')
|
@wsgi.api_version('2.1', '2.52')
|
||||||
@wsgi.expected_errors(404)
|
@wsgi.expected_errors(404)
|
||||||
@validation.query_schema(schema.search_query)
|
@validation.query_schema(schema.search_query)
|
||||||
def search(self, req, id):
|
def search(self, req, id):
|
||||||
@@ -451,7 +451,7 @@ class HypervisorsController(wsgi.Controller):
|
|||||||
|
|
||||||
return {'hypervisors': hypervisors}
|
return {'hypervisors': hypervisors}
|
||||||
|
|
||||||
@wsgi.Controller.api_version('2.1', '2.52')
|
@wsgi.api_version('2.1', '2.52')
|
||||||
@wsgi.expected_errors(404)
|
@wsgi.expected_errors(404)
|
||||||
@validation.query_schema(schema.servers_query)
|
@validation.query_schema(schema.servers_query)
|
||||||
def servers(self, req, id):
|
def servers(self, req, id):
|
||||||
@@ -497,7 +497,7 @@ class HypervisorsController(wsgi.Controller):
|
|||||||
|
|
||||||
return {'hypervisors': hypervisors}
|
return {'hypervisors': hypervisors}
|
||||||
|
|
||||||
@wsgi.Controller.api_version('2.1', '2.87')
|
@wsgi.api_version('2.1', '2.87')
|
||||||
@wsgi.expected_errors(())
|
@wsgi.expected_errors(())
|
||||||
@validation.query_schema(schema.statistics_query)
|
@validation.query_schema(schema.statistics_query)
|
||||||
def statistics(self, req):
|
def statistics(self, req):
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class ImageMetadataController(wsgi.Controller):
|
|||||||
msg = _("Image not found.")
|
msg = _("Image not found.")
|
||||||
raise exc.HTTPNotFound(explanation=msg)
|
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))
|
@wsgi.expected_errors((403, 404))
|
||||||
@validation.query_schema(image_metadata.index_query)
|
@validation.query_schema(image_metadata.index_query)
|
||||||
def index(self, req, image_id):
|
def index(self, req, image_id):
|
||||||
@@ -52,7 +52,7 @@ class ImageMetadataController(wsgi.Controller):
|
|||||||
metadata = self._get_image(context, image_id)['properties']
|
metadata = self._get_image(context, image_id)['properties']
|
||||||
return dict(metadata=metadata)
|
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.expected_errors((403, 404))
|
||||||
@validation.query_schema(image_metadata.show_query)
|
@validation.query_schema(image_metadata.show_query)
|
||||||
def show(self, req, image_id, id):
|
def show(self, req, image_id, id):
|
||||||
@@ -63,7 +63,7 @@ class ImageMetadataController(wsgi.Controller):
|
|||||||
else:
|
else:
|
||||||
raise exc.HTTPNotFound()
|
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))
|
@wsgi.expected_errors((400, 403, 404))
|
||||||
@validation.schema(image_metadata.create)
|
@validation.schema(image_metadata.create)
|
||||||
def create(self, req, image_id, body):
|
def create(self, req, image_id, body):
|
||||||
@@ -80,7 +80,7 @@ class ImageMetadataController(wsgi.Controller):
|
|||||||
raise exc.HTTPForbidden(explanation=e.format_message())
|
raise exc.HTTPForbidden(explanation=e.format_message())
|
||||||
return dict(metadata=image['properties'])
|
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))
|
@wsgi.expected_errors((400, 403, 404))
|
||||||
@validation.schema(image_metadata.update)
|
@validation.schema(image_metadata.update)
|
||||||
def update(self, req, image_id, id, body):
|
def update(self, req, image_id, id, body):
|
||||||
@@ -103,7 +103,7 @@ class ImageMetadataController(wsgi.Controller):
|
|||||||
raise exc.HTTPForbidden(explanation=e.format_message())
|
raise exc.HTTPForbidden(explanation=e.format_message())
|
||||||
return dict(meta=meta)
|
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))
|
@wsgi.expected_errors((400, 403, 404))
|
||||||
@validation.schema(image_metadata.update_all)
|
@validation.schema(image_metadata.update_all)
|
||||||
def update_all(self, req, image_id, body):
|
def update_all(self, req, image_id, body):
|
||||||
@@ -119,7 +119,7 @@ class ImageMetadataController(wsgi.Controller):
|
|||||||
raise exc.HTTPForbidden(explanation=e.format_message())
|
raise exc.HTTPForbidden(explanation=e.format_message())
|
||||||
return dict(metadata=metadata)
|
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.expected_errors((403, 404))
|
||||||
@wsgi.response(204)
|
@wsgi.response(204)
|
||||||
def delete(self, req, image_id, id):
|
def delete(self, req, image_id, id):
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ class ImagesController(wsgi.Controller):
|
|||||||
|
|
||||||
return filters
|
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)
|
@wsgi.expected_errors(404)
|
||||||
@validation.query_schema(schema.show_query)
|
@validation.query_schema(schema.show_query)
|
||||||
def show(self, req, id):
|
def show(self, req, id):
|
||||||
@@ -93,7 +93,7 @@ class ImagesController(wsgi.Controller):
|
|||||||
|
|
||||||
return self._view_builder.show(req, image)
|
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.expected_errors((403, 404))
|
||||||
@wsgi.response(204)
|
@wsgi.response(204)
|
||||||
def delete(self, req, id):
|
def delete(self, req, id):
|
||||||
@@ -114,7 +114,7 @@ class ImagesController(wsgi.Controller):
|
|||||||
explanation = _("You are not allowed to delete the image.")
|
explanation = _("You are not allowed to delete the image.")
|
||||||
raise webob.exc.HTTPForbidden(explanation=explanation)
|
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)
|
@wsgi.expected_errors(400)
|
||||||
@validation.query_schema(schema.index_query)
|
@validation.query_schema(schema.index_query)
|
||||||
def index(self, req):
|
def index(self, req):
|
||||||
@@ -134,7 +134,7 @@ class ImagesController(wsgi.Controller):
|
|||||||
raise webob.exc.HTTPBadRequest(explanation=e.format_message())
|
raise webob.exc.HTTPBadRequest(explanation=e.format_message())
|
||||||
return self._view_builder.index(req, images)
|
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)
|
@wsgi.expected_errors(400)
|
||||||
@validation.query_schema(schema.detail_query)
|
@validation.query_schema(schema.detail_query)
|
||||||
def detail(self, req):
|
def detail(self, req):
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class MultinicController(wsgi.Controller):
|
|||||||
super(MultinicController, self).__init__()
|
super(MultinicController, self).__init__()
|
||||||
self.compute_api = compute.API()
|
self.compute_api = compute.API()
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.1", "2.43")
|
@wsgi.api_version("2.1", "2.43")
|
||||||
@wsgi.response(202)
|
@wsgi.response(202)
|
||||||
@wsgi.action('addFixedIp')
|
@wsgi.action('addFixedIp')
|
||||||
@wsgi.expected_errors((400, 404))
|
@wsgi.expected_errors((400, 404))
|
||||||
@@ -52,7 +52,7 @@ class MultinicController(wsgi.Controller):
|
|||||||
except exception.NoMoreFixedIps as e:
|
except exception.NoMoreFixedIps as e:
|
||||||
raise exc.HTTPBadRequest(explanation=e.format_message())
|
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.response(202)
|
||||||
@wsgi.action('removeFixedIp')
|
@wsgi.action('removeFixedIp')
|
||||||
@wsgi.expected_errors((400, 404))
|
@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
|
# TODO(stephenfin): 'network_api' is only being passed for use by tests
|
||||||
self.network_api = network_api or neutron.API()
|
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(())
|
@wsgi.expected_errors(())
|
||||||
@validation.query_schema(schema.index_query)
|
@validation.query_schema(schema.index_query)
|
||||||
def index(self, req):
|
def index(self, req):
|
||||||
@@ -88,7 +88,7 @@ class NetworkController(wsgi.Controller):
|
|||||||
result = [network_dict(context, net_ref) for net_ref in networks]
|
result = [network_dict(context, net_ref) for net_ref in networks]
|
||||||
return {'networks': result}
|
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)
|
@wsgi.expected_errors(404)
|
||||||
@validation.query_schema(schema.show_query)
|
@validation.query_schema(schema.show_query)
|
||||||
def show(self, req, id):
|
def show(self, req, id):
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ class QuotaSetsController(wsgi.Controller):
|
|||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
@wsgi.Controller.api_version('2.1')
|
@wsgi.api_version('2.1')
|
||||||
@wsgi.expected_errors(400)
|
@wsgi.expected_errors(400)
|
||||||
@validation.query_schema(quota_sets.show_query, '2.0', '2.74')
|
@validation.query_schema(quota_sets.show_query, '2.0', '2.74')
|
||||||
@validation.query_schema(quota_sets.show_query_v275, '2.75')
|
@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),
|
self._get_quotas(context, id, user_id=user_id, usages=True),
|
||||||
filtered_quotas=filtered_quotas)
|
filtered_quotas=filtered_quotas)
|
||||||
|
|
||||||
@wsgi.Controller.api_version('2.1')
|
@wsgi.api_version('2.1')
|
||||||
@wsgi.expected_errors(400)
|
@wsgi.expected_errors(400)
|
||||||
@validation.schema(quota_sets.update, '2.0', '2.35')
|
@validation.schema(quota_sets.update, '2.0', '2.35')
|
||||||
@validation.schema(quota_sets.update_v236, '2.36', '2.56')
|
@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),
|
self._get_quotas(context, id, user_id=user_id),
|
||||||
filtered_quotas=filtered_quotas)
|
filtered_quotas=filtered_quotas)
|
||||||
|
|
||||||
@wsgi.Controller.api_version('2.0')
|
@wsgi.api_version('2.0')
|
||||||
@wsgi.expected_errors(400)
|
@wsgi.expected_errors(400)
|
||||||
@validation.query_schema(quota_sets.defaults_query)
|
@validation.query_schema(quota_sets.defaults_query)
|
||||||
def defaults(self, req, id):
|
def defaults(self, req, id):
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class RemoteConsolesController(wsgi.Controller):
|
|||||||
'serial': self.compute_api.get_serial_console,
|
'serial': self.compute_api.get_serial_console,
|
||||||
'mks': self.compute_api.get_mks_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.expected_errors((400, 404, 409, 501))
|
||||||
@wsgi.action('os-getVNCConsole')
|
@wsgi.action('os-getVNCConsole')
|
||||||
@validation.schema(schema.get_vnc_console)
|
@validation.schema(schema.get_vnc_console)
|
||||||
@@ -69,7 +69,7 @@ class RemoteConsolesController(wsgi.Controller):
|
|||||||
|
|
||||||
return {'console': {'type': console_type, 'url': output['url']}}
|
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.expected_errors((400, 404, 409, 501))
|
||||||
@wsgi.action('os-getSPICEConsole')
|
@wsgi.action('os-getSPICEConsole')
|
||||||
@validation.schema(schema.get_spice_console)
|
@validation.schema(schema.get_spice_console)
|
||||||
@@ -98,7 +98,7 @@ class RemoteConsolesController(wsgi.Controller):
|
|||||||
|
|
||||||
return {'console': {'type': console_type, 'url': output['url']}}
|
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.expected_errors((400, 404, 409, 501))
|
||||||
@wsgi.action('os-getRDPConsole')
|
@wsgi.action('os-getRDPConsole')
|
||||||
@wsgi.removed('29.0.0', _rdp_console_removal_reason)
|
@wsgi.removed('29.0.0', _rdp_console_removal_reason)
|
||||||
@@ -109,7 +109,7 @@ class RemoteConsolesController(wsgi.Controller):
|
|||||||
"""
|
"""
|
||||||
raise webob.exc.HTTPBadRequest()
|
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.expected_errors((400, 404, 409, 501))
|
||||||
@wsgi.action('os-getSerialConsole')
|
@wsgi.action('os-getSerialConsole')
|
||||||
@validation.schema(schema.get_serial_console)
|
@validation.schema(schema.get_serial_console)
|
||||||
@@ -140,7 +140,7 @@ class RemoteConsolesController(wsgi.Controller):
|
|||||||
|
|
||||||
return {'console': {'type': console_type, 'url': output['url']}}
|
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))
|
@wsgi.expected_errors((400, 404, 409, 501))
|
||||||
@validation.schema(schema.create_v26, "2.6", "2.7")
|
@validation.schema(schema.create_v26, "2.6", "2.7")
|
||||||
@validation.schema(schema.create_v28, "2.8", "2.98")
|
@validation.schema(schema.create_v28, "2.8", "2.98")
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ class SecurityGroupControllerBase(object):
|
|||||||
class SecurityGroupController(SecurityGroupControllerBase, wsgi.Controller):
|
class SecurityGroupController(SecurityGroupControllerBase, wsgi.Controller):
|
||||||
"""The Security group API controller for the OpenStack API."""
|
"""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))
|
@wsgi.expected_errors((400, 404))
|
||||||
@validation.query_schema(schema.show_query)
|
@validation.query_schema(schema.show_query)
|
||||||
def show(self, req, id):
|
def show(self, req, id):
|
||||||
@@ -154,7 +154,7 @@ class SecurityGroupController(SecurityGroupControllerBase, wsgi.Controller):
|
|||||||
return {'security_group': self._format_security_group(context,
|
return {'security_group': self._format_security_group(context,
|
||||||
security_group)}
|
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.expected_errors((400, 404))
|
||||||
@wsgi.response(202)
|
@wsgi.response(202)
|
||||||
def delete(self, req, id):
|
def delete(self, req, id):
|
||||||
@@ -172,7 +172,7 @@ class SecurityGroupController(SecurityGroupControllerBase, wsgi.Controller):
|
|||||||
except exception.Invalid as exp:
|
except exception.Invalid as exp:
|
||||||
raise exc.HTTPBadRequest(explanation=exp.format_message())
|
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)
|
@validation.query_schema(schema.index_query)
|
||||||
@wsgi.expected_errors(404)
|
@wsgi.expected_errors(404)
|
||||||
def index(self, req):
|
def index(self, req):
|
||||||
@@ -196,7 +196,7 @@ class SecurityGroupController(SecurityGroupControllerBase, wsgi.Controller):
|
|||||||
list(sorted(result,
|
list(sorted(result,
|
||||||
key=lambda k: (k['tenant_id'], k['name'])))}
|
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))
|
@wsgi.expected_errors((400, 403))
|
||||||
@validation.schema(schema.create)
|
@validation.schema(schema.create)
|
||||||
def create(self, req, body):
|
def create(self, req, body):
|
||||||
@@ -219,7 +219,7 @@ class SecurityGroupController(SecurityGroupControllerBase, wsgi.Controller):
|
|||||||
return {'security_group': self._format_security_group(context,
|
return {'security_group': self._format_security_group(context,
|
||||||
group_ref)}
|
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))
|
@wsgi.expected_errors((400, 404))
|
||||||
@validation.schema(schema.update)
|
@validation.schema(schema.update)
|
||||||
def update(self, req, id, body):
|
def update(self, req, id, body):
|
||||||
@@ -254,7 +254,7 @@ class SecurityGroupController(SecurityGroupControllerBase, wsgi.Controller):
|
|||||||
class SecurityGroupRulesController(SecurityGroupControllerBase,
|
class SecurityGroupRulesController(SecurityGroupControllerBase,
|
||||||
wsgi.Controller):
|
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))
|
@wsgi.expected_errors((400, 403, 404))
|
||||||
@validation.schema(schema.create_rules)
|
@validation.schema(schema.create_rules)
|
||||||
def create(self, req, body):
|
def create(self, req, body):
|
||||||
@@ -327,7 +327,7 @@ class SecurityGroupRulesController(SecurityGroupControllerBase,
|
|||||||
return security_group_api.new_cidr_ingress_rule(
|
return security_group_api.new_cidr_ingress_rule(
|
||||||
cidr, ip_protocol, from_port, to_port)
|
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.expected_errors((400, 404, 409))
|
||||||
@wsgi.response(202)
|
@wsgi.response(202)
|
||||||
def delete(self, req, id):
|
def delete(self, req, id):
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ class ServerGroupController(wsgi.Controller):
|
|||||||
for group in limited_list]
|
for group in limited_list]
|
||||||
return {'server_groups': result}
|
return {'server_groups': result}
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.1")
|
@wsgi.api_version("2.1")
|
||||||
@wsgi.expected_errors((400, 403, 409))
|
@wsgi.expected_errors((400, 403, 409))
|
||||||
@validation.schema(schema.create, "2.0", "2.14")
|
@validation.schema(schema.create, "2.0", "2.14")
|
||||||
@validation.schema(schema.create_v215, "2.15", "2.63")
|
@validation.schema(schema.create_v215, "2.15", "2.63")
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class ServerMigrationsController(wsgi.Controller):
|
|||||||
super(ServerMigrationsController, self).__init__()
|
super(ServerMigrationsController, self).__init__()
|
||||||
self.compute_api = compute.API()
|
self.compute_api = compute.API()
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.22")
|
@wsgi.api_version("2.22")
|
||||||
@wsgi.response(202)
|
@wsgi.response(202)
|
||||||
@wsgi.expected_errors((400, 403, 404, 409))
|
@wsgi.expected_errors((400, 403, 404, 409))
|
||||||
@wsgi.action('force_complete')
|
@wsgi.action('force_complete')
|
||||||
@@ -91,7 +91,7 @@ class ServerMigrationsController(wsgi.Controller):
|
|||||||
common.raise_http_conflict_for_instance_invalid_state(
|
common.raise_http_conflict_for_instance_invalid_state(
|
||||||
state_error, 'force_complete', server_id)
|
state_error, 'force_complete', server_id)
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.23")
|
@wsgi.api_version("2.23")
|
||||||
@wsgi.expected_errors(404)
|
@wsgi.expected_errors(404)
|
||||||
@validation.query_schema(schema.index_query)
|
@validation.query_schema(schema.index_query)
|
||||||
def index(self, req, server_id):
|
def index(self, req, server_id):
|
||||||
@@ -114,7 +114,7 @@ class ServerMigrationsController(wsgi.Controller):
|
|||||||
output(migration, include_uuid, include_user_project)
|
output(migration, include_uuid, include_user_project)
|
||||||
for migration in migrations]}
|
for migration in migrations]}
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.23")
|
@wsgi.api_version("2.23")
|
||||||
@wsgi.expected_errors(404)
|
@wsgi.expected_errors(404)
|
||||||
@validation.query_schema(schema.show_query)
|
@validation.query_schema(schema.show_query)
|
||||||
def show(self, req, server_id, id):
|
def show(self, req, server_id, id):
|
||||||
@@ -153,7 +153,7 @@ class ServerMigrationsController(wsgi.Controller):
|
|||||||
return {'migration': output(migration, include_uuid,
|
return {'migration': output(migration, include_uuid,
|
||||||
include_user_project)}
|
include_user_project)}
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.24")
|
@wsgi.api_version("2.24")
|
||||||
@wsgi.response(202)
|
@wsgi.response(202)
|
||||||
@wsgi.expected_errors((400, 404, 409))
|
@wsgi.expected_errors((400, 404, 409))
|
||||||
def delete(self, req, server_id, id):
|
def delete(self, req, server_id, id):
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ class ServerSharesController(wsgi.Controller):
|
|||||||
)
|
)
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.97")
|
@wsgi.api_version("2.97")
|
||||||
@wsgi.response(200)
|
@wsgi.response(200)
|
||||||
@wsgi.expected_errors((400, 403, 404))
|
@wsgi.expected_errors((400, 403, 404))
|
||||||
@validation.query_schema(schema.index_query)
|
@validation.query_schema(schema.index_query)
|
||||||
@@ -91,7 +91,7 @@ class ServerSharesController(wsgi.Controller):
|
|||||||
|
|
||||||
return self._view_builder._list_view(db_shares)
|
return self._view_builder._list_view(db_shares)
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.97")
|
@wsgi.api_version("2.97")
|
||||||
@wsgi.response(201)
|
@wsgi.response(201)
|
||||||
@wsgi.expected_errors((400, 403, 404, 409))
|
@wsgi.expected_errors((400, 403, 404, 409))
|
||||||
@validation.schema(schema.create, '2.97')
|
@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.
|
Prevent user from using the same tag twice on the same instance.
|
||||||
"""
|
"""
|
||||||
try:
|
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
|
share_mapping.instance_uuid, share_mapping.share_id
|
||||||
)
|
)
|
||||||
raise exception.ShareMappingAlreadyExists(
|
raise exception.ShareMappingAlreadyExists(
|
||||||
@@ -196,7 +197,7 @@ class ServerSharesController(wsgi.Controller):
|
|||||||
|
|
||||||
return view
|
return view
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.97")
|
@wsgi.api_version("2.97")
|
||||||
@wsgi.response(200)
|
@wsgi.response(200)
|
||||||
@wsgi.expected_errors((400, 403, 404))
|
@wsgi.expected_errors((400, 403, 404))
|
||||||
@validation.query_schema(schema.show_query)
|
@validation.query_schema(schema.show_query)
|
||||||
@@ -227,7 +228,7 @@ class ServerSharesController(wsgi.Controller):
|
|||||||
|
|
||||||
return view
|
return view
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.97")
|
@wsgi.api_version("2.97")
|
||||||
@wsgi.response(200)
|
@wsgi.response(200)
|
||||||
@wsgi.expected_errors((400, 403, 404, 409))
|
@wsgi.expected_errors((400, 403, 404, 409))
|
||||||
def delete(self, req, server_id, id):
|
def delete(self, req, server_id, id):
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class ServerTagsController(wsgi.Controller):
|
|||||||
server_id)
|
server_id)
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.26")
|
@wsgi.api_version("2.26")
|
||||||
@wsgi.response(204)
|
@wsgi.response(204)
|
||||||
@wsgi.expected_errors(404)
|
@wsgi.expected_errors(404)
|
||||||
@validation.query_schema(schema.show_query)
|
@validation.query_schema(schema.show_query)
|
||||||
@@ -81,7 +81,7 @@ class ServerTagsController(wsgi.Controller):
|
|||||||
% {'server_id': server_id, 'tag': id})
|
% {'server_id': server_id, 'tag': id})
|
||||||
raise webob.exc.HTTPNotFound(explanation=msg)
|
raise webob.exc.HTTPNotFound(explanation=msg)
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.26")
|
@wsgi.api_version("2.26")
|
||||||
@wsgi.expected_errors(404)
|
@wsgi.expected_errors(404)
|
||||||
@validation.query_schema(schema.index_query)
|
@validation.query_schema(schema.index_query)
|
||||||
def index(self, req, server_id):
|
def index(self, req, server_id):
|
||||||
@@ -98,7 +98,7 @@ class ServerTagsController(wsgi.Controller):
|
|||||||
|
|
||||||
return {'tags': _get_tags_names(tags)}
|
return {'tags': _get_tags_names(tags)}
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.26")
|
@wsgi.api_version("2.26")
|
||||||
@wsgi.expected_errors((400, 404, 409))
|
@wsgi.expected_errors((400, 404, 409))
|
||||||
@validation.schema(schema.update)
|
@validation.schema(schema.update)
|
||||||
def update(self, req, server_id, id, body):
|
def update(self, req, server_id, id, body):
|
||||||
@@ -151,7 +151,7 @@ class ServerTagsController(wsgi.Controller):
|
|||||||
req, server_id, id)
|
req, server_id, id)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.26")
|
@wsgi.api_version("2.26")
|
||||||
@wsgi.expected_errors((404, 409))
|
@wsgi.expected_errors((404, 409))
|
||||||
@validation.schema(schema.update_all)
|
@validation.schema(schema.update_all)
|
||||||
def update_all(self, req, server_id, body):
|
def update_all(self, req, server_id, body):
|
||||||
@@ -176,7 +176,7 @@ class ServerTagsController(wsgi.Controller):
|
|||||||
|
|
||||||
return {'tags': _get_tags_names(tags)}
|
return {'tags': _get_tags_names(tags)}
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.26")
|
@wsgi.api_version("2.26")
|
||||||
@wsgi.response(204)
|
@wsgi.response(204)
|
||||||
@wsgi.expected_errors((404, 409))
|
@wsgi.expected_errors((404, 409))
|
||||||
def delete(self, req, server_id, id):
|
def delete(self, req, server_id, id):
|
||||||
@@ -201,7 +201,7 @@ class ServerTagsController(wsgi.Controller):
|
|||||||
notifications_base.send_instance_update_notification(
|
notifications_base.send_instance_update_notification(
|
||||||
context, instance, service="nova-api")
|
context, instance, service="nova-api")
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.26")
|
@wsgi.api_version("2.26")
|
||||||
@wsgi.response(204)
|
@wsgi.response(204)
|
||||||
@wsgi.expected_errors((404, 409))
|
@wsgi.expected_errors((404, 409))
|
||||||
def delete_all(self, req, server_id):
|
def delete_all(self, req, server_id):
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class ServerTopologyController(wsgi.Controller):
|
|||||||
super(ServerTopologyController, self).__init__(*args, **kwargs)
|
super(ServerTopologyController, self).__init__(*args, **kwargs)
|
||||||
self.compute_api = compute.API()
|
self.compute_api = compute.API()
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.78")
|
@wsgi.api_version("2.78")
|
||||||
@wsgi.expected_errors(404)
|
@wsgi.expected_errors(404)
|
||||||
@validation.query_schema(schema.query_params_v21)
|
@validation.query_schema(schema.query_params_v21)
|
||||||
def index(self, req, server_id):
|
def index(self, req, server_id):
|
||||||
|
|||||||
@@ -1502,7 +1502,7 @@ class ServersController(wsgi.Controller):
|
|||||||
state_error, 'stop', id
|
state_error, 'stop', id
|
||||||
)
|
)
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.17")
|
@wsgi.api_version("2.17")
|
||||||
@wsgi.response(202)
|
@wsgi.response(202)
|
||||||
@wsgi.expected_errors((400, 404, 409))
|
@wsgi.expected_errors((400, 404, 409))
|
||||||
@wsgi.action('trigger_crash_dump')
|
@wsgi.action('trigger_crash_dump')
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ class TenantNetworkController(wsgi.Controller):
|
|||||||
project_id=project_id)
|
project_id=project_id)
|
||||||
return self.network_api.get_all(ctx)
|
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(())
|
@wsgi.expected_errors(())
|
||||||
@validation.query_schema(schema.index_query)
|
@validation.query_schema(schema.index_query)
|
||||||
def index(self, req):
|
def index(self, req):
|
||||||
@@ -87,7 +87,7 @@ class TenantNetworkController(wsgi.Controller):
|
|||||||
networks.extend(self._default_networks)
|
networks.extend(self._default_networks)
|
||||||
return {'networks': [network_dict(n) for n in 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)
|
@wsgi.expected_errors(404)
|
||||||
@validation.query_schema(schema.show_query)
|
@validation.query_schema(schema.show_query)
|
||||||
def show(self, req, id):
|
def show(self, req, id):
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ class VolumeController(wsgi.Controller):
|
|||||||
super(VolumeController, self).__init__()
|
super(VolumeController, self).__init__()
|
||||||
self.volume_api = cinder.API()
|
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)
|
@wsgi.expected_errors(404)
|
||||||
@validation.query_schema(volumes_schema.show_query)
|
@validation.query_schema(volumes_schema.show_query)
|
||||||
def show(self, req, id):
|
def show(self, req, id):
|
||||||
@@ -125,7 +125,7 @@ class VolumeController(wsgi.Controller):
|
|||||||
|
|
||||||
return {'volume': _translate_volume_detail_view(context, vol)}
|
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.response(202)
|
||||||
@wsgi.expected_errors((400, 404))
|
@wsgi.expected_errors((400, 404))
|
||||||
def delete(self, req, id):
|
def delete(self, req, id):
|
||||||
@@ -141,7 +141,7 @@ class VolumeController(wsgi.Controller):
|
|||||||
except exception.VolumeNotFound as e:
|
except exception.VolumeNotFound as e:
|
||||||
raise exc.HTTPNotFound(explanation=e.format_message())
|
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(())
|
@wsgi.expected_errors(())
|
||||||
@validation.query_schema(volumes_schema.index_query)
|
@validation.query_schema(volumes_schema.index_query)
|
||||||
def index(self, req):
|
def index(self, req):
|
||||||
@@ -151,7 +151,7 @@ class VolumeController(wsgi.Controller):
|
|||||||
target={'project_id': context.project_id})
|
target={'project_id': context.project_id})
|
||||||
return self._items(req, entity_maker=_translate_volume_summary_view)
|
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(())
|
@wsgi.expected_errors(())
|
||||||
@validation.query_schema(volumes_schema.detail_query)
|
@validation.query_schema(volumes_schema.detail_query)
|
||||||
def detail(self, req):
|
def detail(self, req):
|
||||||
@@ -170,7 +170,7 @@ class VolumeController(wsgi.Controller):
|
|||||||
res = [entity_maker(context, vol) for vol in limited_list]
|
res = [entity_maker(context, vol) for vol in limited_list]
|
||||||
return {'volumes': res}
|
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))
|
@wsgi.expected_errors((400, 403, 404))
|
||||||
@validation.schema(volumes_schema.create)
|
@validation.schema(volumes_schema.create)
|
||||||
def create(self, req, body):
|
def create(self, req, body):
|
||||||
@@ -607,7 +607,7 @@ class SnapshotController(wsgi.Controller):
|
|||||||
self.volume_api = cinder.API()
|
self.volume_api = cinder.API()
|
||||||
super(SnapshotController, self).__init__()
|
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)
|
@wsgi.expected_errors(404)
|
||||||
@validation.query_schema(volumes_schema.snapshot_show_query)
|
@validation.query_schema(volumes_schema.snapshot_show_query)
|
||||||
def show(self, req, id):
|
def show(self, req, id):
|
||||||
@@ -623,7 +623,7 @@ class SnapshotController(wsgi.Controller):
|
|||||||
|
|
||||||
return {'snapshot': _translate_snapshot_detail_view(context, vol)}
|
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.response(202)
|
||||||
@wsgi.expected_errors(404)
|
@wsgi.expected_errors(404)
|
||||||
def delete(self, req, id):
|
def delete(self, req, id):
|
||||||
@@ -637,7 +637,7 @@ class SnapshotController(wsgi.Controller):
|
|||||||
except exception.SnapshotNotFound as e:
|
except exception.SnapshotNotFound as e:
|
||||||
raise exc.HTTPNotFound(explanation=e.format_message())
|
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(())
|
@wsgi.expected_errors(())
|
||||||
@validation.query_schema(volumes_schema.index_query)
|
@validation.query_schema(volumes_schema.index_query)
|
||||||
def index(self, req):
|
def index(self, req):
|
||||||
@@ -647,7 +647,7 @@ class SnapshotController(wsgi.Controller):
|
|||||||
target={'project_id': context.project_id})
|
target={'project_id': context.project_id})
|
||||||
return self._items(req, entity_maker=_translate_snapshot_summary_view)
|
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(())
|
@wsgi.expected_errors(())
|
||||||
@validation.query_schema(volumes_schema.detail_query)
|
@validation.query_schema(volumes_schema.detail_query)
|
||||||
def detail(self, req):
|
def detail(self, req):
|
||||||
@@ -666,7 +666,7 @@ class SnapshotController(wsgi.Controller):
|
|||||||
res = [entity_maker(context, snapshot) for snapshot in limited_list]
|
res = [entity_maker(context, snapshot) for snapshot in limited_list]
|
||||||
return {'snapshots': res}
|
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))
|
@wsgi.expected_errors((400, 403))
|
||||||
@validation.schema(volumes_schema.snapshot_create)
|
@validation.schema(volumes_schema.snapshot_create)
|
||||||
def create(self, req, body):
|
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
|
from oslo_utils import strutils
|
||||||
import webob
|
import webob
|
||||||
|
|
||||||
from nova.api.openstack import api_version_request as api_version
|
from nova.api.openstack import api_version_request
|
||||||
from nova.api.openstack import versioned_method
|
|
||||||
from nova.api import wsgi
|
from nova.api import wsgi
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import i18n
|
from nova import i18n
|
||||||
@@ -59,9 +58,6 @@ _METHODS_WITH_BODY = [
|
|||||||
# support is fully merged. It does not affect the V2 API.
|
# support is fully merged. It does not affect the V2 API.
|
||||||
DEFAULT_API_VERSION = "2.1"
|
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
|
# Names of headers used by clients to request a specific version
|
||||||
# of the REST API
|
# of the REST API
|
||||||
API_VERSION_REQUEST_HEADER = 'OpenStack-API-Version'
|
API_VERSION_REQUEST_HEADER = 'OpenStack-API-Version'
|
||||||
@@ -81,7 +77,7 @@ class Request(wsgi.Request):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(Request, self).__init__(*args, **kwargs)
|
super(Request, self).__init__(*args, **kwargs)
|
||||||
if not hasattr(self, 'api_version_request'):
|
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):
|
def best_match_content_type(self):
|
||||||
"""Determine the requested response content-type."""
|
"""Determine the requested response content-type."""
|
||||||
@@ -158,25 +154,25 @@ class Request(wsgi.Request):
|
|||||||
legacy_headers=[LEGACY_API_VERSION_REQUEST_HEADER])
|
legacy_headers=[LEGACY_API_VERSION_REQUEST_HEADER])
|
||||||
|
|
||||||
if hdr_string is None:
|
if hdr_string is None:
|
||||||
self.api_version_request = api_version.APIVersionRequest(
|
self.api_version_request = api_version_request.APIVersionRequest(
|
||||||
api_version.DEFAULT_API_VERSION)
|
api_version_request.DEFAULT_API_VERSION)
|
||||||
elif hdr_string == 'latest':
|
elif hdr_string == 'latest':
|
||||||
# 'latest' is a special keyword which is equivalent to
|
# 'latest' is a special keyword which is equivalent to
|
||||||
# requesting the maximum version of the API supported
|
# 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:
|
else:
|
||||||
self.api_version_request = api_version.APIVersionRequest(
|
self.api_version_request = api_version_request.APIVersionRequest(
|
||||||
hdr_string)
|
hdr_string)
|
||||||
|
|
||||||
# Check that the version requested is within the global
|
# Check that the version requested is within the global
|
||||||
# minimum/maximum of supported API versions
|
# minimum/maximum of supported API versions
|
||||||
if not self.api_version_request.matches(
|
if not self.api_version_request.matches(
|
||||||
api_version.min_api_version(),
|
api_version_request.min_api_version(),
|
||||||
api_version.max_api_version()):
|
api_version_request.max_api_version()):
|
||||||
raise exception.InvalidGlobalAPIVersion(
|
raise exception.InvalidGlobalAPIVersion(
|
||||||
req_ver=self.api_version_request.get_string(),
|
req_ver=self.api_version_request.get_string(),
|
||||||
min_ver=api_version.min_api_version().get_string(),
|
min_ver=api_version_request.min_api_version().get_string(),
|
||||||
max_ver=api_version.max_api_version().get_string())
|
max_ver=api_version_request.max_api_version().get_string())
|
||||||
|
|
||||||
def set_legacy_v2(self):
|
def set_legacy_v2(self):
|
||||||
self.environ[ENV_LEGACY_V2] = True
|
self.environ[ENV_LEGACY_V2] = True
|
||||||
@@ -243,8 +239,8 @@ class WSGICodes:
|
|||||||
ver = req.api_version_request
|
ver = req.api_version_request
|
||||||
|
|
||||||
for code, min_version, max_version in self._codes:
|
for code, min_version, max_version in self._codes:
|
||||||
min_ver = api_version.APIVersionRequest(min_version)
|
min_ver = api_version_request.APIVersionRequest(min_version)
|
||||||
max_ver = api_version.APIVersionRequest(max_version)
|
max_ver = api_version_request.APIVersionRequest(max_version)
|
||||||
if ver.matches(min_ver, max_ver):
|
if ver.matches(min_ver, max_ver):
|
||||||
return code
|
return code
|
||||||
|
|
||||||
@@ -700,6 +696,46 @@ def removed(version: str, reason: str):
|
|||||||
return decorator
|
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(
|
def expected_errors(
|
||||||
errors: ty.Union[int, tuple[int, ...]],
|
errors: ty.Union[int, tuple[int, ...]],
|
||||||
min_version: ty.Optional[str] = None,
|
min_version: ty.Optional[str] = None,
|
||||||
@@ -714,8 +750,8 @@ def expected_errors(
|
|||||||
def decorator(f):
|
def decorator(f):
|
||||||
@functools.wraps(f)
|
@functools.wraps(f)
|
||||||
def wrapped(*args, **kwargs):
|
def wrapped(*args, **kwargs):
|
||||||
min_ver = api_version.APIVersionRequest(min_version)
|
min_ver = api_version_request.APIVersionRequest(min_version)
|
||||||
max_ver = api_version.APIVersionRequest(max_version)
|
max_ver = api_version_request.APIVersionRequest(max_version)
|
||||||
|
|
||||||
# The request object is always the second argument.
|
# The request object is always the second argument.
|
||||||
# However numerous unittests pass in the request object
|
# However numerous unittests pass in the request object
|
||||||
@@ -791,36 +827,22 @@ class ControllerMetaclass(type):
|
|||||||
|
|
||||||
def __new__(mcs, name, bases, cls_dict):
|
def __new__(mcs, name, bases, cls_dict):
|
||||||
"""Adds the wsgi_actions dictionary to the class."""
|
"""Adds the wsgi_actions dictionary to the class."""
|
||||||
|
|
||||||
# Find all actions
|
# Find all actions
|
||||||
actions = {}
|
actions = {}
|
||||||
versioned_methods = None
|
|
||||||
# start with wsgi actions from base classes
|
# start with wsgi actions from base classes
|
||||||
for base in bases:
|
for base in bases:
|
||||||
actions.update(getattr(base, 'wsgi_actions', {}))
|
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():
|
for key, value in cls_dict.items():
|
||||||
if not callable(value):
|
if not callable(value):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if getattr(value, 'wsgi_action', None):
|
if getattr(value, 'wsgi_action', None):
|
||||||
actions[value.wsgi_action] = key
|
actions[value.wsgi_action] = key
|
||||||
|
|
||||||
# Add the actions to the class dict
|
# Add the actions to the class dict
|
||||||
cls_dict['wsgi_actions'] = actions
|
cls_dict['wsgi_actions'] = actions
|
||||||
if versioned_methods:
|
|
||||||
cls_dict[VER_METHOD_ATTR] = versioned_methods
|
|
||||||
|
|
||||||
return super(ControllerMetaclass, mcs).__new__(mcs, name, bases,
|
return super(ControllerMetaclass, mcs).__new__(mcs, name, bases,
|
||||||
cls_dict)
|
cls_dict)
|
||||||
|
|
||||||
@@ -837,103 +859,6 @@ class Controller(metaclass=ControllerMetaclass):
|
|||||||
else:
|
else:
|
||||||
self._view_builder = None
|
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
|
@staticmethod
|
||||||
def is_valid_body(body, entity_name):
|
def is_valid_body(body, entity_name):
|
||||||
if not (body and entity_name in body):
|
if not (body and entity_name in body):
|
||||||
@@ -948,36 +873,6 @@ class Controller(metaclass=ControllerMetaclass):
|
|||||||
|
|
||||||
return is_dict(body[entity_name])
|
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):
|
class Fault(webob.exc.HTTPException):
|
||||||
"""Wrap webob.exc.HTTPException to provide API friendly response."""
|
"""Wrap webob.exc.HTTPException to provide API friendly response."""
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import functools
|
|||||||
|
|
||||||
import webob
|
import webob
|
||||||
|
|
||||||
|
from nova.api.openstack import api_version_request
|
||||||
from nova.api.openstack.compute import routes
|
from nova.api.openstack.compute import routes
|
||||||
from nova.api.openstack import wsgi
|
from nova.api.openstack import wsgi
|
||||||
from nova.api import validation
|
from nova.api import validation
|
||||||
@@ -25,54 +26,50 @@ from nova.tests.unit.api.openstack.compute import dummy_schema
|
|||||||
|
|
||||||
class MicroversionsController(wsgi.Controller):
|
class MicroversionsController(wsgi.Controller):
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.1")
|
@wsgi.api_version("2.1")
|
||||||
def index(self, req):
|
def index(self, req):
|
||||||
data = {'param': 'val'}
|
if api_version_request.is_supported(req, '3.0'):
|
||||||
return data
|
raise webob.exc.HTTPBadRequest()
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.2") # noqa
|
if api_version_request.is_supported(req, '2.2'):
|
||||||
def index(self, req): # noqa
|
data = {'param': 'val2'}
|
||||||
data = {'param': 'val2'}
|
else:
|
||||||
|
data = {'param': 'val'}
|
||||||
return data
|
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
|
# We have a second example controller here to help check
|
||||||
# for accidental dependencies between API controllers
|
# for accidental dependencies between API controllers
|
||||||
# due to base class changes
|
# due to base class changes
|
||||||
class MicroversionsController2(wsgi.Controller):
|
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):
|
def index(self, req):
|
||||||
data = {'param': 'controller2_val1'}
|
if api_version_request.is_supported(req, '2.5'):
|
||||||
return data
|
data = {'param': 'controller2_val2'}
|
||||||
|
else:
|
||||||
@wsgi.Controller.api_version("2.5", "3.1") # noqa
|
data = {'param': 'controller2_val1'}
|
||||||
@wsgi.response(202)
|
|
||||||
def index(self, req): # noqa
|
|
||||||
data = {'param': 'controller2_val2'}
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
class MicroversionsController3(wsgi.Controller):
|
class MicroversionsController3(wsgi.Controller):
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.1")
|
@wsgi.api_version("2.1")
|
||||||
@validation.schema(dummy_schema.dummy)
|
@validation.schema(dummy_schema.dummy)
|
||||||
def create(self, req, body):
|
def create(self, req, body):
|
||||||
data = {'param': 'create_val1'}
|
data = {'param': 'create_val1'}
|
||||||
return data
|
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.dummy, "2.3", "2.8")
|
||||||
@validation.schema(dummy_schema.dummy2, "2.9")
|
@validation.schema(dummy_schema.dummy2, "2.9")
|
||||||
def update(self, req, id, body):
|
def update(self, req, id, body):
|
||||||
data = {'param': 'update_val1'}
|
data = {'param': 'update_val1'}
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@wsgi.Controller.api_version("2.1", "2.2")
|
@wsgi.api_version("2.1", "2.2")
|
||||||
@wsgi.response(202)
|
@wsgi.response(202)
|
||||||
@wsgi.action('foo')
|
@wsgi.action('foo')
|
||||||
def _foo(self, req, id, body):
|
def _foo(self, req, id, body):
|
||||||
@@ -80,24 +77,8 @@ class MicroversionsController3(wsgi.Controller):
|
|||||||
return data
|
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):
|
class MicroversionsExtendsBaseController(wsgi.Controller):
|
||||||
@wsgi.Controller.api_version("2.1")
|
@wsgi.api_version("2.1")
|
||||||
def show(self, req, id):
|
def show(self, req, id):
|
||||||
return {'base_param': 'base_val'}
|
return {'base_param': 'base_val'}
|
||||||
|
|
||||||
@@ -114,10 +95,6 @@ mv3_controller = functools.partial(routes._create_controller,
|
|||||||
MicroversionsController3, [])
|
MicroversionsController3, [])
|
||||||
|
|
||||||
|
|
||||||
mv4_controller = functools.partial(routes._create_controller,
|
|
||||||
MicroversionsController4, [])
|
|
||||||
|
|
||||||
|
|
||||||
mv5_controller = functools.partial(routes._create_controller,
|
mv5_controller = functools.partial(routes._create_controller,
|
||||||
MicroversionsExtendsBaseController, [])
|
MicroversionsExtendsBaseController, [])
|
||||||
|
|
||||||
@@ -138,9 +115,6 @@ ROUTES = (
|
|||||||
('/microversions3/{id}/action', {
|
('/microversions3/{id}/action', {
|
||||||
'POST': [mv3_controller, 'action']
|
'POST': [mv3_controller, 'action']
|
||||||
}),
|
}),
|
||||||
('/microversions4', {
|
|
||||||
'POST': [mv4_controller, 'create']
|
|
||||||
}),
|
|
||||||
('/microversions5/{id}', {
|
('/microversions5/{id}', {
|
||||||
'GET': [mv5_controller, 'show']
|
'GET': [mv5_controller, 'show']
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -72,8 +72,7 @@ class LegacyMicroversionsTest(test.NoDBTestCase):
|
|||||||
self.assertIn(self.header_name, res.headers.getall('Vary'))
|
self.assertIn(self.header_name, res.headers.getall('Vary'))
|
||||||
|
|
||||||
@mock.patch("nova.api.openstack.api_version_request.max_api_version")
|
@mock.patch("nova.api.openstack.api_version_request.max_api_version")
|
||||||
def test_microversions_return_header_non_default(self,
|
def test_microversions_return_header_non_default(self, mock_maxver):
|
||||||
mock_maxver):
|
|
||||||
mock_maxver.return_value = api_version.APIVersionRequest("2.3")
|
mock_maxver.return_value = api_version.APIVersionRequest("2.3")
|
||||||
|
|
||||||
req = fakes.HTTPRequest.blank(
|
req = fakes.HTTPRequest.blank(
|
||||||
@@ -255,31 +254,6 @@ class LegacyMicroversionsTest(test.NoDBTestCase):
|
|||||||
else:
|
else:
|
||||||
self.assertEqual("compute 2.10", res.headers[self.header_name])
|
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")
|
@mock.patch("nova.api.openstack.api_version_request.max_api_version")
|
||||||
def _test_microversions_actions(self, ret_code, ret_header, req_header,
|
def _test_microversions_actions(self, ret_code, ret_header, req_header,
|
||||||
mock_maxver):
|
mock_maxver):
|
||||||
|
|||||||
@@ -116,37 +116,12 @@ class SchemaTest(test.NoDBTestCase):
|
|||||||
wsgi_action, wsgi_method, action_controller
|
wsgi_action, wsgi_method, action_controller
|
||||||
) in wsgi_actions:
|
) in wsgi_actions:
|
||||||
func = controller.wsgi_actions[wsgi_action]
|
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
|
# method will always be POST for actions
|
||||||
_validate_func(func, method)
|
_validate_func(func, method)
|
||||||
else:
|
else:
|
||||||
# body validation
|
# body validation
|
||||||
versioned_methods = getattr(
|
func = getattr(controller.controller, action)
|
||||||
controller.controller, 'versioned_methods', {}
|
_validate_func(func, method)
|
||||||
)
|
|
||||||
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)
|
|
||||||
|
|
||||||
if missing_request_schemas:
|
if missing_request_schemas:
|
||||||
raise test.TestingException(
|
raise test.TestingException(
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import testscenarios
|
|||||||
import webob
|
import webob
|
||||||
|
|
||||||
from nova.api.openstack import api_version_request as api_version
|
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.api.openstack import wsgi
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import test
|
from nova import test
|
||||||
@@ -854,77 +853,42 @@ class ValidBodyTest(test.NoDBTestCase):
|
|||||||
self.assertFalse(self.controller.is_valid_body(body, 'foo'))
|
self.assertFalse(self.controller.is_valid_body(body, 'foo'))
|
||||||
|
|
||||||
|
|
||||||
class TestController(test.NoDBTestCase):
|
class APIVersionTestCase(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),
|
|
||||||
]
|
|
||||||
|
|
||||||
result = wsgi.Controller.check_for_versions_intersection(func_list=
|
def test_api_version(self):
|
||||||
func_list)
|
class FakeController(wsgi.Controller):
|
||||||
self.assertFalse(result)
|
@wsgi.api_version('2.10', '2.19')
|
||||||
|
def fake_func(self, req):
|
||||||
|
return {'resources': []}
|
||||||
|
|
||||||
func_list = \
|
controller = FakeController()
|
||||||
[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)
|
|
||||||
]
|
|
||||||
|
|
||||||
result = wsgi.Controller.check_for_versions_intersection(func_list=
|
req = fakes.HTTPRequest.blank('', version='2.10')
|
||||||
func_list)
|
self.assertEqual({'resources': []}, controller.fake_func(req))
|
||||||
self.assertFalse(result)
|
|
||||||
|
|
||||||
def test_check_for_versions_intersection_positive(self):
|
req = fakes.HTTPRequest.blank('', version='2.19')
|
||||||
func_list = \
|
self.assertEqual({'resources': []}, controller.fake_func(req))
|
||||||
[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),
|
|
||||||
]
|
|
||||||
|
|
||||||
result = wsgi.Controller.check_for_versions_intersection(func_list=
|
req = fakes.HTTPRequest.blank('', version='2.9')
|
||||||
func_list)
|
self.assertRaises(
|
||||||
self.assertTrue(result)
|
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):
|
class ExpectedErrorTestCase(test.NoDBTestCase):
|
||||||
|
|||||||
Reference in New Issue
Block a user