summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2011-12-16 17:35:10 +0000
committerGerrit Code Review <review@openstack.org>2011-12-16 17:35:10 +0000
commit874a20131856ec4e96664f0a4980d5b8ae6f9f5e (patch)
treea0abdfd760bd2164cdbd35ee6a517d2e6104a827
parent5bec325dca4601c878ffeed70e72bd4611fd3f02 (diff)
parentbaf7e02f29600e79eacb6c0f747075afeb74fdd5 (diff)
Merge "Fix scheduler error handler"
-rw-r--r--nova/compute/api.py2
-rw-r--r--nova/scheduler/chance.py5
-rw-r--r--nova/scheduler/distributed_scheduler.py7
-rw-r--r--nova/scheduler/driver.py8
-rw-r--r--nova/scheduler/manager.py29
-rw-r--r--nova/scheduler/simple.py4
-rw-r--r--nova/tests/scheduler/test_scheduler.py31
7 files changed, 70 insertions, 16 deletions
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 3b79e660d..e939de62c 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -310,7 +310,7 @@ class API(base.Base):
context, instance_type, image, base_options,
security_group, block_device_mapping)
# Tells scheduler we created the instance already.
- base_options['id'] = instance['id']
+ base_options['uuid'] = instance['uuid']
rpc_method = rpc.cast
else:
# We need to wait for the scheduler to create the instance
diff --git a/nova/scheduler/chance.py b/nova/scheduler/chance.py
index fe47e4f54..2995bda70 100644
--- a/nova/scheduler/chance.py
+++ b/nova/scheduler/chance.py
@@ -74,7 +74,10 @@ class ChanceScheduler(driver.Scheduler):
driver.cast_to_compute_host(context, host,
'run_instance', instance_uuid=instance['uuid'], **kwargs)
instances.append(driver.encode_instance(instance))
-
+ # So if we loop around, create_instance_db_entry will actually
+ # create a new entry, instead of assume it's been created
+ # already
+ del request_spec['instance_properties']['uuid']
return instances
def schedule_prep_resize(self, context, request_spec, *args, **kwargs):
diff --git a/nova/scheduler/distributed_scheduler.py b/nova/scheduler/distributed_scheduler.py
index 888594731..1d149a139 100644
--- a/nova/scheduler/distributed_scheduler.py
+++ b/nova/scheduler/distributed_scheduler.py
@@ -173,7 +173,12 @@ class DistributedScheduler(driver.Scheduler):
instance = self.create_instance_db_entry(context, request_spec)
driver.cast_to_compute_host(context, weighted_host.host,
'run_instance', instance_uuid=instance['uuid'], **kwargs)
- return driver.encode_instance(instance, local=True)
+ inst = driver.encode_instance(instance, local=True)
+ # So if another instance is created, create_instance_db_entry will
+ # actually create a new entry, instead of assume it's been created
+ # already
+ del request_spec['instance_properties']['uuid']
+ return inst
def _make_weighted_host_from_blob(self, blob):
"""Returns the decrypted blob as a WeightedHost object
diff --git a/nova/scheduler/driver.py b/nova/scheduler/driver.py
index 8c7945200..85acf6a09 100644
--- a/nova/scheduler/driver.py
+++ b/nova/scheduler/driver.py
@@ -147,9 +147,9 @@ class Scheduler(object):
def create_instance_db_entry(self, context, request_spec):
"""Create instance DB entry based on request_spec"""
base_options = request_spec['instance_properties']
- if base_options.get('id'):
+ if base_options.get('uuid'):
# Instance was already created before calling scheduler
- return db.instance_get(context, base_options['id'])
+ return db.instance_get_by_uuid(context, base_options['uuid'])
image = request_spec['image']
instance_type = request_spec.get('instance_type')
security_group = request_spec.get('security_group', 'default')
@@ -158,6 +158,10 @@ class Scheduler(object):
instance = self.compute_api.create_db_entry_for_new_instance(
context, instance_type, image, base_options,
security_group, block_device_mapping)
+ # NOTE(comstud): This needs to be set for the generic exception
+ # checking in scheduler manager, so that it'll set this instance
+ # to ERROR properly.
+ base_options['uuid'] = instance['uuid']
return instance
def schedule(self, context, topic, method, *_args, **_kwargs):
diff --git a/nova/scheduler/manager.py b/nova/scheduler/manager.py
index 38dda9931..7edc4e4f2 100644
--- a/nova/scheduler/manager.py
+++ b/nova/scheduler/manager.py
@@ -108,18 +108,29 @@ class SchedulerManager(manager.Manager):
with utils.save_and_reraise_exception():
self._set_instance_error(method, context, ex, *args, **kwargs)
- # NOTE (David Subiros) : If the exception is raised ruing run_instance
- # method, the DB record probably does not exist yet.
+ # NOTE (David Subiros) : If the exception is raised during run_instance
+ # method, we may or may not have an instance_id
def _set_instance_error(self, method, context, ex, *args, **kwargs):
"""Sets VM to Error state"""
LOG.warning(_("Failed to schedule_%(method)s: %(ex)s") % locals())
- if method == "start_instance" or method == "run_instance":
- instance_id = kwargs['instance_id']
- if instance_id:
- LOG.warning(_("Setting instance %(instance_id)s to "
- "ERROR state.") % locals())
- db.instance_update(context, instance_id,
- {'vm_state': vm_states.ERROR})
+ if method != "start_instance" and method != "run_instance":
+ return
+ # FIXME(comstud): Clean this up after fully on UUIDs.
+ instance_id = kwargs.get('instance_uuid', kwargs.get('instance_id'))
+ if not instance_id:
+ # FIXME(comstud): We should make this easier. run_instance
+ # only sends a request_spec, and an instance may or may not
+ # have been created in the API (or scheduler) already. If it
+ # was created, there's a 'uuid' set in the instance_properties
+ # of the request_spec.
+ request_spec = kwargs.get('request_spec', {})
+ properties = request_spec.get('instance_properties', {})
+ instance_id = properties.get('uuid', {})
+ if instance_id:
+ LOG.warning(_("Setting instance %(instance_id)s to "
+ "ERROR state.") % locals())
+ db.instance_update(context, instance_id,
+ {'vm_state': vm_states.ERROR})
# NOTE (masumotok) : This method should be moved to nova.api.ec2.admin.
# Based on bexar design summit discussion,
diff --git a/nova/scheduler/simple.py b/nova/scheduler/simple.py
index 6fed16841..dfd2115f3 100644
--- a/nova/scheduler/simple.py
+++ b/nova/scheduler/simple.py
@@ -82,6 +82,10 @@ class SimpleScheduler(chance.ChanceScheduler):
driver.cast_to_compute_host(context, host, 'run_instance',
instance_uuid=instance_ref['uuid'], **_kwargs)
instances.append(driver.encode_instance(instance_ref))
+ # So if we loop around, create_instance_db_entry will actually
+ # create a new entry, instead of assume it's been created
+ # already
+ del request_spec['instance_properties']['uuid']
return instances
def schedule_start_instance(self, context, instance_id, *_args, **_kwargs):
diff --git a/nova/tests/scheduler/test_scheduler.py b/nova/tests/scheduler/test_scheduler.py
index c0fce0fe3..57218fca3 100644
--- a/nova/tests/scheduler/test_scheduler.py
+++ b/nova/tests/scheduler/test_scheduler.py
@@ -113,6 +113,7 @@ def _fake_create_instance_db_entry(simple_self, context, request_spec):
instance = _create_instance_from_spec(request_spec)
global instance_uuids
instance_uuids.append(instance['uuid'])
+ request_spec['instance_properties']['uuid'] = instance['uuid']
return instance
@@ -236,15 +237,41 @@ class SchedulerTestCase(test.TestCase):
scheduler = manager.SchedulerManager()
ins_ref = _create_instance(task_state=task_states.STARTING,
vm_state=vm_states.STOPPED)
- self.stubs = stubout.StubOutForTesting()
self.stubs.Set(TestDriver, 'schedule', NoValidHost_raiser)
- self.mox.StubOutWithMock(rpc, 'cast', use_mock_anything=True)
ctxt = context.get_admin_context()
scheduler.start_instance(ctxt, 'topic', instance_id=ins_ref['id'])
# assert that the instance goes to ERROR state
self._assert_state({'vm_state': vm_states.ERROR,
'task_state': task_states.STARTING})
+ def test_no_valid_host_exception_on_run_with_id(self):
+ """check the vm goes to ERROR state if run_instance fails"""
+
+ def NoValidHost_raiser(context, topic, *args, **kwargs):
+ raise exception.NoValidHost(_("Test NoValidHost exception"))
+ scheduler = manager.SchedulerManager()
+ ins_ref = _create_instance(task_state=task_states.STARTING,
+ vm_state=vm_states.STOPPED)
+ self.stubs.Set(TestDriver, 'schedule', NoValidHost_raiser)
+ ctxt = context.get_admin_context()
+ request_spec = {'instance_properties': {'uuid': ins_ref['uuid']}}
+ scheduler.run_instance(ctxt, 'topic', request_spec=request_spec)
+ # assert that the instance goes to ERROR state
+ self._assert_state({'vm_state': vm_states.ERROR,
+ 'task_state': task_states.STARTING})
+
+ def test_no_valid_host_exception_on_run_without_id(self):
+ """check error handler doesn't raise if instance wasn't created"""
+
+ def NoValidHost_raiser(context, topic, *args, **kwargs):
+ raise exception.NoValidHost(_("Test NoValidHost exception"))
+ scheduler = manager.SchedulerManager()
+ self.stubs.Set(TestDriver, 'schedule', NoValidHost_raiser)
+ ctxt = context.get_admin_context()
+ request_spec = {'instance_properties': {}}
+ scheduler.run_instance(ctxt, 'topic', request_spec=request_spec)
+ # No error
+
def test_show_host_resources_no_project(self):
"""No instance are running on the given host."""