diff --git a/nova/api/openstack/api_version_request.py b/nova/api/openstack/api_version_request.py index 2929e19568d2..35e2aaae5dff 100644 --- a/nova/api/openstack/api_version_request.py +++ b/nova/api/openstack/api_version_request.py @@ -283,7 +283,8 @@ REST_API_VERSION_HISTORY = """REST API Version History: 202 Accepted instead of HTTP 200 and a volumeAttachment response. * 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. + filters from various flavors APIs and restrict additional query + string parameters for all APIs. """ # The minimum and maximum versions of the API supported diff --git a/nova/api/openstack/compute/aggregates.py b/nova/api/openstack/compute/aggregates.py index de33003fee2a..c34e6297b5cc 100644 --- a/nova/api/openstack/compute/aggregates.py +++ b/nova/api/openstack/compute/aggregates.py @@ -50,7 +50,8 @@ class AggregateController(wsgi.Controller): self.conductor_tasks = conductor.ComputeTaskAPI() @wsgi.expected_errors(()) - @validation.query_schema(schema.index_query) + @validation.query_schema(schema.index_query, '2.1', '2.101') + @validation.query_schema(schema.index_query_v2102, '2.102') @validation.response_body_schema(schema.index_response, '2.1', '2.40') @validation.response_body_schema(schema.index_response_v241, '2.41') def index(self, req): @@ -100,7 +101,8 @@ class AggregateController(wsgi.Controller): return agg @wsgi.expected_errors((400, 404)) - @validation.query_schema(schema.show_query) + @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.1', '2.40') @validation.response_body_schema(schema.show_response_v241, '2.41') def show(self, req, id): diff --git a/nova/api/openstack/compute/assisted_volume_snapshots.py b/nova/api/openstack/compute/assisted_volume_snapshots.py index 9d57220c3d81..fbd7f98b6db2 100644 --- a/nova/api/openstack/compute/assisted_volume_snapshots.py +++ b/nova/api/openstack/compute/assisted_volume_snapshots.py @@ -65,7 +65,7 @@ class AssistedVolumeSnapshotsController(wsgi.Controller): @wsgi.response(204) @wsgi.expected_errors((400, 404)) @validation.query_schema(schema.delete_query, '2.0', '2.74') - @validation.query_schema(schema.delete_query_275, '2.75') + @validation.query_schema(schema.delete_query_v275, '2.75') @validation.response_body_schema(schema.delete_response) def delete(self, req, id): """Delete a snapshot.""" diff --git a/nova/api/openstack/compute/attach_interfaces.py b/nova/api/openstack/compute/attach_interfaces.py index cafa88719964..e9f16df230ea 100644 --- a/nova/api/openstack/compute/attach_interfaces.py +++ b/nova/api/openstack/compute/attach_interfaces.py @@ -65,7 +65,8 @@ class InterfaceAttachmentController(wsgi.Controller): self.network_api = neutron.API() @wsgi.expected_errors((404, 501)) - @validation.query_schema(schema.index_query) + @validation.query_schema(schema.index_query, '2.1', '2.101') + @validation.query_schema(schema.index_query_v2102, '2.102') @validation.response_body_schema(schema.index_response, '2.1', '2.69') @validation.response_body_schema(schema.index_response_v270, '2.70') def index(self, req, server_id): @@ -110,7 +111,8 @@ class InterfaceAttachmentController(wsgi.Controller): return {'interfaceAttachments': results} @wsgi.expected_errors((403, 404)) - @validation.query_schema(schema.show_query) + @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.1', '2.69') @validation.response_body_schema(schema.show_response_v270, '2.70') def show(self, req, server_id, id): diff --git a/nova/api/openstack/compute/availability_zone.py b/nova/api/openstack/compute/availability_zone.py index 450f18e8b137..179161d3408d 100644 --- a/nova/api/openstack/compute/availability_zone.py +++ b/nova/api/openstack/compute/availability_zone.py @@ -106,7 +106,8 @@ class AvailabilityZoneController(wsgi.Controller): return {'availabilityZoneInfo': result} @wsgi.expected_errors(()) - @validation.query_schema(schema.index_query) + @validation.query_schema(schema.index_query, '2.1', '2.101') + @validation.query_schema(schema.index_query_v2102, '2.102') @validation.response_body_schema(schema.index_response) def index(self, req): """Returns a summary list of availability zone.""" @@ -116,7 +117,8 @@ class AvailabilityZoneController(wsgi.Controller): return self._describe_availability_zones(context) @wsgi.expected_errors(()) - @validation.query_schema(schema.detail_query) + @validation.query_schema(schema.detail_query, '2.1', '2.101') + @validation.query_schema(schema.detail_query_v2102, '2.102') @validation.response_body_schema(schema.detail_response) def detail(self, req): """Returns a detailed list of availability zone.""" diff --git a/nova/api/openstack/compute/extension_info.py b/nova/api/openstack/compute/extension_info.py index d21ec5fb45a2..a953d82ee5bf 100644 --- a/nova/api/openstack/compute/extension_info.py +++ b/nova/api/openstack/compute/extension_info.py @@ -856,7 +856,8 @@ EXTENSION_LIST_LEGACY_V2_COMPATIBLE = sorted( class ExtensionInfoController(wsgi.Controller): @wsgi.expected_errors(()) - @validation.query_schema(schema.index_query) + @validation.query_schema(schema.index_query, '2.1', '2.101') + @validation.query_schema(schema.index_query_v2102, '2.102') @validation.response_body_schema(schema.index_response) def index(self, req): context = req.environ['nova.context'] @@ -870,7 +871,8 @@ class ExtensionInfoController(wsgi.Controller): return dict(extensions=EXTENSION_LIST) @wsgi.expected_errors(404) - @validation.query_schema(schema.show_query) + @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) def show(self, req, id): context = req.environ['nova.context'] diff --git a/nova/api/openstack/compute/flavor_access.py b/nova/api/openstack/compute/flavor_access.py index dec4613e065f..28abbccb9590 100644 --- a/nova/api/openstack/compute/flavor_access.py +++ b/nova/api/openstack/compute/flavor_access.py @@ -42,7 +42,8 @@ class FlavorAccessController(wsgi.Controller): """The flavor access API controller for the OpenStack API.""" @wsgi.expected_errors(404) - @validation.query_schema(schema.index_query) + @validation.query_schema(schema.index_query, '2.1', '2.101') + @validation.query_schema(schema.index_query_v2102, '2.102') @validation.response_body_schema(schema.index_response) def index(self, req, flavor_id): context = req.environ['nova.context'] diff --git a/nova/api/openstack/compute/flavors.py b/nova/api/openstack/compute/flavors.py index 8e3590401f58..65f330021480 100644 --- a/nova/api/openstack/compute/flavors.py +++ b/nova/api/openstack/compute/flavors.py @@ -171,7 +171,8 @@ class FlavorsController(wsgi.Controller): req, limited_flavors, include_extra_specs=include_extra_specs) @wsgi.expected_errors(404) - @validation.query_schema(schema.show_query) + @validation.query_schema(schema.show_query, '2.0', '2.101') + @validation.query_schema(schema.show_query_v2102, '2.102') @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') diff --git a/nova/api/openstack/compute/flavors_extraspecs.py b/nova/api/openstack/compute/flavors_extraspecs.py index 1552a6f1d30f..db16dd0646e8 100644 --- a/nova/api/openstack/compute/flavors_extraspecs.py +++ b/nova/api/openstack/compute/flavors_extraspecs.py @@ -55,7 +55,8 @@ class FlavorExtraSpecsController(wsgi.Controller): validators.validate(name, value) @wsgi.expected_errors(404) - @validation.query_schema(schema.index_query) + @validation.query_schema(schema.index_query, '2.1', '2.101') + @validation.query_schema(schema.index_query_v2102, '2.102') @validation.response_body_schema(schema.index_response) def index(self, req, flavor_id): """Returns the list of extra specs for a given flavor.""" @@ -108,7 +109,8 @@ class FlavorExtraSpecsController(wsgi.Controller): return body @wsgi.expected_errors(404) - @validation.query_schema(schema.show_query) + @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) def show(self, req, flavor_id, id): """Return a single extra spec item.""" diff --git a/nova/api/openstack/compute/instance_actions.py b/nova/api/openstack/compute/instance_actions.py index d2746df2a909..e3b1ef8158ad 100644 --- a/nova/api/openstack/compute/instance_actions.py +++ b/nova/api/openstack/compute/instance_actions.py @@ -139,7 +139,8 @@ class InstanceActionsController(wsgi.Controller): return actions_dict @wsgi.expected_errors(404) - @validation.query_schema(schema.show_query) + @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.1", "2.50") @validation.response_body_schema(schema.show_response_v251, "2.51", "2.57") @validation.response_body_schema(schema.show_response_v258, "2.58", "2.61") diff --git a/nova/api/openstack/compute/instance_usage_audit_log.py b/nova/api/openstack/compute/instance_usage_audit_log.py index 17715eae2a28..881eb52f45fb 100644 --- a/nova/api/openstack/compute/instance_usage_audit_log.py +++ b/nova/api/openstack/compute/instance_usage_audit_log.py @@ -35,7 +35,8 @@ class InstanceUsageAuditLogController(wsgi.Controller): self.host_api = compute.HostAPI() @wsgi.expected_errors(()) - @validation.query_schema(schema.index_query) + @validation.query_schema(schema.index_query, '2.1', '2.101') + @validation.query_schema(schema.index_query_v2102, '2.102') @validation.response_body_schema(schema.index_response) def index(self, req): context = req.environ['nova.context'] @@ -44,7 +45,8 @@ class InstanceUsageAuditLogController(wsgi.Controller): return {'instance_usage_audit_logs': task_log} @wsgi.expected_errors(400) - @validation.query_schema(schema.show_query) + @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) def show(self, req, id): context = req.environ['nova.context'] diff --git a/nova/api/openstack/compute/ips.py b/nova/api/openstack/compute/ips.py index ab52a61b4804..e47a4d405b69 100644 --- a/nova/api/openstack/compute/ips.py +++ b/nova/api/openstack/compute/ips.py @@ -35,7 +35,8 @@ class IPsController(wsgi.Controller): self._compute_api = compute.API() @wsgi.expected_errors(404) - @validation.query_schema(schema.index_query) + @validation.query_schema(schema.index_query, '2.1', '2.101') + @validation.query_schema(schema.index_query_v2102, '2.102') @validation.response_body_schema(schema.index_response) def index(self, req, server_id): context = req.environ["nova.context"] @@ -46,7 +47,8 @@ class IPsController(wsgi.Controller): return self._view_builder.index(req, networks) @wsgi.expected_errors(404) - @validation.query_schema(schema.show_query) + @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) def show(self, req, server_id, id): context = req.environ["nova.context"] diff --git a/nova/api/openstack/compute/keypairs.py b/nova/api/openstack/compute/keypairs.py index e84016034810..84b63017dd13 100644 --- a/nova/api/openstack/compute/keypairs.py +++ b/nova/api/openstack/compute/keypairs.py @@ -118,9 +118,9 @@ class KeypairController(wsgi.Controller): @wsgi.response(202, '2.0', '2.1') @wsgi.response(204, '2.2') - @validation.query_schema(schema.delete_query_schema_v20, '2.0', '2.9') - @validation.query_schema(schema.delete_query_schema_v210, '2.10', '2.74') - @validation.query_schema(schema.delete_query_schema_v275, '2.75') + @validation.query_schema(schema.delete_query_v20, '2.0', '2.9') + @validation.query_schema(schema.delete_query_v210, '2.10', '2.74') + @validation.query_schema(schema.delete_query_v275, '2.75') @validation.response_body_schema(schema.delete_response) @wsgi.expected_errors(404) def delete(self, req, id): @@ -143,9 +143,9 @@ class KeypairController(wsgi.Controller): except exception.KeypairNotFound as exc: raise webob.exc.HTTPNotFound(explanation=exc.format_message()) - @validation.query_schema(schema.show_query_schema_v20, '2.0', '2.9') - @validation.query_schema(schema.show_query_schema_v210, '2.10', '2.74') - @validation.query_schema(schema.show_query_schema_v275, '2.75') + @validation.query_schema(schema.show_query_v20, '2.0', '2.9') + @validation.query_schema(schema.show_query_v210, '2.10', '2.74') + @validation.query_schema(schema.show_query_v275, '2.75') @validation.response_body_schema(schema.show_response, '2.0', '2.1') @validation.response_body_schema(schema.show_response_v22, '2.2') @wsgi.expected_errors(404) @@ -174,10 +174,10 @@ class KeypairController(wsgi.Controller): raise webob.exc.HTTPNotFound(explanation=exc.format_message()) return self._view_builder.show(keypair, key_type=key_type) - @validation.query_schema(schema.index_query_schema_v20, '2.0', '2.9') - @validation.query_schema(schema.index_query_schema_v210, '2.10', '2.34') - @validation.query_schema(schema.index_query_schema_v235, '2.35', '2.74') - @validation.query_schema(schema.index_query_schema_v275, '2.75') + @validation.query_schema(schema.index_query_v20, '2.0', '2.9') + @validation.query_schema(schema.index_query_v210, '2.10', '2.34') + @validation.query_schema(schema.index_query_v235, '2.35', '2.74') + @validation.query_schema(schema.index_query_v275, '2.75') @validation.response_body_schema(schema.index_response, '2.0', '2.1') @validation.response_body_schema(schema.index_response_v22, '2.2', '2.34') @validation.response_body_schema(schema.index_response_v235, '2.35') diff --git a/nova/api/openstack/compute/quota_classes.py b/nova/api/openstack/compute/quota_classes.py index 4b9fcf7c7ccb..ac186bdfc33a 100644 --- a/nova/api/openstack/compute/quota_classes.py +++ b/nova/api/openstack/compute/quota_classes.py @@ -87,7 +87,8 @@ class QuotaClassSetsController(wsgi.Controller): return [] @wsgi.expected_errors(()) - @validation.query_schema(schema.show_query) + @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.1', '2.49') @validation.response_body_schema(schema.show_response_v250, '2.50', '2.56') # noqa: E501 @validation.response_body_schema(schema.show_response_v257, '2.57') diff --git a/nova/api/openstack/compute/schemas/aggregates.py b/nova/api/openstack/compute/schemas/aggregates.py index 6bb185d20b1a..72c46ab9ee78 100644 --- a/nova/api/openstack/compute/schemas/aggregates.py +++ b/nova/api/openstack/compute/schemas/aggregates.py @@ -125,19 +125,21 @@ set_metadata = { 'additionalProperties': False, } -# TODO(stephenfin): Remove additionalProperties in a future API version index_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } +index_query_v2102 = copy.deepcopy(index_query) +index_query_v2102['additionalProperties'] = False -# TODO(stephenfin): Remove additionalProperties in a future API version show_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } +show_query_v2102 = copy.deepcopy(show_query) +show_query_v2102['additionalProperties'] = False _aggregate_response = { 'type': 'object', diff --git a/nova/api/openstack/compute/schemas/assisted_volume_snapshots.py b/nova/api/openstack/compute/schemas/assisted_volume_snapshots.py index c8d818dd06c4..4355a91ca308 100644 --- a/nova/api/openstack/compute/schemas/assisted_volume_snapshots.py +++ b/nova/api/openstack/compute/schemas/assisted_volume_snapshots.py @@ -65,8 +65,8 @@ delete_query = { 'additionalProperties': True } -delete_query_275 = copy.deepcopy(delete_query) -delete_query_275['additionalProperties'] = False +delete_query_v275 = copy.deepcopy(delete_query) +delete_query_v275['additionalProperties'] = False create_response = { 'type': 'object', diff --git a/nova/api/openstack/compute/schemas/attach_interfaces.py b/nova/api/openstack/compute/schemas/attach_interfaces.py index 1dd326a04cbf..c889d480c896 100644 --- a/nova/api/openstack/compute/schemas/attach_interfaces.py +++ b/nova/api/openstack/compute/schemas/attach_interfaces.py @@ -16,7 +16,6 @@ import copy from nova.api.validation import parameter_types - create = { 'type': 'object', 'properties': { @@ -50,20 +49,24 @@ create = { create_v249 = copy.deepcopy(create) create_v249['properties']['interfaceAttachment']['properties']['tag'] = parameter_types.tag # noqa: E501 -# TODO(stephenfin): Remove additionalProperties in a future API version index_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } -# TODO(stephenfin): Remove additionalProperties in a future API version +index_query_v2102 = copy.deepcopy(index_query) +index_query_v2102['additionalProperties'] = False + show_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } +show_query_v2102 = copy.deepcopy(show_query) +show_query_v2102['additionalProperties'] = False + _interface_attachment = { 'type': 'object', 'properties': { diff --git a/nova/api/openstack/compute/schemas/availability_zone.py b/nova/api/openstack/compute/schemas/availability_zone.py index 6c19079a0134..d0ad1e94c414 100644 --- a/nova/api/openstack/compute/schemas/availability_zone.py +++ b/nova/api/openstack/compute/schemas/availability_zone.py @@ -14,15 +14,23 @@ import copy - -# TODO(stephenfin): Remove additionalProperties in a future API version index_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } -detail_query = index_query +index_query_v2102 = copy.deepcopy(index_query) +index_query_v2102['additionalProperties'] = False + +detail_query = { + 'type': 'object', + 'properties': {}, + 'additionalProperties': True, +} + +detail_query_v2102 = copy.deepcopy(detail_query) +detail_query_v2102['additionalProperties'] = False index_response = { 'type': 'object', diff --git a/nova/api/openstack/compute/schemas/extension_info.py b/nova/api/openstack/compute/schemas/extension_info.py index b50924f1c1b2..12a0c31f366b 100644 --- a/nova/api/openstack/compute/schemas/extension_info.py +++ b/nova/api/openstack/compute/schemas/extension_info.py @@ -10,19 +10,23 @@ # License for the specific language governing permissions and limitations # under the License. -# TODO(stephenfin): Remove additionalProperties in a future API version +import copy + index_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } +index_query_v2102 = copy.deepcopy(index_query) +index_query_v2102['additionalProperties'] = False -# TODO(stephenfin): Remove additionalProperties in a future API version show_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } +show_query_v2102 = copy.deepcopy(show_query) +show_query_v2102['additionalProperties'] = False _extension_obj = { 'type': 'object', diff --git a/nova/api/openstack/compute/schemas/flavor_access.py b/nova/api/openstack/compute/schemas/flavor_access.py index 3356b4ce9228..4602c86e2a50 100644 --- a/nova/api/openstack/compute/schemas/flavor_access.py +++ b/nova/api/openstack/compute/schemas/flavor_access.py @@ -16,7 +16,6 @@ import copy from nova.api.validation import parameter_types - add_tenant_access = { 'type': 'object', 'properties': { @@ -55,13 +54,15 @@ remove_tenant_access = { 'additionalProperties': False, } -# TODO(stephenfin): Remove additionalProperties in a future API version index_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } +index_query_v2102 = copy.deepcopy(index_query) +index_query_v2102['additionalProperties'] = False + _common_response = { 'type': 'object', 'properties': { diff --git a/nova/api/openstack/compute/schemas/flavors.py b/nova/api/openstack/compute/schemas/flavors.py index 96bd23b31087..14cd17b81f83 100644 --- a/nova/api/openstack/compute/schemas/flavors.py +++ b/nova/api/openstack/compute/schemas/flavors.py @@ -144,13 +144,15 @@ index_query_v2102['properties']['name'] = parameter_types.multi_params( index_query_v2102['properties']['sort_key']['items']['enum'].remove( 'rxtx_factor') -# TODO(stephenfin): Remove additionalProperties in a future API version show_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } +show_query_v2102 = copy.deepcopy(show_query) +show_query_v2102['additionalProperties'] = False + _flavor_basic = { 'type': 'object', 'properties': { diff --git a/nova/api/openstack/compute/schemas/flavors_extraspecs.py b/nova/api/openstack/compute/schemas/flavors_extraspecs.py index d5327d60b158..6798c2df40cd 100644 --- a/nova/api/openstack/compute/schemas/flavors_extraspecs.py +++ b/nova/api/openstack/compute/schemas/flavors_extraspecs.py @@ -39,20 +39,24 @@ update.update({ 'maxProperties': 1 }) -# TODO(stephenfin): Remove additionalProperties in a future API version index_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } -# TODO(stephenfin): Remove additionalProperties in a future API version +index_query_v2102 = copy.deepcopy(index_query) +index_query_v2102['additionalProperties'] = False + show_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } +show_query_v2102 = copy.deepcopy(show_query) +show_query_v2102['additionalProperties'] = False + index_response = { 'type': 'object', 'properties': { diff --git a/nova/api/openstack/compute/schemas/floating_ip_pools.py b/nova/api/openstack/compute/schemas/floating_ip_pools.py index eb4ac1beee1f..633e32310cad 100644 --- a/nova/api/openstack/compute/schemas/floating_ip_pools.py +++ b/nova/api/openstack/compute/schemas/floating_ip_pools.py @@ -10,13 +10,17 @@ # License for the specific language governing permissions and limitations # under the License. -# TODO(stephenfin): Remove additionalProperties in a future API version +import copy + index_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } +index_query_v2102 = copy.deepcopy(index_query) +index_query_v2102['additionalProperties'] = False + index_response = { 'type': 'object', 'properties': { diff --git a/nova/api/openstack/compute/schemas/instance_actions.py b/nova/api/openstack/compute/schemas/instance_actions.py index 61a229b799b5..ba185ec30bd5 100644 --- a/nova/api/openstack/compute/schemas/instance_actions.py +++ b/nova/api/openstack/compute/schemas/instance_actions.py @@ -49,6 +49,9 @@ show_query = { 'additionalProperties': True, } +show_query_v2102 = copy.deepcopy(show_query) +show_query_v2102['additionalProperties'] = False + index_response = { 'type': 'object', 'properties': { diff --git a/nova/api/openstack/compute/schemas/instance_usage_audit_log.py b/nova/api/openstack/compute/schemas/instance_usage_audit_log.py index 95b2026c5757..f4dbfa8ba6c5 100644 --- a/nova/api/openstack/compute/schemas/instance_usage_audit_log.py +++ b/nova/api/openstack/compute/schemas/instance_usage_audit_log.py @@ -10,18 +10,26 @@ # License for the specific language governing permissions and limitations # under the License. +import copy + index_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } +index_query_v2102 = copy.deepcopy(index_query) +index_query_v2102['additionalProperties'] = False + show_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } +show_query_v2102 = copy.deepcopy(show_query) +show_query_v2102['additionalProperties'] = False + _instance_usage_audit_log_response = { 'type': 'object', 'properties': { diff --git a/nova/api/openstack/compute/schemas/ips.py b/nova/api/openstack/compute/schemas/ips.py index a8ac4ec7f887..8e7e586f8867 100644 --- a/nova/api/openstack/compute/schemas/ips.py +++ b/nova/api/openstack/compute/schemas/ips.py @@ -12,20 +12,24 @@ import copy -# TODO(stephenfin): Remove additionalProperties in a future API version index_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } -# TODO(stephenfin): Remove additionalProperties in a future API version +index_query_v2102 = copy.deepcopy(index_query) +index_query_v2102['additionalProperties'] = False + show_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } +show_query_v2102 = copy.deepcopy(show_query) +show_query_v2102['additionalProperties'] = False + _ip_address = { 'type': 'object', 'properties': { diff --git a/nova/api/openstack/compute/schemas/keypairs.py b/nova/api/openstack/compute/schemas/keypairs.py index 89a316caf940..43dc03c0713b 100644 --- a/nova/api/openstack/compute/schemas/keypairs.py +++ b/nova/api/openstack/compute/schemas/keypairs.py @@ -89,35 +89,33 @@ create_v292['properties']['keypair']['properties']['name'] = ( parameter_types.keypair_name_special_chars_v292) create_v292['properties']['keypair']['required'] = ['name', 'public_key'] -index_query_schema_v20 = { +index_query_v20 = { 'type': 'object', 'properties': {}, 'additionalProperties': True } - -index_query_schema_v210 = { +index_query_v210 = { 'type': 'object', 'properties': { 'user_id': parameter_types.multi_params({'type': 'string'}) }, 'additionalProperties': True } - -index_query_schema_v235 = copy.deepcopy(index_query_schema_v210) -index_query_schema_v235['properties'].update( +index_query_v235 = copy.deepcopy(index_query_v210) +index_query_v235['properties'].update( parameter_types.pagination_parameters) +index_query_v275 = copy.deepcopy(index_query_v235) +index_query_v275['additionalProperties'] = False -show_query_schema_v20 = index_query_schema_v20 -show_query_schema_v210 = index_query_schema_v210 -delete_query_schema_v20 = index_query_schema_v20 -delete_query_schema_v210 = index_query_schema_v210 +show_query_v20 = index_query_v20 +show_query_v210 = index_query_v210 +show_query_v275 = copy.deepcopy(show_query_v210) +show_query_v275['additionalProperties'] = False -index_query_schema_v275 = copy.deepcopy(index_query_schema_v235) -index_query_schema_v275['additionalProperties'] = False -show_query_schema_v275 = copy.deepcopy(show_query_schema_v210) -show_query_schema_v275['additionalProperties'] = False -delete_query_schema_v275 = copy.deepcopy(delete_query_schema_v210) -delete_query_schema_v275['additionalProperties'] = False +delete_query_v20 = index_query_v20 +delete_query_v210 = index_query_v210 +delete_query_v275 = copy.deepcopy(delete_query_v210) +delete_query_v275['additionalProperties'] = False create_response = { 'type': 'object', diff --git a/nova/api/openstack/compute/schemas/migrations.py b/nova/api/openstack/compute/schemas/migrations.py index e5be5029103d..2198c42cbf16 100644 --- a/nova/api/openstack/compute/schemas/migrations.py +++ b/nova/api/openstack/compute/schemas/migrations.py @@ -17,7 +17,6 @@ import copy from nova.api.validation import parameter_types from nova.api.validation import response_types - index_query_v20 = { 'type': 'object', 'properties': { diff --git a/nova/api/openstack/compute/schemas/quota_classes.py b/nova/api/openstack/compute/schemas/quota_classes.py index e1cf37a3e67d..8f73992e108e 100644 --- a/nova/api/openstack/compute/schemas/quota_classes.py +++ b/nova/api/openstack/compute/schemas/quota_classes.py @@ -11,6 +11,7 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. + import copy from nova.api.openstack.compute.schemas import quota_sets @@ -45,13 +46,15 @@ del update_v257['properties']['quota_class_set']['properties'][ del update_v257['properties']['quota_class_set']['properties'][ 'injected_file_path_bytes'] -# TODO(stephenfin): Remove additionalProperties in a future API version show_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } +show_query_v2102 = copy.deepcopy(show_query) +show_query_v2102['additionalProperties'] = False + _quota_response = { 'type': 'object', 'properties': { diff --git a/nova/api/openstack/compute/schemas/quota_sets.py b/nova/api/openstack/compute/schemas/quota_sets.py index 0757c44719c9..5791ed7af4e4 100644 --- a/nova/api/openstack/compute/schemas/quota_sets.py +++ b/nova/api/openstack/compute/schemas/quota_sets.py @@ -101,15 +101,17 @@ detail_query_v275 = copy.deepcopy(show_query_v275) update_query = copy.deepcopy(show_query) update_query_v275 = copy.deepcopy(show_query_v275) -# TODO(stephenfin): Remove additionalProperties in a future API version +delete_query = copy.deepcopy(show_query) +delete_query_v275 = copy.deepcopy(show_query_v275) + defaults_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } -delete_query = copy.deepcopy(show_query) -delete_query_v275 = copy.deepcopy(show_query_v275) +defaults_query_v2102 = copy.deepcopy(defaults_query) +defaults_query_v2102['additionalProperties'] = False _quota_response = { 'type': 'object', diff --git a/nova/api/openstack/compute/schemas/security_groups.py b/nova/api/openstack/compute/schemas/security_groups.py index 50484aaf0ec2..db560104d116 100644 --- a/nova/api/openstack/compute/schemas/security_groups.py +++ b/nova/api/openstack/compute/schemas/security_groups.py @@ -94,13 +94,15 @@ index_query = { 'additionalProperties': True } -# TODO(stephenfin): Remove additionalProperties in a future API version index_server_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } +index_server_query_v2102 = copy.deepcopy(index_server_query) +index_server_query_v2102['additionalProperties'] = False + # TODO(stephenfin): Remove additionalProperties in a future API version add_security_group = { 'type': 'object', diff --git a/nova/api/openstack/compute/schemas/server_diagnostics.py b/nova/api/openstack/compute/schemas/server_diagnostics.py index 69f55c59ce87..e1d406a93abb 100644 --- a/nova/api/openstack/compute/schemas/server_diagnostics.py +++ b/nova/api/openstack/compute/schemas/server_diagnostics.py @@ -10,12 +10,15 @@ # License for the specific language governing permissions and limitations # under the License. -# TODO(stephenfin): Remove additionalProperties in a future API version +import copy + index_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } +index_query_v2102 = copy.deepcopy(index_query) +index_query_v2102['additionalProperties'] = False # NOTE(stephenfin): We could define all available response types for the # various virt drivers, but we'd need to be able to do this (accurately) for diff --git a/nova/api/openstack/compute/schemas/server_groups.py b/nova/api/openstack/compute/schemas/server_groups.py index 48f3a11705bf..805e78e80f22 100644 --- a/nova/api/openstack/compute/schemas/server_groups.py +++ b/nova/api/openstack/compute/schemas/server_groups.py @@ -99,6 +99,9 @@ show_query = { 'additionalProperties': True, } +show_query_v2102 = copy.deepcopy(show_query) +show_query_v2102['additionalProperties'] = False + _server_group_response = { 'type': 'object', 'properties': { diff --git a/nova/api/openstack/compute/schemas/server_metadata.py b/nova/api/openstack/compute/schemas/server_metadata.py index ac6b8dfe27e8..75da87718469 100644 --- a/nova/api/openstack/compute/schemas/server_metadata.py +++ b/nova/api/openstack/compute/schemas/server_metadata.py @@ -51,20 +51,23 @@ update_all = { 'additionalProperties': False, } -# TODO(stephenfin): Remove additionalProperties in a future API version index_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } +index_query_v2102 = copy.deepcopy(index_query) +index_query_v2102['additionalProperties'] = False -# TODO(stephenfin): Remove additionalProperties in a future API version show_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } +show_query_v2102 = copy.deepcopy(show_query) +show_query_v2102['additionalProperties'] = False + index_response = { 'type': 'object', 'properties': { diff --git a/nova/api/openstack/compute/schemas/server_migrations.py b/nova/api/openstack/compute/schemas/server_migrations.py index 0a09f66820bb..6322631ccda0 100644 --- a/nova/api/openstack/compute/schemas/server_migrations.py +++ b/nova/api/openstack/compute/schemas/server_migrations.py @@ -17,6 +17,23 @@ import copy from nova.api.validation import parameter_types +index_query = { + 'type': 'object', + 'properties': {}, + 'additionalProperties': True, +} + +index_query_v2102 = copy.deepcopy(index_query) +index_query_v2102['additionalProperties'] = False + +show_query = { + 'type': 'object', + 'properties': {}, + 'additionalProperties': True, +} + +show_query_v2102 = copy.deepcopy(show_query) +show_query_v2102['additionalProperties'] = False force_complete = { 'type': 'object', @@ -29,20 +46,6 @@ force_complete = { 'additionalProperties': False, } -# TODO(stephenfin): Remove additionalProperties in a future API version -index_query = { - 'type': 'object', - 'properties': {}, - 'additionalProperties': True, -} - -# TODO(stephenfin): Remove additionalProperties in a future API version -show_query = { - 'type': 'object', - 'properties': {}, - 'additionalProperties': True, -} - force_complete_response = { 'type': 'null', } diff --git a/nova/api/openstack/compute/schemas/server_password.py b/nova/api/openstack/compute/schemas/server_password.py index 758935da6eb4..127082109d7c 100644 --- a/nova/api/openstack/compute/schemas/server_password.py +++ b/nova/api/openstack/compute/schemas/server_password.py @@ -10,13 +10,17 @@ # License for the specific language governing permissions and limitations # under the License. -# TODO(stephenfin): Remove additionalProperties in a future API version +import copy + index_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } +index_query_v2102 = copy.deepcopy(index_query) +index_query_v2102['additionalProperties'] = False + index_response = { 'type': 'object', 'properties': { diff --git a/nova/api/openstack/compute/schemas/server_tags.py b/nova/api/openstack/compute/schemas/server_tags.py index e9f43a5f62bc..375a28026827 100644 --- a/nova/api/openstack/compute/schemas/server_tags.py +++ b/nova/api/openstack/compute/schemas/server_tags.py @@ -10,6 +10,8 @@ # License for the specific language governing permissions and limitations # under the License. +import copy + from nova.api.validation import parameter_types from nova.objects import instance @@ -32,20 +34,24 @@ update = { "type": "null", } -# TODO(stephenfin): Remove additionalProperties in a future API version index_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } -# TODO(stephenfin): Remove additionalProperties in a future API version +index_query_v2102 = copy.deepcopy(index_query) +index_query_v2102['additionalProperties'] = False + show_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } +show_query_v2102 = copy.deepcopy(show_query) +show_query_v2102['additionalProperties'] = False + show_response = {'type': 'null'} index_response = { diff --git a/nova/api/openstack/compute/schemas/server_topology.py b/nova/api/openstack/compute/schemas/server_topology.py index 091da073af8f..a6360cd64b27 100644 --- a/nova/api/openstack/compute/schemas/server_topology.py +++ b/nova/api/openstack/compute/schemas/server_topology.py @@ -10,12 +10,15 @@ # License for the specific language governing permissions and limitations # under the License. -# TODO(stephenfin): Remove additionalProperties in a future API version -query_params_v21 = { +import copy + +index_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } +index_query_v2102 = copy.deepcopy(index_query) +index_query_v2102['additionalProperties'] = False index_response = { 'type': 'object', diff --git a/nova/api/openstack/compute/schemas/servers.py b/nova/api/openstack/compute/schemas/servers.py index 255d25e09299..075596233d30 100644 --- a/nova/api/openstack/compute/schemas/servers.py +++ b/nova/api/openstack/compute/schemas/servers.py @@ -619,7 +619,7 @@ VALID_SORT_KEYS_V275['enum'] = list( set(VALID_SORT_KEYS_V273["enum"]) - set(SERVER_LIST_IGNORE_SORT_KEY_V273) ) -query_params_v21 = { +index_query = { 'type': 'object', 'properties': { 'user_id': parameter_types.common_query_param, @@ -692,38 +692,38 @@ query_params_v21 = { # Update the joined-table fields to the list so it will not be # stripped in later process, thus can be handled later in api # to raise HTTP 400. -query_params_v21['properties'].update( +index_query['properties'].update( JOINED_TABLE_QUERY_PARAMS_SERVERS) -query_params_v21['properties'].update( +index_query['properties'].update( parameter_types.pagination_parameters) -query_params_v226 = copy.deepcopy(query_params_v21) -query_params_v226['properties'].update({ +index_query_v226 = copy.deepcopy(index_query) +index_query_v226['properties'].update({ 'tags': parameter_types.common_query_regex_param, 'tags-any': parameter_types.common_query_regex_param, 'not-tags': parameter_types.common_query_regex_param, 'not-tags-any': parameter_types.common_query_regex_param, }) -query_params_v266 = copy.deepcopy(query_params_v226) -query_params_v266['properties'].update({ +index_query_v266 = copy.deepcopy(index_query_v226) +index_query_v266['properties'].update({ 'changes-before': parameter_types.multi_params( {'type': 'string', 'format': 'date-time'} ), }) -query_params_v273 = copy.deepcopy(query_params_v266) -query_params_v273['properties'].update({ +index_query_v273 = copy.deepcopy(index_query_v266) +index_query_v273['properties'].update({ 'sort_key': parameter_types.multi_params(VALID_SORT_KEYS_V273), 'locked': parameter_types.common_query_param, }) -query_params_v275 = copy.deepcopy(query_params_v273) -query_params_v275['properties'].update({ +index_query_v275 = copy.deepcopy(index_query_v273) +index_query_v275['properties'].update({ 'sort_key': parameter_types.multi_params(VALID_SORT_KEYS_V275), }) -query_params_v275['additionalProperties'] = False +index_query_v275['additionalProperties'] = False show_query = { 'type': 'object', @@ -731,6 +731,9 @@ show_query = { 'additionalProperties': True, } +show_query_v2102 = copy.deepcopy(show_query) +show_query_v2102['additionalProperties'] = False + _server_status = { 'type': 'string', 'enum': [ diff --git a/nova/api/openstack/compute/schemas/services.py b/nova/api/openstack/compute/schemas/services.py index ed10f3593be3..183e43ff212b 100644 --- a/nova/api/openstack/compute/schemas/services.py +++ b/nova/api/openstack/compute/schemas/services.py @@ -68,7 +68,6 @@ update_v253 = { 'additionalProperties': False } - index_query = { 'type': 'object', 'properties': { diff --git a/nova/api/openstack/compute/schemas/snapshots.py b/nova/api/openstack/compute/schemas/snapshots.py index b1501b7d8cd5..55270683df5f 100644 --- a/nova/api/openstack/compute/schemas/snapshots.py +++ b/nova/api/openstack/compute/schemas/snapshots.py @@ -12,6 +12,8 @@ # License for the specific language governing permissions and limitations # under the License. +import copy + from nova.api.validation import parameter_types create = { @@ -52,6 +54,9 @@ show_query = { 'additionalProperties': True } +show_query_v2102 = copy.deepcopy(show_query) +show_query_v2102['additionalProperties'] = False + _snapshot_response = { 'type': 'object', 'properties': { diff --git a/nova/api/openstack/compute/schemas/versions.py b/nova/api/openstack/compute/schemas/versions.py index 7e97eae1ef51..4a4457d8f116 100644 --- a/nova/api/openstack/compute/schemas/versions.py +++ b/nova/api/openstack/compute/schemas/versions.py @@ -10,14 +10,15 @@ # License for the specific language governing permissions and limitations # under the License. -# TODO(stephenfin): Remove additionalProperties in a future API version +# NOTE(stephenfin): We would like to change additionalProperties to false, but +# these APIs are unversioned so we can't + show_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True, } -# TODO(stephenfin): Remove additionalProperties in a future API version multi_query = { 'type': 'object', 'properties': {}, diff --git a/nova/api/openstack/compute/schemas/volume_attachments.py b/nova/api/openstack/compute/schemas/volume_attachments.py index ad83951b177d..61a3b10685a1 100644 --- a/nova/api/openstack/compute/schemas/volume_attachments.py +++ b/nova/api/openstack/compute/schemas/volume_attachments.py @@ -14,6 +14,33 @@ import copy from nova.api.validation import parameter_types +index_query = { + 'type': 'object', + 'properties': { + 'limit': parameter_types.multi_params( + parameter_types.non_negative_integer), + 'offset': parameter_types.multi_params( + parameter_types.non_negative_integer) + }, + # NOTE(gmann): This is kept True to keep backward compatibility. + # As of now Schema validation stripped out the additional parameters and + # does not raise 400. In microversion 2.75, we have blocked the additional + # parameters. + 'additionalProperties': True +} + +index_query_v275 = copy.deepcopy(index_query) +index_query_v275['additionalProperties'] = False + +show_query = { + 'type': 'object', + 'properties': {}, + 'additionalProperties': True, +} + +show_query_v2102 = copy.deepcopy(show_query) +show_query_v2102['additionalProperties'] = False + create = { 'type': 'object', 'properties': { @@ -76,31 +103,6 @@ update_v285 = { 'additionalProperties': False, } -index_query = { - 'type': 'object', - 'properties': { - 'limit': parameter_types.multi_params( - parameter_types.non_negative_integer), - 'offset': parameter_types.multi_params( - parameter_types.non_negative_integer) - }, - # NOTE(gmann): This is kept True to keep backward compatibility. - # As of now Schema validation stripped out the additional parameters and - # does not raise 400. In microversion 2.75, we have blocked the additional - # parameters. - 'additionalProperties': True -} - -index_query_v275 = copy.deepcopy(index_query) -index_query_v275['additionalProperties'] = False - -# TODO(stephenfin): Remove additionalProperties in a future API version -show_query = { - 'type': 'object', - 'properties': {}, - 'additionalProperties': True, -} - _volume_attachment_response = { 'type': 'object', 'properties': { diff --git a/nova/api/openstack/compute/schemas/volumes.py b/nova/api/openstack/compute/schemas/volumes.py index e823f8331f18..5724c021ca0b 100644 --- a/nova/api/openstack/compute/schemas/volumes.py +++ b/nova/api/openstack/compute/schemas/volumes.py @@ -12,6 +12,8 @@ # License for the specific language governing permissions and limitations # under the License. +import copy + from nova.api.validation import parameter_types from nova.api.validation import response_types @@ -58,14 +60,23 @@ index_query = { 'additionalProperties': True } +index_query_v275 = copy.deepcopy(index_query) +index_query_v275['additionalProperties'] = False + detail_query = index_query +detail_query_v2102 = copy.deepcopy(detail_query) +detail_query_v2102['additionalProperties'] = False + show_query = { 'type': 'object', 'properties': {}, 'additionalProperties': True } +show_query_v2102 = copy.deepcopy(show_query) +show_query_v2102['additionalProperties'] = False + _volume_response = { 'type': 'object', 'properties': { diff --git a/nova/api/openstack/compute/security_groups.py b/nova/api/openstack/compute/security_groups.py index 7f162258bae8..99b14dccafbc 100644 --- a/nova/api/openstack/compute/security_groups.py +++ b/nova/api/openstack/compute/security_groups.py @@ -366,7 +366,8 @@ class ServerSecurityGroupController( ): @wsgi.expected_errors(404) - @validation.query_schema(schema.index_server_query) + @validation.query_schema(schema.index_server_query, '2.1', '2.101') + @validation.query_schema(schema.index_server_query_v2102, '2.102') @validation.response_body_schema(schema.index_server_response) def index(self, req, server_id): """Returns a list of security groups for the given instance.""" diff --git a/nova/api/openstack/compute/server_diagnostics.py b/nova/api/openstack/compute/server_diagnostics.py index 803e7d1b238d..3e8506f92dbc 100644 --- a/nova/api/openstack/compute/server_diagnostics.py +++ b/nova/api/openstack/compute/server_diagnostics.py @@ -35,7 +35,8 @@ class ServerDiagnosticsController(wsgi.Controller): self.compute_api = compute.API() @wsgi.expected_errors((400, 404, 409, 501)) - @validation.query_schema(schema.index_query) + @validation.query_schema(schema.index_query, '2.1', '2.101') + @validation.query_schema(schema.index_query_v2102, '2.102') @validation.response_body_schema(schema.index_response, '2.1', '2.47') @validation.response_body_schema(schema.index_response_v248, '2.48') def index(self, req, server_id): diff --git a/nova/api/openstack/compute/server_groups.py b/nova/api/openstack/compute/server_groups.py index 69ad945a25b2..6d4eb7822dd1 100644 --- a/nova/api/openstack/compute/server_groups.py +++ b/nova/api/openstack/compute/server_groups.py @@ -131,7 +131,8 @@ class ServerGroupController(wsgi.Controller): return server_group @wsgi.expected_errors(404) - @validation.query_schema(schema.show_query) + @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.1', '2.12') @validation.response_body_schema(schema.show_response_v213, '2.13', '2.14') @validation.response_body_schema(schema.show_response_v215, '2.15', '2.63') diff --git a/nova/api/openstack/compute/server_metadata.py b/nova/api/openstack/compute/server_metadata.py index c66959ee4bef..0056f3be148e 100644 --- a/nova/api/openstack/compute/server_metadata.py +++ b/nova/api/openstack/compute/server_metadata.py @@ -49,7 +49,8 @@ class ServerMetadataController(wsgi.Controller): return meta_dict @wsgi.expected_errors(404) - @validation.query_schema(schema.index_query) + @validation.query_schema(schema.index_query, '2.1', '2.101') + @validation.query_schema(schema.index_query_v2102, '2.102') @validation.response_body_schema(schema.index_response) def index(self, req, server_id): """Returns the list of metadata for a given instance.""" @@ -126,7 +127,8 @@ class ServerMetadataController(wsgi.Controller): state_error, 'update metadata', server.uuid) @wsgi.expected_errors(404) - @validation.query_schema(schema.show_query) + @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) def show(self, req, server_id, id): """Return a single metadata item.""" diff --git a/nova/api/openstack/compute/server_migrations.py b/nova/api/openstack/compute/server_migrations.py index e81b0bb2c573..53c7150c97c9 100644 --- a/nova/api/openstack/compute/server_migrations.py +++ b/nova/api/openstack/compute/server_migrations.py @@ -119,7 +119,8 @@ class ServerMigrationsController(wsgi.Controller): @wsgi.api_version("2.23") @wsgi.expected_errors(404) - @validation.query_schema(schema.index_query) + @validation.query_schema(schema.index_query, '2.23', '2.101') + @validation.query_schema(schema.index_query_v2102, '2.102') @validation.response_body_schema(schema.index_response_v223, '2.23', '2.58') # noqa: E501 @validation.response_body_schema(schema.index_response_v259, '2.59', '2.79') # noqa: E501 @validation.response_body_schema(schema.index_response_v280, '2.80') @@ -148,7 +149,8 @@ class ServerMigrationsController(wsgi.Controller): @wsgi.api_version("2.23") @wsgi.expected_errors(404) - @validation.query_schema(schema.show_query) + @validation.query_schema(schema.show_query, '2.23', '2.101') + @validation.query_schema(schema.show_query_v2102, '2.102') @validation.response_body_schema(schema.show_response_v223, '2.23', '2.58') @validation.response_body_schema(schema.show_response_v259, '2.59', '2.79') # noqa: E501 @validation.response_body_schema(schema.show_response_v280, '2.80') diff --git a/nova/api/openstack/compute/server_password.py b/nova/api/openstack/compute/server_password.py index 6aa6abcd9951..d6af0a1e0ada 100644 --- a/nova/api/openstack/compute/server_password.py +++ b/nova/api/openstack/compute/server_password.py @@ -33,7 +33,8 @@ class ServerPasswordController(wsgi.Controller): self.compute_api = compute.API() @wsgi.expected_errors(404) - @validation.query_schema(schema.index_query) + @validation.query_schema(schema.index_query, '2.1', '2.101') + @validation.query_schema(schema.index_query_v2102, '2.102') @validation.response_body_schema(schema.index_response) def index(self, req, server_id): context = req.environ['nova.context'] diff --git a/nova/api/openstack/compute/server_topology.py b/nova/api/openstack/compute/server_topology.py index 7df0dd024182..236d5384c5e6 100644 --- a/nova/api/openstack/compute/server_topology.py +++ b/nova/api/openstack/compute/server_topology.py @@ -28,7 +28,8 @@ class ServerTopologyController(wsgi.Controller): @wsgi.api_version("2.78") @wsgi.expected_errors(404) - @validation.query_schema(schema.query_params_v21) + @validation.query_schema(schema.index_query, '2.78', '2.101') + @validation.query_schema(schema.index_query_v2102, '2.102') @validation.response_body_schema(schema.index_response) def index(self, req, server_id): context = req.environ["nova.context"] diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py index 96f2a551d4bd..5e5e2205f0c0 100644 --- a/nova/api/openstack/compute/servers.py +++ b/nova/api/openstack/compute/servers.py @@ -114,11 +114,11 @@ class ServersController(wsgi.Controller): self.compute_api = compute.API() @wsgi.expected_errors((400, 403)) - @validation.query_schema(schema.query_params_v21, '2.1', '2.25') - @validation.query_schema(schema.query_params_v226, '2.26', '2.65') - @validation.query_schema(schema.query_params_v266, '2.66', '2.72') - @validation.query_schema(schema.query_params_v273, '2.73', '2.74') - @validation.query_schema(schema.query_params_v275, '2.75') + @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): @@ -132,11 +132,11 @@ class ServersController(wsgi.Controller): return servers @wsgi.expected_errors((400, 403)) - @validation.query_schema(schema.query_params_v21, '2.1', '2.25') - @validation.query_schema(schema.query_params_v226, '2.26', '2.65') - @validation.query_schema(schema.query_params_v266, '2.66', '2.72') - @validation.query_schema(schema.query_params_v273, '2.73', '2.74') - @validation.query_schema(schema.query_params_v275, '2.75') + @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') @@ -474,7 +474,8 @@ class ServersController(wsgi.Controller): return objects.NetworkRequestList(objects=networks) @wsgi.expected_errors(404) - @validation.query_schema(schema.show_query) + @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') diff --git a/nova/tests/unit/api/openstack/compute/test_aggregates.py b/nova/tests/unit/api/openstack/compute/test_aggregates.py index 15993c67c17d..ffffc987c519 100644 --- a/nova/tests/unit/api/openstack/compute/test_aggregates.py +++ b/nova/tests/unit/api/openstack/compute/test_aggregates.py @@ -106,17 +106,14 @@ class AggregateTestCaseV21(test.NoDBTestCase): set_metadata = 'self.controller._set_metadata' bad_request = exception.ValidationError - def _set_up(self): + def setUp(self): + super().setUp() self.controller = aggregates_v21.AggregateController() self.req = fakes.HTTPRequest.blank('/v2.1/os-aggregates', use_admin_context=True) self.user_req = fakes.HTTPRequest.blank('/v2.1/os-aggregates') self.context = self.req.environ['nova.context'] - def setUp(self): - super(AggregateTestCaseV21, self).setUp() - self._set_up() - def test_index(self): def _list_aggregates(context): if context is None: @@ -130,6 +127,15 @@ class AggregateTestCaseV21(test.NoDBTestCase): self._assert_agg_data(AGGREGATE_LIST, _make_agg_list(result)) self.assertTrue(mock_list.called) + def test_index_invalid_query_params(self): + req = fakes.HTTPRequest.blank( + '/v2/os-aggregates?unknown=1', + use_admin_context=True, + version='2.102') + self.assertRaises( + exception.ValidationError, self.controller.index, req + ) + def test_create(self): with mock.patch.object(self.controller.api, 'create_aggregate', return_value=AGGREGATE) as mock_create: @@ -293,6 +299,15 @@ class AggregateTestCaseV21(test.NoDBTestCase): self._assert_agg_data(AGGREGATE, _make_agg_obj(aggregate)) mock_get.assert_called_once_with(self.context, '1') + def test_show_invalid_query_params(self): + req = fakes.HTTPRequest.blank( + '/v2/os-aggregates/1?unknown=1', + use_admin_context=True, + version='2.102') + self.assertRaises( + exception.ValidationError, self.controller.show, req, '1' + ) + def test_show_with_bad_aggregate(self): side_effect = exception.AggregateNotFound(aggregate_id='2') with mock.patch.object(self.controller.api, 'get_aggregate', diff --git a/nova/tests/unit/api/openstack/compute/test_attach_interfaces.py b/nova/tests/unit/api/openstack/compute/test_attach_interfaces.py index 56404ab970e5..f7b19d7d5957 100644 --- a/nova/tests/unit/api/openstack/compute/test_attach_interfaces.py +++ b/nova/tests/unit/api/openstack/compute/test_attach_interfaces.py @@ -184,6 +184,29 @@ class InterfaceAttachTestsV21(test.NoDBTestCase): self.attachments.show, self.req, FAKE_UUID1, FAKE_PORT_ID1) + def test_show_invalid_query_params(self): + req = fakes.HTTPRequest.blank( + f'/servers/{FAKE_UUID1}/os-interface/{FAKE_PORT_ID1}?invalid=1', + use_admin_context=True, version='2.102') + self.assertRaises( + exception.ValidationError, + self.attachments.show, + req, + FAKE_UUID1, + FAKE_PORT_ID1, + ) + + def test_index_invalid_query_params(self): + req = fakes.HTTPRequest.blank( + f'/servers/{FAKE_UUID1}/os-interface?invalid=1', + use_admin_context=True, version='2.102') + self.assertRaises( + exception.ValidationError, + self.attachments.index, + req, + FAKE_UUID1, + ) + def test_delete(self): self.stub_out('nova.compute.api.API.detach_interface', fake_detach_interface) diff --git a/nova/tests/unit/api/openstack/compute/test_availability_zone.py b/nova/tests/unit/api/openstack/compute/test_availability_zone.py index 334173f2a692..52a2e69fa07e 100644 --- a/nova/tests/unit/api/openstack/compute/test_availability_zone.py +++ b/nova/tests/unit/api/openstack/compute/test_availability_zone.py @@ -128,6 +128,14 @@ class AvailabilityZoneApiTestV21(test.NoDBTestCase): self.assertFalse(zones[1]['zoneState']['available']) self.assertIsNone(zones[1]['hosts']) + def test_availability_zone_index_invalid_query_params(self): + req = fakes.HTTPRequest.blank('?invalid=1', version='2.102') + self.assertRaises( + exception.ValidationError, + self.controller.index, + req, + ) + def test_availability_zone_detail(self): req = fakes.HTTPRequest.blank('') resp_dict = self.controller.detail(req) @@ -191,6 +199,14 @@ class AvailabilityZoneApiTestV21(test.NoDBTestCase): self.assertThat(resp_dict, matchers.DictMatches(expected_response)) + def test_availability_zone_detail_invalid_query_params(self): + req = fakes.HTTPRequest.blank('?invalid=1', version='2.102') + self.assertRaises( + exception.ValidationError, + self.controller.index, + req, + ) + class ServersControllerCreateTestV21(test.TestCase): base_url = '/v2.1' diff --git a/nova/tests/unit/api/openstack/compute/test_extension_info.py b/nova/tests/unit/api/openstack/compute/test_extension_info.py index 0f9ba7726558..2f1b09a86ab4 100644 --- a/nova/tests/unit/api/openstack/compute/test_extension_info.py +++ b/nova/tests/unit/api/openstack/compute/test_extension_info.py @@ -15,6 +15,7 @@ import webob from nova.api.openstack.compute import extension_info +from nova import exception from nova import test from nova.tests.unit.api.openstack import fakes @@ -25,7 +26,24 @@ class ExtensionInfoV21Test(test.NoDBTestCase): super(ExtensionInfoV21Test, self).setUp() self.controller = extension_info.ExtensionInfoController() - def test_extension_info_show_servers_not_present(self): + def test_extension_info_index_invalid_query_params(self): + req = fakes.HTTPRequest.blank('?invalid=1', version='2.102') + self.assertRaises( + exception.ValidationError, + self.controller.index, + req, + ) + + def test_extension_info_show_extension_not_present(self): req = fakes.HTTPRequest.blank('/extensions/servers') self.assertRaises(webob.exc.HTTPNotFound, self.controller.show, req, 'servers') + + def test_extension_info_show_invalid_query_params(self): + req = fakes.HTTPRequest.blank('?invalid=1', version='2.102') + self.assertRaises( + exception.ValidationError, + self.controller.show, + req, + 'servers', + ) diff --git a/nova/tests/unit/api/openstack/compute/test_flavors.py b/nova/tests/unit/api/openstack/compute/test_flavors.py index e085a244f2a9..0699c67293fe 100644 --- a/nova/tests/unit/api/openstack/compute/test_flavors.py +++ b/nova/tests/unit/api/openstack/compute/test_flavors.py @@ -839,8 +839,7 @@ class FlavorsTestV275(FlavorsTestV261): @mock.patch('nova.objects.Flavor.get_by_flavor_id') def test_show_flavor_default_swap_value_old_version(self, mock_get): mock_get.return_value = self.FLAVOR_WITH_NO_SWAP - req = fakes.HTTPRequestV21.blank( - '/flavors/detail?limit=1', version='2.74') + req = fakes.HTTPRequestV21.blank('/flavors/1', version='2.74') response = self.controller.show(req, 1) response_list = response["flavor"] self.assertEqual(response_list['swap'], "") @@ -859,7 +858,7 @@ class FlavorsTestV275(FlavorsTestV261): def test_show_flavor_default_swap_value(self, mock_get): mock_get.return_value = self.FLAVOR_WITH_NO_SWAP req = fakes.HTTPRequestV21.blank( - '/flavors/detail?limit=1', version=self.microversion) + '/flavors/1', version=self.microversion) response = self.controller.show(req, 1) response_list = response["flavor"] self.assertEqual(response_list['swap'], 0) @@ -943,6 +942,33 @@ class FlavorsTestV2102(FlavorsTestV275): self.omit_legacy_fields = False super().test_list_detail_flavors_with_additional_filter_old_version() + def test_list_flavor_invalid_query_params(self): + req = fakes.HTTPRequest.blank( + '/flavors?unknown=1', + use_admin_context=True, + version='2.102') + self.assertRaises( + exception.ValidationError, self.controller.index, req + ) + + def test_detail_flavor_invalid_query_params(self): + req = fakes.HTTPRequest.blank( + '/flavors/detail?unknown=1', + use_admin_context=True, + version='2.102') + self.assertRaises( + exception.ValidationError, self.controller.detail, req + ) + + def test_show_flavor_invalid_query_params(self): + req = fakes.HTTPRequest.blank( + '/flavors/123?unknown=1', + use_admin_context=True, + version='2.102') + self.assertRaises( + exception.ValidationError, self.controller.show, req, '123' + ) + 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 ad071ce189ea..3a92d41da40a 100644 --- a/releasenotes/notes/flavor-name-search-4133a0788bd1c37f.yaml +++ b/releasenotes/notes/flavor-name-search-4133a0788bd1c37f.yaml @@ -8,4 +8,6 @@ features: 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. + field can no longer be provided when creating a server. 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.