diff --git a/doc/api_samples/versions/v21-version-get-resp.json b/doc/api_samples/versions/v21-version-get-resp.json index c065f1ecd669..5dc60e1e9f7c 100644 --- a/doc/api_samples/versions/v21-version-get-resp.json +++ b/doc/api_samples/versions/v21-version-get-resp.json @@ -19,7 +19,7 @@ } ], "status": "CURRENT", - "version": "2.102", + "version": "2.103", "min_version": "2.1", "updated": "2013-07-23T11:33:21Z" } diff --git a/doc/api_samples/versions/versions-get-resp.json b/doc/api_samples/versions/versions-get-resp.json index e66f5c3f6599..5f04e06f3048 100644 --- a/doc/api_samples/versions/versions-get-resp.json +++ b/doc/api_samples/versions/versions-get-resp.json @@ -22,7 +22,7 @@ } ], "status": "CURRENT", - "version": "2.102", + "version": "2.103", "min_version": "2.1", "updated": "2013-07-23T11:33:21Z" } diff --git a/nova/api/openstack/api_version_request.py b/nova/api/openstack/api_version_request.py index 35e2aaae5dff..fa52df755626 100644 --- a/nova/api/openstack/api_version_request.py +++ b/nova/api/openstack/api_version_request.py @@ -285,6 +285,7 @@ REST_API_VERSION_HISTORY = """REST API Version History: ``rxtx_factor`` and ``OS-FLV-DISABLED:disabled`` fields and filters from various flavors APIs and restrict additional query string parameters for all APIs. + * 2.103 - Remove the ``/os-volumes_boot`` API """ # The minimum and maximum versions of the API supported @@ -293,7 +294,7 @@ REST_API_VERSION_HISTORY = """REST API Version History: # Note(cyeoh): This only applies for the v2.1 API once microversions # support is fully merged. It does not affect the V2 API. _MIN_API_VERSION = '2.1' -_MAX_API_VERSION = '2.102' +_MAX_API_VERSION = '2.103' DEFAULT_API_VERSION = _MIN_API_VERSION # Almost all proxy APIs which are related to network, images and baremetal diff --git a/nova/api/openstack/compute/rest_api_version_history.rst b/nova/api/openstack/compute/rest_api_version_history.rst index d0566be0b010..9ac970c611ac 100644 --- a/nova/api/openstack/compute/rest_api_version_history.rst +++ b/nova/api/openstack/compute/rest_api_version_history.rst @@ -1315,8 +1315,8 @@ volume-attachment process finished. .. _microversion 2.102: -2.102 (Maximum in 2026.1 Gazpacho) ----------------------------------- +2.102 +----- The ``GET /flavors`` API now accepts a ``name`` filter to filter the returned flavors by name. In addition, the ``rxtx_factor`` and @@ -1326,3 +1326,12 @@ creating a server and the ``rxtx_factor`` filter can no longer be provided when listing flavors. Finally, all APIs now reject unknown query string parameters with a HTTP 400 (Bad Request) error, building upon work first started in microversion 2.75. + +.. _microversion 2.103: + +2.103 (Maximum in 2026.1 Gazpacho) +---------------------------------- + +The ``/os-volumes_boot`` API is an old alias for the ``/servers`` API and was +undocumented and untested. It has now been removed and will return HTTP 404 for +all requests. diff --git a/nova/api/openstack/compute/routes.py b/nova/api/openstack/compute/routes.py index 5c7da53c8d8d..631c1abfa963 100644 --- a/nova/api/openstack/compute/routes.py +++ b/nova/api/openstack/compute/routes.py @@ -86,6 +86,7 @@ from nova.api.openstack.compute import versionsV21 from nova.api.openstack.compute import virtual_interfaces from nova.api.openstack.compute import volume_attachments from nova.api.openstack.compute import volumes +from nova.api.openstack.compute import volumes_boot from nova.api.openstack import wsgi from nova.api import wsgi as base_wsgi @@ -354,6 +355,10 @@ volumes_controller = functools.partial(_create_controller, volumes.VolumeController, []) +volumes_boot_controller = functools.partial( + _create_controller, volumes_boot.VolumesBootController, []) + + # NOTE(alex_xu): This is structure of this route list as below: # ( # ('Route path', { @@ -725,22 +730,20 @@ ROUTE_LIST = ( 'GET': [volumes_controller, 'show'], 'DELETE': [volumes_controller, 'delete'] }), - # NOTE: '/os-volumes_boot' is a clone of '/servers'. We may want to - # deprecate it in the future. ('/os-volumes_boot', { - 'GET': [server_controller, 'index'], - 'POST': [server_controller, 'create'] + 'GET': [volumes_boot_controller, 'index'], + 'POST': [volumes_boot_controller, 'create'] }), ('/os-volumes_boot/detail', { - 'GET': [server_controller, 'detail'] + 'GET': [volumes_boot_controller, 'detail'] }), ('/os-volumes_boot/{id}', { - 'GET': [server_controller, 'show'], - 'PUT': [server_controller, 'update'], - 'DELETE': [server_controller, 'delete'] + 'GET': [volumes_boot_controller, 'show'], + 'PUT': [volumes_boot_controller, 'update'], + 'DELETE': [volumes_boot_controller, 'delete'] }), ('/os-volumes_boot/{id}/action', { - 'POST': [server_controller, 'action'] + 'POST': [volumes_boot_controller, 'action'] }), ('/servers', { 'GET': [server_controller, 'index'], diff --git a/nova/api/openstack/compute/volumes_boot.py b/nova/api/openstack/compute/volumes_boot.py new file mode 100644 index 000000000000..b3333cf2a0a1 --- /dev/null +++ b/nova/api/openstack/compute/volumes_boot.py @@ -0,0 +1,231 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from nova.api.openstack.compute.schemas import servers as schema +from nova.api.openstack.compute import servers +from nova.api.openstack import wsgi +from nova.api import validation + + +class VolumesBootController(servers.ServersController): + """This API is deprecated from microversion '2.103'.""" + + @wsgi.api_version('2.1', '2.102') + @wsgi.expected_errors((400, 403)) + @validation.query_schema(schema.index_query, '2.1', '2.25') + @validation.query_schema(schema.index_query_v226, '2.26', '2.65') + @validation.query_schema(schema.index_query_v266, '2.66', '2.72') + @validation.query_schema(schema.index_query_v273, '2.73', '2.74') + @validation.query_schema(schema.index_query_v275, '2.75') + @validation.response_body_schema(schema.index_response, '2.1', '2.68') + @validation.response_body_schema(schema.index_response_v269, '2.69') + def index(self, req): + return super().index(req) + + @wsgi.api_version('2.1', '2.102') + @wsgi.expected_errors((400, 403)) + @validation.query_schema(schema.index_query, '2.1', '2.25') + @validation.query_schema(schema.index_query_v226, '2.26', '2.65') + @validation.query_schema(schema.index_query_v266, '2.66', '2.72') + @validation.query_schema(schema.index_query_v273, '2.73', '2.74') + @validation.query_schema(schema.index_query_v275, '2.75') + @validation.response_body_schema(schema.detail_response, '2.1', '2.2') + @validation.response_body_schema(schema.detail_response_v23, '2.3', '2.8') + @validation.response_body_schema(schema.detail_response_v29, '2.9', '2.15') + @validation.response_body_schema(schema.detail_response_v216, '2.16', '2.18') # noqa: E501 + @validation.response_body_schema(schema.detail_response_v219, '2.19', '2.25') # noqa: E501 + @validation.response_body_schema(schema.detail_response_v226, '2.26', '2.46') # noqa: E501 + @validation.response_body_schema(schema.detail_response_v247, '2.47', '2.62') # noqa: E501 + @validation.response_body_schema(schema.detail_response_v263, '2.63', '2.68') # noqa: E501 + @validation.response_body_schema(schema.detail_response_v269, '2.69', '2.72') # noqa: E501 + @validation.response_body_schema(schema.detail_response_v273, '2.73', '2.89') # noqa: E501 + @validation.response_body_schema(schema.detail_response_v290, '2.90', '2.95') # noqa: E501 + @validation.response_body_schema(schema.detail_response_v296, '2.96', '2.97') # noqa: E501 + @validation.response_body_schema(schema.detail_response_v298, '2.98', '2.99') # noqa: E501 + @validation.response_body_schema(schema.detail_response_v2100, '2.100') + def detail(self, req): + return super().detail(req) + + @wsgi.api_version('2.1', '2.102') + @wsgi.expected_errors(404) + @validation.query_schema(schema.show_query, '2.1', '2.101') + @validation.query_schema(schema.show_query_v2102, '2.102') + @validation.response_body_schema(schema.show_response, '2.0', '2.2') + @validation.response_body_schema(schema.show_response_v23, '2.3', '2.8') + @validation.response_body_schema(schema.show_response_v29, '2.9', '2.15') + @validation.response_body_schema(schema.show_response_v216, '2.16', '2.18') + @validation.response_body_schema(schema.show_response_v219, '2.19', '2.25') + @validation.response_body_schema(schema.show_response_v226, '2.26', '2.46') + @validation.response_body_schema(schema.show_response_v247, '2.47', '2.62') + @validation.response_body_schema(schema.show_response_v263, '2.63', '2.68') + @validation.response_body_schema(schema.show_response_v269, '2.69', '2.70') + @validation.response_body_schema(schema.show_response_v271, '2.71', '2.72') + @validation.response_body_schema(schema.show_response_v273, '2.73', '2.89') + @validation.response_body_schema(schema.show_response_v290, '2.90', '2.95') + @validation.response_body_schema(schema.show_response_v296, '2.96', '2.97') + @validation.response_body_schema(schema.show_response_v298, '2.98', '2.99') + @validation.response_body_schema(schema.show_response_v2100, '2.100') + def show(self, req, id): + return super().show(req, id) + + @wsgi.api_version('2.1', '2.102') + @wsgi.response(202) + @wsgi.expected_errors((400, 403, 409)) + @validation.schema(schema.create_v20, '2.0', '2.0') + @validation.schema(schema.create, '2.1', '2.18') + @validation.schema(schema.create_v219, '2.19', '2.31') + @validation.schema(schema.create_v232, '2.32', '2.32') + @validation.schema(schema.create_v233, '2.33', '2.36') + @validation.schema(schema.create_v237, '2.37', '2.41') + @validation.schema(schema.create_v242, '2.42', '2.51') + @validation.schema(schema.create_v252, '2.52', '2.56') + @validation.schema(schema.create_v257, '2.57', '2.62') + @validation.schema(schema.create_v263, '2.63', '2.66') + @validation.schema(schema.create_v267, '2.67', '2.73') + @validation.schema(schema.create_v274, '2.74', '2.89') + @validation.schema(schema.create_v290, '2.90', '2.93') + @validation.schema(schema.create_v294, '2.94') + @validation.response_body_schema(schema.create_response) + def create(self, req, body): + return super().create(req, body) + + @wsgi.api_version('2.1', '2.102') + @wsgi.response(204) + @wsgi.expected_errors((404, 409)) + @validation.response_body_schema(schema.delete_response) + def delete(self, req, id): + return super().delete(req, id) + + @wsgi.api_version('2.1', '2.102') + @wsgi.expected_errors(404) + @validation.schema(schema.update_v20, '2.0', '2.0') + @validation.schema(schema.update, '2.1', '2.18') + @validation.schema(schema.update_v219, '2.19', '2.89') + @validation.schema(schema.update_v290, '2.90', '2.93') + @validation.schema(schema.update_v294, '2.94') + @validation.response_body_schema(schema.update_response, '2.0', '2.8') + @validation.response_body_schema(schema.update_response_v29, '2.9', '2.18') + @validation.response_body_schema(schema.update_response_v219, '2.19', '2.25') # noqa: E501 + @validation.response_body_schema(schema.update_response_v226, '2.26', '2.46') # noqa: E501 + @validation.response_body_schema(schema.update_response_v247, '2.47', '2.62') # noqa: E501 + @validation.response_body_schema(schema.update_response_v263, '2.63', '2.70') # noqa: E501 + @validation.response_body_schema(schema.update_response_v271, '2.71', '2.72') # noqa: E501 + @validation.response_body_schema(schema.update_response_v273, '2.73', '2.74') # noqa: E501 + @validation.response_body_schema(schema.update_response_v275, '2.75', '2.95') # noqa: E501 + @validation.response_body_schema(schema.update_response_v296, '2.96', '2.97') # noqa: E501 + @validation.response_body_schema(schema.update_response_v298, '2.98', '2.99') # noqa: E501 + @validation.response_body_schema(schema.update_response_v2100, '2.100') + def update(self, req, id, body): + return super().update(req, id) + + @wsgi.api_version('2.1', '2.102') + @wsgi.response(204) + @wsgi.expected_errors((400, 404, 409)) + @wsgi.action('confirmResize') + @validation.schema(schema.confirm_resize) + @validation.response_body_schema(schema.confirm_resize_response) + def _confirm_resize(self, req, id, body): + return super()._confirm_resize(req, id, body) + + @wsgi.api_version('2.1', '2.102') + @wsgi.response(202) + @wsgi.expected_errors((400, 404, 409)) + @wsgi.action('revertResize') + @validation.schema(schema.revert_resize) + @validation.response_body_schema(schema.revert_resize_response) + def _revert_resize(self, req, id, body): + return super()._revert_resize(req, id, body) + + @wsgi.api_version('2.1', '2.102') + @wsgi.response(202) + @wsgi.expected_errors((404, 409)) + @wsgi.action('reboot') + @validation.schema(schema.reboot) + @validation.response_body_schema(schema.reboot_response) + def _reboot(self, req, id, body): + return super()._reboot(req, id, body) + + @wsgi.api_version('2.1', '2.102') + @wsgi.response(202) + @wsgi.expected_errors((400, 401, 403, 404, 409)) + @wsgi.action('resize') + @validation.schema(schema.resize) + @validation.response_body_schema(schema.resize_response) + def _resize(self, req, id, body): + return super()._resize(req, id, body) + + @wsgi.api_version('2.1', '2.102') + @wsgi.response(202) + @wsgi.expected_errors((400, 403, 404, 409)) + @wsgi.action('rebuild') + @validation.schema(schema.rebuild_v20, '2.0', '2.0') + @validation.schema(schema.rebuild, '2.1', '2.18') + @validation.schema(schema.rebuild_v219, '2.19', '2.53') + @validation.schema(schema.rebuild_v254, '2.54', '2.56') + @validation.schema(schema.rebuild_v257, '2.57', '2.62') + @validation.schema(schema.rebuild_v263, '2.63', '2.89') + @validation.schema(schema.rebuild_v290, '2.90', '2.93') + @validation.schema(schema.rebuild_v294, '2.94') + @validation.response_body_schema(schema.rebuild_response, '2.0', '2.8') + @validation.response_body_schema(schema.rebuild_response_v29, '2.9', '2.18') # noqa: E501 + @validation.response_body_schema(schema.rebuild_response_v219, '2.19', '2.25') # noqa: E501 + @validation.response_body_schema(schema.rebuild_response_v226, '2.26', '2.46') # noqa: E501 + @validation.response_body_schema(schema.rebuild_response_v247, '2.47', '2.53') # noqa: E501 + @validation.response_body_schema(schema.rebuild_response_v254, '2.54', '2.56') # noqa: E501 + @validation.response_body_schema(schema.rebuild_response_v257, '2.57', '2.62') # noqa: E501 + @validation.response_body_schema(schema.rebuild_response_v263, '2.63', '2.70') # noqa: E501 + @validation.response_body_schema(schema.rebuild_response_v271, '2.71', '2.72') # noqa: E501 + @validation.response_body_schema(schema.rebuild_response_v273, '2.73', '2.74') # noqa: E501 + @validation.response_body_schema(schema.rebuild_response_v275, '2.75', '2.95') # noqa: E501 + @validation.response_body_schema(schema.rebuild_response_v296, '2.96', '2.97') # noqa: E501 + @validation.response_body_schema(schema.rebuild_response_v298, '2.98', '2.99') # noqa: E501 + @validation.response_body_schema(schema.rebuild_response_v2100, '2.100') + def _rebuild(self, req, id, body): + return super()._rebuild(req, id, body) + + @wsgi.api_version('2.1', '2.102') + @wsgi.response(202) + @wsgi.expected_errors((400, 403, 404, 409)) + @wsgi.action('createImage') + @validation.schema(schema.create_image, '2.0', '2.0') + @validation.schema(schema.create_image, '2.1') + @validation.response_body_schema(schema.create_image_response, '2.0', '2.44') # noqa: E501 + @validation.response_body_schema(schema.create_image_response_v245, '2.45') + def _create_image(self, req, id, body): + return super()._create_image(req, id, body) + + @wsgi.api_version('2.1', '2.102') + @wsgi.response(202) + @wsgi.expected_errors((404, 409)) + @wsgi.action('os-start') + @validation.schema(schema.start_server) + @validation.response_body_schema(schema.start_server_response) + def _start(self, req, id, body): + return super()._start(req, id, body) + + @wsgi.api_version('2.1', '2.102') + @wsgi.response(202) + @wsgi.expected_errors((404, 409)) + @wsgi.action('os-stop') + @validation.schema(schema.stop_server) + @validation.response_body_schema(schema.stop_server_response) + def _stop(self, req, id, body): + return super()._stop(req, id, body) + + @wsgi.api_version('2.17', '2.102') + @wsgi.response(202) + @wsgi.expected_errors((400, 404, 409)) + @wsgi.action('trigger_crash_dump') + @validation.schema(schema.trigger_crash_dump) + @validation.response_body_schema(schema.trigger_crash_dump_response) + def _trigger_crash_dump(self, req, id, body): + return super()._trigger_crash_dump(req, id, body) diff --git a/nova/tests/unit/api/openstack/compute/test_volumes.py b/nova/tests/unit/api/openstack/compute/test_volumes.py index e01e7ca396b9..1ae147138d89 100644 --- a/nova/tests/unit/api/openstack/compute/test_volumes.py +++ b/nova/tests/unit/api/openstack/compute/test_volumes.py @@ -77,8 +77,7 @@ class BootFromVolumeTest(test.TestCase): delete_on_termination=False, )] )) - # FIXME(stephenfin): Use /servers instead? - req = fakes.HTTPRequest.blank('/v2.1/os-volumes_boot') + req = fakes.HTTPRequest.blank('/v2.1/servers') req.method = 'POST' req.body = jsonutils.dump_as_bytes(body) req.headers['content-type'] = 'application/json' @@ -106,8 +105,7 @@ class BootFromVolumeTest(test.TestCase): delete_on_termination=False, )] )) - # FIXME(stephenfin): Use /servers instead? - req = fakes.HTTPRequest.blank('/v2.1/os-volumes_boot') + req = fakes.HTTPRequest.blank('/v2.1/servers') req.method = 'POST' req.body = jsonutils.dump_as_bytes(body) req.headers['content-type'] = 'application/json' @@ -140,8 +138,7 @@ class BootFromVolumeTest(test.TestCase): delete_on_termination=False, )] )) - req = fakes.HTTPRequest.blank('/v2/%s/os-volumes_boot' % - fakes.FAKE_PROJECT_ID) + req = fakes.HTTPRequest.blank('/v2/servers') req.method = 'POST' req.body = jsonutils.dump_as_bytes(body) req.headers['content-type'] = 'application/json' diff --git a/nova/tests/unit/api/openstack/compute/test_volumes_boot.py b/nova/tests/unit/api/openstack/compute/test_volumes_boot.py new file mode 100644 index 000000000000..e72528e2a937 --- /dev/null +++ b/nova/tests/unit/api/openstack/compute/test_volumes_boot.py @@ -0,0 +1,63 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from nova.api.openstack.compute import volumes_boot +from nova import exception +from nova import test +from nova.tests.unit.api.openstack import fakes + + +class VolumesBootControllerDeprecationTest(test.NoDBTestCase): + + def setUp(self): + super().setUp() + self.controller = volumes_boot.VolumesBootController() + self.req = fakes.HTTPRequest.blank('', version='2.103') + + def test_not_found(self): + for method in ( + self.controller.index, + self.controller.detail, + ): + self.assertRaises( + exception.VersionNotFoundForAPIMethod, method, self.req + ) + + for method in ( + self.controller.show, + self.controller.delete, + ): + self.assertRaises( + exception.VersionNotFoundForAPIMethod, method, self.req, 123 + ) + + for method in ( + self.controller.update, + self.controller._confirm_resize, + self.controller._revert_resize, + self.controller._reboot, + self.controller._resize, + self.controller._rebuild, + self.controller._create_image, + self.controller._start, + self.controller._stop, + self.controller._trigger_crash_dump, + ): + self.assertRaises( + exception.VersionNotFoundForAPIMethod, + method, + self.req, + 123, + # intentionally incomplete body since version validation + # happens before schema validation + body={}, + ) diff --git a/releasenotes/notes/remove-os-volumes_boot-api-861809a0b33845ba.yaml b/releasenotes/notes/remove-os-volumes_boot-api-861809a0b33845ba.yaml new file mode 100644 index 000000000000..0c20a7584da7 --- /dev/null +++ b/releasenotes/notes/remove-os-volumes_boot-api-861809a0b33845ba.yaml @@ -0,0 +1,6 @@ +--- +upgrade: + - | + The v2.103 microversion has been introduced. This deprecates the hitherto + undocumented ``/os-volumes_boot`` API. HTTP 404 will be returned for all + requests starting with this API microversion.