Merge "Hyper-V: properly handle loopback shares" into stable/mitaka

This commit is contained in:
Jenkins 2016-05-26 09:48:47 +00:00 committed by Gerrit Code Review
commit 832d96bd2e
4 changed files with 83 additions and 6 deletions

View File

@ -19,11 +19,15 @@ import time
from nova import exception
from os_win.utils import pathutils
from os_win import utilsfactory
from oslo_config import cfg
from oslo_log import log as logging
from hyperv.i18n import _
from hyperv.i18n import _, _LE
from hyperv.nova import constants
LOG = logging.getLogger(__name__)
hyperv_opts = [
cfg.StrOpt('instances_path_share',
default="",
@ -47,6 +51,10 @@ ERROR_INVALID_NAME = 123
# the os_win.pathutils.PathUtils class into this PathUtils.
class PathUtils(pathutils.PathUtils):
def __init__(self):
super(PathUtils, self).__init__()
self._smbutils = utilsfactory.get_smbutils()
def get_instances_dir(self, remote_server=None):
local_instance_path = os.path.normpath(CONF.instances_path)
@ -190,3 +198,18 @@ class PathUtils(pathutils.PathUtils):
shared_storage = os.path.exists(src_path)
return shared_storage
def get_loopback_share_path(self, share_address):
# In case of loopback shares, we use the local share path.
share_name = share_address.strip('\\').split('\\')[1]
local_share_path = self._smbutils.get_smb_share_path(
share_name)
try:
if local_share_path and self.check_dirs_shared_storage(
local_share_path, share_address):
return local_share_path
except Exception:
err_msg = _LE("Got exception while verifying if share %s "
"is local, thus it will not be handled as a "
"loopback share.")
LOG.exception(err_msg)

View File

@ -39,6 +39,7 @@ import six
from hyperv.i18n import _, _LI, _LE, _LW
from hyperv.nova import constants
from hyperv.nova import pathutils
LOG = logging.getLogger(__name__)
@ -498,6 +499,7 @@ class SMBFSVolumeDriver(BaseVolumeDriver):
_is_block_dev = False
def __init__(self):
self._pathutils = pathutils.PathUtils()
self._smbutils = utilsfactory.get_smbutils()
self._username_regex = re.compile(r'user(?:name)?=([^, ]+)')
self._password_regex = re.compile(r'pass(?:word)?=([^, ]+)')
@ -532,10 +534,17 @@ class SMBFSVolumeDriver(BaseVolumeDriver):
self._smbutils.unmount_smb_share(export_path)
def _get_export_path(self, connection_info):
return connection_info['data']['export'].replace('/', '\\')
return connection_info[
'data']['export'].replace('/', '\\').rstrip('\\')
def _get_disk_path(self, connection_info):
export = self._get_export_path(connection_info)
# In case of loopback shares, we use the local share path.
local_share_path = self._pathutils.get_loopback_share_path(export)
if local_share_path:
export = local_share_path
disk_name = connection_info['data']['name']
disk_path = os.path.join(export, disk_name)
return disk_path

View File

@ -15,6 +15,7 @@
import os
import time
import ddt
import mock
from nova import exception
from six.moves import builtins
@ -24,6 +25,7 @@ from hyperv.nova import pathutils
from hyperv.tests.unit import test_base
@ddt.ddt
class PathUtilsTestCase(test_base.HyperVBaseTestCase):
"""Unit tests for the Hyper-V PathUtils class."""
@ -34,6 +36,8 @@ class PathUtilsTestCase(test_base.HyperVBaseTestCase):
self._pathutils = pathutils.PathUtils()
self._pathutils._smb_conn_attr = mock.MagicMock()
self._pathutils._smbutils = mock.MagicMock()
self._smbutils = self._pathutils._smbutils
def _mock_lookup_configdrive_path(self, ext, rescue=False):
self._pathutils.get_instance_dir = mock.MagicMock(
@ -172,3 +176,34 @@ class PathUtilsTestCase(test_base.HyperVBaseTestCase):
mock_named_tempfile.assert_called_once_with(dir=fake_dest_dir)
mock_exists.assert_called_once_with(expected_src_tmp_path)
@ddt.data({},
{'local_share_path': None},
{'is_same_dir': True},
{'raised_exc': Exception})
@ddt.unpack
@mock.patch.object(pathutils.PathUtils, 'check_dirs_shared_storage')
def test_get_loopback_share_path(
self, mock_check_dirs_shared_storage,
local_share_path=mock.sentinel.local_share_path,
is_same_dir=False, raised_exc=None):
self._smbutils.get_smb_share_path.return_value = local_share_path
mock_check_dirs_shared_storage.side_effect = (
raised_exc or [is_same_dir])
share_address = r'\\1.2.3.4\fake_share'
expected_path = (
local_share_path
if local_share_path and is_same_dir and not raised_exc
else None)
share_path = self._pathutils.get_loopback_share_path(share_address)
self.assertEqual(expected_path, share_path)
self._smbutils.get_smb_share_path.assert_called_once_with(
'fake_share')
if local_share_path:
mock_check_dirs_shared_storage.assert_called_once_with(
local_share_path, share_address)
else:
self.assertFalse(mock_check_dirs_shared_storage.called)

View File

@ -651,6 +651,7 @@ class ISCSIVolumeDriverTestCase(test_base.HyperVBaseTestCase):
mock_get_mounted_disk.assert_called_once_with(mock.sentinel.dev_path)
@ddt.ddt
class SMBFSVolumeDriverTestCase(test_base.HyperVBaseTestCase):
"""Unit tests for the Hyper-V SMBFSVolumeDriver class."""
@ -671,6 +672,9 @@ class SMBFSVolumeDriverTestCase(test_base.HyperVBaseTestCase):
self._volume_driver = volumeops.SMBFSVolumeDriver()
self._volume_driver._vmutils = mock.MagicMock()
self._volume_driver._smbutils = mock.MagicMock()
self._volume_driver._pathutils = mock.MagicMock()
self._smbutils = self._volume_driver._smbutils
self._pathutils = self._volume_driver._pathutils
@mock.patch.object(volumeops.SMBFSVolumeDriver, '_get_disk_path')
def test_get_disk_resource_path(self, mock_get_disk_path):
@ -693,13 +697,19 @@ class SMBFSVolumeDriverTestCase(test_base.HyperVBaseTestCase):
expected = self._FAKE_SHARE.replace('/', '\\')
self.assertEqual(expected, result)
def test_get_disk_path(self):
expected = os.path.join(self._FAKE_SHARE_NORMALIZED,
self._FAKE_DISK_NAME)
@ddt.data(True, False)
def test_get_disk_path(self, is_local):
fake_local_share_path = 'fake_local_share_path' if is_local else None
mock_get_loopback_share_path = self._pathutils.get_loopback_share_path
mock_get_loopback_share_path.return_value = fake_local_share_path
expected = os.path.join(
fake_local_share_path or self._FAKE_SHARE_NORMALIZED,
self._FAKE_DISK_NAME)
disk_path = self._volume_driver._get_disk_path(
self._FAKE_CONNECTION_INFO)
mock_get_loopback_share_path.assert_called_once_with(
self._FAKE_SHARE_NORMALIZED)
self.assertEqual(expected, disk_path)
@mock.patch.object(volumeops.SMBFSVolumeDriver, '_parse_credentials')