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:
parent
fb083138eb
commit
43bca185fe
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user