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,
}
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:
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,
}
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)
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()
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)
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)
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)
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)
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)
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 = {
'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)