From 2cc7c0e58924b201d5353a6289883b0aec760543 Mon Sep 17 00:00:00 2001 From: Yongli He Date: Tue, 13 Nov 2018 15:40:49 +0800 Subject: [PATCH] Adds the server group info into show server detail API. The server-groups UUID add to response of 'GET /servers/{id}', 'PUT /servers/{server_id}" and rebuild API 'POST /servers/{server_id}/action'. Change-Id: I4a2a584df56ece7beb8b12c0ce9b0e6b30237120 Implements: blueprint show-server-group Co-authored-by: Gerry Kopec Signed-off-by: Yongli He --- api-guide/source/down_cells.rst | 4 + api-ref/source/parameters.yaml | 8 ++ api-ref/source/servers-actions.inc | 1 + api-ref/source/servers.inc | 2 + .../v2.71/server-action-rebuild-resp.json | 65 ++++++++++++ .../servers/v2.71/server-action-rebuild.json | 14 +++ .../servers/v2.71/server-create-req.json | 23 +++++ .../servers/v2.71/server-create-resp.json | 22 +++++ .../v2.71/server-get-down-cell-resp.json | 32 ++++++ .../servers/v2.71/server-get-resp.json | 89 +++++++++++++++++ .../servers/v2.71/server-groups-post-req.json | 6 ++ .../v2.71/server-groups-post-resp.json | 11 +++ .../servers/v2.71/server-update-req.json | 9 ++ .../servers/v2.71/server-update-resp.json | 62 ++++++++++++ .../versions/v21-version-get-resp.json | 2 +- .../versions/versions-get-resp.json | 2 +- nova/api/openstack/api_version_request.py | 5 +- .../compute/rest_api_version_history.rst | 11 +++ nova/api/openstack/compute/servers.py | 38 ++++--- nova/api/openstack/compute/views/servers.py | 24 ++++- .../v2.71/server-action-rebuild-resp.json.tpl | 63 ++++++++++++ .../v2.71/server-action-rebuild.json.tpl | 14 +++ .../servers/v2.71/server-create-req.json.tpl | 23 +++++ .../servers/v2.71/server-create-resp.json.tpl | 22 +++++ .../v2.71/server-get-down-cell-resp.json.tpl | 30 ++++++ .../servers/v2.71/server-get-resp.json.tpl | 87 ++++++++++++++++ .../v2.71/server-groups-post-req.json.tpl | 6 ++ .../v2.71/server-groups-post-resp.json.tpl | 11 +++ .../servers/v2.71/server-update-req.json.tpl | 9 ++ .../servers/v2.71/server-update-resp.json.tpl | 61 ++++++++++++ .../api_sample_tests/test_servers.py | 98 ++++++++++++++++++- .../api/openstack/compute/test_serversV21.py | 70 +++++++++++++ .../show-server-group-8d4bf609213a94de.yaml | 10 ++ 33 files changed, 914 insertions(+), 20 deletions(-) create mode 100644 doc/api_samples/servers/v2.71/server-action-rebuild-resp.json create mode 100644 doc/api_samples/servers/v2.71/server-action-rebuild.json create mode 100644 doc/api_samples/servers/v2.71/server-create-req.json create mode 100644 doc/api_samples/servers/v2.71/server-create-resp.json create mode 100644 doc/api_samples/servers/v2.71/server-get-down-cell-resp.json create mode 100644 doc/api_samples/servers/v2.71/server-get-resp.json create mode 100644 doc/api_samples/servers/v2.71/server-groups-post-req.json create mode 100644 doc/api_samples/servers/v2.71/server-groups-post-resp.json create mode 100644 doc/api_samples/servers/v2.71/server-update-req.json create mode 100644 doc/api_samples/servers/v2.71/server-update-resp.json create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-action-rebuild-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-action-rebuild.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-create-req.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-create-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-get-down-cell-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-get-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-groups-post-req.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-groups-post-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-update-req.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-update-resp.json.tpl create mode 100644 releasenotes/notes/show-server-group-8d4bf609213a94de.yaml diff --git a/api-guide/source/down_cells.rst b/api-guide/source/down_cells.rst index 5d6bdf2959..0a1fa4aeb3 100644 --- a/api-guide/source/down_cells.rst +++ b/api-guide/source/down_cells.rst @@ -240,6 +240,9 @@ behavior are described below: - availability_zone: The availability_zone of the server if it was specified during during boot time and "UNKNOWN" otherwise. - power_state: Its value will be 0 (``NOSTATE``). + - server_groups: The UUIDs of the server groups to which the server belongs. + Currently this can contain at most one entry. Note that this key will be in + the response only from the "2.71" microversion. A sample response for a GET /servers/{server_id} request that includes one server from an unreachable part of the infrastructure @@ -272,6 +275,7 @@ behavior are described below: }, "OS-EXT-AZ:availability_zone": "geneva", "OS-EXT-STS:power_state": 0, + "server_groups": ["0fd77252-4eef-4ec4-ae9b-e05dfc98aeac"] } ] } diff --git a/api-ref/source/parameters.yaml b/api-ref/source/parameters.yaml index 5b9957de3b..a5ee4f369d 100644 --- a/api-ref/source/parameters.yaml +++ b/api-ref/source/parameters.yaml @@ -5861,6 +5861,14 @@ server_groups: &server_groups in: body required: true type: integer +server_groups_2_71: + description: | + The UUIDs of the server groups to which the server belongs. Currently + this can contain at most one entry. + in: body + required: true + type: array + min_version: 2.71 server_groups_list: description: | The list of existing server groups. diff --git a/api-ref/source/servers-actions.inc b/api-ref/source/servers-actions.inc index f95d88ca79..dcb60d4a3d 100644 --- a/api-ref/source/servers-actions.inc +++ b/api-ref/source/servers-actions.inc @@ -613,6 +613,7 @@ Response - key_name: key_name_rebuild_resp - user_data: user_data_rebuild_resp - trusted_image_certificates: server_trusted_image_certificates_resp + - server_groups: server_groups_2_71 **Example Rebuild Server (rebuild Action) (v2.63)** diff --git a/api-ref/source/servers.inc b/api-ref/source/servers.inc index 6e2bd07ff3..f80ad59912 100644 --- a/api-ref/source/servers.inc +++ b/api-ref/source/servers.inc @@ -768,6 +768,7 @@ Response - description: server_description_resp - tags: tags - trusted_image_certificates: server_trusted_image_certificates_resp + - server_groups: server_groups_2_71 **Example Show Server Details (2.63)** @@ -859,6 +860,7 @@ Response - description: server_description_resp - tags: tags - trusted_image_certificates: server_trusted_image_certificates_resp + - server_groups: server_groups_2_71 **Example Update Server (2.63)** diff --git a/doc/api_samples/servers/v2.71/server-action-rebuild-resp.json b/doc/api_samples/servers/v2.71/server-action-rebuild-resp.json new file mode 100644 index 0000000000..a4ca94e85d --- /dev/null +++ b/doc/api_samples/servers/v2.71/server-action-rebuild-resp.json @@ -0,0 +1,65 @@ +{ + "server": { + "OS-DCF:diskConfig": "AUTO", + "accessIPv4": "1.2.3.4", + "accessIPv6": "80fe::", + "addresses": { + "private": [ + { + "addr": "192.168.0.3", + "version": 4 + } + ] + }, + "adminPass": "seekr3t", + "created": "2019-02-28T03:16:19Z", + "description": null, + "flavor": { + "disk": 1, + "ephemeral": 0, + "extra_specs": {}, + "original_name": "m1.tiny", + "ram": 512, + "swap": 0, + "vcpus": 1 + }, + "hostId": "2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6", + "id": "36b2afd5-1684-4d18-a49c-915bf0f5344c", + "image": { + "id": "70a599e0-31e7-49b7-b260-868f441e862b", + "links": [ + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "bookmark" + } + ] + }, + "key_name": null, + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/36b2afd5-1684-4d18-a49c-915bf0f5344c", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/36b2afd5-1684-4d18-a49c-915bf0f5344c", + "rel": "bookmark" + } + ], + "locked": false, + "metadata": { + "meta_var": "meta_val" + }, + "name": "foobar", + "progress": 0, + "server_groups": [ + "f3d86fe6-4246-4be8-b87c-eb894626c741" + ], + "status": "ACTIVE", + "tags": [], + "tenant_id": "6f70656e737461636b20342065766572", + "trusted_image_certificates": null, + "updated": "2019-02-28T03:16:20Z", + "user_data": "ZWNobyAiaGVsbG8gd29ybGQi", + "user_id": "fake" + } +} diff --git a/doc/api_samples/servers/v2.71/server-action-rebuild.json b/doc/api_samples/servers/v2.71/server-action-rebuild.json new file mode 100644 index 0000000000..f1431a0506 --- /dev/null +++ b/doc/api_samples/servers/v2.71/server-action-rebuild.json @@ -0,0 +1,14 @@ +{ + "rebuild" : { + "accessIPv4" : "1.2.3.4", + "accessIPv6" : "80fe::", + "OS-DCF:diskConfig": "AUTO", + "imageRef" : "70a599e0-31e7-49b7-b260-868f441e862b", + "name" : "foobar", + "adminPass" : "seekr3t", + "metadata" : { + "meta_var" : "meta_val" + }, + "user_data": "ZWNobyAiaGVsbG8gd29ybGQi" + } +} \ No newline at end of file diff --git a/doc/api_samples/servers/v2.71/server-create-req.json b/doc/api_samples/servers/v2.71/server-create-req.json new file mode 100644 index 0000000000..b5a9b238ac --- /dev/null +++ b/doc/api_samples/servers/v2.71/server-create-req.json @@ -0,0 +1,23 @@ +{ + "server" : { + "accessIPv4": "1.2.3.4", + "accessIPv6": "80fe::", + "name" : "new-server-test", + "imageRef" : "70a599e0-31e7-49b7-b260-868f441e862b", + "flavorRef" : "1", + "OS-DCF:diskConfig": "AUTO", + "metadata" : { + "My Server Name" : "Apache1" + }, + "security_groups": [ + { + "name": "default" + } + ], + "user_data" : "IyEvYmluL2Jhc2gKL2Jpbi9zdQplY2hvICJJIGFtIGluIHlvdSEiCg==", + "networks": "auto" + }, + "OS-SCH-HNT:scheduler_hints": { + "group": "f3d86fe6-4246-4be8-b87c-eb894626c741" + } +} \ No newline at end of file diff --git a/doc/api_samples/servers/v2.71/server-create-resp.json b/doc/api_samples/servers/v2.71/server-create-resp.json new file mode 100644 index 0000000000..7ebe2e20a2 --- /dev/null +++ b/doc/api_samples/servers/v2.71/server-create-resp.json @@ -0,0 +1,22 @@ +{ + "server": { + "OS-DCF:diskConfig": "AUTO", + "adminPass": "DB2bQBhxvq8a", + "id": "84e2b49d-39a9-4d32-9100-e62161c236db", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/84e2b49d-39a9-4d32-9100-e62161c236db", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/84e2b49d-39a9-4d32-9100-e62161c236db", + "rel": "bookmark" + } + ], + "security_groups": [ + { + "name": "default" + } + ] + } +} \ No newline at end of file diff --git a/doc/api_samples/servers/v2.71/server-get-down-cell-resp.json b/doc/api_samples/servers/v2.71/server-get-down-cell-resp.json new file mode 100644 index 0000000000..2d506c5d89 --- /dev/null +++ b/doc/api_samples/servers/v2.71/server-get-down-cell-resp.json @@ -0,0 +1,32 @@ +{ + "server": { + "OS-EXT-AZ:availability_zone": "UNKNOWN", + "OS-EXT-STS:power_state": 0, + "created": "2019-02-28T03:16:19Z", + "flavor": { + "disk": 1, + "ephemeral": 0, + "extra_specs": {}, + "original_name": "m1.tiny", + "ram": 512, + "swap": 0, + "vcpus": 1 + }, + "id": "2669556b-b4a3-41f1-a0c1-f9c7ff75e53c", + "image": { + "id": "70a599e0-31e7-49b7-b260-868f441e862b", + "links": [ + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "bookmark" + } + ] + }, + "server_groups": [ + "f3d86fe6-4246-4be8-b87c-eb894626c741" + ], + "status": "UNKNOWN", + "tenant_id": "project", + "user_id": "fake" + } +} diff --git a/doc/api_samples/servers/v2.71/server-get-resp.json b/doc/api_samples/servers/v2.71/server-get-resp.json new file mode 100644 index 0000000000..46f07e9478 --- /dev/null +++ b/doc/api_samples/servers/v2.71/server-get-resp.json @@ -0,0 +1,89 @@ +{ + "server": { + "OS-DCF:diskConfig": "AUTO", + "OS-EXT-AZ:availability_zone": "nova", + "OS-EXT-SRV-ATTR:host": "compute", + "OS-EXT-SRV-ATTR:hostname": "new-server-test", + "OS-EXT-SRV-ATTR:hypervisor_hostname": "fake-mini", + "OS-EXT-SRV-ATTR:instance_name": "instance-00000001", + "OS-EXT-SRV-ATTR:kernel_id": "", + "OS-EXT-SRV-ATTR:launch_index": 0, + "OS-EXT-SRV-ATTR:ramdisk_id": "", + "OS-EXT-SRV-ATTR:reservation_id": "r-0scisg0g", + "OS-EXT-SRV-ATTR:root_device_name": "/dev/sda", + "OS-EXT-SRV-ATTR:user_data": "IyEvYmluL2Jhc2gKL2Jpbi9zdQplY2hvICJJIGFtIGluIHlvdSEiCg==", + "OS-EXT-STS:power_state": 1, + "OS-EXT-STS:task_state": null, + "OS-EXT-STS:vm_state": "active", + "OS-SRV-USG:launched_at": "2019-02-28T03:16:19.600768", + "OS-SRV-USG:terminated_at": null, + "accessIPv4": "1.2.3.4", + "accessIPv6": "80fe::", + "addresses": { + "private": [ + { + "OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff", + "OS-EXT-IPS:type": "fixed", + "addr": "192.168.0.3", + "version": 4 + } + ] + }, + "config_drive": "", + "created": "2019-02-28T03:16:18Z", + "description": null, + "flavor": { + "disk": 1, + "ephemeral": 0, + "extra_specs": {}, + "original_name": "m1.tiny", + "ram": 512, + "swap": 0, + "vcpus": 1 + }, + "hostId": "2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6", + "host_status": "UP", + "id": "84e2b49d-39a9-4d32-9100-e62161c236db", + "image": { + "id": "70a599e0-31e7-49b7-b260-868f441e862b", + "links": [ + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "bookmark" + } + ] + }, + "key_name": null, + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/84e2b49d-39a9-4d32-9100-e62161c236db", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/84e2b49d-39a9-4d32-9100-e62161c236db", + "rel": "bookmark" + } + ], + "locked": false, + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "os-extended-volumes:volumes_attached": [], + "progress": 0, + "security_groups": [ + { + "name": "default" + } + ], + "server_groups": [ + "f3d86fe6-4246-4be8-b87c-eb894626c741" + ], + "status": "ACTIVE", + "tags": [], + "tenant_id": "6f70656e737461636b20342065766572", + "trusted_image_certificates": null, + "updated": "2019-02-28T03:16:19Z", + "user_id": "fake" + } +} \ No newline at end of file diff --git a/doc/api_samples/servers/v2.71/server-groups-post-req.json b/doc/api_samples/servers/v2.71/server-groups-post-req.json new file mode 100644 index 0000000000..bbdf2ff4c8 --- /dev/null +++ b/doc/api_samples/servers/v2.71/server-groups-post-req.json @@ -0,0 +1,6 @@ +{ + "server_group": { + "name": "test", + "policy": "affinity" + } +} \ No newline at end of file diff --git a/doc/api_samples/servers/v2.71/server-groups-post-resp.json b/doc/api_samples/servers/v2.71/server-groups-post-resp.json new file mode 100644 index 0000000000..969da31263 --- /dev/null +++ b/doc/api_samples/servers/v2.71/server-groups-post-resp.json @@ -0,0 +1,11 @@ +{ + "server_group": { + "id": "f3d86fe6-4246-4be8-b87c-eb894626c741", + "members": [], + "name": "test", + "policy": "affinity", + "project_id": "6f70656e737461636b20342065766572", + "rules": {}, + "user_id": "fake" + } +} \ No newline at end of file diff --git a/doc/api_samples/servers/v2.71/server-update-req.json b/doc/api_samples/servers/v2.71/server-update-req.json new file mode 100644 index 0000000000..3b3995d51e --- /dev/null +++ b/doc/api_samples/servers/v2.71/server-update-req.json @@ -0,0 +1,9 @@ +{ + "server": { + "accessIPv4": "1.2.3.4", + "accessIPv6": "80fe::", + "OS-DCF:diskConfig": "AUTO", + "name": "new-server-test", + "description": "Sample description" + } +} \ No newline at end of file diff --git a/doc/api_samples/servers/v2.71/server-update-resp.json b/doc/api_samples/servers/v2.71/server-update-resp.json new file mode 100644 index 0000000000..8024a7cd9f --- /dev/null +++ b/doc/api_samples/servers/v2.71/server-update-resp.json @@ -0,0 +1,62 @@ +{ + "server": { + "OS-DCF:diskConfig": "AUTO", + "accessIPv4": "1.2.3.4", + "accessIPv6": "80fe::", + "addresses": { + "private": [ + { + "addr": "192.168.0.3", + "version": 4 + } + ] + }, + "created": "2019-02-28T03:16:19Z", + "description": "Sample description", + "flavor": { + "disk": 1, + "ephemeral": 0, + "extra_specs": {}, + "original_name": "m1.tiny", + "ram": 512, + "swap": 0, + "vcpus": 1 + }, + "hostId": "2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6", + "id": "60e840f8-dd17-476b-bd1d-33785066c496", + "image": { + "id": "70a599e0-31e7-49b7-b260-868f441e862b", + "links": [ + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "bookmark" + } + ] + }, + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/60e840f8-dd17-476b-bd1d-33785066c496", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/60e840f8-dd17-476b-bd1d-33785066c496", + "rel": "bookmark" + } + ], + "locked": false, + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "progress": 0, + "server_groups": [ + "f3d86fe6-4246-4be8-b87c-eb894626c741" + ], + "status": "ACTIVE", + "tags": [], + "tenant_id": "6f70656e737461636b20342065766572", + "trusted_image_certificates": null, + "updated": "2019-02-28T03:16:19Z", + "user_id": "fake" + } +} diff --git a/doc/api_samples/versions/v21-version-get-resp.json b/doc/api_samples/versions/v21-version-get-resp.json index d9d08a41fc..53984b63cf 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.70", + "version": "2.71", "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 1722025e96..4c51794ca6 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.70", + "version": "2.71", "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 12ff776bfd..c85a1b740e 100644 --- a/nova/api/openstack/api_version_request.py +++ b/nova/api/openstack/api_version_request.py @@ -172,6 +172,9 @@ REST_API_VERSION_HISTORY = """REST API Version History: condition in the deployment like an infrastructure failure. * 2.70 - Exposes virtual device tags in the response of the ``os-volume_attachments`` and ``os-interface`` APIs. + * 2.71 - Adds the ``server_groups`` field to ``GET /servers/{id}``, + ``PUT /servers/{server_id}`` and + ``POST /servers/{server_id}/action`` (rebuild) responses. """ # The minimum and maximum versions of the API supported @@ -180,7 +183,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.70" +_MAX_API_VERSION = "2.71" 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 c47093fe82..10b5974125 100644 --- a/nova/api/openstack/compute/rest_api_version_history.rst +++ b/nova/api/openstack/compute/rest_api_version_history.rst @@ -898,3 +898,14 @@ APIs: * GET /servers/{server_id}/os-interface (list) * GET /servers/{server_id}/os-interface/{port_id} (show) * POST /servers/{server_id}/os-interface (attach) + +2.71 +---- + +The ``server_groups`` parameter will be in the response body of the following +APIs to list the server groups to which the server belongs: + +* ``GET /servers/{server_id}`` +* ``PUT /servers/{server_id}`` +* ``POST /servers/{server_id}/action (rebuild)`` + diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py index 5b71901eea..527fbdcd5e 100644 --- a/nova/api/openstack/compute/servers.py +++ b/nova/api/openstack/compute/servers.py @@ -425,11 +425,15 @@ class ServersController(wsgi.Controller): context.can(server_policies.SERVERS % 'show') cell_down_support = api_version_request.is_supported( req, min_version=PARTIAL_CONSTRUCT_FOR_CELL_DOWN_MIN_VERSION) + show_server_groups = api_version_request.is_supported( + req, min_version='2.71') + instance = self._get_server( context, req, id, is_detail=True, cell_down_support=cell_down_support) return self._view_builder.show( - req, instance, cell_down_support=cell_down_support) + req, instance, cell_down_support=cell_down_support, + show_server_groups=show_server_groups) @staticmethod def _process_bdms_for_create( @@ -779,6 +783,8 @@ class ServersController(wsgi.Controller): ctxt.can(server_policies.SERVERS % 'update', target={'user_id': instance.user_id, 'project_id': instance.project_id}) + show_server_groups = api_version_request.is_supported( + req, min_version='2.71') server = body['server'] @@ -795,17 +801,19 @@ class ServersController(wsgi.Controller): try: instance = self.compute_api.update_instance(ctxt, instance, update_dict) - return self._view_builder.show(req, instance, - extend_address=False, - show_AZ=False, - show_config_drive=False, - show_extended_attr=False, - show_host_status=False, - show_keypair=False, - show_srv_usg=False, - show_sec_grp=False, - show_extended_status=False, - show_extended_volumes=False) + return self._view_builder.show( + req, instance, + extend_address=False, + show_AZ=False, + show_config_drive=False, + show_extended_attr=False, + show_host_status=False, + show_keypair=False, + show_srv_usg=False, + show_sec_grp=False, + show_extended_status=False, + show_extended_volumes=False, + show_server_groups=show_server_groups) except exception.InstanceNotFound: msg = _("Instance could not be found") raise exc.HTTPNotFound(explanation=msg) @@ -1087,6 +1095,9 @@ class ServersController(wsgi.Controller): # from microversion 2.54 onwards. show_keypair = api_version_request.is_supported( req, min_version='2.54') + show_server_groups = api_version_request.is_supported( + req, min_version='2.71') + view = self._view_builder.show(req, instance, extend_address=False, show_AZ=False, show_config_drive=False, @@ -1096,7 +1107,8 @@ class ServersController(wsgi.Controller): show_srv_usg=False, show_sec_grp=False, show_extended_status=False, - show_extended_volumes=False) + show_extended_volumes=False, + show_server_groups=show_server_groups) # Add on the admin_password attribute since the view doesn't do it # unless instance passwords are disabled diff --git a/nova/api/openstack/compute/views/servers.py b/nova/api/openstack/compute/views/servers.py index 78813c44c6..e0340274dc 100644 --- a/nova/api/openstack/compute/views/servers.py +++ b/nova/api/openstack/compute/views/servers.py @@ -140,7 +140,8 @@ class ViewBuilder(common.ViewBuilder): # results. return sorted(list(set(self._show_expected_attrs + expected_attrs))) - def _show_from_down_cell(self, request, instance, show_extra_specs): + def _show_from_down_cell(self, request, instance, show_extra_specs, + show_server_groups): """Function that constructs the partial response for the instance.""" ret = { "server": { @@ -172,6 +173,10 @@ class ViewBuilder(common.ViewBuilder): # in case its an old request spec which doesn't have the user_id # data migrated, return UNKNOWN. ret["server"]["user_id"] = instance.user_id or "UNKNOWN" + if show_server_groups: + context = request.environ['nova.context'] + ret['server']['server_groups'] = self._get_server_groups( + context, instance) else: # GET /servers/detail includes links for GET /servers/{server_id}. ret['server']["links"] = self._get_links( @@ -183,7 +188,7 @@ class ViewBuilder(common.ViewBuilder): 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): + bdms=None, cell_down_support=False, show_server_groups=False): """Detailed view of a single instance.""" if show_extra_specs is None: # detail will pre-calculate this for us. If we're doing show, @@ -201,7 +206,7 @@ class ViewBuilder(common.ViewBuilder): # `display_name`) and return partial constructs based on the # information available from the nova_api database. return self._show_from_down_cell( - request, instance, show_extra_specs) + request, instance, show_extra_specs, show_server_groups) ip_v4 = instance.get('access_ip_v4') ip_v6 = instance.get('access_ip_v6') @@ -339,6 +344,10 @@ class ViewBuilder(common.ViewBuilder): trusted_certs = instance.trusted_certs.ids server["server"]["trusted_image_certificates"] = trusted_certs + if show_server_groups: + server['server']['server_groups'] = self._get_server_groups( + context, + instance) return server def index(self, request, instances, cell_down_support=False): @@ -633,3 +642,12 @@ class ViewBuilder(common.ViewBuilder): # with v2.0. key = "os-extended-volumes:volumes_attached" server[key] = volumes_attached + + @staticmethod + def _get_server_groups(context, instance): + try: + sg = objects.InstanceGroup.get_by_instance_uuid(context, + instance.uuid) + return [sg.uuid] + except exception.InstanceGroupNotFound: + return [] diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-action-rebuild-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-action-rebuild-resp.json.tpl new file mode 100644 index 0000000000..6082dd35f7 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-action-rebuild-resp.json.tpl @@ -0,0 +1,63 @@ +{ + "server": { + "accessIPv4": "%(access_ip_v4)s", + "accessIPv6": "%(access_ip_v6)s", + "addresses": { + "private": [ + { + "addr": "%(ip)s", + "version": 4 + } + ] + }, + "adminPass": "%(password)s", + "created": "%(isotime)s", + "flavor": { + "disk": 1, + "ephemeral": 0, + "extra_specs": {}, + "original_name": "m1.tiny", + "ram": 512, + "swap": 0, + "vcpus": 1 + }, + "hostId": "%(hostid)s", + "id": "%(uuid)s", + "image": { + "id": "%(uuid)s", + "links": [ + { + "href": "%(compute_endpoint)s/images/%(uuid)s", + "rel": "bookmark" + } + ] + }, + "key_name": null, + "links": [ + { + "href": "%(versioned_compute_endpoint)s/servers/%(uuid)s", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/servers/%(uuid)s", + "rel": "bookmark" + } + ], + "locked": false, + "metadata": { + "meta_var": "meta_val" + }, + "server_groups": ["%(uuid)s"], + "trusted_image_certificates": null, + "name": "%(name)s", + "description": null, + "progress": 0, + "OS-DCF:diskConfig": "AUTO", + "status": "ACTIVE", + "tags": [], + "tenant_id": "6f70656e737461636b20342065766572", + "updated": "%(isotime)s", + "user_id": "fake", + "user_data": "ZWNobyAiaGVsbG8gd29ybGQi" + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-action-rebuild.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-action-rebuild.json.tpl new file mode 100644 index 0000000000..5b61faeed8 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-action-rebuild.json.tpl @@ -0,0 +1,14 @@ +{ + "rebuild" : { + "accessIPv4" : "%(access_ip_v4)s", + "accessIPv6" : "%(access_ip_v6)s", + "OS-DCF:diskConfig": "AUTO", + "imageRef" : "%(uuid)s", + "name" : "%(name)s", + "adminPass" : "%(pass)s", + "metadata" : { + "meta_var" : "meta_val" + }, + "user_data": "ZWNobyAiaGVsbG8gd29ybGQi" + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-create-req.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-create-req.json.tpl new file mode 100644 index 0000000000..7ee3c40404 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-create-req.json.tpl @@ -0,0 +1,23 @@ +{ + "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", + "metadata" : { + "My Server Name" : "Apache1" + }, + "security_groups": [ + { + "name": "default" + } + ], + "user_data" : "%(user_data)s", + "networks": "auto" + }, + "OS-SCH-HNT:scheduler_hints": { + "group": "%(sg_uuid)s" + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-create-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-create-resp.json.tpl new file mode 100644 index 0000000000..20265ed889 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/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" + } + ] + } +} \ No newline at end of file diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-get-down-cell-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-get-down-cell-resp.json.tpl new file mode 100644 index 0000000000..355594317b --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-get-down-cell-resp.json.tpl @@ -0,0 +1,30 @@ +{ + "server": { + "OS-EXT-STS:power_state": 0, + "OS-EXT-AZ:availability_zone": "UNKNOWN", + "created": "%(isotime)s", + "flavor": { + "disk": 1, + "ephemeral": 0, + "extra_specs": {}, + "original_name": "m1.tiny", + "ram": 512, + "swap": 0, + "vcpus": 1 + }, + "id": "%(id)s", + "image": { + "id": "70a599e0-31e7-49b7-b260-868f441e862b", + "links": [ + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "bookmark" + } + ] + }, + "status": "UNKNOWN", + "server_groups": ["%(uuid)s"], + "tenant_id": "project", + "user_id": "fake" + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-get-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-get-resp.json.tpl new file mode 100644 index 0000000000..ac2536ab77 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-get-resp.json.tpl @@ -0,0 +1,87 @@ +{ + "server": { + "accessIPv4": "%(access_ip_v4)s", + "accessIPv6": "%(access_ip_v6)s", + "addresses": { + "private": [ + { + "addr": "%(ip)s", + "OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff", + "OS-EXT-IPS:type": "fixed", + "version": 4 + } + ] + }, + "created": "%(isotime)s", + "description": null, + "host_status": "UP", + "locked": false, + "tags": [], + "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" + } + ] + }, + "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": "nova", + "OS-EXT-SRV-ATTR:host": "%(compute_host)s", + "OS-EXT-SRV-ATTR:hostname": "%(hostname)s", + "OS-EXT-SRV-ATTR:hypervisor_hostname": "%(hypervisor_hostname)s", + "OS-EXT-SRV-ATTR:instance_name": "%(instance_name)s", + "OS-EXT-SRV-ATTR:kernel_id": "", + "OS-EXT-SRV-ATTR:launch_index": 0, + "OS-EXT-SRV-ATTR:ramdisk_id": "", + "OS-EXT-SRV-ATTR:reservation_id": "%(reservation_id)s", + "OS-EXT-SRV-ATTR:root_device_name": "/dev/sda", + "OS-EXT-SRV-ATTR:user_data": "%(user_data)s", + "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, + "progress": 0, + "security_groups": [ + { + "name": "default" + } + ], + "server_groups": ["%(uuid)s"], + "status": "ACTIVE", + "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.71/server-groups-post-req.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-groups-post-req.json.tpl new file mode 100644 index 0000000000..f758e7a806 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-groups-post-req.json.tpl @@ -0,0 +1,6 @@ +{ + "server_group": { + "name": "%(name)s", + "policy": "affinity" + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-groups-post-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-groups-post-resp.json.tpl new file mode 100644 index 0000000000..ab5af46265 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-groups-post-resp.json.tpl @@ -0,0 +1,11 @@ +{ + "server_group": { + "id": "%(id)s", + "members": [], + "name": "test", + "policy": "affinity", + "project_id": "6f70656e737461636b20342065766572", + "rules": {}, + "user_id": "fake" + } +} \ No newline at end of file diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-update-req.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-update-req.json.tpl new file mode 100644 index 0000000000..f1f436642f --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-update-req.json.tpl @@ -0,0 +1,9 @@ +{ + "server": { + "accessIPv4": "%(access_ip_v4)s", + "accessIPv6": "%(access_ip_v6)s", + "OS-DCF:diskConfig": "AUTO", + "name": "new-server-test", + "description": "Sample description" + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-update-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-update-resp.json.tpl new file mode 100644 index 0000000000..a7353ec3db --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.71/server-update-resp.json.tpl @@ -0,0 +1,61 @@ +{ + "server": { + "OS-DCF:diskConfig": "AUTO", + "accessIPv4": "%(access_ip_v4)s", + "accessIPv6": "%(access_ip_v6)s", + "addresses": { + "private": [ + { + "addr": "192.168.0.3", + "version": 4 + } + ] + }, + "created": "%(isotime)s", + "description": "Sample 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" + } + ] + }, + "links": [ + { + "href": "%(versioned_compute_endpoint)s/servers/%(id)s", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/servers/%(id)s", + "rel": "bookmark" + } + ], + "locked": false, + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "progress": 0, + "status": "ACTIVE", + "server_groups": ["%(uuid)s"], + "tags": [], + "tenant_id": "6f70656e737461636b20342065766572", + "trusted_image_certificates": null, + "updated": "%(isotime)s", + "user_id": "fake" + } +} diff --git a/nova/tests/functional/api_sample_tests/test_servers.py b/nova/tests/functional/api_sample_tests/test_servers.py index af85d97ac0..5532171a5e 100644 --- a/nova/tests/functional/api_sample_tests/test_servers.py +++ b/nova/tests/functional/api_sample_tests/test_servers.py @@ -53,7 +53,8 @@ class ServersSampleBase(api_sample_base.ApiSampleTestBaseV21): avr.APIVersionRequest(min), avr.APIVersionRequest(max)): return name - def _post_server(self, use_common_server_api_samples=True, name=None): + def _post_server(self, use_common_server_api_samples=True, name=None, + extra_subs=None): # param use_common_server_api_samples: Boolean to set whether tests use # common sample files for server post request and response. # Default is True which means _get_sample_path method will fetch the @@ -73,6 +74,8 @@ class ServersSampleBase(api_sample_base.ApiSampleTestBaseV21): '-[0-9a-f]{4}-[0-9a-f]{12}', 'name': 'new-server-test' if name is None else name, } + if extra_subs: + subs.update(extra_subs) orig_value = self.__class__._use_common_server_api_samples try: @@ -414,6 +417,99 @@ class ServersSampleJson269Test(ServersSampleBase): self._verify_response('server-get-resp', subs, response, 200) +class ServersSampleJson271Test(ServersSampleBase): + microversion = '2.71' + scenarios = [('v2_71', {'api_major_version': 'v2.1'})] + + def setUp(self): + super(ServersSampleJson271Test, self).setUp() + self.common_subs = { + 'hostid': '[a-f0-9]+', + 'instance_name': 'instance-\d{8}', + 'hypervisor_hostname': r'[\w\.\-]+', + 'hostname': r'[\w\.\-]+', + 'access_ip_v4': '1.2.3.4', + 'access_ip_v6': '80fe::', + 'user_data': (self.user_data if six.PY2 + else self.user_data.decode('utf-8')), + 'cdrive': '.*', + } + + # create server group + subs = {'name': 'test'} + response = self._do_post('os-server-groups', + 'server-groups-post-req', subs) + self.sg_uuid = self._verify_response('server-groups-post-resp', + subs, response, 200) + + def _test_servers_post(self): + return self._post_server( + use_common_server_api_samples=False, + extra_subs={'sg_uuid': self.sg_uuid}) + + def test_servers_get_with_server_group(self): + uuid = self._test_servers_post() + response = self._do_get('servers/%s' % uuid) + subs = self.common_subs.copy() + subs['id'] = uuid + self._verify_response('server-get-resp', subs, response, 200) + + def test_servers_update_with_server_groups(self): + uuid = self._test_servers_post() + subs = self.common_subs.copy() + subs['id'] = uuid + response = self._do_put('servers/%s' % uuid, + 'server-update-req', subs) + self._verify_response('server-update-resp', subs, response, 200) + + def test_servers_rebuild_with_server_groups(self): + uuid = self._test_servers_post() + fakes.stub_out_key_pair_funcs(self) + image = fake.get_valid_image_id() + params = { + 'uuid': image, + 'name': 'foobar', + 'key_name': 'new-key', + 'description': 'description of foobar', + 'pass': 'seekr3t', + 'access_ip_v4': '1.2.3.4', + 'access_ip_v6': '80fe::', + } + resp = self._do_post('servers/%s/action' % uuid, + 'server-action-rebuild', params) + subs = self.common_subs.copy() + subs.update(params) + subs['id'] = uuid + del subs['uuid'] + self._verify_response('server-action-rebuild-resp', subs, resp, 202) + + def test_server_get_from_down_cells(self): + def _fake_instancemapping_get_by_cell_and_project(*args, **kwargs): + # global cell based on which rest of the functions are stubbed out + cell_fixture = nova_fixtures.SingleCellSimple() + return [{ + 'id': 1, + 'updated_at': None, + 'created_at': None, + 'instance_uuid': utils_fixture.uuidsentinel.inst, + 'cell_id': 1, + 'project_id': "6f70656e737461636b20342065766572", + 'cell_mapping': cell_fixture._fake_cell_list()[0], + 'queued_for_delete': False + }] + + self.stub_out('nova.objects.InstanceMappingList.' + '_get_not_deleted_by_cell_and_project_from_db', + _fake_instancemapping_get_by_cell_and_project) + + uuid = self._test_servers_post() + with nova_fixtures.DownCellFixture(): + response = self._do_get('servers/%s' % uuid) + subs = {'id': uuid} + self._verify_response('server-get-down-cell-resp', + subs, response, 200) + + class ServersUpdateSampleJsonTest(ServersSampleBase): def test_update_server(self): diff --git a/nova/tests/unit/api/openstack/compute/test_serversV21.py b/nova/tests/unit/api/openstack/compute/test_serversV21.py index b5d10a0ac0..483cd10b2c 100644 --- a/nova/tests/unit/api/openstack/compute/test_serversV21.py +++ b/nova/tests/unit/api/openstack/compute/test_serversV21.py @@ -57,6 +57,7 @@ from nova import exception from nova.image import glance from nova import objects from nova.objects import instance as instance_obj +from nova.objects.instance_group import InstanceGroup from nova.objects import tag from nova.policies import servers as server_policies from nova import policy @@ -2508,6 +2509,21 @@ class ServerControllerTestV266(ControllerTest): self.assertRaises(webob.exc.HTTPBadRequest, self.controller.index, req) +class ServersControllerTestV271(ControllerTest): + wsgi_api_version = '2.71' + + def req(self, url, use_admin_context=False): + return fakes.HTTPRequest.blank(url, + use_admin_context=use_admin_context, + version=self.wsgi_api_version) + + def test_show_server_group_not_exist(self): + req = self.req('/fake/servers/%s' % FAKE_UUID) + servers = self.controller.show(req, FAKE_UUID) + expect_sg = [] + self.assertEqual(expect_sg, servers['server']['server_groups']) + + class ServersControllerDeleteTest(ControllerTest): def setUp(self): @@ -3433,6 +3449,43 @@ class ServersControllerRebuildTestV263(ControllerTest): six.text_type(ex)) +class ServersControllerRebuildTestV271(ControllerTest): + image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6' + + def setUp(self): + super(ServersControllerRebuildTestV271, self).setUp() + self.req = fakes.HTTPRequest.blank('/fake/servers/a/action', + use_admin_context=True) + self.req.method = 'POST' + self.req.headers["content-type"] = "application/json" + self.req_user_id = self.req.environ['nova.context'].user_id + self.req_project_id = self.req.environ['nova.context'].project_id + self.req.api_version_request = (api_version_request. + APIVersionRequest('2.71')) + self.body = { + "rebuild": { + "imageRef": self.image_uuid, + "user_data": None + } + } + + @mock.patch('nova.compute.api.API.get') + def _rebuild_server(self, mock_get): + ctx = self.req.environ['nova.context'] + mock_get.return_value = fakes.stub_instance_obj(ctx, + vm_state=vm_states.ACTIVE, project_id=self.req_project_id, + user_id=self.req_user_id) + server = self.controller._action_rebuild( + self.req, FAKE_UUID, body=self.body).obj['server'] + return server + + @mock.patch.object(InstanceGroup, 'get_by_instance_uuid', + side_effect=exception.InstanceGroupNotFound(group_uuid=FAKE_UUID)) + def test_rebuild_with_server_group_not_exist(self, mock_sg_get): + server = self._rebuild_server() + self.assertEqual([], server['server_groups']) + + class ServersControllerUpdateTest(ControllerTest): def _get_request(self, body=None): @@ -3721,6 +3774,23 @@ class ServersControllerUpdateTestV219(ServersControllerUpdateTest): req, FAKE_UUID, body=body) +class ServersControllerUpdateTestV271(ServersControllerUpdateTest): + body = {'server': {'name': 'server_test'}} + + def _get_request(self, body=None): + req = super(ServersControllerUpdateTestV271, self)._get_request( + body=body) + req.api_version_request = api_version_request.APIVersionRequest('2.71') + return req + + @mock.patch.object(InstanceGroup, 'get_by_instance_uuid', + side_effect=exception.InstanceGroupNotFound(group_uuid=FAKE_UUID)) + def test_update_with_server_group_not_exist(self, mock_sg_get): + req = self._get_request(self.body) + res_dict = self.controller.update(req, FAKE_UUID, body=self.body) + self.assertEqual([], res_dict['server']['server_groups']) + + class ServerStatusTest(test.TestCase): def setUp(self): diff --git a/releasenotes/notes/show-server-group-8d4bf609213a94de.yaml b/releasenotes/notes/show-server-group-8d4bf609213a94de.yaml new file mode 100644 index 0000000000..cf234c2e9a --- /dev/null +++ b/releasenotes/notes/show-server-group-8d4bf609213a94de.yaml @@ -0,0 +1,10 @@ +--- +features: + - | + Starting with the 2.71 microversion the ``server_groups`` parameter will be + in the response body of the following APIs to list the server groups to + which the server belongs: + + * ``GET /servers/{server_id}`` + * ``PUT /servers/{server_id}`` + * ``POST /servers/{server_id}/action (rebuild)``