Make StackResource less strict on initial validation
When doing the initial validate(), skip validating values by setting
the stack strict_validate to False, otherwise we incorrectly fail
validation when values are passed in via properties/parameters which
refer to resources in the parent stack.
Co-Authored-by: Angus Salkeld <asalkeld@mirantis.com>
Change-Id: Ib75c2de6c32373de72901b9f7c5e3828bd9ee7d9
Closes-Bug: #1407100
Closes-Bug: #1407877
Closes-Bug: #1405446
diff --git a/common/test.py b/common/test.py
index 3de44f5..450ed82 100644
--- a/common/test.py
+++ b/common/test.py
@@ -331,7 +331,8 @@
return dict((r.resource_name, r.resource_type) for r in resources)
def stack_create(self, stack_name=None, template=None, files=None,
- parameters=None, environment=None):
+ parameters=None, environment=None,
+ expected_status='CREATE_COMPLETE'):
name = stack_name or self._stack_rand_name()
templ = template or self.template
templ_files = files or {}
@@ -349,5 +350,5 @@
stack = self.client.stacks.get(name)
stack_identifier = '%s/%s' % (name, stack.id)
- self._wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
+ self._wait_for_stack_status(stack_identifier, expected_status)
return stack_identifier
diff --git a/functional/test_validation.py b/functional/test_validation.py
new file mode 100644
index 0000000..52309cd
--- /dev/null
+++ b/functional/test_validation.py
@@ -0,0 +1,95 @@
+# 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 logging
+
+from heat_integrationtests.common import test
+
+
+LOG = logging.getLogger(__name__)
+
+
+class StackValidationTest(test.HeatIntegrationTest):
+
+ def setUp(self):
+ super(StackValidationTest, self).setUp()
+ self.client = self.orchestration_client
+ if not self.conf.minimal_image_ref:
+ raise self.skipException("No image configured to test")
+
+ if not self.conf.instance_type:
+ raise self.skipException("No instance_type configured to test")
+
+ if self.conf.keypair_name:
+ self.keypair_name = self.conf.keypair_name
+ else:
+ self.keypair = self.create_keypair()
+ self.keypair_name = self.keypair.id
+
+ def test_stack_validate_provider_references_parent_resource(self):
+ template = '''
+heat_template_version: 2014-10-16
+parameters:
+ keyname:
+ type: string
+ flavor:
+ type: string
+ image:
+ type: string
+resources:
+ config:
+ type: My::Config
+ properties:
+ server: {get_resource: server}
+
+ server:
+ type: OS::Nova::Server
+ properties:
+ image: {get_param: image}
+ flavor: {get_param: flavor}
+ key_name: {get_param: keyname}
+ user_data_format: SOFTWARE_CONFIG
+'''
+ config_template = '''
+heat_template_version: 2014-10-16
+parameters:
+ server:
+ type: string
+resources:
+ config:
+ type: OS::Heat::SoftwareConfig
+
+ deployment:
+ type: OS::Heat::SoftwareDeployment
+ properties:
+ config:
+ get_resource: config
+ server:
+ get_param: server
+'''
+ files = {'provider.yaml': config_template}
+ env = {'resource_registry':
+ {'My::Config': 'provider.yaml'}}
+ parameters = {'keyname': self.keypair_name,
+ 'flavor': self.conf.instance_type,
+ 'image': self.conf.minimal_image_ref}
+ # Note we don't wait for CREATE_COMPLETE, because we're using a
+ # minimal image without the tools to apply the config.
+ # The point of the test is just to prove that validation won't
+ # falsely prevent stack creation starting, ref bug #1407100
+ # Note that we can be sure My::Config will stay IN_PROGRESS as
+ # there's no signal sent to the deployment
+ self.stack_create(template=template,
+ files=files,
+ environment=env,
+ parameters=parameters,
+ expected_status='CREATE_IN_PROGRESS')