Reference the parent stack, not parent resource in Stack

In order to eliminate circular references, we need to define the Stack as
the top of any reference hierarchy. This means we can't hold a reference to
a Resource directly without also holding a reference to its Stack.

Change-Id: I7430b109bbe1c5d6d64be9b8c778b394e9cff269
Related-Bug: #1454873
This commit is contained in:
Zane Bitter 2015-05-13 18:56:32 -04:00
parent e95336340e
commit 2032548c4e
4 changed files with 30 additions and 27 deletions

View File

@ -123,7 +123,7 @@ class Stack(collections.Mapping):
self.timeout_mins = timeout_mins
self.disable_rollback = disable_rollback
self.parent_resource_name = parent_resource
self._parent_resource = None
self._parent_stack = None
self._resources = None
self._dependencies = None
self._access_allowed_handlers = {}
@ -176,19 +176,18 @@ class Stack(collections.Mapping):
Note: this should only be used by "Fn::ResourceFacade"
"""
if self._parent_resource is not None:
return self._parent_resource
if self._parent_stack is None:
# we need both parent name and owner id.
if self.parent_resource_name is None or self.owner_id is None:
return None
# we need both parent name and owner id.
if self.parent_resource_name is None or self.owner_id is None:
return None
try:
owner = self.load(self.context, stack_id=self.owner_id)
except exception.NotFound:
return None
self._parent_stack = owner
try:
owner = self.load(self.context, stack_id=self.owner_id)
except exception.NotFound:
return None
self._parent_resource = owner[self.parent_resource_name]
return self._parent_resource
return self._parent_stack[self.parent_resource_name]
def stored_context(self):
if self.user_creds_id:

View File

@ -797,7 +797,7 @@ class HOTemplateTest(common.HeatTestCase):
stack = parser.Stack(utils.dummy_context(), 'test_stack',
template.Template(hot_tpl_empty),
parent_resource='parent')
stack._parent_resource = parent_resource
stack._parent_stack = dict(parent=parent_resource)
self.assertEqual({"foo": "bar"},
self.resolve(metadata_snippet, stack.t, stack))
self.assertEqual('Retain',
@ -823,7 +823,7 @@ class HOTemplateTest(common.HeatTestCase):
stack = parser.Stack(utils.dummy_context(), 'test_stack',
template.Template(hot_tpl_empty),
parent_resource='parent')
stack._parent_resource = parent_resource
stack._parent_stack = dict(parent=parent_resource)
self.assertEqual('Retain',
self.resolve(deletion_policy_snippet, stack.t, stack))
@ -843,13 +843,14 @@ class HOTemplateTest(common.HeatTestCase):
parent_resource = DummyClass()
parent_resource.metadata_set({"foo": "bar"})
parent_resource.t = rsrc_defn.ResourceDefinition('parent', 'SomeType')
parent_resource.stack = parser.Stack(utils.dummy_context(),
'toplevel_stack',
template.Template(hot_tpl_empty))
parent_stack = parser.Stack(utils.dummy_context(),
'toplevel_stack',
template.Template(hot_tpl_empty))
parent_stack._resources = {'parent': parent_resource}
stack = parser.Stack(utils.dummy_context(), 'test_stack',
template.Template(hot_tpl_empty),
parent_resource='parent')
stack._parent_resource = parent_resource
stack._parent_stack = parent_stack
self.assertEqual('Delete', self.resolve(snippet, stack.t, stack))
def test_removed_function(self):

View File

@ -279,10 +279,12 @@ class StackTest(common.HeatTestCase):
{'A': {'Type': 'GenericResourceType'}}}
self.stack = stack.Stack(self.ctx, 'test_stack',
template.Template(tpl),
status_reason='blarg')
status_reason='blarg',
parent_resource='parent')
self.stack._parent_resource = mock.Mock()
self.stack._parent_resource.stack = None
parent_resource = mock.Mock()
parent_resource.stack = None
self.stack._parent_stack = dict(parent=parent_resource)
self.assertEqual(self.stack, self.stack.root_stack)
def test_root_stack_with_parent(self):
@ -290,10 +292,11 @@ class StackTest(common.HeatTestCase):
'Resources':
{'A': {'Type': 'GenericResourceType'}}}
stk = stack.Stack(self.ctx, 'test_stack', template.Template(tpl),
status_reason='blarg')
status_reason='blarg', parent_resource='parent')
stk._parent_resource = mock.Mock()
stk._parent_resource.stack.root_stack = 'test value'
parent_resource = mock.Mock()
parent_resource.stack.root_stack = 'test value'
stk._parent_stack = dict(parent=parent_resource)
self.assertEqual('test value', stk.root_stack)
def test_load_parent_resource(self):

View File

@ -777,7 +777,7 @@ Mappings:
stk = stack.Stack(self.ctx, 'test_stack',
template.Template(empty_template),
parent_resource='parent', owner_id=45)
stk._parent_resource = parent_resource
stk._parent_stack = dict(parent=parent_resource)
self.assertEqual({"foo": "bar"},
self.resolve(metadata_snippet, stk.t, stk))
self.assertEqual('Retain',
@ -801,7 +801,7 @@ Mappings:
stk = stack.Stack(self.ctx, 'test_stack',
template.Template(empty_template),
parent_resource='parent')
stk._parent_resource = parent_resource
stk._parent_stack = dict(parent=parent_resource)
self.assertEqual('Retain',
self.resolve(deletion_policy_snippet, stk.t, stk))
@ -825,7 +825,7 @@ Mappings:
stk = stack.Stack(self.ctx, 'test_stack',
template.Template(empty_template),
parent_resource='parent', owner_id=78)
stk._parent_resource = parent_resource
stk._parent_stack = dict(parent=parent_resource)
self.assertEqual('Delete', self.resolve(snippet, stk.t, stk))
def test_prevent_parameters_access(self):