]> review.fuel-infra Code Review - openstack-build/heat-build.git/commitdiff
Convert Events to separate action/status
authorSteven Hardy <shardy@redhat.com>
Thu, 13 Jun 2013 10:19:32 +0000 (11:19 +0100)
committerSteven Hardy <shardy@redhat.com>
Thu, 13 Jun 2013 10:19:32 +0000 (11:19 +0100)
First step in decoupling action/status in Resource

This adjusts the Event DB columns, model and class to split
action/status, but in order to be backwards compatible we set the action
to None, which means we can do the right thing in the CFN API, and
resource_status still maps correctly to what is expected in
python-heatclient (which will need to change after the Resource
action/status split happens)

Change-Id: I261d47d2a3fdb3cdc2a8aaf6c159763f4636f633

heat/api/cfn/v1/stacks.py
heat/api/openstack/v1/events.py
heat/db/sqlalchemy/migrate_repo/versions/017_event_state_status.py [new file with mode: 0644]
heat/db/sqlalchemy/models.py
heat/engine/api.py
heat/engine/event.py
heat/engine/resource.py
heat/rpc/api.py
heat/tests/test_api_cfn_v1.py
heat/tests/test_engine_service.py
heat/tests/test_event.py

index dab7ad4a8ddf0b46fde97b0231817d0f3f9ccfd0..b02c62c0fde53d93a073687c5a6a80c003605d27 100644 (file)
@@ -469,6 +469,12 @@ class StackController(object):
             }
 
             result = api_utils.reformat_dict_keys(keymap, e)
+            action = e[engine_api.EVENT_RES_ACTION]
+            status = e[engine_api.EVENT_RES_STATUS]
+            if action and status:
+                result['ResourceStatus'] = '_'.join((action, status))
+            else:
+                result['ResourceStatus'] = status
             result['ResourceProperties'] = json.dumps(result[
                                                       'ResourceProperties'])
 
index d1881c39fdab7d31e385f2a26bd80599ef116284..651b2e14ae77f2716611f0b86775eda55fc975e4 100644 (file)
@@ -29,6 +29,7 @@ summary_keys = [
     engine_api.EVENT_ID,
     engine_api.EVENT_TIMESTAMP,
     engine_api.EVENT_RES_NAME,
+    engine_api.EVENT_RES_ACTION,
     engine_api.EVENT_RES_STATUS,
     engine_api.EVENT_RES_STATUS_DATA,
     engine_api.EVENT_RES_PHYSICAL_ID,
diff --git a/heat/db/sqlalchemy/migrate_repo/versions/017_event_state_status.py b/heat/db/sqlalchemy/migrate_repo/versions/017_event_state_status.py
new file mode 100644 (file)
index 0000000..8e4302f
--- /dev/null
@@ -0,0 +1,37 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from sqlalchemy import *
+from migrate import *
+
+
+def upgrade(migrate_engine):
+    meta = MetaData()
+    meta.bind = migrate_engine
+
+    event = Table('event', meta, autoload=True)
+    # Currently there is a 'name' column which really holds the
+    # resource status, so rename it and add a separate action column
+    # action is e.g "CREATE" and status is e.g "IN_PROGRESS"
+    event.c.name.alter(name='resource_status')
+    Column('resource_action', String(255)).create(event)
+
+
+def downgrade(migrate_engine):
+    meta = MetaData()
+    meta.bind = migrate_engine
+
+    event = Table('event', meta, autoload=True)
+    event.c.resource_status.alter(name='name')
+    event.c.resource_action.drop()
index 8dc553dfec87cfb4e16ae80f2d069670788657d4..0812ca1c8a83fcea3a175950882b05acc4fd76c5 100644 (file)
@@ -197,7 +197,8 @@ class Event(BASE, HeatBase):
     stack_id = Column(String, ForeignKey('stack.id'), nullable=False)
     stack = relationship(Stack, backref=backref('events'))
 
-    name = Column(String)
+    resource_action = Column(String)
+    resource_status = Column(String)
     logical_resource_id = Column(String)
     physical_resource_id = Column(String)
     resource_status_reason = Column(String)
index 6a8e28eac1e5b0eaa2479d475c6c87196c24256b..bf9ddd7479b235f2e300f284e087dc68eb4491cf 100644 (file)
@@ -126,7 +126,8 @@ def format_event(event):
         EVENT_TIMESTAMP: timeutils.isotime(event.timestamp),
         EVENT_RES_NAME: event.resource.name,
         EVENT_RES_PHYSICAL_ID: event.physical_resource_id,
-        EVENT_RES_STATUS: event.new_state,
+        EVENT_RES_ACTION: event.action,
+        EVENT_RES_STATUS: event.status,
         EVENT_RES_STATUS_DATA: event.reason,
         EVENT_RES_TYPE: event.resource.type(),
         EVENT_RES_PROPERTIES: event.resource_properties,
index 17de7ad0de9cb2498b641bed2cc5fdefaae7ed18..50e85ff26127e869f7ea18b578d72241b0cf987d 100644 (file)
@@ -25,7 +25,7 @@ class Event(object):
     '''Class representing a Resource state change.'''
 
     def __init__(self, context, stack, resource,
-                 new_state, reason,
+                 action, status, reason,
                  physical_resource_id, resource_properties,
                  timestamp=None, id=None):
         '''
@@ -36,7 +36,8 @@ class Event(object):
         self.context = context
         self.resource = resource
         self.stack = stack
-        self.new_state = new_state
+        self.action = action
+        self.status = status
         self.reason = reason
         self.physical_resource_id = physical_resource_id
         try:
@@ -60,7 +61,8 @@ class Event(object):
         resource = stack[ev.logical_resource_id]
 
         event = cls(context, stack, resource,
-                    ev.name, ev.resource_status_reason,
+                    ev.resource_action, ev.resource_status,
+                    ev.resource_status_reason,
                     ev.physical_resource_id, ev.resource_properties,
                     ev.created_at, ev.id)
 
@@ -72,9 +74,8 @@ class Event(object):
             'logical_resource_id': self.resource.name,
             'physical_resource_id': self.physical_resource_id,
             'stack_id': self.stack.id,
-            'stack_name': self.stack.name,
-            'resource_status': self.new_state,
-            'name': self.new_state,
+            'resource_action': self.action,
+            'resource_status': self.status,
             'resource_status_reason': self.reason,
             'resource_type': self.resource.type(),
             'resource_properties': self.resource_properties,
index 63b180f12f30a6e38fcdf786701cc92f0f125b12..cc5f560f334a23b71c2cc1bd3318b78dc0c3ff9c 100644 (file)
@@ -505,7 +505,7 @@ class Resource(object):
     def _add_event(self, new_state, reason):
         '''Add a state change event to the database.'''
         ev = event.Event(self.context, self.stack, self,
-                         new_state, reason,
+                         None, new_state, reason,
                          self.resource_id, self.properties)
 
         try:
index d8192328ca9678e6eabf0b2e076ab913e303b1fa..20d7d30e54530aae4243d8bee3a2221ee2e78c9e 100644 (file)
@@ -48,28 +48,28 @@ STACK_OUTPUT_KEYS = (
 
 RES_KEYS = (
     RES_DESCRIPTION, RES_UPDATED_TIME,
-    RES_NAME, RES_PHYSICAL_ID, RES_METADATA,
+    RES_NAME, RES_PHYSICAL_ID, RES_METADATA, RES_ACTION,
     RES_STATUS, RES_STATUS_DATA, RES_TYPE,
     RES_ID, RES_STACK_ID, RES_STACK_NAME,
 ) = (
     'description', 'updated_time',
     'logical_resource_id', 'physical_resource_id', 'metadata',
-    'resource_status', 'resource_status_reason', 'resource_type',
-    'resource_identity', STACK_ID, STACK_NAME,
+    'resource_action', 'resource_status', 'resource_status_reason',
+    'resource_type', 'resource_identity', STACK_ID, STACK_NAME,
 )
 
 EVENT_KEYS = (
     EVENT_ID,
     EVENT_STACK_ID, EVENT_STACK_NAME,
     EVENT_TIMESTAMP,
-    EVENT_RES_NAME, EVENT_RES_PHYSICAL_ID,
+    EVENT_RES_NAME, EVENT_RES_PHYSICAL_ID, EVENT_RES_ACTION,
     EVENT_RES_STATUS, EVENT_RES_STATUS_DATA, EVENT_RES_TYPE,
     EVENT_RES_PROPERTIES,
 ) = (
     'event_identity',
     STACK_ID, STACK_NAME,
     "event_time",
-    RES_NAME, RES_PHYSICAL_ID,
+    RES_NAME, RES_PHYSICAL_ID, RES_ACTION,
     RES_STATUS, RES_STATUS_DATA, RES_TYPE,
     'resource_properties',
 )
index 130d2682aab1b6272ea3f54c45f645548e9c7d4a..b701c068ca8c5cf9ad1431d597108670ae8b9a27 100644 (file)
@@ -957,6 +957,7 @@ class CfnStackControllerTest(HeatTestCase):
                          u'stack_name': u'wordpress',
                          u'stack_id': u'6',
                          u'path': u'/resources/WikiDatabase/events/42'},
+                        u'resource_action': u'TEST',
                         u'resource_status': u'IN_PROGRESS',
                         u'physical_resource_id': None,
                         u'resource_properties': {u'UserData': u'blah'},
@@ -983,7 +984,68 @@ class CfnStackControllerTest(HeatTestCase):
                      {'StackEvents':
                       [{'EventId': u'42',
                         'StackId': u'arn:openstack:heat::t:stacks/wordpress/6',
-                        'ResourceStatus': u'IN_PROGRESS',
+                        'ResourceStatus': u'TEST_IN_PROGRESS',
+                        'ResourceType': u'AWS::EC2::Instance',
+                        'Timestamp': u'2012-07-23T13:05:39Z',
+                        'StackName': u'wordpress',
+                        'ResourceProperties':
+                        json.dumps({u'UserData': u'blah'}),
+                        'PhysicalResourceId': None,
+                        'ResourceStatusReason': u'state changed',
+                        'LogicalResourceId': u'WikiDatabase'}]}}}
+
+        self.assertEqual(response, expected)
+        self.m.VerifyAll()
+
+    def test_events_list_onlystatus(self):
+        # Format a dummy request
+        stack_name = "wordpress"
+        identity = dict(identifier.HeatIdentifier('t', stack_name, '6'))
+        params = {'Action': 'DescribeStackEvents', 'StackName': stack_name}
+        dummy_req = self._dummy_GET_request(params)
+
+        # Stub out the RPC call to the engine with a pre-canned response
+        engine_resp = [{u'stack_name': u'wordpress',
+                        u'event_time': u'2012-07-23T13:05:39Z',
+                        u'stack_identity': {u'tenant': u't',
+                                            u'stack_name': u'wordpress',
+                                            u'stack_id': u'6',
+                                            u'path': u''},
+                        u'logical_resource_id': u'WikiDatabase',
+                        u'resource_status_reason': u'state changed',
+                        u'event_identity':
+                        {u'tenant': u't',
+                         u'stack_name': u'wordpress',
+                         u'stack_id': u'6',
+                         u'path': u'/resources/WikiDatabase/events/42'},
+                        u'resource_action': None,
+                        u'resource_status': u'TEST_IN_PROGRESS',
+                        u'physical_resource_id': None,
+                        u'resource_properties': {u'UserData': u'blah'},
+                        u'resource_type': u'AWS::EC2::Instance'}]
+
+        self.m.StubOutWithMock(rpc, 'call')
+        rpc.call(dummy_req.context, self.topic,
+                 {'namespace': None,
+                  'method': 'identify_stack',
+                  'args': {'stack_name': stack_name},
+                  'version': self.api_version}, None).AndReturn(identity)
+        rpc.call(dummy_req.context, self.topic,
+                 {'namespace': None,
+                  'method': 'list_events',
+                  'args': {'stack_identity': identity},
+                  'version': self.api_version}, None).AndReturn(engine_resp)
+
+        self.m.ReplayAll()
+
+        response = self.controller.events_list(dummy_req)
+
+        expected = {'DescribeStackEventsResponse':
+                    {'DescribeStackEventsResult':
+                     {'StackEvents':
+                      [{'EventId': u'42',
+                        'StackId': u'arn:openstack:heat::t:stacks/wordpress/6',
+                        'ResourceStatus': u'TEST_IN_PROGRESS',
                         'ResourceType': u'AWS::EC2::Instance',
                         'Timestamp': u'2012-07-23T13:05:39Z',
                         'StackName': u'wordpress',
index 479745062995f91a7332ca752da079149e162ee8..162a67460a54d5a5ccefe7dd194a95978a57c740 100644 (file)
@@ -557,7 +557,7 @@ class stackServiceTest(HeatTestCase):
             self.assertEqual(ev['resource_properties']['InstanceType'],
                              'm1.large')
 
-            self.assertTrue('resource_status' in ev)
+            self.assertTrue('resource_action' in ev)
             self.assertTrue(ev['resource_status'] in ('IN_PROGRESS',
                                                       'CREATE_COMPLETE'))
 
index 812fc42dd7993b0271a9074b74e97b16dfc3ac58..8e23a584dd70aa756bedf3498b2f4542400104d9 100644 (file)
@@ -67,7 +67,7 @@ class EventTest(HeatTestCase):
         self.resource.resource_id_set('resource_physical_id')
 
         e = event.Event(self.ctx, self.stack, self.resource,
-                        'TEST_IN_PROGRESS', 'Testing',
+                        'TEST', 'IN_PROGRESS', 'Testing',
                         'wibble', self.resource.properties)
 
         e.store()
@@ -79,14 +79,15 @@ class EventTest(HeatTestCase):
         self.assertEqual(loaded_e.resource.name, self.resource.name)
         self.assertEqual(loaded_e.resource.id, self.resource.id)
         self.assertEqual(loaded_e.physical_resource_id, 'wibble')
-        self.assertEqual(loaded_e.new_state, 'TEST_IN_PROGRESS')
+        self.assertEqual(loaded_e.action, 'TEST')
+        self.assertEqual(loaded_e.status, 'IN_PROGRESS')
         self.assertEqual(loaded_e.reason, 'Testing')
         self.assertNotEqual(loaded_e.timestamp, None)
         self.assertEqual(loaded_e.resource_properties, {'foo': True})
 
     def test_identifier(self):
         e = event.Event(self.ctx, self.stack, self.resource,
-                        'TEST_IN_PROGRESS', 'Testing',
+                        'TEST', 'IN_PROGRESS', 'Testing',
                         'wibble', self.resource.properties)
 
         eid = e.store()
@@ -103,6 +104,6 @@ class EventTest(HeatTestCase):
         rname = 'bad_resource'
         res = generic_rsrc.GenericResource(rname, tmpl, self.stack)
         e = event.Event(self.ctx, self.stack, res,
-                        'TEST_IN_PROGRESS', 'Testing',
+                        'TEST', 'IN_PROGRESS', 'Testing',
                         'wibble', res.properties)
         self.assertTrue('Error' in e.resource_properties)