diff --git a/glance/api/v2/images.py b/glance/api/v2/images.py index 84d746e118..fcfb35e644 100644 --- a/glance/api/v2/images.py +++ b/glance/api/v2/images.py @@ -14,6 +14,7 @@ # under the License. import hashlib +import os import re import glance_store @@ -336,11 +337,25 @@ class ImagesController(object): image = image_repo.get(image_id) if image.status == 'uploading': - file_path = str(CONF.node_staging_uri + '/' + image.image_id) - if CONF.enabled_backends: - self.store_api.delete(file_path, None) + file_path = str( + CONF.node_staging_uri + '/' + image.image_id)[7:] + if os.path.exists(file_path): + try: + LOG.debug( + "After upload to the backend, deleting staged " + "image data from %(fn)s", {'fn': file_path}) + os.unlink(file_path) + except OSError as e: + LOG.error( + "After upload to backend, deletion of staged " + "image data from %(fn)s has failed because " + "[Errno %(en)d]", {'fn': file_path, + 'en': e.errno}) else: - self.store_api.delete_from_backend(file_path) + LOG.warning(_( + "After upload to backend, deletion of staged " + "image data has failed because " + "it cannot be found at %(fn)s"), {'fn': file_path}) image.delete() image_repo.remove(image) diff --git a/glance/tests/unit/v2/test_images_resource.py b/glance/tests/unit/v2/test_images_resource.py index e201079718..cf24cfb007 100644 --- a/glance/tests/unit/v2/test_images_resource.py +++ b/glance/tests/unit/v2/test_images_resource.py @@ -16,6 +16,7 @@ import datetime import eventlet import hashlib +import os import uuid import glance_store as store @@ -2643,17 +2644,42 @@ class TestImagesController(base.IsolatedUnitTest): request, UUID1) def test_delete_uploading_status_image(self): - """Ensure status of uploading image is updated (LP bug #1733289)""" + """Ensure uploading image is deleted (LP bug #1733289) + Ensure image stuck in uploading state is deleted (LP bug #1836140) + """ request = unit_test_utils.get_fake_request(is_admin=True) image = self.db.image_create(request.context, {'status': 'uploading'}) image_id = image['id'] - with mock.patch.object(self.store, - 'delete_from_backend') as mock_store: - self.controller.delete(request, image_id) + with mock.patch.object(os.path, 'exists') as mock_exists: + mock_exists.return_value = True + with mock.patch.object(os, "unlink") as mock_unlik: + self.controller.delete(request, image_id) - # Ensure delete_from_backend is called - self.assertEqual(1, mock_store.call_count) + self.assertEqual(1, mock_exists.call_count) + self.assertEqual(1, mock_unlik.call_count) + # Ensure that image is deleted + image = self.db.image_get(request.context, image_id, + force_show_deleted=True) + self.assertTrue(image['deleted']) + self.assertEqual('deleted', image['status']) + + def test_deletion_of_staging_data_failed(self): + """Ensure uploading image is deleted (LP bug #1733289) + Ensure image stuck in uploading state is deleted (LP bug #1836140) + """ + request = unit_test_utils.get_fake_request(is_admin=True) + image = self.db.image_create(request.context, {'status': 'uploading'}) + image_id = image['id'] + with mock.patch.object(os.path, 'exists') as mock_exists: + mock_exists.return_value = False + with mock.patch.object(os, "unlink") as mock_unlik: + self.controller.delete(request, image_id) + + self.assertEqual(1, mock_exists.call_count) + self.assertEqual(0, mock_unlik.call_count) + + # Ensure that image is deleted image = self.db.image_get(request.context, image_id, force_show_deleted=True) self.assertTrue(image['deleted'])