From 8a13967f127184c3ef1251f75325490000b722ee Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Wed, 7 Aug 2013 09:12:44 -0700 Subject: [PATCH] Make compute_api use InstanceAction object This makes the compute_api instance action code use objects instead of direct-to-database calls. This should open the door for deprecating some conductor proxies for compute_api that help compute manager avoid the database hit required for the instance action to complete. Related to blueprint compute-api-objects Change-Id: If622d8079ca2897b0d5094e9341e29cde7c1ff59 --- nova/compute/api.py | 18 ++++++---- .../compute/contrib/test_instance_actions.py | 26 +++++++------- .../plugins/v3/test_instance_actions.py | 34 +++++++++++-------- nova/tests/fake_instance_actions.py | 25 +++++++++++++- 4 files changed, 69 insertions(+), 34 deletions(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index ab40a7f31617..568eef760e3e 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -53,6 +53,7 @@ from nova.network.security_group import security_group_base from nova import notifications from nova.objects import base as obj_base from nova.objects import instance as instance_obj +from nova.objects import instance_action from nova.objects import instance_info_cache from nova.objects import security_group from nova.openstack.common import excutils @@ -277,9 +278,10 @@ class API(base.Base): return instance_ref def _record_action_start(self, context, instance, action): - act = compute_utils.pack_action_start(context, instance['uuid'], - action) - self.db.action_start(context, act) + instance_action.InstanceAction.action_start(context, + instance['uuid'], + action, + want_result=False) def _check_injected_file_quota(self, context, injected_files): """Enforce quota limits on injected files. @@ -2949,14 +2951,16 @@ class InstanceActionAPI(base.Base): """Sub-set of the Compute Manager API for managing instance actions.""" def actions_get(self, context, instance): - return self.db.actions_get(context, instance['uuid']) + return instance_action.InstanceActionList.get_by_instance_uuid( + context, instance['uuid']) def action_get_by_request_id(self, context, instance, request_id): - return self.db.action_get_by_request_id(context, instance['uuid'], - request_id) + return instance_action.InstanceAction.get_by_request_id( + context, instance['uuid'], request_id) def action_events_get(self, context, instance, action_id): - return self.db.action_events_get(context, action_id) + return instance_action.InstanceActionEventList.get_by_action( + context, action_id) class AggregateAPI(base.Base): diff --git a/nova/tests/api/openstack/compute/contrib/test_instance_actions.py b/nova/tests/api/openstack/compute/contrib/test_instance_actions.py index 4f49b2853720..b2240395a8e4 100644 --- a/nova/tests/api/openstack/compute/contrib/test_instance_actions.py +++ b/nova/tests/api/openstack/compute/contrib/test_instance_actions.py @@ -36,13 +36,14 @@ FAKE_REQUEST_ID = fake_instance_actions.FAKE_REQUEST_ID1 def format_action(action): '''Remove keys that aren't serialized.''' - if 'id' in action: - del(action['id']) - if 'finish_time' in action: - del(action['finish_time']) + to_delete = ('id', 'finish_time', 'created_at', 'updated_at', 'deleted_at', + 'deleted') + for key in to_delete: + if key in action: + del(action[key]) if 'start_time' in action: # NOTE(danms): Without WSGI above us, these will be just stringified - action['start_time'] = str(action['start_time']) + action['start_time'] = str(action['start_time'].replace(tzinfo=None)) for event in action.get('events', []): format_event(event) return action @@ -50,14 +51,17 @@ def format_action(action): def format_event(event): '''Remove keys that aren't serialized.''' - if 'id' in event: - del(event['id']) + to_delete = ('id', 'created_at', 'updated_at', 'deleted_at', 'deleted', + 'action_id') + for key in to_delete: + if key in event: + del(event[key]) if 'start_time' in event: # NOTE(danms): Without WSGI above us, these will be just stringified - event['start_time'] = str(event['start_time']) + event['start_time'] = str(event['start_time'].replace(tzinfo=None)) if 'finish_time' in event: # NOTE(danms): Without WSGI above us, these will be just stringified - event['finish_time'] = str(event['finish_time']) + event['finish_time'] = str(event['finish_time'].replace(tzinfo=None)) return event @@ -156,8 +160,6 @@ class InstanceActionsTest(test.TestCase): res_dict = self.controller.show(req, FAKE_UUID, FAKE_REQUEST_ID) fake_action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID] fake_events = self.fake_events[fake_action['id']] - fake_events = [format_event(event) for event in fake_events] - fake_action = format_action(fake_action) fake_action['events'] = fake_events self.assertEqual(format_action(fake_action), format_action(res_dict['instanceAction'])) @@ -239,7 +241,7 @@ class InstanceActionsSerializerTest(test.TestCase): serializer = instance_actions.InstanceActionTemplate() action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID] event = self.fake_events[action['id']][0] - action['events'] = [event, event] + action['events'] = [dict(event), dict(event)] text = serializer.serialize({'instanceAction': action}) tree = etree.fromstring(text) diff --git a/nova/tests/api/openstack/compute/plugins/v3/test_instance_actions.py b/nova/tests/api/openstack/compute/plugins/v3/test_instance_actions.py index 55b826e4469b..a663683b5f95 100644 --- a/nova/tests/api/openstack/compute/plugins/v3/test_instance_actions.py +++ b/nova/tests/api/openstack/compute/plugins/v3/test_instance_actions.py @@ -36,13 +36,15 @@ FAKE_REQUEST_ID = fake_instance_actions.FAKE_REQUEST_ID1 def format_action(action): '''Remove keys that aren't serialized.''' - if 'id' in action: - del(action['id']) - if 'finish_time' in action: - del(action['finish_time']) + to_delete = ('id', 'finish_time', 'created_at', 'updated_at', 'deleted_at', + 'deleted') + for key in to_delete: + if key in action: + del(action[key]) if 'start_time' in action: - # NOTE(danms): Without WSGI above us, these will be just stringified - action['start_time'] = str(action['start_time']) + # NOTE(danms): Without WSGI above us, these will be just stringified, + # and objects will have added a timezone, so strip that for comparison + action['start_time'] = str(action['start_time'].replace(tzinfo=None)) for event in action.get('events', []): format_event(event) return action @@ -50,14 +52,19 @@ def format_action(action): def format_event(event): '''Remove keys that aren't serialized.''' - if 'id' in event: - del(event['id']) + to_delete = ('id', 'created_at', 'updated_at', 'deleted_at', 'deleted', + 'action_id') + for key in to_delete: + if key in event: + del(event[key]) if 'start_time' in event: - # NOTE(danms): Without WSGI above us, these will be just stringified - event['start_time'] = str(event['start_time']) + # NOTE(danms): Without WSGI above us, these will be just stringified, + # and objects will have added a timezone, so strip that for comparison + event['start_time'] = str(event['start_time'].replace(tzinfo=None)) if 'finish_time' in event: - # NOTE(danms): Without WSGI above us, these will be just stringified - event['finish_time'] = str(event['finish_time']) + # NOTE(danms): Without WSGI above us, these will be just stringified, + # and objects will have added a timezone, so strip that for comparison + event['finish_time'] = str(event['finish_time'].replace(tzinfo=None)) return event @@ -160,7 +167,6 @@ class InstanceActionsTest(test.TestCase): res_dict = self.controller.show(req, FAKE_UUID, FAKE_REQUEST_ID) fake_action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID] fake_events = self.fake_events[fake_action['id']] - fake_events = [format_event(event) for event in fake_events] fake_action['events'] = fake_events self.assertEqual(format_action(fake_action), format_action(res_dict['instance_action'])) @@ -251,7 +257,7 @@ class InstanceActionsSerializerTest(test.TestCase): serializer = instance_actions.InstanceActionTemplate() action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID] event = self.fake_events[action['id']][0] - action['events'] = [event, event] + action['events'] = [dict(event), dict(event)] text = serializer.serialize({'instance_action': action}) tree = etree.fromstring(text) diff --git a/nova/tests/fake_instance_actions.py b/nova/tests/fake_instance_actions.py index 959e9ba55989..f3ab1f8ad14b 100644 --- a/nova/tests/fake_instance_actions.py +++ b/nova/tests/fake_instance_actions.py @@ -37,6 +37,10 @@ FAKE_ACTIONS = { 2012, 12, 5, 0, 0, 0, 0), 'finish_time': None, 'message': '', + 'created_at': None, + 'updated_at': None, + 'deleted_at': None, + 'deleted': False, }, FAKE_REQUEST_ID2: {'id': FAKE_ACTION_ID2, 'action': 'resize', @@ -48,12 +52,17 @@ FAKE_ACTIONS = { 2012, 12, 5, 1, 0, 0, 0), 'finish_time': None, 'message': '', + 'created_at': None, + 'updated_at': None, + 'deleted_at': None, + 'deleted': False, } } } FAKE_EVENTS = { FAKE_ACTION_ID1: [{'id': 1, + 'action_id': FAKE_ACTION_ID1, 'event': 'schedule', 'start_time': datetime.datetime( 2012, 12, 5, 1, 0, 2, 0), @@ -61,8 +70,13 @@ FAKE_EVENTS = { 2012, 12, 5, 1, 2, 0, 0), 'result': 'Success', 'traceback': '', + 'created_at': None, + 'updated_at': None, + 'deleted_at': None, + 'deleted': False, }, {'id': 2, + 'action_id': FAKE_ACTION_ID1, 'event': 'compute_create', 'start_time': datetime.datetime( 2012, 12, 5, 1, 3, 0, 0), @@ -70,16 +84,25 @@ FAKE_EVENTS = { 2012, 12, 5, 1, 4, 0, 0), 'result': 'Success', 'traceback': '', + 'created_at': None, + 'updated_at': None, + 'deleted_at': None, + 'deleted': False, } ], FAKE_ACTION_ID2: [{'id': 3, + 'action_id': FAKE_ACTION_ID2, 'event': 'schedule', 'start_time': datetime.datetime( 2012, 12, 5, 3, 0, 0, 0), 'finish_time': datetime.datetime( 2012, 12, 5, 3, 2, 0, 0), 'result': 'Error', - 'traceback': '' + 'traceback': '', + 'created_at': None, + 'updated_at': None, + 'deleted_at': None, + 'deleted': False, } ] }