Persist parent_resource_name and make sure it's available

We are persisting for a number of reasons:
- so we don't have to pass this through ever rpc call
- the API exposes parent_resource (currently always None as
  it is not persisted)

Closes-bug: #1438978
Change-Id: Id2db36c0234a085ec4f0ce2ab114ec483ea29d81
This commit is contained in:
Angus Salkeld 2015-04-07 09:25:50 +10:00
parent 947aaf97da
commit edf86aeac2
15 changed files with 134 additions and 53 deletions

View File

@ -0,0 +1,45 @@
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sqlalchemy
from heat.db.sqlalchemy import utils as migrate_utils
def upgrade(migrate_engine):
meta = sqlalchemy.MetaData(bind=migrate_engine)
stack = sqlalchemy.Table('stack', meta, autoload=True)
parent_resource_name = sqlalchemy.Column('parent_resource_name',
sqlalchemy.String(255))
parent_resource_name.create(stack)
def downgrade(migrate_engine):
meta = sqlalchemy.MetaData(bind=migrate_engine)
stack = sqlalchemy.Table('stack', meta, autoload=True)
if migrate_engine.name == 'sqlite':
_downgrade_062_sqlite(migrate_engine, meta, stack)
else:
stack.c.parent_resource_name.drop()
def _downgrade_062_sqlite(migrate_engine, metadata, table):
new_table = migrate_utils.clone_table(
table.name + '__tmp__', table, metadata,
ignorecols=['parent_resource_name'])
migrate_utils.migrate_data(migrate_engine,
table,
new_table,
['parent_resource_name'])

View File

@ -169,6 +169,7 @@ class Stack(BASE, HeatBase, SoftDelete, StateAware):
sqlalchemy.Integer, sqlalchemy.Integer,
sqlalchemy.ForeignKey('user_creds.id')) sqlalchemy.ForeignKey('user_creds.id'))
owner_id = sqlalchemy.Column(sqlalchemy.String(36)) owner_id = sqlalchemy.Column(sqlalchemy.String(36))
parent_resource_name = sqlalchemy.Column(sqlalchemy.String(255))
timeout = sqlalchemy.Column(sqlalchemy.Integer) timeout = sqlalchemy.Column(sqlalchemy.Integer)
disable_rollback = sqlalchemy.Column(sqlalchemy.Boolean, nullable=False) disable_rollback = sqlalchemy.Column(sqlalchemy.Boolean, nullable=False)
stack_user_project_id = sqlalchemy.Column(sqlalchemy.String(64)) stack_user_project_id = sqlalchemy.Column(sqlalchemy.String(64))

View File

@ -97,7 +97,6 @@ class StackResource(resource.Resource):
if self._nested is None and self.resource_id is not None: if self._nested is None and self.resource_id is not None:
self._nested = parser.Stack.load(self.context, self._nested = parser.Stack.load(self.context,
self.resource_id, self.resource_id,
parent_resource=self.name,
show_deleted=show_deleted, show_deleted=show_deleted,
force_reload=force_reload) force_reload=force_reload)
@ -259,7 +258,8 @@ class StackResource(resource.Resource):
owner_id=self.stack.id, owner_id=self.stack.id,
user_creds_id=self.stack.user_creds_id, user_creds_id=self.stack.user_creds_id,
stack_user_project_id=stack_user_project_id, stack_user_project_id=stack_user_project_id,
nested_depth=new_nested_depth) nested_depth=new_nested_depth,
parent_resource_name=self.name)
except Exception as ex: except Exception as ex:
self.raise_local_exception(ex) self.raise_local_exception(ex)

View File

@ -266,7 +266,7 @@ class EngineService(service.Service):
by the RPC caller. by the RPC caller.
""" """
RPC_API_VERSION = '1.6' RPC_API_VERSION = '1.7'
def __init__(self, host, topic, manager=None): def __init__(self, host, topic, manager=None):
super(EngineService, self).__init__() super(EngineService, self).__init__()
@ -549,7 +549,8 @@ class EngineService(service.Service):
params, files, args, owner_id=None, params, files, args, owner_id=None,
nested_depth=0, user_creds_id=None, nested_depth=0, user_creds_id=None,
stack_user_project_id=None, stack_user_project_id=None,
convergence=False): convergence=False,
parent_resource_name=None):
# If it is stack-adopt, use parameters from adopt_stack_data # If it is stack-adopt, use parameters from adopt_stack_data
common_params = api.extract_args(args) common_params = api.extract_args(args)
if (rpc_api.PARAM_ADOPT_STACK_DATA in common_params and if (rpc_api.PARAM_ADOPT_STACK_DATA in common_params and
@ -574,6 +575,7 @@ class EngineService(service.Service):
user_creds_id=user_creds_id, user_creds_id=user_creds_id,
stack_user_project_id=stack_user_project_id, stack_user_project_id=stack_user_project_id,
convergence=convergence, convergence=convergence,
parent_resource=parent_resource_name,
**common_params) **common_params)
self._validate_deferred_auth_context(cnxt, stack) self._validate_deferred_auth_context(cnxt, stack)
@ -615,7 +617,7 @@ class EngineService(service.Service):
@context.request_context @context.request_context
def create_stack(self, cnxt, stack_name, template, params, files, args, def create_stack(self, cnxt, stack_name, template, params, files, args,
owner_id=None, nested_depth=0, user_creds_id=None, owner_id=None, nested_depth=0, user_creds_id=None,
stack_user_project_id=None): stack_user_project_id=None, parent_resource_name=None):
""" """
The create_stack method creates a new stack using the template The create_stack method creates a new stack using the template
provided. provided.
@ -635,6 +637,7 @@ class EngineService(service.Service):
:param user_creds_id: the parent user_creds record for nested stacks :param user_creds_id: the parent user_creds record for nested stacks
:param stack_user_project_id: the parent stack_user_project_id for :param stack_user_project_id: the parent stack_user_project_id for
nested stacks nested stacks
:param parent_resource_name: the parent resource name
""" """
LOG.info(_LI('Creating stack %s'), stack_name) LOG.info(_LI('Creating stack %s'), stack_name)
@ -667,7 +670,8 @@ class EngineService(service.Service):
stack = self._parse_template_and_validate_stack( stack = self._parse_template_and_validate_stack(
cnxt, stack_name, template, params, files, args, owner_id, cnxt, stack_name, template, params, files, args, owner_id,
nested_depth, user_creds_id, stack_user_project_id, convergence) nested_depth, user_creds_id, stack_user_project_id, convergence,
parent_resource_name)
stack.store() stack.store()

View File

@ -331,7 +331,7 @@ class Stack(collections.Mapping):
return deps return deps
@classmethod @classmethod
def load(cls, context, stack_id=None, stack=None, parent_resource=None, def load(cls, context, stack_id=None, stack=None,
show_deleted=True, use_stored_context=False, force_reload=False): show_deleted=True, use_stored_context=False, force_reload=False):
'''Retrieve a Stack from the database.''' '''Retrieve a Stack from the database.'''
if stack is None: if stack is None:
@ -347,7 +347,7 @@ class Stack(collections.Mapping):
if force_reload: if force_reload:
stack.refresh() stack.refresh()
return cls._from_db(context, stack, parent_resource=parent_resource, return cls._from_db(context, stack,
use_stored_context=use_stored_context) use_stored_context=use_stored_context)
@classmethod @classmethod
@ -370,7 +370,7 @@ class Stack(collections.Mapping):
yield cls._from_db(context, stack, resolve_data=resolve_data) yield cls._from_db(context, stack, resolve_data=resolve_data)
@classmethod @classmethod
def _from_db(cls, context, stack, parent_resource=None, resolve_data=True, def _from_db(cls, context, stack, resolve_data=True,
use_stored_context=False): use_stored_context=False):
template = tmpl.Template.load( template = tmpl.Template.load(
context, stack.raw_template_id, stack.raw_template) context, stack.raw_template_id, stack.raw_template)
@ -384,7 +384,7 @@ class Stack(collections.Mapping):
timeout_mins=stack.timeout, timeout_mins=stack.timeout,
resolve_data=resolve_data, resolve_data=resolve_data,
disable_rollback=stack.disable_rollback, disable_rollback=stack.disable_rollback,
parent_resource=parent_resource, parent_resource=stack.parent_resource_name,
owner_id=stack.owner_id, owner_id=stack.owner_id,
stack_user_project_id=stack.stack_user_project_id, stack_user_project_id=stack.stack_user_project_id,
created_time=stack.created_at, created_time=stack.created_at,
@ -412,8 +412,6 @@ class Stack(collections.Mapping):
stack = { stack = {
'owner_id': self.owner_id, 'owner_id': self.owner_id,
'username': self.username, 'username': self.username,
'tenant_id': self.tenant_id,
'timeout_mins': self.timeout_mins,
'disable_rollback': self.disable_rollback, 'disable_rollback': self.disable_rollback,
'stack_user_project_id': self.stack_user_project_id, 'stack_user_project_id': self.stack_user_project_id,
'user_creds_id': self.user_creds_id, 'user_creds_id': self.user_creds_id,
@ -426,8 +424,15 @@ class Stack(collections.Mapping):
'action': self.action, 'action': self.action,
'status': self.status, 'status': self.status,
'status_reason': self.status_reason}) 'status_reason': self.status_reason})
if not only_db:
if only_db:
stack['parent_resource_name'] = self.parent_resource_name
stack['tenant'] = self.tenant_id
stack['timeout'] = self.timeout_mins
else:
stack['parent_resource'] = self.parent_resource_name stack['parent_resource'] = self.parent_resource_name
stack['tenant_id'] = self.tenant_id
stack['timeout_mins'] = self.timeout_mins
stack['strict_validate'] = self.strict_validate stack['strict_validate'] = self.strict_validate
return stack return stack
@ -446,11 +451,6 @@ class Stack(collections.Mapping):
s['raw_template_id'] = self.t.store(self.context) s['raw_template_id'] = self.t.store(self.context)
else: else:
s['raw_template_id'] = self.t.id s['raw_template_id'] = self.t.id
# name inconsistencies
s['tenant'] = s['tenant_id']
del s['tenant_id']
s['timeout'] = s['timeout_mins']
del s['timeout_mins']
if self.id: if self.id:
stack_object.Stack.update_by_id(self.context, self.id, s) stack_object.Stack.update_by_id(self.context, self.id, s)

View File

@ -58,6 +58,7 @@ class Stack(
'prev_raw_template_id': fields.IntegerField(), 'prev_raw_template_id': fields.IntegerField(),
'prev_raw_template': fields.ObjectField('RawTemplate'), 'prev_raw_template': fields.ObjectField('RawTemplate'),
'tags': fields.ObjectField('StackTagList'), 'tags': fields.ObjectField('StackTagList'),
'parent_resource_name': fields.StringField(nullable=True),
} }
@staticmethod @staticmethod

View File

@ -185,7 +185,7 @@ class EngineClient(object):
def _create_stack(self, ctxt, stack_name, template, params, files, args, def _create_stack(self, ctxt, stack_name, template, params, files, args,
owner_id=None, nested_depth=0, user_creds_id=None, owner_id=None, nested_depth=0, user_creds_id=None,
stack_user_project_id=None): stack_user_project_id=None, parent_resource_name=None):
""" """
Internal create_stack interface for engine-to-engine communication via Internal create_stack interface for engine-to-engine communication via
RPC. Allows some additional options which should not be exposed to RPC. Allows some additional options which should not be exposed to
@ -194,6 +194,7 @@ class EngineClient(object):
:param nested_depth: nested depth for nested stacks :param nested_depth: nested depth for nested stacks
:param user_creds_id: user_creds record for nested stack :param user_creds_id: user_creds record for nested stack
:param stack_user_project_id: stack user project for nested stack :param stack_user_project_id: stack user project for nested stack
:param parent_resource_name: the parent resource name
""" """
return self.call( return self.call(
ctxt, self.make_msg('create_stack', stack_name=stack_name, ctxt, self.make_msg('create_stack', stack_name=stack_name,
@ -202,8 +203,9 @@ class EngineClient(object):
owner_id=owner_id, owner_id=owner_id,
nested_depth=nested_depth, nested_depth=nested_depth,
user_creds_id=user_creds_id, user_creds_id=user_creds_id,
stack_user_project_id=stack_user_project_id), stack_user_project_id=stack_user_project_id,
version='1.2') parent_resource_name=parent_resource_name),
version='1.7')
def update_stack(self, ctxt, stack_identity, template, params, def update_stack(self, ctxt, stack_identity, template, params,
files, args): files, args):

View File

@ -606,6 +606,9 @@ class HeatMigrationsCheckers(test_migrations.WalkVersionsMixin,
self.assertColumnType(engine, tab_name, 'status_reason', self.assertColumnType(engine, tab_name, 'status_reason',
sqlalchemy.Text) sqlalchemy.Text)
def _check_062(self, engine, data):
self.assertColumnExists(engine, 'stack', 'parent_resource_name')
class TestHeatMigrationsMySQL(HeatMigrationsCheckers, class TestHeatMigrationsMySQL(HeatMigrationsCheckers,
test_base.MySQLOpportunisticTestCase): test_base.MySQLOpportunisticTestCase):

View File

@ -506,8 +506,9 @@ class CfnStackControllerTest(common.HeatTestCase):
'owner_id': None, 'owner_id': None,
'nested_depth': 0, 'nested_depth': 0,
'user_creds_id': None, 'user_creds_id': None,
'parent_resource_name': None,
'stack_user_project_id': None}), 'stack_user_project_id': None}),
version='1.2' version='1.7'
).AndRaise(failure) ).AndRaise(failure)
def _stub_rpc_create_stack_call_success(self, stack_name, engine_parms, def _stub_rpc_create_stack_call_success(self, stack_name, engine_parms,
@ -533,8 +534,9 @@ class CfnStackControllerTest(common.HeatTestCase):
'owner_id': None, 'owner_id': None,
'nested_depth': 0, 'nested_depth': 0,
'user_creds_id': None, 'user_creds_id': None,
'parent_resource_name': None,
'stack_user_project_id': None}), 'stack_user_project_id': None}),
version='1.2' version='1.7'
).AndReturn(engine_resp) ).AndReturn(engine_resp)
self.m.ReplayAll() self.m.ReplayAll()

View File

@ -741,8 +741,9 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
'owner_id': None, 'owner_id': None,
'nested_depth': 0, 'nested_depth': 0,
'user_creds_id': None, 'user_creds_id': None,
'parent_resource_name': None,
'stack_user_project_id': None}), 'stack_user_project_id': None}),
version='1.2' version='1.7'
).AndReturn(dict(identity)) ).AndReturn(dict(identity))
self.m.ReplayAll() self.m.ReplayAll()
@ -803,8 +804,9 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
'owner_id': None, 'owner_id': None,
'nested_depth': 0, 'nested_depth': 0,
'user_creds_id': None, 'user_creds_id': None,
'parent_resource_name': None,
'stack_user_project_id': None}), 'stack_user_project_id': None}),
version='1.2' version='1.7'
).AndReturn(dict(identity)) ).AndReturn(dict(identity))
self.m.ReplayAll() self.m.ReplayAll()
@ -889,8 +891,9 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
'owner_id': None, 'owner_id': None,
'nested_depth': 0, 'nested_depth': 0,
'user_creds_id': None, 'user_creds_id': None,
'parent_resource_name': None,
'stack_user_project_id': None}), 'stack_user_project_id': None}),
version='1.2' version='1.7'
).AndReturn(dict(identity)) ).AndReturn(dict(identity))
self.m.ReplayAll() self.m.ReplayAll()
@ -932,8 +935,9 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
'owner_id': None, 'owner_id': None,
'nested_depth': 0, 'nested_depth': 0,
'user_creds_id': None, 'user_creds_id': None,
'parent_resource_name': None,
'stack_user_project_id': None}), 'stack_user_project_id': None}),
version='1.2' version='1.7'
).AndRaise(to_remote_error(AttributeError())) ).AndRaise(to_remote_error(AttributeError()))
rpc_client.EngineClient.call( rpc_client.EngineClient.call(
req.context, req.context,
@ -948,8 +952,9 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
'owner_id': None, 'owner_id': None,
'nested_depth': 0, 'nested_depth': 0,
'user_creds_id': None, 'user_creds_id': None,
'parent_resource_name': None,
'stack_user_project_id': None}), 'stack_user_project_id': None}),
version='1.2' version='1.7'
).AndRaise(to_remote_error(unknown_parameter)) ).AndRaise(to_remote_error(unknown_parameter))
rpc_client.EngineClient.call( rpc_client.EngineClient.call(
req.context, req.context,
@ -964,8 +969,9 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
'owner_id': None, 'owner_id': None,
'nested_depth': 0, 'nested_depth': 0,
'user_creds_id': None, 'user_creds_id': None,
'parent_resource_name': None,
'stack_user_project_id': None}), 'stack_user_project_id': None}),
version='1.2' version='1.7'
).AndRaise(to_remote_error(missing_parameter)) ).AndRaise(to_remote_error(missing_parameter))
self.m.ReplayAll() self.m.ReplayAll()
resp = request_with_middleware(fault.FaultWrapper, resp = request_with_middleware(fault.FaultWrapper,
@ -1017,8 +1023,9 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
'owner_id': None, 'owner_id': None,
'nested_depth': 0, 'nested_depth': 0,
'user_creds_id': None, 'user_creds_id': None,
'parent_resource_name': None,
'stack_user_project_id': None}), 'stack_user_project_id': None}),
version='1.2' version='1.7'
).AndRaise(to_remote_error(error)) ).AndRaise(to_remote_error(error))
self.m.ReplayAll() self.m.ReplayAll()
@ -1097,8 +1104,9 @@ class StackControllerTest(ControllerTest, common.HeatTestCase):
'owner_id': None, 'owner_id': None,
'nested_depth': 0, 'nested_depth': 0,
'user_creds_id': None, 'user_creds_id': None,
'parent_resource_name': None,
'stack_user_project_id': None}), 'stack_user_project_id': None}),
version='1.2' version='1.7'
).AndRaise(to_remote_error(error)) ).AndRaise(to_remote_error(error))
self.m.ReplayAll() self.m.ReplayAll()

View File

@ -473,7 +473,8 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
stack.t, owner_id=None, stack.t, owner_id=None,
nested_depth=0, user_creds_id=None, nested_depth=0, user_creds_id=None,
stack_user_project_id=None, stack_user_project_id=None,
convergence=False).AndReturn(stack) convergence=False,
parent_resource=None).AndReturn(stack)
self.m.StubOutWithMock(stack, 'validate') self.m.StubOutWithMock(stack, 'validate')
stack.validate().AndReturn(None) stack.validate().AndReturn(None)
@ -528,7 +529,8 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
nested_depth=0, nested_depth=0,
user_creds_id=None, user_creds_id=None,
stack_user_project_id=None, stack_user_project_id=None,
convergence=False).AndReturn(stack) convergence=False,
parent_resource=None).AndReturn(stack)
self.m.StubOutWithMock(stack, 'validate') self.m.StubOutWithMock(stack, 'validate')
stack.validate().AndRaise(exception.StackValidationFailed( stack.validate().AndRaise(exception.StackValidationFailed(
@ -697,7 +699,8 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
stack.t, owner_id=None, stack.t, owner_id=None,
nested_depth=0, user_creds_id=None, nested_depth=0, user_creds_id=None,
stack_user_project_id=None, stack_user_project_id=None,
convergence=False).AndReturn(stack) convergence=False,
parent_resource=None).AndReturn(stack)
templatem.Template(template, files=None, templatem.Template(template, files=None,
env=stack.env).AndReturn(stack.t) env=stack.env).AndReturn(stack.t)
@ -706,7 +709,8 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
stack.t, owner_id=None, stack.t, owner_id=None,
nested_depth=0, user_creds_id=None, nested_depth=0, user_creds_id=None,
stack_user_project_id=None, stack_user_project_id=None,
convergence=False).AndReturn(stack) convergence=False,
parent_resource=None).AndReturn(stack)
self.m.ReplayAll() self.m.ReplayAll()
@ -755,7 +759,8 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
nested_depth=0, nested_depth=0,
user_creds_id=None, user_creds_id=None,
stack_user_project_id=None, stack_user_project_id=None,
convergence=False).AndReturn(stack) convergence=False,
parent_resource=None).AndReturn(stack)
self.m.ReplayAll() self.m.ReplayAll()
@ -1731,7 +1736,7 @@ class StackServiceTest(common.HeatTestCase):
def test_make_sure_rpc_version(self): def test_make_sure_rpc_version(self):
self.assertEqual( self.assertEqual(
'1.6', '1.7',
service.EngineService.RPC_API_VERSION, service.EngineService.RPC_API_VERSION,
('RPC version is changed, please update this test to new version ' ('RPC version is changed, please update this test to new version '
'and make sure additional test cases are added for RPC APIs ' 'and make sure additional test cases are added for RPC APIs '

View File

@ -154,6 +154,7 @@ class EngineRpcAPITestCase(common.HeatTestCase):
call_kwargs['nested_depth'] = 0 call_kwargs['nested_depth'] = 0
call_kwargs['user_creds_id'] = None call_kwargs['user_creds_id'] = None
call_kwargs['stack_user_project_id'] = None call_kwargs['stack_user_project_id'] = None
call_kwargs['parent_resource_name'] = None
expected_message = self.rpcapi.make_msg('create_stack', **call_kwargs) expected_message = self.rpcapi.make_msg('create_stack', **call_kwargs)
kwargs['expected_message'] = expected_message kwargs['expected_message'] = expected_message
self._test_engine_api('create_stack', 'call', **kwargs) self._test_engine_api('create_stack', 'call', **kwargs)

View File

@ -266,7 +266,8 @@ class StackTest(common.HeatTestCase):
self.assertEqual('test value', stk.root_stack) self.assertEqual('test value', stk.root_stack)
def test_load_parent_resource(self): def test_load_parent_resource(self):
self.stack = stack.Stack(self.ctx, 'load_parent_resource', self.tmpl) self.stack = stack.Stack(self.ctx, 'load_parent_resource', self.tmpl,
parent_resource='parent')
self.stack.store() self.stack.store()
stk = stack_object.Stack.get_by_id(self.ctx, self.stack.id) stk = stack_object.Stack.get_by_id(self.ctx, self.stack.id)
@ -295,8 +296,7 @@ class StackTest(common.HeatTestCase):
tags=mox.IgnoreArg()) tags=mox.IgnoreArg())
self.m.ReplayAll() self.m.ReplayAll()
stack.Stack.load(self.ctx, stack_id=self.stack.id, stack.Stack.load(self.ctx, stack_id=self.stack.id)
parent_resource='parent')
self.m.VerifyAll() self.m.VerifyAll()
@ -1812,13 +1812,11 @@ class StackKwargsForCloningTest(common.HeatTestCase):
not_included=['action', 'status', 'status_reason'])), not_included=['action', 'status', 'status_reason'])),
('only_db', dict(keep_status=False, only_db=True, ('only_db', dict(keep_status=False, only_db=True,
not_included=['action', 'status', 'status_reason', not_included=['action', 'status', 'status_reason',
'parent_resource',
'strict_validate'])), 'strict_validate'])),
('keep_status', dict(keep_status=True, only_db=False, ('keep_status', dict(keep_status=True, only_db=False,
not_included=[])), not_included=[])),
('status_db', dict(keep_status=True, only_db=True, ('status_db', dict(keep_status=True, only_db=True,
not_included=['parent_resource', not_included=['strict_validate'])),
'strict_validate'])),
] ]
def test_kwargs(self): def test_kwargs(self):
@ -1832,6 +1830,13 @@ class StackKwargsForCloningTest(common.HeatTestCase):
username='jo', nested_depth=3, username='jo', nested_depth=3,
strict_validate=True, convergence=False, strict_validate=True, convergence=False,
current_traversal=45) current_traversal=45)
db_map = {'parent_resource': 'parent_resource_name',
'tenant_id': 'tenant', 'timeout_mins': 'timeout'}
test_db_data = {}
for key in test_data:
dbkey = db_map.get(key, key)
test_db_data[dbkey] = test_data[key]
self.stack = stack.Stack(ctx, utils.random_name(), tmpl, self.stack = stack.Stack(ctx, utils.random_name(), tmpl,
**test_data) **test_data)
res = self.stack.get_kwargs_for_cloning(keep_status=self.keep_status, res = self.stack.get_kwargs_for_cloning(keep_status=self.keep_status,
@ -1841,8 +1846,13 @@ class StackKwargsForCloningTest(common.HeatTestCase):
for key in test_data: for key in test_data:
if key not in self.not_included: if key not in self.not_included:
self.assertEqual(test_data[key], res[key]) dbkey = db_map.get(key, key)
if self.only_db:
self.assertEqual(test_data[key], res[dbkey])
else:
self.assertEqual(test_data[key], res[key])
# just make sure that the kwargs are valid if not self.only_db:
# (no exception should be raised) # just make sure that the kwargs are valid
stack.Stack(ctx, utils.random_name(), tmpl, **res) # (no exception should be raised)
stack.Stack(ctx, utils.random_name(), tmpl, **res)

View File

@ -430,7 +430,6 @@ class StackResourceTest(common.HeatTestCase):
self.m.StubOutWithMock(parser.Stack, 'load') self.m.StubOutWithMock(parser.Stack, 'load')
parser.Stack.load(self.parent_resource.context, parser.Stack.load(self.parent_resource.context,
self.parent_resource.resource_id, self.parent_resource.resource_id,
parent_resource=self.parent_resource.name,
show_deleted=False, show_deleted=False,
force_reload=False).AndReturn('s') force_reload=False).AndReturn('s')
self.m.ReplayAll() self.m.ReplayAll()
@ -443,7 +442,6 @@ class StackResourceTest(common.HeatTestCase):
self.m.StubOutWithMock(parser.Stack, 'load') self.m.StubOutWithMock(parser.Stack, 'load')
parser.Stack.load(self.parent_resource.context, parser.Stack.load(self.parent_resource.context,
self.parent_resource.resource_id, self.parent_resource.resource_id,
parent_resource=self.parent_resource.name,
show_deleted=False, show_deleted=False,
force_reload=True).AndReturn('ok') force_reload=True).AndReturn('ok')
self.m.ReplayAll() self.m.ReplayAll()
@ -457,7 +455,6 @@ class StackResourceTest(common.HeatTestCase):
self.m.StubOutWithMock(parser.Stack, 'load') self.m.StubOutWithMock(parser.Stack, 'load')
parser.Stack.load(self.parent_resource.context, parser.Stack.load(self.parent_resource.context,
self.parent_resource.resource_id, self.parent_resource.resource_id,
parent_resource=self.parent_resource.name,
show_deleted=False, show_deleted=False,
force_reload=False).AndReturn(None) force_reload=False).AndReturn(None)
self.m.ReplayAll() self.m.ReplayAll()
@ -475,7 +472,6 @@ class StackResourceTest(common.HeatTestCase):
self.m.StubOutWithMock(parser.Stack, 'load') self.m.StubOutWithMock(parser.Stack, 'load')
parser.Stack.load(self.parent_resource.context, parser.Stack.load(self.parent_resource.context,
self.parent_resource.resource_id, self.parent_resource.resource_id,
parent_resource=self.parent_resource.name,
show_deleted=False, show_deleted=False,
force_reload=True).AndReturn('s') force_reload=True).AndReturn('s')
self.m.ReplayAll() self.m.ReplayAll()
@ -489,7 +485,6 @@ class StackResourceTest(common.HeatTestCase):
self.m.StubOutWithMock(parser.Stack, 'load') self.m.StubOutWithMock(parser.Stack, 'load')
parser.Stack.load(self.parent_resource.context, parser.Stack.load(self.parent_resource.context,
self.parent_resource.resource_id, self.parent_resource.resource_id,
parent_resource=self.parent_resource.name,
show_deleted=False, show_deleted=False,
force_reload=True).AndReturn(None) force_reload=True).AndReturn(None)
self.m.ReplayAll() self.m.ReplayAll()

View File

@ -79,7 +79,11 @@ resource_registry:
template=main_templ, template=main_templ,
files={'nested.yaml': nested_templ}, files={'nested.yaml': nested_templ},
environment=env_templ) environment=env_templ)
self.assert_resource_is_a_stack(stack_identifier, 'secret1') nested_ident = self.assert_resource_is_a_stack(stack_identifier,
'secret1')
# prove that resource.parent_resource is populated.
sec2 = self.client.resources.get(nested_ident, 'secret2')
self.assertEqual('secret1', sec2.parent_resource)
def test_no_infinite_recursion(self): def test_no_infinite_recursion(self):
"""Prove that we can override a python resource. """Prove that we can override a python resource.