From b95a2c5219b75bb5879b338c475428311f3e1d09 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 20 Jun 2025 15:10:19 +0100 Subject: [PATCH] api: Remove dead fields from flavors response Change-Id: I65be4f2e522c9f73a28b8837d7937a371d3e73d3 Signed-off-by: Stephen Finucane --- api-ref/source/flavors.inc | 21 ++- api-ref/source/parameters.yaml | 3 + .../v2.102/flavor-create-post-req.json | 10 ++ .../v2.102/flavor-create-post-resp.json | 24 +++ .../v2.102/flavor-update-req.json | 5 + .../v2.102/flavor-update-resp.json | 24 +++ .../flavors/v2.102/flavor-get-resp.json | 27 +++ .../flavors/v2.102/flavors-detail-resp.json | 163 ++++++++++++++++++ .../flavors/v2.102/flavors-list-resp.json | 109 ++++++++++++ nova/api/openstack/api_version_request.py | 4 +- nova/api/openstack/compute/flavors.py | 15 +- nova/api/openstack/compute/schemas/flavors.py | 25 ++- nova/api/openstack/compute/views/flavors.py | 4 + .../v2.102/flavor-create-post-req.json.tpl | 10 ++ .../v2.102/flavor-create-post-resp.json.tpl | 24 +++ .../v2.102/flavor-update-req.json.tpl | 5 + .../v2.102/flavor-update-resp.json.tpl | 24 +++ .../flavors/v2.102/flavor-get-resp.json.tpl | 27 +++ .../v2.102/flavors-detail-resp.json.tpl | 163 ++++++++++++++++++ .../flavors/v2.102/flavors-list-resp.json.tpl | 109 ++++++++++++ .../api_sample_tests/test_flavor_manage.py | 9 +- .../api_sample_tests/test_flavors.py | 18 +- nova/tests/functional/integrated_helpers.py | 12 +- .../notification_sample_tests/test_flavor.py | 2 + .../api/openstack/compute/test_flavors.py | 22 ++- .../flavor-name-search-4133a0788bd1c37f.yaml | 4 + tox.ini | 3 + 27 files changed, 831 insertions(+), 35 deletions(-) create mode 100644 doc/api_samples/flavor-manage/v2.102/flavor-create-post-req.json create mode 100644 doc/api_samples/flavor-manage/v2.102/flavor-create-post-resp.json create mode 100644 doc/api_samples/flavor-manage/v2.102/flavor-update-req.json create mode 100644 doc/api_samples/flavor-manage/v2.102/flavor-update-resp.json create mode 100644 doc/api_samples/flavors/v2.102/flavor-get-resp.json create mode 100644 doc/api_samples/flavors/v2.102/flavors-detail-resp.json create mode 100644 doc/api_samples/flavors/v2.102/flavors-list-resp.json create mode 100644 nova/tests/functional/api_sample_tests/api_samples/flavor-manage/v2.102/flavor-create-post-req.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/flavor-manage/v2.102/flavor-create-post-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/flavor-manage/v2.102/flavor-update-req.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/flavor-manage/v2.102/flavor-update-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/flavors/v2.102/flavor-get-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/flavors/v2.102/flavors-detail-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/flavors/v2.102/flavors-list-resp.json.tpl diff --git a/api-ref/source/flavors.inc b/api-ref/source/flavors.inc index bea4d4ca3e..a2bf639c23 100644 --- a/api-ref/source/flavors.inc +++ b/api-ref/source/flavors.inc @@ -46,9 +46,9 @@ Response - description: flavor_description_resp - links: links -**Example List Flavors (v2.55)** +**Example List Flavors (v2.102)** -.. literalinclude:: ../../doc/api_samples/flavors/v2.55/flavors-list-resp.json +.. literalinclude:: ../../doc/api_samples/flavors/v2.102/flavors-list-resp.json :language: javascript Create Flavor @@ -92,9 +92,9 @@ Request - rxtx_factor: flavor_rxtx_factor_in - os-flavor-access:is_public: flavor_is_public_in -**Example Create Flavor (v2.55)** +**Example Create Flavor (v2.102)** -.. literalinclude:: ../../doc/api_samples/flavor-manage/v2.55/flavor-create-post-req.json +.. literalinclude:: ../../doc/api_samples/flavor-manage/v2.102/flavor-create-post-req.json :language: javascript Response @@ -117,10 +117,9 @@ Response - os-flavor-access:is_public: flavor_is_public - extra_specs: extra_specs_2_61 +**Example Create Flavor (v2.102)** -**Example Create Flavor (v2.75)** - -.. literalinclude:: ../../doc/api_samples/flavor-manage/v2.75/flavor-create-post-resp.json +.. literalinclude:: ../../doc/api_samples/flavor-manage/v2.102/flavor-create-post-resp.json :language: javascript List Flavors With Details @@ -168,9 +167,9 @@ Response - os-flavor-access:is_public: flavor_is_public - extra_specs: extra_specs_2_61 -**Example List Flavors With Details (v2.75)** +**Example List Flavors With Details (v2.102)** -.. literalinclude:: ../../doc/api_samples/flavors/v2.75/flavors-detail-resp.json +.. literalinclude:: ../../doc/api_samples/flavors/v2.102/flavors-detail-resp.json :language: javascript Show Flavor Details @@ -211,9 +210,9 @@ Response - os-flavor-access:is_public: flavor_is_public - extra_specs: extra_specs_2_61 -**Example Show Flavor Details (v2.75)** +**Example Show Flavor Details (v2.102)** -.. literalinclude:: ../../doc/api_samples/flavors/v2.75/flavor-get-resp.json +.. literalinclude:: ../../doc/api_samples/flavors/v2.102/flavor-get-resp.json :language: javascript Update Flavor Description diff --git a/api-ref/source/parameters.yaml b/api-ref/source/parameters.yaml index edbf3c2cf3..9a23f96dbd 100644 --- a/api-ref/source/parameters.yaml +++ b/api-ref/source/parameters.yaml @@ -3059,6 +3059,7 @@ flavor_disabled: This is an artifact of the legacy v2 API and will always be set to ``false``. There is currently no way to disable a flavor and set this to ``true``. + max_version: 2.101 flavor_disk: in: body required: true @@ -3221,6 +3222,7 @@ flavor_rxtx_factor: in: body required: true type: float + max_version: 2.101 flavor_rxtx_factor_in: description: | The receive / transmit factor (as a float) that will be set on @@ -3229,6 +3231,7 @@ flavor_rxtx_factor_in: in: body required: false type: float + max_version: 2.101 flavor_server: description: | Before microversion 2.47 this contains the ID and links for the flavor diff --git a/doc/api_samples/flavor-manage/v2.102/flavor-create-post-req.json b/doc/api_samples/flavor-manage/v2.102/flavor-create-post-req.json new file mode 100644 index 0000000000..ba0251e733 --- /dev/null +++ b/doc/api_samples/flavor-manage/v2.102/flavor-create-post-req.json @@ -0,0 +1,10 @@ +{ + "flavor": { + "name": "test_flavor", + "ram": 1024, + "vcpus": 2, + "disk": 10, + "id": "10", + "description": "test description" + } +} \ No newline at end of file diff --git a/doc/api_samples/flavor-manage/v2.102/flavor-create-post-resp.json b/doc/api_samples/flavor-manage/v2.102/flavor-create-post-resp.json new file mode 100644 index 0000000000..2661195630 --- /dev/null +++ b/doc/api_samples/flavor-manage/v2.102/flavor-create-post-resp.json @@ -0,0 +1,24 @@ +{ + "flavor": { + "OS-FLV-EXT-DATA:ephemeral": 0, + "description": "test description", + "disk": 10, + "extra_specs": {}, + "id": "10", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/10", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/10", + "rel": "bookmark" + } + ], + "name": "test_flavor", + "os-flavor-access:is_public": true, + "ram": 1024, + "swap": 0, + "vcpus": 2 + } +} \ No newline at end of file diff --git a/doc/api_samples/flavor-manage/v2.102/flavor-update-req.json b/doc/api_samples/flavor-manage/v2.102/flavor-update-req.json new file mode 100644 index 0000000000..89678a5267 --- /dev/null +++ b/doc/api_samples/flavor-manage/v2.102/flavor-update-req.json @@ -0,0 +1,5 @@ +{ + "flavor": { + "description": "updated description" + } +} \ No newline at end of file diff --git a/doc/api_samples/flavor-manage/v2.102/flavor-update-resp.json b/doc/api_samples/flavor-manage/v2.102/flavor-update-resp.json new file mode 100644 index 0000000000..bc6b8ea463 --- /dev/null +++ b/doc/api_samples/flavor-manage/v2.102/flavor-update-resp.json @@ -0,0 +1,24 @@ +{ + "flavor": { + "OS-FLV-EXT-DATA:ephemeral": 0, + "description": "updated description", + "disk": 1, + "extra_specs": {}, + "id": "1", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/1", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/1", + "rel": "bookmark" + } + ], + "name": "m1.tiny", + "os-flavor-access:is_public": true, + "ram": 512, + "swap": 0, + "vcpus": 1 + } +} \ No newline at end of file diff --git a/doc/api_samples/flavors/v2.102/flavor-get-resp.json b/doc/api_samples/flavors/v2.102/flavor-get-resp.json new file mode 100644 index 0000000000..d854a1faac --- /dev/null +++ b/doc/api_samples/flavors/v2.102/flavor-get-resp.json @@ -0,0 +1,27 @@ +{ + "flavor": { + "OS-FLV-EXT-DATA:ephemeral": 0, + "description": "test description", + "disk": 20, + "extra_specs": { + "hw:cpu_policy": "shared", + "hw:numa_nodes": "1" + }, + "id": "7", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/7", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/7", + "rel": "bookmark" + } + ], + "name": "m1.small.description", + "os-flavor-access:is_public": true, + "ram": 2048, + "swap": 0, + "vcpus": 1 + } +} \ No newline at end of file diff --git a/doc/api_samples/flavors/v2.102/flavors-detail-resp.json b/doc/api_samples/flavors/v2.102/flavors-detail-resp.json new file mode 100644 index 0000000000..25503f61bb --- /dev/null +++ b/doc/api_samples/flavors/v2.102/flavors-detail-resp.json @@ -0,0 +1,163 @@ +{ + "flavors": [ + { + "OS-FLV-EXT-DATA:ephemeral": 0, + "description": null, + "disk": 1, + "extra_specs": {}, + "id": "1", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/1", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/1", + "rel": "bookmark" + } + ], + "name": "m1.tiny", + "os-flavor-access:is_public": true, + "ram": 512, + "swap": 0, + "vcpus": 1 + }, + { + "OS-FLV-EXT-DATA:ephemeral": 0, + "description": null, + "disk": 20, + "extra_specs": {}, + "id": "2", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/2", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/2", + "rel": "bookmark" + } + ], + "name": "m1.small", + "os-flavor-access:is_public": true, + "ram": 2048, + "swap": 0, + "vcpus": 1 + }, + { + "OS-FLV-EXT-DATA:ephemeral": 0, + "description": null, + "disk": 40, + "extra_specs": {}, + "id": "3", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/3", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/3", + "rel": "bookmark" + } + ], + "name": "m1.medium", + "os-flavor-access:is_public": true, + "ram": 4096, + "swap": 0, + "vcpus": 2 + }, + { + "OS-FLV-EXT-DATA:ephemeral": 0, + "description": null, + "disk": 80, + "extra_specs": {}, + "id": "4", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/4", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/4", + "rel": "bookmark" + } + ], + "name": "m1.large", + "os-flavor-access:is_public": true, + "ram": 8192, + "swap": 0, + "vcpus": 4 + }, + { + "OS-FLV-EXT-DATA:ephemeral": 0, + "description": null, + "disk": 160, + "extra_specs": {}, + "id": "5", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/5", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/5", + "rel": "bookmark" + } + ], + "name": "m1.xlarge", + "os-flavor-access:is_public": true, + "ram": 16384, + "swap": 0, + "vcpus": 8 + }, + { + "OS-FLV-EXT-DATA:ephemeral": 0, + "description": null, + "disk": 1, + "extra_specs": { + "hw:numa_nodes": "1" + }, + "id": "6", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/6", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/6", + "rel": "bookmark" + } + ], + "name": "m1.tiny.specs", + "os-flavor-access:is_public": true, + "ram": 512, + "swap": 0, + "vcpus": 1 + }, + { + "OS-FLV-EXT-DATA:ephemeral": 0, + "description": "test description", + "disk": 20, + "extra_specs": { + "hw:cpu_policy": "shared", + "hw:numa_nodes": "1" + }, + "id": "7", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/7", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/7", + "rel": "bookmark" + } + ], + "name": "m1.small.description", + "os-flavor-access:is_public": true, + "ram": 2048, + "swap": 0, + "vcpus": 1 + } + ] +} \ No newline at end of file diff --git a/doc/api_samples/flavors/v2.102/flavors-list-resp.json b/doc/api_samples/flavors/v2.102/flavors-list-resp.json new file mode 100644 index 0000000000..1c416099c4 --- /dev/null +++ b/doc/api_samples/flavors/v2.102/flavors-list-resp.json @@ -0,0 +1,109 @@ +{ + "flavors": [ + { + "description": null, + "id": "1", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/1", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/1", + "rel": "bookmark" + } + ], + "name": "m1.tiny" + }, + { + "description": null, + "id": "2", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/2", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/2", + "rel": "bookmark" + } + ], + "name": "m1.small" + }, + { + "description": null, + "id": "3", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/3", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/3", + "rel": "bookmark" + } + ], + "name": "m1.medium" + }, + { + "description": null, + "id": "4", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/4", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/4", + "rel": "bookmark" + } + ], + "name": "m1.large" + }, + { + "description": null, + "id": "5", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/5", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/5", + "rel": "bookmark" + } + ], + "name": "m1.xlarge" + }, + { + "description": null, + "id": "6", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/6", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/6", + "rel": "bookmark" + } + ], + "name": "m1.tiny.specs" + }, + { + "description": "test description", + "id": "7", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/7", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/7", + "rel": "bookmark" + } + ], + "name": "m1.small.description" + } + ] +} \ No newline at end of file diff --git a/nova/api/openstack/api_version_request.py b/nova/api/openstack/api_version_request.py index f82b52c168..2929e19568 100644 --- a/nova/api/openstack/api_version_request.py +++ b/nova/api/openstack/api_version_request.py @@ -281,7 +281,9 @@ REST_API_VERSION_HISTORY = """REST API Version History: * 2.101 - Attaching a volume via ``POST /servers/{server_id}/os-volume_attachments`` returns HTTP 202 Accepted instead of HTTP 200 and a volumeAttachment response. - * 2.102 - Add support for filtering flavors by name. + * 2.102 - Add support for filtering flavors by name. Remove the deprecated + ``rxtx_factor`` and ``OS-FLV-DISABLED:disabled`` fields and + filters from various flavors APIs. """ # The minimum and maximum versions of the API supported diff --git a/nova/api/openstack/compute/flavors.py b/nova/api/openstack/compute/flavors.py index dc513b9820..8e3590401f 100644 --- a/nova/api/openstack/compute/flavors.py +++ b/nova/api/openstack/compute/flavors.py @@ -58,11 +58,13 @@ class FlavorsController(wsgi.Controller): @wsgi.expected_errors((400, 409)) @validation.schema(schema.create_v20, '2.0', '2.0') @validation.schema(schema.create, '2.1', '2.54') - @validation.schema(schema.create_v255, '2.55') + @validation.schema(schema.create_v255, '2.55', '2.101') + @validation.schema(schema.create_v2102, '2.102') @validation.response_body_schema(schema.create_response, '2.0', '2.54') @validation.response_body_schema(schema.create_response_v255, '2.55', '2.60') # noqa: E501 @validation.response_body_schema(schema.create_response_v261, '2.61', '2.74') # noqa: E501 - @validation.response_body_schema(schema.create_response_v275, '2.75') + @validation.response_body_schema(schema.create_response_v275, '2.75', '2.101') # noqa: E501 + @validation.response_body_schema(schema.create_response_v2102, '2.102') def create(self, req, body): context = req.environ['nova.context'] context.can(fm_policies.POLICY_ROOT % 'create', target={}) @@ -114,7 +116,8 @@ class FlavorsController(wsgi.Controller): @validation.schema(schema.update, '2.55') @validation.response_body_schema(schema.update_response, '2.55', '2.60') @validation.response_body_schema(schema.update_response_v261, '2.61', '2.74') # noqa: E501 - @validation.response_body_schema(schema.update_response_v275, '2.75') + @validation.response_body_schema(schema.update_response_v275, '2.75', '2.101') # noqa: E501 + @validation.response_body_schema(schema.update_response_v2102, '2.102') def update(self, req, id, body): # Validate the policy. context = req.environ['nova.context'] @@ -152,7 +155,8 @@ class FlavorsController(wsgi.Controller): @validation.query_schema(schema.index_query_v2102, '2.102') @validation.response_body_schema(schema.detail_response, '2.0', '2.54') @validation.response_body_schema(schema.detail_response_v255, '2.55', '2.60') # noqa: E501 - @validation.response_body_schema(schema.detail_response_v261, '2.61') + @validation.response_body_schema(schema.detail_response_v261, '2.61', '2.101') # noqa: E501 + @validation.response_body_schema(schema.detail_response_v2102, '2.102') def detail(self, req): """Return all flavors in detail.""" context = req.environ['nova.context'] @@ -171,7 +175,8 @@ class FlavorsController(wsgi.Controller): @validation.response_body_schema(schema.show_response, '2.0', '2.54') @validation.response_body_schema(schema.show_response_v255, '2.55', '2.60') @validation.response_body_schema(schema.show_response_v261, '2.61', '2.74') - @validation.response_body_schema(schema.show_response_v275, '2.75') + @validation.response_body_schema(schema.show_response_v275, '2.75', '2.101') # noqa: E501 + @validation.response_body_schema(schema.show_response_v2102, '2.102') def show(self, req, id): """Return data about the given flavor id.""" context = req.environ['nova.context'] diff --git a/nova/api/openstack/compute/schemas/flavors.py b/nova/api/openstack/compute/schemas/flavors.py index 16f0e913f4..96bd23b310 100644 --- a/nova/api/openstack/compute/schemas/flavors.py +++ b/nova/api/openstack/compute/schemas/flavors.py @@ -75,13 +75,11 @@ create = { 'additionalProperties': False, } - create_v20 = copy.deepcopy(create) create_v20['properties']['flavor']['properties']['name'] = ( parameter_types.name_with_leading_trailing_spaces ) - # 2.55 adds an optional description field with a max length of 65535 since the # backing database column is a TEXT column which is 64KiB. _flavor_description = { @@ -89,11 +87,12 @@ _flavor_description = { 'pattern': parameter_types.valid_description_regex, } - create_v255 = copy.deepcopy(create) create_v255['properties']['flavor']['properties']['description'] = ( _flavor_description) +create_v2102 = copy.deepcopy(create_v255) +del create_v2102['properties']['flavor']['properties']['rxtx_factor'] update = { 'type': 'object', @@ -142,6 +141,8 @@ index_query_v275['additionalProperties'] = False index_query_v2102 = copy.deepcopy(index_query_v275) index_query_v2102['properties']['name'] = parameter_types.multi_params( {'type': 'string'}) +index_query_v2102['properties']['sort_key']['items']['enum'].remove( + 'rxtx_factor') # TODO(stephenfin): Remove additionalProperties in a future API version show_query = { @@ -239,6 +240,12 @@ _flavor_v275 = copy.deepcopy(_flavor_v261) # we completely overwrite this since the new variant is much simpler _flavor_v275['properties']['swap'] = {'type': 'integer'} +_flavor_v2102 = copy.deepcopy(_flavor_v275) +del _flavor_v2102['properties']['rxtx_factor'] +del _flavor_v2102['properties']['OS-FLV-DISABLED:disabled'] +_flavor_v2102['required'].remove('rxtx_factor') +_flavor_v2102['required'].remove('OS-FLV-DISABLED:disabled') + _flavors_links = { 'type': 'array', 'items': { @@ -274,6 +281,9 @@ create_response_v261['properties']['flavor'] = copy.deepcopy(_flavor_v261) create_response_v275 = copy.deepcopy(create_response_v261) create_response_v275['properties']['flavor'] = copy.deepcopy(_flavor_v275) +create_response_v2102 = copy.deepcopy(create_response_v261) +create_response_v2102['properties']['flavor'] = copy.deepcopy(_flavor_v2102) + # NOTE(stephenfin): update is only available from 2.55 and the response is # identical to the create and show response from that point forward update_response = { @@ -291,6 +301,9 @@ update_response_v261['properties']['flavor'] = copy.deepcopy(_flavor_v261) update_response_v275 = copy.deepcopy(update_response_v261) update_response_v275['properties']['flavor'] = copy.deepcopy(_flavor_v275) +update_response_v2102 = copy.deepcopy(update_response_v261) +update_response_v2102['properties']['flavor'] = copy.deepcopy(_flavor_v2102) + index_response = { 'type': 'object', 'properties': { @@ -329,6 +342,9 @@ detail_response_v261['properties']['flavors']['items'] = _flavor_v261 detail_response_v275 = copy.deepcopy(detail_response_v261) detail_response_v275['properties']['flavors']['items'] = _flavor_v275 +detail_response_v2102 = copy.deepcopy(detail_response_v261) +detail_response_v2102['properties']['flavors']['items'] = _flavor_v2102 + show_response = { 'type': 'object', 'properties': { @@ -346,3 +362,6 @@ show_response_v261['properties']['flavor'] = copy.deepcopy(_flavor_v261) show_response_v275 = copy.deepcopy(show_response_v261) show_response_v275['properties']['flavor'] = copy.deepcopy(_flavor_v275) + +show_response_v2102 = copy.deepcopy(show_response_v261) +show_response_v2102['properties']['flavor'] = copy.deepcopy(_flavor_v2102) diff --git a/nova/api/openstack/compute/views/flavors.py b/nova/api/openstack/compute/views/flavors.py index f82a061f84..bb67abb60c 100644 --- a/nova/api/openstack/compute/views/flavors.py +++ b/nova/api/openstack/compute/views/flavors.py @@ -68,6 +68,10 @@ class ViewBuilder(common.ViewBuilder): if api_version_request.is_supported(request, '2.75'): flavor_dict['flavor']['swap'] = flavor["swap"] or 0 + if api_version_request.is_supported(request, '2.102'): + del flavor_dict['flavor']['OS-FLV-DISABLED:disabled'] + del flavor_dict['flavor']['rxtx_factor'] + return flavor_dict def index(self, request, flavors): diff --git a/nova/tests/functional/api_sample_tests/api_samples/flavor-manage/v2.102/flavor-create-post-req.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/flavor-manage/v2.102/flavor-create-post-req.json.tpl new file mode 100644 index 0000000000..d6bdab2c1b --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/flavor-manage/v2.102/flavor-create-post-req.json.tpl @@ -0,0 +1,10 @@ +{ + "flavor": { + "name": "%(flavor_name)s", + "ram": 1024, + "vcpus": 2, + "disk": 10, + "id": "%(flavor_id)s", + "description": "test description" + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/flavor-manage/v2.102/flavor-create-post-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/flavor-manage/v2.102/flavor-create-post-resp.json.tpl new file mode 100644 index 0000000000..68b9c60878 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/flavor-manage/v2.102/flavor-create-post-resp.json.tpl @@ -0,0 +1,24 @@ +{ + "flavor": { + "disk": 10, + "id": "%(flavor_id)s", + "links": [ + { + "href": "%(versioned_compute_endpoint)s/flavors/%(flavor_id)s", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/flavors/%(flavor_id)s", + "rel": "bookmark" + } + ], + "name": "%(flavor_name)s", + "os-flavor-access:is_public": true, + "ram": 1024, + "vcpus": 2, + "OS-FLV-EXT-DATA:ephemeral": 0, + "swap": 0, + "description": "test description", + "extra_specs": {} + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/flavor-manage/v2.102/flavor-update-req.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/flavor-manage/v2.102/flavor-update-req.json.tpl new file mode 100644 index 0000000000..93c8e1e8ab --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/flavor-manage/v2.102/flavor-update-req.json.tpl @@ -0,0 +1,5 @@ +{ + "flavor": { + "description": "updated description" + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/flavor-manage/v2.102/flavor-update-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/flavor-manage/v2.102/flavor-update-resp.json.tpl new file mode 100644 index 0000000000..4d9ba4942b --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/flavor-manage/v2.102/flavor-update-resp.json.tpl @@ -0,0 +1,24 @@ +{ + "flavor": { + "disk": 1, + "OS-FLV-EXT-DATA:ephemeral": 0, + "os-flavor-access:is_public": true, + "id": "1", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/1", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/1", + "rel": "bookmark" + } + ], + "name": "m1.tiny", + "ram": 512, + "swap": 0, + "vcpus": 1, + "description": "updated description", + "extra_specs": {} + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/flavors/v2.102/flavor-get-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/flavors/v2.102/flavor-get-resp.json.tpl new file mode 100644 index 0000000000..fd7620b18c --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/flavors/v2.102/flavor-get-resp.json.tpl @@ -0,0 +1,27 @@ +{ + "flavor": { + "disk": 20, + "OS-FLV-EXT-DATA:ephemeral": 0, + "id": "%(flavorid)s", + "links": [ + { + "href": "%(versioned_compute_endpoint)s/flavors/%(flavorid)s", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/flavors/%(flavorid)s", + "rel": "bookmark" + } + ], + "name": "m1.small.description", + "os-flavor-access:is_public": true, + "ram": 2048, + "swap": 0, + "vcpus": 1, + "description": "test description", + "extra_specs": { + "hw:cpu_policy": "shared", + "hw:numa_nodes": "1" + } + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/flavors/v2.102/flavors-detail-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/flavors/v2.102/flavors-detail-resp.json.tpl new file mode 100644 index 0000000000..67df7a0896 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/flavors/v2.102/flavors-detail-resp.json.tpl @@ -0,0 +1,163 @@ +{ + "flavors": [ + { + "disk": 1, + "OS-FLV-EXT-DATA:ephemeral": 0, + "id": "1", + "links": [ + { + "href": "%(versioned_compute_endpoint)s/flavors/1", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/flavors/1", + "rel": "bookmark" + } + ], + "name": "m1.tiny", + "os-flavor-access:is_public": true, + "ram": 512, + "swap": 0, + "vcpus": 1, + "description": null, + "extra_specs": {} + }, + { + "disk": 20, + "OS-FLV-EXT-DATA:ephemeral": 0, + "id": "2", + "links": [ + { + "href": "%(versioned_compute_endpoint)s/flavors/2", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/flavors/2", + "rel": "bookmark" + } + ], + "name": "m1.small", + "os-flavor-access:is_public": true, + "ram": 2048, + "swap": 0, + "vcpus": 1, + "description": null, + "extra_specs": {} + }, + { + "disk": 40, + "OS-FLV-EXT-DATA:ephemeral": 0, + "id": "3", + "links": [ + { + "href": "%(versioned_compute_endpoint)s/flavors/3", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/flavors/3", + "rel": "bookmark" + } + ], + "name": "m1.medium", + "os-flavor-access:is_public": true, + "ram": 4096, + "swap": 0, + "vcpus": 2, + "description": null, + "extra_specs": {} + }, + { + "disk": 80, + "OS-FLV-EXT-DATA:ephemeral": 0, + "id": "4", + "links": [ + { + "href": "%(versioned_compute_endpoint)s/flavors/4", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/flavors/4", + "rel": "bookmark" + } + ], + "name": "m1.large", + "os-flavor-access:is_public": true, + "ram": 8192, + "swap": 0, + "vcpus": 4, + "description": null, + "extra_specs": {} + }, + { + "disk": 160, + "OS-FLV-EXT-DATA:ephemeral": 0, + "id": "5", + "links": [ + { + "href": "%(versioned_compute_endpoint)s/flavors/5", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/flavors/5", + "rel": "bookmark" + } + ], + "name": "m1.xlarge", + "os-flavor-access:is_public": true, + "ram": 16384, + "swap": 0, + "vcpus": 8, + "description": null, + "extra_specs": {} + }, + { + "disk": 1, + "OS-FLV-EXT-DATA:ephemeral": 0, + "id": "6", + "links": [ + { + "href": "%(versioned_compute_endpoint)s/flavors/6", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/flavors/6", + "rel": "bookmark" + } + ], + "name": "m1.tiny.specs", + "os-flavor-access:is_public": true, + "ram": 512, + "swap": 0, + "vcpus": 1, + "description": null, + "extra_specs": { + "hw:numa_nodes": "1" + } + }, + { + "disk": 20, + "OS-FLV-EXT-DATA:ephemeral": 0, + "id": "%(flavorid)s", + "links": [ + { + "href": "%(versioned_compute_endpoint)s/flavors/%(flavorid)s", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/flavors/%(flavorid)s", + "rel": "bookmark" + } + ], + "name": "m1.small.description", + "os-flavor-access:is_public": true, + "ram": 2048, + "swap": 0, + "vcpus": 1, + "description": "test description", + "extra_specs": { + "hw:cpu_policy": "shared", + "hw:numa_nodes": "1" + } + } + ] +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/flavors/v2.102/flavors-list-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/flavors/v2.102/flavors-list-resp.json.tpl new file mode 100644 index 0000000000..ca8deedcca --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/flavors/v2.102/flavors-list-resp.json.tpl @@ -0,0 +1,109 @@ +{ + "flavors": [ + { + "description": null, + "id": "1", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/1", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/1", + "rel": "bookmark" + } + ], + "name": "m1.tiny" + }, + { + "description": null, + "id": "2", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/2", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/2", + "rel": "bookmark" + } + ], + "name": "m1.small" + }, + { + "description": null, + "id": "3", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/3", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/3", + "rel": "bookmark" + } + ], + "name": "m1.medium" + }, + { + "description": null, + "id": "4", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/4", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/4", + "rel": "bookmark" + } + ], + "name": "m1.large" + }, + { + "description": null, + "id": "5", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/5", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/5", + "rel": "bookmark" + } + ], + "name": "m1.xlarge" + }, + { + "description": null, + "id": "6", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/6", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/6", + "rel": "bookmark" + } + ], + "name": "m1.tiny.specs" + }, + { + "description": "test description", + "id": "7", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/7", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/7", + "rel": "bookmark" + } + ], + "name": "m1.small.description" + } + ] +} diff --git a/nova/tests/functional/api_sample_tests/test_flavor_manage.py b/nova/tests/functional/api_sample_tests/test_flavor_manage.py index 05d360ffde..b3f58b238c 100644 --- a/nova/tests/functional/api_sample_tests/test_flavor_manage.py +++ b/nova/tests/functional/api_sample_tests/test_flavor_manage.py @@ -39,7 +39,7 @@ class FlavorManageSampleJsonTests(api_sample_base.ApiSampleTestBaseV21): self.assertEqual('', response.text) -class FlavorManageSampleJsonTests2_55(FlavorManageSampleJsonTests): +class FlavorManageSampleJsonTests255(FlavorManageSampleJsonTests): microversion = '2.55' scenarios = [('v2_55', {'api_major_version': 'v2.1'})] @@ -48,6 +48,11 @@ class FlavorManageSampleJsonTests2_55(FlavorManageSampleJsonTests): self._verify_response("flavor-update-resp", {}, response, 200) -class FlavorManageSampleJsonTests2_75(FlavorManageSampleJsonTests2_55): +class FlavorManageSampleJsonTests275(FlavorManageSampleJsonTests255): microversion = '2.75' scenarios = [('v2_75', {'api_major_version': 'v2.1'})] + + +class FlavorManageSampleJsonTests2102(FlavorManageSampleJsonTests255): + microversion = '2.102' + scenarios = [('v2_102', {'api_major_version': 'v2.1'})] diff --git a/nova/tests/functional/api_sample_tests/test_flavors.py b/nova/tests/functional/api_sample_tests/test_flavors.py index 6d1612b08a..530a2a577e 100644 --- a/nova/tests/functional/api_sample_tests/test_flavors.py +++ b/nova/tests/functional/api_sample_tests/test_flavors.py @@ -82,12 +82,12 @@ class FlavorsSampleJsonTest(api_sample_base.ApiSampleTestBaseV21): self.assertEqual(400, response.status_code) -class FlavorsSampleJsonTest2_55(FlavorsSampleJsonTest): +class FlavorsSampleJsonTest255(FlavorsSampleJsonTest): microversion = '2.55' scenarios = [('v2_55', {'api_major_version': 'v2.1'})] def setUp(self): - super(FlavorsSampleJsonTest2_55, self).setUp() + super().setUp() # Get the existing flavors created by DefaultFlavorsFixture. ctxt = nova_context.get_admin_context() flavors = objects.FlavorList.get_all(ctxt) @@ -104,12 +104,12 @@ class FlavorsSampleJsonTest2_55(FlavorsSampleJsonTest): self.subs = {'flavorid': new_flavor_id} -class FlavorsSampleJsonTest2_61(FlavorsSampleJsonTest): +class FlavorsSampleJsonTest261(FlavorsSampleJsonTest): microversion = '2.61' scenarios = [('v2_61', {'api_major_version': 'v2.1'})] def setUp(self): - super(FlavorsSampleJsonTest2_61, self).setUp() + super().setUp() # Get the existing flavors created by DefaultFlavorsFixture. ctxt = nova_context.get_admin_context() flavors = objects.FlavorList.get_all(ctxt) @@ -130,9 +130,17 @@ class FlavorsSampleJsonTest2_61(FlavorsSampleJsonTest): self.subs = {'flavorid': new_flavor_id} -class FlavorsSampleJsonTest2_75(FlavorsSampleJsonTest2_61): +class FlavorsSampleJsonTest275(FlavorsSampleJsonTest261): microversion = '2.75' scenarios = [('v2_75', {'api_major_version': 'v2.1'})] def test_flavors_list(self): pass + + +class FlavorsSampleJsonTest2102(FlavorsSampleJsonTest261): + microversion = '2.102' + scenarios = [('v2_102', {'api_major_version': 'v2.1'})] + + sort_keys = FlavorsSampleJsonTest.sort_keys + sort_keys.remove('rxtx_factor') diff --git a/nova/tests/functional/integrated_helpers.py b/nova/tests/functional/integrated_helpers.py index 0adbe8b768..eb3b2b9e9d 100644 --- a/nova/tests/functional/integrated_helpers.py +++ b/nova/tests/functional/integrated_helpers.py @@ -334,7 +334,7 @@ class InstanceHelperMixin: return api.post_aggregate(body)['id'] def _build_flavor(self, id=None, name=None, memory_mb=2048, vcpu=2, - disk=10, ephemeral=10, swap=0, rxtx_factor=1.0, + disk=10, ephemeral=10, swap=0, rxtx_factor=None, is_public=True): """Build a request for the flavor create API. @@ -353,7 +353,7 @@ class InstanceHelperMixin: name = ''.join( random.choice(string.ascii_lowercase) for i in range(20)) - return { + body = { "flavor": { "id": id, "name": name, @@ -362,13 +362,17 @@ class InstanceHelperMixin: "disk": disk, "OS-FLV-EXT-DATA:ephemeral": ephemeral, "swap": swap, - "rxtx_factor": rxtx_factor, "os-flavor-access:is_public": is_public, } } + if rxtx_factor is not None: + body["rxtx_factor"] = rxtx_factor + + return body + def _create_flavor(self, id=None, name=None, memory_mb=2048, vcpu=2, - disk=10, ephemeral=10, swap=0, rxtx_factor=1.0, + disk=10, ephemeral=10, swap=0, rxtx_factor=None, is_public=True, extra_spec=None): """Build and submit a request to the flavor create API. diff --git a/nova/tests/functional/notification_sample_tests/test_flavor.py b/nova/tests/functional/notification_sample_tests/test_flavor.py index 2f0afb320b..e1d49c487e 100644 --- a/nova/tests/functional/notification_sample_tests/test_flavor.py +++ b/nova/tests/functional/notification_sample_tests/test_flavor.py @@ -17,6 +17,8 @@ from nova.tests.functional.notification_sample_tests \ class TestFlavorNotificationSample( notification_sample_base.NotificationSampleTestBase): + MAX_MICROVERSION = '2.1' + def test_flavor_create(self): body = { "flavor": { diff --git a/nova/tests/unit/api/openstack/compute/test_flavors.py b/nova/tests/unit/api/openstack/compute/test_flavors.py index 85e62a06e0..e085a244f2 100644 --- a/nova/tests/unit/api/openstack/compute/test_flavors.py +++ b/nova/tests/unit/api/openstack/compute/test_flavors.py @@ -47,6 +47,8 @@ class FlavorsTestV21(test.TestCase): expect_description = False # Flag to tell the test if a extra_specs should be expected in a response. expect_extra_specs = False + # Flag to tell the test if legacy fields should be omitted from responses. + omit_legacy_fields = False def setUp(self): super().setUp() @@ -67,6 +69,9 @@ class FlavorsTestV21(test.TestCase): expected['description'] = flavor.description if self.expect_extra_specs: expected['extra_specs'] = flavor.extra_specs + if self.omit_legacy_fields: + expected.pop('rxtx_factor', None) + expected.pop('OS-FLV-DISABLED:disabled', None) @mock.patch('nova.objects.Flavor.get_by_flavor_id', side_effect=return_flavor_not_found) @@ -249,7 +254,7 @@ class FlavorsTestV21(test.TestCase): self.assertThat({'limit': ['1'], 'marker': ['1']}, matchers.DictMatches(params)) - def test_get_flavor_with_limit(self): + def test_get_flavor_list_with_limit(self): req = self._build_request('/flavors?limit=2') response = self.controller.index(req) response_list = response["flavors"] @@ -298,7 +303,7 @@ class FlavorsTestV21(test.TestCase): self.assertThat({'limit': ['2'], 'marker': ['2']}, matchers.DictMatches(params)) - def test_get_flavor_with_default_limit(self): + def test_get_flavor_list_with_default_limit(self): self.stub_out('nova.api.openstack.common.get_limit_and_marker', fake_get_limit_and_marker) self.flags(max_limit=1, group='api') @@ -547,6 +552,9 @@ class FlavorsTestV21(test.TestCase): if 'detail' in url and self.expect_extra_specs: expected_resp[0]['extra_specs'] = ( fakes.FLAVORS['2'].extra_specs) + if self.omit_legacy_fields: + expected_resp[0].pop('rxtx_factor', None) + expected_resp[0].pop('OS-FLV-DISABLED:disabled', None) params = { 'limit': 1, 'marker': 1, @@ -609,6 +617,9 @@ class FlavorsTestV21(test.TestCase): if 'detail' in url and self.expect_extra_specs: expected_resp[0]['extra_specs'] = ( fakes.FLAVORS['2'].extra_specs) + if self.omit_legacy_fields: + expected_resp[0].pop('rxtx_factor', None) + expected_resp[0].pop('OS-FLV-DISABLED:disabled', None) req = req or self._build_request(url + '&limit=1&marker=1') result = controller_list(req) self.assertEqual(expected_resp, result['flavors']) @@ -856,6 +867,7 @@ class FlavorsTestV275(FlavorsTestV261): class FlavorsTestV2102(FlavorsTestV275): microversion = '2.102' + omit_legacy_fields = True def test_list_flavors_with_name_filter_old_version(self): req = fakes.HTTPRequestV21.blank( @@ -901,7 +913,6 @@ class FlavorsTestV2102(FlavorsTestV275): expected = { 'flavors': [ { - 'OS-FLV-DISABLED:disabled': fakes.FLAVORS['2'].disabled, 'OS-FLV-EXT-DATA:ephemeral': fakes.FLAVORS['2'].ephemeral_gb, 'description': fakes.FLAVORS['2'].description, @@ -921,7 +932,6 @@ class FlavorsTestV2102(FlavorsTestV275): 'name': fakes.FLAVORS['2'].name, 'os-flavor-access:is_public': True, 'ram': fakes.FLAVORS['2'].memory_mb, - 'rxtx_factor': '', 'swap': fakes.FLAVORS['2'].swap, 'vcpus': fakes.FLAVORS['2'].vcpus, }, @@ -929,6 +939,10 @@ class FlavorsTestV2102(FlavorsTestV275): } self.assertEqual(expected, actual) + def test_list_detail_flavors_with_additional_filter_old_version(self): + self.omit_legacy_fields = False + super().test_list_detail_flavors_with_additional_filter_old_version() + class DisabledFlavorsWithRealDBTestV21(test.TestCase): """Tests that disabled flavors should not be shown nor listed.""" diff --git a/releasenotes/notes/flavor-name-search-4133a0788bd1c37f.yaml b/releasenotes/notes/flavor-name-search-4133a0788bd1c37f.yaml index ab4739214c..ad071ce189 100644 --- a/releasenotes/notes/flavor-name-search-4133a0788bd1c37f.yaml +++ b/releasenotes/notes/flavor-name-search-4133a0788bd1c37f.yaml @@ -5,3 +5,7 @@ features: flavors by name, e.g.:: GET /flavors?name=gpu + + In addition, the ``rxtx_factor`` and ``OS-FLV-DISABLED:disabled`` fields + have been removed from all flavors responses, while the ``rxtx_factor`` + field can no longer be provided when creating a server. diff --git a/tox.ini b/tox.ini index b309179506..6b18145edc 100644 --- a/tox.ini +++ b/tox.ini @@ -86,6 +86,9 @@ commands = [testenv:functional{,-py310,-py311,-py312,-py313}] description = Run functional tests. +passenv = + {[testenv]passenv} + GENERATE_SAMPLES setenv = {[testenv]setenv} # we do not have any greenlet leaks in functional tests so enforce that