Make Event object independent of resource object

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
This commit is contained in:
Liang Chen 2013-08-13 15:47:58 +08:00
parent d3bc51ffaf
commit d233cf6703
5 changed files with 94 additions and 39 deletions

View 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,
}

View 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)

View 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()

View 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)

View 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)