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:
Lucian Petrut 2017-12-19 13:32:37 +02:00
parent 3478777537
commit aaf41258c5
4 changed files with 104 additions and 0 deletions

View File

@ -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)

View File

@ -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,

View File

@ -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)

View File

@ -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