Merge "Deprecate file injection"
This commit is contained in:
commit
29e453df8e
@ -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.
|
||||
@ -3300,6 +3301,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,
|
||||
@ -3308,18 +3310,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,
|
||||
@ -3328,18 +3333,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: |
|
||||
@ -3354,12 +3362,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.
|
||||
@ -4575,6 +4585,7 @@ path:
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
max_version: 2.56
|
||||
pause:
|
||||
description: |
|
||||
The action to pause a server.
|
||||
@ -4603,6 +4614,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
|
||||
@ -5846,6 +5858,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.
|
||||
|
@ -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)**
|
||||
|
||||
|
@ -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
|
||||
|
18
doc/api_samples/limits/v2.57/limit-get-resp.json
Normal file
18
doc/api_samples/limits/v2.57/limit-get-resp.json
Normal file
@ -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": []
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"quota_set": {
|
||||
"force": "True",
|
||||
"instances": 45
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"quota_set": {
|
||||
"instances": 20
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"quota_set": {
|
||||
"instances": 9
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
15
doc/api_samples/servers/v2.57/server-action-rebuild.json
Normal file
15
doc/api_samples/servers/v2.57/server-action-rebuild.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
21
doc/api_samples/servers/v2.57/server-create-req.json
Normal file
21
doc/api_samples/servers/v2.57/server-create-req.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
22
doc/api_samples/servers/v2.57/server-create-resp.json
Normal file
22
doc/api_samples/servers/v2.57/server-create-resp.json
Normal file
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"status": "CURRENT",
|
||||
"version": "2.56",
|
||||
"version": "2.57",
|
||||
"min_version": "2.1",
|
||||
"updated": "2013-07-23T11:33:21Z"
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
}
|
||||
],
|
||||
"status": "CURRENT",
|
||||
"version": "2.56",
|
||||
"version": "2.57",
|
||||
"min_version": "2.1",
|
||||
"updated": "2013-07-23T11:33:21Z"
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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']
|
||||
|
@ -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.
|
||||
|
@ -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']
|
||||
|
@ -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': {
|
||||
|
@ -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': {
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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": []
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"quota_set": {
|
||||
"force": "True",
|
||||
"instances": 45
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"quota_set": {
|
||||
"instances": 20
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"quota_set": {
|
||||
"instances": 9
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -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'})]
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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."""
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
|
@ -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'
|
||||
|
@ -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
|
Loading…
Reference in New Issue
Block a user