From: Steven Hardy Date: Thu, 13 Jun 2013 10:19:32 +0000 (+0100) Subject: Convert Events to separate action/status X-Git-Tag: 2014.1~493 X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=5206990f9a4c921b0b1d3924cd5295f948d93b47;p=openstack-build%2Fheat-build.git Convert Events to separate action/status 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 --- diff --git a/heat/api/cfn/v1/stacks.py b/heat/api/cfn/v1/stacks.py index dab7ad4a..b02c62c0 100644 --- a/heat/api/cfn/v1/stacks.py +++ b/heat/api/cfn/v1/stacks.py @@ -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']) diff --git a/heat/api/openstack/v1/events.py b/heat/api/openstack/v1/events.py index d1881c39..651b2e14 100644 --- a/heat/api/openstack/v1/events.py +++ b/heat/api/openstack/v1/events.py @@ -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 index 00000000..8e4302f6 --- /dev/null +++ b/heat/db/sqlalchemy/migrate_repo/versions/017_event_state_status.py @@ -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() diff --git a/heat/db/sqlalchemy/models.py b/heat/db/sqlalchemy/models.py index 8dc553df..0812ca1c 100644 --- a/heat/db/sqlalchemy/models.py +++ b/heat/db/sqlalchemy/models.py @@ -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) diff --git a/heat/engine/api.py b/heat/engine/api.py index 6a8e28ea..bf9ddd74 100644 --- a/heat/engine/api.py +++ b/heat/engine/api.py @@ -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, diff --git a/heat/engine/event.py b/heat/engine/event.py index 17de7ad0..50e85ff2 100644 --- a/heat/engine/event.py +++ b/heat/engine/event.py @@ -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, diff --git a/heat/engine/resource.py b/heat/engine/resource.py index 63b180f1..cc5f560f 100644 --- a/heat/engine/resource.py +++ b/heat/engine/resource.py @@ -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: diff --git a/heat/rpc/api.py b/heat/rpc/api.py index d8192328..20d7d30e 100644 --- a/heat/rpc/api.py +++ b/heat/rpc/api.py @@ -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', ) diff --git a/heat/tests/test_api_cfn_v1.py b/heat/tests/test_api_cfn_v1.py index 130d2682..b701c068 100644 --- a/heat/tests/test_api_cfn_v1.py +++ b/heat/tests/test_api_cfn_v1.py @@ -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', diff --git a/heat/tests/test_engine_service.py b/heat/tests/test_engine_service.py index 47974506..162a6746 100644 --- a/heat/tests/test_engine_service.py +++ b/heat/tests/test_engine_service.py @@ -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')) diff --git a/heat/tests/test_event.py b/heat/tests/test_event.py index 812fc42d..8e23a584 100644 --- a/heat/tests/test_event.py +++ b/heat/tests/test_event.py @@ -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)