From: Liang Chen Date: Tue, 13 Aug 2013 07:47:58 +0000 (+0800) Subject: Make Event object independent of resource object X-Git-Tag: 2014.1~199^2 X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=d233cf67032af0a4484ebf4bbf668c060f61c792;p=openstack-build%2Fheat-build.git Make Event object independent of resource object The event table is pretty much self contained. So we actually don't need to referece the corresponding resources to retrieve information. Fixes bug #1204506 Change-Id: If0b88e0f9e243cf3cc6d747ffa04b9a429ea83a2 --- diff --git a/heat/engine/api.py b/heat/engine/api.py index 33aeeef7..33862de0 100644 --- a/heat/engine/api.py +++ b/heat/engine/api.py @@ -127,12 +127,12 @@ def format_event(event): api.EVENT_STACK_ID: dict(stack_identifier), api.EVENT_STACK_NAME: stack_identifier.stack_name, api.EVENT_TIMESTAMP: timeutils.isotime(event.timestamp), - api.EVENT_RES_NAME: event.resource.name, + api.EVENT_RES_NAME: event.logical_resource_id, api.EVENT_RES_PHYSICAL_ID: event.physical_resource_id, api.EVENT_RES_ACTION: event.action, api.EVENT_RES_STATUS: event.status, api.EVENT_RES_STATUS_DATA: event.reason, - api.EVENT_RES_TYPE: event.resource.type(), + api.EVENT_RES_TYPE: event.resource_type, api.EVENT_RES_PROPERTIES: event.resource_properties, } diff --git a/heat/engine/event.py b/heat/engine/event.py index 8fe17614..6c095cc9 100644 --- a/heat/engine/event.py +++ b/heat/engine/event.py @@ -24,22 +24,22 @@ logger = logging.getLogger(__name__) class Event(object): '''Class representing a Resource state change.''' - def __init__(self, context, stack, resource, - action, status, reason, - physical_resource_id, resource_properties, - timestamp=None, id=None): + def __init__(self, context, stack, action, status, reason, + physical_resource_id, resource_properties, resource_name, + resource_type, timestamp=None, id=None): ''' - Initialise from a context, stack, resource, event information and - current resource data. The timestamp and database ID may also be - initialised if the event is already in the database. + Initialise from a context, stack, and event information. The timestamp + and database ID may also be initialised if the event is already in the + database. ''' self.context = context - self.resource = resource self.stack = stack self.action = action self.status = status self.reason = reason self.physical_resource_id = physical_resource_id + self.logical_resource_id = resource_name + self.resource_type = resource_type try: self.resource_properties = dict(resource_properties) except ValueError as ex: @@ -60,24 +60,22 @@ class Event(object): st = stack if stack is not None else\ parser.Stack.load(context, ev.stack_id) - resource = st[ev.logical_resource_id] - return cls(context, st, resource, - ev.resource_action, ev.resource_status, - ev.resource_status_reason, - ev.physical_resource_id, ev.resource_properties, - ev.created_at, ev.id) + return cls(context, st, ev.resource_action, ev.resource_status, + ev.resource_status_reason, ev.physical_resource_id, + ev.resource_properties, ev.logical_resource_id, + ev.resource_type, ev.created_at, ev.id) def store(self): '''Store the Event in the database.''' ev = { - 'logical_resource_id': self.resource.name, + 'logical_resource_id': self.logical_resource_id, 'physical_resource_id': self.physical_resource_id, 'stack_id': self.stack.id, 'resource_action': self.action, 'resource_status': self.status, 'resource_status_reason': self.reason, - 'resource_type': self.resource.type(), + 'resource_type': self.resource_type, 'resource_properties': self.resource_properties, } @@ -96,5 +94,7 @@ class Event(object): if self.id is None: return None - return identifier.EventIdentifier(event_id=str(self.id), - **self.resource.identifier()) + res_id = identifier.ResourceIdentifier( + resource_name=self.logical_resource_id, **self.stack.identifier()) + + return identifier.EventIdentifier(event_id=str(self.id), **res_id) diff --git a/heat/engine/resource.py b/heat/engine/resource.py index 656a71cb..02ed1098 100644 --- a/heat/engine/resource.py +++ b/heat/engine/resource.py @@ -595,9 +595,9 @@ class Resource(object): def _add_event(self, action, status, reason): '''Add a state change event to the database.''' - ev = event.Event(self.context, self.stack, self, - action, status, reason, - self.resource_id, self.properties) + ev = event.Event(self.context, self.stack, action, status, reason, + self.resource_id, self.properties, + self.name, self.type()) try: ev.store() diff --git a/heat/tests/test_engine_service.py b/heat/tests/test_engine_service.py index 0b4a64df..b69a17e2 100644 --- a/heat/tests/test_engine_service.py +++ b/heat/tests/test_engine_service.py @@ -744,6 +744,64 @@ class StackServiceTest(HeatTestCase): self.m.VerifyAll() + @stack_context('service_event_list_deleted_resource_test_stack') + def test_stack_event_list_deleted_resource(self): + rsrs._register_class('GenericResourceType', + generic_rsrc.GenericResource) + + def run(stack_id, func, *args): + func(*args) + self.eng._start_in_thread = run + + new_tmpl = {'Resources': {'AResource': {'Type': + 'GenericResourceType'}}} + + self.m.StubOutWithMock(instances.Instance, 'handle_delete') + instances.Instance.handle_delete() + + self.m.ReplayAll() + + result = self.eng.update_stack(self.ctx, self.stack.identifier(), + new_tmpl, None, None, {}) + + # The self.stack reference needs to be updated. Since the underlying + # stack is updated in update_stack, the original reference is now + # pointing to an orphaned stack object. + self.stack = parser.Stack.load(self.ctx, stack_id=result['stack_id']) + + self.assertEqual(self.stack.identifier(), result) + self.assertTrue(isinstance(result, dict)) + self.assertTrue(result['stack_id']) + events = self.eng.list_events(self.ctx, self.stack.identifier()) + + self.assertEqual(6, len(events)) + + for ev in events: + self.assertIn('event_identity', ev) + self.assertEqual(dict, type(ev['event_identity'])) + self.assertTrue(ev['event_identity']['path'].rsplit('/', 1)[1]) + + self.assertIn('logical_resource_id', ev) + self.assertIn('physical_resource_id', ev) + self.assertIn('resource_properties', ev) + self.assertIn('resource_status_reason', ev) + + self.assertIn(ev['resource_action'], ('CREATE', 'DELETE')) + self.assertIn(ev['resource_status'], ('IN_PROGRESS', 'COMPLETE')) + + self.assertIn('resource_type', ev) + self.assertIn(ev['resource_type'], ('AWS::EC2::Instance', + 'GenericResourceType')) + + self.assertIn('stack_identity', ev) + + self.assertIn('stack_name', ev) + self.assertEqual(self.stack.name, ev['stack_name']) + + self.assertIn('event_time', ev) + + self.m.VerifyAll() + @stack_context('service_event_list_test_stack') def test_stack_event_list_by_tenant(self): events = self.eng.list_events(self.ctx, None) diff --git a/heat/tests/test_event.py b/heat/tests/test_event.py index fd326528..75c6edf2 100644 --- a/heat/tests/test_event.py +++ b/heat/tests/test_event.py @@ -59,9 +59,9 @@ class EventTest(HeatTestCase): def test_load(self): self.resource.resource_id_set('resource_physical_id') - e = event.Event(self.ctx, self.stack, self.resource, - 'TEST', 'IN_PROGRESS', 'Testing', - 'wibble', self.resource.properties) + e = event.Event(self.ctx, self.stack, 'TEST', 'IN_PROGRESS', 'Testing', + 'wibble', self.resource.properties, + self.resource.name, self.resource.type()) e.store() self.assertNotEqual(e.id, None) @@ -69,8 +69,7 @@ class EventTest(HeatTestCase): loaded_e = event.Event.load(self.ctx, e.id) self.assertEqual(self.stack.id, loaded_e.stack.id) - self.assertEqual(self.resource.name, loaded_e.resource.name) - self.assertEqual(self.resource.id, loaded_e.resource.id) + self.assertEqual(self.resource.name, loaded_e.logical_resource_id) self.assertEqual('wibble', loaded_e.physical_resource_id) self.assertEqual('TEST', loaded_e.action) self.assertEqual('IN_PROGRESS', loaded_e.status) @@ -81,9 +80,9 @@ class EventTest(HeatTestCase): def test_load_given_stack_event(self): self.resource.resource_id_set('resource_physical_id') - e = event.Event(self.ctx, self.stack, self.resource, - 'TEST', 'IN_PROGRESS', 'Testing', - 'wibble', self.resource.properties) + e = event.Event(self.ctx, self.stack, 'TEST', 'IN_PROGRESS', 'Testing', + 'wibble', self.resource.properties, + self.resource.name, self.resource.type()) e.store() self.assertNotEqual(e.id, None) @@ -93,8 +92,7 @@ class EventTest(HeatTestCase): loaded_e = event.Event.load(self.ctx, e.id, stack=self.stack, event=ev) self.assertEqual(self.stack.id, loaded_e.stack.id) - self.assertEqual(self.resource.name, loaded_e.resource.name) - self.assertEqual(self.resource.id, loaded_e.resource.id) + self.assertEqual(self.resource.name, loaded_e.logical_resource_id) self.assertEqual('wibble', loaded_e.physical_resource_id) self.assertEqual('TEST', loaded_e.action) self.assertEqual('IN_PROGRESS', loaded_e.status) @@ -103,9 +101,9 @@ class EventTest(HeatTestCase): self.assertEqual({'Foo': 'goo'}, loaded_e.resource_properties) def test_identifier(self): - e = event.Event(self.ctx, self.stack, self.resource, - 'TEST', 'IN_PROGRESS', 'Testing', - 'wibble', self.resource.properties) + e = event.Event(self.ctx, self.stack, 'TEST', 'IN_PROGRESS', 'Testing', + 'wibble', self.resource.properties, + self.resource.name, self.resource.type()) eid = e.store() expected_identifier = { @@ -121,7 +119,6 @@ class EventTest(HeatTestCase): 'Properties': {'Foo': False}} rname = 'bad_resource' res = generic_rsrc.ResourceWithRequiredProps(rname, tmpl, self.stack) - e = event.Event(self.ctx, self.stack, res, - 'TEST', 'IN_PROGRESS', 'Testing', - 'wibble', res.properties) + e = event.Event(self.ctx, self.stack, 'TEST', 'IN_PROGRESS', 'Testing', + 'wibble', res.properties, res.name, res.type()) self.assertTrue('Error' in e.resource_properties)