+++ /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 importlib
-import os
-import sys
-
-import mock
-
-from cinder import exception
-from cinder.image import image_utils
-from cinder import test
-
-
-class WindowsSmbFsTestCase(test.TestCase):
-
- _FAKE_SHARE = '//1.2.3.4/share1'
- _FAKE_MNT_BASE = 'c:\openstack\mnt'
- _FAKE_MNT_POINT = os.path.join(_FAKE_MNT_BASE, 'fake_hash')
- _FAKE_VOLUME_NAME = 'volume-4f711859-4928-4cb7-801a-a50c37ceaccc'
- _FAKE_SNAPSHOT_NAME = _FAKE_VOLUME_NAME + '-snapshot.vhdx'
- _FAKE_VOLUME_PATH = os.path.join(_FAKE_MNT_POINT,
- _FAKE_VOLUME_NAME)
- _FAKE_SNAPSHOT_PATH = os.path.join(_FAKE_MNT_POINT,
- _FAKE_SNAPSHOT_NAME)
- _FAKE_TOTAL_SIZE = '2048'
- _FAKE_TOTAL_AVAILABLE = '1024'
- _FAKE_TOTAL_ALLOCATED = 1024
- _FAKE_VOLUME = {'id': 'e8d76af4-cbb9-4b70-8e9e-5a133f1a1a66',
- 'size': 1,
- 'provider_location': _FAKE_SHARE}
- _FAKE_SNAPSHOT = {'id': '35a23942-7625-4683-ad84-144b76e87a80',
- 'volume': _FAKE_VOLUME,
- 'volume_size': _FAKE_VOLUME['size']}
- _FAKE_SHARE_OPTS = '-o username=Administrator,password=12345'
- _FAKE_VOLUME_PATH = os.path.join(_FAKE_MNT_POINT,
- _FAKE_VOLUME_NAME + '.vhdx')
- _FAKE_LISTDIR = [_FAKE_VOLUME_NAME + '.vhd',
- _FAKE_VOLUME_NAME + '.vhdx', 'fake_folder']
-
- def setUp(self):
- super(WindowsSmbFsTestCase, self).setUp()
- self._mock_wmi = mock.MagicMock()
-
- self._platform_patcher = mock.patch('sys.platform', 'win32')
-
- mock.patch.dict(sys.modules, wmi=self._mock_wmi,
- ctypes=self._mock_wmi).start()
-
- self._platform_patcher.start()
- # self._wmi_patcher.start()
- self.addCleanup(mock.patch.stopall)
-
- smbfs = importlib.import_module(
- 'cinder.volume.drivers.windows.smbfs')
- smbfs.WindowsSmbfsDriver.__init__ = lambda x: None
- self._smbfs_driver = smbfs.WindowsSmbfsDriver()
- self._smbfs_driver._remotefsclient = mock.Mock()
- self._smbfs_driver._delete = mock.Mock()
- self._smbfs_driver.local_path = mock.Mock(
- return_value=self._FAKE_VOLUME_PATH)
- self._smbfs_driver.vhdutils = mock.Mock()
- self._smbfs_driver._check_os_platform = mock.Mock()
-
- def _test_create_volume(self, volume_exists=False, volume_format='vhdx'):
- self._smbfs_driver.create_dynamic_vhd = mock.MagicMock()
- fake_create = self._smbfs_driver.vhdutils.create_dynamic_vhd
- self._smbfs_driver.get_volume_format = mock.Mock(
- return_value=volume_format)
-
- with mock.patch('os.path.exists', new=lambda x: volume_exists):
- if volume_exists or volume_format not in ('vhd', 'vhdx'):
- self.assertRaises(exception.InvalidVolume,
- self._smbfs_driver._do_create_volume,
- self._FAKE_VOLUME)
- else:
- fake_vol_path = self._FAKE_VOLUME_PATH
- self._smbfs_driver._do_create_volume(self._FAKE_VOLUME)
- fake_create.assert_called_once_with(
- fake_vol_path, self._FAKE_VOLUME['size'] << 30)
-
- def test_create_volume(self):
- self._test_create_volume()
-
- def test_create_existing_volume(self):
- self._test_create_volume(True)
-
- def test_create_volume_invalid_volume(self):
- self._test_create_volume(volume_format="qcow")
-
- def test_get_capacity_info(self):
- self._smbfs_driver._remotefsclient.get_capacity_info = mock.Mock(
- return_value=(self._FAKE_TOTAL_SIZE, self._FAKE_TOTAL_AVAILABLE))
- self._smbfs_driver._get_total_allocated = mock.Mock(
- return_value=self._FAKE_TOTAL_ALLOCATED)
-
- ret_val = self._smbfs_driver._get_capacity_info(self._FAKE_SHARE)
- expected_ret_val = [int(x) for x in [self._FAKE_TOTAL_SIZE,
- self._FAKE_TOTAL_AVAILABLE,
- self._FAKE_TOTAL_ALLOCATED]]
- self.assertEqual(ret_val, expected_ret_val)
-
- def test_get_total_allocated(self):
- fake_listdir = mock.Mock(side_effect=[self._FAKE_LISTDIR,
- self._FAKE_LISTDIR[:-1]])
- fake_folder_path = os.path.join(self._FAKE_SHARE, 'fake_folder')
- fake_isdir = lambda x: x == fake_folder_path
- self._smbfs_driver._remotefsclient.is_symlink = mock.Mock(
- return_value=False)
- fake_getsize = mock.Mock(return_value=self._FAKE_VOLUME['size'])
- self._smbfs_driver.vhdutils.get_vhd_size = mock.Mock(
- return_value={'VirtualSize': 1})
-
- with mock.patch.multiple('os.path', isdir=fake_isdir,
- getsize=fake_getsize):
- with mock.patch('os.listdir', fake_listdir):
- ret_val = self._smbfs_driver._get_total_allocated(
- self._FAKE_SHARE)
- self.assertEqual(ret_val, 4)
-
- def _test_get_img_info(self, backing_file=None):
- self._smbfs_driver.vhdutils.get_vhd_parent_path.return_value = (
- backing_file)
-
- image_info = self._smbfs_driver._qemu_img_info(self._FAKE_VOLUME_PATH)
- self.assertEqual(self._FAKE_VOLUME_NAME + '.vhdx',
- image_info.image)
- backing_file_name = backing_file and os.path.basename(backing_file)
- self.assertEqual(backing_file_name, image_info.backing_file)
-
- def test_get_img_info_without_backing_file(self):
- self._test_get_img_info()
-
- def test_get_snapshot_info(self):
- self._test_get_img_info(self._FAKE_VOLUME_PATH)
-
- def test_create_snapshot(self):
- self._smbfs_driver.vhdutils.create_differencing_vhd = (
- mock.Mock())
- self._smbfs_driver._local_volume_dir = mock.Mock(
- return_value=self._FAKE_MNT_POINT)
-
- fake_create_diff = (
- self._smbfs_driver.vhdutils.create_differencing_vhd)
-
- self._smbfs_driver._do_create_snapshot(
- self._FAKE_SNAPSHOT,
- os.path.basename(self._FAKE_VOLUME_PATH),
- self._FAKE_SNAPSHOT_PATH)
-
- fake_create_diff.assert_called_once_with(self._FAKE_SNAPSHOT_PATH,
- self._FAKE_VOLUME_PATH)
-
- def _test_copy_volume_to_image(self, has_parent=False,
- volume_format='vhd'):
- drv = self._smbfs_driver
-
- fake_image_meta = {'id': 'fake-image-id'}
-
- if has_parent:
- fake_volume_path = self._FAKE_SNAPSHOT_PATH
- fake_parent_path = self._FAKE_VOLUME_PATH
- else:
- fake_volume_path = self._FAKE_VOLUME_PATH
- fake_parent_path = None
-
- if volume_format == drv._DISK_FORMAT_VHD:
- fake_volume_path = fake_volume_path[:-1]
-
- fake_active_image = os.path.basename(fake_volume_path)
-
- drv.get_active_image_from_info = mock.Mock(
- return_value=fake_active_image)
- drv._local_volume_dir = mock.Mock(
- return_value=self._FAKE_MNT_POINT)
- drv.get_volume_format = mock.Mock(
- return_value=volume_format)
- drv.vhdutils.get_vhd_parent_path.return_value = (
- fake_parent_path)
-
- with mock.patch.object(image_utils, 'upload_volume') as (
- fake_upload_volume):
- drv.copy_volume_to_image(
- mock.sentinel.context, self._FAKE_VOLUME,
- mock.sentinel.image_service, fake_image_meta)
-
- expected_conversion = (
- has_parent or volume_format == drv._DISK_FORMAT_VHDX)
-
- if expected_conversion:
- fake_temp_image_name = '%s.temp_image.%s.%s' % (
- self._FAKE_VOLUME['id'],
- fake_image_meta['id'],
- drv._DISK_FORMAT_VHD)
- fake_temp_image_path = os.path.join(
- self._FAKE_MNT_POINT,
- fake_temp_image_name)
- fake_active_image_path = os.path.join(
- self._FAKE_MNT_POINT,
- fake_active_image)
- upload_path = fake_temp_image_path
-
- drv.vhdutils.convert_vhd.assert_called_once_with(
- fake_active_image_path,
- fake_temp_image_path)
- drv._delete.assert_called_once_with(
- fake_temp_image_path)
- else:
- upload_path = fake_volume_path
-
- fake_upload_volume.assert_called_once_with(
- mock.sentinel.context, mock.sentinel.image_service,
- fake_image_meta, upload_path, drv._DISK_FORMAT_VHD)
-
- def test_copy_volume_to_image_having_snapshot(self):
- self._test_copy_volume_to_image(has_parent=True)
-
- def test_copy_vhdx_volume_to_image(self):
- self._test_copy_volume_to_image(volume_format='vhdx')
-
- def test_copy_vhd_volume_to_image(self):
- self._test_copy_volume_to_image(volume_format='vhd')
-
- def _test_copy_image_to_volume(self, qemu_version=[1, 7]):
- drv = self._smbfs_driver
-
- fake_image_id = 'fake_image_id'
- fake_image_service = mock.MagicMock()
- fake_image_service.show.return_value = (
- {'id': fake_image_id, 'disk_format': 'raw'})
-
- drv.get_volume_format = mock.Mock(
- return_value='vhdx')
- drv.local_path = mock.Mock(
- return_value=self._FAKE_VOLUME_PATH)
- drv._local_volume_dir = mock.Mock(
- return_value=self._FAKE_MNT_POINT)
- drv.get_qemu_version = mock.Mock(
- return_value=qemu_version)
- drv.configuration = mock.MagicMock()
- drv.configuration.volume_dd_blocksize = mock.sentinel.block_size
-
- with mock.patch.object(image_utils,
- 'fetch_to_volume_format') as fake_fetch:
- drv.copy_image_to_volume(
- mock.sentinel.context, self._FAKE_VOLUME,
- fake_image_service,
- fake_image_id)
-
- if qemu_version < [1, 7]:
- fake_temp_image_name = '%s.temp_image.%s.vhd' % (
- self._FAKE_VOLUME['id'],
- fake_image_id)
- fetch_path = os.path.join(self._FAKE_MNT_POINT,
- fake_temp_image_name)
- fetch_format = 'vpc'
- drv.vhdutils.convert_vhd.assert_called_once_with(
- fetch_path, self._FAKE_VOLUME_PATH)
- drv._delete.assert_called_with(fetch_path)
-
- else:
- fetch_path = self._FAKE_VOLUME_PATH
- fetch_format = 'vhdx'
-
- fake_fetch.assert_called_once_with(
- mock.sentinel.context, fake_image_service, fake_image_id,
- fetch_path, fetch_format, mock.sentinel.block_size)
-
- def test_copy_image_to_volume(self):
- self._test_copy_image_to_volume()
-
- def test_copy_image_to_volume_with_conversion(self):
- self._test_copy_image_to_volume([1, 5])
-
- def test_copy_volume_from_snapshot(self):
- drv = self._smbfs_driver
- fake_volume_info = {
- self._FAKE_SNAPSHOT['id']: 'fake_snapshot_file_name'}
- fake_img_info = mock.MagicMock()
- fake_img_info.backing_file = self._FAKE_VOLUME_NAME + '.vhdx'
-
- drv._local_path_volume_info = mock.Mock(
- return_value=self._FAKE_VOLUME_PATH + '.info')
- drv._local_volume_dir = mock.Mock(
- return_value=self._FAKE_MNT_POINT)
- drv._read_info_file = mock.Mock(
- return_value=fake_volume_info)
- drv._qemu_img_info = mock.Mock(
- return_value=fake_img_info)
- drv.local_path = mock.Mock(
- return_value=mock.sentinel.new_volume_path)
-
- drv._copy_volume_from_snapshot(
- self._FAKE_SNAPSHOT, self._FAKE_VOLUME,
- self._FAKE_VOLUME['size'])
-
- drv._delete.assert_called_once_with(mock.sentinel.new_volume_path)
- drv.vhdutils.convert_vhd.assert_called_once_with(
- self._FAKE_VOLUME_PATH,
- mock.sentinel.new_volume_path)
- drv.vhdutils.resize_vhd.assert_called_once_with(
- mock.sentinel.new_volume_path, self._FAKE_VOLUME['size'] << 30)
-
- def test_rebase_img(self):
- self._smbfs_driver._rebase_img(
- self._FAKE_SNAPSHOT_PATH,
- self._FAKE_VOLUME_NAME + '.vhdx', 'vhdx')
- self._smbfs_driver.vhdutils.reconnect_parent.assert_called_once_with(
- self._FAKE_SNAPSHOT_PATH, self._FAKE_VOLUME_PATH)
+++ /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 ctypes
-import os
-
-import mock
-
-from cinder import exception
-from cinder import test
-from cinder.volume.drivers.windows import remotefs
-
-
-class WindowsRemoteFsTestCase(test.TestCase):
- _FAKE_SHARE = '//1.2.3.4/share1'
- _FAKE_MNT_BASE = 'C:\OpenStack\mnt'
- _FAKE_HASH = 'db0bf952c1734092b83e8990bd321131'
- _FAKE_MNT_POINT = os.path.join(_FAKE_MNT_BASE, _FAKE_HASH)
- _FAKE_SHARE_OPTS = '-o username=Administrator,password=12345'
- _FAKE_OPTIONS_DICT = {'username': 'Administrator',
- 'password': '12345'}
-
- def setUp(self):
- super(WindowsRemoteFsTestCase, self).setUp()
-
- remotefs.ctypes.windll = mock.MagicMock()
- remotefs.WindowsRemoteFsClient.__init__ = mock.Mock(return_value=None)
-
- self._remotefs = remotefs.WindowsRemoteFsClient(
- 'cifs', root_helper=None,
- smbfs_mount_point_base=self._FAKE_MNT_BASE)
- self._remotefs._mount_base = self._FAKE_MNT_BASE
- self._remotefs.smb_conn = mock.MagicMock()
- self._remotefs.conn_cimv2 = mock.MagicMock()
-
- def _test_mount_share(self, mount_point_exists=True, is_symlink=True,
- mount_base_exists=True):
- fake_exists = mock.Mock(return_value=mount_point_exists)
- fake_isdir = mock.Mock(return_value=mount_base_exists)
- fake_makedirs = mock.Mock()
- with mock.patch.multiple('os.path', exists=fake_exists,
- isdir=fake_isdir):
- with mock.patch('os.makedirs', fake_makedirs):
- self._remotefs.is_symlink = mock.Mock(
- return_value=is_symlink)
- self._remotefs.create_sym_link = mock.MagicMock()
- self._remotefs._mount = mock.MagicMock()
- fake_norm_path = os.path.abspath(self._FAKE_SHARE)
-
- if mount_point_exists:
- if not is_symlink:
- self.assertRaises(exception.SmbfsException,
- self._remotefs.mount,
- self._FAKE_MNT_POINT,
- self._FAKE_OPTIONS_DICT)
- else:
- self._remotefs.mount(self._FAKE_SHARE,
- self._FAKE_OPTIONS_DICT)
- if not mount_base_exists:
- fake_makedirs.assert_called_once_with(
- self._FAKE_MNT_BASE)
- self._remotefs._mount.assert_called_once_with(
- fake_norm_path, self._FAKE_OPTIONS_DICT)
- self._remotefs.create_sym_link.assert_called_once_with(
- self._FAKE_MNT_POINT, fake_norm_path)
-
- def test_mount_linked_share(self):
- # The mountpoint contains a symlink targeting the share path
- self._test_mount_share(True)
-
- def test_mount_unlinked_share(self):
- self._test_mount_share(False)
-
- def test_mount_point_exception(self):
- # The mountpoint already exists but it is not a symlink
- self._test_mount_share(True, False)
-
- def test_mount_base_missing(self):
- # The mount point base dir does not exist
- self._test_mount_share(mount_base_exists=False)
-
- def _test_check_symlink(self, is_symlink=True, python_version=(2, 7),
- is_dir=True):
- fake_isdir = mock.Mock(return_value=is_dir)
- fake_islink = mock.Mock(return_value=is_symlink)
- with mock.patch('sys.version_info', python_version):
- with mock.patch.multiple('os.path', isdir=fake_isdir,
- islink=fake_islink):
- if is_symlink:
- ret_value = 0x400
- else:
- ret_value = 0x80
- fake_get_attributes = mock.Mock(return_value=ret_value)
- ctypes.windll.kernel32.GetFileAttributesW = fake_get_attributes
-
- ret_value = self._remotefs.is_symlink(self._FAKE_MNT_POINT)
- if python_version >= (3, 2):
- fake_islink.assert_called_once_with(self._FAKE_MNT_POINT)
- else:
- fake_get_attributes.assert_called_once_with(
- self._FAKE_MNT_POINT)
- self.assertEqual(ret_value, is_symlink)
-
- def test_is_symlink(self):
- self._test_check_symlink()
-
- def test_is_not_symlink(self):
- self._test_check_symlink(False)
-
- def test_check_symlink_python_gt_3_2(self):
- self._test_check_symlink(python_version=(3, 3))
-
- def test_create_sym_link_exception(self):
- ctypes.windll.kernel32.CreateSymbolicLinkW.return_value = 0
- self.assertRaises(exception.VolumeBackendAPIException,
- self._remotefs.create_sym_link,
- self._FAKE_MNT_POINT, self._FAKE_SHARE)
-
- def _test_check_smb_mapping(self, existing_mappings=False,
- share_available=False):
- with mock.patch('os.path.exists', lambda x: share_available):
- fake_mapping = mock.MagicMock()
- if existing_mappings:
- fake_mappings = [fake_mapping]
- else:
- fake_mappings = []
-
- self._remotefs.smb_conn.query.return_value = fake_mappings
- ret_val = self._remotefs.check_smb_mapping(self._FAKE_SHARE)
-
- if existing_mappings:
- if share_available:
- self.assertTrue(ret_val)
- else:
- fake_mapping.Remove.assert_called_once_with(True, True)
- else:
- self.assertFalse(ret_val)
-
- def test_check_mapping(self):
- self._test_check_smb_mapping()
-
- def test_remake_unavailable_mapping(self):
- self._test_check_smb_mapping(True, False)
-
- def test_available_mapping(self):
- self._test_check_smb_mapping(True, True)
-
- def test_mount_smb(self):
- fake_create = self._remotefs.smb_conn.Msft_SmbMapping.Create
- self._remotefs._mount(self._FAKE_SHARE, {})
- fake_create.assert_called_once_with(UserName=None,
- Password=None,
- RemotePath=self._FAKE_SHARE)
+++ /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 ctypes
-import os
-import sys
-
-if sys.platform == 'win32':
- import wmi
-
-from oslo_log import log as logging
-
-from cinder.brick.remotefs import remotefs
-from cinder import exception
-from cinder.i18n import _, _LE, _LI
-
-LOG = logging.getLogger(__name__)
-
-
-class WindowsRemoteFsClient(remotefs.RemoteFsClient):
- _FILE_ATTRIBUTE_REPARSE_POINT = 0x0400
-
- def __init__(self, *args, **kwargs):
- super(WindowsRemoteFsClient, self).__init__(*args, **kwargs)
- self.smb_conn = wmi.WMI(moniker='root/Microsoft/Windows/SMB')
- self.conn_cimv2 = wmi.WMI(moniker='root/cimv2')
-
- def mount(self, export_path, mnt_options=None):
- if not os.path.isdir(self._mount_base):
- os.makedirs(self._mount_base)
- export_hash = self._get_hash_str(export_path)
-
- norm_path = os.path.abspath(export_path)
- mnt_options = mnt_options or {}
-
- if not self.check_smb_mapping(norm_path):
- self._mount(norm_path, mnt_options)
-
- link_path = os.path.join(self._mount_base, export_hash)
- if os.path.exists(link_path):
- if not self.is_symlink(link_path):
- raise exception.SmbfsException(_("Link path already exists "
- "and its not a symlink"))
- else:
- self.create_sym_link(link_path, norm_path)
-
- def is_symlink(self, path):
- if sys.version_info >= (3, 2):
- return os.path.islink(path)
-
- file_attr = ctypes.windll.kernel32.GetFileAttributesW(unicode(path))
-
- return bool(os.path.isdir(path) and (
- file_attr & self._FILE_ATTRIBUTE_REPARSE_POINT))
-
- def create_sym_link(self, link, target, target_is_dir=True):
- """If target_is_dir is True, a junction will be created.
-
- NOTE: Juctions only work on same filesystem.
- """
- symlink = ctypes.windll.kernel32.CreateSymbolicLinkW
- symlink.argtypes = (
- ctypes.c_wchar_p,
- ctypes.c_wchar_p,
- ctypes.c_ulong,
- )
- symlink.restype = ctypes.c_ubyte
- retcode = symlink(link, target, target_is_dir)
- if retcode == 0:
- err_msg = (_("Could not create symbolic link. "
- "Link: %(link)s Target %(target)s")
- % {'link': link, 'target': target})
- raise exception.VolumeBackendAPIException(err_msg)
-
- def check_smb_mapping(self, smbfs_share):
- mappings = self.smb_conn.query("SELECT * FROM "
- "MSFT_SmbMapping "
- "WHERE RemotePath='%s'" %
- smbfs_share)
-
- if len(mappings) > 0:
- if os.path.exists(smbfs_share):
- LOG.debug('Share already mounted: %s' % smbfs_share)
- return True
- else:
- LOG.debug('Share exists but is unavailable: %s '
- % smbfs_share)
- for mapping in mappings:
- # Due to a bug in the WMI module, getting the output of
- # methods returning None will raise an AttributeError
- try:
- mapping.Remove(True, True)
- except AttributeError:
- pass
- return False
-
- def _mount(self, smbfs_share, options):
- smb_opts = {'RemotePath': smbfs_share}
- smb_opts['UserName'] = (options.get('username') or
- options.get('user'))
- smb_opts['Password'] = (options.get('password') or
- options.get('pass'))
-
- try:
- LOG.info(_LI('Mounting share: %s') % smbfs_share)
- self.smb_conn.Msft_SmbMapping.Create(**smb_opts)
- except wmi.x_wmi as exc:
- err_msg = (_(
- 'Unable to mount SMBFS share: %(smbfs_share)s '
- 'WMI exception: %(wmi_exc)s'
- 'Options: %(options)s') % {'smbfs_share': smbfs_share,
- 'options': smb_opts,
- 'wmi_exc': exc})
- raise exception.VolumeBackendAPIException(data=err_msg)
-
- def get_capacity_info(self, smbfs_share):
- norm_path = os.path.abspath(smbfs_share)
- kernel32 = ctypes.windll.kernel32
-
- free_bytes = ctypes.c_ulonglong(0)
- total_bytes = ctypes.c_ulonglong(0)
- retcode = kernel32.GetDiskFreeSpaceExW(ctypes.c_wchar_p(norm_path),
- None,
- ctypes.pointer(total_bytes),
- ctypes.pointer(free_bytes))
- if retcode == 0:
- LOG.error(_LE("Could not get share %s capacity info.") %
- smbfs_share)
- return 0, 0
- return total_bytes.value, free_bytes.value
+++ /dev/null
-# Copyright (c) 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 re
-import sys
-
-from oslo_config import cfg
-from oslo_log import log as logging
-from oslo_utils import units
-
-from cinder import exception
-from cinder.i18n import _
-from cinder.image import image_utils
-from cinder.openstack.common import fileutils
-from cinder import utils
-from cinder.volume.drivers import smbfs
-from cinder.volume.drivers.windows import remotefs
-from cinder.volume.drivers.windows import vhdutils
-
-VERSION = '1.0.0'
-
-LOG = logging.getLogger(__name__)
-
-CONF = cfg.CONF
-CONF.set_default('smbfs_shares_config', r'C:\OpenStack\smbfs_shares.txt')
-CONF.set_default('smbfs_mount_point_base', r'C:\OpenStack\_mnt')
-CONF.set_default('smbfs_default_volume_format', 'vhd')
-
-
-class WindowsSmbfsDriver(smbfs.SmbfsDriver):
- VERSION = VERSION
-
- def __init__(self, *args, **kwargs):
- super(WindowsSmbfsDriver, self).__init__(*args, **kwargs)
- self.base = getattr(self.configuration,
- 'smbfs_mount_point_base',
- CONF.smbfs_mount_point_base)
- opts = getattr(self.configuration,
- 'smbfs_mount_options',
- CONF.smbfs_mount_options)
- self._remotefsclient = remotefs.WindowsRemoteFsClient(
- 'cifs', root_helper=None, smbfs_mount_point_base=self.base,
- smbfs_mount_options=opts)
- self.vhdutils = vhdutils.VHDUtils()
-
- def do_setup(self, context):
- self._check_os_platform()
- super(WindowsSmbfsDriver, self).do_setup(context)
-
- def _check_os_platform(self):
- if sys.platform != 'win32':
- _msg = _("This system platform (%s) is not supported. This "
- "driver supports only Win32 platforms.") % sys.platform
- raise exception.SmbfsException(_msg)
-
- def _do_create_volume(self, volume):
- volume_path = self.local_path(volume)
- volume_format = self.get_volume_format(volume)
- volume_size_bytes = volume['size'] * units.Gi
-
- if os.path.exists(volume_path):
- err_msg = _('File already exists at: %s') % volume_path
- raise exception.InvalidVolume(err_msg)
-
- if volume_format not in (self._DISK_FORMAT_VHD,
- self._DISK_FORMAT_VHDX):
- err_msg = _("Unsupported volume format: %s ") % volume_format
- raise exception.InvalidVolume(err_msg)
-
- self.vhdutils.create_dynamic_vhd(volume_path, volume_size_bytes)
-
- def _ensure_share_mounted(self, smbfs_share):
- mnt_options = {}
- if self.shares.get(smbfs_share) is not None:
- mnt_flags = self.shares[smbfs_share]
- mnt_options = self.parse_options(mnt_flags)[1]
- self._remotefsclient.mount(smbfs_share, mnt_options)
-
- def _delete(self, path):
- fileutils.delete_if_exists(path)
-
- def _get_capacity_info(self, smbfs_share):
- """Calculate available space on the SMBFS share.
-
- :param smbfs_share: example //172.18.194.100/var/smbfs
- """
- total_size, total_available = self._remotefsclient.get_capacity_info(
- smbfs_share)
- total_allocated = self._get_total_allocated(smbfs_share)
- return_value = [total_size, total_available, total_allocated]
- LOG.info('Smb share %s Total size %s Total allocated %s'
- % (smbfs_share, total_size, total_allocated))
- return [float(x) for x in return_value]
-
- def _get_total_allocated(self, smbfs_share):
- elements = os.listdir(smbfs_share)
- total_allocated = 0
- for element in elements:
- element_path = os.path.join(smbfs_share, element)
- if not self._remotefsclient.is_symlink(element_path):
- if "snapshot" in element:
- continue
- if re.search(r'\.vhdx?$', element):
- total_allocated += self.vhdutils.get_vhd_size(
- element_path)['VirtualSize']
- continue
- if os.path.isdir(element_path):
- total_allocated += self._get_total_allocated(element_path)
- continue
- total_allocated += os.path.getsize(element_path)
-
- return total_allocated
-
- def _img_commit(self, snapshot_path):
- self.vhdutils.merge_vhd(snapshot_path)
- self._delete(snapshot_path)
-
- def _rebase_img(self, image, backing_file, volume_format):
- # Relative path names are not supported in this case.
- image_dir = os.path.dirname(image)
- backing_file_path = os.path.join(image_dir, backing_file)
- self.vhdutils.reconnect_parent(image, backing_file_path)
-
- def _qemu_img_info(self, path, volume_name=None):
- # This code expects to deal only with relative filenames.
- # As this method is needed by the upper class and qemu-img does
- # not fully support vhdx images, for the moment we'll use Win32 API
- # for retrieving image information.
- parent_path = self.vhdutils.get_vhd_parent_path(path)
- file_format = os.path.splitext(path)[1][1:].lower()
-
- if parent_path:
- backing_file_name = os.path.split(parent_path)[1].lower()
- else:
- backing_file_name = None
-
- class ImageInfo(object):
- def __init__(self, image, backing_file):
- self.image = image
- self.backing_file = backing_file
- self.file_format = file_format
-
- return ImageInfo(os.path.basename(path),
- backing_file_name)
-
- def _do_create_snapshot(self, snapshot, backing_file, new_snap_path):
- backing_file_full_path = os.path.join(
- self._local_volume_dir(snapshot['volume']),
- backing_file)
- self.vhdutils.create_differencing_vhd(new_snap_path,
- backing_file_full_path)
-
- def _do_extend_volume(self, volume_path, size_gb):
- self.vhdutils.resize_vhd(volume_path, size_gb * units.Gi)
-
- @utils.synchronized('smbfs', external=False)
- def copy_volume_to_image(self, context, volume, image_service, image_meta):
- """Copy the volume to the specified image."""
-
- # If snapshots exist, flatten to a temporary image, and upload it
-
- active_file = self.get_active_image_from_info(volume)
- active_file_path = os.path.join(self._local_volume_dir(volume),
- active_file)
- backing_file = self.vhdutils.get_vhd_parent_path(active_file_path)
- root_file_fmt = self.get_volume_format(volume)
-
- temp_path = None
-
- try:
- if backing_file or root_file_fmt == self._DISK_FORMAT_VHDX:
- temp_file_name = '%s.temp_image.%s.%s' % (
- volume['id'],
- image_meta['id'],
- self._DISK_FORMAT_VHD)
- temp_path = os.path.join(self._local_volume_dir(volume),
- temp_file_name)
-
- self.vhdutils.convert_vhd(active_file_path, temp_path)
- upload_path = temp_path
- else:
- upload_path = active_file_path
-
- image_utils.upload_volume(context,
- image_service,
- image_meta,
- upload_path,
- self._DISK_FORMAT_VHD)
- finally:
- if temp_path:
- self._delete(temp_path)
-
- def copy_image_to_volume(self, context, volume, image_service, image_id):
- """Fetch the image from image_service and write it to the volume."""
- volume_format = self.get_volume_format(volume, qemu_format=True)
- image_meta = image_service.show(context, image_id)
-
- fetch_format = volume_format
- fetch_path = self.local_path(volume)
- self._delete(fetch_path)
- qemu_version = self.get_qemu_version()
-
- needs_conversion = False
-
- if (qemu_version < [1, 7] and (
- volume_format == self._DISK_FORMAT_VHDX and
- image_meta['disk_format'] != self._DISK_FORMAT_VHDX)):
- needs_conversion = True
- fetch_format = 'vpc'
- temp_file_name = '%s.temp_image.%s.%s' % (
- volume['id'],
- image_meta['id'],
- self._DISK_FORMAT_VHD)
- fetch_path = os.path.join(self._local_volume_dir(volume),
- temp_file_name)
-
- image_utils.fetch_to_volume_format(
- context, image_service, image_id,
- fetch_path, fetch_format,
- self.configuration.volume_dd_blocksize)
-
- if needs_conversion:
- self.vhdutils.convert_vhd(fetch_path, self.local_path(volume))
- self._delete(fetch_path)
-
- self.vhdutils.resize_vhd(self.local_path(volume),
- volume['size'] * units.Gi)
-
- def _copy_volume_from_snapshot(self, snapshot, volume, volume_size):
- """Copy data from snapshot to destination volume."""
-
- LOG.debug("snapshot: %(snap)s, volume: %(vol)s, "
- "volume_size: %(size)s" %
- {'snap': snapshot['id'],
- 'vol': volume['id'],
- 'size': snapshot['volume_size']})
-
- info_path = self._local_path_volume_info(snapshot['volume'])
- snap_info = self._read_info_file(info_path)
- vol_dir = self._local_volume_dir(snapshot['volume'])
-
- forward_file = snap_info[snapshot['id']]
- forward_path = os.path.join(vol_dir, forward_file)
-
- # Find the file which backs this file, which represents the point
- # when this snapshot was created.
- img_info = self._qemu_img_info(forward_path)
- snapshot_path = os.path.join(vol_dir, img_info.backing_file)
-
- volume_path = self.local_path(volume)
- self._delete(volume_path)
- self.vhdutils.convert_vhd(snapshot_path,
- volume_path)
- self.vhdutils.resize_vhd(volume_path, volume_size * units.Gi)