From 1f26df24a63624545cfe67745af53623947a6d28 Mon Sep 17 00:00:00 2001 From: Lucian Petrut Date: Thu, 18 Sep 2014 11:55:56 +0300 Subject: [PATCH] Fixes differencing VHDX images issue on Hyper-V When using differencing vhdx images, one will be created pointing to the base image when a VM is spawned. This image will be created having the according flavor size. In this case, due to a Win32 API issue, the image is not generated properly. Simply creating the root image with no size specified and resizing it afterwards fixes the issue. Change-Id: I7bb46a63d4c2a06ed6f63c839461cbbc1abffa65 Closes-Bug: #1370531 --- nova/tests/unit/virt/hyperv/test_hypervapi.py | 14 ++----- nova/tests/unit/virt/hyperv/test_vhdutils.py | 8 ---- nova/virt/hyperv/vhdutils.py | 5 +-- nova/virt/hyperv/vhdutilsv2.py | 9 +++-- nova/virt/hyperv/vmops.py | 40 +++++++------------ 5 files changed, 26 insertions(+), 50 deletions(-) diff --git a/nova/tests/unit/virt/hyperv/test_hypervapi.py b/nova/tests/unit/virt/hyperv/test_hypervapi.py index 2495a07c36..69f3d23e5b 100644 --- a/nova/tests/unit/virt/hyperv/test_hypervapi.py +++ b/nova/tests/unit/virt/hyperv/test_hypervapi.py @@ -1105,20 +1105,14 @@ class HyperVAPITestCase(HyperVAPIBaseTestCase): 'Type': 2}) if cow: + vhdutils.VHDUtils.create_differencing_vhd(mox.IsA(str), + mox.IsA(str)) m = vhdutils.VHDUtils.get_vhd_format(mox.IsA(str)) m.AndReturn(vhd_format) - if vhd_format == constants.DISK_FORMAT_VHD: - vhdutils.VHDUtils.create_differencing_vhd(mox.IsA(str), - mox.IsA(str)) - else: - m = vhdutils.VHDUtils.get_internal_vhd_size_by_file_size( - mox.IsA(str), mox.IsA(object)) - m.AndReturn(1025) - vhdutils.VHDUtils.create_differencing_vhd(mox.IsA(str), - mox.IsA(str), - mox.IsA(int)) else: fake.PathUtils.copyfile(mox.IsA(str), mox.IsA(str)) + + if not (cow and vhd_format == constants.DISK_FORMAT_VHD): m = vhdutils.VHDUtils.get_internal_vhd_size_by_file_size( mox.IsA(str), mox.IsA(object)) m.AndReturn(1025) diff --git a/nova/tests/unit/virt/hyperv/test_vhdutils.py b/nova/tests/unit/virt/hyperv/test_vhdutils.py index e41353329a..5022b17f9a 100644 --- a/nova/tests/unit/virt/hyperv/test_vhdutils.py +++ b/nova/tests/unit/virt/hyperv/test_vhdutils.py @@ -64,14 +64,6 @@ class VHDUtilsTestCase(test.NoDBTestCase): Path=self._FAKE_VHD_PATH, ParentPath=self._FAKE_PARENT_PATH) - def test_create_differencing_vhd_with_new_size(self): - fake_new_size = 1024 - self.assertRaises(vmutils.HyperVException, - self._vhdutils.create_differencing_vhd, - self._FAKE_VHD_PATH, - self._FAKE_PARENT_PATH, - fake_new_size) - def test_get_internal_vhd_size_by_file_size_fixed(self): vhdutil = vhdutils.VHDUtils() root_vhd_size = 1 * 1024 ** 3 diff --git a/nova/virt/hyperv/vhdutils.py b/nova/virt/hyperv/vhdutils.py index 55c3a45658..e5ac1311b7 100644 --- a/nova/virt/hyperv/vhdutils.py +++ b/nova/virt/hyperv/vhdutils.py @@ -72,10 +72,7 @@ class VHDUtils(object): Path=path, MaxInternalSize=max_internal_size) self._vmutils.check_ret_val(ret_val, job_path) - def create_differencing_vhd(self, path, parent_path, size=None): - if size is not None: - raise vmutils.HyperVException(_('VHD differencing disks cannot be ' - 'resized')) + def create_differencing_vhd(self, path, parent_path): image_man_svc = self._conn.Msvm_ImageManagementService()[0] (job_path, ret_val) = image_man_svc.CreateDifferencingVirtualHardDisk( diff --git a/nova/virt/hyperv/vhdutilsv2.py b/nova/virt/hyperv/vhdutilsv2.py index d2b69a9a79..3ae319b729 100644 --- a/nova/virt/hyperv/vhdutilsv2.py +++ b/nova/virt/hyperv/vhdutilsv2.py @@ -68,12 +68,15 @@ class VHDUtilsV2(vhdutils.VHDUtils): self._create_vhd(self._VHD_TYPE_DYNAMIC, vhd_format, path, max_internal_size=max_internal_size) - def create_differencing_vhd(self, path, parent_path, size=None): + def create_differencing_vhd(self, path, parent_path): + # Although this method can take a size argument in case of VHDX + # images, avoid it as the underlying Win32 is currently not + # resizing the disk properly. This can be reconsidered once the + # Win32 issue is fixed. parent_vhd_info = self.get_vhd_info(parent_path) self._create_vhd(self._VHD_TYPE_DIFFERENCING, parent_vhd_info["Format"], - path, parent_path=parent_path, - max_internal_size=size) + path, parent_path=parent_path) def _create_vhd(self, vhd_type, format, path, max_internal_size=None, parent_path=None): diff --git a/nova/virt/hyperv/vmops.py b/nova/virt/hyperv/vmops.py index a170b04535..a17f8c5650 100644 --- a/nova/virt/hyperv/vmops.py +++ b/nova/virt/hyperv/vmops.py @@ -181,24 +181,14 @@ class VMOps(object): {'base_vhd_path': base_vhd_path, 'root_vhd_path': root_vhd_path}, instance=instance) + self._vhdutils.create_differencing_vhd(root_vhd_path, + base_vhd_path) vhd_type = self._vhdutils.get_vhd_format(base_vhd_path) - if vhd_type == constants.DISK_FORMAT_VHDX: - # Differencing vhdx images can be resized, so we use - # the flavor size when creating the root image - root_vhd_internal_size = ( - self._vhdutils.get_internal_vhd_size_by_file_size( - base_vhd_path, root_vhd_size)) - if not self._is_resize_needed(root_vhd_path, base_vhd_size, - root_vhd_internal_size, - instance): - root_vhd_internal_size = None - - self._vhdutils.create_differencing_vhd( - root_vhd_path, base_vhd_path, root_vhd_internal_size) - else: - # The base image had already been resized - self._vhdutils.create_differencing_vhd(root_vhd_path, - base_vhd_path) + if vhd_type == constants.DISK_FORMAT_VHD: + # The base image has already been resized. As differencing + # vhdx images support it, the root image will be resized + # instead if needed. + return root_vhd_path else: LOG.debug("Copying VHD image %(base_vhd_path)s to target: " "%(root_vhd_path)s", @@ -207,16 +197,16 @@ class VMOps(object): instance=instance) self._pathutils.copyfile(base_vhd_path, root_vhd_path) - root_vhd_internal_size = ( - self._vhdutils.get_internal_vhd_size_by_file_size( - root_vhd_path, root_vhd_size)) + root_vhd_internal_size = ( + self._vhdutils.get_internal_vhd_size_by_file_size( + base_vhd_path, root_vhd_size)) - if self._is_resize_needed(root_vhd_path, base_vhd_size, + if self._is_resize_needed(root_vhd_path, base_vhd_size, + root_vhd_internal_size, + instance): + self._vhdutils.resize_vhd(root_vhd_path, root_vhd_internal_size, - instance): - self._vhdutils.resize_vhd(root_vhd_path, - root_vhd_internal_size, - is_file_max_size=False) + is_file_max_size=False) except Exception: with excutils.save_and_reraise_exception(): if self._pathutils.exists(root_vhd_path):