diff options
author | Dmitry Tantsur <divius.inside@gmail.com> | 2018-01-04 16:47:20 +0100 |
---|---|---|
committer | Dmitry Tantsur <divius.inside@gmail.com> | 2018-02-07 13:45:55 +0100 |
commit | 70039cbe607195f66872d8640976c13284f75b79 (patch) | |
tree | 9e72b2273f7f316fc35ef711109210a0fbe19881 | |
parent | bf8cb05aa4fcdb3b8c115fda6139d464fc94c014 (diff) | |
download | ironic-70039cbe607195f66872d8640976c13284f75b79.tar.gz |
Handle case when a glance image contains no data
In my experience, it happens when Swift storage backing Glance was
purged, but it can probably also happen if an image never had data
at all. This patch raises a correct exception instead of TypeError.
Switch relevant unit tests to Glance V2, as V1 is long deprecated.
Change-Id: I75e5ae7f46ce3a1506ed6108ff05df3083fd5084
Closes-Bug: #1741223
-rw-r--r-- | ironic/common/glance_service/base_image_service.py | 8 | ||||
-rw-r--r-- | ironic/tests/unit/common/test_glance_service.py | 15 | ||||
-rw-r--r-- | ironic/tests/unit/stubs.py | 12 | ||||
-rw-r--r-- | releasenotes/notes/image-no-data-c281f638d3dedfb2.yaml | 6 |
4 files changed, 38 insertions, 3 deletions
diff --git a/ironic/common/glance_service/base_image_service.py b/ironic/common/glance_service/base_image_service.py index 1768b2a11..85aae5734 100644 --- a/ironic/common/glance_service/base_image_service.py +++ b/ironic/common/glance_service/base_image_service.py @@ -217,6 +217,14 @@ class BaseImageService(object): return image_chunks = self.call(method, image_id) + # NOTE(dtantsur): when using Glance V2, image_chunks is a wrapper + # around real data, so we have to check the wrapped data for None. + # Glance V1 returns HTTP 404 in this case, so no need to fix it. + # TODO(dtantsur): remove the hasattr check when we no longer support + # Glance V1. + if hasattr(image_chunks, 'wrapped') and image_chunks.wrapped is None: + raise exception.ImageDownloadFailed( + image_href=image_href, reason=_('image contains no data.')) if data is None: return image_chunks diff --git a/ironic/tests/unit/common/test_glance_service.py b/ironic/tests/unit/common/test_glance_service.py index 7e135fb40..71c9846fc 100644 --- a/ironic/tests/unit/common/test_glance_service.py +++ b/ironic/tests/unit/common/test_glance_service.py @@ -92,11 +92,11 @@ class TestGlanceImageService(base.TestCase): def setUp(self): super(TestGlanceImageService, self).setUp() - client = stubs.StubGlanceClient() + self.client = stubs.StubGlanceClient() self.context = context.RequestContext(auth_token=True) self.context.user_id = 'fake' self.context.project_id = 'fake' - self.service = service.GlanceImageService(client, 1, self.context) + self.service = service.GlanceImageService(self.client, 2, self.context) self.config(glance_api_servers=['http://localhost'], group='glance') self.config(auth_strategy='keystone', group='glance') @@ -203,6 +203,17 @@ class TestGlanceImageService(base.TestCase): stub_service.download(image_id, writer) self.assertTrue(mock_sleep.called) + def test_download_no_data(self): + self.client.fake_wrapped = None + image_id = uuidutils.generate_uuid() + + image = self._make_datetime_fixture() + with mock.patch.object(self.client, 'get', return_value=image, + autospec=True): + self.assertRaisesRegex(exception.ImageDownloadFailed, + 'image contains no data', + self.service.download, image_id) + @mock.patch('sendfile.sendfile', autospec=True) @mock.patch('os.path.getsize', autospec=True) @mock.patch('%s.open' % __name__, new=mock.mock_open(), create=True) diff --git a/ironic/tests/unit/stubs.py b/ironic/tests/unit/stubs.py index d639ad95d..ba66e15f2 100644 --- a/ironic/tests/unit/stubs.py +++ b/ironic/tests/unit/stubs.py @@ -18,8 +18,18 @@ from glanceclient import exc as glance_exc NOW_GLANCE_FORMAT = "2010-10-11T10:30:22" +class _GlanceWrapper(object): + def __init__(self, wrapped): + self.wrapped = wrapped + + def __iter__(self): + return iter(()) + + class StubGlanceClient(object): + fake_wrapped = object() + def __init__(self, images=None): self._images = [] _images = images or [] @@ -38,7 +48,7 @@ class StubGlanceClient(object): def data(self, image_id): self.get(image_id) - return [] + return _GlanceWrapper(self.fake_wrapped) class FakeImage(object): diff --git a/releasenotes/notes/image-no-data-c281f638d3dedfb2.yaml b/releasenotes/notes/image-no-data-c281f638d3dedfb2.yaml new file mode 100644 index 000000000..66e1165b1 --- /dev/null +++ b/releasenotes/notes/image-no-data-c281f638d3dedfb2.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fails deployment with the correct error message in a node's ``last_error`` + field if an image from the Image service doesn't contain any data. + See `bug 1741223 <https://bugs.launchpad.net/bugs/1741223>`_ for details. |