Increase size of volume image metadata values

Volume image metadata values were limited to 255 characters but Glance
allows up to 65535 (considering it uses a TEXT field in MySQL). Cinder
database also uses a TEXT field for those values so it made no sense to
limit them to 255. The actual values could already be longer when they
were copied from the image at volume creation time.

Closes-Bug: #1988942
Change-Id: Id200ae93384a452b34bdd20dd1f3fc656ec5650f
This commit is contained in:
Jorge Merlino 2022-12-23 09:46:43 -03:00
parent 12fb54ad60
commit 0bd1bd699d
5 changed files with 89 additions and 3 deletions

View File

@ -27,7 +27,7 @@ set_image_metadata = {
'os-set_image_metadata': {
'type': 'object',
'properties': {
'metadata': parameter_types.extra_specs,
'metadata': parameter_types.image_metadata,
},
'required': ['metadata'],
'additionalProperties': False,

View File

@ -157,6 +157,15 @@ extra_specs = {
'additionalProperties': False
}
image_metadata = {
'type': 'object',
'patternProperties': {
'^[a-zA-Z0-9-_:. /]{1,255}$': {
'type': 'string', 'format': 'mysql_text'
}
},
'additionalProperties': False
}
extra_specs_with_no_spaces_key = {
'type': 'object',

View File

@ -398,6 +398,14 @@ def _validate_key_size(param_value):
return True
@jsonschema.FormatChecker.cls_checks('mysql_text')
def _validate_mysql_text(param_value):
length = len(param_value.encode('utf8'))
if length > 65535:
return False
return True
class FormatChecker(jsonschema.FormatChecker):
"""A FormatChecker can output the message from cause exception

View File

@ -220,6 +220,44 @@ class VolumeImageMetadataTest(test.TestCase):
self.assertEqual(fake_image_metadata,
jsonutils.loads(res.body)["metadata"])
# Test for value > 255
body = {"os-set_image_metadata": {
"metadata": {"key": "v" * 260}}
}
req = webob.Request.blank('/v3/%s/volumes/%s/action' % (
fake.PROJECT_ID, fake.VOLUME_ID))
req.method = "POST"
req.body = jsonutils.dump_as_bytes(body)
req.headers["content-type"] = "application/json"
fake_get.return_value = {}
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
self.assertEqual(HTTPStatus.OK, res.status_int)
# This is a weird one ... take a supplementary unicode
# char that requires 4 bytes, which will give us a short
# string in terms of character count, but a long string
# in terms of bytes, and make this string be exactly
# 65535 bytes in length. This should be OK.
char4bytes = "\N{CJK UNIFIED IDEOGRAPH-29D98}"
self.assertEqual(1, len(char4bytes))
self.assertEqual(4, len(char4bytes.encode('utf-8')))
str65535bytes = char4bytes * 16383 + '123'
self.assertLess(len(str65535bytes), 65535)
self.assertEqual(65535, len(str65535bytes.encode('utf-8')))
body = {"os-set_image_metadata": {
"metadata": {"key": str65535bytes}}
}
req = webob.Request.blank('/v3/%s/volumes/%s/action' % (
fake.PROJECT_ID, fake.VOLUME_ID))
req.method = "POST"
req.body = jsonutils.dump_as_bytes(body)
req.headers["content-type"] = "application/json"
fake_get.return_value = {}
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
self.assertEqual(HTTPStatus.OK, res.status_int)
@mock.patch('cinder.objects.Volume.get_by_id')
def test_create_image_metadata_policy_not_authorized(self, fake_get):
rules = {
@ -323,15 +361,38 @@ class VolumeImageMetadataTest(test.TestCase):
self.controller.create, req, fake.VOLUME_ID,
body=data)
# Test for long value
# Test for very long value
data = {"os-set_image_metadata": {
"metadata": {"key": "v" * 260}}
"metadata": {"key": "v" * 65550}}
}
req.body = jsonutils.dump_as_bytes(data)
self.assertRaises(exception.ValidationError,
self.controller.create, req, fake.VOLUME_ID,
body=data)
# Test for very long utf8 value
data = {"os-set_image_metadata": {
"metadata": {"key": "á" * 32775}}
}
req.body = jsonutils.dump_as_bytes(data)
self.assertRaises(exception.ValidationError,
self.controller.create, req, fake.VOLUME_ID,
body=data)
# Test a short unicode string that actually exceeds
# the allowed byte count
char4bytes = "\N{CJK UNIFIED IDEOGRAPH-29D98}"
str65536bytes = char4bytes * 16384
self.assertEqual(65536, len(str65536bytes.encode('utf-8')))
self.assertLess(len(str65536bytes), 65535)
body = {"os-set_image_metadata": {
"metadata": {"key": str65536bytes}}
}
req.body = jsonutils.dump_as_bytes(body)
self.assertRaises(exception.ValidationError,
self.controller.create, req, fake.VOLUME_ID,
body=data)
# Test for empty key.
data = {"os-set_image_metadata": {
"metadata": {"": "value1"}}

View File

@ -0,0 +1,8 @@
---
fixes:
- |
`Bug #1988942 <https://bugs.launchpad.net/cinder/+bug/1988942>`_: Increased
size of volume image metadata values accepted by the Block Storage API.
Volume image metadata values were limited to 255 characters but Glance
allows up to 65535 bytes. This change does not affect the database
tables which already allow up to 65535 bytes for image metadata values.