diff options
author | Jenkins <jenkins@review.openstack.org> | 2015-01-23 16:31:28 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2015-01-23 16:31:28 +0000 |
commit | 340e30f347dbd86469f300370500ebb0d19399f8 (patch) | |
tree | 12d45cd7b78dd190d9d66051287cc540877888ff | |
parent | cf70dbff33b1d74a72cbd8f3d958c67bff105d43 (diff) | |
parent | c2b89f93a2ae25faeb18e1fcd93249bcf29ebc2e (diff) | |
download | ironic-340e30f347dbd86469f300370500ebb0d19399f8.tar.gz |
Merge "Ensure that image link points to the correct image" into stable/juno
-rw-r--r-- | ironic/drivers/modules/image_cache.py | 17 | ||||
-rw-r--r-- | ironic/tests/drivers/test_image_cache.py | 39 |
2 files changed, 48 insertions, 8 deletions
diff --git a/ironic/drivers/modules/image_cache.py b/ironic/drivers/modules/image_cache.py index 2765c18c0..e50c602d1 100644 --- a/ironic/drivers/modules/image_cache.py +++ b/ironic/drivers/modules/image_cache.py @@ -104,11 +104,18 @@ class ImageCache(object): # TODO(dtantsur): lock expiration time with lockutils.lock(img_download_lock_name, 'ironic-'): if os.path.exists(dest_path): - LOG.debug("Destination %(dest)s already exists for " - "image %(uuid)s" % - {'uuid': uuid, - 'dest': dest_path}) - return + # NOTE(vdrok): After rebuild requested image can change, so we + # should ensure that dest_path and master_path (if exists) are + # pointing to the same file + if (os.path.exists(master_path) and + (os.stat(dest_path).st_ino == + os.stat(master_path).st_ino)): + LOG.debug("Destination %(dest)s already exists for " + "image %(uuid)s" % + {'uuid': uuid, + 'dest': dest_path}) + return + os.unlink(dest_path) try: # NOTE(dtantsur): ensure we're not in the middle of clean up diff --git a/ironic/tests/drivers/test_image_cache.py b/ironic/tests/drivers/test_image_cache.py index 0849b8285..0991b48fc 100644 --- a/ironic/tests/drivers/test_image_cache.py +++ b/ironic/tests/drivers/test_image_cache.py @@ -56,16 +56,49 @@ class TestImageCacheFetch(base.TestCase): None, 'uuid', self.dest_path, None) self.assertFalse(mock_clean_up.called) + @mock.patch.object(os, 'unlink') @mock.patch.object(image_cache.ImageCache, 'clean_up') @mock.patch.object(image_cache.ImageCache, '_download_image') - def test_fetch_image_dest_exists(self, mock_download, mock_clean_up, - mock_fetch_to_raw): + def test_fetch_image_dest_and_master_exist_uptodate(self, mock_download, + mock_clean_up, mock_unlink, mock_fetch): + touch(self.master_path) + os.link(self.master_path, self.dest_path) + self.cache.fetch_image(self.uuid, self.dest_path) + self.assertFalse(mock_unlink.called) + self.assertFalse(mock_download.called) + self.assertFalse(mock_fetch.called) + self.assertFalse(mock_clean_up.called) + + @mock.patch.object(image_cache.ImageCache, 'clean_up') + @mock.patch.object(image_cache.ImageCache, '_download_image') + def test_fetch_image_dest_and_master_exist_outdated(self, mock_download, + mock_clean_up, mock_fetch): + touch(self.master_path) touch(self.dest_path) + self.assertNotEqual(os.stat(self.dest_path).st_ino, + os.stat(self.master_path).st_ino) self.cache.fetch_image(self.uuid, self.dest_path) self.assertFalse(mock_download.called) - self.assertFalse(mock_fetch_to_raw.called) + self.assertFalse(mock_fetch.called) + self.assertTrue(os.path.isfile(self.dest_path)) + self.assertEqual(os.stat(self.dest_path).st_ino, + os.stat(self.master_path).st_ino) self.assertFalse(mock_clean_up.called) + @mock.patch.object(os, 'unlink') + @mock.patch.object(image_cache.ImageCache, 'clean_up') + @mock.patch.object(image_cache.ImageCache, '_download_image') + def test_fetch_image_only_dest_exists(self, mock_download, + mock_clean_up, mock_unlink, mock_fetch): + touch(self.dest_path) + self.cache.fetch_image(self.uuid, self.dest_path) + mock_unlink.assert_called_once_with(self.dest_path) + self.assertFalse(mock_fetch.called) + mock_download.assert_called_once_with( + self.uuid, self.master_path, self.dest_path, + ctx=None) + self.assertTrue(mock_clean_up.called) + @mock.patch.object(image_cache.ImageCache, 'clean_up') @mock.patch.object(image_cache.ImageCache, '_download_image') def test_fetch_image_master_exists(self, mock_download, mock_clean_up, |