From bb5fec7725524bec62498361163c9d3b25fcf2b2 Mon Sep 17 00:00:00 2001 From: Anant Patil Date: Wed, 11 Mar 2015 10:49:52 +1000 Subject: [PATCH] Store template + environment for rollback. In order to allow the user to roll back to a previous state, we need to store both the old template and the old environment. Moved the parameter column from 'stack' table to 'raw_template' table and renamed it to environment. Implements: blueprint convergence-parameter-storage Co-Authored-by: Angus Salkeld Co-Authored-by: Kanagaraj Manickam Change-Id: Ib776f651be0beccdc05b9973f152e2ff901970df --- .../056_convergence_parameter_storage.py | 179 ++++++++++++++++++ heat/db/sqlalchemy/models.py | 4 +- heat/engine/resources/stack_resource.py | 21 +- heat/engine/service.py | 23 +-- heat/engine/stack.py | 8 +- heat/engine/template.py | 10 +- heat/tests/test_engine_service.py | 65 ++++--- heat/tests/test_stack.py | 6 +- heat/tests/test_stack_resource.py | 11 +- heat/tests/test_stack_update.py | 6 +- heat/tests/utils.py | 7 +- 11 files changed, 263 insertions(+), 77 deletions(-) create mode 100644 heat/db/sqlalchemy/migrate_repo/versions/056_convergence_parameter_storage.py diff --git a/heat/db/sqlalchemy/migrate_repo/versions/056_convergence_parameter_storage.py b/heat/db/sqlalchemy/migrate_repo/versions/056_convergence_parameter_storage.py new file mode 100644 index 000000000..7d814d0b4 --- /dev/null +++ b/heat/db/sqlalchemy/migrate_repo/versions/056_convergence_parameter_storage.py @@ -0,0 +1,179 @@ +# +# 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 migrate +import sqlalchemy + +from heat.db.sqlalchemy import types as heat_db_types +from heat.db.sqlalchemy import utils as migrate_utils + + +def upgrade(migrate_engine): + if migrate_engine.name == 'sqlite': + upgrade_sqlite(migrate_engine) + return + + meta = sqlalchemy.MetaData() + meta.bind = migrate_engine + + tmpl_table = sqlalchemy.Table('raw_template', meta, autoload=True) + environment = sqlalchemy.Column('environment', heat_db_types.Json) + environment.create(tmpl_table) + predecessor = sqlalchemy.Column('predecessor', sqlalchemy.Integer) + predecessor.create(tmpl_table) + + fkey = migrate.ForeignKeyConstraint( + columns=[tmpl_table.c.predecessor], + refcolumns=[tmpl_table.c.id], + name='predecessor_fkey_ref') + fkey.create() + + stack_table = sqlalchemy.Table('stack', meta, autoload=True) + update_query = tmpl_table.update().values( + environment=sqlalchemy.select([stack_table.c.parameters]). + where(tmpl_table.c.id == stack_table.c.raw_template_id). + as_scalar()) + migrate_engine.execute(update_query) + + stack_table.c.parameters.drop() + + +def upgrade_sqlite(migrate_engine): + meta = sqlalchemy.MetaData() + meta.bind = migrate_engine + + tmpl_table = sqlalchemy.Table('raw_template', meta, autoload=True) + newcols = [ + sqlalchemy.Column('environment', heat_db_types.Json), + sqlalchemy.Column('predecessor', sqlalchemy.Integer, + sqlalchemy.ForeignKey('raw_template.id'))] + new_template = migrate_utils.clone_table('new_raw_template', + tmpl_table, + meta, newcols=newcols) + + stack_table = sqlalchemy.Table('stack', meta, autoload=True) + ignorecols = [stack_table.c.parameters.name] + new_stack = migrate_utils.clone_table('new_stack', stack_table, + meta, ignorecols=ignorecols) + + # migrate parameters to environment + templates = list(tmpl_table.select().order_by( + sqlalchemy.sql.expression.asc(tmpl_table.c.created_at)) + .execute()) + colnames = [c.name for c in tmpl_table.columns] + for template in templates: + values = dict(zip(colnames, + map(lambda colname: getattr(template, colname), + colnames))) + params = (stack_table.select(stack_table.c.parameters). + where(stack_table.c.raw_template_id == values['id']). + execute().fetchone()) + values['environment'] = params + migrate_engine.execute(new_template.insert(values)) + + # migrate stacks to new table + migrate_utils.migrate_data(migrate_engine, + stack_table, + new_stack, + skip_columns=['parameters']) + + # Drop old tables and rename new ones + tmpl_table.drop() + + # add the indexes back to new table + _add_indexes(migrate_engine, new_stack) + new_template.rename('raw_template') + + +def downgrade(migrate_engine): + if migrate_engine.name == 'sqlite': + downgrade_sqlite(migrate_engine) + return + + meta = sqlalchemy.MetaData() + meta.bind = migrate_engine + + stack_table = sqlalchemy.Table('stack', meta, autoload=True) + parameters = sqlalchemy.Column('parameters', heat_db_types.Json) + parameters.create(stack_table) + + tmpl_table = sqlalchemy.Table('raw_template', meta, autoload=True) + update_query = stack_table.update().values( + parameters=sqlalchemy.select([tmpl_table.c.environment]). + where(stack_table.c.raw_template_id == tmpl_table.c.id). + as_scalar()) + migrate_engine.execute(update_query) + + tmpl_table.c.environment.drop() + + fkey = migrate.ForeignKeyConstraint( + columns=[tmpl_table.c.predecessor], + refcolumns=[tmpl_table.c.id], + name='predecessor_fkey_ref') + fkey.drop() + tmpl_table.c.predecessor.drop() + + +def downgrade_sqlite(migrate_engine): + meta = sqlalchemy.MetaData() + meta.bind = migrate_engine + + stack_table = sqlalchemy.Table('stack', meta, autoload=True) + newcols = [sqlalchemy.Column('parameters', heat_db_types.Json)] + new_stack = migrate_utils.clone_table('new_stack', stack_table, + meta, newcols=newcols) + + tmpl_table = sqlalchemy.Table('raw_template', meta, autoload=True) + ignorecols = [tmpl_table.c.environment.name, tmpl_table.c.predecessor.name] + new_template = migrate_utils.clone_table('new_raw_template', tmpl_table, + meta, ignorecols=ignorecols) + + # migrate stack data to new table + stacks = list(stack_table.select().order_by( + sqlalchemy.sql.expression.asc(stack_table.c.created_at)) + .execute()) + colnames = [c.name for c in stack_table.columns] + for stack in stacks: + values = dict(zip(colnames, + map(lambda colname: getattr(stack, colname), + colnames))) + migrate_engine.execute(new_stack.insert(values)) + + update_query = new_stack.update().values( + parameters=sqlalchemy.select([tmpl_table.c.environment]). + where(new_stack.c.raw_template_id == tmpl_table.c.id). + as_scalar()) + migrate_engine.execute(update_query) + + # migrate template data to new table + migrate_utils.migrate_data(migrate_engine, + tmpl_table, + new_template, + skip_columns=['environment', 'predecessor']) + + stack_table.drop() + new_stack.rename('stack') + + # add the indexes back to new table + _add_indexes(migrate_engine, new_stack) + + +def _add_indexes(migrate_engine, stack): + name_index = sqlalchemy.Index('ix_stack_name', + stack.c.name, + mysql_length=255) + tenant_index = sqlalchemy.Index('ix_stack_tenant', + stack.c.tenant, + mysql_length=255) + name_index.create(migrate_engine) + tenant_index.create(migrate_engine) diff --git a/heat/db/sqlalchemy/models.py b/heat/db/sqlalchemy/models.py index 4b2e9efbf..604a049d4 100644 --- a/heat/db/sqlalchemy/models.py +++ b/heat/db/sqlalchemy/models.py @@ -107,6 +107,9 @@ class RawTemplate(BASE, HeatBase): id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True) template = sqlalchemy.Column(types.Json) files = sqlalchemy.Column(types.Json) + environment = sqlalchemy.Column('environment', types.Json) + predecessor = sqlalchemy.Column('predecessor', sqlalchemy.Integer, + sqlalchemy.ForeignKey('raw_template.id')) class StackTag(BASE, HeatBase): @@ -151,7 +154,6 @@ class Stack(BASE, HeatBase, SoftDelete, StateAware): foreign_keys=[prev_raw_template_id]) username = sqlalchemy.Column(sqlalchemy.String(256)) tenant = sqlalchemy.Column(sqlalchemy.String(256)) - parameters = sqlalchemy.Column('parameters', types.Json) user_creds_id = sqlalchemy.Column( sqlalchemy.Integer, sqlalchemy.ForeignKey('user_creds.id')) diff --git a/heat/engine/resources/stack_resource.py b/heat/engine/resources/stack_resource.py index 39bb3e630..58f2c8261 100644 --- a/heat/engine/resources/stack_resource.py +++ b/heat/engine/resources/stack_resource.py @@ -147,12 +147,12 @@ class StackResource(resource.Resource): return self.nested().preview_resources() - def _parse_child_template(self, child_template): + def _parse_child_template(self, child_template, child_env): parsed_child_template = child_template if isinstance(parsed_child_template, template.Template): parsed_child_template = parsed_child_template.t return template.Template(parsed_child_template, - files=self.stack.t.files) + files=self.stack.t.files, env=child_env) def _parse_nested_stack(self, stack_name, child_template, child_params=None, timeout_mins=None, @@ -162,7 +162,14 @@ class StackResource(resource.Resource): ) % cfg.CONF.max_nested_stack_depth raise exception.RequestLimitExceeded(message=msg) - parsed_template = self._parse_child_template(child_template) + if child_params is None: + child_params = self.child_params() + + child_env = environment.get_child_environment( + self.stack.env, child_params, + item_to_remove=self.resource_info) + + parsed_template = self._parse_child_template(child_template, child_env) self._validate_nested_resources(parsed_template) # Don't overwrite the attributes_schema for subclasses that @@ -177,19 +184,11 @@ class StackResource(resource.Resource): stack_user_project_id = self.stack.stack_user_project_id new_nested_depth = self.stack.nested_depth + 1 - if child_params is None: - child_params = self.child_params() - - child_env = environment.get_child_environment( - self.stack.env, child_params, - item_to_remove=self.resource_info) - # Note we disable rollback for nested stacks, since they # should be rolled back by the parent stack on failure nested = parser.Stack(self.context, stack_name, parsed_template, - env=child_env, timeout_mins=timeout_mins, disable_rollback=True, parent_resource=self.name, diff --git a/heat/engine/service.py b/heat/engine/service.py index 676b6945a..99f51ef59 100644 --- a/heat/engine/service.py +++ b/heat/engine/service.py @@ -533,9 +533,6 @@ class EngineService(service.Service): not cfg.CONF.enable_stack_adopt): raise exception.NotSupported(feature='Stack Adopt') - tmpl = templatem.Template(template, files=files) - self._validate_new_stack(cnxt, stack_name, tmpl) - if rpc_api.PARAM_ADOPT_STACK_DATA in common_params: # Override the params with values given with -P option new_params = common_params[rpc_api.PARAM_ADOPT_STACK_DATA][ @@ -544,7 +541,11 @@ class EngineService(service.Service): params[rpc_api.STACK_PARAMETERS] = new_params env = environment.Environment(params) - stack = parser.Stack(cnxt, stack_name, tmpl, env, + + tmpl = templatem.Template(template, files=files, env=env) + self._validate_new_stack(cnxt, stack_name, tmpl) + + stack = parser.Stack(cnxt, stack_name, tmpl, owner_id=owner_id, nested_depth=nested_depth, user_creds_id=user_creds_id, @@ -684,7 +685,12 @@ class EngineService(service.Service): # Now parse the template and any parameters for the updated # stack definition. - tmpl = templatem.Template(template, files=files) + env = environment.Environment(params) + if args.get(rpc_api.PARAM_EXISTING, None): + env.patch_previous_parameters( + current_stack.env, + args.get(rpc_api.PARAM_CLEAR_PARAMETERS, [])) + tmpl = templatem.Template(template, files=files, env=env) if len(tmpl[tmpl.RESOURCES]) > cfg.CONF.max_resources_per_stack: raise exception.RequestLimitExceeded( message=exception.StackResourceLimitExceeded.msg_fmt) @@ -695,13 +701,8 @@ class EngineService(service.Service): current_stack.timeout_mins) common_params.setdefault(rpc_api.PARAM_DISABLE_ROLLBACK, current_stack.disable_rollback) - env = environment.Environment(params) - if args.get(rpc_api.PARAM_EXISTING, None): - env.patch_previous_parameters( - current_stack.env, - args.get(rpc_api.PARAM_CLEAR_PARAMETERS, [])) updated_stack = parser.Stack(cnxt, stack_name, tmpl, - env, convergence=convergence, + convergence=convergence, **common_params) updated_stack.parameters.set_stack_id(current_stack.identifier()) diff --git a/heat/engine/stack.py b/heat/engine/stack.py index 08e606eb2..902c7ce30 100644 --- a/heat/engine/stack.py +++ b/heat/engine/stack.py @@ -33,7 +33,6 @@ from heat.common import identifier from heat.common import lifecycle_plugin_utils from heat.db import api as db_api from heat.engine import dependencies -from heat.engine import environment from heat.engine import function from heat.engine.notification import stack as notification from heat.engine import parameter_groups as param_groups @@ -136,7 +135,7 @@ class Stack(collections.Mapping): resources.initialise() - self.env = env or environment.Environment({}) + self.env = env or self.t.env self.parameters = self.t.parameters( self.identifier(), user_params=self.env.params, @@ -314,8 +313,7 @@ class Stack(collections.Mapping): use_stored_context=False): template = tmpl.Template.load( context, stack.raw_template_id, stack.raw_template) - env = environment.Environment(stack.parameters) - return cls(context, stack.name, template, env, + return cls(context, stack.name, template, template.env, stack.id, stack.action, stack.status, stack.status_reason, stack.timeout, resolve_data, stack.disable_rollback, parent_resource, owner_id=stack.owner_id, @@ -336,7 +334,6 @@ class Stack(collections.Mapping): s = { 'name': self._backup_name() if backup else self.name, 'raw_template_id': self.t.store(self.context), - 'parameters': self.env.user_env_as_dict(), 'owner_id': self.owner_id, 'username': self.username, 'tenant': self.tenant_id, @@ -806,6 +803,7 @@ class Stack(collections.Mapping): self.env = newstack.env self.parameters = newstack.parameters self.t.files = newstack.t.files + self.t.env = newstack.t.env self.disable_rollback = newstack.disable_rollback self.timeout_mins = newstack.timeout_mins self._set_param_stackid() diff --git a/heat/engine/template.py b/heat/engine/template.py index 6932e02ea..52c2f8454 100644 --- a/heat/engine/template.py +++ b/heat/engine/template.py @@ -23,6 +23,7 @@ from stevedore import extension from heat.common import exception from heat.common.i18n import _ from heat.db import api as db_api +from heat.engine import environment LOG = logging.getLogger(__name__) @@ -106,7 +107,7 @@ class Template(collections.Mapping): return super(Template, cls).__new__(TemplateClass) - def __init__(self, template, template_id=None, files=None): + def __init__(self, template, template_id=None, files=None, env=None): ''' Initialise the template with a JSON object and a set of Parameters ''' @@ -114,6 +115,7 @@ class Template(collections.Mapping): self.t = template self.files = files or {} self.maps = self[self.MAPPINGS] + self.env = env or environment.Environment({}) self.version = get_version(self.t, _template_classes.keys()) def __deepcopy__(self, memo): @@ -124,13 +126,15 @@ class Template(collections.Mapping): '''Retrieve a Template with the given ID from the database.''' if t is None: t = db_api.raw_template_get(context, template_id) - return cls(t.template, template_id=template_id, files=t.files) + env = environment.Environment(t.environment) + return cls(t.template, template_id=template_id, files=t.files, env=env) def store(self, context=None): '''Store the Template in the database and return its ID.''' rt = { 'template': self.t, - 'files': self.files + 'files': self.files, + 'environment': self.env.user_env_as_dict() } if self.id is None: new_rt = db_api.raw_template_create(context, rt) diff --git a/heat/tests/test_engine_service.py b/heat/tests/test_engine_service.py index a45cf64f8..7869c7aaa 100644 --- a/heat/tests/test_engine_service.py +++ b/heat/tests/test_engine_service.py @@ -174,17 +174,16 @@ resources: def get_wordpress_stack(stack_name, ctx): t = template_format.parse(wp_template) - template = templatem.Template(t) - stack = parser.Stack(ctx, stack_name, template, - environment.Environment({'KeyName': 'test'})) + template = templatem.Template( + t, env=environment.Environment({'KeyName': 'test'})) + stack = parser.Stack(ctx, stack_name, template) return stack def get_wordpress_stack_no_params(stack_name, ctx): t = template_format.parse(wp_template) template = templatem.Template(t) - stack = parser.Stack(ctx, stack_name, template, - environment.Environment({})) + stack = parser.Stack(ctx, stack_name, template) return stack @@ -452,10 +451,11 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase): self.m.StubOutWithMock(environment, 'Environment') self.m.StubOutWithMock(parser, 'Stack') - templatem.Template(template, files=None).AndReturn(stack.t) + templatem.Template(template, files=None, + env=stack.env).AndReturn(stack.t) environment.Environment(params).AndReturn(stack.env) parser.Stack(self.ctx, stack.name, - stack.t, stack.env, owner_id=None, + stack.t, owner_id=None, nested_depth=0, user_creds_id=None, stack_user_project_id=None, convergence=False).AndReturn(stack) @@ -504,11 +504,11 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase): self.m.StubOutWithMock(environment, 'Environment') self.m.StubOutWithMock(parser, 'Stack') - templatem.Template(template, files=None).AndReturn(stack.t) + templatem.Template(template, files=None, + env=stack.env).AndReturn(stack.t) environment.Environment(params).AndReturn(stack.env) parser.Stack(self.ctx, stack.name, stack.t, - stack.env, owner_id=None, nested_depth=0, user_creds_id=None, @@ -565,7 +565,7 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase): stack = db_api.stack_get(self.ctx, result['stack_id']) self.assertEqual(template, stack.raw_template.template) self.assertEqual(environment['parameters'], - stack.parameters['parameters']) + stack.raw_template.environment['parameters']) def test_stack_adopt_saves_input_params(self): cfg.CONF.set_override('enable_stack_adopt', True) @@ -584,7 +584,7 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase): stack = db_api.stack_get(self.ctx, result['stack_id']) self.assertEqual(template, stack.raw_template.template) self.assertEqual(input_params['parameters'], - stack.parameters['parameters']) + stack.raw_template.environment['parameters']) def test_stack_adopt_stack_state(self): cfg.CONF.set_override('enable_stack_adopt', True) @@ -674,18 +674,20 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase): ctx_no_pwd = utils.dummy_context(password=None) ctx_no_user = utils.dummy_context(user=None) - templatem.Template(template, files=None).AndReturn(stack.t) + templatem.Template(template, files=None, + env=stack.env).AndReturn(stack.t) environment.Environment(params).AndReturn(stack.env) parser.Stack(ctx_no_pwd, stack.name, - stack.t, stack.env, owner_id=None, + stack.t, owner_id=None, nested_depth=0, user_creds_id=None, stack_user_project_id=None, convergence=False).AndReturn(stack) - templatem.Template(template, files=None).AndReturn(stack.t) + templatem.Template(template, files=None, + env=stack.env).AndReturn(stack.t) environment.Environment(params).AndReturn(stack.env) parser.Stack(ctx_no_user, stack.name, - stack.t, stack.env, owner_id=None, + stack.t, owner_id=None, nested_depth=0, user_creds_id=None, stack_user_project_id=None, convergence=False).AndReturn(stack) @@ -729,11 +731,11 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase): self.m.StubOutWithMock(environment, 'Environment') self.m.StubOutWithMock(parser, 'Stack') - templatem.Template(template, files=None).AndReturn(stack.t) + templatem.Template(template, files=None, + env=stack.env).AndReturn(stack.t) environment.Environment(params).AndReturn(stack.env) parser.Stack(self.ctx, stack.name, stack.t, - stack.env, owner_id=None, nested_depth=0, user_creds_id=None, @@ -1005,10 +1007,11 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase): self._stub_update_mocks(s, old_stack) - templatem.Template(template, files=None).AndReturn(stack.t) + templatem.Template(template, files=None, + env=stack.env).AndReturn(stack.t) environment.Environment(params).AndReturn(stack.env) parser.Stack(self.ctx, stack.name, - stack.t, stack.env, + stack.t, timeout_mins=60, disable_rollback=True, convergence=False).AndReturn(stack) @@ -1054,10 +1057,10 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase): self._stub_update_mocks(s, old_stack) templatem.Template(wp_template_no_default, - files=None).AndReturn(stack.t) + files=None, env=old_stack.env).AndReturn(stack.t) environment.Environment(no_params).AndReturn(old_stack.env) parser.Stack(self.ctx, stack.name, - stack.t, old_stack.env, + stack.t, timeout_mins=60, disable_rollback=True, convergence=False).AndReturn(stack) @@ -1098,10 +1101,11 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase): self._stub_update_mocks(s, old_stack) - templatem.Template(template, files=None).AndReturn(stack.t) + templatem.Template(template, files=None, + env=stack.env).AndReturn(stack.t) environment.Environment(params).AndReturn(stack.env) parser.Stack(self.ctx, stack.name, - stack.t, stack.env, + stack.t, timeout_mins=1, disable_rollback=False, convergence=False).AndReturn(stack) @@ -1176,10 +1180,11 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase): self._stub_update_mocks(s, old_stack) - templatem.Template(template, files=None).AndReturn(stack.t) + templatem.Template(template, files=None, + env=stack.env).AndReturn(stack.t) environment.Environment(params).AndReturn(stack.env) parser.Stack(self.ctx, stack.name, - stack.t, stack.env, + stack.t, timeout_mins=60, disable_rollback=True, convergence=False).AndReturn(stack) @@ -1297,10 +1302,11 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase): self._stub_update_mocks(s, old_stack) - templatem.Template(template, files=None).AndReturn(stack.t) + templatem.Template(template, files=None, + env=stack.env).AndReturn(stack.t) environment.Environment(params).AndReturn(stack.env) parser.Stack(self.ctx, stack.name, - stack.t, stack.env, + stack.t, timeout_mins=60, disable_rollback=True, convergence=False).AndReturn(stack) @@ -1354,10 +1360,11 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase): self._stub_update_mocks(s, old_stack) - templatem.Template(template, files=None).AndReturn(old_stack.t) + templatem.Template(template, files=None, + env=old_stack.env).AndReturn(old_stack.t) environment.Environment(params).AndReturn(old_stack.env) parser.Stack(self.ctx, old_stack.name, - old_stack.t, old_stack.env, + old_stack.t, timeout_mins=60, disable_rollback=True, convergence=False).AndReturn(old_stack) diff --git a/heat/tests/test_stack.py b/heat/tests/test_stack.py index 8c71631bc..3bd70d314 100644 --- a/heat/tests/test_stack.py +++ b/heat/tests/test_stack.py @@ -273,12 +273,8 @@ class StackTest(common.HeatTestCase): self.ctx, stk.raw_template_id, stk.raw_template ).AndReturn(t) - env = environment.Environment(stk.parameters) - self.m.StubOutWithMock(environment, 'Environment') - environment.Environment(stk.parameters).AndReturn(env) - self.m.StubOutWithMock(stack.Stack, '__init__') - stack.Stack.__init__(self.ctx, stk.name, t, env, stk.id, + stack.Stack.__init__(self.ctx, stk.name, t, t.env, stk.id, stk.action, stk.status, stk.status_reason, stk.timeout, True, stk.disable_rollback, 'parent', owner_id=None, diff --git a/heat/tests/test_stack_resource.py b/heat/tests/test_stack_resource.py index d7bdedcba..0f291f088 100644 --- a/heat/tests/test_stack_resource.py +++ b/heat/tests/test_stack_resource.py @@ -214,7 +214,7 @@ class StackResourceTest(common.HeatTestCase): are passed on to the child stack. """ self.parent_stack.t.files["foo"] = "bar" - parsed_t = self.parent_resource._parse_child_template(self.templ) + parsed_t = self.parent_resource._parse_child_template(self.templ, None) self.assertEqual({"foo": "bar"}, parsed_t.files) @mock.patch('heat.engine.environment.get_child_environment') @@ -245,7 +245,6 @@ class StackResourceTest(common.HeatTestCase): mock.ANY, 'test_stack-test', mock.ANY, - env='environment', timeout_mins=None, disable_rollback=True, parent_resource=parent_resource.name, @@ -285,7 +284,6 @@ class StackResourceTest(common.HeatTestCase): mock.ANY, 'test_stack-test', mock.ANY, - env='environment', timeout_mins=None, disable_rollback=True, parent_resource=parent_resource.name, @@ -312,9 +310,10 @@ class StackResourceTest(common.HeatTestCase): 'test', resource_defns[self.ws_resname], self.parent_stack) + stk_resource.child_params = mock.Mock(return_value={}) stk_resource.child_template = mock.Mock( - return_value=templatem.Template(self.simple_template)) - stk_resource.child_params = mock.Mock() + return_value=templatem.Template(self.simple_template, + stk_resource.child_params)) exc = exception.RequestLimitExceeded(message='Validation Failed') validation_mock = mock.Mock(side_effect=exc) stk_resource._validate_nested_resources = validation_mock @@ -329,9 +328,9 @@ class StackResourceTest(common.HeatTestCase): 'test', resource_defns[self.ws_resname], self.parent_stack) + stk_resource.child_params = mock.Mock(return_value={}) stk_resource.child_template = mock.Mock( return_value=self.simple_template) - stk_resource.child_params = mock.Mock() exc = exception.RequestLimitExceeded(message='Validation Failed') validation_mock = mock.Mock(side_effect=exc) stk_resource._validate_nested_resources = validation_mock diff --git a/heat/tests/test_stack_update.py b/heat/tests/test_stack_update.py index 3bc3f1564..24c45a34f 100644 --- a/heat/tests/test_stack_update.py +++ b/heat/tests/test_stack_update.py @@ -1332,7 +1332,7 @@ class StackUpdateTest(common.HeatTestCase): env2 = environment.Environment({'smelly-param': 'smelly'}) self.stack = stack.Stack(self.ctx, 'update_test_stack', - template.Template(tmpl), env1, + template.Template(tmpl, env=env1), disable_rollback=True) self.stack.store() @@ -1360,7 +1360,7 @@ class StackUpdateTest(common.HeatTestCase): self.m.ReplayAll() updated_stack = stack.Stack(self.ctx, 'updated_stack', - template.Template(tmpl2), env2, + template.Template(tmpl2, env=env2), disable_rollback=True) self.stack.update(updated_stack) self.assertEqual((stack.Stack.UPDATE, stack.Stack.FAILED), @@ -1369,7 +1369,7 @@ class StackUpdateTest(common.HeatTestCase): self.stack = stack.Stack.load(self.ctx, self.stack.id) updated_stack2 = stack.Stack(self.ctx, 'updated_stack', - template.Template(tmpl2), env2, + template.Template(tmpl2, env=env2), disable_rollback=True) self.stack.update(updated_stack2) diff --git a/heat/tests/utils.py b/heat/tests/utils.py index ef8e65222..35bdb124b 100644 --- a/heat/tests/utils.py +++ b/heat/tests/utils.py @@ -91,11 +91,12 @@ def parse_stack(t, params=None, files=None, stack_name=None, params = params or {} files = files or {} ctx = dummy_context() - templ = template.Template(t, files=files) + templ = template.Template(t, files=files, + env=environment.Environment(params)) + templ.store() if stack_name is None: stack_name = random_name() - stk = stack.Stack(ctx, stack_name, templ, - environment.Environment(params), stack_id, + stk = stack.Stack(ctx, stack_name, templ, stack_id, timeout_mins=timeout_mins) stk.store() return stk