Merge "Record instance actions and events"

This commit is contained in:
Jenkins
2013-02-05 01:26:44 +00:00
committed by Gerrit Code Review
4 changed files with 132 additions and 39 deletions

View File

@@ -104,22 +104,26 @@ class SchedulerManager(manager.Manager):
"""Tries to call schedule_run_instance on the driver.
Sets instance vm_state to ERROR on exceptions
"""
try:
return self.driver.schedule_run_instance(context,
request_spec, admin_password, injected_files,
requested_networks, is_first_time, filter_properties)
except exception.NoValidHost as ex:
# don't re-raise
self._set_vm_state_and_notify('run_instance',
{'vm_state': vm_states.ERROR,
'task_state': None},
context, ex, request_spec)
except Exception as ex:
with excutils.save_and_reraise_exception():
instance_uuids = request_spec['instance_uuids']
with compute_utils.EventReporter(context, conductor_api.LocalAPI(),
'schedule', *instance_uuids):
try:
return self.driver.schedule_run_instance(context,
request_spec, admin_password, injected_files,
requested_networks, is_first_time, filter_properties)
except exception.NoValidHost as ex:
# don't re-raise
self._set_vm_state_and_notify('run_instance',
{'vm_state': vm_states.ERROR,
{'vm_state': vm_states.ERROR,
'task_state': None},
context, ex, request_spec)
context, ex, request_spec)
except Exception as ex:
with excutils.save_and_reraise_exception():
self._set_vm_state_and_notify('run_instance',
{'vm_state': vm_states.ERROR,
'task_state': None},
context, ex, request_spec)
def prep_resize(self, context, image, request_spec, filter_properties,
instance, instance_type, reservations):
@@ -127,32 +131,35 @@ class SchedulerManager(manager.Manager):
Sets instance vm_state to ACTIVE on NoHostFound
Sets vm_state to ERROR on other exceptions
"""
try:
kwargs = {
'context': context,
'image': image,
'request_spec': request_spec,
'filter_properties': filter_properties,
'instance': instance,
'instance_type': instance_type,
'reservations': reservations,
}
return self.driver.schedule_prep_resize(**kwargs)
except exception.NoValidHost as ex:
self._set_vm_state_and_notify('prep_resize',
{'vm_state': vm_states.ACTIVE,
'task_state': None},
context, ex, request_spec)
if reservations:
QUOTAS.rollback(context, reservations)
except Exception as ex:
with excutils.save_and_reraise_exception():
instance_uuid = instance['uuid']
with compute_utils.EventReporter(context, conductor_api.LocalAPI(),
'schedule', instance_uuid):
try:
kwargs = {
'context': context,
'image': image,
'request_spec': request_spec,
'filter_properties': filter_properties,
'instance': instance,
'instance_type': instance_type,
'reservations': reservations,
}
return self.driver.schedule_prep_resize(**kwargs)
except exception.NoValidHost as ex:
self._set_vm_state_and_notify('prep_resize',
{'vm_state': vm_states.ERROR,
{'vm_state': vm_states.ACTIVE,
'task_state': None},
context, ex, request_spec)
if reservations:
QUOTAS.rollback(context, reservations)
except Exception as ex:
with excutils.save_and_reraise_exception():
self._set_vm_state_and_notify('prep_resize',
{'vm_state': vm_states.ERROR,
'task_state': None},
context, ex, request_spec)
if reservations:
QUOTAS.rollback(context, reservations)
def _set_vm_state_and_notify(self, method, updates, context, ex,
request_spec):

View File

@@ -37,6 +37,7 @@ from nova.scheduler import driver
from nova.scheduler import manager
from nova import servicegroup
from nova import test
from nova.tests import fake_instance_actions
from nova.tests import matchers
from nova.tests.scheduler import fakes
@@ -57,6 +58,7 @@ class SchedulerManagerTestCase(test.TestCase):
self.topic = 'fake_topic'
self.fake_args = (1, 2, 3)
self.fake_kwargs = {'cat': 'meow', 'dog': 'woof'}
fake_instance_actions.stub_out_action_events(self.stubs)
def test_1_correct_init(self):
# Correct scheduler driver
@@ -179,8 +181,8 @@ class SchedulerManagerTestCase(test.TestCase):
self.mox.StubOutWithMock(compute_utils, 'add_instance_fault_from_exc')
self.mox.StubOutWithMock(db, 'instance_update_and_get_original')
request_spec = {'instance_properties':
{'uuid': fake_instance_uuid}}
request_spec = {'instance_properties': inst,
'instance_uuids': [fake_instance_uuid]}
self.manager.driver.schedule_run_instance(self.context,
request_spec, None, None, None, None, {}).AndRaise(
@@ -199,6 +201,7 @@ class SchedulerManagerTestCase(test.TestCase):
def test_prep_resize_no_valid_host_back_in_active_state(self):
fake_instance_uuid = 'fake-instance-id'
fake_instance = {'uuid': fake_instance_uuid}
inst = {"vm_state": "", "task_state": ""}
self._mox_schedule_method_helper('schedule_prep_resize')
@@ -214,7 +217,7 @@ class SchedulerManagerTestCase(test.TestCase):
'image': 'fake_image',
'request_spec': request_spec,
'filter_properties': 'fake_props',
'instance': 'fake_instance',
'instance': fake_instance,
'instance_type': 'fake_type',
'reservations': list('fake_res'),
}
@@ -233,6 +236,7 @@ class SchedulerManagerTestCase(test.TestCase):
def test_prep_resize_exception_host_in_error_state_and_raise(self):
fake_instance_uuid = 'fake-instance-id'
fake_instance = {'uuid': fake_instance_uuid}
self._mox_schedule_method_helper('schedule_prep_resize')
@@ -246,7 +250,7 @@ class SchedulerManagerTestCase(test.TestCase):
'image': 'fake_image',
'request_spec': request_spec,
'filter_properties': 'fake_props',
'instance': 'fake_instance',
'instance': fake_instance,
'instance_type': 'fake_type',
'reservations': list('fake_res'),
}

View File

@@ -750,6 +750,34 @@ class DbApiTestCase(test.TestCase):
self.assertEqual(start_time, events[0]['start_time'])
self.assertEqual(finish_time, events[0]['finish_time'])
def test_instance_action_and_event_start_string_time(self):
"""Create an instance action and event with a string start_time."""
ctxt = context.get_admin_context()
uuid = str(stdlib_uuid.uuid4())
start_time = timeutils.utcnow()
start_time_str = timeutils.strtime(start_time)
action_values = {'action': 'run_instance',
'instance_uuid': uuid,
'request_id': ctxt.request_id,
'user_id': ctxt.user_id,
'project_id': ctxt.project_id,
'start_time': start_time_str}
action = db.action_start(ctxt, action_values)
event_values = {'event': 'schedule',
'instance_uuid': uuid,
'request_id': ctxt.request_id,
'start_time': start_time_str}
db.action_event_start(ctxt, event_values)
# Retrieve the event to ensure it was successfully added
events = db.action_events_get(ctxt, action['id'])
self.assertEqual(1, len(events))
self.assertEqual('schedule', events[0]['event'])
# db api still returns models with datetime, not str, values
self.assertEqual(start_time, events[0]['start_time'])
def test_instance_action_event_get_by_id(self):
"""Get a specific instance action event."""
ctxt1 = context.get_admin_context()

View File

@@ -1284,3 +1284,57 @@ def metadata_to_dict(metadata):
if not item.get('deleted'):
result[item['key']] = item['value']
return result
def get_wrapped_function(function):
"""Get the method at the bottom of a stack of decorators."""
if not hasattr(function, 'func_closure') or not function.func_closure:
return function
def _get_wrapped_function(function):
if not hasattr(function, 'func_closure') or not function.func_closure:
return None
for closure in function.func_closure:
func = closure.cell_contents
deeper_func = _get_wrapped_function(func)
if deeper_func:
return deeper_func
elif hasattr(closure.cell_contents, '__call__'):
return closure.cell_contents
return _get_wrapped_function(function)
def getcallargs(function, *args, **kwargs):
"""This is a simplified inspect.getcallargs (2.7+).
It should be replaced when python >= 2.7 is standard.
"""
keyed_args = {}
argnames, varargs, keywords, defaults = inspect.getargspec(function)
keyed_args.update(kwargs)
#NOTE(alaski) the implicit 'self' or 'cls' argument shows up in
# argnames but not in args or kwargs. Uses 'in' rather than '==' because
# some tests use 'self2'.
if 'self' in argnames[0] or 'cls' == argnames[0]:
# The function may not actually be a method or have im_self.
# Typically seen when it's stubbed with mox.
if inspect.ismethod(function) and hasattr(function, 'im_self'):
keyed_args[argnames[0]] = function.im_self
else:
keyed_args[argnames[0]] = None
remaining_argnames = filter(lambda x: x not in keyed_args, argnames)
keyed_args.update(dict(zip(remaining_argnames, args)))
if defaults:
num_defaults = len(defaults)
for argname, value in zip(argnames[-num_defaults:], defaults):
if argname not in keyed_args:
keyed_args[argname] = value
return keyed_args