diff --git a/heat/db/api.py b/heat/db/api.py index a2bf0378e..412f83980 100644 --- a/heat/db/api.py +++ b/heat/db/api.py @@ -198,6 +198,10 @@ def stack_lock_release(stack_id, engine_id): return IMPL.stack_lock_release(stack_id, engine_id) +def stack_get_root_id(context, stack_id): + return IMPL.stack_get_root_id(context, stack_id) + + def user_creds_create(context): return IMPL.user_creds_create(context) diff --git a/heat/db/sqlalchemy/api.py b/heat/db/sqlalchemy/api.py index c1d6cea04..0ac4fcd50 100644 --- a/heat/db/sqlalchemy/api.py +++ b/heat/db/sqlalchemy/api.py @@ -576,6 +576,13 @@ def stack_lock_release(stack_id, engine_id): return True +def stack_get_root_id(context, stack_id): + s = stack_get(context, stack_id) + while s.owner_id: + s = stack_get(context, s.owner_id) + return s.id + + def user_creds_create(context): values = context.to_dict() user_creds_ref = models.UserCreds() diff --git a/heat/engine/resources/aws/ec2/instance.py b/heat/engine/resources/aws/ec2/instance.py index 17eb69a04..a3ec88906 100644 --- a/heat/engine/resources/aws/ec2/instance.py +++ b/heat/engine/resources/aws/ec2/instance.py @@ -528,7 +528,7 @@ class Instance(resource.Resource): if cfg.CONF.stack_scheduler_hints: if scheduler_hints is None: scheduler_hints = {} - scheduler_hints['heat_root_stack_id'] = self.stack.root_stack.id + scheduler_hints['heat_root_stack_id'] = self.stack.root_stack_id() scheduler_hints['heat_stack_id'] = self.stack.id scheduler_hints['heat_stack_name'] = self.stack.name scheduler_hints['heat_path_in_stack'] = self.stack.path_in_stack() diff --git a/heat/engine/resources/openstack/nova/server.py b/heat/engine/resources/openstack/nova/server.py index 0caf36326..abeac45a5 100644 --- a/heat/engine/resources/openstack/nova/server.py +++ b/heat/engine/resources/openstack/nova/server.py @@ -670,7 +670,7 @@ class Server(stack_user.StackUser): if cfg.CONF.stack_scheduler_hints: if scheduler_hints is None: scheduler_hints = {} - scheduler_hints['heat_root_stack_id'] = self.stack.root_stack.id + scheduler_hints['heat_root_stack_id'] = self.stack.root_stack_id() scheduler_hints['heat_stack_id'] = self.stack.id scheduler_hints['heat_stack_name'] = self.stack.name scheduler_hints['heat_path_in_stack'] = self.stack.path_in_stack() diff --git a/heat/engine/stack.py b/heat/engine/stack.py index b566bca04..55ae8ca1e 100755 --- a/heat/engine/stack.py +++ b/heat/engine/stack.py @@ -257,6 +257,11 @@ class Stack(collections.Mapping): def reset_dependencies(self): self._dependencies = None + def root_stack_id(self): + if not self.owner_id: + return self.id + return stack_object.Stack.get_root_id(self.context, self.id) + @property def root_stack(self): ''' diff --git a/heat/objects/stack.py b/heat/objects/stack.py index 1a1420dd1..bef24ad10 100755 --- a/heat/objects/stack.py +++ b/heat/objects/stack.py @@ -80,6 +80,10 @@ class Stack( stack.obj_reset_changes() return stack + @classmethod + def get_root_id(cls, context, stack_id): + return db_api.stack_get_root_id(context, stack_id) + @classmethod def get_by_id(cls, context, stack_id, **kwargs): db_stack = db_api.stack_get(context, stack_id, **kwargs) diff --git a/heat/tests/aws/test_instance.py b/heat/tests/aws/test_instance.py index ca5de12eb..5d19b8990 100644 --- a/heat/tests/aws/test_instance.py +++ b/heat/tests/aws/test_instance.py @@ -550,7 +550,7 @@ class InstancesTest(common.HeatTestCase): limit=instance.physical_resource_name_limit), security_groups=None, userdata=mox.IgnoreArg(), - scheduler_hints={'heat_root_stack_id': stack.root_stack.id, + scheduler_hints={'heat_root_stack_id': stack.root_stack_id(), 'heat_stack_id': stack.id, 'heat_stack_name': stack.name, 'heat_path_in_stack': [(None, stack.name)], diff --git a/heat/tests/db/test_sqlalchemy_api.py b/heat/tests/db/test_sqlalchemy_api.py index 3445e0e1a..e6505884e 100644 --- a/heat/tests/db/test_sqlalchemy_api.py +++ b/heat/tests/db/test_sqlalchemy_api.py @@ -1801,6 +1801,25 @@ class DBAPIStackTest(common.HeatTestCase): self.assertIsNone(db_api.stack_get(ctx, stacks[s].id, show_deleted=True)) + def test_stack_get_root_id(self): + root = create_stack(self.ctx, self.template, self.user_creds, + name='root stack') + child_1 = create_stack(self.ctx, self.template, self.user_creds, + name='child 1 stack', owner_id=root.id) + child_2 = create_stack(self.ctx, self.template, self.user_creds, + name='child 2 stack', owner_id=child_1.id) + child_3 = create_stack(self.ctx, self.template, self.user_creds, + name='child 3 stack', owner_id=child_2.id) + + self.assertEqual(root.id, db_api.stack_get_root_id( + self.ctx, child_3.id)) + self.assertEqual(root.id, db_api.stack_get_root_id( + self.ctx, child_2.id)) + self.assertEqual(root.id, db_api.stack_get_root_id( + self.ctx, root.id)) + self.assertEqual(root.id, db_api.stack_get_root_id( + self.ctx, child_1.id)) + class DBAPIResourceTest(common.HeatTestCase): def setUp(self): diff --git a/heat/tests/test_server.py b/heat/tests/test_server.py index 110488108..17bc5d2cd 100644 --- a/heat/tests/test_server.py +++ b/heat/tests/test_server.py @@ -905,7 +905,7 @@ class ServersTest(common.HeatTestCase): name=server_name, security_groups=[], userdata=mox.IgnoreArg(), - scheduler_hints={'heat_root_stack_id': stack.root_stack.id, + scheduler_hints={'heat_root_stack_id': stack.root_stack_id(), 'heat_stack_id': stack.id, 'heat_stack_name': stack.name, 'heat_path_in_stack': [(None, stack.name)],