Increase the concurrency of software-config functional test
The test now creates up to 10 deployments in various stack/deployment
resource combinations and asserts that the resulting server metadata
has the appropriate number of resources.
This test now creates a deployment via OS::Heat::SoftwareDeployments as
the extra nested stack is required to trigger the race causing bug #1477329
Related-Bug: #1477329
Change-Id: Id3d5b09def6d03bca669c1ab0751641b72f61ce4
diff --git a/functional/test_software_config.py b/functional/test_software_config.py
index 2f38c55..019e6c9 100644
--- a/functional/test_software_config.py
+++ b/functional/test_software_config.py
@@ -10,11 +10,17 @@
# License for the specific language governing permissions and limitations
# under the License.
+from oslo_utils import timeutils
+import requests
+import time
+import yaml
+
+from heat_integrationtests.common import exceptions
from heat_integrationtests.functional import functional_base
class ParallelDeploymentsTest(functional_base.FunctionalTestsBase):
- template = '''
+ server_template = '''
heat_template_version: "2013-05-23"
parameters:
flavor:
@@ -30,47 +36,124 @@
image: {get_param: image}
flavor: {get_param: flavor}
user_data_format: SOFTWARE_CONFIG
- networks: [{network: {get_param: network} }]
+ networks: [{network: {get_param: network}}]
+outputs:
+ server:
+ value: {get_resource: server}
+'''
+
+ config_template = '''
+heat_template_version: "2013-05-23"
+parameters:
+ server:
+ type: string
+resources:
config:
type: OS::Heat::SoftwareConfig
properties:
- config: hi!
- dep1:
- type: OS::Heat::SoftwareDeployment
- properties:
- config: {get_resource: config}
- server: {get_resource: server}
- signal_transport: NO_SIGNAL
- dep2:
- type: OS::Heat::SoftwareDeployment
- properties:
- config: {get_resource: config}
- server: {get_resource: server}
- signal_transport: NO_SIGNAL
- dep3:
- type: OS::Heat::SoftwareDeployment
- properties:
- config: {get_resource: config}
- server: {get_resource: server}
- signal_transport: NO_SIGNAL
- dep4:
- type: OS::Heat::SoftwareDeployment
- properties:
- config: {get_resource: config}
- server: {get_resource: server}
- signal_transport: NO_SIGNAL
'''
- def setUp(self):
- super(ParallelDeploymentsTest, self).setUp()
+ deployment_snippet = '''
+type: OS::Heat::SoftwareDeployments
+properties:
+ config: {get_resource: config}
+ servers: {'0': {get_param: server}}
+'''
- def test_fail(self):
+ enable_cleanup = True
+
+ def test_deployments_metadata(self):
parms = {'flavor': self.conf.minimal_instance_type,
'network': self.conf.fixed_network_name,
'image': self.conf.minimal_image_ref}
stack_identifier = self.stack_create(
parameters=parms,
- template=self.template)
- stack = self.client.stacks.get(stack_identifier)
- server_metadata = self.client.resources.metadata(stack.id, 'server')
- self.assertEqual(4, len(server_metadata['deployments']))
+ template=self.server_template,
+ enable_cleanup=self.enable_cleanup)
+ server_stack = self.client.stacks.get(stack_identifier)
+ server = server_stack.outputs[0]['output_value']
+
+ config_stacks = []
+ # add up to 3 stacks each with up to 3 deployments
+ deploy_count = 0
+ deploy_count = self.deploy_many_configs(
+ stack_identifier,
+ server,
+ config_stacks,
+ 2,
+ 5,
+ deploy_count)
+ deploy_count = self.deploy_many_configs(
+ stack_identifier,
+ server,
+ config_stacks,
+ 3,
+ 3,
+ deploy_count)
+
+ self.signal_deployments(stack_identifier)
+ for config_stack in config_stacks:
+ self._wait_for_stack_status(config_stack, 'CREATE_COMPLETE')
+
+ def deploy_many_configs(self, stack_identifier, server, config_stacks,
+ stack_count, deploys_per_stack,
+ deploy_count_start):
+ for a in range(stack_count):
+ config_stacks.append(
+ self.deploy_config(server, deploys_per_stack))
+
+ for config_stack in config_stacks:
+ self.wait_for_deploy_physical_id(config_stack)
+
+ new_count = deploy_count_start + stack_count * deploys_per_stack
+ server_metadata = self.client.resources.metadata(
+ stack_identifier, 'server')
+ self.assertEqual(
+ new_count,
+ len(server_metadata['deployments']),
+ '%s stacks with %s deployments' % (stack_count, deploys_per_stack)
+ )
+ return new_count
+
+ def deploy_config(self, server, deploy_count):
+ parms = {'server': server}
+ template = yaml.safe_load(self.config_template)
+ resources = template['resources']
+ resources['config']['properties'] = {'config': 'x' * 10000}
+ for a in range(deploy_count):
+ resources['dep_%s' % a] = yaml.safe_load(self.deployment_snippet)
+ return self.stack_create(
+ parameters=parms,
+ template=template,
+ enable_cleanup=self.enable_cleanup,
+ expected_status=None)
+
+ def wait_for_deploy_physical_id(self, stack):
+ build_timeout = self.conf.build_timeout
+ build_interval = self.conf.build_interval
+
+ start = timeutils.utcnow()
+ while timeutils.delta_seconds(start,
+ timeutils.utcnow()) < build_timeout:
+ created = True
+ for res in self.client.resources.list(stack, nested_depth='2'):
+ if not res.physical_resource_id:
+ created = False
+ break
+ if created:
+ return
+ time.sleep(build_interval)
+
+ message = ('Deployment resources failed to be created within '
+ 'the required time (%s s).' %
+ (build_timeout))
+ raise exceptions.TimeoutException(message)
+
+ def signal_deployments(self, stack_identifier):
+ server_metadata = self.client.resources.metadata(
+ stack_identifier, 'server')
+ for dep in server_metadata['deployments']:
+ iv = dict((i['name'], i['value']) for i in dep['inputs'])
+ sigurl = iv.get('deploy_signal_id')
+ requests.post(sigurl, data='{}',
+ headers={'content-type': None})