Merge "api: Add response body schemas for servers APIs (3/6)"

This commit is contained in:
Zuul
2026-02-24 23:57:05 +00:00
committed by Gerrit Code Review
4 changed files with 175 additions and 17 deletions

View File

@@ -752,6 +752,8 @@ _server_status = {
'SHUTOFF',
'SOFT_DELETED',
'SUSPENDED',
# UNKNOWN can be returned if the DB is corrupt
'UNKNOWN',
'VERIFY_RESIZE',
],
}
@@ -862,6 +864,24 @@ _server_cell_down_response = {
'additionalProperties': False,
}
_server_detail_cell_down_response = copy.deepcopy(_server_cell_down_response)
del _server_detail_cell_down_response['properties']['flavor']
del _server_detail_cell_down_response['properties']['image']
del _server_detail_cell_down_response['properties']['user_id']
del _server_detail_cell_down_response['properties'][
'OS-EXT-AZ:availability_zone'
]
del _server_detail_cell_down_response['properties']['OS-EXT-STS:power_state']
_server_detail_cell_down_response['required'].remove('flavor')
_server_detail_cell_down_response['required'].remove('image')
_server_detail_cell_down_response['required'].remove('user_id')
_server_detail_cell_down_response['required'].remove(
'OS-EXT-AZ:availability_zone'
)
_server_detail_cell_down_response['required'].remove(
'OS-EXT-STS:power_state'
)
_server_cell_down_response_v271 = copy.deepcopy(_server_cell_down_response)
_server_cell_down_response_v271['properties'].update({
'server_groups': {
@@ -1054,7 +1074,7 @@ _server_response_v23 = copy.deepcopy(_server_response)
_server_response_v23['properties'].update({
'OS-EXT-SRV-ATTR:hostname': {'type': 'string'},
'OS-EXT-SRV-ATTR:kernel_id': {'type': ['string', 'null']},
'OS-EXT-SRV-ATTR:launch_index': {'type': 'integer'},
'OS-EXT-SRV-ATTR:launch_index': {'type': ['integer', 'null']},
'OS-EXT-SRV-ATTR:ramdisk_id': {'type': ['string', 'null']},
'OS-EXT-SRV-ATTR:reservation_id': {'type': ['string', 'null']},
'OS-EXT-SRV-ATTR:root_device_name': {'type': ['string', 'null']},
@@ -1137,6 +1157,9 @@ _server_response_v263['properties'].update({
})
_server_response_v263['required'].append('trusted_image_certificates')
# Unfortunately from here the server show and server detail list views differ
# since server_groups are not shown for the latter. We should remedy that but
# for now, we need to take different paths.
_server_response_v271 = copy.deepcopy(_server_response_v263)
_server_response_v271['properties'].update({
'server_groups': {
@@ -1153,15 +1176,31 @@ _server_response_v273['properties'].update({
})
_server_response_v273['required'].append('locked_reason')
# Note that we based on v2.63 to exclude the server_groups addition
_server_detail_response_v273 = copy.deepcopy(_server_response_v263)
_server_detail_response_v273['properties'].update({
'locked_reason': {'type': ['null', 'string']},
})
_server_detail_response_v273['required'].append('locked_reason')
_server_response_v290 = copy.deepcopy(_server_response_v273)
_server_response_v290['required'].append('OS-EXT-SRV-ATTR:hostname')
_server_detail_response_v290 = copy.deepcopy(_server_detail_response_v273)
_server_detail_response_v290['required'].append('OS-EXT-SRV-ATTR:hostname')
_server_response_v296 = copy.deepcopy(_server_response_v290)
_server_response_v296['properties'].update({
'pinned_availability_zone': {'type': ['string', 'null']},
})
_server_response_v296['required'].append('pinned_availability_zone')
_server_detail_response_v296 = copy.deepcopy(_server_detail_response_v290)
_server_detail_response_v296['properties'].update({
'pinned_availability_zone': {'type': ['string', 'null']},
})
_server_detail_response_v296['required'].append('pinned_availability_zone')
_server_response_v298 = copy.deepcopy(_server_response_v296)
_server_response_v298['properties']['image']['oneOf'][1]['properties'].update({
'properties': {
@@ -1176,12 +1215,115 @@ _server_response_v298['properties']['image']['oneOf'][1]['properties'].update({
},
})
_server_detail_response_v298 = copy.deepcopy(_server_detail_response_v296)
_server_detail_response_v298['properties']['image']['oneOf'][1][
'properties'
].update({
'properties': {
'type': 'object',
'patternProperties': {
'^[a-zA-Z0-9_:. ]{1,255}$': {
'type': ['string', 'null'],
'maxLength': 255,
},
},
'additionalProperties': False,
},
})
_server_response_v2100 = copy.deepcopy(_server_response_v298)
_server_response_v2100['properties'].update({
'scheduler_hints': _hints,
})
_server_response_v2100['required'].append('scheduler_hints')
_server_detail_response_v2100 = copy.deepcopy(_server_detail_response_v298)
_server_detail_response_v2100['properties'].update({
'scheduler_hints': _hints,
})
_server_detail_response_v2100['required'].append('scheduler_hints')
detail_response = {
'type': 'object',
'properties': {
'servers': {
'type': 'array',
'items': _server_response,
},
'servers_links': response_types.collection_links,
},
'required': ['servers'],
'additionalProperties': False,
}
detail_response_v23 = copy.deepcopy(detail_response)
detail_response_v23['properties']['servers']['items'] = (
_server_response_v23
)
detail_response_v29 = copy.deepcopy(detail_response_v23)
detail_response_v29['properties']['servers']['items'] = (
_server_response_v29
)
detail_response_v216 = copy.deepcopy(detail_response_v29)
detail_response_v216['properties']['servers']['items'] = (
_server_response_v216
)
detail_response_v219 = copy.deepcopy(detail_response_v216)
detail_response_v219['properties']['servers']['items'] = (
_server_response_v219
)
detail_response_v226 = copy.deepcopy(detail_response_v219)
detail_response_v226['properties']['servers']['items'] = (
_server_response_v226
)
detail_response_v247 = copy.deepcopy(detail_response_v226)
detail_response_v247['properties']['servers']['items'] = (
_server_response_v247
)
detail_response_v263 = copy.deepcopy(detail_response_v247)
detail_response_v263['properties']['servers']['items'] = (
_server_response_v263
)
# this is the first version to introduce down cell support. We model this as an
# entirely different schema rather than making most of the fields optional
detail_response_v269 = copy.deepcopy(detail_response_v263)
detail_response_v269['properties']['servers']['items'] = {
'oneOf': [_server_response_v263, _server_detail_cell_down_response],
}
detail_response_v273 = copy.deepcopy(detail_response_v263)
detail_response_v273['properties']['servers']['items'] = {
'oneOf': [_server_detail_response_v273, _server_detail_cell_down_response],
}
detail_response_v290 = copy.deepcopy(detail_response_v273)
detail_response_v290['properties']['servers']['items'] = {
'oneOf': [_server_detail_response_v290, _server_detail_cell_down_response],
}
detail_response_v296 = copy.deepcopy(detail_response_v290)
detail_response_v296['properties']['servers']['items'] = {
'oneOf': [_server_detail_response_v296, _server_detail_cell_down_response],
}
detail_response_v298 = copy.deepcopy(detail_response_v296)
detail_response_v298['properties']['servers']['items'] = {
'oneOf': [_server_detail_response_v298, _server_detail_cell_down_response],
}
detail_response_v2100 = copy.deepcopy(detail_response_v298)
detail_response_v2100['properties']['servers']['items'] = {
'oneOf': [
_server_detail_response_v2100, _server_detail_cell_down_response
],
}
show_response = {
'type': 'object',
@@ -1501,7 +1643,7 @@ rebuild_response_v275['properties']['server']['properties'].update(
'OS-EXT-SRV-ATTR:hypervisor_hostname': {'type': ['string', 'null']},
'OS-EXT-SRV-ATTR:instance_name': {'type': 'string'},
'OS-EXT-SRV-ATTR:kernel_id': {'type': ['string', 'null']},
'OS-EXT-SRV-ATTR:launch_index': {'type': 'integer'},
'OS-EXT-SRV-ATTR:launch_index': {'type': ['integer', 'null']},
'OS-EXT-SRV-ATTR:ramdisk_id': {'type': ['string', 'null']},
'OS-EXT-SRV-ATTR:reservation_id': {'type': ['string', 'null']},
'OS-EXT-SRV-ATTR:root_device_name': {'type': ['string', 'null']},

View File

@@ -131,11 +131,25 @@ class ServersController(wsgi.Controller):
return servers
@wsgi.expected_errors((400, 403))
@validation.query_schema(schema.query_params_v275, '2.75')
@validation.query_schema(schema.query_params_v273, '2.73', '2.74')
@validation.query_schema(schema.query_params_v266, '2.66', '2.72')
@validation.query_schema(schema.query_params_v226, '2.26', '2.65')
@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.response_body_schema(schema.detail_response, '2.1', '2.2')
@validation.response_body_schema(schema.detail_response_v23, '2.3', '2.8')
@validation.response_body_schema(schema.detail_response_v29, '2.9', '2.15')
@validation.response_body_schema(schema.detail_response_v216, '2.16', '2.18') # noqa: E501
@validation.response_body_schema(schema.detail_response_v219, '2.19', '2.25') # noqa: E501
@validation.response_body_schema(schema.detail_response_v226, '2.26', '2.46') # noqa: E501
@validation.response_body_schema(schema.detail_response_v247, '2.47', '2.62') # noqa: E501
@validation.response_body_schema(schema.detail_response_v263, '2.63', '2.68') # noqa: E501
@validation.response_body_schema(schema.detail_response_v269, '2.69', '2.72') # noqa: E501
@validation.response_body_schema(schema.detail_response_v273, '2.73', '2.89') # noqa: E501
@validation.response_body_schema(schema.detail_response_v290, '2.90', '2.95') # noqa: E501
@validation.response_body_schema(schema.detail_response_v296, '2.96', '2.97') # noqa: E501
@validation.response_body_schema(schema.detail_response_v298, '2.98', '2.99') # noqa: E501
@validation.response_body_schema(schema.detail_response_v2100, '2.100')
def detail(self, req):
"""Returns a list of server details for a given user."""
context = req.environ['nova.context']

View File

@@ -1732,8 +1732,8 @@ class ServersControllerTest(_ServersControllerTest):
return objects.InstanceList(
objects=[fakes.stub_instance_obj(None,
id=i + 1,
user_id='fake',
project_id='fake',
user_id=uuids.user_id,
project_id=uuids.project_id,
host=i % 2,
uuid=fakes.get_fake_uuid(i))
for i in range(5)])

View File

@@ -78,8 +78,8 @@ class ServersPolicyTest(base.BasePolicyTest):
hostname='foo', launch_index=0)
self.mock_flavor = self.useFixture(
fixtures.MockPatch('nova.compute.flavors.get_flavor_by_flavor_id'
)).mock
fixtures.MockPatch('nova.compute.flavors.get_flavor_by_flavor_id')
).mock
self.mock_flavor.return_value = fake_flavor.fake_flavor_obj(
self.req.environ['nova.context'], flavorid='1')
@@ -109,12 +109,13 @@ class ServersPolicyTest(base.BasePolicyTest):
)
)
self.servers = [fakes.stub_instance_obj(
1, vm_state=vm_states.ACTIVE, uuid=uuids.fake,
project_id=self.project_id, user_id='user1'),
fakes.stub_instance_obj(
2, vm_state=vm_states.ACTIVE, uuid=uuids.fake,
project_id='proj2', user_id='user2')]
self.servers = [
fakes.stub_instance_obj(
1, vm_state=vm_states.ACTIVE, uuid=uuids.fake,
project_id=self.project_id, user_id=uuids.user_a_id),
fakes.stub_instance_obj(
2, vm_state=vm_states.ACTIVE, uuid=uuids.fake,
project_id=self.project_id_other, user_id=uuids.user_b_id)]
fakes.stub_out_secgroup_api(
self, security_groups=[{'name': 'default'}])
self.mock_get_all = self.useFixture(fixtures.MockPatchObject(
@@ -126,7 +127,8 @@ class ServersPolicyTest(base.BasePolicyTest):
'flavorRef': uuids.fake_id,
},
}
self.extended_attr = ['OS-EXT-SRV-ATTR:host',
self.extended_attr = [
'OS-EXT-SRV-ATTR:host',
'OS-EXT-SRV-ATTR:hypervisor_hostname',
'OS-EXT-SRV-ATTR:instance_name',
'OS-EXT-SRV-ATTR:hostname',