Don't pass the parent_resource object into Stack()

The reason for doing this is, is the difficulty of passing this
via RPC.

- pass the parent_resource name in, not the object
- make parent_resource a property that is looked as needed

There are 3 things that use "parent_resource"
1. Fn::ResourceFacade - OK, no getting around this
2. root_stack - used for determining the total resources in a stack
   (TODO: this should use a db lookup)

part of blueprint decouple-nested
Change-Id: Ia70395716085729176d869bf7564170db76bc24f
This commit is contained in:
Angus Salkeld 2015-02-26 21:27:26 +10:00
parent 8bc93e286b
commit a43a1a94ab
8 changed files with 67 additions and 37 deletions

View File

@ -180,8 +180,8 @@ def format_stack_resource(resource, detail=True, with_props=False,
resource.nested() is not None):
res[rpc_api.RES_NESTED_STACK_ID] = dict(resource.nested().identifier())
if resource.stack.parent_resource:
res[rpc_api.RES_PARENT_RESOURCE] = resource.stack.parent_resource.name
if resource.stack.parent_resource_name:
res[rpc_api.RES_PARENT_RESOURCE] = resource.stack.parent_resource_name
if detail:
res[rpc_api.RES_DESCRIPTION] = resource.t.description

View File

@ -107,7 +107,8 @@ class Stack(collections.Mapping):
self.status_reason = status_reason
self.timeout_mins = timeout_mins
self.disable_rollback = disable_rollback
self.parent_resource = parent_resource
self.parent_resource_name = parent_resource
self._parent_resource = None
self._resources = None
self._dependencies = None
self._access_allowed_handlers = {}
@ -145,6 +146,26 @@ class Stack(collections.Mapping):
else:
self.outputs = {}
@property
def parent_resource(self):
"""Dynamically load up the parent_resource.
Note: this should only be used by "Fn::ResourceFacade"
"""
if self._parent_resource is not None:
return self._parent_resource
# 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_resource = owner[self.parent_resource_name]
return self._parent_resource
def stored_context(self):
if self.user_creds_id:
creds = db_api.user_creds_get(self.user_creds_id)

View File

@ -57,8 +57,9 @@ class StackResource(resource.Resource):
def validate_nested_stack(self):
try:
name = "%s-%s" % (self.stack.name, self.name)
nested_stack = self._parse_nested_stack(
self.stack.name,
name,
self.child_template(),
self.child_params())
nested_stack.strict_validate = False
@ -95,7 +96,7 @@ class StackResource(resource.Resource):
if self._nested is None and self.resource_id is not None:
self._nested = parser.Stack.load(self.context,
self.resource_id,
parent_resource=self,
parent_resource=self.name,
show_deleted=show_deleted,
force_reload=force_reload)
@ -191,7 +192,7 @@ class StackResource(resource.Resource):
env=child_env,
timeout_mins=timeout_mins,
disable_rollback=True,
parent_resource=self,
parent_resource=self.name,
owner_id=self.stack.id,
user_creds_id=self.stack.user_creds_id,
stack_user_project_id=stack_user_project_id,

View File

@ -228,8 +228,7 @@ class FormatTest(common.HeatTestCase):
def test_format_stack_resource_with_parent_stack(self):
res = self.stack['generic1']
res.stack.parent_resource = mock.Mock()
res.stack.parent_resource.name = 'foobar'
res.stack.parent_resource_name = 'foobar'
formatted = api.format_stack_resource(res, False)
self.assertEqual('foobar', formatted[rpc_api.RES_PARENT_RESOURCE])

View File

@ -753,7 +753,8 @@ class HOTemplateTest(common.HeatTestCase):
parser.Template(hot_tpl_empty))
stack = parser.Stack(utils.dummy_context(), 'test_stack',
parser.Template(hot_tpl_empty),
parent_resource=parent_resource)
parent_resource='parent')
stack._parent_resource = parent_resource
self.assertEqual({"foo": "bar"},
self.resolve(metadata_snippet, stack.t, stack))
self.assertEqual('Retain',
@ -778,7 +779,8 @@ class HOTemplateTest(common.HeatTestCase):
stack = parser.Stack(utils.dummy_context(), 'test_stack',
parser.Template(hot_tpl_empty),
parent_resource=parent_resource)
parent_resource='parent')
stack._parent_resource = parent_resource
self.assertEqual('Retain',
self.resolve(deletion_policy_snippet, stack.t, stack))
@ -803,7 +805,8 @@ class HOTemplateTest(common.HeatTestCase):
parser.Template(hot_tpl_empty))
stack = parser.Stack(utils.dummy_context(), 'test_stack',
parser.Template(hot_tpl_empty),
parent_resource=parent_resource)
parent_resource='parent')
stack._parent_resource = parent_resource
self.assertEqual('Delete', self.resolve(snippet, stack.t, stack))
def test_removed_function(self):

View File

@ -559,7 +559,8 @@ Mappings:
parser.Template(empty_template))
stack = parser.Stack(self.ctx, 'test_stack',
parser.Template(empty_template),
parent_resource=parent_resource)
parent_resource='parent', owner_id=45)
stack._parent_resource = parent_resource
self.assertEqual({"foo": "bar"},
self.resolve(metadata_snippet, stack.t, stack))
self.assertEqual('Retain',
@ -582,7 +583,8 @@ Mappings:
stack = parser.Stack(self.ctx, 'test_stack',
parser.Template(empty_template),
parent_resource=parent_resource)
parent_resource='parent')
stack._parent_resource = parent_resource
self.assertEqual('Retain',
self.resolve(deletion_policy_snippet, stack.t, stack))
@ -607,7 +609,8 @@ Mappings:
parser.Template(empty_template))
stack = parser.Stack(self.ctx, 'test_stack',
parser.Template(empty_template),
parent_resource=parent_resource)
parent_resource='parent', owner_id=78)
stack._parent_resource = parent_resource
self.assertEqual('Delete', self.resolve(snippet, stack.t, stack))
def test_prevent_parameters_access(self):
@ -1107,8 +1110,8 @@ class StackTest(common.HeatTestCase):
stack = parser.Stack(self.ctx, 'test_stack', parser.Template(tpl),
status_reason='blarg')
stack.parent_resource = mock.Mock()
stack.parent_resource.stack = None
stack._parent_resource = mock.Mock()
stack._parent_resource.stack = None
self.assertEqual(stack, stack.root_stack)
def test_root_stack_with_parent(self):
@ -1118,8 +1121,8 @@ class StackTest(common.HeatTestCase):
stack = parser.Stack(self.ctx, 'test_stack', parser.Template(tpl),
status_reason='blarg')
stack.parent_resource = mock.Mock()
stack.parent_resource.stack.root_stack = 'test value'
stack._parent_resource = mock.Mock()
stack._parent_resource.stack.root_stack = 'test value'
self.assertEqual('test value', stack.root_stack)
def test_load_parent_resource(self):

View File

@ -1081,5 +1081,5 @@ class SoftwareDeploymentsTest(common.HeatTestCase):
def test_validate(self):
stack = utils.parse_stack(self.template)
snip = stack.t.resource_definitions(stack)['deploy_mysql']
resg = sd.SoftwareDeployments('test', snip, stack)
resg = sd.SoftwareDeployments('deploy_mysql', snip, stack)
self.assertIsNone(resg.validate())

View File

@ -248,7 +248,7 @@ class StackResourceTest(common.HeatTestCase):
env='environment',
timeout_mins=None,
disable_rollback=True,
parent_resource=parent_resource,
parent_resource=parent_resource.name,
owner_id=self.parent_stack.id,
user_creds_id=self.parent_stack.user_creds_id,
stack_user_project_id=self.parent_stack.stack_user_project_id,
@ -288,7 +288,7 @@ class StackResourceTest(common.HeatTestCase):
env='environment',
timeout_mins=None,
disable_rollback=True,
parent_resource=parent_resource,
parent_resource=parent_resource.name,
owner_id=self.parent_stack.id,
user_creds_id=self.parent_stack.user_creds_id,
stack_user_project_id=self.parent_stack.stack_user_project_id,
@ -436,10 +436,7 @@ class StackResourceTest(common.HeatTestCase):
def test_update_with_template_validates(self):
"""Updating a stack with a template validates the created stack."""
create_result = self.parent_resource.create_with_template(
self.simple_template, {})
while not create_result.step():
pass
self.parent_resource._nested = mock.MagicMock()
template = self.simple_template.copy()
template['Parameters']['WebServer'] = {'Type': 'String'}
@ -454,10 +451,11 @@ class StackResourceTest(common.HeatTestCase):
self.stack = self.parent_resource.nested()
self.parent_resource._nested = None
self.parent_resource.resource_id = 319
self.m.StubOutWithMock(parser.Stack, 'load')
parser.Stack.load(self.parent_resource.context,
self.parent_resource.resource_id,
parent_resource=self.parent_resource,
parent_resource=self.parent_resource.name,
show_deleted=False,
force_reload=False).AndReturn('s')
self.m.ReplayAll()
@ -475,7 +473,7 @@ class StackResourceTest(common.HeatTestCase):
stack = parser.Stack.load(
self.parent_resource.context,
self.parent_resource.resource_id,
parent_resource=self.parent_resource,
parent_resource=self.parent_resource.name,
show_deleted=False)
stack.state_set(parser.Stack.CREATE, parser.Stack.FAILED, "foo")
self.assertEqual(expected_state, self.parent_resource.nested().state)
@ -506,7 +504,7 @@ class StackResourceTest(common.HeatTestCase):
self.m.StubOutWithMock(parser.Stack, 'load')
parser.Stack.load(self.parent_resource.context,
self.parent_resource.resource_id,
parent_resource=self.parent_resource,
parent_resource=self.parent_resource.name,
show_deleted=False,
force_reload=False)
self.m.ReplayAll()
@ -514,14 +512,18 @@ class StackResourceTest(common.HeatTestCase):
self.assertRaises(exception.NotFound, self.parent_resource.nested)
self.m.VerifyAll()
def test_delete_nested_ok(self):
nested = self.m.CreateMockAnything()
self.m.StubOutWithMock(stack_resource.StackResource, 'nested')
stack_resource.StackResource.nested().AndReturn(nested)
nested.delete()
def test_load_nested_force_reload_none(self):
self.parent_resource._nested = mock.MagicMock()
self.parent_resource.resource_id = '90-8'
self.m.StubOutWithMock(parser.Stack, 'load')
parser.Stack.load(self.parent_resource.context,
self.parent_resource.resource_id,
parent_resource=self.parent_resource.name,
show_deleted=False,
force_reload=True).AndReturn(None)
self.m.ReplayAll()
self.parent_resource.delete_nested()
self.assertRaises(exception.NotFound, self.parent_resource.nested,
force_reload=True)
self.m.VerifyAll()
def test_delete_nested_not_found_nested_stack(self):
@ -534,7 +536,7 @@ class StackResourceTest(common.HeatTestCase):
parser.Stack.load(
self.parent_resource.context,
self.parent_resource.resource_id,
parent_resource=self.parent_resource,
parent_resource=self.parent_resource.name,
show_deleted=False, force_reload=False
).AndRaise(exception.NotFound(''))
self.m.ReplayAll()
@ -706,8 +708,9 @@ class StackResourceAttrTest(common.HeatTestCase):
nested.validate().AndReturn(True)
self.m.StubOutWithMock(stack_resource.StackResource,
'_parse_nested_stack')
name = '%s-%s' % (self.parent_stack.name, self.parent_resource.name)
stack_resource.StackResource._parse_nested_stack(
self.parent_stack.name, 'foo', {}).AndReturn(nested)
name, 'foo', {}).AndReturn(nested)
self.m.ReplayAll()
self.parent_resource.validate_nested_stack()