summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2015-01-27 21:25:28 +0000
committerGerrit Code Review <review@openstack.org>2015-01-27 21:25:28 +0000
commitf17e36e25dcc7f134d72cb5bbf32babfd3656823 (patch)
treeb8fc1f246c71a010d9cf9afaf3683d0e4715e5b9
parent681a8edfcbbdf399a18e5eaba395210973b1a293 (diff)
parentaf3af7755b31dad1f8efa6260a4d6b31e136ad4a (diff)
downloadnova-f17e36e25dcc7f134d72cb5bbf32babfd3656823.tar.gz
Merge "Fixes Hyper-V boot from volume live migration" into stable/juno
-rw-r--r--nova/tests/virt/hyperv/test_imagecache.py119
-rw-r--r--nova/virt/hyperv/imagecache.py6
-rw-r--r--nova/virt/hyperv/livemigrationops.py2
3 files changed, 123 insertions, 4 deletions
diff --git a/nova/tests/virt/hyperv/test_imagecache.py b/nova/tests/virt/hyperv/test_imagecache.py
new file mode 100644
index 0000000000..19ee889c86
--- /dev/null
+++ b/nova/tests/virt/hyperv/test_imagecache.py
@@ -0,0 +1,119 @@
+# Copyright 2014 Cloudbase Solutions Srl
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import os
+
+import mock
+from oslo.config import cfg
+
+from nova import exception
+from nova import test
+from nova.tests import fake_instance
+from nova.virt.hyperv import constants
+from nova.virt.hyperv import imagecache
+
+CONF = cfg.CONF
+
+
+class ImageCacheTestCase(test.NoDBTestCase):
+ """Unit tests for the Hyper-V ImageCache class."""
+
+ FAKE_BASE_DIR = 'fake/base/dir'
+ FAKE_FORMAT = 'fake_format'
+ FAKE_IMAGE_REF = 'fake_image_ref'
+
+ def setUp(self):
+ super(ImageCacheTestCase, self).setUp()
+
+ self.context = 'fake-context'
+ self.instance = fake_instance.fake_instance_obj(self.context)
+
+ # utilsfactory will check the host OS version via get_hostutils,
+ # in order to return the proper Utils Class, so it must be mocked.
+ patched_func = mock.patch.object(imagecache.utilsfactory,
+ "get_hostutils")
+ patched_get_pathutils = mock.patch.object(imagecache.utilsfactory,
+ "get_pathutils")
+ patched_func.start()
+ patched_get_pathutils.start()
+ self.addCleanup(patched_func.stop)
+ self.addCleanup(patched_get_pathutils.stop)
+
+ self.imagecache = imagecache.ImageCache()
+ self.imagecache._pathutils = mock.MagicMock()
+ self.imagecache._vhdutils = mock.MagicMock()
+
+ def _prepare_get_cached_image(self, path_exists, use_cow):
+ self.instance.image_ref = self.FAKE_IMAGE_REF
+ self.imagecache._pathutils.get_base_vhd_dir.return_value = (
+ self.FAKE_BASE_DIR)
+ self.imagecache._pathutils.exists.return_value = path_exists
+ self.imagecache._vhdutils.get_vhd_format.return_value = (
+ constants.DISK_FORMAT_VHD)
+
+ CONF.set_override('use_cow_images', use_cow)
+
+ expected_path = os.path.join(self.FAKE_BASE_DIR,
+ self.FAKE_IMAGE_REF)
+ expected_vhd_path = "%s.%s" % (expected_path,
+ constants.DISK_FORMAT_VHD.lower())
+ return (expected_path, expected_vhd_path)
+
+ @mock.patch.object(imagecache.images, 'fetch')
+ def test_get_cached_image_with_fetch(self, mock_fetch):
+ (expected_path,
+ expected_vhd_path) = self._prepare_get_cached_image(False, False)
+
+ result = self.imagecache.get_cached_image(self.context, self.instance)
+ self.assertEqual(expected_vhd_path, result)
+
+ mock_fetch.assert_called_once_with(self.context, self.FAKE_IMAGE_REF,
+ expected_path,
+ self.instance['user_id'],
+ self.instance['project_id'])
+ self.imagecache._vhdutils.get_vhd_format.assert_called_once_with(
+ expected_path)
+ self.imagecache._pathutils.rename.assert_called_once_with(
+ expected_path, expected_vhd_path)
+
+ @mock.patch.object(imagecache.images, 'fetch')
+ def test_get_cached_image_with_fetch_exception(self, mock_fetch):
+ (expected_path,
+ expected_vhd_path) = self._prepare_get_cached_image(False, False)
+
+ # path doesn't exist until fetched.
+ self.imagecache._pathutils.exists.side_effect = [False, False, True]
+ mock_fetch.side_effect = exception.InvalidImageRef(
+ image_href=self.FAKE_IMAGE_REF)
+
+ self.assertRaises(exception.InvalidImageRef,
+ self.imagecache.get_cached_image,
+ self.context, self.instance)
+
+ self.imagecache._pathutils.remove.assert_called_once_with(
+ expected_path)
+
+ @mock.patch.object(imagecache.ImageCache, '_resize_and_cache_vhd')
+ def test_get_cached_image_use_cow(self, mock_resize):
+ (expected_path,
+ expected_vhd_path) = self._prepare_get_cached_image(True, True)
+
+ expected_resized_vhd_path = expected_vhd_path + 'x'
+ mock_resize.return_value = expected_resized_vhd_path
+
+ result = self.imagecache.get_cached_image(self.context, self.instance)
+ self.assertEqual(expected_resized_vhd_path, result)
+
+ mock_resize.assert_called_once_with(self.instance, expected_vhd_path)
diff --git a/nova/virt/hyperv/imagecache.py b/nova/virt/hyperv/imagecache.py
index 88eacb14fd..99eb29e696 100644
--- a/nova/virt/hyperv/imagecache.py
+++ b/nova/virt/hyperv/imagecache.py
@@ -98,7 +98,7 @@ class ImageCache(object):
return resized_vhd_path
def get_cached_image(self, context, instance):
- image_id = instance['image_ref']
+ image_id = instance.image_ref
base_vhd_dir = self._pathutils.get_base_vhd_dir()
base_vhd_path = os.path.join(base_vhd_dir, image_id)
@@ -115,8 +115,8 @@ class ImageCache(object):
if not vhd_path:
try:
images.fetch(context, image_id, base_vhd_path,
- instance['user_id'],
- instance['project_id'])
+ instance.user_id,
+ instance.project_id)
format_ext = self._vhdutils.get_vhd_format(base_vhd_path)
vhd_path = base_vhd_path + '.' + format_ext.lower()
diff --git a/nova/virt/hyperv/livemigrationops.py b/nova/virt/hyperv/livemigrationops.py
index f41c19d009..5a70876328 100644
--- a/nova/virt/hyperv/livemigrationops.py
+++ b/nova/virt/hyperv/livemigrationops.py
@@ -89,7 +89,7 @@ class LiveMigrationOps(object):
if CONF.use_cow_images:
boot_from_volume = self._volumeops.ebs_root_in_block_devices(
block_device_info)
- if not boot_from_volume:
+ if not boot_from_volume and instance.image_ref:
self._imagecache.get_cached_image(context, instance)
self._volumeops.login_storage_targets(block_device_info)