]> review.fuel-infra Code Review - openstack-build/heat-build.git/commitdiff
Make Event object independent of resource object
authorLiang Chen <cbjchen@cn.ibm.com>
Tue, 13 Aug 2013 07:47:58 +0000 (15:47 +0800)
committerLiang Chen <cbjchen@cn.ibm.com>
Fri, 16 Aug 2013 03:12:17 +0000 (11:12 +0800)
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

heat/engine/api.py
heat/engine/event.py
heat/engine/resource.py
heat/tests/test_engine_service.py
heat/tests/test_event.py

index 33aeeef7c6d9e09f42077cc2bd956c711544eda2..33862de01026ade65caa9aa55868a6e91c9db05e 100644 (file)
@@ -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,
     }
 
index 8fe176145f7a9e48ad2719b920545866989fe369..6c095cc9491ef4066936d673f9902eba79b594a9 100644 (file)
@@ -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)
index 656a71cb095bda4526275c3f2672a25f91272120..02ed109868a0fc83545375ad631780a8f09eec54 100644 (file)
@@ -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()
index 0b4a64dfad9fafc0e3427d78d20cc0b4ade808a7..b69a17e24fe7765ec985ae03762f737a77d6b73a 100644 (file)
@@ -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)
index fd326528881ef622b45c1dfbfd5a082abe83a3f0..75c6edf2ae13b5e6936051816311182f59c50123 100644 (file)
@@ -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)