import mock
+from cinder import exception
from cinder import test
+from cinder.volume.drivers.windows import constants
from cinder.volume.drivers.windows import vhdutils
-from cinder.volume.drivers.windows import windows_utils
class VHDUtilsTestCase(test.TestCase):
_FAKE_FORMAT = 2
- _FAKE_TYPE = 3
+ _FAKE_TYPE = constants.VHD_TYPE_DYNAMIC
_FAKE_JOB_PATH = 'fake_job_path'
_FAKE_VHD_PATH = r'C:\fake\vhd.vhd'
- _FAKE_DESTINATION_PATH = r'C:\fake\destination.vhd'
+ _FAKE_DEST_PATH = r'C:\fake\destination.vhdx'
_FAKE_RET_VAL = 0
_FAKE_VHD_SIZE = 1024
+ _FAKE_DEVICE_ID = 'fake_device_id'
def setUp(self):
super(VHDUtilsTestCase, self).setUp()
- windows_utils.WindowsUtils.__init__ = lambda x: None
- vhdutils.VHDUtils.__init__ = lambda x: None
- self.wutils = windows_utils.WindowsUtils()
- self.wutils.check_ret_val = mock.MagicMock()
- self.vhdutils = vhdutils.VHDUtils()
- self.vhdutils._conn = mock.MagicMock()
- self.vhdutils.utils = self.wutils
- self.mock_img_svc = (
- self.vhdutils._conn.Msvm_ImageManagementService()[0])
- self.vhdutils._get_resize_method = mock.Mock(
- return_value=self.mock_img_svc.ExpandVirtualHardDisk)
-
- def test_convert_vhd(self):
- self.mock_img_svc.ConvertVirtualHardDisk.return_value = (
- self._FAKE_JOB_PATH, self._FAKE_RET_VAL)
-
- self.vhdutils.convert_vhd(self._FAKE_VHD_PATH,
- self._FAKE_DESTINATION_PATH,
- self._FAKE_TYPE)
-
- self.mock_img_svc.ConvertVirtualHardDisk.assert_called_once()
- self.wutils.check_ret_val.assert_called_once_with(
- self._FAKE_RET_VAL, self._FAKE_JOB_PATH)
-
- def test_resize_vhd(self):
- self.mock_img_svc.ExpandVirtualHardDisk.return_value = (
- self._FAKE_JOB_PATH, self._FAKE_RET_VAL)
-
- self.vhdutils.resize_vhd(self._FAKE_VHD_PATH,
- self._FAKE_VHD_SIZE)
-
- self.mock_img_svc.ExpandVirtualHardDisk.assert_called_once()
- self.wutils.check_ret_val.assert_called_once_with(self._FAKE_RET_VAL,
- self._FAKE_JOB_PATH)
- self.vhdutils._get_resize_method.assert_called_once()
- self.mock_img_svc.ExpandVirtualHardDisk.assert_called_once_with(
- Path=self._FAKE_VHD_PATH, MaxInternalSize=self._FAKE_VHD_SIZE)
+ self._setup_mocks()
+ self._vhdutils = vhdutils.VHDUtils()
+ self._vhdutils._msft_vendor_id = 'fake_vendor_id'
+
+ self.addCleanup(mock.patch.stopall)
+
+ def _setup_mocks(self):
+ fake_ctypes = mock.Mock()
+ # Use this in order to make assertions on the variables parsed by
+ # references.
+ fake_ctypes.byref = lambda x: x
+ fake_ctypes.c_wchar_p = lambda x: x
+
+ mock.patch.multiple(
+ 'cinder.volume.drivers.windows.vhdutils', ctypes=fake_ctypes,
+ windll=mock.DEFAULT, wintypes=mock.DEFAULT, kernel32=mock.DEFAULT,
+ virtdisk=mock.DEFAULT, Win32_GUID=mock.DEFAULT,
+ Win32_RESIZE_VIRTUAL_DISK_PARAMETERS=mock.DEFAULT,
+ Win32_CREATE_VIRTUAL_DISK_PARAMETERS=mock.DEFAULT,
+ Win32_VIRTUAL_STORAGE_TYPE=mock.DEFAULT,
+ create=True).start()
+
+ def _test_convert_vhd(self, convertion_failed=False):
+ self._vhdutils._get_device_id_by_path = mock.Mock(
+ side_effect=(vhdutils.VIRTUAL_STORAGE_TYPE_DEVICE_VHD,
+ vhdutils.VIRTUAL_STORAGE_TYPE_DEVICE_VHDX))
+ self._vhdutils._close = mock.Mock()
+
+ fake_params = (
+ vhdutils.Win32_CREATE_VIRTUAL_DISK_PARAMETERS.return_value)
+ fake_vst = mock.Mock()
+ fake_source_vst = mock.Mock()
+
+ vhdutils.Win32_VIRTUAL_STORAGE_TYPE = mock.Mock(
+ side_effect=[fake_vst, None, fake_source_vst])
+ vhdutils.virtdisk.CreateVirtualDisk.return_value = int(
+ convertion_failed)
+
+ if convertion_failed:
+ self.assertRaises(exception.VolumeBackendAPIException,
+ self._vhdutils.convert_vhd,
+ self._FAKE_VHD_PATH, self._FAKE_DEST_PATH,
+ self._FAKE_TYPE)
+ else:
+ self._vhdutils.convert_vhd(self._FAKE_VHD_PATH,
+ self._FAKE_DEST_PATH,
+ self._FAKE_TYPE)
+
+ self.assertEqual(vhdutils.VIRTUAL_STORAGE_TYPE_DEVICE_VHDX,
+ fake_vst.DeviceId)
+ self.assertEqual(vhdutils.VIRTUAL_STORAGE_TYPE_DEVICE_VHD,
+ fake_source_vst.DeviceId)
+
+ vhdutils.virtdisk.CreateVirtualDisk.assert_called_with(
+ vhdutils.ctypes.byref(fake_vst),
+ vhdutils.ctypes.c_wchar_p(self._FAKE_DEST_PATH),
+ vhdutils.VIRTUAL_DISK_ACCESS_NONE, None,
+ vhdutils.CREATE_VIRTUAL_DISK_FLAG_NONE, 0,
+ vhdutils.ctypes.byref(fake_params), None,
+ vhdutils.ctypes.byref(vhdutils.wintypes.HANDLE()))
+ self.assertTrue(self._vhdutils._close.called)
+
+ def test_convert_vhd_successfully(self):
+ self._test_convert_vhd()
+
+ def test_convert_vhd_exception(self):
+ self._test_convert_vhd(True)
+
+ def _test_open(self, open_failed=False):
+ vhdutils.virtdisk.OpenVirtualDisk.return_value = int(open_failed)
+
+ fake_vst = vhdutils.Win32_VIRTUAL_STORAGE_TYPE.return_value
+
+ if open_failed:
+ self.assertRaises(exception.VolumeBackendAPIException,
+ self._vhdutils._open,
+ self._FAKE_DEVICE_ID, self._FAKE_VHD_PATH)
+ else:
+ self._vhdutils._open(self._FAKE_DEVICE_ID,
+ self._FAKE_VHD_PATH)
+
+ vhdutils.virtdisk.OpenVirtualDisk.assert_called_with(
+ vhdutils.ctypes.byref(fake_vst),
+ vhdutils.ctypes.c_wchar_p(self._FAKE_VHD_PATH),
+ vhdutils.VIRTUAL_DISK_ACCESS_ALL,
+ vhdutils.CREATE_VIRTUAL_DISK_FLAG_NONE, 0,
+ vhdutils.ctypes.byref(vhdutils.wintypes.HANDLE()))
+ self.assertEqual(self._FAKE_DEVICE_ID, fake_vst.DeviceId)
+
+ def test_open_success(self):
+ self._test_open()
+
+ def test_open_failed(self):
+ self._test_open(open_failed=True)
+
+ def _test_get_device_id_by_path(self,
+ get_device_failed=False):
+ if get_device_failed:
+ self.assertRaises(exception.VolumeBackendAPIException,
+ self._vhdutils._get_device_id_by_path,
+ self._FAKE_VHD_PATH[:-4])
+ else:
+ ret_val = self._vhdutils._get_device_id_by_path(
+ self._FAKE_VHD_PATH)
+
+ self.assertEqual(
+ ret_val,
+ vhdutils.VIRTUAL_STORAGE_TYPE_DEVICE_VHD)
+
+ def test_get_device_id_by_path_success(self):
+ self._test_get_device_id_by_path()
+
+ def test_get_device_id_by_path_failed(self):
+ self._test_get_device_id_by_path(get_device_failed=True)
+
+ def _test_resize_vhd(self, resize_failed=False):
+ fake_params = (
+ vhdutils.Win32_RESIZE_VIRTUAL_DISK_PARAMETERS.return_value)
+
+ self._vhdutils._open = mock.Mock(
+ return_value=vhdutils.ctypes.byref(
+ vhdutils.wintypes.HANDLE()))
+ self._vhdutils._close = mock.Mock()
+ self._vhdutils._get_device_id_by_path = mock.Mock(return_value=2)
+
+ vhdutils.virtdisk.ResizeVirtualDisk.return_value = int(
+ resize_failed)
+
+ if resize_failed:
+ self.assertRaises(exception.VolumeBackendAPIException,
+ self._vhdutils.resize_vhd,
+ self._FAKE_VHD_PATH,
+ self._FAKE_VHD_SIZE)
+ else:
+ self._vhdutils.resize_vhd(self._FAKE_VHD_PATH,
+ self._FAKE_VHD_SIZE)
+
+ vhdutils.virtdisk.ResizeVirtualDisk.assert_called_with(
+ vhdutils.ctypes.byref(vhdutils.wintypes.HANDLE()),
+ vhdutils.RESIZE_VIRTUAL_DISK_FLAG_NONE,
+ vhdutils.ctypes.byref(fake_params),
+ None)
+ self.assertTrue(self._vhdutils._close.called)
+
+ def test_resize_vhd_success(self):
+ self._test_resize_vhd()
+
+ def test_resize_vhd_failed(self):
+ self._test_resize_vhd(resize_failed=True)
+++ /dev/null
-# Copyright 2014 Cloudbase Solutions Srl
-#
-# 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 mock
-
-from cinder import test
-from cinder.volume.drivers.windows import vhdutilsv2
-from cinder.volume.drivers.windows import windows_utils
-
-
-class VHDUtilsV2TestCase(test.TestCase):
-
- _FAKE_FORMAT = 2
- _FAKE_TYPE = 3
- _FAKE_JOB_PATH = 'fake_job_path'
- _FAKE_VHD_PATH = r'C:\fake\vhd.vhd'
- _FAKE_DESTINATION_PATH = r'C:\fake\destination.vhd'
- _FAKE_RET_VAL = 0
- _FAKE_VHD_SIZE = 1024
-
- def setUp(self):
- super(VHDUtilsV2TestCase, self).setUp()
- windows_utils.WindowsUtils.__init__ = lambda x: None
- vhdutilsv2.VHDUtilsV2.__init__ = lambda x: None
- self.wutils = windows_utils.WindowsUtils()
- self.wutils.check_ret_val = mock.MagicMock()
- self.vhdutilsv2 = vhdutilsv2.VHDUtilsV2()
- self.vhdutilsv2._conn = mock.MagicMock()
- self.vhdutilsv2.utils = self.wutils
- self.mock_img_svc = (
- self.vhdutilsv2._conn.Msvm_ImageManagementService()[0])
- self.vhdutilsv2._get_resize_method = mock.Mock(
- return_value=self.mock_img_svc.ResizeVirtualHardDisk)
-
- def test_convert_vhd(self):
- self.mock_img_svc.ConvertVirtualHardDisk.return_value = (
- self._FAKE_JOB_PATH, self._FAKE_RET_VAL)
-
- self.vhdutilsv2.convert_vhd(self._FAKE_VHD_PATH,
- self._FAKE_DESTINATION_PATH,
- self._FAKE_TYPE)
-
- self.mock_img_svc.ConvertVirtualHardDisk.assert_called_once()
- self.wutils.check_ret_val.assert_called_once_with(
- self._FAKE_RET_VAL, self._FAKE_JOB_PATH)
-
- def test_resize_vhd(self):
- self.mock_img_svc.ResizeVirtualHardDisk.return_value = (
- self._FAKE_JOB_PATH, self._FAKE_RET_VAL)
-
- self.vhdutilsv2.resize_vhd(self._FAKE_VHD_PATH,
- self._FAKE_VHD_SIZE)
-
- self.mock_img_svc.ResizeVirtualHardDisk.assert_called_once()
- self.wutils.check_ret_val.assert_called_once_with(self._FAKE_RET_VAL,
- self._FAKE_JOB_PATH)
- self.vhdutilsv2._get_resize_method.assert_called_once()
- self.mock_img_svc.ResizeVirtualHardDisk.assert_called_once_with(
- Path=self._FAKE_VHD_PATH, MaxInternalSize=self._FAKE_VHD_SIZE)
from cinder.tests.windows import db_fakes
from cinder.volume import configuration as conf
from cinder.volume.drivers.windows import constants
-from cinder.volume.drivers.windows import utilsfactory
from cinder.volume.drivers.windows import vhdutils
from cinder.volume.drivers.windows import windows
from cinder.volume.drivers.windows import windows_utils
def fake_wutils__init__(self):
pass
- def fake_get_vhdutils():
- return vhdutils.VHDUtils()
-
windows_utils.WindowsUtils.__init__ = fake_wutils__init__
- vhdutils.VHDUtils.__init__ = lambda x: None
- utilsfactory.get_vhdutils = fake_get_vhdutils
def fake_local_path(self, volume):
return os.path.join(CONF.windows_iscsi_lun_path,
temp_vhd_path)
if supported_format == 'vhdx':
upload_image = upload_image[:-1]
- vhdutils.VHDUtils.convert_vhd(temp_vhd_path, upload_image)
+ vhdutils.VHDUtils.convert_vhd(temp_vhd_path, upload_image,
+ constants.VHD_TYPE_DYNAMIC)
image_utils.upload_volume(None, None, image_meta, upload_image, 'vpc')
+++ /dev/null
-# Copyright 2014 Cloudbase Solutions Srl
-#
-# 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 mock
-
-from cinder import exception
-from cinder import test
-from cinder.volume.drivers.windows import constants
-from cinder.volume.drivers.windows import windows_utils
-
-
-class WindowsUtilsTestCase(test.TestCase):
-
- _FAKE_JOB_PATH = 'fake_job_path'
- _FAKE_RET_VAL = 0
- _FAKE_RET_VAL_ERROR = 10
- _FAKE_VHD_SIZE = 1024
- _FAKE_JOB = 'fake_job'
-
- def setUp(self):
- super(WindowsUtilsTestCase, self).setUp()
- windows_utils.WindowsUtils.__init__ = lambda x: None
- self.wutils = windows_utils.WindowsUtils()
- self.wutils.time = mock.MagicMock()
-
- def _test_check_ret_val(self, job_started, job_failed):
- self.wutils._wait_for_job = mock.Mock(return_value=self._FAKE_JOB)
- if job_started:
- ret_val = self.wutils.check_ret_val(
- constants.WMI_JOB_STATUS_STARTED, self._FAKE_JOB_PATH)
- self.assertEqual(ret_val, self._FAKE_JOB)
- self.wutils._wait_for_job.assert_called_once_with(
- self._FAKE_JOB_PATH)
-
- elif job_failed:
- self.assertRaises(exception.VolumeBackendAPIException,
- self.wutils.check_ret_val,
- 10, self._FAKE_JOB_PATH)
-
- def test_check_ret_val_failed_job(self):
- self._test_check_ret_val(False, True)
-
- def test_check_ret_val_job_started(self):
- self._test_check_ret_val(True, False)
-
- def _test_wait_for_job(self, job_running, job_failed):
- fake_job = mock.MagicMock()
- fake_job2 = mock.MagicMock()
- fake_job2.JobState = constants.WMI_JOB_STATE_COMPLETED
-
- if job_running:
- fake_job.JobState = constants.WMI_JOB_STATE_RUNNING
- elif job_failed:
- fake_job.JobState = self._FAKE_RET_VAL_ERROR
- fake_job.GetError = mock.Mock(return_value=(
- 1, self._FAKE_RET_VAL_ERROR))
- else:
- fake_job.JobState = constants.WMI_JOB_STATE_COMPLETED
-
- self.wutils._get_wmi_obj = mock.Mock(side_effect=[fake_job, fake_job2])
-
- if job_failed:
- self.assertRaises(exception.VolumeBackendAPIException,
- self.wutils._wait_for_job,
- self._FAKE_JOB_PATH)
- else:
- self.wutils._wait_for_job(self._FAKE_JOB_PATH)
- if job_running:
- call_count = 2
- else:
- call_count = 1
- self.assertEqual(call_count, self.wutils._get_wmi_obj.call_count)
-
- def test_wait_for_running_job(self):
- self._test_wait_for_job(True, False)
-
- def test_wait_for_failed_job(self):
- self._test_wait_for_job(False, True)
# License for the specific language governing permissions and limitations
# under the License.
-WMI_JOB_STATUS_STARTED = 4096
-WMI_JOB_STATE_RUNNING = 4
-WMI_JOB_STATE_COMPLETED = 7
-
VHD_TYPE_FIXED = 2
VHD_TYPE_DYNAMIC = 3
+++ /dev/null
-# 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.
-
-from cinder.openstack.common import log as logging
-from cinder.volume.drivers.windows import vhdutils
-from cinder.volume.drivers.windows import vhdutilsv2
-from cinder.volume.drivers.windows import windows_utils
-
-LOG = logging.getLogger(__name__)
-
-
-def _get_class(v1_class, v2_class):
- # V2 classes are supported starting from Hyper-V Server 2012 and
- # Windows Server 2012 (kernel version 6.2)
- if not windows_utils.WindowsUtils().check_min_windows_version(6, 2):
- cls = v2_class
- else:
- cls = v1_class
- LOG.debug("Loading class: %(module_name)s.%(class_name)s",
- {'module_name': cls.__module__, 'class_name': cls.__name__})
- return cls
-
-
-def get_vhdutils():
- return _get_class(vhdutils.VHDUtils, vhdutilsv2.VHDUtilsV2)()
Official VHDX format specs can be retrieved at:
http://www.microsoft.com/en-us/download/details.aspx?id=34750
"""
+import ctypes
import os
if os.name == 'nt':
- import wmi
+ from ctypes import windll
+ from ctypes import wintypes
+ kernel32 = windll.kernel32
+ virtdisk = windll.virtdisk
+
+from cinder import exception
+from cinder.openstack.common.gettextutils import _
from cinder.openstack.common import log as logging
-from cinder.volume.drivers.windows import windows_utils
+from cinder.volume.drivers.windows import constants
LOG = logging.getLogger(__name__)
+if os.name == 'nt':
+ class Win32_GUID(ctypes.Structure):
+ _fields_ = [("Data1", wintypes.DWORD),
+ ("Data2", wintypes.WORD),
+ ("Data3", wintypes.WORD),
+ ("Data4", wintypes.BYTE * 8)]
+
+ class Win32_VIRTUAL_STORAGE_TYPE(ctypes.Structure):
+ _fields_ = [
+ ('DeviceId', wintypes.DWORD),
+ ('VendorId', Win32_GUID)
+ ]
+
+ class Win32_RESIZE_VIRTUAL_DISK_PARAMETERS(ctypes.Structure):
+ _fields_ = [
+ ('Version', wintypes.DWORD),
+ ('NewSize', ctypes.c_ulonglong)
+ ]
+
+ class Win32_CREATE_VIRTUAL_DISK_PARAMETERS(ctypes.Structure):
+ _fields_ = [
+ ('Version', wintypes.DWORD),
+ ('UniqueId', Win32_GUID),
+ ('MaximumSize', ctypes.c_ulonglong),
+ ('BlockSizeInBytes', wintypes.ULONG),
+ ('SectorSizeInBytes', wintypes.ULONG),
+ ('PhysicalSectorSizeInBytes', wintypes.ULONG),
+ ('ParentPath', wintypes.LPCWSTR),
+ ('SourcePath', wintypes.LPCWSTR),
+ ('OpenFlags', wintypes.DWORD),
+ ('ParentVirtualStorageType', Win32_VIRTUAL_STORAGE_TYPE),
+ ('SourceVirtualStorageType', Win32_VIRTUAL_STORAGE_TYPE),
+ ('ResiliencyGuid', Win32_GUID)
+ ]
+
+VIRTUAL_STORAGE_TYPE_DEVICE_ISO = 1
+VIRTUAL_STORAGE_TYPE_DEVICE_VHD = 2
+VIRTUAL_STORAGE_TYPE_DEVICE_VHDX = 3
+VIRTUAL_DISK_ACCESS_NONE = 0
+VIRTUAL_DISK_ACCESS_ALL = 0x003f0000
+VIRTUAL_DISK_ACCESS_CREATE = 0x00100000
+OPEN_VIRTUAL_DISK_FLAG_NONE = 0
+RESIZE_VIRTUAL_DISK_FLAG_NONE = 0
+RESIZE_VIRTUAL_DISK_VERSION_1 = 1
+CREATE_VIRTUAL_DISK_VERSION_2 = 2
+CREATE_VHD_PARAMS_DEFAULT_BLOCK_SIZE = 0
+CREATE_VIRTUAL_DISK_FLAG_NONE = 0
+CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION = 1
+
class VHDUtils(object):
def __init__(self):
- self.utils = windows_utils.WindowsUtils()
- self._conn = wmi.WMI(moniker='//./root/virtualization')
+ self._ext_device_id_map = {
+ 'vhd': VIRTUAL_STORAGE_TYPE_DEVICE_VHD,
+ 'vhdx': VIRTUAL_STORAGE_TYPE_DEVICE_VHDX}
+ self.create_virtual_disk_flags = {
+ constants.VHD_TYPE_FIXED: (
+ CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION),
+ constants.VHD_TYPE_DYNAMIC: CREATE_VIRTUAL_DISK_FLAG_NONE
+ }
+
+ if os.name == 'nt':
+ self._msft_vendor_id = (
+ self.get_WIN32_VIRTUAL_STORAGE_TYPE_VENDOR_MSFT())
+
+ @staticmethod
+ def get_WIN32_VIRTUAL_STORAGE_TYPE_VENDOR_MSFT():
+ guid = Win32_GUID()
+ guid.Data1 = 0xec984aec
+ guid.Data2 = 0xa0f9
+ guid.Data3 = 0x47e9
+ ByteArray8 = wintypes.BYTE * 8
+ guid.Data4 = ByteArray8(0x90, 0x1f, 0x71, 0x41, 0x5a, 0x66, 0x34, 0x5b)
+ return guid
+
+ def _open(self, device_id, vhd_path):
+ vst = Win32_VIRTUAL_STORAGE_TYPE()
+ vst.DeviceId = device_id
+ vst.VendorId = self._msft_vendor_id
- def convert_vhd(self, src, dest, vhd_type=None):
- image_man_svc = self._conn.Msvm_ImageManagementService()[0]
- (job_path, ret_val) = image_man_svc.ConvertVirtualHardDisk(
- SourcePath=src, DestinationPath=dest, Type=vhd_type)
- self.utils.check_ret_val(ret_val, job_path)
+ handle = wintypes.HANDLE()
+ ret_val = virtdisk.OpenVirtualDisk(ctypes.byref(vst),
+ ctypes.c_wchar_p(vhd_path),
+ VIRTUAL_DISK_ACCESS_ALL,
+ OPEN_VIRTUAL_DISK_FLAG_NONE,
+ 0, ctypes.byref(handle))
+ if ret_val:
+ raise exception.VolumeBackendAPIException(
+ _("Opening virtual disk failed with error: %s") % ret_val)
+ return handle
- def _get_resize_method(self):
- image_man_svc = self._conn.Msvm_ImageManagementService()[0]
- return image_man_svc.ExpandVirtualHardDisk
+ def _close(self, handle):
+ kernel32.CloseHandle(handle)
+
+ def _get_device_id_by_path(self, vhd_path):
+ ext = os.path.splitext(vhd_path)[1][1:].lower()
+ device_id = self._ext_device_id_map.get(ext)
+ if not device_id:
+ raise exception.VolumeBackendAPIException(
+ _("Unsupported virtual disk extension: %s") % ext)
+ return device_id
def resize_vhd(self, vhd_path, new_max_size):
- resize = self._get_resize_method()
- (job_path, ret_val) = resize(Path=vhd_path,
- MaxInternalSize=new_max_size)
- self.utils.check_ret_val(ret_val, job_path)
+ device_id = self._get_device_id_by_path(vhd_path)
+ handle = self._open(device_id, vhd_path)
+
+ params = Win32_RESIZE_VIRTUAL_DISK_PARAMETERS()
+ params.Version = RESIZE_VIRTUAL_DISK_VERSION_1
+ params.NewSize = new_max_size
+
+ ret_val = virtdisk.ResizeVirtualDisk(
+ handle,
+ RESIZE_VIRTUAL_DISK_FLAG_NONE,
+ ctypes.byref(params),
+ None)
+ self._close(handle)
+
+ if ret_val:
+ raise exception.VolumeBackendAPIException(
+ _("Virtual disk resize failed with error: %s") % ret_val)
+
+ def convert_vhd(self, src, dest, vhd_type):
+ src_device_id = self._get_device_id_by_path(src)
+ dest_device_id = self._get_device_id_by_path(dest)
+
+ vst = Win32_VIRTUAL_STORAGE_TYPE()
+ vst.DeviceId = dest_device_id
+ vst.VendorId = self._msft_vendor_id
+
+ params = Win32_CREATE_VIRTUAL_DISK_PARAMETERS()
+ params.Version = CREATE_VIRTUAL_DISK_VERSION_2
+ params.UniqueId = Win32_GUID()
+ params.MaximumSize = 0
+ params.BlockSizeInBytes = CREATE_VHD_PARAMS_DEFAULT_BLOCK_SIZE
+ params.SectorSizeInBytes = 0x200
+ params.PhysicalSectorSizeInBytes = 0x200
+ params.ParentPath = None
+ params.SourcePath = src
+ params.OpenFlags = OPEN_VIRTUAL_DISK_FLAG_NONE
+ params.ParentVirtualStorageType = Win32_VIRTUAL_STORAGE_TYPE()
+ params.SourceVirtualStorageType = Win32_VIRTUAL_STORAGE_TYPE()
+ params.SourceVirtualStorageType.DeviceId = src_device_id
+ params.SourceVirtualStorageType.VendorId = self._msft_vendor_id
+ params.ResiliencyGuid = Win32_GUID()
+
+ handle = wintypes.HANDLE()
+ create_virtual_disk_flag = self.create_virtual_disk_flags.get(vhd_type)
+
+ ret_val = virtdisk.CreateVirtualDisk(
+ ctypes.byref(vst),
+ ctypes.c_wchar_p(dest),
+ VIRTUAL_DISK_ACCESS_NONE,
+ None,
+ create_virtual_disk_flag,
+ 0,
+ ctypes.byref(params),
+ None,
+ ctypes.byref(handle))
+ self._close(handle)
+
+ if ret_val:
+ raise exception.VolumeBackendAPIException(
+ _("Virtual disk conversion failed with error: %s") % ret_val)
+++ /dev/null
-# 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.
-
-"""
-Utility class for VHD related operations.
-Based on the "root/virtualization/v2" namespace available starting with
-Hyper-V Server / Windows Server 2012.
-"""
-import os
-
-if os.name == 'nt':
- import wmi
-
-from cinder.openstack.common import log as logging
-from cinder.volume.drivers.windows import constants
-from cinder.volume.drivers.windows import vhdutils
-from cinder.volume.drivers.windows import windows_utils
-
-LOG = logging.getLogger(__name__)
-
-
-class VHDUtilsV2(vhdutils.VHDUtils):
-
- _vhd_format_map = {
- 'vhd': 2,
- 'vhdx': 3,
- }
-
- def __init__(self):
- self.utils = windows_utils.WindowsUtils()
- self._conn = wmi.WMI(moniker='//./root/virtualization/v2')
-
- def _get_resize_method(self):
- image_man_svc = self._conn.Msvm_ImageManagementService()[0]
- return image_man_svc.ResizeVirtualHardDisk
-
- def convert_vhd(self, src, dest, vhd_type=constants.VHD_TYPE_DYNAMIC):
- vhd_info = self._conn.Msvm_VirtualHardDiskSettingData.new()
- ext = os.path.splitext(dest)[1][1:]
- format = self._vhd_format_map.get(ext)
-
- vhd_info.Type = vhd_type
- vhd_info.Path = dest
- vhd_info.Format = format
- vhd_info.BlockSize = 0
- vhd_info.LogicalSectorSize = 0
- vhd_info.ParentPath = None
-
- image_man_svc = self._conn.Msvm_ImageManagementService()[0]
- (job_path, ret_val) = image_man_svc.ConvertVirtualHardDisk(
- SourcePath=src, VirtualDiskSettingData=vhd_info.GetText_(1))
- self.utils.check_ret_val(ret_val, job_path)
from cinder.openstack.common import fileutils
from cinder.openstack.common import log as logging
from cinder.volume import driver
-from cinder.volume.drivers.windows import utilsfactory
+from cinder.volume.drivers.windows import constants
+from cinder.volume.drivers.windows import vhdutils
from cinder.volume.drivers.windows import windows_utils
LOG = logging.getLogger(__name__)
Validate the flags we care about
"""
self.utils = windows_utils.WindowsUtils()
- self.vhdutils = utilsfactory.get_vhdutils()
+ self.vhdutils = vhdutils.VHDUtils()
def check_for_setup_error(self):
"""Check that the driver is working and can communicate."""
# convert the image to vhd before attempting upload
if disk_format == 'vhdx':
upload_image = upload_image[:-1]
- self.vhdutils.convert_vhd(temp_vhd_path, upload_image)
+ self.vhdutils.convert_vhd(temp_vhd_path, upload_image,
+ constants.VHD_TYPE_DYNAMIC)
image_utils.upload_volume(context, image_service, image_meta,
upload_image, 'vpc')
import ctypes
import os
-import time
from oslo.config import cfg
else:
return constants.VHD_TYPE_FIXED
- def check_ret_val(self, ret_val, job_path, success_values=[0]):
- if ret_val == constants.WMI_JOB_STATUS_STARTED:
- return self._wait_for_job(job_path)
- elif ret_val not in success_values:
- raise exception.VolumeBackendAPIException(
- _('Operation failed with return value: %s') % ret_val)
-
def copy(self, src, dest):
# With large files this is 2x-3x faster than shutil.copy(src, dest),
# especially with UNC targets.
if not retcode:
raise IOError(_('The file copy from %(src)s to %(dest)s failed.')
% {'src': src, 'dest': dest})
-
- def _wait_for_job(self, job_path):
- """Poll WMI job state and wait for completion."""
- job = self._get_wmi_obj(job_path)
-
- while job.JobState == constants.WMI_JOB_STATE_RUNNING:
- time.sleep(0.1)
- job = self._get_wmi_obj(job_path)
- if job.JobState != constants.WMI_JOB_STATE_COMPLETED:
- job_state = job.JobState
- if job.path().Class == "Msvm_ConcreteJob":
- err_sum_desc = job.ErrorSummaryDescription
- err_desc = job.ErrorDescription
- err_code = job.ErrorCode
- raise exception.VolumeBackendAPIException(
- _("WMI job failed with status "
- "%(job_state)d. Error details: "
- "%(err_sum_desc)s - %(err_desc)s - "
- "Error code: %(err_code)d") %
- {'job_state': job_state,
- 'err_sum_desc': err_sum_desc,
- 'err_desc': err_desc,
- 'err_code': err_code})
- else:
- (error, ret_val) = job.GetError()
- if not ret_val and error:
- raise exception.VolumeBackendAPIException(
- _("WMI job failed with status %(job_state)d. "
- "Job path: %(job_path)s Error details: "
- "%(error)s") % {'job_state': job_state,
- 'error': error,
- 'job_path': job_path})
- else:
- raise exception.VolumeBackendAPIException(
- _("WMI job failed with status %d. No error "
- "description available") % job_state)
- desc = job.Description
- elap = job.ElapsedTime
- LOG.debug("WMI job succeeded: %(desc)s, Elapsed=%(elap)s" %
- {'desc': desc, 'elap': elap})
- return job
-
- def _get_wmi_obj(self, path):
- return wmi.WMI(moniker=path.replace('\\', '/'))