Merge "[proxy-api] microversion 2.39 deprecates image-metadata proxy API"
This commit is contained in:
@@ -24,7 +24,7 @@ Response
|
|||||||
|
|
||||||
- limits: limits
|
- limits: limits
|
||||||
- absolute: limits_absolutes
|
- absolute: limits_absolutes
|
||||||
- maxImageMeta: metadata_items
|
- maxImageMeta: image_metadata_items
|
||||||
- maxPersonality: injected_files
|
- maxPersonality: injected_files
|
||||||
- maxPersonalitySize: injected_file_content_bytes
|
- maxPersonalitySize: injected_file_content_bytes
|
||||||
- maxSecurityGroupRules: security_group_rules
|
- maxSecurityGroupRules: security_group_rules
|
||||||
|
|||||||
@@ -2370,6 +2370,15 @@ image_id_body:
|
|||||||
in: body
|
in: body
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
image_metadata_items:
|
||||||
|
description: |
|
||||||
|
The number of allowed metadata items for each image. Starting from
|
||||||
|
version 2.39 this field is dropped from 'os-limits' response, because
|
||||||
|
'image-metadata' proxy API was deprecated.
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
max_version: 2.38
|
||||||
image_name:
|
image_name:
|
||||||
description: |
|
description: |
|
||||||
The display name of an Image.
|
The display name of an Image.
|
||||||
|
|||||||
@@ -219,6 +219,10 @@ If the operation succeeds, the created image has a status of ``active`` and
|
|||||||
the server status returns to the original status. You can also see the new
|
the server status returns to the original status. You can also see the new
|
||||||
image in the image back end that OpenStack Image service manages.
|
image in the image back end that OpenStack Image service manages.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Starting from version 2.39 the image quota enforcement with Nova `metadata`
|
||||||
|
is removed and quota checks should be performed using Glance API directly.
|
||||||
|
|
||||||
**Preconditions**
|
**Preconditions**
|
||||||
|
|
||||||
The server must exist.
|
The server must exist.
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ Policy defaults enable only users with the administrative role or the
|
|||||||
owner of the server to perform this operation. Cloud providers can
|
owner of the server to perform this operation. Cloud providers can
|
||||||
change these permissions through the ``policy.json`` file.
|
change these permissions through the ``policy.json`` file.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Starting from version 2.39 the image quota enforcement with Nova `metadata`
|
||||||
|
is removed and quota checks should be performed using Glance API directly.
|
||||||
|
|
||||||
Normal response codes: 202
|
Normal response codes: 202
|
||||||
|
|
||||||
Error response codes: badRequest(400), unauthorized(401), forbidden(403),
|
Error response codes: badRequest(400), unauthorized(401), forbidden(403),
|
||||||
|
|||||||
20
doc/api_samples/limits/v2.39/limit-get-resp.json
Normal file
20
doc/api_samples/limits/v2.39/limit-get-resp.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"limits": {
|
||||||
|
"absolute": {
|
||||||
|
"maxPersonality": 5,
|
||||||
|
"maxPersonalitySize": 10240,
|
||||||
|
"maxServerMeta": 128,
|
||||||
|
"maxTotalCores": 20,
|
||||||
|
"maxTotalInstances": 10,
|
||||||
|
"maxTotalKeypairs": 100,
|
||||||
|
"maxTotalRAMSize": 51200,
|
||||||
|
"maxServerGroups": 10,
|
||||||
|
"maxServerGroupMembers": 10,
|
||||||
|
"totalCoresUsed": 0,
|
||||||
|
"totalInstancesUsed": 0,
|
||||||
|
"totalRAMUsed": 0,
|
||||||
|
"totalServerGroupsUsed": 0
|
||||||
|
},
|
||||||
|
"rate": []
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"status": "CURRENT",
|
"status": "CURRENT",
|
||||||
"version": "2.38",
|
"version": "2.39",
|
||||||
"min_version": "2.1",
|
"min_version": "2.1",
|
||||||
"updated": "2013-07-23T11:33:21Z"
|
"updated": "2013-07-23T11:33:21Z"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"status": "CURRENT",
|
"status": "CURRENT",
|
||||||
"version": "2.38",
|
"version": "2.39",
|
||||||
"min_version": "2.1",
|
"min_version": "2.1",
|
||||||
"updated": "2013-07-23T11:33:21Z"
|
"updated": "2013-07-23T11:33:21Z"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ REST_API_VERSION_HISTORY = """REST API Version History:
|
|||||||
UUID format.
|
UUID format.
|
||||||
* 2.38 - Add a condition to return HTTPBadRequest if invalid status is
|
* 2.38 - Add a condition to return HTTPBadRequest if invalid status is
|
||||||
provided for listing servers.
|
provided for listing servers.
|
||||||
|
* 2.39 - Deprecates image-metadata proxy API
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# The minimum and maximum versions of the API supported
|
# The minimum and maximum versions of the API supported
|
||||||
@@ -103,14 +104,18 @@ REST_API_VERSION_HISTORY = """REST API Version History:
|
|||||||
# Note(cyeoh): This only applies for the v2.1 API once microversions
|
# Note(cyeoh): This only applies for the v2.1 API once microversions
|
||||||
# support is fully merged. It does not affect the V2 API.
|
# support is fully merged. It does not affect the V2 API.
|
||||||
_MIN_API_VERSION = "2.1"
|
_MIN_API_VERSION = "2.1"
|
||||||
_MAX_API_VERSION = "2.38"
|
_MAX_API_VERSION = "2.39"
|
||||||
DEFAULT_API_VERSION = _MIN_API_VERSION
|
DEFAULT_API_VERSION = _MIN_API_VERSION
|
||||||
|
|
||||||
# All the proxy APIs which related network, images and baremetal
|
# Almost all proxy APIs which related to network, images and baremetal
|
||||||
# were deprecated from 2.36.
|
# were deprecated from 2.36.
|
||||||
MAX_PROXY_API_SUPPORT_VERSION = '2.35'
|
MAX_PROXY_API_SUPPORT_VERSION = '2.35'
|
||||||
MIN_WITHOUT_PROXY_API_SUPPORT_VERSION = '2.36'
|
MIN_WITHOUT_PROXY_API_SUPPORT_VERSION = '2.36'
|
||||||
|
|
||||||
|
# Starting from microversion 2.39 also image-metadata proxy API is deprecated.
|
||||||
|
MAX_IMAGE_META_PROXY_API_VERSION = '2.38'
|
||||||
|
MIN_WITHOUT_IMAGE_META_PROXY_API_VERSION = '2.39'
|
||||||
|
|
||||||
|
|
||||||
# NOTE(cyeoh): min and max versions declared as functions so we can
|
# NOTE(cyeoh): min and max versions declared as functions so we can
|
||||||
# mock them for unittests. Do not use the constants directly anywhere
|
# mock them for unittests. Do not use the constants directly anywhere
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
import webob
|
import webob
|
||||||
|
|
||||||
|
from nova.api.openstack import api_version_request
|
||||||
from nova.api.openstack import common
|
from nova.api.openstack import common
|
||||||
from nova.api.openstack.compute.schemas import create_backup
|
from nova.api.openstack.compute.schemas import create_backup
|
||||||
from nova.api.openstack import extensions
|
from nova.api.openstack import extensions
|
||||||
@@ -57,7 +58,11 @@ class CreateBackupController(wsgi.Controller):
|
|||||||
|
|
||||||
props = {}
|
props = {}
|
||||||
metadata = entity.get('metadata', {})
|
metadata = entity.get('metadata', {})
|
||||||
common.check_img_metadata_properties_quota(context, metadata)
|
# Starting from microversion 2.39 we don't check quotas on createBackup
|
||||||
|
if api_version_request.is_supported(
|
||||||
|
req, max_version=
|
||||||
|
api_version_request.MAX_IMAGE_META_PROXY_API_VERSION):
|
||||||
|
common.check_img_metadata_properties_quota(context, metadata)
|
||||||
props.update(metadata)
|
props.update(metadata)
|
||||||
|
|
||||||
instance = common.get_instance(self.compute_api, context, id)
|
instance = common.get_instance(self.compute_api, context, id)
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
import six
|
import six
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
|
from nova.api.openstack.api_version_request import \
|
||||||
|
MAX_IMAGE_META_PROXY_API_VERSION
|
||||||
from nova.api.openstack import common
|
from nova.api.openstack import common
|
||||||
from nova.api.openstack.compute.schemas import image_metadata
|
from nova.api.openstack.compute.schemas import image_metadata
|
||||||
from nova.api.openstack import extensions
|
from nova.api.openstack import extensions
|
||||||
@@ -43,6 +45,7 @@ class ImageMetadataController(wsgi.Controller):
|
|||||||
msg = _("Image not found.")
|
msg = _("Image not found.")
|
||||||
raise exc.HTTPNotFound(explanation=msg)
|
raise exc.HTTPNotFound(explanation=msg)
|
||||||
|
|
||||||
|
@wsgi.Controller.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
|
||||||
@extensions.expected_errors((403, 404))
|
@extensions.expected_errors((403, 404))
|
||||||
def index(self, req, image_id):
|
def index(self, req, image_id):
|
||||||
"""Returns the list of metadata for a given instance."""
|
"""Returns the list of metadata for a given instance."""
|
||||||
@@ -50,6 +53,7 @@ class ImageMetadataController(wsgi.Controller):
|
|||||||
metadata = self._get_image(context, image_id)['properties']
|
metadata = self._get_image(context, image_id)['properties']
|
||||||
return dict(metadata=metadata)
|
return dict(metadata=metadata)
|
||||||
|
|
||||||
|
@wsgi.Controller.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
|
||||||
@extensions.expected_errors((403, 404))
|
@extensions.expected_errors((403, 404))
|
||||||
def show(self, req, image_id, id):
|
def show(self, req, image_id, id):
|
||||||
context = req.environ['nova.context']
|
context = req.environ['nova.context']
|
||||||
@@ -59,6 +63,7 @@ class ImageMetadataController(wsgi.Controller):
|
|||||||
else:
|
else:
|
||||||
raise exc.HTTPNotFound()
|
raise exc.HTTPNotFound()
|
||||||
|
|
||||||
|
@wsgi.Controller.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
|
||||||
@extensions.expected_errors((400, 403, 404))
|
@extensions.expected_errors((400, 403, 404))
|
||||||
@validation.schema(image_metadata.create)
|
@validation.schema(image_metadata.create)
|
||||||
def create(self, req, image_id, body):
|
def create(self, req, image_id, body):
|
||||||
@@ -75,6 +80,7 @@ class ImageMetadataController(wsgi.Controller):
|
|||||||
raise exc.HTTPForbidden(explanation=e.format_message())
|
raise exc.HTTPForbidden(explanation=e.format_message())
|
||||||
return dict(metadata=image['properties'])
|
return dict(metadata=image['properties'])
|
||||||
|
|
||||||
|
@wsgi.Controller.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
|
||||||
@extensions.expected_errors((400, 403, 404))
|
@extensions.expected_errors((400, 403, 404))
|
||||||
@validation.schema(image_metadata.update)
|
@validation.schema(image_metadata.update)
|
||||||
def update(self, req, image_id, id, body):
|
def update(self, req, image_id, id, body):
|
||||||
@@ -97,6 +103,7 @@ class ImageMetadataController(wsgi.Controller):
|
|||||||
raise exc.HTTPForbidden(explanation=e.format_message())
|
raise exc.HTTPForbidden(explanation=e.format_message())
|
||||||
return dict(meta=meta)
|
return dict(meta=meta)
|
||||||
|
|
||||||
|
@wsgi.Controller.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
|
||||||
@extensions.expected_errors((400, 403, 404))
|
@extensions.expected_errors((400, 403, 404))
|
||||||
@validation.schema(image_metadata.update_all)
|
@validation.schema(image_metadata.update_all)
|
||||||
def update_all(self, req, image_id, body):
|
def update_all(self, req, image_id, body):
|
||||||
@@ -112,6 +119,7 @@ class ImageMetadataController(wsgi.Controller):
|
|||||||
raise exc.HTTPForbidden(explanation=e.format_message())
|
raise exc.HTTPForbidden(explanation=e.format_message())
|
||||||
return dict(metadata=metadata)
|
return dict(metadata=metadata)
|
||||||
|
|
||||||
|
@wsgi.Controller.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
|
||||||
@extensions.expected_errors((403, 404))
|
@extensions.expected_errors((403, 404))
|
||||||
@wsgi.response(204)
|
@wsgi.response(204)
|
||||||
def delete(self, req, image_id, id):
|
def delete(self, req, image_id, id):
|
||||||
|
|||||||
@@ -13,8 +13,12 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from nova.api.openstack.api_version_request \
|
||||||
|
import MAX_IMAGE_META_PROXY_API_VERSION
|
||||||
from nova.api.openstack.api_version_request \
|
from nova.api.openstack.api_version_request \
|
||||||
import MAX_PROXY_API_SUPPORT_VERSION
|
import MAX_PROXY_API_SUPPORT_VERSION
|
||||||
|
from nova.api.openstack.api_version_request \
|
||||||
|
import MIN_WITHOUT_IMAGE_META_PROXY_API_VERSION
|
||||||
from nova.api.openstack.api_version_request \
|
from nova.api.openstack.api_version_request \
|
||||||
import MIN_WITHOUT_PROXY_API_SUPPORT_VERSION
|
import MIN_WITHOUT_PROXY_API_SUPPORT_VERSION
|
||||||
from nova.api.openstack.compute.views import limits as limits_views
|
from nova.api.openstack.compute.views import limits as limits_views
|
||||||
@@ -36,12 +40,19 @@ class LimitsController(wsgi.Controller):
|
|||||||
def index(self, req):
|
def index(self, req):
|
||||||
return self._index(req)
|
return self._index(req)
|
||||||
|
|
||||||
@wsgi.Controller.api_version(MIN_WITHOUT_PROXY_API_SUPPORT_VERSION) # noqa
|
@wsgi.Controller.api_version(MIN_WITHOUT_PROXY_API_SUPPORT_VERSION, # noqa
|
||||||
|
MAX_IMAGE_META_PROXY_API_VERSION) # noqa
|
||||||
@extensions.expected_errors(())
|
@extensions.expected_errors(())
|
||||||
def index(self, req):
|
def index(self, req):
|
||||||
return self._index(req, filter_result=True)
|
return self._index(req, filter_result=True)
|
||||||
|
|
||||||
def _index(self, req, filter_result=False):
|
@wsgi.Controller.api_version( # noqa
|
||||||
|
MIN_WITHOUT_IMAGE_META_PROXY_API_VERSION) # noqa
|
||||||
|
@extensions.expected_errors(())
|
||||||
|
def index(self, req):
|
||||||
|
return self._index(req, filter_result=True, max_image_meta=False)
|
||||||
|
|
||||||
|
def _index(self, req, filter_result=False, max_image_meta=True):
|
||||||
"""Return all global limit information."""
|
"""Return all global limit information."""
|
||||||
context = req.environ['nova.context']
|
context = req.environ['nova.context']
|
||||||
context.can(limits_policies.BASE_POLICY_NAME)
|
context.can(limits_policies.BASE_POLICY_NAME)
|
||||||
@@ -51,7 +62,8 @@ class LimitsController(wsgi.Controller):
|
|||||||
abs_limits = {k: v['limit'] for k, v in quotas.items()}
|
abs_limits = {k: v['limit'] for k, v in quotas.items()}
|
||||||
|
|
||||||
builder = self._get_view_builder(req)
|
builder = self._get_view_builder(req)
|
||||||
return builder.build(abs_limits, filter_result=filter_result)
|
return builder.build(abs_limits, filter_result=filter_result,
|
||||||
|
max_image_meta=max_image_meta)
|
||||||
|
|
||||||
def _get_view_builder(self, req):
|
def _get_view_builder(self, req):
|
||||||
return limits_views.ViewBuilderV21()
|
return limits_views.ViewBuilderV21()
|
||||||
|
|||||||
@@ -1053,7 +1053,11 @@ class ServersController(wsgi.Controller):
|
|||||||
image_name = common.normalize_name(entity["name"])
|
image_name = common.normalize_name(entity["name"])
|
||||||
metadata = entity.get('metadata', {})
|
metadata = entity.get('metadata', {})
|
||||||
|
|
||||||
common.check_img_metadata_properties_quota(context, metadata)
|
# Starting from microversion 2.39 we don't check quotas on createImage
|
||||||
|
if api_version_request.is_supported(
|
||||||
|
req, max_version=
|
||||||
|
api_version_request.MAX_IMAGE_META_PROXY_API_VERSION):
|
||||||
|
common.check_img_metadata_properties_quota(context, metadata)
|
||||||
|
|
||||||
instance = self._get_server(context, req, id)
|
instance = self._get_server(context, req, id)
|
||||||
|
|
||||||
|
|||||||
@@ -41,9 +41,10 @@ class ViewBuilder(object):
|
|||||||
"security_group_rules": ["maxSecurityGroupRules"],
|
"security_group_rules": ["maxSecurityGroupRules"],
|
||||||
}
|
}
|
||||||
|
|
||||||
def build(self, absolute_limits, filter_result=False):
|
def build(self, absolute_limits, filter_result=False, max_image_meta=True):
|
||||||
absolute_limits = self._build_absolute_limits(
|
absolute_limits = self._build_absolute_limits(
|
||||||
absolute_limits, filter_result=filter_result)
|
absolute_limits, filter_result=filter_result,
|
||||||
|
max_image_meta=max_image_meta)
|
||||||
|
|
||||||
output = {
|
output = {
|
||||||
"limits": {
|
"limits": {
|
||||||
@@ -54,7 +55,8 @@ class ViewBuilder(object):
|
|||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def _build_absolute_limits(self, absolute_limits, filter_result=False):
|
def _build_absolute_limits(self, absolute_limits, filter_result=False,
|
||||||
|
max_image_meta=True):
|
||||||
"""Builder for absolute limits
|
"""Builder for absolute limits
|
||||||
|
|
||||||
absolute_limits should be given as a dict of limits.
|
absolute_limits should be given as a dict of limits.
|
||||||
@@ -69,6 +71,8 @@ class ViewBuilder(object):
|
|||||||
if (name in self.limit_names and
|
if (name in self.limit_names and
|
||||||
value is not None and name not in filtered_limits):
|
value is not None and name not in filtered_limits):
|
||||||
for limit_name in self.limit_names[name]:
|
for limit_name in self.limit_names[name]:
|
||||||
|
if not max_image_meta and limit_name == "maxImageMeta":
|
||||||
|
continue
|
||||||
limits[limit_name] = value
|
limits[limit_name] = value
|
||||||
return limits
|
return limits
|
||||||
|
|
||||||
|
|||||||
@@ -415,3 +415,14 @@ user documentation.
|
|||||||
should not be accepted. From this version of the API admin as well as non
|
should not be accepted. From this version of the API admin as well as non
|
||||||
admin user will get 400 HTTPBadRequest if invalid status is passed to nova
|
admin user will get 400 HTTPBadRequest if invalid status is passed to nova
|
||||||
list command.
|
list command.
|
||||||
|
|
||||||
|
2.39
|
||||||
|
----
|
||||||
|
|
||||||
|
Deprecates image-metadata proxy API that is just a proxy for Glance API
|
||||||
|
to operate the image metadata. Also removes the extra quota enforcement with
|
||||||
|
Nova `metadata` quota (quota checks for 'createImage' and 'createBackup'
|
||||||
|
actions in Nova were removed). After this version Glance configuration
|
||||||
|
option `image_property_quota` should be used to control the quota of
|
||||||
|
image metadatas. Also, removes the `maxImageMeta` field from `os-limits`
|
||||||
|
API response.
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"limits": {
|
||||||
|
"absolute": {
|
||||||
|
"maxPersonality": 5,
|
||||||
|
"maxPersonalitySize": 10240,
|
||||||
|
"maxServerMeta": 128,
|
||||||
|
"maxTotalCores": 20,
|
||||||
|
"maxTotalInstances": 10,
|
||||||
|
"maxTotalKeypairs": 100,
|
||||||
|
"maxTotalRAMSize": 51200,
|
||||||
|
"maxServerGroups": 10,
|
||||||
|
"maxServerGroupMembers": 10,
|
||||||
|
"totalCoresUsed": 0,
|
||||||
|
"totalInstancesUsed": 0,
|
||||||
|
"totalRAMUsed": 0,
|
||||||
|
"totalServerGroupsUsed": 0
|
||||||
|
},
|
||||||
|
"rate": []
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,3 +48,20 @@ class LimitsV236Test(api_sample_base.ApiSampleTestBaseV21):
|
|||||||
self.api.microversion = self.microversion
|
self.api.microversion = self.microversion
|
||||||
response = self._do_get('limits')
|
response = self._do_get('limits')
|
||||||
self._verify_response('limit-get-resp', {}, response, 200)
|
self._verify_response('limit-get-resp', {}, response, 200)
|
||||||
|
|
||||||
|
|
||||||
|
class LimitsV239Test(api_sample_base.ApiSampleTestBaseV21):
|
||||||
|
"""Test limits don't return 'maxImageMeta' field after 2.39.
|
||||||
|
|
||||||
|
We dropped the image-metadata proxy API in 2.39, which also means that we
|
||||||
|
shouldn't be returning 'maxImageMeta' field in 'os-limits' response.
|
||||||
|
|
||||||
|
"""
|
||||||
|
sample_dir = "limits"
|
||||||
|
microversion = '2.39'
|
||||||
|
scenarios = [('v2_39', {'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)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import mock
|
||||||
import webob
|
import webob
|
||||||
|
|
||||||
from nova.api.openstack import common
|
from nova.api.openstack import common
|
||||||
@@ -352,3 +353,34 @@ class CreateBackupPolicyEnforcementv21(test.NoDBTestCase):
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
"Policy doesn't allow %s to be performed." % rule_name,
|
"Policy doesn't allow %s to be performed." % rule_name,
|
||||||
exc.format_message())
|
exc.format_message())
|
||||||
|
|
||||||
|
|
||||||
|
class CreateBackupTestsV239(test.NoDBTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(CreateBackupTestsV239, self).setUp()
|
||||||
|
self.controller = create_backup_v21.CreateBackupController()
|
||||||
|
self.req = fakes.HTTPRequest.blank('', version='2.39')
|
||||||
|
|
||||||
|
@mock.patch.object(common, 'check_img_metadata_properties_quota')
|
||||||
|
@mock.patch.object(common, 'get_instance')
|
||||||
|
def test_create_backup_no_quota_checks(self, mock_get_instance,
|
||||||
|
mock_check_quotas):
|
||||||
|
# 'mock_get_instance' helps to skip the whole logic of the action,
|
||||||
|
# but to make the test
|
||||||
|
mock_get_instance.side_effect = webob.exc.HTTPNotFound
|
||||||
|
metadata = {'123': 'asdf'}
|
||||||
|
body = {
|
||||||
|
'createBackup': {
|
||||||
|
'name': 'Backup 1',
|
||||||
|
'backup_type': 'daily',
|
||||||
|
'rotation': 1,
|
||||||
|
'metadata': metadata,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
self.assertRaises(webob.exc.HTTPNotFound,
|
||||||
|
self.controller._create_backup, self.req,
|
||||||
|
fakes.FAKE_UUID, body=body)
|
||||||
|
# starting from version 2.39 no quota checks on Nova side are performed
|
||||||
|
# for 'createBackup' action after removing 'image-metadata' proxy API
|
||||||
|
mock_check_quotas.assert_not_called()
|
||||||
|
|||||||
@@ -348,3 +348,28 @@ class ImageMetaDataTestV21(test.NoDBTestCase):
|
|||||||
self.assertRaises(webob.exc.HTTPForbidden,
|
self.assertRaises(webob.exc.HTTPForbidden,
|
||||||
self.controller.create, req, image_id,
|
self.controller.create, req, image_id,
|
||||||
body=body)
|
body=body)
|
||||||
|
|
||||||
|
|
||||||
|
class ImageMetadataControllerV239(test.NoDBTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(ImageMetadataControllerV239, self).setUp()
|
||||||
|
self.controller = image_metadata_v21.ImageMetadataController()
|
||||||
|
self.req = fakes.HTTPRequest.blank('', version='2.39')
|
||||||
|
|
||||||
|
def test_not_found_for_all_image_metadata_api(self):
|
||||||
|
self.assertRaises(exception.VersionNotFoundForAPIMethod,
|
||||||
|
self.controller.index, self.req)
|
||||||
|
self.assertRaises(exception.VersionNotFoundForAPIMethod,
|
||||||
|
self.controller.show, self.req, fakes.FAKE_UUID)
|
||||||
|
self.assertRaises(exception.VersionNotFoundForAPIMethod,
|
||||||
|
self.controller.create, self.req,
|
||||||
|
fakes.FAKE_UUID, {'metadata': {}})
|
||||||
|
self.assertRaises(exception.VersionNotFoundForAPIMethod,
|
||||||
|
self.controller.update, self.req,
|
||||||
|
fakes.FAKE_UUID, 'id', {'metadata': {}})
|
||||||
|
self.assertRaises(exception.VersionNotFoundForAPIMethod,
|
||||||
|
self.controller.update_all, self.req,
|
||||||
|
fakes.FAKE_UUID, {'metadata': {}})
|
||||||
|
self.assertRaises(exception.VersionNotFoundForAPIMethod,
|
||||||
|
self.controller.delete, self.req, fakes.FAKE_UUID)
|
||||||
|
|||||||
@@ -275,3 +275,36 @@ class LimitsControllerTestV236(BaseLimitTestSuite):
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
self.assertEqual(expected_response, response)
|
self.assertEqual(expected_response, response)
|
||||||
|
|
||||||
|
|
||||||
|
class LimitsControllerTestV239(BaseLimitTestSuite):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(LimitsControllerTestV239, self).setUp()
|
||||||
|
self.controller = limits_v21.LimitsController()
|
||||||
|
self.req = fakes.HTTPRequest.blank("/?tenant_id=faketenant",
|
||||||
|
version='2.39')
|
||||||
|
|
||||||
|
def test_index_filtered_no_max_image_meta(self):
|
||||||
|
absolute_limits = {
|
||||||
|
"metadata_items": 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
def _get_project_quotas(context, project_id, usages=True):
|
||||||
|
return {k: dict(limit=v) for k, v in absolute_limits.items()}
|
||||||
|
|
||||||
|
with mock.patch('nova.quota.QUOTAS.get_project_quotas') as \
|
||||||
|
get_project_quotas:
|
||||||
|
get_project_quotas.side_effect = _get_project_quotas
|
||||||
|
response = self.controller.index(self.req)
|
||||||
|
# staring from version 2.39 there is no 'maxImageMeta' field
|
||||||
|
# in response after removing 'image-metadata' proxy API
|
||||||
|
expected_response = {
|
||||||
|
"limits": {
|
||||||
|
"rate": [],
|
||||||
|
"absolute": {
|
||||||
|
"maxServerMeta": 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
self.assertEqual(expected_response, response)
|
||||||
|
|||||||
@@ -4834,3 +4834,31 @@ class ServersPolicyEnforcementV21(test.NoDBTestCase):
|
|||||||
"os_compute_api:servers:create:attach_volume": "@",
|
"os_compute_api:servers:create:attach_volume": "@",
|
||||||
rule_name: "project:non_fake"}
|
rule_name: "project:non_fake"}
|
||||||
self._create_policy_check(rules, rule_name)
|
self._create_policy_check(rules, rule_name)
|
||||||
|
|
||||||
|
|
||||||
|
class ServersActionsJsonTestV239(test.NoDBTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(ServersActionsJsonTestV239, self).setUp()
|
||||||
|
ext_info = extension_info.LoadedExtensionInfo()
|
||||||
|
self.controller = servers.ServersController(extension_info=ext_info)
|
||||||
|
self.req = fakes.HTTPRequest.blank('', version='2.39')
|
||||||
|
|
||||||
|
@mock.patch.object(common, 'check_img_metadata_properties_quota')
|
||||||
|
@mock.patch.object(common, 'get_instance')
|
||||||
|
def test_server_create_image_no_quota_checks(self, mock_get_instance,
|
||||||
|
mock_check_quotas):
|
||||||
|
# 'mock_get_instance' helps to skip the whole logic of the action,
|
||||||
|
# but to make the test
|
||||||
|
mock_get_instance.side_effect = webob.exc.HTTPNotFound
|
||||||
|
body = {
|
||||||
|
'createImage': {
|
||||||
|
'name': 'Snapshot 1',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
self.assertRaises(webob.exc.HTTPNotFound,
|
||||||
|
self.controller._action_create_image, self.req,
|
||||||
|
FAKE_UUID, body=body)
|
||||||
|
# starting from version 2.39 no quota checks on Nova side are performed
|
||||||
|
# for 'createImage' action after removing 'image-metadata' proxy API
|
||||||
|
mock_check_quotas.assert_not_called()
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
deprecations:
|
||||||
|
- Implemented microversion v2.39 that deprecates `image-metadata` proxy API,
|
||||||
|
removes image metadata quota checks for 'createImage' and 'createBackup'
|
||||||
|
actions.
|
||||||
|
|
||||||
|
After this version Glance configuration option `image_property_quota`
|
||||||
|
should be used to control the quota of image metadatas. Also, removes the
|
||||||
|
`maxImageMeta` field from `os-limits` API response.
|
||||||
Reference in New Issue
Block a user