Set image size to None after removing all locations

Based on current design, the image size should be updated to
None if there is no location assocaited with the image. This
patch fixes this issue and introduces some related changes.

Closes-Bug: #1263729

Change-Id: I893468f1dc320ea9434f07c3a32f978cd5941b33
This commit is contained in:
Fei Long Wang 2014-01-03 11:01:16 +08:00
parent b512b3c321
commit a8ef64c4ec
6 changed files with 40 additions and 11 deletions

View File

@ -136,7 +136,10 @@ class Image(object):
else:
msg = _('Properties %s must be set prior to saving data.')
raise ValueError(msg % ', '.join(missing))
# NOTE(flwang): Image size should be cleared as long as the image
# status is updated to 'queued'
if status == 'queued':
self.size = None
self._status = status
@property

View File

@ -51,8 +51,12 @@ def _calc_required_size(context, image, locations):
required_size = image.size * len(locations)
else:
for location in locations:
size_from_backend = glance.store.get_size_from_backend(
context, location['url'])
size_from_backend = None
try:
size_from_backend = glance.store.get_size_from_backend(
context, location['url'])
except (exception.UnknownScheme, exception.NotFound):
pass
if size_from_backend:
required_size = size_from_backend * len(locations)
break

View File

@ -392,6 +392,19 @@ class TestImages(functional.FunctionalTest):
response = requests.patch(path, headers=headers, data=data)
self.assertEqual(200, response.status_code, response.text)
# Remove all locations of the image then the image size shouldn't be
# able to access
path = self._url('/v2/images/%s' % image2_id)
media_type = 'application/openstack-images-v2.1-json-patch'
headers = self._headers({'content-type': media_type})
doc = [{'op': 'replace', 'path': '/locations', 'value': []}]
data = jsonutils.dumps(doc)
response = requests.patch(path, headers=headers, data=data)
self.assertEqual(200, response.status_code, response.text)
image = jsonutils.loads(response.text)
self.assertTrue('size' not in image)
self.assertEqual('queued', image['status'])
# Deletion should work. Deleting image-1
path = self._url('/v2/images/%s' % image_id)
response = requests.delete(path, headers=self._headers())

View File

@ -76,10 +76,6 @@ class FakeImage(object):
self.size = self. size + len(d)
def fake_get_size_from_backend(context, uri):
return 1
class TestImageQuota(test_utils.BaseTestCase):
def setUp(self):
super(TestImageQuota, self).setUp()
@ -250,7 +246,7 @@ class TestImageQuota(test_utils.BaseTestCase):
self.assertIsNone(image.size)
self.stubs.Set(glance.store, 'get_size_from_backend',
fake_get_size_from_backend)
unit_test_utils.fake_get_size_from_backend)
image.locations.append({'url': 'file:///fake.img.tar.gz',
'metadata': {}})
self.assertIn({'url': 'file:///fake.img.tar.gz', 'metadata': {}},
@ -265,7 +261,7 @@ class TestImageQuota(test_utils.BaseTestCase):
self.assertIsNone(image.size)
self.stubs.Set(glance.store, 'get_size_from_backend',
fake_get_size_from_backend)
unit_test_utils.fake_get_size_from_backend)
image.locations.insert(0,
{'url': 'file:///fake.img.tar.gz',
'metadata': {}})
@ -281,7 +277,7 @@ class TestImageQuota(test_utils.BaseTestCase):
self.assertIsNone(image.size)
self.stubs.Set(glance.store, 'get_size_from_backend',
fake_get_size_from_backend)
unit_test_utils.fake_get_size_from_backend)
image.locations = [{'url': 'file:///fake.img.tar.gz', 'metadata': {}}]
self.assertEqual([{'url': 'file:///fake.img.tar.gz', 'metadata': {}}],
image.locations)
@ -295,7 +291,7 @@ class TestImageQuota(test_utils.BaseTestCase):
self.assertIsNone(image.size)
self.stubs.Set(glance.store, 'get_size_from_backend',
fake_get_size_from_backend)
unit_test_utils.fake_get_size_from_backend)
image.locations += [{'url': 'file:///fake.img.tar.gz', 'metadata': {}}]
self.assertIn({'url': 'file:///fake.img.tar.gz', 'metadata': {}},
image.locations)

View File

@ -55,6 +55,10 @@ def get_fake_request(path='', method='POST', is_admin=False, user=USER1,
return req
def fake_get_size_from_backend(context, uri):
return 1
class FakeDB(object):
def __init__(self):

View File

@ -1186,12 +1186,15 @@ class TestImagesController(base.IsolatedUnitTest):
request, UUID1, changes)
def test_update_replace_locations(self):
self.stubs.Set(glance.store, 'get_size_from_backend',
unit_test_utils.fake_get_size_from_backend)
request = unit_test_utils.get_fake_request()
changes = [{'op': 'replace', 'path': ['locations'], 'value': []}]
output = self.controller.update(request, UUID1, changes)
self.assertEqual(output.image_id, UUID1)
self.assertEqual(len(output.locations), 0)
self.assertEqual(output.status, 'queued')
self.assertEqual(output.size, None)
new_location = {'url': '%s/fake_location' % BASE_URI, 'metadata': {}}
changes = [{'op': 'replace', 'path': ['locations'],
@ -1450,6 +1453,8 @@ class TestImagesController(base.IsolatedUnitTest):
as long as the image has fewer than the limited number of image
locations after the transaction.
"""
self.stubs.Set(glance.store, 'get_size_from_backend',
unit_test_utils.fake_get_size_from_backend)
self.config(show_multiple_locations=True)
request = unit_test_utils.get_fake_request()
@ -1510,12 +1515,16 @@ class TestImagesController(base.IsolatedUnitTest):
self.controller.update, request, UUID1, changes)
def test_update_remove_location(self):
self.stubs.Set(glance.store, 'get_size_from_backend',
unit_test_utils.fake_get_size_from_backend)
request = unit_test_utils.get_fake_request()
changes = [{'op': 'remove', 'path': ['locations', '1']}]
output = self.controller.update(request, UUID1, changes)
self.assertEqual(output.image_id, UUID1)
self.assertEqual(len(output.locations), 0)
self.assertTrue(output.status == 'queued')
self.assertEqual(output.size, None)
new_location = {'url': '%s/fake_location' % BASE_URI, 'metadata': {}}
changes = [{'op': 'add', 'path': ['locations', '-'],