api: Add response body schemas for servers APIs (3/6)
Next up, the detail view. The benefits from being a carbon copy of the show view. Change-Id: I5bd2a3f41c8814f338a15aff4de8edbbd185186b Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
@@ -752,6 +752,8 @@ _server_status = {
|
|||||||
'SHUTOFF',
|
'SHUTOFF',
|
||||||
'SOFT_DELETED',
|
'SOFT_DELETED',
|
||||||
'SUSPENDED',
|
'SUSPENDED',
|
||||||
|
# UNKNOWN can be returned if the DB is corrupt
|
||||||
|
'UNKNOWN',
|
||||||
'VERIFY_RESIZE',
|
'VERIFY_RESIZE',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@@ -862,6 +864,24 @@ _server_cell_down_response = {
|
|||||||
'additionalProperties': False,
|
'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 = copy.deepcopy(_server_cell_down_response)
|
||||||
_server_cell_down_response_v271['properties'].update({
|
_server_cell_down_response_v271['properties'].update({
|
||||||
'server_groups': {
|
'server_groups': {
|
||||||
@@ -1054,7 +1074,7 @@ _server_response_v23 = copy.deepcopy(_server_response)
|
|||||||
_server_response_v23['properties'].update({
|
_server_response_v23['properties'].update({
|
||||||
'OS-EXT-SRV-ATTR:hostname': {'type': 'string'},
|
'OS-EXT-SRV-ATTR:hostname': {'type': 'string'},
|
||||||
'OS-EXT-SRV-ATTR:kernel_id': {'type': ['string', 'null']},
|
'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:ramdisk_id': {'type': ['string', 'null']},
|
||||||
'OS-EXT-SRV-ATTR:reservation_id': {'type': ['string', 'null']},
|
'OS-EXT-SRV-ATTR:reservation_id': {'type': ['string', 'null']},
|
||||||
'OS-EXT-SRV-ATTR:root_device_name': {'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')
|
_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 = copy.deepcopy(_server_response_v263)
|
||||||
_server_response_v271['properties'].update({
|
_server_response_v271['properties'].update({
|
||||||
'server_groups': {
|
'server_groups': {
|
||||||
@@ -1153,15 +1176,31 @@ _server_response_v273['properties'].update({
|
|||||||
})
|
})
|
||||||
_server_response_v273['required'].append('locked_reason')
|
_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 = copy.deepcopy(_server_response_v273)
|
||||||
_server_response_v290['required'].append('OS-EXT-SRV-ATTR:hostname')
|
_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 = copy.deepcopy(_server_response_v290)
|
||||||
_server_response_v296['properties'].update({
|
_server_response_v296['properties'].update({
|
||||||
'pinned_availability_zone': {'type': ['string', 'null']},
|
'pinned_availability_zone': {'type': ['string', 'null']},
|
||||||
})
|
})
|
||||||
_server_response_v296['required'].append('pinned_availability_zone')
|
_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 = copy.deepcopy(_server_response_v296)
|
||||||
_server_response_v298['properties']['image']['oneOf'][1]['properties'].update({
|
_server_response_v298['properties']['image']['oneOf'][1]['properties'].update({
|
||||||
'properties': {
|
'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 = copy.deepcopy(_server_response_v298)
|
||||||
_server_response_v2100['properties'].update({
|
_server_response_v2100['properties'].update({
|
||||||
'scheduler_hints': _hints,
|
'scheduler_hints': _hints,
|
||||||
})
|
})
|
||||||
_server_response_v2100['required'].append('scheduler_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 = {
|
show_response = {
|
||||||
'type': 'object',
|
'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:hypervisor_hostname': {'type': ['string', 'null']},
|
||||||
'OS-EXT-SRV-ATTR:instance_name': {'type': 'string'},
|
'OS-EXT-SRV-ATTR:instance_name': {'type': 'string'},
|
||||||
'OS-EXT-SRV-ATTR:kernel_id': {'type': ['string', 'null']},
|
'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:ramdisk_id': {'type': ['string', 'null']},
|
||||||
'OS-EXT-SRV-ATTR:reservation_id': {'type': ['string', 'null']},
|
'OS-EXT-SRV-ATTR:reservation_id': {'type': ['string', 'null']},
|
||||||
'OS-EXT-SRV-ATTR:root_device_name': {'type': ['string', 'null']},
|
'OS-EXT-SRV-ATTR:root_device_name': {'type': ['string', 'null']},
|
||||||
|
|||||||
@@ -131,11 +131,25 @@ class ServersController(wsgi.Controller):
|
|||||||
return servers
|
return servers
|
||||||
|
|
||||||
@wsgi.expected_errors((400, 403))
|
@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_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):
|
def detail(self, req):
|
||||||
"""Returns a list of server details for a given user."""
|
"""Returns a list of server details for a given user."""
|
||||||
context = req.environ['nova.context']
|
context = req.environ['nova.context']
|
||||||
|
|||||||
@@ -1732,8 +1732,8 @@ class ServersControllerTest(_ServersControllerTest):
|
|||||||
return objects.InstanceList(
|
return objects.InstanceList(
|
||||||
objects=[fakes.stub_instance_obj(None,
|
objects=[fakes.stub_instance_obj(None,
|
||||||
id=i + 1,
|
id=i + 1,
|
||||||
user_id='fake',
|
user_id=uuids.user_id,
|
||||||
project_id='fake',
|
project_id=uuids.project_id,
|
||||||
host=i % 2,
|
host=i % 2,
|
||||||
uuid=fakes.get_fake_uuid(i))
|
uuid=fakes.get_fake_uuid(i))
|
||||||
for i in range(5)])
|
for i in range(5)])
|
||||||
|
|||||||
@@ -78,8 +78,8 @@ class ServersPolicyTest(base.BasePolicyTest):
|
|||||||
hostname='foo', launch_index=0)
|
hostname='foo', launch_index=0)
|
||||||
|
|
||||||
self.mock_flavor = self.useFixture(
|
self.mock_flavor = self.useFixture(
|
||||||
fixtures.MockPatch('nova.compute.flavors.get_flavor_by_flavor_id'
|
fixtures.MockPatch('nova.compute.flavors.get_flavor_by_flavor_id')
|
||||||
)).mock
|
).mock
|
||||||
self.mock_flavor.return_value = fake_flavor.fake_flavor_obj(
|
self.mock_flavor.return_value = fake_flavor.fake_flavor_obj(
|
||||||
self.req.environ['nova.context'], flavorid='1')
|
self.req.environ['nova.context'], flavorid='1')
|
||||||
|
|
||||||
@@ -109,12 +109,13 @@ class ServersPolicyTest(base.BasePolicyTest):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.servers = [fakes.stub_instance_obj(
|
self.servers = [
|
||||||
1, vm_state=vm_states.ACTIVE, uuid=uuids.fake,
|
fakes.stub_instance_obj(
|
||||||
project_id=self.project_id, user_id='user1'),
|
1, vm_state=vm_states.ACTIVE, uuid=uuids.fake,
|
||||||
fakes.stub_instance_obj(
|
project_id=self.project_id, user_id=uuids.user_a_id),
|
||||||
2, vm_state=vm_states.ACTIVE, uuid=uuids.fake,
|
fakes.stub_instance_obj(
|
||||||
project_id='proj2', user_id='user2')]
|
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(
|
fakes.stub_out_secgroup_api(
|
||||||
self, security_groups=[{'name': 'default'}])
|
self, security_groups=[{'name': 'default'}])
|
||||||
self.mock_get_all = self.useFixture(fixtures.MockPatchObject(
|
self.mock_get_all = self.useFixture(fixtures.MockPatchObject(
|
||||||
@@ -126,7 +127,8 @@ class ServersPolicyTest(base.BasePolicyTest):
|
|||||||
'flavorRef': uuids.fake_id,
|
'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:hypervisor_hostname',
|
||||||
'OS-EXT-SRV-ATTR:instance_name',
|
'OS-EXT-SRV-ATTR:instance_name',
|
||||||
'OS-EXT-SRV-ATTR:hostname',
|
'OS-EXT-SRV-ATTR:hostname',
|
||||||
|
|||||||
Reference in New Issue
Block a user