Hyper-V: properly handle UNC instance paths
If the configured instances dir is an UNC path such as \\ip\share\instances_dir, the HyperV driver fails to query the available disk size, as it expects a path containing a drive letter. Also, when attempting to move instance files during live migrations, it will incorrectly try to build the remote path. This change addresses those issues and is part of a bigger series, attempting to fix HyperV shared storage related issues. Change-Id: Ibdb9f7038bf5078867d64aef7fc63974ed8482af Partial-Bug: #1565895
This commit is contained in:
parent
fd1501bcb6
commit
b48ed5217a
|
@ -44,6 +44,7 @@ class HostOpsTestCase(test_base.HyperVBaseTestCase):
|
|||
self._hostops = hostops.HostOps()
|
||||
self._hostops._hostutils = mock.MagicMock()
|
||||
self._hostops._pathutils = mock.MagicMock()
|
||||
self._hostops._diskutils = mock.MagicMock()
|
||||
|
||||
def test_get_cpu_info(self):
|
||||
mock_processors = mock.MagicMock()
|
||||
|
@ -90,13 +91,14 @@ class HostOpsTestCase(test_base.HyperVBaseTestCase):
|
|||
self._hostops._hostutils.get_memory_info.assert_called_once_with()
|
||||
self.assertEqual((2, 1, 1), response)
|
||||
|
||||
def test_get_local_hdd_info_gb(self):
|
||||
def test_get_storage_info_gb(self):
|
||||
self._hostops._pathutils.get_instances_dir.return_value = ''
|
||||
self._hostops._hostutils.get_volume_info.return_value = (2 * units.Gi,
|
||||
1 * units.Gi)
|
||||
response = self._hostops._get_local_hdd_info_gb()
|
||||
self._hostops._diskutils.get_disk_capacity.return_value = (
|
||||
2 * units.Gi, 1 * units.Gi)
|
||||
|
||||
response = self._hostops._get_storage_info_gb()
|
||||
self._hostops._pathutils.get_instances_dir.assert_called_once_with()
|
||||
self._hostops._hostutils.get_volume_info.assert_called_once_with('')
|
||||
self._hostops._diskutils.get_disk_capacity.assert_called_once_with('')
|
||||
self.assertEqual((2, 1, 1), response)
|
||||
|
||||
def test_get_hypervisor_version(self):
|
||||
|
@ -135,16 +137,16 @@ class HostOpsTestCase(test_base.HyperVBaseTestCase):
|
|||
@mock.patch.object(hostops.HostOps, '_get_cpu_info')
|
||||
@mock.patch.object(hostops.HostOps, '_get_memory_info')
|
||||
@mock.patch.object(hostops.HostOps, '_get_hypervisor_version')
|
||||
@mock.patch.object(hostops.HostOps, '_get_local_hdd_info_gb')
|
||||
@mock.patch.object(hostops.HostOps, '_get_storage_info_gb')
|
||||
@mock.patch('platform.node')
|
||||
def test_get_available_resource(self, mock_node,
|
||||
mock_get_local_hdd_info_gb,
|
||||
mock_get_storage_info_gb,
|
||||
mock_get_hypervisor_version,
|
||||
mock_get_memory_info, mock_get_cpu_info,
|
||||
mock_get_gpu_info):
|
||||
mock_get_local_hdd_info_gb.return_value = (mock.sentinel.LOCAL_GB,
|
||||
mock.sentinel.LOCAL_GB_FREE,
|
||||
mock.sentinel.LOCAL_GB_USED)
|
||||
mock_get_storage_info_gb.return_value = (mock.sentinel.LOCAL_GB,
|
||||
mock.sentinel.LOCAL_GB_FREE,
|
||||
mock.sentinel.LOCAL_GB_USED)
|
||||
mock_get_memory_info.return_value = (mock.sentinel.MEMORY_MB,
|
||||
mock.sentinel.MEMORY_MB_FREE,
|
||||
mock.sentinel.MEMORY_MB_USED)
|
||||
|
|
|
@ -72,6 +72,44 @@ class PathUtilsTestCase(test_base.HyperVBaseTestCase):
|
|||
self.fake_instance_name)
|
||||
self.assertIsNone(configdrive_path)
|
||||
|
||||
def test_get_instances_dir_local(self):
|
||||
self.flags(instances_path=self.fake_instance_dir)
|
||||
instances_dir = self._pathutils.get_instances_dir()
|
||||
|
||||
self.assertEqual(self.fake_instance_dir, instances_dir)
|
||||
|
||||
def test_get_instances_dir_remote_instance_share(self):
|
||||
# The Hyper-V driver allows using a pre-configured share exporting
|
||||
# the instances dir. The same share name should be used across nodes.
|
||||
fake_instances_dir_share = 'fake_instances_dir_share'
|
||||
fake_remote = 'fake_remote'
|
||||
expected_instance_dir = r'\\%s\%s' % (fake_remote,
|
||||
fake_instances_dir_share)
|
||||
|
||||
self.flags(instances_path_share=fake_instances_dir_share,
|
||||
group='hyperv')
|
||||
instances_dir = self._pathutils.get_instances_dir(
|
||||
remote_server=fake_remote)
|
||||
self.assertEqual(expected_instance_dir, instances_dir)
|
||||
|
||||
def test_get_instances_dir_administrative_share(self):
|
||||
self.flags(instances_path=r'C:\fake_instance_dir')
|
||||
fake_remote = 'fake_remote'
|
||||
expected_instance_dir = r'\\fake_remote\C$\fake_instance_dir'
|
||||
|
||||
instances_dir = self._pathutils.get_instances_dir(
|
||||
remote_server=fake_remote)
|
||||
self.assertEqual(expected_instance_dir, instances_dir)
|
||||
|
||||
def test_get_instances_dir_unc_path(self):
|
||||
fake_instance_dir = r'\\fake_addr\fake_share\fake_instance_dir'
|
||||
self.flags(instances_path=fake_instance_dir)
|
||||
fake_remote = 'fake_remote'
|
||||
|
||||
instances_dir = self._pathutils.get_instances_dir(
|
||||
remote_server=fake_remote)
|
||||
self.assertEqual(fake_instance_dir, instances_dir)
|
||||
|
||||
@mock.patch('os.path.join')
|
||||
def test_get_instances_sub_dir(self, fake_path_join):
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
Management class for host operations.
|
||||
"""
|
||||
import datetime
|
||||
import os
|
||||
import platform
|
||||
import time
|
||||
|
||||
|
@ -41,6 +40,7 @@ LOG = logging.getLogger(__name__)
|
|||
|
||||
class HostOps(object):
|
||||
def __init__(self):
|
||||
self._diskutils = utilsfactory.get_diskutils()
|
||||
self._hostutils = utilsfactory.get_hostutils()
|
||||
self._pathutils = pathutils.PathUtils()
|
||||
|
||||
|
@ -80,9 +80,10 @@ class HostOps(object):
|
|||
free_mem_mb = free_mem_kb // 1024
|
||||
return (total_mem_mb, free_mem_mb, total_mem_mb - free_mem_mb)
|
||||
|
||||
def _get_local_hdd_info_gb(self):
|
||||
drive = os.path.splitdrive(self._pathutils.get_instances_dir())[0]
|
||||
(size, free_space) = self._hostutils.get_volume_info(drive)
|
||||
def _get_storage_info_gb(self):
|
||||
instances_dir = self._pathutils.get_instances_dir()
|
||||
(size, free_space) = self._diskutils.get_disk_capacity(
|
||||
instances_dir)
|
||||
|
||||
total_gb = size // units.Gi
|
||||
free_gb = free_space // units.Gi
|
||||
|
@ -138,7 +139,7 @@ class HostOps(object):
|
|||
|
||||
(total_hdd_gb,
|
||||
free_hdd_gb,
|
||||
used_hdd_gb) = self._get_local_hdd_info_gb()
|
||||
used_hdd_gb) = self._get_storage_info_gb()
|
||||
|
||||
cpu_info = self._get_cpu_info()
|
||||
cpu_topology = cpu_info['topology']
|
||||
|
|
|
@ -38,7 +38,7 @@ class PathUtils(pathutils.PathUtils):
|
|||
def get_instances_dir(self, remote_server=None):
|
||||
local_instance_path = os.path.normpath(CONF.instances_path)
|
||||
|
||||
if remote_server:
|
||||
if remote_server and not local_instance_path.startswith(r'\\'):
|
||||
if CONF.hyperv.instances_path_share:
|
||||
path = CONF.hyperv.instances_path_share
|
||||
else:
|
||||
|
|
Loading…
Reference in New Issue