Add driver methods checking for shared storage
The driver interface provides public methods that determine if two compute nodes use shared storage. Although we already use a similar mechanism, we do not implement those public driver methods, for which reason the compute manager will wrongfully assume that shared storage is never used. This is not an issue at the moment, as this mechanism is used by the manager only when cleaning up evacuated instances (which we do not currently support) and when reverting migrations (in which case we already have a copy of the instance files in the 'revert dir'). This will become an issue though if we intend to start cleaning up migration files when destroying instances. This change adds the above mentioned public driver methods. Related-Bug: #1724240 Change-Id: I790b39672fd8ffe467fc9d93daf7b38b26103d5d
This commit is contained in:
parent
3478777537
commit
aaf41258c5
|
@ -416,3 +416,21 @@ class HyperVDriver(driver.ComputeDriver):
|
|||
in instance.system_metadata.items()}
|
||||
image_meta["id"] = image_ref
|
||||
return image_meta
|
||||
|
||||
def check_instance_shared_storage_local(self, context, instance):
|
||||
"""Check if instance files located on shared storage.
|
||||
|
||||
This runs check on the destination host, and then calls
|
||||
back to the source host to check the results.
|
||||
|
||||
:param context: security context
|
||||
:param instance: nova.objects.instance.Instance object
|
||||
:returns: A dict containing the tempfile info.
|
||||
"""
|
||||
return self._pathutils.check_instance_shared_storage_local(instance)
|
||||
|
||||
def check_instance_shared_storage_remote(self, context, data):
|
||||
return self._pathutils.check_instance_shared_storage_remote(data)
|
||||
|
||||
def check_instance_shared_storage_cleanup(self, context, data):
|
||||
return self._pathutils.check_instance_shared_storage_cleanup(data)
|
||||
|
|
|
@ -22,6 +22,7 @@ from os_win import exceptions as os_win_exc
|
|||
from os_win.utils import pathutils
|
||||
from os_win import utilsfactory
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import fileutils
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from compute_hyperv.i18n import _
|
||||
|
@ -275,6 +276,25 @@ class PathUtils(pathutils.PathUtils):
|
|||
return self.check_dirs_shared_storage(local_inst_dir,
|
||||
remote_inst_dir)
|
||||
|
||||
def check_instance_shared_storage_local(self, instance):
|
||||
instance_dir = self.get_instance_dir(instance.name)
|
||||
|
||||
fd, tmp_file = tempfile.mkstemp(dir=instance_dir)
|
||||
LOG.debug("Creating tmpfile %s to verify with other "
|
||||
"compute node that the instance is on "
|
||||
"the same shared storage.",
|
||||
tmp_file, instance=instance)
|
||||
os.close(fd)
|
||||
# We're sticking with the same dict key as the libvirt driver.
|
||||
# At some point, this may become a versioned object.
|
||||
return {"filename": tmp_file}
|
||||
|
||||
def check_instance_shared_storage_remote(self, data):
|
||||
return os.path.exists(data['filename'])
|
||||
|
||||
def check_instance_shared_storage_cleanup(self, data):
|
||||
fileutils.delete_if_exists(data["filename"])
|
||||
|
||||
def get_instance_snapshot_dir(self, instance_name=None, instance_dir=None):
|
||||
if instance_name:
|
||||
instance_dir = self.get_instance_dir(instance_name,
|
||||
|
|
|
@ -589,3 +589,33 @@ class HyperVDriverTestCase(test_base.HyperVBaseTestCase):
|
|||
'nova_object.data': {}}
|
||||
|
||||
self._check_recreate_image_meta(mock_image_meta)
|
||||
|
||||
def test_check_instance_shared_storage_local(self):
|
||||
check_local = (
|
||||
self.driver._pathutils.check_instance_shared_storage_local)
|
||||
|
||||
ret_val = self.driver.check_instance_shared_storage_local(
|
||||
mock.sentinel.context, mock.sentinel.instance)
|
||||
|
||||
self.assertEqual(check_local.return_value, ret_val)
|
||||
check_local.assert_called_once_with(mock.sentinel.instance)
|
||||
|
||||
def test_check_instance_shared_storage_remote(self):
|
||||
check_remote = (
|
||||
self.driver._pathutils.check_instance_shared_storage_remote)
|
||||
|
||||
ret_val = self.driver.check_instance_shared_storage_remote(
|
||||
mock.sentinel.context, mock.sentinel.data)
|
||||
|
||||
self.assertEqual(check_remote.return_value, ret_val)
|
||||
check_remote.assert_called_once_with(mock.sentinel.data)
|
||||
|
||||
def test_check_instance_shared_storage_cleanup(self):
|
||||
check_cleanup = (
|
||||
self.driver._pathutils.check_instance_shared_storage_cleanup)
|
||||
|
||||
ret_val = self.driver.check_instance_shared_storage_cleanup(
|
||||
mock.sentinel.context, mock.sentinel.data)
|
||||
|
||||
self.assertEqual(check_cleanup.return_value, ret_val)
|
||||
check_cleanup.assert_called_once_with(mock.sentinel.data)
|
||||
|
|
|
@ -19,6 +19,7 @@ import ddt
|
|||
import mock
|
||||
from nova import exception
|
||||
from os_win import exceptions as os_win_exc
|
||||
from oslo_utils import fileutils
|
||||
from six.moves import builtins
|
||||
|
||||
from compute_hyperv.nova import constants
|
||||
|
@ -400,6 +401,41 @@ class PathUtilsTestCase(test_base.HyperVBaseTestCase):
|
|||
mock_check_dirs_shared_storage.assert_called_once_with(
|
||||
mock.sentinel.local_inst_dir, mock.sentinel.remote_inst_dir)
|
||||
|
||||
@mock.patch.object(os, 'close')
|
||||
@mock.patch('tempfile.mkstemp')
|
||||
@mock.patch.object(pathutils.PathUtils, 'get_instance_dir')
|
||||
def test_check_instance_shared_storage_local(self, mock_get_instance_dir,
|
||||
mock_mkstemp, mock_close):
|
||||
mock_instance = mock.Mock()
|
||||
mock_mkstemp.return_value = (mock.sentinel.tmp_fd,
|
||||
mock.sentinel.tmp_file)
|
||||
|
||||
ret_val = self._pathutils.check_instance_shared_storage_local(
|
||||
mock_instance)
|
||||
exp_ret_val = {'filename': mock.sentinel.tmp_file}
|
||||
|
||||
self.assertEqual(exp_ret_val, ret_val)
|
||||
mock_get_instance_dir.assert_called_once_with(mock_instance.name)
|
||||
mock_mkstemp.assert_called_once_with(
|
||||
dir=mock_get_instance_dir.return_value)
|
||||
mock_close.assert_called_once_with(mock.sentinel.tmp_fd)
|
||||
|
||||
@mock.patch.object(os.path, 'exists')
|
||||
def test_check_instance_shared_storage_remote(self, mock_exists):
|
||||
check_data = dict(filename=mock.sentinel.filename)
|
||||
ret_val = self._pathutils.check_instance_shared_storage_remote(
|
||||
check_data)
|
||||
|
||||
self.assertEqual(mock_exists.return_value, ret_val)
|
||||
|
||||
@mock.patch.object(fileutils, 'delete_if_exists')
|
||||
def test_check_instance_shared_storage_cleanup(self,
|
||||
mock_delete_if_exists):
|
||||
check_data = dict(filename=mock.sentinel.filename)
|
||||
self._pathutils.check_instance_shared_storage_cleanup(check_data)
|
||||
|
||||
mock_delete_if_exists.assert_called_once_with(mock.sentinel.filename)
|
||||
|
||||
@mock.patch.object(pathutils.PathUtils, 'get_instance_dir')
|
||||
def test_get_instance_snapshot_dir(self, mock_get_instance_dir):
|
||||
mock_get_instance_dir.return_value = self.fake_instance_dir
|
||||
|
|
Loading…
Reference in New Issue