diff options
author | Thomas Spatzier <thomas.spatzier@de.ibm.com> | 2014-05-20 11:08:59 +0200 |
---|---|---|
committer | Thomas Spatzier <thomas.spatzier@de.ibm.com> | 2014-06-10 13:35:11 +0200 |
commit | a39ee7c87562eab3dbf176eb265866f61f5a5af7 (patch) | |
tree | 4c0be260fc8c28f9cb577c991cf5e0a2634e7c8c | |
parent | aa7c0306bcc77320b670e0e15895b4b6b3944250 (diff) | |
download | heat-a39ee7c87562eab3dbf176eb265866f61f5a5af7.tar.gz |
Do no re-validate parameters for existing stacks
This patch disables validation of stack parameters values when
loading existing stacks from the database. The old behavior was
to always validate stack parameter values when initializing a
Stack object. However, this causes problems especially with
custom constraints when a constraint could be fulfilled during
stack creation but cannot be fulfilled at a later point (e.g.
when a flavor or keypair has been deleted). In such a case,
the existing stack became completely unusable.
This patch changes the behavior to not do parameter validation
for existing stacks. The assumption is that validation at stack
creation time should be sufficient to make sure the stack is valid,
so only valid stacks end up in the database. Therefore, validating
parameters again when loading stacks is not really required.
Closes-Bug: #1314401
Cherry-pick from review https://review.openstack.org/#/c/94329
(cherry picked from commit 349a6f04b53309f7fa8f3225f98d41670888d20c)
Conflicts:
heat/tests/test_parser.py
Change-Id: I0947c2dcfb9db4c81b07de582aab86f262d0c008
-rw-r--r-- | heat/engine/parser.py | 8 | ||||
-rw-r--r-- | heat/tests/test_parser.py | 56 |
2 files changed, 60 insertions, 4 deletions
diff --git a/heat/engine/parser.py b/heat/engine/parser.py index 3637317e5..73074919c 100644 --- a/heat/engine/parser.py +++ b/heat/engine/parser.py @@ -61,7 +61,7 @@ class Stack(collections.Mapping): disable_rollback=True, parent_resource=None, owner_id=None, adopt_stack_data=None, stack_user_project_id=None, created_time=None, updated_time=None, - user_creds_id=None, tenant_id=None): + user_creds_id=None, tenant_id=None, validate_parameters=True): ''' Initialise from a context, name, Template object and (optionally) Environment object. The database ID may also be initialised, if the @@ -105,7 +105,8 @@ class Stack(collections.Mapping): self.env = env or environment.Environment({}) self.parameters = self.t.parameters(self.identifier(), user_params=self.env.params) - self.parameters.validate(validate_value=True, context=context) + self.parameters.validate(validate_value=validate_parameters, + context=context) self._set_param_stackid() if resolve_data: @@ -193,7 +194,8 @@ class Stack(collections.Mapping): stack_user_project_id=stack.stack_user_project_id, created_time=stack.created_at, updated_time=stack.updated_at, - user_creds_id=stack.user_creds_id, tenant_id=stack.tenant) + user_creds_id=stack.user_creds_id, tenant_id=stack.tenant, + validate_parameters=False) return stack diff --git a/heat/tests/test_parser.py b/heat/tests/test_parser.py index 24bfb76ba..1c7363ba5 100644 --- a/heat/tests/test_parser.py +++ b/heat/tests/test_parser.py @@ -11,6 +11,7 @@ # License for the specific language governing permissions and limitations # under the License. +import collections import json import time @@ -924,7 +925,8 @@ class StackTest(HeatTestCase): created_time=IgnoreArg(), updated_time=None, user_creds_id=stack.user_creds_id, - tenant_id='test_tenant_id') + tenant_id='test_tenant_id', + validate_parameters=False) self.m.ReplayAll() parser.Stack.load(self.ctx, stack_id=self.stack.id, @@ -2740,3 +2742,55 @@ class StackTest(HeatTestCase): resources = self.stack.preview_resources() self.assertEqual(['foo'], resources) + + def test_stack_load_no_param_value_validation(self): + ''' + Test stack loading with disabled parameter value validation. + ''' + tmpl = template_format.parse(''' + heat_template_version: 2013-05-23 + parameters: + flavor: + type: string + description: A flavor. + constraints: + - custom_constraint: nova.flavor + resources: + a_resource: + type: GenericResourceType + ''') + + # Mock objects so the query for flavors in server.FlavorConstraint + # works for stack creation + fc = fakes.FakeClient() + self.m.StubOutWithMock(clients.OpenStackClients, 'nova') + clients.OpenStackClients.nova().MultipleTimes().AndReturn(fc) + + fc.flavors = self.m.CreateMockAnything() + flavor = collections.namedtuple("Flavor", ["id", "name"]) + flavor.id = "1234" + flavor.name = "dummy" + fc.flavors.list().AndReturn([flavor]) + + self.m.ReplayAll() + + self.stack = parser.Stack(self.ctx, 'stack_with_custom_constraint', + template.Template(tmpl), + environment.Environment({'flavor': 'dummy'})) + + self.stack.store() + self.stack.create() + stack_id = self.stack.id + + self.m.VerifyAll() + + self.assertEqual((parser.Stack.CREATE, parser.Stack.COMPLETE), + self.stack.state) + + loaded_stack = parser.Stack.load(self.ctx, stack_id=self.stack.id) + self.assertEqual(stack_id, loaded_stack.parameters['OS::stack_id']) + + # verify that fc.flavors.list() has not been called, i.e. verify that + # parameter value validation did not happen and FlavorConstraint was + # not invoked + self.m.VerifyAll() |