Merge "Handle compute node not available for live migration"
This commit is contained in:
commit
d980805880
@ -282,6 +282,8 @@ class AdminActionsController(wsgi.Controller):
|
||||
instance = self.compute_api.get(context, id)
|
||||
self.compute_api.live_migrate(context, instance, block_migration,
|
||||
disk_over_commit, host)
|
||||
except exception.ComputeServiceUnavailable as ex:
|
||||
raise exc.HTTPBadRequest(explanation=str(ex))
|
||||
except Exception:
|
||||
msg = _("Live migration of instance %(id)s to host %(host)s"
|
||||
" failed") % locals()
|
||||
|
@ -344,7 +344,7 @@ class ComputeResourcesUnavailable(ServiceUnavailable):
|
||||
|
||||
|
||||
class ComputeServiceUnavailable(ServiceUnavailable):
|
||||
message = _("Compute service is unavailable at this time.")
|
||||
message = _("Compute service of %(host)s is unavailable at this time.")
|
||||
|
||||
|
||||
class UnableToMigrateToSelf(Invalid):
|
||||
|
@ -222,7 +222,10 @@ class Scheduler(object):
|
||||
"""
|
||||
|
||||
# Checking dest exists and compute node.
|
||||
dservice_ref = db.service_get_by_compute_host(context, dest)
|
||||
try:
|
||||
dservice_ref = db.service_get_by_compute_host(context, dest)
|
||||
except exception.NotFound:
|
||||
raise exception.ComputeServiceUnavailable(host=dest)
|
||||
|
||||
# Checking dest host is alive.
|
||||
if not self.servicegroup_api.service_is_up(dservice_ref):
|
||||
|
@ -24,6 +24,7 @@ Scheduler Service
|
||||
import sys
|
||||
|
||||
from nova.compute import rpcapi as compute_rpcapi
|
||||
from nova.compute import task_states
|
||||
from nova.compute import utils as compute_utils
|
||||
from nova.compute import vm_states
|
||||
from nova.conductor import api as conductor_api
|
||||
@ -92,6 +93,16 @@ class SchedulerManager(manager.Manager):
|
||||
return self.driver.schedule_live_migration(
|
||||
context, instance, dest,
|
||||
block_migration, disk_over_commit)
|
||||
except exception.ComputeServiceUnavailable as ex:
|
||||
request_spec = {'instance_properties': {
|
||||
'uuid': instance['uuid'], },
|
||||
}
|
||||
with excutils.save_and_reraise_exception():
|
||||
self._set_vm_state_and_notify('live_migration',
|
||||
dict(vm_state=instance['vm_state'],
|
||||
task_state=None,
|
||||
expected_task_state=task_states.MIGRATING,),
|
||||
context, ex, request_spec)
|
||||
except Exception as ex:
|
||||
with excutils.save_and_reraise_exception():
|
||||
self._set_vm_state_and_notify('live_migration',
|
||||
|
@ -64,13 +64,6 @@ def fake_compute_api_get(self, context, instance_id):
|
||||
'task_state': None}
|
||||
|
||||
|
||||
def fake_scheduler_api_live_migration(self, context, dest,
|
||||
block_migration=False,
|
||||
disk_over_commit=False, instance=None,
|
||||
instance_id=None, topic=None):
|
||||
return None
|
||||
|
||||
|
||||
class AdminActionsTest(test.TestCase):
|
||||
|
||||
_actions = ('pause', 'unpause', 'suspend', 'resume', 'migrate',
|
||||
@ -93,9 +86,6 @@ class AdminActionsTest(test.TestCase):
|
||||
self.UUID = uuid.uuid4()
|
||||
for _method in self._methods:
|
||||
self.stubs.Set(compute_api.API, _method, fake_compute_api)
|
||||
self.stubs.Set(scheduler_rpcapi.SchedulerAPI,
|
||||
'live_migration',
|
||||
fake_scheduler_api_live_migration)
|
||||
self.flags(
|
||||
osapi_compute_extension=[
|
||||
'nova.api.openstack.compute.contrib.select_extensions'],
|
||||
@ -150,7 +140,16 @@ class AdminActionsTest(test.TestCase):
|
||||
task_state, expected_task_state):
|
||||
return None
|
||||
|
||||
def fake_scheduler_api_live_migration(self, context, dest,
|
||||
block_migration=False,
|
||||
disk_over_commit=False, instance=None,
|
||||
instance_id=None, topic=None):
|
||||
return None
|
||||
|
||||
self.stubs.Set(compute_api.API, 'update', fake_update)
|
||||
self.stubs.Set(scheduler_rpcapi.SchedulerAPI,
|
||||
'live_migration',
|
||||
fake_scheduler_api_live_migration)
|
||||
|
||||
res = req.get_response(app)
|
||||
self.assertEqual(res.status_int, 202)
|
||||
@ -174,6 +173,44 @@ class AdminActionsTest(test.TestCase):
|
||||
res = req.get_response(app)
|
||||
self.assertEqual(res.status_int, 400)
|
||||
|
||||
def test_migrate_live_compute_service_unavailable(self):
|
||||
ctxt = context.get_admin_context()
|
||||
ctxt.user_id = 'fake'
|
||||
ctxt.project_id = 'fake'
|
||||
ctxt.is_admin = True
|
||||
app = fakes.wsgi_app(fake_auth_context=ctxt, init_only=('servers',))
|
||||
req = webob.Request.blank('/v2/fake/servers/%s/action' % self.UUID)
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps({
|
||||
'os-migrateLive': {
|
||||
'host': 'hostname',
|
||||
'block_migration': False,
|
||||
'disk_over_commit': False,
|
||||
}
|
||||
})
|
||||
req.content_type = 'application/json'
|
||||
|
||||
def fake_update(inst, context, instance,
|
||||
task_state, expected_task_state):
|
||||
return None
|
||||
|
||||
def fake_scheduler_api_live_migration(context, dest,
|
||||
block_migration=False,
|
||||
disk_over_commit=False, instance=None,
|
||||
instance_id=None, topic=None):
|
||||
raise exception.ComputeServiceUnavailable(host='host')
|
||||
|
||||
self.stubs.Set(compute_api.API, 'update', fake_update)
|
||||
self.stubs.Set(scheduler_rpcapi.SchedulerAPI,
|
||||
'live_migration',
|
||||
fake_scheduler_api_live_migration)
|
||||
|
||||
res = req.get_response(app)
|
||||
self.assertEqual(res.status_int, 400)
|
||||
self.assertIn(
|
||||
unicode(exception.ComputeServiceUnavailable(host='host')),
|
||||
res.body)
|
||||
|
||||
|
||||
class CreateBackupTests(test.TestCase):
|
||||
|
||||
|
@ -24,6 +24,7 @@ import mox
|
||||
from nova.compute import api as compute_api
|
||||
from nova.compute import power_state
|
||||
from nova.compute import rpcapi as compute_rpcapi
|
||||
from nova.compute import task_states
|
||||
from nova.compute import utils as compute_utils
|
||||
from nova.compute import vm_states
|
||||
from nova.conductor import api as conductor_api
|
||||
@ -199,6 +200,38 @@ class SchedulerManagerTestCase(test.TestCase):
|
||||
self.manager.run_instance(self.context, request_spec,
|
||||
None, None, None, None, {})
|
||||
|
||||
def test_live_migration_compute_service_notavailable(self):
|
||||
inst = {"uuid": "fake-instance-id",
|
||||
"vm_state": vm_states.ACTIVE,
|
||||
"task_state": task_states.MIGRATING, }
|
||||
|
||||
dest = 'fake_host'
|
||||
block_migration = False
|
||||
disk_over_commit = False
|
||||
|
||||
self._mox_schedule_method_helper('schedule_live_migration')
|
||||
self.mox.StubOutWithMock(compute_utils, 'add_instance_fault_from_exc')
|
||||
self.mox.StubOutWithMock(db, 'instance_update_and_get_original')
|
||||
|
||||
self.manager.driver.schedule_live_migration(self.context,
|
||||
inst, dest, block_migration, disk_over_commit).AndRaise(
|
||||
exception.ComputeServiceUnavailable(host="src"))
|
||||
db.instance_update_and_get_original(self.context, inst["uuid"],
|
||||
{"vm_state": inst['vm_state'],
|
||||
"task_state": None,
|
||||
"expected_task_state": task_states.MIGRATING,
|
||||
}).AndReturn((inst, inst))
|
||||
compute_utils.add_instance_fault_from_exc(self.context,
|
||||
mox.IsA(conductor_api.LocalAPI), inst,
|
||||
mox.IsA(exception.ComputeServiceUnavailable),
|
||||
mox.IgnoreArg())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
self.assertRaises(exception.ComputeServiceUnavailable,
|
||||
self.manager.live_migration,
|
||||
self.context, inst, dest, block_migration,
|
||||
disk_over_commit)
|
||||
|
||||
def test_prep_resize_no_valid_host_back_in_active_state(self):
|
||||
fake_instance_uuid = 'fake-instance-id'
|
||||
fake_instance = {'uuid': fake_instance_uuid}
|
||||
@ -510,6 +543,29 @@ class SchedulerTestCase(test.TestCase):
|
||||
block_migration=block_migration,
|
||||
disk_over_commit=disk_over_commit)
|
||||
|
||||
def test_live_migration_compute_dest_not_exist(self):
|
||||
# Raise exception when dest compute node does not exist.
|
||||
|
||||
self.mox.StubOutWithMock(self.driver, '_live_migration_src_check')
|
||||
self.mox.StubOutWithMock(db, 'service_get_by_compute_host')
|
||||
|
||||
dest = 'fake_host2'
|
||||
block_migration = False
|
||||
disk_over_commit = False
|
||||
instance = self._live_migration_instance()
|
||||
|
||||
self.driver._live_migration_src_check(self.context, instance)
|
||||
# Compute down
|
||||
db.service_get_by_compute_host(self.context,
|
||||
dest).AndRaise(exception.NotFound())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
self.assertRaises(exception.ComputeServiceUnavailable,
|
||||
self.driver.schedule_live_migration, self.context,
|
||||
instance=instance, dest=dest,
|
||||
block_migration=block_migration,
|
||||
disk_over_commit=disk_over_commit)
|
||||
|
||||
def test_live_migration_compute_dest_not_alive(self):
|
||||
# Raise exception when dest compute node is not alive.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user