Merge "Added support for live migration on non-shared storage"
This commit is contained in:
@@ -21,7 +21,7 @@ from oslo_log import log
|
|||||||
import six
|
import six
|
||||||
import voluptuous
|
import voluptuous
|
||||||
|
|
||||||
from watcher._i18n import _
|
from watcher._i18n import _, _LC
|
||||||
from watcher.applier.actions import base
|
from watcher.applier.actions import base
|
||||||
from watcher.common import exception
|
from watcher.common import exception
|
||||||
from watcher.common import nova_helper
|
from watcher.common import nova_helper
|
||||||
@@ -76,6 +76,31 @@ class Migrate(base.BaseAction):
|
|||||||
def src_hypervisor(self):
|
def src_hypervisor(self):
|
||||||
return self.input_parameters.get(self.SRC_HYPERVISOR)
|
return self.input_parameters.get(self.SRC_HYPERVISOR)
|
||||||
|
|
||||||
|
def _live_migrate_instance(self, nova, destination):
|
||||||
|
result = None
|
||||||
|
try:
|
||||||
|
result = nova.live_migrate_instance(instance_id=self.instance_uuid,
|
||||||
|
dest_hostname=destination)
|
||||||
|
except nova_helper.nvexceptions.ClientException as e:
|
||||||
|
if e.code == 400:
|
||||||
|
LOG.debug("Live migration of instance %s failed. "
|
||||||
|
"Trying to live migrate using block migration."
|
||||||
|
% self.instance_uuid)
|
||||||
|
result = nova.live_migrate_instance(
|
||||||
|
instance_id=self.instance_uuid,
|
||||||
|
dest_hostname=destination,
|
||||||
|
block_migration=True)
|
||||||
|
else:
|
||||||
|
LOG.debug("Nova client exception occured while live migrating "
|
||||||
|
"instance %s.Exception: %s" %
|
||||||
|
(self.instance_uuid, e))
|
||||||
|
except Exception:
|
||||||
|
LOG.critical(_LC("Unexpected error occured. Migration failed for"
|
||||||
|
"instance %s. Leaving instance on previous "
|
||||||
|
"host."), self.instance_uuid)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
def migrate(self, destination):
|
def migrate(self, destination):
|
||||||
nova = nova_helper.NovaHelper(osc=self.osc)
|
nova = nova_helper.NovaHelper(osc=self.osc)
|
||||||
LOG.debug("Migrate instance %s to %s", self.instance_uuid,
|
LOG.debug("Migrate instance %s to %s", self.instance_uuid,
|
||||||
@@ -83,8 +108,7 @@ class Migrate(base.BaseAction):
|
|||||||
instance = nova.find_instance(self.instance_uuid)
|
instance = nova.find_instance(self.instance_uuid)
|
||||||
if instance:
|
if instance:
|
||||||
if self.migration_type == 'live':
|
if self.migration_type == 'live':
|
||||||
return nova.live_migrate_instance(
|
return self._live_migrate_instance(nova, destination)
|
||||||
instance_id=self.instance_uuid, dest_hostname=destination)
|
|
||||||
else:
|
else:
|
||||||
raise exception.Invalid(
|
raise exception.Invalid(
|
||||||
message=(_('Migration of type %(migration_type)s is not '
|
message=(_('Migration of type %(migration_type)s is not '
|
||||||
|
|||||||
@@ -157,7 +157,10 @@ class TestMigration(base.TestCase):
|
|||||||
def test_execute_live_migration(self):
|
def test_execute_live_migration(self):
|
||||||
self.m_helper.find_instance.return_value = self.INSTANCE_UUID
|
self.m_helper.find_instance.return_value = self.INSTANCE_UUID
|
||||||
|
|
||||||
self.action.execute()
|
try:
|
||||||
|
self.action.execute()
|
||||||
|
except Exception as exc:
|
||||||
|
self.fail(exc)
|
||||||
|
|
||||||
self.m_helper.live_migrate_instance.assert_called_once_with(
|
self.m_helper.live_migrate_instance.assert_called_once_with(
|
||||||
instance_id=self.INSTANCE_UUID,
|
instance_id=self.INSTANCE_UUID,
|
||||||
@@ -173,3 +176,31 @@ class TestMigration(base.TestCase):
|
|||||||
instance_id=self.INSTANCE_UUID,
|
instance_id=self.INSTANCE_UUID,
|
||||||
dest_hostname="hypervisor1-hostname"
|
dest_hostname="hypervisor1-hostname"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_live_migrate_non_shared_storage_instance(self):
|
||||||
|
self.m_helper.find_instance.return_value = self.INSTANCE_UUID
|
||||||
|
|
||||||
|
self.m_helper.live_migrate_instance.side_effect = [
|
||||||
|
nova_helper.nvexceptions.ClientException(400, "BadRequest"), True]
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.action.execute()
|
||||||
|
except Exception as exc:
|
||||||
|
self.fail(exc)
|
||||||
|
|
||||||
|
self.m_helper.live_migrate_instance.assert_has_calls([
|
||||||
|
mock.call(instance_id=self.INSTANCE_UUID,
|
||||||
|
dest_hostname="hypervisor2-hostname"),
|
||||||
|
mock.call(instance_id=self.INSTANCE_UUID,
|
||||||
|
dest_hostname="hypervisor2-hostname",
|
||||||
|
block_migration=True)
|
||||||
|
])
|
||||||
|
|
||||||
|
expected = [mock.call.first(instance_id=self.INSTANCE_UUID,
|
||||||
|
dest_hostname="hypervisor2-hostname"),
|
||||||
|
mock.call.second(instance_id=self.INSTANCE_UUID,
|
||||||
|
dest_hostname="hypervisor2-hostname",
|
||||||
|
block_migration=True)
|
||||||
|
]
|
||||||
|
self.m_helper.live_migrate_instance.mock_calls == expected
|
||||||
|
self.assertEqual(2, self.m_helper.live_migrate_instance.call_count)
|
||||||
|
|||||||
Reference in New Issue
Block a user