summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIury Gregory Melo Ferreira <iurygregory@gmail.com>2018-11-08 15:26:13 +0100
committerIury Gregory Melo Ferreira <iurygregory@gmail.com>2018-11-18 00:42:17 +0000
commit6ff4419680e6c089f6405f0f39cc7e7290fa9394 (patch)
tree50d8a48552d4e11ab677d26fd3a0e53f8c15175c
parent2c3bdff5ec617b83f37e1f98ed15293531ada9c5 (diff)
downloadironic-6ff4419680e6c089f6405f0f39cc7e7290fa9394.tar.gz
Improve logs when hard linking images fails
When hard linking images fail in ironic the logs doesn't have enough related path information to resolve the underlying cause of the exception. Change-Id: I3331c4eca2deb9383f448f1efa93cbef53019f9c Story: #2004303 Task: #27863 (cherry picked from commit 46a5899543bce73e1d40f6f363031f9ac1a472e8)
-rw-r--r--ironic/drivers/modules/image_cache.py11
-rw-r--r--ironic/tests/unit/drivers/modules/test_image_cache.py12
-rw-r--r--releasenotes/notes/invalid_cross_device_link-7ecf3543a8ada09f.yaml5
3 files changed, 28 insertions, 0 deletions
diff --git a/ironic/drivers/modules/image_cache.py b/ironic/drivers/modules/image_cache.py
index 76b55d51d..10f73253c 100644
--- a/ironic/drivers/modules/image_cache.py
+++ b/ironic/drivers/modules/image_cache.py
@@ -30,6 +30,7 @@ import six
from ironic.common import exception
from ironic.common.glance_service import service_utils
+from ironic.common.i18n import _
from ironic.common import image_service
from ironic.common import images
from ironic.common import utils
@@ -148,6 +149,9 @@ class ImageCache(object):
:param ctx: context
:param force_raw: boolean value, whether to convert the image to raw
format
+ :raise ImageDownloadFailed: when the image cache and the image HTTP or
+ TFTP location are on different file system,
+ causing hard link to fail.
"""
# TODO(ghe): timeout and retry for downloads
# TODO(ghe): logging when image cannot be created
@@ -160,6 +164,13 @@ class ImageCache(object):
# will have link count >1 at any moment, so won't be cleaned up
os.link(tmp_path, master_path)
os.link(master_path, dest_path)
+ except OSError as exc:
+ msg = (_("Could not link image %(img_href)s from %(src_path)s "
+ "to %(dst_path)s, error: %(exc)s") %
+ {'img_href': href, 'src_path': master_path,
+ 'dst_path': dest_path, 'exc': exc})
+ LOG.error(msg)
+ raise exception.ImageDownloadFailed(msg)
finally:
utils.rmtree_without_raise(tmp_dir)
diff --git a/ironic/tests/unit/drivers/modules/test_image_cache.py b/ironic/tests/unit/drivers/modules/test_image_cache.py
index b50d3fe40..5bd4c8d33 100644
--- a/ironic/tests/unit/drivers/modules/test_image_cache.py
+++ b/ironic/tests/unit/drivers/modules/test_image_cache.py
@@ -174,6 +174,18 @@ class TestImageCacheFetch(base.TestCase):
with open(self.dest_path) as fp:
self.assertEqual("TEST", fp.read())
+ @mock.patch.object(image_cache, '_fetch', autospec=True)
+ @mock.patch.object(image_cache, 'LOG', autospec=True)
+ @mock.patch.object(os, 'link', autospec=True)
+ def test__download_image_linkfail(self, mock_link, mock_log, mock_fetch):
+ mock_link.side_effect = [None, OSError]
+ self.assertRaises(exception.ImageDownloadFailed,
+ self.cache._download_image,
+ self.uuid, self.master_path, self.dest_path)
+ self.assertTrue(mock_fetch.called)
+ self.assertEqual(2, mock_link.call_count)
+ self.assertTrue(mock_log.error.called)
+
@mock.patch.object(os, 'unlink', autospec=True)
class TestUpdateImages(base.TestCase):
diff --git a/releasenotes/notes/invalid_cross_device_link-7ecf3543a8ada09f.yaml b/releasenotes/notes/invalid_cross_device_link-7ecf3543a8ada09f.yaml
new file mode 100644
index 000000000..d9e4cebbe
--- /dev/null
+++ b/releasenotes/notes/invalid_cross_device_link-7ecf3543a8ada09f.yaml
@@ -0,0 +1,5 @@
+---
+fixes:
+ - |
+ Properly reports an error when the image cache and the image HTTP or TFTP
+ location are on different file system, causing hard link to fail.