}
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'])
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,
--- /dev/null
+# 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()
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)
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,
'''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):
'''
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:
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)
'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,
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:
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',
)
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'},
{'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',
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'))
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()
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()
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)