Make image stage set image.size

When we stage an image, we know the image size, so we should set it.
Since the user may be streaming an image and did not declare the
expected size, this lets them confirm before they import. It also
provides us a value to count for the staging quota coming in a later
patch.

The bulk of this change is adjusting existing tests to validate the
size for all of our stage/import tests.

This follows the change to set the image size during conversion,
ensuring that we can set it during stage for non-conversion jobs,
and that the conversion code that re-sets it after changing the
image data and size continues to work.

Related to blueprint glance-unified-quotas

Change-Id: I93a9145df27594a0cc59828619a7d0573e58d4fc
This commit is contained in:
Dan Smith 2021-04-26 12:41:28 -07:00
parent 154ef3fe94
commit c290c4af5a
4 changed files with 39 additions and 11 deletions

View File

@ -344,9 +344,10 @@ class ImageDataController(object):
image.status = 'uploading'
image_repo.save(image, from_state='queued')
try:
staging_store.add(
uri, size, id, store_info = staging_store.add(
image_id, utils.LimitingReader(
utils.CooperativeReader(data), CONF.image_size_cap), 0)
image.size = size
except glance_store.Duplicate:
msg = _("The image %s has data on staging") % image_id
raise webob.exc.HTTPConflict(explanation=msg)

View File

@ -24,7 +24,7 @@ from six.moves import http_client as http
def verify_image_hashes_and_status(
test_obj, image_id, checksum=None, os_hash_value=None, status=None,
os_hash_algo='sha512'):
os_hash_algo='sha512', size=None):
"""Makes image-detail request and checks response.
:param test_obj: The test object; expected to have _url() and
@ -47,6 +47,7 @@ def verify_image_hashes_and_status(
image['os_hash_algo'])
test_obj.assertEqual(os_hash_value, image['os_hash_value'])
test_obj.assertEqual(status, image['status'])
test_obj.assertEqual(size, image['size'])
def wait_for_status(request_path, request_headers, status='active',

View File

@ -185,6 +185,7 @@ class TestImages(functional.FunctionalTest):
# Verify image is in uploading state, hashes are None
func_utils.verify_image_hashes_and_status(self, image_id,
size=len(image_data),
status='uploading')
# Import image to store
@ -215,6 +216,7 @@ class TestImages(functional.FunctionalTest):
image_id,
checksum=expect_c,
os_hash_value=expect_h,
size=len(image_data),
status='active')
# Ensure the size is updated to reflect the data uploaded
@ -358,6 +360,7 @@ class TestImages(functional.FunctionalTest):
image_id,
checksum=expect_c,
os_hash_value=expect_h,
size=len(r.content),
status='active')
# kill the local http server
@ -733,7 +736,8 @@ class TestImages(functional.FunctionalTest):
usedforsecurity=False).hexdigest())
expect_h = six.text_type(hashlib.sha512(image_data).hexdigest())
func_utils.verify_image_hashes_and_status(self, image_id, expect_c,
expect_h, 'active')
expect_h, 'active',
size=len(image_data))
# `disk_format` and `container_format` cannot
# be replaced when the image is active.
@ -762,7 +766,8 @@ class TestImages(functional.FunctionalTest):
response = requests.put(path, headers=headers, data='XXX')
self.assertEqual(http.CONFLICT, response.status_code)
func_utils.verify_image_hashes_and_status(self, image_id, expect_c,
expect_h, 'active')
expect_h, 'active',
size=len(image_data))
# Ensure the size is updated to reflect the data uploaded
path = self._url('/v2/images/%s' % image_id)
@ -961,7 +966,8 @@ class TestImages(functional.FunctionalTest):
# Verify image is in uploading state and checksum is None
func_utils.verify_image_hashes_and_status(self, image['id'],
status='uploading')
status='uploading',
size=raw_size)
# Import image to store
path = self._url('/v2/images/%s/import' % image['id'])
@ -1176,6 +1182,7 @@ class TestImages(functional.FunctionalTest):
image_id,
expect_c,
expect_h,
size=len(image_data),
status='active')
# Upload some image data to image-2
path = self._url('/v2/images/%s/file' % image2_id)
@ -1190,6 +1197,7 @@ class TestImages(functional.FunctionalTest):
image2_id,
expect_c,
expect_h,
size=len(image_data),
status='active')
# Hide image-1
path = self._url('/v2/images/%s' % image_id)
@ -4604,6 +4612,7 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
# Verify image is in uploading state and checksum is None
func_utils.verify_image_hashes_and_status(self, image_id,
size=len(image_data),
status='uploading')
# Import image to store
@ -4634,6 +4643,7 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
image_id,
checksum=expect_c,
os_hash_value=expect_h,
size=len(image_data),
status='active')
# Ensure the size is updated to reflect the data uploaded
@ -4767,6 +4777,7 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
# Verify image is in uploading state and checksum is None
func_utils.verify_image_hashes_and_status(self, image_id,
size=len(image_data),
status='uploading')
# Import image to file2 store (other than default backend)
@ -4798,6 +4809,7 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
image_id,
checksum=expect_c,
os_hash_value=expect_h,
size=len(image_data),
status='active')
# Ensure the size is updated to reflect the data uploaded
@ -4962,6 +4974,7 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
image_id,
checksum=expect_c,
os_hash_value=expect_h,
size=len(r.content),
status='active')
# kill the local http server
@ -5125,6 +5138,7 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
image_id,
checksum=expect_c,
os_hash_value=expect_h,
size=len(r.content),
status='active')
# kill the local http server
@ -5287,6 +5301,7 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
image_id,
checksum=expect_c,
os_hash_value=expect_h,
size=len(r.content),
status='active')
# kill the local http server
@ -5451,6 +5466,7 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
image_id,
checksum=expect_c,
os_hash_value=expect_h,
size=len(r.content),
status='active')
# kill the local http server
@ -5675,6 +5691,7 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
image_id,
checksum=expect_c,
os_hash_value=expect_h,
size=len(r.content),
status='active')
# kill the local http server
@ -5933,6 +5950,7 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
image_id,
checksum=expect_c,
os_hash_value=expect_h,
size=len(r.content),
status='active')
# kill the local http server
@ -6075,6 +6093,7 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
image_id,
checksum=expect_c,
os_hash_value=expect_h,
size=len(image_data),
status='active')
# Ensure image is created in default backend
@ -6249,6 +6268,7 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
image_id,
checksum=expect_c,
os_hash_value=expect_h,
size=len(image_data),
status='active')
# Ensure image is created in different backend
@ -6786,6 +6806,7 @@ class TestCopyImagePermissions(functional.MultipleBackendFunctionalTest):
image_id,
checksum=expect_c,
os_hash_value=expect_h,
size=len(r.content),
status='active')
# kill the local http server

View File

@ -459,10 +459,11 @@ class TestImagesController(base.StoreClearingUnitTest):
request = unit_test_utils.get_fake_request()
image = FakeImage(image_id=image_id)
self.image_repo.result = image
with mock.patch.object(filesystem.Store, 'add'):
with mock.patch.object(filesystem.Store, 'add') as mock_add:
mock_add.return_value = ('foo://bar', 4, 'ident', {})
self.controller.stage(request, image_id, 'YYYY', 4)
self.assertEqual('uploading', image.status)
self.assertEqual(0, image.size)
self.assertEqual(4, image.size)
def test_image_already_on_staging(self):
image_id = str(uuid.uuid4())
@ -470,10 +471,11 @@ class TestImagesController(base.StoreClearingUnitTest):
image = FakeImage(image_id=image_id)
self.image_repo.result = image
with mock.patch.object(filesystem.Store, 'add') as mock_store_add:
mock_store_add.return_value = ('foo://bar', 4, 'ident', {})
self.controller.stage(request, image_id, 'YYYY', 4)
self.assertEqual('uploading', image.status)
mock_store_add.side_effect = glance_store.Duplicate()
self.assertEqual(0, image.size)
self.assertEqual(4, image.size)
self.assertRaises(webob.exc.HTTPConflict, self.controller.stage,
request, image_id, 'YYYY', 4)
@ -553,9 +555,11 @@ class TestImagesController(base.StoreClearingUnitTest):
request = unit_test_utils.get_fake_request()
image = FakeImage(image_id=image_id)
self.image_repo.result = image
self.controller.stage(request, image_id, 'YYYY', 4)
with mock.patch.object(filesystem.Store, 'add') as mock_add:
mock_add.return_value = ('foo://bar', 4, 'ident', {})
self.controller.stage(request, image_id, 'YYYY', 4)
self.assertEqual('uploading', image.status)
self.assertEqual(0, image.size)
self.assertEqual(4, image.size)
# try staging again
mock_store_add.side_effect = exception.InvalidImageStatusTransition(
cur_status='uploading', new_status='uploading')
@ -567,7 +571,8 @@ class TestImagesController(base.StoreClearingUnitTest):
request = unit_test_utils.get_fake_request()
image = FakeImage(image_id=image_id)
self.image_repo.result = image
with mock.patch.object(filesystem.Store, 'add'):
with mock.patch.object(filesystem.Store, 'add') as mock_add:
mock_add.return_value = ('foo://bar', 4, 'ident', {})
self.controller.stage(request, image_id, 'YYYY', 4)
if expected_url is None:
self.assertNotIn('os_glance_stage_host', image.extra_properties)