diff --git a/api-ref/source/parameters.yaml b/api-ref/source/parameters.yaml index 05066afd00c9..9a530cffbe7d 100644 --- a/api-ref/source/parameters.yaml +++ b/api-ref/source/parameters.yaml @@ -6127,6 +6127,14 @@ running_vms_total: in: body required: true type: integer +scheduler_hints: + description: | + The dictionary of hints sent to the scheduler during server + creation time. + in: body + required: true + type: object + min_version: 2.100 secgroup_default_rule_id: description: | The security group default rule ID. diff --git a/api-ref/source/servers-actions.inc b/api-ref/source/servers-actions.inc index f318f0ed9f0d..df10bd030bac 100644 --- a/api-ref/source/servers-actions.inc +++ b/api-ref/source/servers-actions.inc @@ -675,10 +675,15 @@ Response - os-extended-volumes:volumes_attached.delete_on_termination: os-extended-volumes:volumes_attached.delete_on_termination_update_rebuild - OS-SRV-USG:launched_at: OS-SRV-USG:launched_at_update_rebuild - OS-SRV-USG:terminated_at: OS-SRV-USG:terminated_at_update_rebuild + - scheduler_hints: scheduler_hints - security_groups: security_groups_obj_update_rebuild - security_group.name: name_update_rebuild - host_status: host_status_update_rebuild +**Example Rebuild Server (rebuild Action) (v2.100)** + +.. literalinclude:: /../../doc/api_samples/servers/v2.100/server-action-rebuild-resp.json + **Example Rebuild Server (rebuild Action) (v2.98)** .. literalinclude:: ../../doc/api_samples/servers/v2.98/server-action-rebuild-resp.json diff --git a/api-ref/source/servers.inc b/api-ref/source/servers.inc index c64ea7515f62..aa9cdfd8812e 100644 --- a/api-ref/source/servers.inc +++ b/api-ref/source/servers.inc @@ -671,6 +671,7 @@ Response - fault.details: fault_details - pinned_availability_zone: pinned_availability_zone - progress: progress + - scheduler_hints: scheduler_hints - security_groups: security_groups_obj_optional - security_group.name: name - servers_links: servers_links @@ -681,6 +682,11 @@ Response - trusted_image_certificates: server_trusted_image_certificates_resp - locked_reason: locked_reason_resp +**Example List Servers Detailed (2.100)** + +.. literalinclude:: /../../doc/api_samples/servers/v2.100/servers-details-resp.json + :language: javascript + **Example List Servers Detailed (2.98)** .. literalinclude:: /../../doc/api_samples/servers/v2.98/servers-details-resp.json @@ -806,6 +812,7 @@ Response - fault.details: fault_details - pinned_availability_zone: pinned_availability_zone - progress: progress + - scheduler_hints: scheduler_hints - security_groups: security_groups_obj_optional - security_group.name: name - locked: locked @@ -816,6 +823,11 @@ Response - server_groups: server_groups_2_71 - locked_reason: locked_reason_resp +**Example Show Server Details (2.100)** + +.. literalinclude:: ../../doc/api_samples/servers/v2.100/server-get-resp.json + :language: javascript + **Example Show Server Details (2.98)** .. literalinclude:: ../../doc/api_samples/servers/v2.98/server-get-resp.json diff --git a/doc/api_samples/servers/v2.100/server-action-rebuild-resp.json b/doc/api_samples/servers/v2.100/server-action-rebuild-resp.json new file mode 100644 index 000000000000..a44dc1327e9e --- /dev/null +++ b/doc/api_samples/servers/v2.100/server-action-rebuild-resp.json @@ -0,0 +1,97 @@ +{ + "server": { + "OS-DCF:diskConfig": "AUTO", + "OS-EXT-AZ:availability_zone": "us-west", + "OS-EXT-SRV-ATTR:hostname": "updated-hostname.example.com", + "OS-EXT-STS:power_state": 1, + "OS-EXT-STS:task_state": null, + "OS-EXT-STS:vm_state": "active", + "OS-SRV-USG:launched_at": "2021-08-19T15:16:22.177882", + "OS-SRV-USG:terminated_at": null, + "accessIPv4": "1.2.3.4", + "accessIPv6": "80fe::", + "addresses": { + "private": [ + { + "OS-EXT-IPS-MAC:mac_addr": "00:0c:29:0d:11:74", + "OS-EXT-IPS:type": "fixed", + "addr": "192.168.1.30", + "version": 4 + } + ] + }, + "adminPass": "seekr3t", + "config_drive": "", + "created": "2019-04-23T17:10:22Z", + "description": null, + "flavor": { + "disk": 1, + "ephemeral": 0, + "extra_specs": {}, + "original_name": "m1.tiny", + "ram": 512, + "swap": 0, + "vcpus": 1 + }, + "hostId": "2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6", + "id": "0c37a84a-c757-4f22-8c7f-0bf8b6970886", + "image": { + "id": "70a599e0-31e7-49b7-b260-868f441e862b", + "links": [ + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "bookmark" + } + ], + "properties": { + "architecture": "x86_64", + "auto_disk_config": "True", + "base_image_ref": "70a599e0-31e7-49b7-b260-868f441e862b", + "container_format": "ova", + "disk_format": "vhd", + "kernel_id": "nokernel", + "min_disk": "1", + "min_ram": "0", + "ramdisk_id": "nokernel" + } + }, + "key_name": null, + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/0c37a84a-c757-4f22-8c7f-0bf8b6970886", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/0c37a84a-c757-4f22-8c7f-0bf8b6970886", + "rel": "bookmark" + } + ], + "locked": false, + "locked_reason": null, + "metadata": { + "meta_var": "meta_val" + }, + "name": "foobar", + "os-extended-volumes:volumes_attached": [], + "progress": 0, + "pinned_availability_zone": "us-west", + "scheduler_hints": { + "same_host": [ + "48e6a9f6-30af-47e0-bc04-acaed113bb4e" + ] + }, + "security_groups": [ + { + "name": "default" + } + ], + "server_groups": [], + "status": "ACTIVE", + "tags": [], + "tenant_id": "6f70656e737461636b20342065766572", + "trusted_image_certificates": null, + "updated": "2019-04-23T17:10:24Z", + "user_data": "ZWNobyAiaGVsbG8gd29ybGQi", + "user_id": "fake" + } +} diff --git a/doc/api_samples/servers/v2.100/server-create-resp.json b/doc/api_samples/servers/v2.100/server-create-resp.json new file mode 100644 index 000000000000..f50e29dd8bef --- /dev/null +++ b/doc/api_samples/servers/v2.100/server-create-resp.json @@ -0,0 +1,22 @@ +{ + "server": { + "OS-DCF:diskConfig": "AUTO", + "adminPass": "6NpUwoz2QDRN", + "id": "f5dc173b-6804-445a-a6d8-c705dad5b5eb", + "links": [ + { + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/servers/f5dc173b-6804-445a-a6d8-c705dad5b5eb", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/f5dc173b-6804-445a-a6d8-c705dad5b5eb", + "rel": "bookmark" + } + ], + "security_groups": [ + { + "name": "default" + } + ] + } +} diff --git a/doc/api_samples/servers/v2.100/server-get-resp.json b/doc/api_samples/servers/v2.100/server-get-resp.json new file mode 100644 index 000000000000..c68a656e486b --- /dev/null +++ b/doc/api_samples/servers/v2.100/server-get-resp.json @@ -0,0 +1,98 @@ +{ + "server": { + "accessIPv4": "1.2.3.4", + "accessIPv6": "80fe::", + "addresses": { + "private": [ + { + "addr": "192.168.1.30", + "OS-EXT-IPS-MAC:mac_addr": "00:0c:29:0d:11:74", + "OS-EXT-IPS:type": "fixed", + "version": 4 + } + ] + }, + "created": "2013-09-03T04:01:32Z", + "description": null, + "locked": false, + "locked_reason": null, + "flavor": { + "disk": 1, + "ephemeral": 0, + "extra_specs": {}, + "original_name": "m1.tiny", + "ram": 512, + "swap": 0, + "vcpus": 1 + }, + "hostId": "92154fab69d5883ba2c8622b7e65f745dd33257221c07af363c51b29", + "id": "0e44cc9c-e052-415d-afbf-469b0d384170", + "image": { + "id": "70a599e0-31e7-49b7-b260-868f441e862b", + "links": [ + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "bookmark" + } + ], + "properties": { + "architecture": "x86_64", + "auto_disk_config": "True", + "base_image_ref": "70a599e0-31e7-49b7-b260-868f441e862b", + "container_format": "ova", + "disk_format": "vhd", + "kernel_id": "nokernel", + "min_disk": "1", + "min_ram": "0", + "ramdisk_id": "nokernel" + } + }, + "key_name": null, + "links": [ + { + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/servers/0e44cc9c-e052-415d-afbf-469b0d384170", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/0e44cc9c-e052-415d-afbf-469b0d384170", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "config_drive": "", + "OS-DCF:diskConfig": "AUTO", + "OS-EXT-AZ:availability_zone": "us-west", + "OS-EXT-SRV-ATTR:hostname": "new-server-test", + "OS-EXT-STS:power_state": 1, + "OS-EXT-STS:task_state": null, + "OS-EXT-STS:vm_state": "active", + "os-extended-volumes:volumes_attached": [ + {"id": "volume_id1", "delete_on_termination": false}, + {"id": "volume_id2", "delete_on_termination": false} + ], + "OS-SRV-USG:launched_at": "2013-09-23T13:37:00.880302", + "OS-SRV-USG:terminated_at": null, + "pinned_availability_zone": "us-west", + "progress": 0, + "scheduler_hints": { + "same_host": [ + "48e6a9f6-30af-47e0-bc04-acaed113bb4e" + ] + }, + "security_groups": [ + { + "name": "default" + } + ], + "server_groups": [], + "status": "ACTIVE", + "tags": [], + "tenant_id": "6f70656e737461636b20342065766572", + "trusted_image_certificates": null, + "updated": "2013-09-03T04:01:33Z", + "user_id": "fake" + } +} diff --git a/doc/api_samples/servers/v2.100/server-update-req.json b/doc/api_samples/servers/v2.100/server-update-req.json new file mode 100644 index 000000000000..1743f05fc7ce --- /dev/null +++ b/doc/api_samples/servers/v2.100/server-update-req.json @@ -0,0 +1,8 @@ +{ + "server": { + "accessIPv4": "4.3.2.1", + "accessIPv6": "80fe::", + "OS-DCF:diskConfig": "AUTO", + "hostname" : "new-server-hostname.example.com" + } +} diff --git a/doc/api_samples/servers/v2.100/server-update-resp.json b/doc/api_samples/servers/v2.100/server-update-resp.json new file mode 100644 index 000000000000..d4cad62fa0b3 --- /dev/null +++ b/doc/api_samples/servers/v2.100/server-update-resp.json @@ -0,0 +1,95 @@ +{ + "server": { + "accessIPv4": "1.2.3.4", + "accessIPv6": "80fe::", + "addresses": { + "private": [ + { + "addr": "192.168.1.30", + "OS-EXT-IPS-MAC:mac_addr": "00:0c:29:0d:11:74", + "OS-EXT-IPS:type": "fixed", + "version": 4 + } + ] + }, + "created": "2013-09-03T04:01:32Z", + "description": null, + "locked": false, + "locked_reason": null, + "flavor": { + "disk": 1, + "ephemeral": 0, + "extra_specs": {}, + "original_name": "m1.tiny", + "ram": 512, + "swap": 0, + "vcpus": 1 + }, + "hostId": "92154fab69d5883ba2c8622b7e65f745dd33257221c07af363c51b29", + "id": "0e44cc9c-e052-415d-afbf-469b0d384170", + "image": { + "id": "70a599e0-31e7-49b7-b260-868f441e862b", + "links": [ + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "bookmark" + } + ], + "properties": { + "architecture": "x86_64", + "auto_disk_config": "True", + "base_image_ref": "70a599e0-31e7-49b7-b260-868f441e862b", + "container_format": "ova", + "disk_format": "vhd", + "kernel_id": "nokernel", + "min_disk": "1", + "min_ram": "0", + "ramdisk_id": "nokernel" + } + }, + "key_name": null, + "links": [ + { + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/servers/0e44cc9c-e052-415d-afbf-469b0d384170", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/0e44cc9c-e052-415d-afbf-469b0d384170", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "config_drive": "", + "OS-DCF:diskConfig": "AUTO", + "OS-EXT-AZ:availability_zone": "us-west", + "OS-EXT-SRV-ATTR:hostname": "new-server-hostname.example.com", + "OS-EXT-STS:power_state": 1, + "OS-EXT-STS:task_state": null, + "OS-EXT-STS:vm_state": "active", + "os-extended-volumes:volumes_attached": [], + "OS-SRV-USG:launched_at": "2013-09-23T13:37:00.880302", + "OS-SRV-USG:terminated_at": null, + "pinned_availability_zone": "us-west", + "progress": 0, + "scheduler_hints": { + "same_host": [ + "48e6a9f6-30af-47e0-bc04-acaed113bb4e" + ] + }, + "security_groups": [ + { + "name": "default" + } + ], + "server_groups": [], + "status": "ACTIVE", + "tags": [], + "tenant_id": "6f70656e737461636b20342065766572", + "trusted_image_certificates": null, + "updated": "2013-09-03T04:01:33Z", + "user_id": "fake" + } +} diff --git a/doc/api_samples/servers/v2.100/servers-details-resp.json b/doc/api_samples/servers/v2.100/servers-details-resp.json new file mode 100644 index 000000000000..28bbef41a507 --- /dev/null +++ b/doc/api_samples/servers/v2.100/servers-details-resp.json @@ -0,0 +1,105 @@ +{ + "servers": [ + { + "accessIPv4": "1.2.3.4", + "accessIPv6": "80fe::", + "addresses": { + "private": [ + { + "addr": "192.168.1.30", + "OS-EXT-IPS-MAC:mac_addr": "00:0c:29:0d:11:74", + "OS-EXT-IPS:type": "fixed", + "version": 4 + } + ] + }, + "created": "2013-09-03T04:01:32Z", + "description": "", + "flavor": { + "disk": 1, + "ephemeral": 0, + "extra_specs": {}, + "original_name": "m1.tiny", + "ram": 512, + "swap": 0, + "vcpus": 1 + }, + "hostId": "bcf92836fc9ed4203a75cb0337afc7f917d2be504164b995c2334b25", + "id": "f5dc173b-6804-445a-a6d8-c705dad5b5eb", + "image": { + "id": "70a599e0-31e7-49b7-b260-868f441e862b", + "links": [ + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "bookmark" + } + ], + "properties": { + "architecture": "x86_64", + "auto_disk_config": "True", + "base_image_ref": "70a599e0-31e7-49b7-b260-868f441e862b", + "container_format": "ova", + "disk_format": "vhd", + "kernel_id": "nokernel", + "min_disk": "1", + "min_ram": "0", + "ramdisk_id": "nokernel" + } + }, + "key_name": null, + "links": [ + { + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/servers/f5dc173b-6804-445a-a6d8-c705dad5b5eb", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/f5dc173b-6804-445a-a6d8-c705dad5b5eb", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "config_drive": "", + "locked": false, + "locked_reason": "", + "OS-DCF:diskConfig": "AUTO", + "OS-EXT-AZ:availability_zone": "us-west", + "OS-EXT-SRV-ATTR:hostname": "new-server-test", + "OS-EXT-STS:power_state": 1, + "OS-EXT-STS:task_state": null, + "OS-EXT-STS:vm_state": "active", + "os-extended-volumes:volumes_attached": [ + {"id": "volume_id1", "delete_on_termination": false}, + {"id": "volume_id2", "delete_on_termination": false} + ], + "OS-SRV-USG:launched_at": "2013-09-23T13:53:12.774549", + "OS-SRV-USG:terminated_at": null, + "pinned_availability_zone": "us-west", + "progress": 0, + "scheduler_hints": { + "same_host": [ + "48e6a9f6-30af-47e0-bc04-acaed113bb4e" + ] + }, + "security_groups": [ + { + "name": "default" + } + ], + "status": "ACTIVE", + "tags": [], + "tenant_id": "6f70656e737461636b20342065766572", + "trusted_image_certificates": null, + "updated": "2013-09-03T04:01:32Z", + "user_id": "fake" + } + ], + "servers_links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/detail?limit=1&marker=f5dc173b-6804-445a-a6d8-c705dad5b5eb", + "rel": "next" + } + ] +} diff --git a/doc/api_samples/servers/v2.100/servers-list-resp.json b/doc/api_samples/servers/v2.100/servers-list-resp.json new file mode 100644 index 000000000000..3932f907b989 --- /dev/null +++ b/doc/api_samples/servers/v2.100/servers-list-resp.json @@ -0,0 +1,24 @@ +{ + "servers": [ + { + "id": "3cfb801c-f03c-45ce-834b-d097b34e9534", + "links": [ + { + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/servers/3cfb801c-f03c-45ce-834b-d097b34e9534", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/3cfb801c-f03c-45ce-834b-d097b34e9534", + "rel": "bookmark" + } + ], + "name": "new-server-test" + } + ], + "servers_links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers?limit=1&marker=3cfb801c-f03c-45ce-834b-d097b34e9534", + "rel": "next" + } + ] +} diff --git a/doc/api_samples/versions/v21-version-get-resp.json b/doc/api_samples/versions/v21-version-get-resp.json index 0ad3022d8288..03bed555701c 100644 --- a/doc/api_samples/versions/v21-version-get-resp.json +++ b/doc/api_samples/versions/v21-version-get-resp.json @@ -19,7 +19,7 @@ } ], "status": "CURRENT", - "version": "2.99", + "version": "2.100", "min_version": "2.1", "updated": "2013-07-23T11:33:21Z" } diff --git a/doc/api_samples/versions/versions-get-resp.json b/doc/api_samples/versions/versions-get-resp.json index 3de8614ce66e..87ddf1865ea4 100644 --- a/doc/api_samples/versions/versions-get-resp.json +++ b/doc/api_samples/versions/versions-get-resp.json @@ -22,7 +22,7 @@ } ], "status": "CURRENT", - "version": "2.99", + "version": "2.100", "min_version": "2.1", "updated": "2013-07-23T11:33:21Z" } diff --git a/nova/api/openstack/api_version_request.py b/nova/api/openstack/api_version_request.py index 7ceed28deb36..8bbeb8306c48 100644 --- a/nova/api/openstack/api_version_request.py +++ b/nova/api/openstack/api_version_request.py @@ -269,6 +269,10 @@ REST_API_VERSION_HISTORY = """REST API Version History: ``server show`` and ``server list --long`` and in the ``server rebuild`` responses. * 2.99 - Add the spice-direct console type to the spice console protocol. + * 2.100 - Add support for returning associated scheduler_hints in + ``GET /servers/{server_id}``, ``GET /servers/detail``, + ``PUT /servers/{server_id}`` and + ``POST /server/{server_id}/action`` (rebuild) responses. """ # The minimum and maximum versions of the API supported @@ -277,7 +281,7 @@ REST_API_VERSION_HISTORY = """REST API Version History: # Note(cyeoh): This only applies for the v2.1 API once microversions # support is fully merged. It does not affect the V2 API. _MIN_API_VERSION = '2.1' -_MAX_API_VERSION = '2.99' +_MAX_API_VERSION = '2.100' DEFAULT_API_VERSION = _MIN_API_VERSION # Almost all proxy APIs which are related to network, images and baremetal diff --git a/nova/api/openstack/compute/rest_api_version_history.rst b/nova/api/openstack/compute/rest_api_version_history.rst index c445075e155b..e8d1f1f1fb26 100644 --- a/nova/api/openstack/compute/rest_api_version_history.rst +++ b/nova/api/openstack/compute/rest_api_version_history.rst @@ -1287,4 +1287,14 @@ under the struct at the existing ``image`` key in the response for Add the ``spice-direct`` console type to the spice console protocol. Also add a ``tls_port`` field to the return value from -``GET /os-console-auth-tokens/{console_token}``. \ No newline at end of file +``GET /os-console-auth-tokens/{console_token}``. + +.. _microversion 2.100: + +2.100 +----------------------------------------------------- + +The ``GET /servers/{server_id}``, ``GET /servers/detail`` +``PUT /servers/{server_id}`` and ``POST /server/{server_id}/action`` +(rebuild) responses now include the scheduler hints provided during +server creation. diff --git a/nova/api/openstack/compute/schemas/servers.py b/nova/api/openstack/compute/schemas/servers.py index a6635762ed00..9f98e7b98fd3 100644 --- a/nova/api/openstack/compute/schemas/servers.py +++ b/nova/api/openstack/compute/schemas/servers.py @@ -1244,3 +1244,11 @@ rebuild_response_v298['properties']['server']['properties']['image'][ 'additionalProperties': False, }, }) + +rebuild_response_v2100 = copy.deepcopy(rebuild_response_v298) +rebuild_response_v2100['properties']['server']['properties'].update({ + 'scheduler_hints': _hints, +}) +rebuild_response_v2100['properties']['server']['required'].append( + 'scheduler_hints' +) diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py index 93f76d348083..5c1617e7fb83 100644 --- a/nova/api/openstack/compute/servers.py +++ b/nova/api/openstack/compute/servers.py @@ -1190,7 +1190,9 @@ class ServersController(wsgi.Controller): @validation.response_body_schema( schema.rebuild_response_v296, '2.96', '2.97') @validation.response_body_schema( - schema.rebuild_response_v298, '2.98') + schema.rebuild_response_v298, '2.98', '2.99') + @validation.response_body_schema( + schema.rebuild_response_v2100, '2.100') def _action_rebuild(self, req, id, body): """Rebuild an instance with the given attributes.""" rebuild_dict = body['rebuild'] diff --git a/nova/api/openstack/compute/views/servers.py b/nova/api/openstack/compute/views/servers.py index b910a1c356ce..8452d6bb1027 100644 --- a/nova/api/openstack/compute/views/servers.py +++ b/nova/api/openstack/compute/views/servers.py @@ -41,6 +41,9 @@ from nova import utils LOG = logging.getLogger(__name__) +SCHED_HINTS_NOT_IN_REQUEST_SPEC = object() + + class ViewBuilder(common.ViewBuilder): """Model a server API response as a python dictionary.""" @@ -96,7 +99,8 @@ class ViewBuilder(common.ViewBuilder): def basic(self, request, instance, show_extra_specs=False, show_extended_attr=None, show_host_status=None, show_sec_grp=None, bdms=None, cell_down_support=False, - show_user_data=False, provided_az=None): + show_user_data=False, provided_az=None, + provided_sched_hints=None): """Generic, non-detailed view of an instance.""" if cell_down_support and 'display_name' not in instance: # NOTE(tssurya): If the microversion is >= 2.69, this boolean will @@ -233,13 +237,29 @@ class ViewBuilder(common.ViewBuilder): pinned_az = '' return pinned_az + def _get_scheduler_hints(self, context, instance, provided_sched_hints): + if provided_sched_hints is SCHED_HINTS_NOT_IN_REQUEST_SPEC: + # Case where it was pre fetched, but not specified + sched_hints = None + elif provided_sched_hints is not None: + sched_hints = provided_sched_hints + else: + # Case the provided_az is not pre fethed. + try: + req_spec = objects.RequestSpec.get_by_instance_uuid( + context, instance.uuid) + sched_hints = req_spec.scheduler_hints + except exception.RequestSpecNotFound: + sched_hints = {} + return sched_hints + def show(self, request, instance, extend_address=True, show_extra_specs=None, show_AZ=True, show_config_drive=True, show_extended_attr=None, show_host_status=None, show_keypair=True, show_srv_usg=True, show_sec_grp=True, show_extended_status=True, show_extended_volumes=True, bdms=None, cell_down_support=False, show_server_groups=False, - show_user_data=True, provided_az=None): + show_user_data=True, provided_az=None, provided_sched_hints=None): """Detailed view of a single instance.""" if show_extra_specs is None: # detail will pre-calculate this for us. If we're doing show, @@ -300,6 +320,7 @@ class ViewBuilder(common.ViewBuilder): server["server"]["progress"] = instance.get("progress", 0) context = request.environ['nova.context'] + if show_AZ: az = avail_zone.get_instance_availability_zone(context, instance) # NOTE(mriedem): The OS-EXT-AZ prefix should not be used for new @@ -310,6 +331,11 @@ class ViewBuilder(common.ViewBuilder): pinned_az = self._get_pinned_az(context, instance, provided_az) server['server']['pinned_availability_zone'] = pinned_az + if api_version_request.is_supported(request, min_version='2.100'): + server['server']['scheduler_hints'] = ( + self._get_scheduler_hints( + context, instance, provided_sched_hints)) + if show_config_drive: server["server"]["config_drive"] = instance["config_drive"] @@ -518,6 +544,7 @@ class ViewBuilder(common.ViewBuilder): """ req_specs = None req_specs_dict = collections.defaultdict(str) + sched_hints_dict = {} if api_version_request.is_supported(request, min_version='2.96'): context = request.environ['nova.context'] instance_uuids = [s.uuid for s in servers] @@ -525,18 +552,27 @@ class ViewBuilder(common.ViewBuilder): context, instance_uuids) req_specs_dict = {req.instance_uuid: req.availability_zone for req in req_specs} + if api_version_request.is_supported(request, min_version='2.100'): + sched_hints_dict.update({ + req.instance_uuid: req.scheduler_hints + for req in req_specs + if req.scheduler_hints is not None}) - server_list = [func(request, server, - show_extra_specs=show_extra_specs, - show_extended_attr=show_extended_attr, - show_host_status=show_host_status, - show_sec_grp=show_sec_grp, bdms=bdms, - cell_down_support=cell_down_support, - provided_az=req_specs_dict[server.uuid])["server"] - for server in servers - # Filter out the fake marker instance created by the - # fill_virtual_interface_list online data migration. - if server.uuid != virtual_interface.FAKE_UUID] + server_list = [ + func(request, server, + show_extra_specs=show_extra_specs, + show_extended_attr=show_extended_attr, + show_host_status=show_host_status, + show_sec_grp=show_sec_grp, bdms=bdms, + cell_down_support=cell_down_support, + provided_az=req_specs_dict[server.uuid], + provided_sched_hints=sched_hints_dict.get( + server.uuid, SCHED_HINTS_NOT_IN_REQUEST_SPEC) + )["server"] + for server in servers + # Filter out the fake marker instance created by the + # fill_virtual_interface_list online data migration. + if server.uuid != virtual_interface.FAKE_UUID] servers_links = self._get_collection_links(request, servers, coll_name) diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-action-rebuild-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-action-rebuild-resp.json.tpl new file mode 100644 index 000000000000..034fa944f56b --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-action-rebuild-resp.json.tpl @@ -0,0 +1,97 @@ +{ + "server": { + "OS-DCF:diskConfig": "AUTO", + "OS-EXT-AZ:availability_zone": "us-west", + "OS-EXT-SRV-ATTR:hostname": "updated-hostname.example.com", + "OS-EXT-STS:power_state": 1, + "OS-EXT-STS:task_state": null, + "OS-EXT-STS:vm_state": "active", + "OS-SRV-USG:launched_at": "%(strtime)s", + "OS-SRV-USG:terminated_at": null, + "accessIPv4": "1.2.3.4", + "accessIPv6": "80fe::", + "addresses": { + "private": [ + { + "OS-EXT-IPS-MAC:mac_addr": "00:0c:29:0d:11:74", + "OS-EXT-IPS:type": "fixed", + "addr": "192.168.1.30", + "version": 4 + } + ] + }, + "adminPass": "seekr3t", + "config_drive": "", + "created": "%(isotime)s", + "description": null, + "flavor": { + "disk": 1, + "ephemeral": 0, + "extra_specs": {}, + "original_name": "m1.tiny", + "ram": 512, + "swap": 0, + "vcpus": 1 + }, + "hostId": "2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6", + "id": "%(id)s", + "image": { + "id": "%(uuid)s", + "links": [ + { + "href": "%(compute_endpoint)s/images/%(uuid)s", + "rel": "bookmark" + } + ], + "properties": { + "architecture": "x86_64", + "auto_disk_config": "True", + "base_image_ref": "%(uuid)s", + "container_format": "ova", + "disk_format": "vhd", + "kernel_id": "nokernel", + "min_disk": "1", + "min_ram": "0", + "ramdisk_id": "nokernel" + } + }, + "key_name": null, + "links": [ + { + "href": "%(versioned_compute_endpoint)s/servers/%(uuid)s", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/servers/%(id)s", + "rel": "bookmark" + } + ], + "locked": false, + "locked_reason": null, + "metadata": { + "meta_var": "meta_val" + }, + "name": "foobar", + "os-extended-volumes:volumes_attached": [], + "pinned_availability_zone": "us-west", + "progress": 0, + "scheduler_hints": { + "same_host": [ + "48e6a9f6-30af-47e0-bc04-acaed113bb4e" + ] + }, + "security_groups": [ + { + "name": "default" + } + ], + "server_groups": [], + "status": "ACTIVE", + "tags": [], + "tenant_id": "6f70656e737461636b20342065766572", + "trusted_image_certificates": null, + "updated": "%(isotime)s", + "user_data": "ZWNobyAiaGVsbG8gd29ybGQi", + "user_id": "fake" + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-action-rebuild.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-action-rebuild.json.tpl new file mode 100644 index 000000000000..3becc83fba6f --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-action-rebuild.json.tpl @@ -0,0 +1,15 @@ +{ + "rebuild" : { + "accessIPv4" : "%(access_ip_v4)s", + "accessIPv6" : "%(access_ip_v6)s", + "OS-DCF:diskConfig": "AUTO", + "imageRef" : "%(uuid)s", + "name" : "%(name)s", + "adminPass" : "%(pass)s", + "hostname": "%(hostname)s", + "metadata" : { + "meta_var" : "meta_val" + }, + "user_data": "ZWNobyAiaGVsbG8gd29ybGQi" + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-create-req.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-create-req.json.tpl new file mode 100644 index 000000000000..3844843fd1d3 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-create-req.json.tpl @@ -0,0 +1,25 @@ +{ + "server" : { + "accessIPv4": "%(access_ip_v4)s", + "accessIPv6": "%(access_ip_v6)s", + "name" : "new-server-test", + "imageRef" : "%(image_id)s", + "flavorRef" : "1", + "OS-DCF:diskConfig": "AUTO", + "availability_zone": "%(availability_zone)s", + "metadata" : { + "My Server Name" : "Apache1" + }, + "security_groups": [ + { + "name": "default" + } + ], + "user_data" : "%(user_data)s", + "networks": "auto", + "hostname": "new-server-test" + }, + "OS-SCH-HNT:scheduler_hints": { + "same_host": "48e6a9f6-30af-47e0-bc04-acaed113bb4e" + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-create-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-create-resp.json.tpl new file mode 100644 index 000000000000..4b30e0cfbdb8 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-create-resp.json.tpl @@ -0,0 +1,22 @@ +{ + "server": { + "OS-DCF:diskConfig": "AUTO", + "adminPass": "%(password)s", + "id": "%(id)s", + "links": [ + { + "href": "%(versioned_compute_endpoint)s/servers/%(uuid)s", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/servers/%(uuid)s", + "rel": "bookmark" + } + ], + "security_groups": [ + { + "name": "default" + } + ] + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-get-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-get-resp.json.tpl new file mode 100644 index 000000000000..459f166ac474 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-get-resp.json.tpl @@ -0,0 +1,99 @@ + +{ + "server": { + "accessIPv4": "%(access_ip_v4)s", + "accessIPv6": "%(access_ip_v6)s", + "addresses": { + "private": [ + { + "addr": "%(ip)s", + "OS-EXT-IPS-MAC:mac_addr": "00:0c:29:0d:11:74", + "OS-EXT-IPS:type": "fixed", + "version": 4 + } + ] + }, + "created": "%(isotime)s", + "description": null, + "locked": false, + "locked_reason": null, + "flavor": { + "disk": 1, + "ephemeral": 0, + "extra_specs": {}, + "original_name": "m1.tiny", + "ram": 512, + "swap": 0, + "vcpus": 1 + }, + "hostId": "%(hostid)s", + "id": "%(id)s", + "image": { + "id": "%(uuid)s", + "links": [ + { + "href": "%(compute_endpoint)s/images/%(uuid)s", + "rel": "bookmark" + } + ], + "properties": { + "architecture": "x86_64", + "auto_disk_config": "True", + "base_image_ref": "%(uuid)s", + "container_format": "ova", + "disk_format": "vhd", + "kernel_id": "nokernel", + "min_disk": "1", + "min_ram": "0", + "ramdisk_id": "nokernel" + } + }, + "key_name": null, + "links": [ + { + "href": "%(versioned_compute_endpoint)s/servers/%(uuid)s", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/servers/%(uuid)s", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "config_drive": "%(cdrive)s", + "OS-DCF:diskConfig": "AUTO", + "OS-EXT-AZ:availability_zone": "us-west", + "OS-EXT-SRV-ATTR:hostname": "%(hostname)s", + "OS-EXT-STS:power_state": 1, + "OS-EXT-STS:task_state": null, + "OS-EXT-STS:vm_state": "active", + "os-extended-volumes:volumes_attached": [ + {"id": "volume_id1", "delete_on_termination": false}, + {"id": "volume_id2", "delete_on_termination": false} + ], + "OS-SRV-USG:launched_at": "%(strtime)s", + "OS-SRV-USG:terminated_at": null, + "pinned_availability_zone": "us-west", + "progress": 0, + "scheduler_hints": { + "same_host": [ + "48e6a9f6-30af-47e0-bc04-acaed113bb4e" + ] + }, + "security_groups": [ + { + "name": "default" + } + ], + "server_groups": [], + "status": "ACTIVE", + "tags": [], + "tenant_id": "6f70656e737461636b20342065766572", + "trusted_image_certificates": null, + "updated": "%(isotime)s", + "user_id": "fake" + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-list-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-list-resp.json.tpl new file mode 100644 index 000000000000..42a21fff8527 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-list-resp.json.tpl @@ -0,0 +1,25 @@ +{ + "servers": [ + { + "id": "%(id)s", + "links": [ + { + "href": "%(versioned_compute_endpoint)s/servers/%(id)s", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/servers/%(id)s", + "rel": "bookmark" + } + ], + "name": "new-server-test" + } + ], + "servers_links": [ + { + "href": "%(versioned_compute_endpoint)s/servers?limit=1&marker=%(id)s", + "rel": "next" + } + ] +} + diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-update-req.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-update-req.json.tpl new file mode 100644 index 000000000000..bc4be64a8e67 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-update-req.json.tpl @@ -0,0 +1,8 @@ +{ + "server": { + "accessIPv4": "%(access_ip_v4)s", + "accessIPv6": "%(access_ip_v6)s", + "OS-DCF:diskConfig": "AUTO", + "hostname": "new-server-hostname.example.com" + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-update-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-update-resp.json.tpl new file mode 100644 index 000000000000..c662e0e8c302 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/server-update-resp.json.tpl @@ -0,0 +1,95 @@ +{ + "server": { + "accessIPv4": "%(access_ip_v4)s", + "accessIPv6": "%(access_ip_v6)s", + "addresses": { + "private": [ + { + "addr": "%(ip)s", + "OS-EXT-IPS-MAC:mac_addr": "00:0c:29:0d:11:74", + "OS-EXT-IPS:type": "fixed", + "version": 4 + } + ] + }, + "created": "%(isotime)s", + "description": null, + "locked": false, + "locked_reason": null, + "flavor": { + "disk": 1, + "ephemeral": 0, + "extra_specs": {}, + "original_name": "m1.tiny", + "ram": 512, + "swap": 0, + "vcpus": 1 + }, + "hostId": "%(hostid)s", + "id": "%(id)s", + "image": { + "id": "%(uuid)s", + "links": [ + { + "href": "%(compute_endpoint)s/images/%(uuid)s", + "rel": "bookmark" + } + ], + "properties": { + "architecture": "x86_64", + "auto_disk_config": "True", + "base_image_ref": "%(uuid)s", + "container_format": "ova", + "disk_format": "vhd", + "kernel_id": "nokernel", + "min_disk": "1", + "min_ram": "0", + "ramdisk_id": "nokernel" + } + }, + "key_name": null, + "links": [ + { + "href": "%(versioned_compute_endpoint)s/servers/%(uuid)s", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/servers/%(uuid)s", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "config_drive": "", + "OS-DCF:diskConfig": "AUTO", + "OS-EXT-AZ:availability_zone": "us-west", + "OS-EXT-SRV-ATTR:hostname": "new-server-hostname.example.com", + "OS-EXT-STS:power_state": 1, + "OS-EXT-STS:task_state": null, + "OS-EXT-STS:vm_state": "active", + "os-extended-volumes:volumes_attached": [], + "OS-SRV-USG:launched_at": "%(strtime)s", + "OS-SRV-USG:terminated_at": null, + "pinned_availability_zone": "us-west", + "progress": 0, + "scheduler_hints": { + "same_host": [ + "48e6a9f6-30af-47e0-bc04-acaed113bb4e" + ] + }, + "security_groups": [ + { + "name": "default" + } + ], + "server_groups": [], + "status": "ACTIVE", + "tags": [], + "tenant_id": "6f70656e737461636b20342065766572", + "trusted_image_certificates": null, + "updated": "%(isotime)s", + "user_id": "fake" + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/servers-details-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/servers-details-resp.json.tpl new file mode 100644 index 000000000000..f0bdf5ff38f5 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/servers-details-resp.json.tpl @@ -0,0 +1,106 @@ + +{ + "servers": [ + { + "accessIPv4": "%(access_ip_v4)s", + "accessIPv6": "%(access_ip_v6)s", + "addresses": { + "private": [ + { + "addr": "%(ip)s", + "OS-EXT-IPS-MAC:mac_addr": "00:0c:29:0d:11:74", + "OS-EXT-IPS:type": "fixed", + "version": 4 + } + ] + }, + "created": "%(isotime)s", + "description": "", + "flavor": { + "disk": 1, + "ephemeral": 0, + "extra_specs": {}, + "original_name": "m1.tiny", + "ram": 512, + "swap": 0, + "vcpus": 1 + }, + "hostId": "%(hostid)s", + "id": "%(id)s", + "image": { + "id": "%(uuid)s", + "links": [ + { + "href": "%(compute_endpoint)s/images/%(uuid)s", + "rel": "bookmark" + } + ], + "properties": { + "architecture": "x86_64", + "auto_disk_config": "True", + "base_image_ref": "%(uuid)s", + "container_format": "ova", + "disk_format": "vhd", + "kernel_id": "nokernel", + "min_disk": "1", + "min_ram": "0", + "ramdisk_id": "nokernel" + } + }, + "key_name": null, + "links": [ + { + "href": "%(versioned_compute_endpoint)s/servers/%(uuid)s", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/servers/%(id)s", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "config_drive": "%(cdrive)s", + "locked": false, + "locked_reason": "", + "OS-DCF:diskConfig": "AUTO", + "OS-EXT-AZ:availability_zone": "us-west", + "OS-EXT-SRV-ATTR:hostname": "new-server-test", + "OS-EXT-STS:power_state": 1, + "OS-EXT-STS:task_state": null, + "OS-EXT-STS:vm_state": "active", + "os-extended-volumes:volumes_attached": [ + {"id": "volume_id1", "delete_on_termination": false}, + {"id": "volume_id2", "delete_on_termination": false} + ], + "OS-SRV-USG:launched_at": "%(strtime)s", + "OS-SRV-USG:terminated_at": null, + "pinned_availability_zone": "us-west", + "progress": 0, + "scheduler_hints": { + "same_host": [ + "48e6a9f6-30af-47e0-bc04-acaed113bb4e" + ] + }, + "security_groups": [ + { + "name": "default" + } + ], + "status": "ACTIVE", + "tags": [], + "tenant_id": "6f70656e737461636b20342065766572", + "trusted_image_certificates": null, + "updated": "%(isotime)s", + "user_id": "fake" + } + ], + "servers_links": [ + { + "href": "%(versioned_compute_endpoint)s/servers/detail?limit=1&marker=%(id)s", + "rel": "next" + } + ] +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/servers-list-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/servers-list-resp.json.tpl new file mode 100644 index 000000000000..9cdb3aa64475 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.100/servers-list-resp.json.tpl @@ -0,0 +1,24 @@ +{ + "servers": [ + { + "id": "%(id)s", + "links": [ + { + "href": "%(versioned_compute_endpoint)s/servers/%(id)s", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/servers/%(id)s", + "rel": "bookmark" + } + ], + "name": "new-server-test" + } + ], + "servers_links": [ + { + "href": "%(versioned_compute_endpoint)s/servers?limit=1&marker=%(id)s", + "rel": "next" + } + ] +} diff --git a/nova/tests/functional/api_sample_tests/test_servers.py b/nova/tests/functional/api_sample_tests/test_servers.py index 23565ed42ad7..2fc4fd925ea3 100644 --- a/nova/tests/functional/api_sample_tests/test_servers.py +++ b/nova/tests/functional/api_sample_tests/test_servers.py @@ -637,6 +637,47 @@ class ServerSampleJson298Test(ServersSampleJsonTest): ADMIN_API = False +class ServersSampleJson2100Test(ServersSampleJsonTest): + microversion = '2.100' + scenarios = [('v2_100', {'api_major_version': 'v2.1'})] + ADMIN_API = False + use_common_server_post = False + + def test_server_rebuild(self): + uuid = self._post_server( + use_common_server_api_samples=self.use_common_server_post + ) + params = { + 'uuid': self.glance.auto_disk_config_enabled_image['id'], + 'name': 'foobar', + 'pass': 'seekr3t', + 'hostid': '[a-f0-9]+', + 'access_ip_v4': '1.2.3.4', + 'access_ip_v6': '80fe::', + 'hostname': 'updated-hostname.example.com', + } + + resp = self._do_post( + 'servers/%s/action' % uuid, + 'server-action-rebuild', + params, + ) + subs = params.copy() + del subs['uuid'] + self._verify_response('server-action-rebuild-resp', subs, resp, 202) + + def test_update_server(self): + uuid = self._post_server( + use_common_server_api_samples=self.use_common_server_post) + subs = {} + subs['hostid'] = '[a-f0-9]+' + subs['access_ip_v4'] = '1.2.3.4' + subs['access_ip_v6'] = '80fe::' + response = self._do_put('servers/%s' % uuid, + 'server-update-req', subs) + self._verify_response('server-update-resp', subs, response, 200) + + class ServersUpdateSampleJsonTest(ServersSampleBase): # Many of the 'os_compute_api:servers:*' policies are admin-only, and we diff --git a/nova/tests/unit/api/openstack/compute/test_servers.py b/nova/tests/unit/api/openstack/compute/test_servers.py index e2bbc6399e3a..cf165fde2504 100644 --- a/nova/tests/unit/api/openstack/compute/test_servers.py +++ b/nova/tests/unit/api/openstack/compute/test_servers.py @@ -69,6 +69,7 @@ from nova.tests.unit.api.openstack import fakes from nova.tests.unit import fake_block_device from nova.tests.unit import fake_flavor from nova.tests.unit import fake_instance +from nova.tests.unit import fake_request_spec from nova.tests.unit import matchers from nova import utils as nova_utils @@ -8469,6 +8470,65 @@ class ServersViewBuilderTestV296(_ServersViewBuilderTest): req, self.instances, False) +class ServersViewBuilderTestV2100(_ServersViewBuilderTest): + """Server ViewBuilder test for microversion 2.100 + + The intent is simply to verify that when showing server details + after microversion 2.100 the response will always have a dict for + scheduler_hints. + """ + + def setUp(self): + super(ServersViewBuilderTestV2100, self).setUp() + self.view_builder = views.servers.ViewBuilder() + self.ctxt = context.RequestContext('fake', self.project_id) + self.request.api_version_request = ( + api_version_request.APIVersionRequest('2.100')) + + @mock.patch('nova.objects.RequestSpec.get_by_instance_uuid') + def test_build_server_detail_v2100(self, mock_get_req_spec): + mock_get_req_spec.return_value = fake_request_spec.fake_spec_obj() + expected_hints = {'hint': ['over-there']} + + output = self.view_builder.show(self.request, self.instance) + + self.assertIn('scheduler_hints', output['server'].keys()) + self.assertThat(output['server']['scheduler_hints'], + matchers.DictMatches(expected_hints)) + exp_call = mock.call( + self.request.environ['nova.context'], self.instance.uuid) + mock_get_req_spec.assert_has_calls([exp_call, exp_call]) + + @mock.patch('nova.objects.RequestSpec.get_by_instance_uuid') + def test_build_server_detail_v2100_no_spec(self, mock_get_req_spec): + mock_get_req_spec.side_effect = exception.RequestSpecNotFound( + instance_uuid='foo') + expected_hints = {} + + output = self.view_builder.show(self.request, self.instance) + + self.assertIn('scheduler_hints', output['server'].keys()) + self.assertThat(output['server']['scheduler_hints'], + matchers.DictMatches(expected_hints)) + exp_call = mock.call( + self.request.environ['nova.context'], self.instance.uuid) + mock_get_req_spec.assert_has_calls([exp_call, exp_call]) + + @mock.patch('nova.objects.RequestSpec.get_by_instance_uuid') + def test_build_server_detail_v299_no_hints(self, mock_get_req_spec): + # req_spec is retrieved since 2.96, but no scheduler_hints + # should be returned + self.request.api_version_request = ( + api_version_request.APIVersionRequest('2.99')) + mock_get_req_spec.return_value = fake_request_spec.fake_spec_obj() + + output = self.view_builder.show(self.request, self.instance) + + self.assertNotIn('scheduler_hints', output['server'].keys()) + mock_get_req_spec.assert_called_once_with( + self.request.environ['nova.context'], self.instance.uuid) + + class ServersActionsJsonTestV239(test.NoDBTestCase): def setUp(self): diff --git a/releasenotes/notes/bp-show-sched-hints-server-details-22bc15d5ea81e43a.yaml b/releasenotes/notes/bp-show-sched-hints-server-details-22bc15d5ea81e43a.yaml new file mode 100644 index 000000000000..d9cc62d4d594 --- /dev/null +++ b/releasenotes/notes/bp-show-sched-hints-server-details-22bc15d5ea81e43a.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + A new microversion has been added that allows users to retrieve + server's associated scheduler hints in ``GET /servers/{server_id}``, + ``GET /servers/detail``, ``PUT /servers/{server_id}`` and + ``POST /server/{server_id}/action`` (rebuild) responses.