Merge "api: Deprecate os-volumes_boot API"

This commit is contained in:
Zuul
2026-03-01 03:18:06 +00:00
committed by Gerrit Code Review
9 changed files with 330 additions and 20 deletions

View File

@@ -19,7 +19,7 @@
}
],
"status": "CURRENT",
"version": "2.102",
"version": "2.103",
"min_version": "2.1",
"updated": "2013-07-23T11:33:21Z"
}

View File

@@ -22,7 +22,7 @@
}
],
"status": "CURRENT",
"version": "2.102",
"version": "2.103",
"min_version": "2.1",
"updated": "2013-07-23T11:33:21Z"
}

View File

@@ -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

View File

@@ -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.

View File

@@ -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'],

View File

@@ -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)

View File

@@ -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'

View File

@@ -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={},
)

View File

@@ -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.