From 126c3d4c78d937888213979272534e1cb706a4d4 Mon Sep 17 00:00:00 2001 From: Matt Riedemann Date: Tue, 21 Nov 2017 15:02:45 -0500 Subject: [PATCH] Deprecate file injection This microversion makes the following changes: 1. Deprecates personality files from POST /servers and the rebuild server action APIs. 2. Adds the ability to pass new user_data to the rebuild server action API. 3. Personality / file injection related limits and quota resources are removed from the limits, os-quota-sets and os-quota-class-sets APIs. Implements blueprint deprecate-file-injection Change-Id: Ia89eeb6725459c35369e8f790f68ad9180bd3aba --- api-ref/source/parameters.yaml | 28 ++++ api-ref/source/servers-actions.inc | 2 + api-ref/source/servers.inc | 4 + .../limits/v2.57/limit-get-resp.json | 18 +++ .../v2.57/quota-classes-show-get-resp.json | 12 ++ .../v2.57/quota-classes-update-post-req.json | 11 ++ .../v2.57/quota-classes-update-post-resp.json | 11 ++ .../v2.57/quotas-show-defaults-get-resp.json | 12 ++ .../v2.57/quotas-show-detail-get-resp.json | 40 ++++++ .../v2.57/quotas-show-get-resp.json | 12 ++ .../v2.57/quotas-update-force-post-req.json | 6 + .../v2.57/quotas-update-force-post-resp.json | 11 ++ .../v2.57/quotas-update-post-req.json | 5 + .../v2.57/quotas-update-post-resp.json | 11 ++ .../v2.57/user-quotas-show-get-resp.json | 12 ++ .../v2.57/user-quotas-update-post-req.json | 5 + .../v2.57/user-quotas-update-post-resp.json | 11 ++ .../v2.57/server-action-rebuild-resp.json | 61 +++++++++ .../servers/v2.57/server-action-rebuild.json | 15 +++ .../servers/v2.57/server-create-req.json | 21 +++ .../servers/v2.57/server-create-resp.json | 22 +++ .../versions/v21-version-get-resp.json | 2 +- .../versions/versions-get-resp.json | 2 +- nova/api/openstack/api_version_request.py | 6 +- nova/api/openstack/compute/limits.py | 25 +++- nova/api/openstack/compute/quota_classes.py | 60 +++++++-- nova/api/openstack/compute/quota_sets.py | 49 +++++-- .../compute/rest_api_version_history.rst | 14 ++ .../compute/schemas/quota_classes.py | 9 ++ .../openstack/compute/schemas/quota_sets.py | 8 ++ nova/api/openstack/compute/schemas/servers.py | 18 +++ nova/api/openstack/compute/servers.py | 19 ++- nova/api/openstack/compute/views/limits.py | 19 +-- .../limits/v2.57/limit-get-resp.json.tpl | 18 +++ .../quota-classes-show-get-resp.json.tpl | 12 ++ .../quota-classes-update-post-req.json.tpl | 11 ++ .../quota-classes-update-post-resp.json.tpl | 11 ++ .../quotas-show-defaults-get-resp.json.tpl | 12 ++ .../quotas-show-detail-get-resp.json.tpl | 40 ++++++ .../v2.57/quotas-show-get-resp.json.tpl | 12 ++ .../quotas-update-force-post-req.json.tpl | 6 + .../quotas-update-force-post-resp.json.tpl | 11 ++ .../v2.57/quotas-update-post-req.json.tpl | 5 + .../v2.57/quotas-update-post-resp.json.tpl | 11 ++ .../v2.57/user-quotas-show-get-resp.json.tpl | 12 ++ .../user-quotas-update-post-req.json.tpl | 5 + .../user-quotas-update-post-resp.json.tpl | 11 ++ .../v2.57/server-action-rebuild-resp.json.tpl | 61 +++++++++ .../v2.57/server-action-rebuild.json.tpl | 15 +++ .../servers/v2.57/server-create-req.json.tpl | 21 +++ .../servers/v2.57/server-create-resp.json.tpl | 22 +++ .../api_sample_tests/test_limits.py | 12 ++ .../api_sample_tests/test_quota_classes.py | 5 + .../api_sample_tests/test_quota_sets.py | 8 ++ .../api_sample_tests/test_servers.py | 14 +- .../openstack/compute/test_quota_classes.py | 38 +++--- .../unit/api/openstack/compute/test_quotas.py | 11 +- .../api/openstack/compute/test_serversV21.py | 126 ++++++++++++++++++ ...ecate-file-injection-feaf490524d10b3d.yaml | 17 +++ 59 files changed, 1026 insertions(+), 62 deletions(-) create mode 100644 doc/api_samples/limits/v2.57/limit-get-resp.json create mode 100644 doc/api_samples/os-quota-class-sets/v2.57/quota-classes-show-get-resp.json create mode 100644 doc/api_samples/os-quota-class-sets/v2.57/quota-classes-update-post-req.json create mode 100644 doc/api_samples/os-quota-class-sets/v2.57/quota-classes-update-post-resp.json create mode 100644 doc/api_samples/os-quota-sets/v2.57/quotas-show-defaults-get-resp.json create mode 100644 doc/api_samples/os-quota-sets/v2.57/quotas-show-detail-get-resp.json create mode 100644 doc/api_samples/os-quota-sets/v2.57/quotas-show-get-resp.json create mode 100644 doc/api_samples/os-quota-sets/v2.57/quotas-update-force-post-req.json create mode 100644 doc/api_samples/os-quota-sets/v2.57/quotas-update-force-post-resp.json create mode 100644 doc/api_samples/os-quota-sets/v2.57/quotas-update-post-req.json create mode 100644 doc/api_samples/os-quota-sets/v2.57/quotas-update-post-resp.json create mode 100644 doc/api_samples/os-quota-sets/v2.57/user-quotas-show-get-resp.json create mode 100644 doc/api_samples/os-quota-sets/v2.57/user-quotas-update-post-req.json create mode 100644 doc/api_samples/os-quota-sets/v2.57/user-quotas-update-post-resp.json create mode 100644 doc/api_samples/servers/v2.57/server-action-rebuild-resp.json create mode 100644 doc/api_samples/servers/v2.57/server-action-rebuild.json create mode 100644 doc/api_samples/servers/v2.57/server-create-req.json create mode 100644 doc/api_samples/servers/v2.57/server-create-resp.json create mode 100644 nova/tests/functional/api_sample_tests/api_samples/limits/v2.57/limit-get-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/os-quota-class-sets/v2.57/quota-classes-show-get-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/os-quota-class-sets/v2.57/quota-classes-update-post-req.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/os-quota-class-sets/v2.57/quota-classes-update-post-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-show-defaults-get-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-show-detail-get-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-show-get-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-update-force-post-req.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-update-force-post-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-update-post-req.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-update-post-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/user-quotas-show-get-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/user-quotas-update-post-req.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/user-quotas-update-post-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.57/server-action-rebuild-resp.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.57/server-action-rebuild.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.57/server-create-req.json.tpl create mode 100644 nova/tests/functional/api_sample_tests/api_samples/servers/v2.57/server-create-resp.json.tpl create mode 100644 releasenotes/notes/bp-deprecate-file-injection-feaf490524d10b3d.yaml diff --git a/api-ref/source/parameters.yaml b/api-ref/source/parameters.yaml index b8201eb0a147..bb005e4072fc 100644 --- a/api-ref/source/parameters.yaml +++ b/api-ref/source/parameters.yaml @@ -1739,6 +1739,7 @@ contents: in: body required: true type: string + max_version: 2.56 cores: &cores description: | The number of allowed server cores for each tenant. @@ -3298,6 +3299,7 @@ injected_file_content_bytes: in: body required: true type: integer + max_version: 2.56 injected_file_content_bytes_quota_details: description: | The object of detailed injected file content bytes quota, @@ -3306,18 +3308,21 @@ injected_file_content_bytes_quota_details: in: body required: true type: object + max_version: 2.56 injected_file_content_bytes_quota_optional: description: | The number of allowed bytes of content for each injected file. in: body required: false type: integer + max_version: 2.56 injected_file_path_bytes: description: | The number of allowed bytes for each injected file path. in: body required: true type: integer + max_version: 2.56 injected_file_path_bytes_quota_details: description: | The object of detailed injected file path bytes quota, @@ -3326,18 +3331,21 @@ injected_file_path_bytes_quota_details: in: body required: true type: object + max_version: 2.56 injected_file_path_bytes_quota_optional: description: | The number of allowed bytes for each injected file path. in: body required: false type: integer + max_version: 2.56 injected_files: &injected_files description: | The number of allowed injected files for each tenant. in: body required: true type: integer + max_version: 2.56 injected_files_quota_class: &injected_files_quota_class <<: *injected_files description: | @@ -3352,12 +3360,14 @@ injected_files_quota_details: in: body required: true type: object + max_version: 2.56 injected_files_quota_optional: description: | The number of allowed injected files for each tenant. in: body required: false type: integer + max_version: 2.56 injectNetworkInfo: description: | The action. @@ -4573,6 +4583,7 @@ path: in: body required: true type: string + max_version: 2.56 pause: description: | The action to pause a server. @@ -4601,6 +4612,7 @@ personality: in: body required: false type: array + max_version: 2.56 policies: description: | A list of exactly one policy name to associate with the server group. The @@ -5844,6 +5856,22 @@ user_data: in: body required: false type: string +user_data_rebuild_req: + description: | + Configuration information or scripts to use upon rebuild. + Must be Base64 encoded. If ``null`` is specified, the existing user_data + is unset. + in: body + required: false + type: string + min_version: 2.57 +user_data_rebuild_resp: + in: body + required: true + type: string + description: | + The current user_data for the instance. + min_version: 2.57 user_id: description: | The user ID of the user who owns the server. diff --git a/api-ref/source/servers-actions.inc b/api-ref/source/servers-actions.inc index 31ce02293e7b..c4924dce2a1f 100644 --- a/api-ref/source/servers-actions.inc +++ b/api-ref/source/servers-actions.inc @@ -488,6 +488,7 @@ Request - preserve_ephemeral: preserve_ephemeral - description: server_description - key_name: key_name_rebuild_req + - user_data: user_data_rebuild_req **Example Rebuild Server (rebuild Action) (v2.54)** @@ -536,6 +537,7 @@ Response - description: server_description_resp - tags: tags - key_name: key_name_rebuild_resp + - user_data: user_data_rebuild_resp **Example Rebuild Server (rebuild Action) (v2.54)** diff --git a/api-ref/source/servers.inc b/api-ref/source/servers.inc index c142b8ef0a3a..0686fb61a0e8 100644 --- a/api-ref/source/servers.inc +++ b/api-ref/source/servers.inc @@ -44,6 +44,10 @@ the fixed IP address to assign to the server interface. **Server personality** +.. note:: The use of personality files is deprecated starting with the 2.57 + microversion. Use ``metadata`` and ``user_data`` to customize a server + instance. + To customize the personality of a server instance, you can inject data into its file system. For example, you might insert ssh keys, set configuration files, or store data that you want to retrieve from inside diff --git a/doc/api_samples/limits/v2.57/limit-get-resp.json b/doc/api_samples/limits/v2.57/limit-get-resp.json new file mode 100644 index 000000000000..ac4ef69d7c3a --- /dev/null +++ b/doc/api_samples/limits/v2.57/limit-get-resp.json @@ -0,0 +1,18 @@ +{ + "limits": { + "absolute": { + "maxServerMeta": 128, + "maxTotalCores": 20, + "maxTotalInstances": 10, + "maxTotalKeypairs": 100, + "maxTotalRAMSize": 51200, + "maxServerGroups": 10, + "maxServerGroupMembers": 10, + "totalCoresUsed": 0, + "totalInstancesUsed": 0, + "totalRAMUsed": 0, + "totalServerGroupsUsed": 0 + }, + "rate": [] + } +} diff --git a/doc/api_samples/os-quota-class-sets/v2.57/quota-classes-show-get-resp.json b/doc/api_samples/os-quota-class-sets/v2.57/quota-classes-show-get-resp.json new file mode 100644 index 000000000000..e8114bea9245 --- /dev/null +++ b/doc/api_samples/os-quota-class-sets/v2.57/quota-classes-show-get-resp.json @@ -0,0 +1,12 @@ +{ + "quota_class_set": { + "cores": 20, + "id": "test_class", + "instances": 10, + "key_pairs": 100, + "metadata_items": 128, + "ram": 51200, + "server_groups": 10, + "server_group_members": 10 + } +} diff --git a/doc/api_samples/os-quota-class-sets/v2.57/quota-classes-update-post-req.json b/doc/api_samples/os-quota-class-sets/v2.57/quota-classes-update-post-req.json new file mode 100644 index 000000000000..c722307eea2f --- /dev/null +++ b/doc/api_samples/os-quota-class-sets/v2.57/quota-classes-update-post-req.json @@ -0,0 +1,11 @@ +{ + "quota_class_set": { + "instances": 50, + "cores": 50, + "ram": 51200, + "metadata_items": 128, + "key_pairs": 100, + "server_groups": 10, + "server_group_members": 10 + } +} diff --git a/doc/api_samples/os-quota-class-sets/v2.57/quota-classes-update-post-resp.json b/doc/api_samples/os-quota-class-sets/v2.57/quota-classes-update-post-resp.json new file mode 100644 index 000000000000..4b624e978332 --- /dev/null +++ b/doc/api_samples/os-quota-class-sets/v2.57/quota-classes-update-post-resp.json @@ -0,0 +1,11 @@ +{ + "quota_class_set": { + "cores": 50, + "instances": 50, + "key_pairs": 100, + "metadata_items": 128, + "ram": 51200, + "server_groups": 10, + "server_group_members": 10 + } +} diff --git a/doc/api_samples/os-quota-sets/v2.57/quotas-show-defaults-get-resp.json b/doc/api_samples/os-quota-sets/v2.57/quotas-show-defaults-get-resp.json new file mode 100644 index 000000000000..d5e30ecd76db --- /dev/null +++ b/doc/api_samples/os-quota-sets/v2.57/quotas-show-defaults-get-resp.json @@ -0,0 +1,12 @@ +{ + "quota_set": { + "cores": 20, + "id": "fake_tenant", + "instances": 10, + "key_pairs": 100, + "metadata_items": 128, + "ram": 51200, + "server_groups": 10, + "server_group_members": 10 + } +} diff --git a/doc/api_samples/os-quota-sets/v2.57/quotas-show-detail-get-resp.json b/doc/api_samples/os-quota-sets/v2.57/quotas-show-detail-get-resp.json new file mode 100644 index 000000000000..5cd0d46602e1 --- /dev/null +++ b/doc/api_samples/os-quota-sets/v2.57/quotas-show-detail-get-resp.json @@ -0,0 +1,40 @@ +{ + "quota_set": { + "cores": { + "in_use": 0, + "limit": 20, + "reserved": 0 + }, + "id": "fake_tenant", + "instances": { + "in_use": 0, + "limit": 10, + "reserved": 0 + }, + "key_pairs": { + "in_use": 0, + "limit": 100, + "reserved": 0 + }, + "metadata_items": { + "in_use": 0, + "limit": 128, + "reserved": 0 + }, + "ram": { + "in_use": 0, + "limit": 51200, + "reserved": 0 + }, + "server_group_members": { + "in_use": 0, + "limit": 10, + "reserved": 0 + }, + "server_groups": { + "in_use": 0, + "limit": 10, + "reserved": 0 + } + } +} diff --git a/doc/api_samples/os-quota-sets/v2.57/quotas-show-get-resp.json b/doc/api_samples/os-quota-sets/v2.57/quotas-show-get-resp.json new file mode 100644 index 000000000000..d5e30ecd76db --- /dev/null +++ b/doc/api_samples/os-quota-sets/v2.57/quotas-show-get-resp.json @@ -0,0 +1,12 @@ +{ + "quota_set": { + "cores": 20, + "id": "fake_tenant", + "instances": 10, + "key_pairs": 100, + "metadata_items": 128, + "ram": 51200, + "server_groups": 10, + "server_group_members": 10 + } +} diff --git a/doc/api_samples/os-quota-sets/v2.57/quotas-update-force-post-req.json b/doc/api_samples/os-quota-sets/v2.57/quotas-update-force-post-req.json new file mode 100644 index 000000000000..460d2ac1c7c4 --- /dev/null +++ b/doc/api_samples/os-quota-sets/v2.57/quotas-update-force-post-req.json @@ -0,0 +1,6 @@ +{ + "quota_set": { + "force": "True", + "instances": 45 + } +} \ No newline at end of file diff --git a/doc/api_samples/os-quota-sets/v2.57/quotas-update-force-post-resp.json b/doc/api_samples/os-quota-sets/v2.57/quotas-update-force-post-resp.json new file mode 100644 index 000000000000..0ccff9ac4530 --- /dev/null +++ b/doc/api_samples/os-quota-sets/v2.57/quotas-update-force-post-resp.json @@ -0,0 +1,11 @@ +{ + "quota_set": { + "cores": 20, + "instances": 45, + "key_pairs": 100, + "metadata_items": 128, + "ram": 51200, + "server_groups": 10, + "server_group_members": 10 + } +} diff --git a/doc/api_samples/os-quota-sets/v2.57/quotas-update-post-req.json b/doc/api_samples/os-quota-sets/v2.57/quotas-update-post-req.json new file mode 100644 index 000000000000..c9b5ca40fea9 --- /dev/null +++ b/doc/api_samples/os-quota-sets/v2.57/quotas-update-post-req.json @@ -0,0 +1,5 @@ +{ + "quota_set": { + "instances": 20 + } +} \ No newline at end of file diff --git a/doc/api_samples/os-quota-sets/v2.57/quotas-update-post-resp.json b/doc/api_samples/os-quota-sets/v2.57/quotas-update-post-resp.json new file mode 100644 index 000000000000..5b23fab468c1 --- /dev/null +++ b/doc/api_samples/os-quota-sets/v2.57/quotas-update-post-resp.json @@ -0,0 +1,11 @@ +{ + "quota_set": { + "cores": 20, + "instances": 20, + "key_pairs": 100, + "metadata_items": 128, + "ram": 51200, + "server_groups": 10, + "server_group_members": 10 + } +} diff --git a/doc/api_samples/os-quota-sets/v2.57/user-quotas-show-get-resp.json b/doc/api_samples/os-quota-sets/v2.57/user-quotas-show-get-resp.json new file mode 100644 index 000000000000..d5e30ecd76db --- /dev/null +++ b/doc/api_samples/os-quota-sets/v2.57/user-quotas-show-get-resp.json @@ -0,0 +1,12 @@ +{ + "quota_set": { + "cores": 20, + "id": "fake_tenant", + "instances": 10, + "key_pairs": 100, + "metadata_items": 128, + "ram": 51200, + "server_groups": 10, + "server_group_members": 10 + } +} diff --git a/doc/api_samples/os-quota-sets/v2.57/user-quotas-update-post-req.json b/doc/api_samples/os-quota-sets/v2.57/user-quotas-update-post-req.json new file mode 100644 index 000000000000..2ff273c9a064 --- /dev/null +++ b/doc/api_samples/os-quota-sets/v2.57/user-quotas-update-post-req.json @@ -0,0 +1,5 @@ +{ + "quota_set": { + "instances": 9 + } +} \ No newline at end of file diff --git a/doc/api_samples/os-quota-sets/v2.57/user-quotas-update-post-resp.json b/doc/api_samples/os-quota-sets/v2.57/user-quotas-update-post-resp.json new file mode 100644 index 000000000000..82f6ab585b6e --- /dev/null +++ b/doc/api_samples/os-quota-sets/v2.57/user-quotas-update-post-resp.json @@ -0,0 +1,11 @@ +{ + "quota_set": { + "cores": 20, + "instances": 9, + "key_pairs": 100, + "metadata_items": 128, + "ram": 51200, + "server_groups": 10, + "server_group_members": 10 + } +} diff --git a/doc/api_samples/servers/v2.57/server-action-rebuild-resp.json b/doc/api_samples/servers/v2.57/server-action-rebuild-resp.json new file mode 100644 index 000000000000..05225e7dcb29 --- /dev/null +++ b/doc/api_samples/servers/v2.57/server-action-rebuild-resp.json @@ -0,0 +1,61 @@ +{ + "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", + "key_name": "new-key", + "description": "description of foobar", + "progress": 0, + "status": "ACTIVE", + "OS-DCF:diskConfig": "AUTO", + "tenant_id": "6f70656e737461636b20342065766572", + "updated": "2013-11-14T06:29:02Z", + "user_id": "fake", + "tags": [], + "user_data": "ZWNobyAiaGVsbG8gd29ybGQi" + } +} diff --git a/doc/api_samples/servers/v2.57/server-action-rebuild.json b/doc/api_samples/servers/v2.57/server-action-rebuild.json new file mode 100644 index 000000000000..8e0b60cf41c6 --- /dev/null +++ b/doc/api_samples/servers/v2.57/server-action-rebuild.json @@ -0,0 +1,15 @@ +{ + "rebuild" : { + "accessIPv4": "1.2.3.4", + "accessIPv6": "80fe::", + "imageRef": "70a599e0-31e7-49b7-b260-868f441e862b", + "name": "foobar", + "key_name": "new-key", + "description": "description of foobar", + "adminPass": "seekr3t", + "metadata" : { + "meta_var": "meta_val" + }, + "user_data": "ZWNobyAiaGVsbG8gd29ybGQi" + } +} diff --git a/doc/api_samples/servers/v2.57/server-create-req.json b/doc/api_samples/servers/v2.57/server-create-req.json new file mode 100644 index 000000000000..c6d8dec24244 --- /dev/null +++ b/doc/api_samples/servers/v2.57/server-create-req.json @@ -0,0 +1,21 @@ +{ + "server" : { + "accessIPv4": "1.2.3.4", + "accessIPv6": "80fe::", + "name" : "new-server-test", + "imageRef" : "70a599e0-31e7-49b7-b260-868f441e862b", + "flavorRef" : "http://openstack.example.com/flavors/1", + "availability_zone": "nova", + "OS-DCF:diskConfig": "AUTO", + "metadata" : { + "My Server Name" : "Apache1" + }, + "security_groups": [ + { + "name": "default" + } + ], + "user_data": "IyEvYmluL2Jhc2gKL2Jpbi9zdQplY2hvICJJIGFtIGluIHlvdSEiCg==", + "networks": "auto" + } +} diff --git a/doc/api_samples/servers/v2.57/server-create-resp.json b/doc/api_samples/servers/v2.57/server-create-resp.json new file mode 100644 index 000000000000..dd0bb9f2284e --- /dev/null +++ b/doc/api_samples/servers/v2.57/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/versions/v21-version-get-resp.json b/doc/api_samples/versions/v21-version-get-resp.json index 82c2ccb796ce..076594566224 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.56", + "version": "2.57", "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 671b9429117b..4d4c7af4aafc 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.56", + "version": "2.57", "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 e23804b801db..2dabb24c6281 100644 --- a/nova/api/openstack/api_version_request.py +++ b/nova/api/openstack/api_version_request.py @@ -133,6 +133,10 @@ REST_API_VERSION_HISTORY = """REST API Version History: * 2.56 - Add a host parameter in migrate request body in order to enable users to specify a target host in cold migration. The target host is checked by the scheduler. + * 2.57 - Deprecated personality files from POST /servers and the rebuild + server action APIs. Added the ability to pass new user_data to + the rebuild server action API. Personality / file injection + related limits and quota resources are also removed. """ # The minimum and maximum versions of the API supported @@ -141,7 +145,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.56" +_MAX_API_VERSION = "2.57" 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/limits.py b/nova/api/openstack/compute/limits.py index 66c79d343e10..0748b8fcaa86 100644 --- a/nova/api/openstack/compute/limits.py +++ b/nova/api/openstack/compute/limits.py @@ -32,6 +32,15 @@ from nova import quota QUOTAS = quota.QUOTAS +# This is a list of limits which needs to filter out from the API response. +# This is due to the deprecation of network related proxy APIs, the related +# limit should be removed from the API also. +FILTERED_LIMITS_2_36 = ['floating_ips', 'security_groups', + 'security_group_rules'] + +FILTERED_LIMITS_2_57 = list(FILTERED_LIMITS_2_36) +FILTERED_LIMITS_2_57.extend(['injected_files', 'injected_file_content_bytes']) + class LimitsController(wsgi.Controller): """Controller for accessing limits in the OpenStack API.""" @@ -47,16 +56,22 @@ class LimitsController(wsgi.Controller): @extensions.expected_errors(()) @validation.query_schema(limits.limits_query_schema) def index(self, req): - return self._index(req, filter_result=True) + return self._index(req, FILTERED_LIMITS_2_36) @wsgi.Controller.api_version( # noqa - MIN_WITHOUT_IMAGE_META_PROXY_API_VERSION) # noqa + MIN_WITHOUT_IMAGE_META_PROXY_API_VERSION, '2.56') # noqa @extensions.expected_errors(()) @validation.query_schema(limits.limits_query_schema) def index(self, req): - return self._index(req, filter_result=True, max_image_meta=False) + return self._index(req, FILTERED_LIMITS_2_36, max_image_meta=False) - def _index(self, req, filter_result=False, max_image_meta=True): + @wsgi.Controller.api_version('2.57') # noqa + @extensions.expected_errors(()) + @validation.query_schema(limits.limits_query_schema) + def index(self, req): + return self._index(req, FILTERED_LIMITS_2_57, max_image_meta=False) + + def _index(self, req, filtered_limits=None, max_image_meta=True): """Return all global limit information.""" context = req.environ['nova.context'] context.can(limits_policies.BASE_POLICY_NAME) @@ -66,5 +81,5 @@ class LimitsController(wsgi.Controller): abs_limits = {k: v['limit'] for k, v in quotas.items()} builder = limits_views.ViewBuilder() - return builder.build(abs_limits, filter_result=filter_result, + return builder.build(abs_limits, filtered_limits=filtered_limits, max_image_meta=max_image_meta) diff --git a/nova/api/openstack/compute/quota_classes.py b/nova/api/openstack/compute/quota_classes.py index 275238507baf..c3f9ca4af20f 100644 --- a/nova/api/openstack/compute/quota_classes.py +++ b/nova/api/openstack/compute/quota_classes.py @@ -16,7 +16,6 @@ import copy import webob -from nova.api.openstack import api_version_request from nova.api.openstack.compute.schemas import quota_classes from nova.api.openstack import extensions from nova.api.openstack import wsgi @@ -36,8 +35,13 @@ EXTENDED_QUOTAS = ['server_groups', 'server_group_members'] # NOTE(gmann): Network related quotas are filter out in # microversion 2.50. Bug#1701211. -FILTERED_QUOTAS = ["fixed_ips", "floating_ips", "networks", - "security_group_rules", "security_groups"] +FILTERED_QUOTAS_2_50 = ["fixed_ips", "floating_ips", "networks", + "security_group_rules", "security_groups"] + +# Microversion 2.57 removes personality (injected) files from the API. +FILTERED_QUOTAS_2_57 = list(FILTERED_QUOTAS_2_50) +FILTERED_QUOTAS_2_57.extend(['injected_files', 'injected_file_content_bytes', + 'injected_file_path_bytes']) class QuotaClassSetsController(wsgi.Controller): @@ -47,7 +51,8 @@ class QuotaClassSetsController(wsgi.Controller): def __init__(self, **kwargs): self.supported_quotas = QUOTAS.resources - def _format_quota_set(self, quota_class, quota_set, req): + def _format_quota_set(self, quota_class, quota_set, filtered_quotas=None, + exclude_server_groups=False): """Convert the quota object to a result dict.""" if quota_class: @@ -55,13 +60,13 @@ class QuotaClassSetsController(wsgi.Controller): else: result = {} original_quotas = copy.deepcopy(self.supported_quotas) - if api_version_request.is_supported(req, min_version="2.50"): + if filtered_quotas: original_quotas = [resource for resource in original_quotas - if resource not in FILTERED_QUOTAS] + if resource not in filtered_quotas] # NOTE(gmann): Before microversion v2.50, v2.1 API does not return the # 'server_groups' & 'server_group_members' key in quota class API # response. - else: + if exclude_server_groups: for resource in EXTENDED_QUOTAS: original_quotas.remove(resource) for resource in original_quotas: @@ -70,17 +75,49 @@ class QuotaClassSetsController(wsgi.Controller): return dict(quota_class_set=result) + @wsgi.Controller.api_version('2.1', '2.49') @extensions.expected_errors(()) def show(self, req, id): + return self._show(req, id, exclude_server_groups=True) + + @wsgi.Controller.api_version('2.50', '2.56') # noqa + @extensions.expected_errors(()) + def show(self, req, id): + return self._show(req, id, FILTERED_QUOTAS_2_50) + + @wsgi.Controller.api_version('2.57') # noqa + @extensions.expected_errors(()) + def show(self, req, id): + return self._show(req, id, FILTERED_QUOTAS_2_57) + + def _show(self, req, id, filtered_quotas=None, + exclude_server_groups=False): context = req.environ['nova.context'] context.can(qcs_policies.POLICY_ROOT % 'show', {'quota_class': id}) values = QUOTAS.get_class_quotas(context, id) - return self._format_quota_set(id, values, req) + return self._format_quota_set(id, values, filtered_quotas, + exclude_server_groups) + @wsgi.Controller.api_version("2.1", "2.49") # noqa @extensions.expected_errors(400) - @validation.schema(quota_classes.update, "2.0", "2.49") - @validation.schema(quota_classes.update_v250, "2.50") + @validation.schema(quota_classes.update) def update(self, req, id, body): + return self._update(req, id, body, exclude_server_groups=True) + + @wsgi.Controller.api_version("2.50", "2.56") # noqa + @extensions.expected_errors(400) + @validation.schema(quota_classes.update_v250) + def update(self, req, id, body): + return self._update(req, id, body, FILTERED_QUOTAS_2_50) + + @wsgi.Controller.api_version("2.57") # noqa + @extensions.expected_errors(400) + @validation.schema(quota_classes.update_v257) + def update(self, req, id, body): + return self._update(req, id, body, FILTERED_QUOTAS_2_57) + + def _update(self, req, id, body, filtered_quotas=None, + exclude_server_groups=False): context = req.environ['nova.context'] context.can(qcs_policies.POLICY_ROOT % 'update', {'quota_class': id}) try: @@ -99,4 +136,5 @@ class QuotaClassSetsController(wsgi.Controller): objects.Quotas.create_class(context, quota_class, key, value) values = QUOTAS.get_class_quotas(context, quota_class) - return self._format_quota_set(None, values, req) + return self._format_quota_set(None, values, filtered_quotas, + exclude_server_groups) diff --git a/nova/api/openstack/compute/quota_sets.py b/nova/api/openstack/compute/quota_sets.py index cfaa13af8fc5..c31c24d90c59 100644 --- a/nova/api/openstack/compute/quota_sets.py +++ b/nova/api/openstack/compute/quota_sets.py @@ -38,8 +38,12 @@ from nova import quota CONF = nova.conf.CONF QUOTAS = quota.QUOTAS -FILTERED_QUOTAS = ["fixed_ips", "floating_ips", "networks", - "security_group_rules", "security_groups"] +FILTERED_QUOTAS_2_36 = ["fixed_ips", "floating_ips", "networks", + "security_group_rules", "security_groups"] + +FILTERED_QUOTAS_2_57 = list(FILTERED_QUOTAS_2_36) +FILTERED_QUOTAS_2_57.extend(['injected_files', 'injected_file_content_bytes', + 'injected_file_path_bytes']) class QuotaSetsController(wsgi.Controller): @@ -106,10 +110,16 @@ class QuotaSetsController(wsgi.Controller): def show(self, req, id): return self._show(req, id, []) - @wsgi.Controller.api_version(MIN_WITHOUT_PROXY_API_SUPPORT_VERSION) # noqa + @wsgi.Controller.api_version( # noqa + MIN_WITHOUT_PROXY_API_SUPPORT_VERSION, '2.56') @extensions.expected_errors(400) def show(self, req, id): - return self._show(req, id, FILTERED_QUOTAS) + return self._show(req, id, FILTERED_QUOTAS_2_36) + + @wsgi.Controller.api_version('2.57') # noqa + @extensions.expected_errors(400) + def show(self, req, id): + return self._show(req, id, FILTERED_QUOTAS_2_57) @validation.query_schema(quota_sets.query_schema) def _show(self, req, id, filtered_quotas): @@ -128,10 +138,16 @@ class QuotaSetsController(wsgi.Controller): def detail(self, req, id): return self._detail(req, id, []) - @wsgi.Controller.api_version(MIN_WITHOUT_PROXY_API_SUPPORT_VERSION) # noqa + @wsgi.Controller.api_version( # noqa + MIN_WITHOUT_PROXY_API_SUPPORT_VERSION, '2.56') @extensions.expected_errors(400) def detail(self, req, id): - return self._detail(req, id, FILTERED_QUOTAS) + return self._detail(req, id, FILTERED_QUOTAS_2_36) + + @wsgi.Controller.api_version('2.57') # noqa + @extensions.expected_errors(400) + def detail(self, req, id): + return self._detail(req, id, FILTERED_QUOTAS_2_57) @validation.query_schema(quota_sets.query_schema) def _detail(self, req, id, filtered_quotas): @@ -151,11 +167,18 @@ class QuotaSetsController(wsgi.Controller): def update(self, req, id, body): return self._update(req, id, body, []) - @wsgi.Controller.api_version(MIN_WITHOUT_PROXY_API_SUPPORT_VERSION) # noqa + @wsgi.Controller.api_version( # noqa + MIN_WITHOUT_PROXY_API_SUPPORT_VERSION, '2.56') @extensions.expected_errors(400) @validation.schema(quota_sets.update_v236) def update(self, req, id, body): - return self._update(req, id, body, FILTERED_QUOTAS) + return self._update(req, id, body, FILTERED_QUOTAS_2_36) + + @wsgi.Controller.api_version('2.57') # noqa + @extensions.expected_errors(400) + @validation.schema(quota_sets.update_v257) + def update(self, req, id, body): + return self._update(req, id, body, FILTERED_QUOTAS_2_57) @validation.query_schema(quota_sets.query_schema) def _update(self, req, id, body, filtered_quotas): @@ -221,10 +244,16 @@ class QuotaSetsController(wsgi.Controller): def defaults(self, req, id): return self._defaults(req, id, []) - @wsgi.Controller.api_version(MIN_WITHOUT_PROXY_API_SUPPORT_VERSION) # noqa + @wsgi.Controller.api_version( # noqa + MIN_WITHOUT_PROXY_API_SUPPORT_VERSION, '2.56') @extensions.expected_errors(400) def defaults(self, req, id): - return self._defaults(req, id, FILTERED_QUOTAS) + return self._defaults(req, id, FILTERED_QUOTAS_2_36) + + @wsgi.Controller.api_version('2.57') # noqa + @extensions.expected_errors(400) + def defaults(self, req, id): + return self._defaults(req, id, FILTERED_QUOTAS_2_57) def _defaults(self, req, id, filtered_quotas): context = req.environ['nova.context'] diff --git a/nova/api/openstack/compute/rest_api_version_history.rst b/nova/api/openstack/compute/rest_api_version_history.rst index 4cb75d865a00..6ed3f62b5136 100644 --- a/nova/api/openstack/compute/rest_api_version_history.rst +++ b/nova/api/openstack/compute/rest_api_version_history.rst @@ -715,3 +715,17 @@ The embedded flavor description will not be included in server representations. the optional ``host`` string field defaulted to ``null``. If ``host`` is set the migrate action verifies the provided host with the nova scheduler and uses it as the destination for the migration. + +2.57 +---- + +The 2.57 microversion makes the following changes: + +* The ``personality`` parameter is removed from the server create and rebuild + APIs. +* The ``user_data`` parameter is added to the server rebuild API. +* The ``maxPersonality`` and ``maxPersonalitySize`` limits are excluded from + the ``GET /limits`` API response. +* The ``injected_files``, ``injected_file_content_bytes`` and + ``injected_file_path_bytes`` quotas are removed from the ``os-quota-sets`` + and ``os-quota-class-sets`` APIs. diff --git a/nova/api/openstack/compute/schemas/quota_classes.py b/nova/api/openstack/compute/schemas/quota_classes.py index 173cfb464140..6b181359b936 100644 --- a/nova/api/openstack/compute/schemas/quota_classes.py +++ b/nova/api/openstack/compute/schemas/quota_classes.py @@ -36,3 +36,12 @@ del update_v250['properties']['quota_class_set']['properties'][ del update_v250['properties']['quota_class_set']['properties'][ 'security_group_rules'] del update_v250['properties']['quota_class_set']['properties']['networks'] + +# 2.57 builds on 2.50 and removes injected_file* quotas. +update_v257 = copy.deepcopy(update_v250) +del update_v257['properties']['quota_class_set']['properties'][ + 'injected_files'] +del update_v257['properties']['quota_class_set']['properties'][ + 'injected_file_content_bytes'] +del update_v257['properties']['quota_class_set']['properties'][ + 'injected_file_path_bytes'] diff --git a/nova/api/openstack/compute/schemas/quota_sets.py b/nova/api/openstack/compute/schemas/quota_sets.py index ebd0884bba88..fddf074ca4b2 100644 --- a/nova/api/openstack/compute/schemas/quota_sets.py +++ b/nova/api/openstack/compute/schemas/quota_sets.py @@ -69,6 +69,14 @@ update = { update_v236 = copy.deepcopy(update) update_v236['properties']['quota_set']['properties'] = update_quota_set_v236 +# 2.57 builds on 2.36 and removes injected_file* quotas. +update_quota_set_v257 = copy.deepcopy(update_quota_set_v236) +del update_quota_set_v257['injected_files'] +del update_quota_set_v257['injected_file_content_bytes'] +del update_quota_set_v257['injected_file_path_bytes'] +update_v257 = copy.deepcopy(update_v236) +update_v257['properties']['quota_set']['properties'] = update_quota_set_v257 + query_schema = { 'type': 'object', 'properties': { diff --git a/nova/api/openstack/compute/schemas/servers.py b/nova/api/openstack/compute/schemas/servers.py index 151578429c21..33f3a7ea1daf 100644 --- a/nova/api/openstack/compute/schemas/servers.py +++ b/nova/api/openstack/compute/schemas/servers.py @@ -14,6 +14,7 @@ import copy +from nova.api.openstack.compute.schemas import user_data from nova.api.validation import parameter_types from nova.api.validation.parameter_types import multi_params from nova.objects import instance @@ -139,6 +140,11 @@ base_create_v252['properties']['server']['properties']['tags'] = { } +# 2.57 builds on 2.52 and removes the personality parameter. +base_create_v257 = copy.deepcopy(base_create_v252) +base_create_v257['properties']['server']['properties'].pop('personality') + + base_update = { 'type': 'object', 'properties': { @@ -203,6 +209,18 @@ base_rebuild_v254 = copy.deepcopy(base_rebuild_v219) base_rebuild_v254['properties']['rebuild'][ 'properties']['key_name'] = parameter_types.name_or_none +# 2.57 builds on 2.54 and makes the following changes: +# 1. Remove the personality parameter. +# 2. Add the user_data parameter which is nullable so user_data can be reset. +base_rebuild_v257 = copy.deepcopy(base_rebuild_v254) +base_rebuild_v257['properties']['rebuild']['properties'].pop('personality') +base_rebuild_v257['properties']['rebuild']['properties']['user_data'] = ({ + 'oneOf': [ + user_data.common_user_data, + {'type': 'null'} + ] +}) + resize = { 'type': 'object', 'properties': { diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py index c945c5202358..1597fa8bc021 100644 --- a/nova/api/openstack/compute/servers.py +++ b/nova/api/openstack/compute/servers.py @@ -80,11 +80,13 @@ class ServersController(wsgi.Controller): schema_server_update_v219 = schema_servers.base_update_v219 schema_server_rebuild_v219 = schema_servers.base_rebuild_v219 schema_server_rebuild_v254 = schema_servers.base_rebuild_v254 + schema_server_rebuild_v257 = schema_servers.base_rebuild_v257 schema_server_create_v232 = schema_servers.base_create_v232 schema_server_create_v237 = schema_servers.base_create_v237 schema_server_create_v242 = schema_servers.base_create_v242 schema_server_create_v252 = schema_servers.base_create_v252 + schema_server_create_v257 = schema_servers.base_create_v257 # NOTE(alex_xu): Please do not add more items into this list. This list # should be removed in the future. @@ -134,6 +136,7 @@ class ServersController(wsgi.Controller): # TODO(alex_xu): The final goal is that merging all of # extended json-schema into server main json-schema. + self._create_schema(self.schema_server_create_v257, '2.57') self._create_schema(self.schema_server_create_v252, '2.52') self._create_schema(self.schema_server_create_v242, '2.42') self._create_schema(self.schema_server_create_v237, '2.37') @@ -447,7 +450,8 @@ class ServersController(wsgi.Controller): @validation.schema(schema_server_create_v232, '2.32', '2.36') @validation.schema(schema_server_create_v237, '2.37', '2.41') @validation.schema(schema_server_create_v242, '2.42', '2.51') - @validation.schema(schema_server_create_v252, '2.52') + @validation.schema(schema_server_create_v252, '2.52', '2.56') + @validation.schema(schema_server_create_v257, '2.57') def create(self, req, body): """Creates a new server for a given user.""" context = req.environ['nova.context'] @@ -878,7 +882,8 @@ class ServersController(wsgi.Controller): @validation.schema(schema_server_rebuild_v20, '2.0', '2.0') @validation.schema(schema_server_rebuild, '2.1', '2.18') @validation.schema(schema_server_rebuild_v219, '2.19', '2.53') - @validation.schema(schema_server_rebuild_v254, '2.54') + @validation.schema(schema_server_rebuild_v254, '2.54', '2.56') + @validation.schema(schema_server_rebuild_v257, '2.57') def _action_rebuild(self, req, id, body): """Rebuild an instance with the given attributes.""" rebuild_dict = body['rebuild'] @@ -906,6 +911,13 @@ class ServersController(wsgi.Controller): and 'key_name' in rebuild_dict): kwargs['key_name'] = rebuild_dict.get('key_name') + # If user_data is not specified, we don't include it in kwargs because + # we don't want to overwrite the existing user_data. + include_user_data = api_version_request.is_supported( + req, min_version='2.57') + if include_user_data and 'user_data' in rebuild_dict: + kwargs['user_data'] = rebuild_dict['user_data'] + for request_attribute, instance_attribute in attr_map.items(): try: if request_attribute == 'name': @@ -962,6 +974,9 @@ class ServersController(wsgi.Controller): # NOTE(liuyulong): set the new key_name for the API response. view['server']['key_name'] = instance.key_name + if include_user_data: + view['server']['user_data'] = instance.user_data + robj = wsgi.ResponseObject(view) return self._add_location(robj) diff --git a/nova/api/openstack/compute/views/limits.py b/nova/api/openstack/compute/views/limits.py index ae93349ed64a..db935a56e95e 100644 --- a/nova/api/openstack/compute/views/limits.py +++ b/nova/api/openstack/compute/views/limits.py @@ -14,12 +14,6 @@ # under the License. -# This is a list of limits which needs to filter out from the API response. -# This is due to the deprecation of network related proxy APIs, the related -# limit should be removed from the API also. -FILTERED_LIMITS = ['floating_ips', 'security_groups', 'security_group_rules'] - - class ViewBuilder(object): """OpenStack API base limits view builder.""" @@ -41,9 +35,10 @@ class ViewBuilder(object): "server_group_members": ["maxServerGroupMembers"] } - def build(self, absolute_limits, filter_result=False, max_image_meta=True): + def build(self, absolute_limits, filtered_limits=None, + max_image_meta=True): absolute_limits = self._build_absolute_limits( - absolute_limits, filter_result=filter_result, + absolute_limits, filtered_limits, max_image_meta=max_image_meta) output = { @@ -55,17 +50,17 @@ class ViewBuilder(object): return output - def _build_absolute_limits(self, absolute_limits, filter_result=False, + def _build_absolute_limits(self, absolute_limits, filtered_limits=None, max_image_meta=True): """Builder for absolute limits absolute_limits should be given as a dict of limits. For example: {"ram": 512, "gigabytes": 1024}. + filtered_limits is an optional list of limits to exclude from the + result set. """ - filtered_limits = [] - if filter_result: - filtered_limits = FILTERED_LIMITS + filtered_limits = filtered_limits or [] limits = {} for name, value in absolute_limits.items(): if (name in self.limit_names and diff --git a/nova/tests/functional/api_sample_tests/api_samples/limits/v2.57/limit-get-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/limits/v2.57/limit-get-resp.json.tpl new file mode 100644 index 000000000000..ac4ef69d7c3a --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/limits/v2.57/limit-get-resp.json.tpl @@ -0,0 +1,18 @@ +{ + "limits": { + "absolute": { + "maxServerMeta": 128, + "maxTotalCores": 20, + "maxTotalInstances": 10, + "maxTotalKeypairs": 100, + "maxTotalRAMSize": 51200, + "maxServerGroups": 10, + "maxServerGroupMembers": 10, + "totalCoresUsed": 0, + "totalInstancesUsed": 0, + "totalRAMUsed": 0, + "totalServerGroupsUsed": 0 + }, + "rate": [] + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/os-quota-class-sets/v2.57/quota-classes-show-get-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/os-quota-class-sets/v2.57/quota-classes-show-get-resp.json.tpl new file mode 100644 index 000000000000..c6601dd93f9a --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/os-quota-class-sets/v2.57/quota-classes-show-get-resp.json.tpl @@ -0,0 +1,12 @@ +{ + "quota_class_set": { + "cores": 20, + "id": "%(set_id)s", + "instances": 10, + "key_pairs": 100, + "metadata_items": 128, + "ram": 51200, + "server_groups": 10, + "server_group_members": 10 + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/os-quota-class-sets/v2.57/quota-classes-update-post-req.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/os-quota-class-sets/v2.57/quota-classes-update-post-req.json.tpl new file mode 100644 index 000000000000..c722307eea2f --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/os-quota-class-sets/v2.57/quota-classes-update-post-req.json.tpl @@ -0,0 +1,11 @@ +{ + "quota_class_set": { + "instances": 50, + "cores": 50, + "ram": 51200, + "metadata_items": 128, + "key_pairs": 100, + "server_groups": 10, + "server_group_members": 10 + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/os-quota-class-sets/v2.57/quota-classes-update-post-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/os-quota-class-sets/v2.57/quota-classes-update-post-resp.json.tpl new file mode 100644 index 000000000000..4b624e978332 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/os-quota-class-sets/v2.57/quota-classes-update-post-resp.json.tpl @@ -0,0 +1,11 @@ +{ + "quota_class_set": { + "cores": 50, + "instances": 50, + "key_pairs": 100, + "metadata_items": 128, + "ram": 51200, + "server_groups": 10, + "server_group_members": 10 + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-show-defaults-get-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-show-defaults-get-resp.json.tpl new file mode 100644 index 000000000000..d5e30ecd76db --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-show-defaults-get-resp.json.tpl @@ -0,0 +1,12 @@ +{ + "quota_set": { + "cores": 20, + "id": "fake_tenant", + "instances": 10, + "key_pairs": 100, + "metadata_items": 128, + "ram": 51200, + "server_groups": 10, + "server_group_members": 10 + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-show-detail-get-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-show-detail-get-resp.json.tpl new file mode 100644 index 000000000000..5cd0d46602e1 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-show-detail-get-resp.json.tpl @@ -0,0 +1,40 @@ +{ + "quota_set": { + "cores": { + "in_use": 0, + "limit": 20, + "reserved": 0 + }, + "id": "fake_tenant", + "instances": { + "in_use": 0, + "limit": 10, + "reserved": 0 + }, + "key_pairs": { + "in_use": 0, + "limit": 100, + "reserved": 0 + }, + "metadata_items": { + "in_use": 0, + "limit": 128, + "reserved": 0 + }, + "ram": { + "in_use": 0, + "limit": 51200, + "reserved": 0 + }, + "server_group_members": { + "in_use": 0, + "limit": 10, + "reserved": 0 + }, + "server_groups": { + "in_use": 0, + "limit": 10, + "reserved": 0 + } + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-show-get-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-show-get-resp.json.tpl new file mode 100644 index 000000000000..d5e30ecd76db --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-show-get-resp.json.tpl @@ -0,0 +1,12 @@ +{ + "quota_set": { + "cores": 20, + "id": "fake_tenant", + "instances": 10, + "key_pairs": 100, + "metadata_items": 128, + "ram": 51200, + "server_groups": 10, + "server_group_members": 10 + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-update-force-post-req.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-update-force-post-req.json.tpl new file mode 100644 index 000000000000..a58a17912375 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-update-force-post-req.json.tpl @@ -0,0 +1,6 @@ +{ + "quota_set": { + "force": "True", + "instances": 45 + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-update-force-post-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-update-force-post-resp.json.tpl new file mode 100644 index 000000000000..0ccff9ac4530 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-update-force-post-resp.json.tpl @@ -0,0 +1,11 @@ +{ + "quota_set": { + "cores": 20, + "instances": 45, + "key_pairs": 100, + "metadata_items": 128, + "ram": 51200, + "server_groups": 10, + "server_group_members": 10 + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-update-post-req.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-update-post-req.json.tpl new file mode 100644 index 000000000000..2eb76c5dca1f --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-update-post-req.json.tpl @@ -0,0 +1,5 @@ +{ + "quota_set": { + "instances": 20 + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-update-post-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-update-post-resp.json.tpl new file mode 100644 index 000000000000..5b23fab468c1 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/quotas-update-post-resp.json.tpl @@ -0,0 +1,11 @@ +{ + "quota_set": { + "cores": 20, + "instances": 20, + "key_pairs": 100, + "metadata_items": 128, + "ram": 51200, + "server_groups": 10, + "server_group_members": 10 + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/user-quotas-show-get-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/user-quotas-show-get-resp.json.tpl new file mode 100644 index 000000000000..d5e30ecd76db --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/user-quotas-show-get-resp.json.tpl @@ -0,0 +1,12 @@ +{ + "quota_set": { + "cores": 20, + "id": "fake_tenant", + "instances": 10, + "key_pairs": 100, + "metadata_items": 128, + "ram": 51200, + "server_groups": 10, + "server_group_members": 10 + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/user-quotas-update-post-req.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/user-quotas-update-post-req.json.tpl new file mode 100644 index 000000000000..f64fcda3bf53 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/user-quotas-update-post-req.json.tpl @@ -0,0 +1,5 @@ +{ + "quota_set": { + "instances": 9 + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/user-quotas-update-post-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/user-quotas-update-post-resp.json.tpl new file mode 100644 index 000000000000..82f6ab585b6e --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/os-quota-sets/v2.57/user-quotas-update-post-resp.json.tpl @@ -0,0 +1,11 @@ +{ + "quota_set": { + "cores": 20, + "instances": 9, + "key_pairs": 100, + "metadata_items": 128, + "ram": 51200, + "server_groups": 10, + "server_group_members": 10 + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.57/server-action-rebuild-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.57/server-action-rebuild-resp.json.tpl new file mode 100644 index 000000000000..33c05f6ca26c --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.57/server-action-rebuild-resp.json.tpl @@ -0,0 +1,61 @@ +{ + "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", + "key_name": "%(key_name)s", + "description": "%(description)s", + "progress": 0, + "OS-DCF:diskConfig": "AUTO", + "status": "ACTIVE", + "tenant_id": "6f70656e737461636b20342065766572", + "updated": "%(isotime)s", + "user_id": "fake", + "tags": [], + "user_data": "ZWNobyAiaGVsbG8gd29ybGQi" + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.57/server-action-rebuild.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.57/server-action-rebuild.json.tpl new file mode 100644 index 000000000000..7ee5de0c4c4d --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.57/server-action-rebuild.json.tpl @@ -0,0 +1,15 @@ +{ + "rebuild" : { + "accessIPv4" : "%(access_ip_v4)s", + "accessIPv6" : "%(access_ip_v6)s", + "imageRef" : "%(uuid)s", + "name" : "%(name)s", + "key_name" : "%(key_name)s", + "description" : "%(description)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.57/server-create-req.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.57/server-create-req.json.tpl new file mode 100644 index 000000000000..ff9a9c8b1c4f --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.57/server-create-req.json.tpl @@ -0,0 +1,21 @@ +{ + "server" : { + "accessIPv4": "%(access_ip_v4)s", + "accessIPv6": "%(access_ip_v6)s", + "name" : "new-server-test", + "imageRef" : "%(image_id)s", + "flavorRef" : "http://openstack.example.com/flavors/1", + "availability_zone": "nova", + "OS-DCF:diskConfig": "AUTO", + "metadata" : { + "My Server Name" : "Apache1" + }, + "security_groups": [ + { + "name": "default" + } + ], + "user_data" : "%(user_data)s", + "networks": "auto" + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/servers/v2.57/server-create-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/servers/v2.57/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.57/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/test_limits.py b/nova/tests/functional/api_sample_tests/test_limits.py index 939b79603e18..024a60f42ce2 100644 --- a/nova/tests/functional/api_sample_tests/test_limits.py +++ b/nova/tests/functional/api_sample_tests/test_limits.py @@ -65,3 +65,15 @@ class LimitsV239Test(api_sample_base.ApiSampleTestBaseV21): self.api.microversion = self.microversion response = self._do_get('limits') self._verify_response('limit-get-resp', {}, response, 200) + + +class LimitsV257Test(api_sample_base.ApiSampleTestBaseV21): + """Test limits don't return maxPersonality* fields after 2.57.""" + sample_dir = "limits" + microversion = '2.57' + scenarios = [('v2_57', {'api_major_version': 'v2.1'})] + + def test_limits_get(self): + self.api.microversion = self.microversion + response = self._do_get('limits') + self._verify_response('limit-get-resp', {}, response, 200) diff --git a/nova/tests/functional/api_sample_tests/test_quota_classes.py b/nova/tests/functional/api_sample_tests/test_quota_classes.py index f5e20577cb11..5b5017282ebd 100644 --- a/nova/tests/functional/api_sample_tests/test_quota_classes.py +++ b/nova/tests/functional/api_sample_tests/test_quota_classes.py @@ -40,3 +40,8 @@ class QuotaClassesSampleJsonTests(api_sample_base.ApiSampleTestBaseV21): class QuotaClassesV250SampleJsonTests(QuotaClassesSampleJsonTests): microversion = '2.50' scenarios = [('v2_50', {'api_major_version': 'v2.1'})] + + +class QuotaClassesV257SampleJsonTests(QuotaClassesSampleJsonTests): + microversion = '2.57' + scenarios = [('v2_57', {'api_major_version': 'v2.1'})] diff --git a/nova/tests/functional/api_sample_tests/test_quota_sets.py b/nova/tests/functional/api_sample_tests/test_quota_sets.py index 95b91be6ff72..43956028d4e2 100644 --- a/nova/tests/functional/api_sample_tests/test_quota_sets.py +++ b/nova/tests/functional/api_sample_tests/test_quota_sets.py @@ -83,6 +83,14 @@ class QuotaSetsSampleJsonTests2_36(QuotaSetsSampleJsonTests): scenarios = [('v2_36', {'api_major_version': 'v2.1'})] +class QuotaSetsSampleJsonTestsV2_57(QuotaSetsSampleJsonTests): + """Tests that injected_file* quotas are not in request or response values. + starting with microversion 2.57. + """ + microversion = '2.57' + scenarios = [('v2_57', {'api_major_version': 'v2.1'})] + + class NoopQuotaSetsSampleJsonTests(QuotaSetsSampleJsonTests): sample_dir = "os-quota-sets-noop" diff --git a/nova/tests/functional/api_sample_tests/test_servers.py b/nova/tests/functional/api_sample_tests/test_servers.py index a384f14695d6..b34cfc9061e0 100644 --- a/nova/tests/functional/api_sample_tests/test_servers.py +++ b/nova/tests/functional/api_sample_tests/test_servers.py @@ -463,9 +463,12 @@ class ServersActionsJson254Test(ServersSampleBase): sample_dir = 'servers' scenarios = [('v2_54', {'api_major_version': 'v2.1'})] + def _create_server(self): + return self._post_server() + def test_server_rebuild(self): fakes.stub_out_key_pair_funcs(self) - uuid = self._post_server() + uuid = self._create_server() image = fake.get_valid_image_id() params = { 'uuid': image, @@ -485,6 +488,15 @@ class ServersActionsJson254Test(ServersSampleBase): self._verify_response('server-action-rebuild-resp', subs, resp, 202) +class ServersActionsJson257Test(ServersActionsJson254Test): + """Tests rebuilding a server with new user_data.""" + microversion = '2.57' + scenarios = [('v2_57', {'api_major_version': 'v2.1'})] + + def _create_server(self): + return self._post_server(use_common_server_api_samples=False) + + class ServersCreateImageJsonTest(ServersSampleBase, _ServersActionsJsonTestMixin): """Tests the createImage server action API against 2.1.""" diff --git a/nova/tests/unit/api/openstack/compute/test_quota_classes.py b/nova/tests/unit/api/openstack/compute/test_quota_classes.py index 8b5b2ac6cda8..c710dd3e8b86 100644 --- a/nova/tests/unit/api/openstack/compute/test_quota_classes.py +++ b/nova/tests/unit/api/openstack/compute/test_quota_classes.py @@ -33,6 +33,7 @@ class QuotaClassSetsTestV21(test.TestCase): 'security_groups': 10, 'security_group_rules': 20, 'key_pairs': 100, 'injected_file_path_bytes': 255} + filtered_quotas = None def quota_set(self, class_name): quotas = copy.deepcopy(self.quota_resources) @@ -58,18 +59,15 @@ class QuotaClassSetsTestV21(test.TestCase): def test_format_quota_set(self): quota_set = self.controller._format_quota_set('test_class', self.quota_resources, - self.req) + self.filtered_quotas) qs = quota_set['quota_class_set'] self.assertEqual(qs['id'], 'test_class') - self.assertEqual(qs['instances'], 10) - self.assertEqual(qs['cores'], 20) - self.assertEqual(qs['ram'], 51200) - self.assertEqual(qs['metadata_items'], 128) - self.assertEqual(qs['injected_files'], 5) - self.assertEqual(qs['injected_file_path_bytes'], 255) - self.assertEqual(qs['injected_file_content_bytes'], 10240) - self.assertEqual(qs['key_pairs'], 100) + for resource, value in self.quota_resources.items(): + self.assertEqual(value, qs[resource]) + if self.filtered_quotas: + for resource in self.filtered_quotas: + self.assertNotIn(resource, qs) self._check_filtered_extended_quota(qs) def test_quotas_show(self): @@ -135,25 +133,31 @@ class QuotaClassSetsTestV250(QuotaClassSetsTestV21): 'injected_file_path_bytes': 255, 'server_groups': 10, 'server_group_members': 10} + filtered_quotas = quota_classes_v21.FILTERED_QUOTAS_2_50 def _check_filtered_extended_quota(self, quota_set): self.assertEqual(10, quota_set['server_groups']) self.assertEqual(10, quota_set['server_group_members']) - self.assertNotIn('floating_ips', quota_set) - self.assertNotIn('fixed_ips', quota_set) - self.assertNotIn('security_groups', quota_set) - self.assertNotIn('security_group_rules', quota_set) - self.assertNotIn('networks', quota_set) + for resource in self.filtered_quotas: + self.assertNotIn(resource, quota_set) def test_quotas_update_with_filtered_quota(self): - filtered_quotas = ["fixed_ips", "floating_ips", "networks", - "security_group_rules", "security_groups"] - for resource in filtered_quotas: + for resource in self.filtered_quotas: body = {'quota_class_set': {resource: 10}} self.assertRaises(self.validation_error, self.controller.update, self.req, 'test_class', body=body) +class QuotaClassSetsTestV257(QuotaClassSetsTestV250): + api_version = '2.57' + + def setUp(self): + super(QuotaClassSetsTestV257, self).setUp() + for resource in quota_classes_v21.FILTERED_QUOTAS_2_57: + self.quota_resources.pop(resource, None) + self.filtered_quotas.extend(quota_classes_v21.FILTERED_QUOTAS_2_57) + + class QuotaClassesPolicyEnforcementV21(test.NoDBTestCase): def setUp(self): diff --git a/nova/tests/unit/api/openstack/compute/test_quotas.py b/nova/tests/unit/api/openstack/compute/test_quotas.py index ac3dc993f4a1..26aed6f63804 100644 --- a/nova/tests/unit/api/openstack/compute/test_quotas.py +++ b/nova/tests/unit/api/openstack/compute/test_quotas.py @@ -564,6 +564,7 @@ class QuotaSetsPolicyEnforcementV21(test.NoDBTestCase): class QuotaSetsTestV236(test.NoDBTestCase): + microversion = '2.36' def setUp(self): super(QuotaSetsTestV236, self).setUp() @@ -613,7 +614,7 @@ class QuotaSetsTestV236(test.NoDBTestCase): 'server_groups': 10 } self.controller = quotas_v21.QuotaSetsController() - self.req = fakes.HTTPRequest.blank('', version='2.36') + self.req = fakes.HTTPRequest.blank('', version=self.microversion) def _ensure_filtered_quotas_existed_in_old_api(self): res_dict = self.controller.show(self.old_req, 1234) @@ -666,3 +667,11 @@ class QuotaSetsTestV236(test.NoDBTestCase): body={'quota_set': {'cores': 100}}) for filtered in self.filtered_quotas: self.assertNotIn(filtered, res_dict['quota_set']) + + +class QuotaSetsTestV257(QuotaSetsTestV236): + microversion = '2.57' + + def setUp(self): + super(QuotaSetsTestV257, self).setUp() + self.filtered_quotas.extend(quotas_v21.FILTERED_QUOTAS_2_57) diff --git a/nova/tests/unit/api/openstack/compute/test_serversV21.py b/nova/tests/unit/api/openstack/compute/test_serversV21.py index 3e4d0504f664..5d373087c8f9 100644 --- a/nova/tests/unit/api/openstack/compute/test_serversV21.py +++ b/nova/tests/unit/api/openstack/compute/test_serversV21.py @@ -2295,6 +2295,105 @@ class ServersControllerRebuildTestV254(ServersControllerRebuildInstanceTest): self.req, FAKE_UUID, body=body) +class ServersControllerRebuildTestV257(ServersControllerRebuildTestV254): + """Tests server rebuild at microversion 2.57 where user_data can be + provided and personality files are no longer accepted. + """ + + def setUp(self): + super(ServersControllerRebuildTestV257, self).setUp() + self.req.api_version_request = \ + api_version_request.APIVersionRequest('2.57') + + def test_rebuild_personality(self): + """Tests that trying to rebuild with personality files fails.""" + body = { + "rebuild": { + "imageRef": self.image_uuid, + "personality": [{ + "path": "/path/to/file", + "contents": base64.encode_as_text("Test String"), + }] + } + } + ex = self.assertRaises(exception.ValidationError, + self.controller._action_rebuild, + self.req, FAKE_UUID, body=body) + self.assertIn('personality', six.text_type(ex)) + + def test_rebuild_user_data_old_version(self): + """Tests that trying to rebuild with user_data before 2.57 fails.""" + body = { + "rebuild": { + "imageRef": self.image_uuid, + "user_data": "ZWNobyAiaGVsbG8gd29ybGQi" + } + } + self.req.api_version_request = \ + api_version_request.APIVersionRequest('2.55') + ex = self.assertRaises(exception.ValidationError, + self.controller._action_rebuild, + self.req, FAKE_UUID, body=body) + self.assertIn('user_data', six.text_type(ex)) + + def test_rebuild_user_data_malformed(self): + """Tests that trying to rebuild with malformed user_data fails.""" + body = { + "rebuild": { + "imageRef": self.image_uuid, + "user_data": b'invalid' + } + } + ex = self.assertRaises(exception.ValidationError, + self.controller._action_rebuild, + self.req, FAKE_UUID, body=body) + self.assertIn('user_data', six.text_type(ex)) + + def test_rebuild_user_data_too_large(self): + """Tests that passing user_data to rebuild that is too large fails.""" + body = { + "rebuild": { + "imageRef": self.image_uuid, + "user_data": ('MQ==' * 16384) + } + } + ex = self.assertRaises(exception.ValidationError, + self.controller._action_rebuild, + self.req, FAKE_UUID, body=body) + self.assertIn('user_data', six.text_type(ex)) + + @mock.patch.object(context.RequestContext, 'can') + @mock.patch.object(compute_api.API, 'get') + @mock.patch('nova.db.instance_update_and_get_original') + def test_rebuild_reset_user_data(self, mock_update, mock_get, mock_policy): + """Tests that passing user_data=None resets the user_data on the + instance. + """ + body = { + "rebuild": { + "imageRef": self.image_uuid, + "user_data": None + } + } + + mock_get.return_value = fakes.stub_instance_obj( + context.RequestContext(self.req_user_id, self.req_project_id), + user_data='ZWNobyAiaGVsbG8gd29ybGQi') + + def fake_instance_update_and_get_original( + ctxt, instance_uuid, values, **kwargs): + # save() is called twice and the second one has system_metadata + # in the updates, so we can ignore that one. + if 'system_metadata' not in values: + self.assertIn('user_data', values) + self.assertIsNone(values['user_data']) + return instance_update_and_get_original( + ctxt, instance_uuid, values, **kwargs) + mock_update.side_effect = fake_instance_update_and_get_original + self.controller._action_rebuild(self.req, FAKE_UUID, body=body) + self.assertEqual(2, mock_update.call_count) + + class ServersControllerRebuildTestV219(ServersControllerRebuildInstanceTest): def setUp(self): @@ -4096,6 +4195,33 @@ class ServersControllerCreateTestV252(test.NoDBTestCase): exception.ValidationError, self._create_server, tags) +class ServersControllerCreateTestV257(test.NoDBTestCase): + """Tests that trying to create a server with personality files using + microversion 2.57 fails. + """ + def test_create_server_with_personality_fails(self): + controller = servers.ServersController() + body = { + 'server': { + 'name': 'no-personality-files', + 'imageRef': '6b0edabb-8cde-4684-a3f4-978960a51378', + 'flavorRef': '2', + 'networks': 'auto', + 'personality': [{ + 'path': '/path/to/file', + 'contents': 'ZWNobyAiaGVsbG8gd29ybGQi' + }] + } + } + req = fakes.HTTPRequestV21.blank('/servers', version='2.57') + req.body = jsonutils.dump_as_bytes(body) + req.method = 'POST' + req.headers['content-type'] = 'application/json' + ex = self.assertRaises( + exception.ValidationError, controller.create, req, body=body) + self.assertIn('personality', six.text_type(ex)) + + class ServersControllerCreateTestWithMock(test.TestCase): image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6' flavor_ref = 'http://localhost/123/flavors/3' diff --git a/releasenotes/notes/bp-deprecate-file-injection-feaf490524d10b3d.yaml b/releasenotes/notes/bp-deprecate-file-injection-feaf490524d10b3d.yaml new file mode 100644 index 000000000000..80c868819071 --- /dev/null +++ b/releasenotes/notes/bp-deprecate-file-injection-feaf490524d10b3d.yaml @@ -0,0 +1,17 @@ +--- +features: + - | + The 2.57 microversion makes the following changes: + + * The ``user_data`` parameter is added to the server rebuild API. + * The ``personality`` parameter is removed from the server create and + rebuild APIs. Use the ``user_data`` parameter instead. + * The ``maxPersonality`` and ``maxPersonalitySize`` limits are excluded + from the ``GET /limits`` API response. + * The ``injected_files``, ``injected_file_content_bytes`` and + ``injected_file_path_bytes`` quotas are removed from the + ``os-quota-sets`` and ``os-quota-class-sets`` APIs. + + See the `spec`_ for more details and reasoning. + + .. _spec: https://specs.openstack.org/openstack/nova-specs/specs/queens/approved/deprecate-file-injection.html