Close Glance image if downloading failed.

If downloding of Glance image failed we should
close iterator of image body.
Otherwise Glance is unable to delete the image.

Change-Id: I193df2fcbf2588c10be953eb4e9eef4609b6286f
Closes-Bug: 1948706
This commit is contained in:
Mitya_Eremeev 2021-11-11 18:52:11 +03:00
parent fb083138eb
commit 43bca185fe
2 changed files with 49 additions and 15 deletions

View File

@ -418,17 +418,17 @@ class GlanceImageServiceV2(object):
if data is None:
write_image = False
# Retrieve properties for verification of Glance image signature
verifier = self._get_verifier(context, image_id, trusted_certs)
# Exit early if we do not need write nor verify
if verifier is None and write_image is False:
if data is None:
return image_chunks
else:
return
try:
# Retrieve properties for verification of Glance image signature
verifier = self._get_verifier(context, image_id, trusted_certs)
# Exit early if we do not need write nor verify
if verifier is None and write_image is False:
if data is None:
return image_chunks
else:
return
for chunk in image_chunks:
if verifier:
verifier.update(chunk)
@ -462,6 +462,8 @@ class GlanceImageServiceV2(object):
data.flush()
self._safe_fsync(data)
data.close()
if isinstance(image_chunks, glance_utils.IterableWithLength):
image_chunks.iterable.close()
if data is None:
return image_chunks

View File

@ -16,12 +16,14 @@
import copy
import datetime
import io
from io import StringIO
import urllib.parse as urlparse
import cryptography
from cursive import exception as cursive_exception
import ddt
import glanceclient.common.utils
import glanceclient.exc
from glanceclient.v1 import images
from glanceclient.v2 import schemas
@ -687,8 +689,7 @@ class TestDownloadNoDirectUri(test.NoDBTestCase):
with testtools.ExpectedException(exception.ImageUnacceptable):
service.download(ctx, mock.sentinel.image_id)
@mock.patch('glanceclient.common.utils.IterableWithLength')
@mock.patch('os.path.getsize', return_value=1)
@mock.patch('os.path.getsize')
@mock.patch('builtins.open')
@mock.patch('nova.image.glance.LOG')
@mock.patch('nova.image.glance.GlanceImageServiceV2._get_verifier')
@ -696,7 +697,7 @@ class TestDownloadNoDirectUri(test.NoDBTestCase):
@mock.patch('nova.image.glance.GlanceImageServiceV2.show')
def test_download_direct_rbd_uri_v2(
self, show_mock, get_tran_mock, get_verifier_mock, log_mock,
open_mock, getsize_mock, iterable_with_length_mock):
open_mock, getsize_mock):
self.flags(enable_rbd_download=True, group='glance')
show_mock.return_value = {
'locations': [
@ -710,9 +711,13 @@ class TestDownloadNoDirectUri(test.NoDBTestCase):
get_tran_mock.return_value = tran_mod
client = mock.MagicMock()
ctx = mock.sentinel.ctx
image_content = ["rbd1", "rbd2"]
getsize_mock.return_value = len(image_content)
file_object = mock.MagicMock(spec=io.BytesIO)
file_object.__iter__.return_value = image_content
writer = mock.MagicMock()
writer.__enter__.return_value = file_object
open_mock.return_value = writer
iterable_with_length_mock.return_value = ["rbd1", "rbd2"]
service = glance.GlanceImageServiceV2(client)
verifier = mock.MagicMock()
@ -980,7 +985,7 @@ class TestDownloadSignatureVerification(test.NoDBTestCase):
service.download,
context=None, image_id=None,
data=None, dst_path=None)
mock_log.error.assert_called_once_with(mock.ANY, mock.ANY)
self.assertEqual(mock_log.error.call_count, 2)
@mock.patch('nova.image.glance.LOG')
@mock.patch('nova.image.glance.GlanceImageServiceV2.show')
@ -1038,6 +1043,33 @@ class TestDownloadSignatureVerification(test.NoDBTestCase):
mock_dest.truncate.assert_called_once_with(0)
self.assertTrue(mock_dest.close.called)
@mock.patch('builtins.open')
@mock.patch('cursive.signature_utils.get_verifier')
@mock.patch('nova.image.glance.GlanceImageServiceV2.show')
@mock.patch('nova.image.glance.GlanceImageServiceV2._safe_fsync')
def test_download_dst_path_with_invalid_signature_v2(
self, mock_fsync, mock_show, mock_get_verifier, mock_open):
glance_iterable = mock.MagicMock(spec=io.BytesIO)
glance_iterable.__iter__.return_value = self.fake_img_data
self.client.call.return_value = fake_glance_response(
glanceclient.common.utils.IterableWithLength(
iterable=glance_iterable, length=len(self.fake_img_data)))
service = glance.GlanceImageServiceV2(self.client)
mock_get_verifier.side_effect = \
cursive_exception.SignatureVerificationError
mock_dest = mock.MagicMock()
mock_open.return_value = mock_dest
mock_show.return_value = self.fake_img_props
fake_path = 'FAKE_PATH'
self.assertRaises(cursive_exception.SignatureVerificationError,
service.download,
context=None, image_id=None,
data=None, dst_path=fake_path)
mock_open.assert_called_once_with(fake_path, 'wb')
mock_fsync.assert_called_once_with(mock_dest)
mock_dest.close.assert_called()
glance_iterable.close.assert_called()
class TestDownloadCertificateValidation(test.NoDBTestCase):
"""Tests the download method of the GlanceImageServiceV2 when