Update restrictions on allowed v2 image properties

The list of allowed and readonly image attributes has gotten out of
date, so this change updates those lists. This change also adds a
similar check to ensure certain special properties names are reserved as
they would conflict with existing database properties that are either
not presently exposed or exposed under a different name.

Change-Id: I56d6c938dd6a5353e15b3e5ef913fae5b4629d52
This commit is contained in:
Brian Waldon 2012-08-11 15:39:46 -07:00 committed by Mark Washenberger
parent 9b98df52fe
commit 60576a5bae
2 changed files with 94 additions and 57 deletions

View File

@ -162,11 +162,16 @@ class RequestDeserializer(wsgi.JSONRequestDeserializer):
except exception.InvalidObject as e:
raise webob.exc.HTTPBadRequest(explanation=unicode(e))
# Ensure all specified properties are allowed
self._check_readonly(body)
self._check_reserved(body)
# Create a dict of base image properties, with user- and deployer-
# defined properties contained in a 'properties' dictionary
image = {'properties': body}
for key in ['id', 'name', 'visibility', 'created_at', 'updated_at',
'tags', 'status']:
for key in ['checksum', 'created_at', 'container_format',
'disk_format', 'id', 'min_disk', 'min_ram', 'name', 'size',
'status', 'tags', 'updated_at', 'visibility']:
try:
image[key] = image['properties'].pop(key)
except KeyError:
@ -175,16 +180,24 @@ class RequestDeserializer(wsgi.JSONRequestDeserializer):
if 'visibility' in image:
image['is_public'] = image.pop('visibility') == 'public'
self._check_readonly(image)
return {'image': image}
@staticmethod
def _check_readonly(image):
for key in ['created_at', 'updated_at', 'status']:
for key in ['created_at', 'updated_at', 'status', 'checksum', 'size',
'direct_url', 'self', 'file', 'schema']:
if key in image:
msg = "Attribute \'%s\' is read-only." % key
raise webob.exc.HTTPForbidden(explanation=unicode(msg))
@staticmethod
def _check_reserved(image):
for key in ['owner', 'protected', 'is_public', 'location',
'deleted', 'deleted_at']:
if key in image:
msg = "Attribute \'%s\' is reserved." % key
raise webob.exc.HTTPForbidden(explanation=unicode(msg))
def create(self, request):
return self._parse_image(request)

View File

@ -338,81 +338,105 @@ class TestImagesDeserializer(test_utils.BaseTestCase):
super(TestImagesDeserializer, self).setUp()
self.deserializer = glance.api.v2.images.RequestDeserializer()
def test_create_with_id(self):
def test_create_minimal(self):
request = unit_test_utils.get_fake_request()
image_id = utils.generate_uuid()
request.body = json.dumps({'id': image_id})
request.body = json.dumps({})
output = self.deserializer.create(request)
expected = {'image': {'id': image_id, 'properties': {}}}
expected = {'image': {'properties': {}}}
self.assertEqual(expected, output)
def test_create_with_name(self):
def test_create_full(self):
request = unit_test_utils.get_fake_request()
request.body = json.dumps({'name': 'image-1'})
request.body = json.dumps({
'id': UUID3,
'name': 'image-1',
'visibility': 'public',
'tags': ['one', 'two'],
'container_format': 'ami',
'disk_format': 'ami',
'min_ram': 128,
'min_disk': 10,
'foo': 'bar',
})
output = self.deserializer.create(request)
expected = {'image': {'name': 'image-1', 'properties': {}}}
self.assertEqual(expected, output)
def test_create_public(self):
request = unit_test_utils.get_fake_request()
request.body = json.dumps({'visibility': 'public'})
output = self.deserializer.create(request)
expected = {'image': {'is_public': True, 'properties': {}}}
self.assertEqual(expected, output)
def test_create_private(self):
request = unit_test_utils.get_fake_request()
request.body = json.dumps({'visibility': 'private'})
output = self.deserializer.create(request)
expected = {'image': {'is_public': False, 'properties': {}}}
expected = {'image': {
'id': UUID3,
'name': 'image-1',
'is_public': True,
'tags': ['one', 'two'],
'container_format': 'ami',
'disk_format': 'ami',
'min_ram': 128,
'min_disk': 10,
'properties': {'foo': 'bar'},
}}
self.assertEqual(expected, output)
def test_create_readonly_attributes_forbidden(self):
for key in ['created_at', 'updated_at']:
bodies = [
{'created_at': ISOTIME},
{'updated_at': ISOTIME},
{'status': 'saving'},
{'direct_url': 'http://example.com'},
{'size': 10},
{'checksum': 'asdf'},
{'self': 'http://example.com'},
{'file': 'http://example.com'},
{'schema': 'http://example.com'},
]
for body in bodies:
request = unit_test_utils.get_fake_request()
request.body = json.dumps({key: ISOTIME})
request.body = json.dumps(body)
self.assertRaises(webob.exc.HTTPForbidden,
self.deserializer.update, request)
def test_create_status_attribute_forbidden(self):
request = unit_test_utils.get_fake_request()
request.body = json.dumps({'status': 'saving'})
self.assertRaises(webob.exc.HTTPForbidden,
self.deserializer.update, request)
def test_create_with_tags(self):
request = unit_test_utils.get_fake_request()
request.body = json.dumps({'tags': ['one', 'two']})
output = self.deserializer.create(request)
expected = {'image': {'tags': ['one', 'two'], 'properties': {}}}
self.assertEqual(expected, output)
self.deserializer.create, request)
def test_update(self):
request = unit_test_utils.get_fake_request()
request.body = json.dumps({'name': 'image-1', 'visibility': 'public'})
request.body = json.dumps({
'id': UUID3,
'name': 'image-1',
'visibility': 'public',
'tags': ['one', 'two'],
'container_format': 'ami',
'disk_format': 'ami',
'min_ram': 128,
'min_disk': 10,
'foo': 'bar',
})
output = self.deserializer.update(request)
expected = {
'image': {
'name': 'image-1',
'is_public': True,
'properties': {},
},
}
expected = {'image': {
'id': UUID3,
'name': 'image-1',
'is_public': True,
'tags': ['one', 'two'],
'container_format': 'ami',
'disk_format': 'ami',
'min_ram': 128,
'min_disk': 10,
'properties': {'foo': 'bar'},
}}
self.assertEqual(expected, output)
def test_update_readonly_attributes_forbidden(self):
for key in ['created_at', 'updated_at']:
bodies = [
{'created_at': ISOTIME},
{'updated_at': ISOTIME},
{'status': 'saving'},
{'direct_url': 'http://example.com'},
{'size': 10},
{'checksum': 'asdf'},
{'self': 'http://example.com'},
{'file': 'http://example.com'},
{'schema': 'http://example.com'},
]
for body in bodies:
request = unit_test_utils.get_fake_request()
request.body = json.dumps({key: ISOTIME})
request.body = json.dumps(body)
self.assertRaises(webob.exc.HTTPForbidden,
self.deserializer.update, request)
def test_update_status_attribute_forbidden(self):
request = unit_test_utils.get_fake_request()
request.body = json.dumps({'status': 'saving'})
self.assertRaises(webob.exc.HTTPForbidden,
self.deserializer.update, request)
def test_index(self):
marker = utils.generate_uuid()
path = '/images?limit=1&marker=%s' % marker