From 90636e0f33e50857b7d3e6be3ae855918e2c199a Mon Sep 17 00:00:00 2001 From: Chris Friesen Date: Mon, 13 Feb 2017 09:55:01 -0600 Subject: [PATCH] show flavor info in server details Add a new microversion to change the flavor field in the server details to display a subset of the flavor information instead of just a link to the original flavor. This is more reliable since it shows the actual instance size, while the flavor may have been deleted/recreated in the meantime or the flavor extra-specs may have been modified. Implements: blueprint instance-flavor-api Change-Id: If646149efb7eec8c90bf7d07c39ff4c495349941 --- api-ref/source/parameters.yaml | 93 +++++++++++++++- api-ref/source/servers-actions.inc | 23 ++-- api-ref/source/servers.inc | 49 +++++++-- .../v2.47/server-action-rebuild-resp.json | 59 +++++++++++ .../servers/v2.47/server-action-rebuild.json | 19 ++++ .../servers/v2.47/server-create-req.json | 30 ++++++ .../servers/v2.47/server-create-resp.json | 22 ++++ .../servers/v2.47/server-get-resp.json | 98 +++++++++++++++++ .../servers/v2.47/server-update-req.json | 8 ++ .../servers/v2.47/server-update-resp.json | 58 ++++++++++ .../servers/v2.47/servers-details-resp.json | 100 ++++++++++++++++++ .../servers/v2.47/servers-list-resp.json | 18 ++++ .../versions/v21-version-get-resp.json | 2 +- .../versions/versions-get-resp.json | 2 +- nova/api/openstack/api_version_request.py | 6 +- .../compute/rest_api_version_history.rst | 11 ++ nova/api/openstack/compute/servers.py | 1 - nova/api/openstack/compute/views/servers.py | 19 ++++ .../v2.47/server-action-rebuild-resp.json.tpl | 59 +++++++++++ .../v2.47/server-action-rebuild.json.tpl | 19 ++++ .../servers/v2.47/server-create-req.json.tpl | 30 ++++++ .../servers/v2.47/server-create-resp.json.tpl | 22 ++++ .../servers/v2.47/server-get-resp.json.tpl | 92 ++++++++++++++++ .../servers/v2.47/server-update-req.json.tpl | 8 ++ .../servers/v2.47/server-update-resp.json.tpl | 58 ++++++++++ .../v2.47/servers-details-resp.json.tpl | 94 ++++++++++++++++ .../servers/v2.47/servers-list-resp.json.tpl | 18 ++++ .../api_sample_tests/test_servers.py | 35 +++++- nova/tests/functional/wsgi/test_servers.py | 10 +- .../api/openstack/compute/test_serversV21.py | 58 ++++++++++ ...ct-in-server-details-589c1db487f226cb.yaml | 7 ++ 31 files changed, 1103 insertions(+), 25 deletions(-) create mode 100644 doc/api_samples/servers/v2.47/server-action-rebuild-resp.json create mode 100644 doc/api_samples/servers/v2.47/server-action-rebuild.json create mode 100644 doc/api_samples/servers/v2.47/server-create-req.json create mode 100644 doc/api_samples/servers/v2.47/server-create-resp.json create mode 100644 doc/api_samples/servers/v2.47/server-get-resp.json create mode 100644 doc/api_samples/servers/v2.47/server-update-req.json create mode 100644 doc/api_samples/servers/v2.47/server-update-resp.json create mode 100644 doc/api_samples/servers/v2.47/servers-details-resp.json create mode 100644 doc/api_samples/servers/v2.47/servers-list-resp.json create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-action-rebuild-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-action-rebuild.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-create-req.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-create-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-get-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-update-req.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-update-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/servers-details-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/servers-list-resp.json.tpl create mode 100644 releasenotes/notes/display-flavor-dict-in-server-details-589c1db487f226cb.yaml diff --git a/api-ref/source/parameters.yaml b/api-ref/source/parameters.yaml index 3a572160a424..91fb504fb77d 100644 --- a/api-ref/source/parameters.yaml +++ b/api-ref/source/parameters.yaml @@ -1988,6 +1988,15 @@ extra_specs: in: body required: true type: object +extra_specs_2_47: + min_version: 2.47 + description: | + A dictionary of the flavor's extra-specs key-and-value pairs. This will + only be included if the user is allowed by policy to index flavor + extra_specs. + in: body + required: false + type: object fault: description: | A fault object. Only displayed in the failed response. @@ -2092,6 +2101,13 @@ flavor_cpus: type: integer description: | The number of virtual CPUs that will be allocated to the server. +flavor_cpus_2_47: + min_version: 2.47 + in: body + required: true + type: integer + description: | + The number of virtual CPUs that were allocated to the server. flavor_disabled: in: body required: false @@ -2110,6 +2126,13 @@ flavor_disk: select the compute host based on the virtual image size. Therefore, 0 should only be used for volume booted instances or for testing purposes. +flavor_disk_2_47: + min_version: 2.47 + in: body + required: true + type: integer + description: | + The size of the root disk that was created in GiB. flavor_ephem_disk: in: body required: true @@ -2119,6 +2142,13 @@ flavor_ephem_disk: GiB. Ephemeral disks may be written over on server state changes. So should only be used as a scratch space for applications that are aware of its limitations. Defaults to 0. +flavor_ephem_disk_2_47: + min_version: 2.47 + in: body + required: true + type: integer + description: | + The size of the ephemeral disk that was created, in GiB. flavor_ephem_disk_in: in: body required: false @@ -2136,6 +2166,13 @@ flavor_extra_spec_key2: in: body required: true type: string +flavor_extra_spec_key_2_47: + description: | + The extra spec key of a flavor. + in: body + required: true + type: string + min_version: 2.47 flavor_extra_spec_value: description: | The extra spec value of a flavor. It appears in the os-extra-specs' @@ -2144,6 +2181,13 @@ flavor_extra_spec_value: in: body required: true type: string +flavor_extra_spec_value_2_47: + description: | + The extra spec value of a flavor. + in: body + required: true + type: string + min_version: 2.47 flavor_id_body: description: | The ID of the flavor. While people often make this look like @@ -2151,6 +2195,14 @@ flavor_id_body: in: body required: true type: string +flavor_id_body_2_46: + description: | + The ID of the flavor. While people often make this look like + an int, this is really a string. + in: body + required: true + type: string + max_version: 2.46 flavor_id_body_create: description: | The ID of the flavor. While people often make this look like an int, this @@ -2172,6 +2224,16 @@ flavor_is_public_in: in: body required: false type: boolean +flavor_links_2_46: + description: | + Links to the flavor resource. See `API Guide / Links and + References + `_ + for more info. + in: body + required: true + type: array + max_version: 2.46 flavor_name: description: | The display name of a flavor. @@ -2184,12 +2246,26 @@ flavor_name_optional: in: body required: false type: string +flavor_original_name: + description: | + The display name of a flavor. + in: body + required: true + type: string + min_version: 2.47 flavor_ram: description: | The amount of RAM a flavor has, in MiB. in: body required: true type: integer +flavor_ram_2_47: + description: | + The amount of RAM a flavor has, in MiB. + in: body + required: true + type: integer + min_version: 2.47 flavor_rxtx_factor: description: | The receive / transmit factor (as a float) that will be set on @@ -2208,9 +2284,13 @@ flavor_rxtx_factor_in: type: float flavor_server: description: | - The ID and links for the flavor for your server instance. A flavor is a combination - of memory, disk size, and CPUs. This can be empty object in case flavor information - is not present in the system. + Before microversion 2.47 this contains the ID and links for the flavor + used to boot the server instance. This can be an empty object in case + flavor information is no longer present in the system. + + As of microversion 2.47 this contains a subset of the actual flavor + information used to create the server instance, represented as a nested + dictionary. in: body required: true type: object @@ -2221,6 +2301,13 @@ flavor_swap: in: body required: true type: integer +flavor_swap_2_47: + description: | + The size of a dedicated swap disk that was allocated, in MiB. + in: body + required: true + type: integer + min_version: 2.47 flavor_swap_in: description: | The size of a dedicated swap disk that will be allocated, in diff --git a/api-ref/source/servers-actions.inc b/api-ref/source/servers-actions.inc index 290b1f8fa9a3..8a57cfcf9adf 100644 --- a/api-ref/source/servers-actions.inc +++ b/api-ref/source/servers-actions.inc @@ -486,9 +486,9 @@ Request - preserve_ephemeral: preserve_ephemeral - description: server_description -**Example Rebuild Server (rebuild Action) (v2.26)** +**Example Rebuild Server (rebuild Action) (v2.47)** -.. literalinclude:: ../../doc/api_samples/servers/v2.26/server-action-rebuild.json +.. literalinclude:: ../../doc/api_samples/servers/v2.47/server-action-rebuild.json :language: javascript Response @@ -503,9 +503,18 @@ Response - addresses: addresses_obj - adminPass: adminPass_response - created: created - - flavor: flavor - - flavor.id: flavor_id_body - - flavor.links: links + - flavor: flavor_server + - flavor.id: flavor_id_body_2_46 + - flavor.links: flavor_links_2_46 + - flavor.vcpus: flavor_cpus_2_47 + - flavor.ram: flavor_ram_2_47 + - flavor.disk: flavor_disk_2_47 + - flavor.ephemeral: flavor_ephem_disk_2_47 + - flavor.swap: flavor_swap_2_47 + - flavor.original_name: flavor_original_name + - flavor.extra_specs: extra_specs_2_47 + - flavor.extra_specs.key: flavor_extra_spec_key_2_47 + - flavor.extra_specs.value: flavor_extra_spec_value_2_47 - hostId: hostId - id: server_id - image: image @@ -524,9 +533,9 @@ Response - description: server_description_resp - tags: tags -**Example Rebuild Server (rebuild Action) (v2.26)** +**Example Rebuild Server (rebuild Action) (v2.47)** -.. literalinclude:: ../../doc/api_samples/servers/v2.26/server-action-rebuild-resp.json +.. literalinclude:: ../../doc/api_samples/servers/v2.47/server-action-rebuild-resp.json :language: javascript Remove (Disassociate) Floating Ip (removeFloatingIp Action) (DEPRECATED) diff --git a/api-ref/source/servers.inc b/api-ref/source/servers.inc index 9092349e765f..2279dfed7a49 100644 --- a/api-ref/source/servers.inc +++ b/api-ref/source/servers.inc @@ -502,6 +502,17 @@ Response - addresses: addresses - created: created - flavor: flavor_server + - flavor.id: flavor_id_body_2_46 + - flavor.links: flavor_links_2_46 + - flavor.vcpus: flavor_cpus_2_47 + - flavor.ram: flavor_ram_2_47 + - flavor.disk: flavor_disk_2_47 + - flavor.ephemeral: flavor_ephem_disk_2_47 + - flavor.swap: flavor_swap_2_47 + - flavor.original_name: flavor_original_name + - flavor.extra_specs: extra_specs_2_47 + - flavor.extra_specs.key: flavor_extra_spec_key_2_47 + - flavor.extra_specs.value: flavor_extra_spec_value_2_47 - hostId: hostId - id: server_id - image: image @@ -542,9 +553,9 @@ Response - OS-EXT-SRV-ATTR:user_data: server_user_data - locked: locked -**Example List Servers Detailed** +**Example List Servers Detailed (2.47)** -.. literalinclude:: /../../doc/api_samples/servers/servers-details-resp.json +.. literalinclude:: /../../doc/api_samples/servers/v2.47/servers-details-resp.json :language: javascript @@ -590,6 +601,17 @@ Response - addresses: addresses - created: created - flavor: flavor_server + - flavor.id: flavor_id_body_2_46 + - flavor.links: flavor_links_2_46 + - flavor.vcpus: flavor_cpus_2_47 + - flavor.ram: flavor_ram_2_47 + - flavor.disk: flavor_disk_2_47 + - flavor.ephemeral: flavor_ephem_disk_2_47 + - flavor.swap: flavor_swap_2_47 + - flavor.original_name: flavor_original_name + - flavor.extra_specs: extra_specs_2_47 + - flavor.extra_specs.key: flavor_extra_spec_key_2_47 + - flavor.extra_specs.value: flavor_extra_spec_value_2_47 - hostId: hostId - id: server_id - image: image @@ -631,9 +653,9 @@ Response - OS-EXT-SRV-ATTR:user_data: server_user_data - locked: locked -**Example Show Server Details** +**Example Show Server Details (2.47)** -.. literalinclude:: ../../doc/api_samples/servers/server-get-resp.json +.. literalinclude:: ../../doc/api_samples/servers/v2.47/server-get-resp.json :language: javascript Update Server @@ -660,9 +682,9 @@ Request - OS-DCF:diskConfig: OS-DCF:diskConfig - description: server_description -**Example Update server name** +**Example Update server name (2.47)** -.. literalinclude:: ../../doc/api_samples/servers/server-update-req.json +.. literalinclude:: ../../doc/api_samples/servers/v2.47/server-update-req.json :language: javascript .. @@ -688,6 +710,17 @@ Response - addresses: addresses - created: created - flavor: flavor_server + - flavor.id: flavor_id_body_2_46 + - flavor.links: flavor_links_2_46 + - flavor.vcpus: flavor_cpus_2_47 + - flavor.ram: flavor_ram_2_47 + - flavor.disk: flavor_disk_2_47 + - flavor.ephemeral: flavor_ephem_disk_2_47 + - flavor.swap: flavor_swap_2_47 + - flavor.original_name: flavor_original_name + - flavor.extra_specs: extra_specs_2_47 + - flavor.extra_specs.key: flavor_extra_spec_key_2_47 + - flavor.extra_specs.value: flavor_extra_spec_value_2_47 - hostId: hostId - id: server_id - image: image @@ -724,9 +757,9 @@ Response - OS-EXT-SRV-ATTR:user_data: server_user_data - locked: locked -**Example Update server name** +**Example Update server name (2.47)** -.. literalinclude:: ../../doc/api_samples/servers/server-update-resp.json +.. literalinclude:: ../../doc/api_samples/servers/v2.47/server-update-resp.json :language: javascript Delete Server diff --git a/doc/api_samples/servers/v2.47/server-action-rebuild-resp.json b/doc/api_samples/servers/v2.47/server-action-rebuild-resp.json new file mode 100644 index 000000000000..7069951d97f3 --- /dev/null +++ b/doc/api_samples/servers/v2.47/server-action-rebuild-resp.json @@ -0,0 +1,59 @@ +{ + "server": { + "accessIPv4": "1.2.3.4", + "accessIPv6": "80fe::", + "addresses": { + "private": [ + { + "addr": "192.168.0.3", + "version": 4 + } + ] + }, + "adminPass": "seekr3t", + "created": "2013-11-14T06:29:00Z", + "flavor": { + "disk": 1, + "ephemeral": 0, + "extra_specs": {}, + "original_name": "m1.tiny", + "ram": 512, + "swap": 0, + "vcpus": 1 + }, + "hostId": "28d8d56f0e3a77e20891f455721cbb68032e017045e20aa5dfc6cb66", + "id": "a0a80a94-3d81-4a10-822a-daa0cf9e870b", + "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/6f70656e737461636b20342065766572/servers/a0a80a94-3d81-4a10-822a-daa0cf9e870b", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/a0a80a94-3d81-4a10-822a-daa0cf9e870b", + "rel": "bookmark" + } + ], + "locked": false, + "metadata": { + "meta_var": "meta_val" + }, + "name": "foobar", + "description" : null, + "progress": 0, + "status": "ACTIVE", + "OS-DCF:diskConfig": "AUTO", + "tags": [], + "tenant_id": "6f70656e737461636b20342065766572", + "updated": "2013-11-14T06:29:02Z", + "user_id": "fake" + } +} diff --git a/doc/api_samples/servers/v2.47/server-action-rebuild.json b/doc/api_samples/servers/v2.47/server-action-rebuild.json new file mode 100644 index 000000000000..c65c0457afb9 --- /dev/null +++ b/doc/api_samples/servers/v2.47/server-action-rebuild.json @@ -0,0 +1,19 @@ +{ + "rebuild" : { + "imageRef" : "70a599e0-31e7-49b7-b260-868f441e862b", + "accessIPv4" : "1.2.3.4", + "accessIPv6" : "80fe::", + "adminPass" : "seekr3t", + "metadata" : { + "meta_var" : "meta_val" + }, + "name" : "foobar", + "OS-DCF:diskConfig": "AUTO", + "personality" : [ + { + "path" : "/etc/banner.txt", + "contents" : "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6 b25zLiINCg0KLVJpY2hhcmQgQmFjaA==" + } + ] + } +} diff --git a/doc/api_samples/servers/v2.47/server-create-req.json b/doc/api_samples/servers/v2.47/server-create-req.json new file mode 100644 index 000000000000..4068a9ed1ef5 --- /dev/null +++ b/doc/api_samples/servers/v2.47/server-create-req.json @@ -0,0 +1,30 @@ +{ + "server" : { + "accessIPv4": "1.2.3.4", + "accessIPv6": "80fe::", + "name" : "new-server-test", + "imageRef" : "70a599e0-31e7-49b7-b260-868f441e862b", + "flavorRef" : "6", + "availability_zone": "nova", + "OS-DCF:diskConfig": "AUTO", + "metadata" : { + "My Server Name" : "Apache1" + }, + "personality": [ + { + "path": "/etc/banner.txt", + "contents": "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6 b25zLiINCg0KLVJpY2hhcmQgQmFjaA==" + } + ], + "security_groups": [ + { + "name": "default" + } + ], + "user_data" : "IyEvYmluL2Jhc2gKL2Jpbi9zdQplY2hvICJJIGFtIGluIHlvdSEiCg==", + "networks": "auto" + }, + "OS-SCH-HNT:scheduler_hints": { + "same_host": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" + } +} \ No newline at end of file diff --git a/doc/api_samples/servers/v2.47/server-create-resp.json b/doc/api_samples/servers/v2.47/server-create-resp.json new file mode 100644 index 000000000000..dd0bb9f2284e --- /dev/null +++ b/doc/api_samples/servers/v2.47/server-create-resp.json @@ -0,0 +1,22 @@ +{ + "server": { + "OS-DCF:diskConfig": "AUTO", + "adminPass": "S5wqy9sPYUvU", + "id": "97108291-2fd7-4dc2-a909-eaae0306a6a9", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/97108291-2fd7-4dc2-a909-eaae0306a6a9", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/97108291-2fd7-4dc2-a909-eaae0306a6a9", + "rel": "bookmark" + } + ], + "security_groups": [ + { + "name": "default" + } + ] + } +} \ No newline at end of file diff --git a/doc/api_samples/servers/v2.47/server-get-resp.json b/doc/api_samples/servers/v2.47/server-get-resp.json new file mode 100644 index 000000000000..51dc94949aa0 --- /dev/null +++ b/doc/api_samples/servers/v2.47/server-get-resp.json @@ -0,0 +1,98 @@ +{ + "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-ov3q80zj", + "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": "2017-02-14T19:23:59.895661", + "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": "2017-02-14T19:23:58Z", + "description": null, + "flavor": { + "disk": 1, + "ephemeral": 0, + "extra_specs": { + "hw:cpu_model": "SandyBridge", + "hw:mem_page_size": "2048", + "hw:cpu_policy": "dedicated" + }, + "original_name": "m1.tiny.specs", + "ram": 512, + "swap": 0, + "vcpus": 1 + }, + "hostId": "2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6", + "host_status": "UP", + "id": "9168b536-cd40-4630-b43f-b259807c6e87", + "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/9168b536-cd40-4630-b43f-b259807c6e87", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/9168b536-cd40-4630-b43f-b259807c6e87", + "rel": "bookmark" + } + ], + "locked": false, + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "os-extended-volumes:volumes_attached": [ + { + "delete_on_termination": false, + "id": "volume_id1" + }, + { + "delete_on_termination": false, + "id": "volume_id2" + } + ], + "progress": 0, + "security_groups": [ + { + "name": "default" + } + ], + "status": "ACTIVE", + "tags": [], + "tenant_id": "6f70656e737461636b20342065766572", + "updated": "2017-02-14T19:24:00Z", + "user_id": "fake" + } +} diff --git a/doc/api_samples/servers/v2.47/server-update-req.json b/doc/api_samples/servers/v2.47/server-update-req.json new file mode 100644 index 000000000000..56e1a8c56a65 --- /dev/null +++ b/doc/api_samples/servers/v2.47/server-update-req.json @@ -0,0 +1,8 @@ +{ + "server": { + "accessIPv4": "1.2.3.4", + "accessIPv6": "80fe::", + "OS-DCF:diskConfig": "AUTO", + "name" : "new-server-test" + } +} \ No newline at end of file diff --git a/doc/api_samples/servers/v2.47/server-update-resp.json b/doc/api_samples/servers/v2.47/server-update-resp.json new file mode 100644 index 000000000000..d2b2545f35aa --- /dev/null +++ b/doc/api_samples/servers/v2.47/server-update-resp.json @@ -0,0 +1,58 @@ +{ + "server": { + "OS-DCF:diskConfig": "AUTO", + "accessIPv4": "1.2.3.4", + "accessIPv6": "80fe::", + "addresses": { + "private": [ + { + "addr": "192.168.0.3", + "version": 4 + } + ] + }, + "created": "2012-12-02T02:11:57Z", + "description": null, + "flavor": { + "disk": 1, + "ephemeral": 0, + "extra_specs": {}, + "original_name": "m1.tiny", + "ram": 512, + "swap": 0, + "vcpus": 1 + }, + "hostId": "6e84af987b4e7ec1c039b16d21f508f4a505672bd94fb0218b668d07", + "id": "324dfb7d-f4a9-419a-9a19-237df04b443b", + "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/6f70656e737461636b20342065766572/servers/324dfb7d-f4a9-419a-9a19-237df04b443b", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/324dfb7d-f4a9-419a-9a19-237df04b443b", + "rel": "bookmark" + } + ], + "locked": false, + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "progress": 0, + "status": "ACTIVE", + "tags": [], + "tenant_id": "6f70656e737461636b20342065766572", + "updated": "2012-12-02T02:11:58Z", + "user_id": "fake" + } +} diff --git a/doc/api_samples/servers/v2.47/servers-details-resp.json b/doc/api_samples/servers/v2.47/servers-details-resp.json new file mode 100644 index 000000000000..003bc65198e5 --- /dev/null +++ b/doc/api_samples/servers/v2.47/servers-details-resp.json @@ -0,0 +1,100 @@ +{ + "servers": [ + { + "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-iffothgx", + "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": "2017-02-14T19:24:43.891568", + "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": "2017-02-14T19:24:42Z", + "description": null, + "flavor": { + "disk": 1, + "ephemeral": 0, + "extra_specs": { + "hw:cpu_model": "SandyBridge", + "hw:mem_page_size": "2048", + "hw:cpu_policy": "dedicated" + }, + "original_name": "m1.tiny.specs", + "ram": 512, + "swap": 0, + "vcpus": 1 + }, + "hostId": "2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6", + "host_status": "UP", + "id": "764e369e-a874-4401-b7ce-43e4760888da", + "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/764e369e-a874-4401-b7ce-43e4760888da", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/764e369e-a874-4401-b7ce-43e4760888da", + "rel": "bookmark" + } + ], + "locked": false, + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "os-extended-volumes:volumes_attached": [ + { + "delete_on_termination": false, + "id": "volume_id1" + }, + { + "delete_on_termination": false, + "id": "volume_id2" + } + ], + "progress": 0, + "security_groups": [ + { + "name": "default" + } + ], + "status": "ACTIVE", + "tags": [], + "tenant_id": "6f70656e737461636b20342065766572", + "updated": "2017-02-14T19:24:43Z", + "user_id": "fake" + } + ] +} diff --git a/doc/api_samples/servers/v2.47/servers-list-resp.json b/doc/api_samples/servers/v2.47/servers-list-resp.json new file mode 100644 index 000000000000..c197a33167f8 --- /dev/null +++ b/doc/api_samples/servers/v2.47/servers-list-resp.json @@ -0,0 +1,18 @@ +{ + "servers": [ + { + "id": "6e3a87e6-a133-452e-86e1-a31291c1b1c8", + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/6e3a87e6-a133-452e-86e1-a31291c1b1c8", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/6e3a87e6-a133-452e-86e1-a31291c1b1c8", + "rel": "bookmark" + } + ], + "name": "new-server-test" + } + ] +} \ No newline at end of file diff --git a/doc/api_samples/versions/v21-version-get-resp.json b/doc/api_samples/versions/v21-version-get-resp.json index c52f282a993d..65a8cd182eea 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.46", + "version": "2.47", "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 257f11a156fd..b0daa7741a06 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.46", + "version": "2.47", "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 604374a4e7fd..1de20a291913 100644 --- a/nova/api/openstack/api_version_request.py +++ b/nova/api/openstack/api_version_request.py @@ -110,6 +110,10 @@ REST_API_VERSION_HISTORY = """REST API Version History: json dict in the response body with an image_id key and uuid value. * 2.46 - Return ``X-OpenStack-Request-ID`` header on requests. + * 2.47 - When displaying server details, display the flavor as a dict + rather than a link. If the user is prevented from retrieving + the flavor extra-specs by policy, simply omit the field from + the output. """ # The minimum and maximum versions of the API supported @@ -118,7 +122,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.46" +_MAX_API_VERSION = "2.47" DEFAULT_API_VERSION = _MIN_API_VERSION # Almost all proxy APIs which 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 1e28cf499cf2..f771c4aad7bc 100644 --- a/nova/api/openstack/compute/rest_api_version_history.rst +++ b/nova/api/openstack/compute/rest_api_version_history.rst @@ -545,3 +545,14 @@ user documentation. to be consistent with the rest of OpenStack. This is a signaling only microversion, as these header settings happen well before microversion processing. + +2.47 +---- + + Replace the ``flavor`` name/ref with the actual flavor details from the embedded + flavor object when displaying server details. Requests made with microversion + >= 2.47 will no longer return the flavor ID/link but instead will return a + subset of the flavor details. If the user is prevented by policy from + indexing extra-specs, then the ``extra_specs`` field will not be included in the + flavor information. + diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py index 5e49e79fdb15..238cfc7b842f 100644 --- a/nova/api/openstack/compute/servers.py +++ b/nova/api/openstack/compute/servers.py @@ -448,7 +448,6 @@ class ServersController(wsgi.Controller): @validation.schema(schema_server_create_v242, '2.42') def create(self, req, body): """Creates a new server for a given user.""" - context = req.environ['nova.context'] server_dict = body['server'] password = self._get_server_admin_password(server_dict) diff --git a/nova/api/openstack/compute/views/servers.py b/nova/api/openstack/compute/views/servers.py index b88b1f222cf6..44c672586c35 100644 --- a/nova/api/openstack/compute/views/servers.py +++ b/nova/api/openstack/compute/views/servers.py @@ -27,6 +27,7 @@ from nova import context as nova_context from nova import exception from nova import objects from nova.objects import base as obj_base +from nova.policies import flavor_extra_specs as fes_policies from nova import utils @@ -244,12 +245,30 @@ class ViewBuilder(common.ViewBuilder): else: return "" + def _get_flavor_dict(self, request, instance_type): + flavordict = { + "vcpus": instance_type.vcpus, + "ram": instance_type.memory_mb, + "disk": instance_type.root_gb, + "ephemeral": instance_type.ephemeral_gb, + "swap": instance_type.swap, + "original_name": instance_type.name + } + context = request.environ['nova.context'] + if context.can(fes_policies.POLICY_ROOT % 'index', fatal=False): + flavordict['extra_specs'] = instance_type.extra_specs + return flavordict + def _get_flavor(self, request, instance): instance_type = instance.get_flavor() if not instance_type: LOG.warning("Instance has had its instance_type removed " "from the DB", instance=instance) return {} + + if api_version_request.is_supported(request, min_version="2.47"): + return self._get_flavor_dict(request, instance_type) + flavor_id = instance_type["flavorid"] flavor_bookmark = self._flavor_builder._get_bookmark_link(request, flavor_id, diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-action-rebuild-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-action-rebuild-resp.json.tpl new file mode 100644 index 000000000000..1e990ed9e3aa --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-action-rebuild-resp.json.tpl @@ -0,0 +1,59 @@ +{ + "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" + } + ] + }, + "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" + }, + "name": "%(name)s", + "description": null, + "progress": 0, + "OS-DCF:diskConfig": "AUTO", + "status": "ACTIVE", + "tags": [], + "tenant_id": "6f70656e737461636b20342065766572", + "updated": "%(isotime)s", + "user_id": "fake" + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-action-rebuild.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-action-rebuild.json.tpl new file mode 100644 index 000000000000..b1e2cf9d9f0c --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-action-rebuild.json.tpl @@ -0,0 +1,19 @@ +{ + "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" + }, + "personality": [ + { + "path": "/etc/banner.txt", + "contents": "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6 b25zLiINCg0KLVJpY2hhcmQgQmFjaA==" + } + ] + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-create-req.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-create-req.json.tpl new file mode 100644 index 000000000000..c78f5815851a --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-create-req.json.tpl @@ -0,0 +1,30 @@ +{ + "server" : { + "accessIPv4": "%(access_ip_v4)s", + "accessIPv6": "%(access_ip_v6)s", + "name" : "%(name)s", + "imageRef" : "%(image_id)s", + "flavorRef" : "6", + "availability_zone": "nova", + "OS-DCF:diskConfig": "AUTO", + "metadata" : { + "My Server Name" : "Apache1" + }, + "personality": [ + { + "path": "/etc/banner.txt", + "contents": "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6 b25zLiINCg0KLVJpY2hhcmQgQmFjaA==" + } + ], + "security_groups": [ + { + "name": "default" + } + ], + "user_data" : "%(user_data)s", + "networks": "auto" + }, + "OS-SCH-HNT:scheduler_hints": { + "same_host": "%(uuid)s" + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-create-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/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.47/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.47/server-get-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-get-resp.json.tpl new file mode 100644 index 000000000000..e1d30e08dcf2 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-get-resp.json.tpl @@ -0,0 +1,92 @@ +{ + "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": { + "hw:cpu_model": "SandyBridge", + "hw:mem_page_size": "2048", + "hw:cpu_policy": "dedicated" + }, + "original_name": "m1.tiny.specs", + "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": [ + {"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, + "progress": 0, + "security_groups": [ + { + "name": "default" + } + ], + "status": "ACTIVE", + "tenant_id": "6f70656e737461636b20342065766572", + "updated": "%(isotime)s", + "user_id": "fake" + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-update-req.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-update-req.json.tpl new file mode 100644 index 000000000000..e34896621d2e --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-update-req.json.tpl @@ -0,0 +1,8 @@ +{ + "server": { + "accessIPv4": "%(access_ip_v4)s", + "accessIPv6": "%(access_ip_v6)s", + "OS-DCF:diskConfig": "AUTO", + "name" : "new-server-test" + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-update-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-update-resp.json.tpl new file mode 100644 index 000000000000..76944a9ba7af --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/server-update-resp.json.tpl @@ -0,0 +1,58 @@ +{ + "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": 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" + } + ] + }, + "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", + "tags": [], + "tenant_id": "6f70656e737461636b20342065766572", + "updated": "%(isotime)s", + "user_id": "fake" + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/servers-details-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/servers-details-resp.json.tpl new file mode 100644 index 000000000000..5c848bcd295b --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/servers-details-resp.json.tpl @@ -0,0 +1,94 @@ +{ + "servers": [ + { + "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": { + "hw:cpu_model": "SandyBridge", + "hw:mem_page_size": "2048", + "hw:cpu_policy": "dedicated" + }, + "original_name": "m1.tiny.specs", + "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/%(id)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": [ + {"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, + "progress": 0, + "security_groups": [ + { + "name": "default" + } + ], + "status": "ACTIVE", + "tenant_id": "6f70656e737461636b20342065766572", + "updated": "%(isotime)s", + "user_id": "fake" + } + ] +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/servers-list-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/servers-list-resp.json.tpl new file mode 100644 index 000000000000..f78d963d5d02 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.47/servers-list-resp.json.tpl @@ -0,0 +1,18 @@ +{ + "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" + } + ] +} diff --git a/nova/tests/functional/api_sample_tests/test_servers.py b/nova/tests/functional/api_sample_tests/test_servers.py index e53634ec2f0f..0195564469eb 100644 --- a/nova/tests/functional/api_sample_tests/test_servers.py +++ b/nova/tests/functional/api_sample_tests/test_servers.py @@ -85,10 +85,14 @@ class ServersSampleBase(api_sample_base.ApiSampleTestBaseV21): class ServersSampleJsonTest(ServersSampleBase): + # This controls whether or not we use the common server API sample + # for server post req/resp. + use_common_server_post = True microversion = None def test_servers_post(self): - return self._post_server() + return self._post_server( + use_common_server_api_samples=self.use_common_server_post) def test_servers_get(self): self.stub_out('nova.db.block_device_mapping_get_all_by_instance_uuids', @@ -202,6 +206,30 @@ class ServersSampleJson242Test(ServersSampleBase): self._post_server(use_common_server_api_samples=False) +class ServersSampleJson247Test(ServersSampleJsonTest): + microversion = '2.47' + scenarios = [('v2_47', {'api_major_version': 'v2.1'})] + use_common_server_post = False + + def test_server_rebuild(self): + uuid = self._post_server() + image = fake.get_valid_image_id() + params = { + 'uuid': image, + 'name': 'foobar', + 'pass': 'seekr3t', + 'hostid': '[a-f0-9]+', + 'access_ip_v4': '1.2.3.4', + 'access_ip_v6': '80fe::', + } + + 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) + + class ServersUpdateSampleJsonTest(ServersSampleBase): def test_update_server(self): @@ -215,6 +243,11 @@ class ServersUpdateSampleJsonTest(ServersSampleBase): self._verify_response('server-update-resp', subs, response, 200) +class ServersUpdateSampleJson247Test(ServersUpdateSampleJsonTest): + microversion = '2.47' + scenarios = [('v2_47', {'api_major_version': 'v2.1'})] + + class ServerSortKeysJsonTests(ServersSampleBase): sample_dir = 'servers-sort' diff --git a/nova/tests/functional/wsgi/test_servers.py b/nova/tests/functional/wsgi/test_servers.py index 6b5ab081b7dc..93a8c10632a3 100644 --- a/nova/tests/functional/wsgi/test_servers.py +++ b/nova/tests/functional/wsgi/test_servers.py @@ -61,12 +61,15 @@ class ServersPreSchedulingTestCase(test.TestCase): create_resp = self.api.api_post('servers', body) get_resp = self.api.api_get('servers/%s' % create_resp.body['server']['id']) + flavor_get_resp = self.api.api_get('flavors/%s' % + body['server']['flavorRef']) server = get_resp.body['server'] # Validate a few things self.assertEqual('foo', server['name']) self.assertEqual(image_ref, server['image']['id']) - self.assertEqual('1', server['flavor']['id']) + self.assertEqual(flavor_get_resp.body['flavor']['name'], + server['flavor']['original_name']) self.assertEqual('', server['hostId']) self.assertIsNone(None, server['OS-SRV-USG:launched_at']) self.assertIsNone(None, server['OS-SRV-USG:terminated_at']) @@ -89,11 +92,14 @@ class ServersPreSchedulingTestCase(test.TestCase): create_resp = self.api.api_post('servers', body) get_resp = self.api.api_get('servers/%s' % create_resp.body['server']['id']) + flavor_get_resp = self.api.api_get('flavors/%s' % + body['server']['flavorRef']) server = get_resp.body['server'] # Just validate some basics self.assertEqual('foo', server['name']) self.assertEqual(image_ref, server['image']['id']) - self.assertEqual('1', server['flavor']['id']) + self.assertEqual(flavor_get_resp.body['flavor']['name'], + server['flavor']['original_name']) self.assertEqual('', server['hostId']) self.assertIsNone(None, server['OS-SRV-USG:launched_at']) self.assertIsNone(None, server['OS-SRV-USG:terminated_at']) diff --git a/nova/tests/unit/api/openstack/compute/test_serversV21.py b/nova/tests/unit/api/openstack/compute/test_serversV21.py index 4bcacde054de..cb435849a40f 100644 --- a/nova/tests/unit/api/openstack/compute/test_serversV21.py +++ b/nova/tests/unit/api/openstack/compute/test_serversV21.py @@ -1662,6 +1662,64 @@ class ServerControllerTestV238(ControllerTest): self._test_invalid_status(False) +class ServerControllerTestV247(ControllerTest): + """Server controller test for microversion 2.47 + + The intent here is simply to verify that when showing server details + after microversion 2.47 that the flavor is shown as a dict of flavor + information rather than as dict of id/links. The existence of the + 'extra_specs' key is controlled by policy. + """ + wsgi_api_version = '2.47' + + @mock.patch.object(objects.TagList, 'get_by_resource_id') + def test_get_all_server_details(self, mock_get_by_resource_id): + # Fake out tags on the instances + mock_get_by_resource_id.return_value = objects.TagList() + + expected_flavor = { + 'disk': 20, + 'ephemeral': 0, + 'extra_specs': {}, + 'original_name': u'm1.small', + 'ram': 2048, + 'swap': 0, + 'vcpus': 1} + + req = fakes.HTTPRequest.blank('/fake/servers/detail', + version=self.wsgi_api_version) + res_dict = self.controller.detail(req) + for i, s in enumerate(res_dict['servers']): + self.assertEqual(s['flavor'], expected_flavor) + + @mock.patch.object(objects.TagList, 'get_by_resource_id') + def test_get_all_server_details_no_extra_spec(self, + mock_get_by_resource_id): + # Fake out tags on the instances + mock_get_by_resource_id.return_value = objects.TagList() + # Set the policy so we don't have permission to index + # flavor extra-specs but are able to get server details. + servers_rule = 'os_compute_api:servers:detail' + extraspec_rule = 'os_compute_api:os-flavor-extra-specs:index' + self.policy.set_rules({ + extraspec_rule: 'rule:admin_api', + servers_rule: '@'}) + + expected_flavor = { + 'disk': 20, + 'ephemeral': 0, + 'original_name': u'm1.small', + 'ram': 2048, + 'swap': 0, + 'vcpus': 1} + + req = fakes.HTTPRequest.blank('/fake/servers/detail', + version=self.wsgi_api_version) + res_dict = self.controller.detail(req) + for i, s in enumerate(res_dict['servers']): + self.assertEqual(s['flavor'], expected_flavor) + + class ServersControllerDeleteTest(ControllerTest): def setUp(self): diff --git a/releasenotes/notes/display-flavor-dict-in-server-details-589c1db487f226cb.yaml b/releasenotes/notes/display-flavor-dict-in-server-details-589c1db487f226cb.yaml new file mode 100644 index 000000000000..ea56e402d618 --- /dev/null +++ b/releasenotes/notes/display-flavor-dict-in-server-details-589c1db487f226cb.yaml @@ -0,0 +1,7 @@ +--- +features: + - A new 2.47 microversion was added to the Compute API. Users specifying + this microversion or later will see the "flavor" information displayed as + a dict when displaying server details via the `servers` REST API endpoint. + If the user is prevented by policy from indexing extra-specs, then the + "extra_specs" field will not be included in the flavor information.