From a53f14f96804db4e78ad8971d54844ee5f69af65 Mon Sep 17 00:00:00 2001 From: Eric Harney Date: Mon, 3 Oct 2016 14:09:26 -0400 Subject: [PATCH] Error message for image conversion failure When image conversion fails due to space constraints on image_conversion_dir, log a straightforward error message indicating this is the case: "No space left in image_conversion_dir path (/var/lib/cinder/conversion) while fetching image 6261d1ec-2a15-4a68-977a-ea22ff342b74." Change-Id: I4c4ca1bdcbb86739613d64997bbc78e3a72d570a --- cinder/image/image_utils.py | 17 +++++++++++++++-- cinder/tests/unit/test_image_utils.py | 26 ++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/cinder/image/image_utils.py b/cinder/image/image_utils.py index df6f4af1f45..fb54a27a7e6 100644 --- a/cinder/image/image_utils.py +++ b/cinder/image/image_utils.py @@ -25,6 +25,7 @@ we should look at maybe pushing this up to Oslo import contextlib +import errno import math import os import re @@ -33,13 +34,14 @@ import tempfile from oslo_concurrency import processutils from oslo_config import cfg from oslo_log import log as logging +from oslo_utils import excutils from oslo_utils import fileutils from oslo_utils import imageutils from oslo_utils import timeutils from oslo_utils import units from cinder import exception -from cinder.i18n import _, _LI, _LW +from cinder.i18n import _, _LE, _LI, _LW from cinder import utils from cinder.volume import throttling from cinder.volume import utils as volume_utils @@ -187,7 +189,18 @@ def fetch(context, image_service, image_id, path, _user_id, _project_id): start_time = timeutils.utcnow() with fileutils.remove_path_on_error(path): with open(path, "wb") as image_file: - image_service.download(context, image_id, image_file) + try: + image_service.download(context, image_id, image_file) + except IOError as e: + with excutils.save_and_reraise_exception(): + if e.errno == errno.ENOSPC: + # TODO(eharney): Fire an async error message for this + LOG.error(_LE("No space left in image_conversion_dir " + "path (%(path)s) while fetching " + "image %(image)s."), + {'path': os.path.dirname(path), + 'image': image_id}) + duration = timeutils.delta_seconds(start_time, timeutils.utcnow()) # NOTE(jdg): use a default of 1, mostly for unit test, but in diff --git a/cinder/tests/unit/test_image_utils.py b/cinder/tests/unit/test_image_utils.py index a5143e9869c..e6a182f0cd7 100644 --- a/cinder/tests/unit/test_image_utils.py +++ b/cinder/tests/unit/test_image_utils.py @@ -15,6 +15,7 @@ # under the License. """Unit tests for image utils.""" +import errno import math import mock @@ -24,6 +25,7 @@ from oslo_utils import units from cinder import exception from cinder.image import image_utils from cinder import test +from cinder.tests import fixtures from cinder.tests.unit import fake_constants as fake from cinder.volume import throttling @@ -275,6 +277,30 @@ class TestFetch(test.TestCase): (mock_fileutils.remove_path_on_error.return_value.__exit__ .assert_called_once_with(None, None, None)) + def test_fetch_enospc(self): + stdlog = self.useFixture(fixtures.StandardLogging()) + + context = mock.sentinel.context + image_service = mock.Mock() + e = IOError() + e.errno = errno.ENOSPC + image_service.download.side_effect = e + image_id = mock.sentinel.image_id + path = '/test_path' + _user_id = mock.sentinel._user_id + _project_id = mock.sentinel._project_id + + with mock.patch('cinder.image.image_utils.open', + new=mock.mock_open(), create=True): + self.assertRaises(IOError, + image_utils.fetch, + context, image_service, image_id, path, + _user_id, _project_id) + error_message = ('No space left in image_conversion_dir path ' + '(/) while fetching image %s.' % image_id) + + self.assertTrue(error_message in stdlog.logger.output) + class TestVerifyImage(test.TestCase): @mock.patch('cinder.image.image_utils.qemu_img_info')