Merge "Zuul: Remove project name"
diff --git a/heat_tempest_plugin/config.py b/heat_tempest_plugin/config.py
index 6d2ead6..d658a98 100644
--- a/heat_tempest_plugin/config.py
+++ b/heat_tempest_plugin/config.py
@@ -122,9 +122,6 @@
default=60,
help="Timeout in seconds to wait for output from ssh "
"channel."),
- cfg.IntOpt('tenant_network_mask_bits',
- default=28,
- help="The mask bits for tenant ipv4 subnets"),
cfg.BoolOpt('skip_scenario_tests',
default=False,
help="Skip all scenario tests"),
@@ -153,15 +150,6 @@
default=120,
help="Timeout in seconds to wait for connectivity to "
"server."),
- cfg.IntOpt('sighup_timeout',
- default=120,
- help="Timeout in seconds to wait for adding or removing child "
- "process after receiving of sighup signal"),
- cfg.IntOpt('sighup_config_edit_retries',
- default=10,
- help='Count of retries to edit config file during sighup. If '
- 'another worker already edit config file, file can be '
- 'busy, so need to wait and try edit file again.'),
cfg.StrOpt('heat_config_notify_script',
default=('heat-config-notify'),
help="Path to the script heat-config-notify"),
diff --git a/heat_tempest_plugin/tests/functional/test_admin_actions.py b/heat_tempest_plugin/tests/functional/test_admin_actions.py
deleted file mode 100644
index 757b03c..0000000
--- a/heat_tempest_plugin/tests/functional/test_admin_actions.py
+++ /dev/null
@@ -1,101 +0,0 @@
-# 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.
-
-from heat_tempest_plugin.tests.functional import functional_base
-
-# Simple stack
-test_template = {
- 'heat_template_version': '2013-05-23',
- 'resources': {
- 'test1': {
- 'type': 'OS::Heat::TestResource',
- 'properties': {
- 'value': 'Test1'
- }
- }
- }
-}
-
-# Nested stack
-rsg_template = {
- 'heat_template_version': '2013-05-23',
- 'resources': {
- 'random_group': {
- 'type': 'OS::Heat::ResourceGroup',
- 'properties': {
- 'count': 2,
- 'resource_def': {
- 'type': 'OS::Heat::RandomString',
- 'properties': {
- 'length': 30,
- 'salt': 'initial'
- }
- }
- }
- }
- }
-}
-
-
-class AdminActionsTest(functional_base.FunctionalTestsBase):
-
- def setUp(self):
- super(AdminActionsTest, self).setUp()
- if not self.conf.admin_username or not self.conf.admin_password:
- self.skipTest('No admin creds found, skipping')
-
- def create_stack_setup_admin_client(self, template=test_template):
- # Create the stack with the default user
- self.stack_identifier = self.stack_create(template=template)
-
- # Setup admin clients
- self.setup_clients_for_admin()
-
- def test_admin_simple_stack_actions(self):
- self.create_stack_setup_admin_client()
-
- updated_template = test_template.copy()
- props = updated_template['resources']['test1']['properties']
- props['value'] = 'new_value'
-
- # Update, suspend and resume stack
- self.update_stack(self.stack_identifier,
- template=updated_template)
- self.stack_suspend(self.stack_identifier)
- self.stack_resume(self.stack_identifier)
-
- # List stack resources
- initial_resources = {'test1': 'OS::Heat::TestResource'}
- self.assertEqual(initial_resources,
- self.list_resources(self.stack_identifier))
- # Delete stack
- self._stack_delete(self.stack_identifier)
-
- def test_admin_complex_stack_actions(self):
- self.create_stack_setup_admin_client(template=rsg_template)
-
- updated_template = rsg_template.copy()
- props = updated_template['resources']['random_group']['properties']
- props['count'] = 3
-
- # Update, suspend and resume stack
- self.update_stack(self.stack_identifier,
- template=updated_template)
- self.stack_suspend(self.stack_identifier)
- self.stack_resume(self.stack_identifier)
-
- # List stack resources
- resources = {'random_group': 'OS::Heat::ResourceGroup'}
- self.assertEqual(resources,
- self.list_resources(self.stack_identifier))
- # Delete stack
- self._stack_delete(self.stack_identifier)
diff --git a/heat_tempest_plugin/tests/functional/test_autoscaling.py b/heat_tempest_plugin/tests/functional/test_autoscaling.py
deleted file mode 100644
index d266646..0000000
--- a/heat_tempest_plugin/tests/functional/test_autoscaling.py
+++ /dev/null
@@ -1,752 +0,0 @@
-# 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 copy
-import json
-
-from heatclient import exc
-from oslo_log import log as logging
-import six
-from testtools import matchers
-
-from heat_tempest_plugin.common import test
-from heat_tempest_plugin.tests.functional import functional_base
-
-
-LOG = logging.getLogger(__name__)
-
-
-class AutoscalingGroupTest(functional_base.FunctionalTestsBase):
-
- template = '''
-{
- "AWSTemplateFormatVersion" : "2010-09-09",
- "Description" : "Template to create multiple instances.",
- "Parameters" : {"size": {"Type": "String", "Default": "1"},
- "AZ": {"Type": "String", "Default": "nova"},
- "image": {"Type": "String"},
- "flavor": {"Type": "String"},
- "user_data": {"Type": "String", "Default": "jsconfig data"}},
- "Resources": {
- "JobServerGroup": {
- "Type" : "AWS::AutoScaling::AutoScalingGroup",
- "Properties" : {
- "AvailabilityZones" : [{"Ref": "AZ"}],
- "LaunchConfigurationName" : { "Ref" : "JobServerConfig" },
- "MinSize" : {"Ref": "size"},
- "MaxSize" : "20"
- }
- },
-
- "JobServerConfig" : {
- "Type" : "AWS::AutoScaling::LaunchConfiguration",
- "Metadata": {"foo": "bar"},
- "Properties": {
- "ImageId" : {"Ref": "image"},
- "InstanceType" : {"Ref": "flavor"},
- "SecurityGroups" : [ "sg-1" ],
- "UserData" : {"Ref": "user_data"}
- }
- }
- },
- "Outputs": {
- "InstanceList": {"Value": {
- "Fn::GetAtt": ["JobServerGroup", "InstanceList"]}},
- "JobServerConfigRef": {"Value": {
- "Ref": "JobServerConfig"}}
- }
-}
-'''
-
- instance_template = '''
-heat_template_version: 2013-05-23
-parameters:
- ImageId: {type: string}
- InstanceType: {type: string}
- SecurityGroups: {type: comma_delimited_list}
- UserData: {type: string}
- Tags: {type: comma_delimited_list, default: "x,y"}
-
-resources:
- random1:
- type: OS::Heat::RandomString
- properties:
- salt: {get_param: UserData}
-outputs:
- PublicIp: {value: {get_attr: [random1, value]}}
- AvailabilityZone: {value: 'not-used11'}
- PrivateDnsName: {value: 'not-used12'}
- PublicDnsName: {value: 'not-used13'}
- PrivateIp: {value: 'not-used14'}
-'''
-
- # This is designed to fail.
- bad_instance_template = '''
-heat_template_version: 2013-05-23
-parameters:
- ImageId: {type: string}
- InstanceType: {type: string}
- SecurityGroups: {type: comma_delimited_list}
- UserData: {type: string}
- Tags: {type: comma_delimited_list, default: "x,y"}
-
-resources:
- random1:
- type: OS::Heat::RandomString
- depends_on: waiter
- ready_poster:
- type: AWS::CloudFormation::WaitConditionHandle
- waiter:
- type: AWS::CloudFormation::WaitCondition
- properties:
- Handle: {get_resource: ready_poster}
- Timeout: 1
-outputs:
- PublicIp:
- value: {get_attr: [random1, value]}
-'''
-
- def setUp(self):
- super(AutoscalingGroupTest, self).setUp()
- if not self.conf.minimal_image_ref:
- raise self.skipException("No minimal image configured to test")
- if not self.conf.instance_type:
- raise self.skipException("No flavor configured to test")
-
- def assert_instance_count(self, stack, expected_count):
- inst_list = self._stack_output(stack, 'InstanceList')
- self.assertEqual(expected_count, len(inst_list.split(',')))
-
- def _assert_instance_state(self, nested_identifier,
- num_complete, num_failed):
- for res in self.client.resources.list(nested_identifier):
- if 'COMPLETE' in res.resource_status:
- num_complete = num_complete - 1
- elif 'FAILED' in res.resource_status:
- num_failed = num_failed - 1
- self.assertEqual(0, num_failed)
- self.assertEqual(0, num_complete)
-
-
-class AutoscalingGroupBasicTest(AutoscalingGroupTest):
-
- def test_basic_create_works(self):
- """Make sure the working case is good.
-
- Note this combines test_override_aws_ec2_instance into this test as
- well, which is:
- If AWS::EC2::Instance is overridden, AutoScalingGroup will
- automatically use that overridden resource type.
- """
-
- files = {'provider.yaml': self.instance_template}
- env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'},
- 'parameters': {'size': 4,
- 'image': self.conf.minimal_image_ref,
- 'flavor': self.conf.instance_type}}
- stack_identifier = self.stack_create(template=self.template,
- files=files, environment=env)
- initial_resources = {
- 'JobServerConfig': 'AWS::AutoScaling::LaunchConfiguration',
- 'JobServerGroup': 'AWS::AutoScaling::AutoScalingGroup'}
- self.assertEqual(initial_resources,
- self.list_resources(stack_identifier))
-
- stack = self.client.stacks.get(stack_identifier)
- self.assert_instance_count(stack, 4)
-
- def test_size_updates_work(self):
- files = {'provider.yaml': self.instance_template}
- env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'},
- 'parameters': {'size': 2,
- 'image': self.conf.minimal_image_ref,
- 'flavor': self.conf.instance_type}}
-
- stack_identifier = self.stack_create(template=self.template,
- files=files,
- environment=env)
- stack = self.client.stacks.get(stack_identifier)
- self.assert_instance_count(stack, 2)
-
- # Increase min size to 5
- env2 = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'},
- 'parameters': {'size': 5,
- 'image': self.conf.minimal_image_ref,
- 'flavor': self.conf.instance_type}}
- self.update_stack(stack_identifier, self.template,
- environment=env2, files=files)
- stack = self.client.stacks.get(stack_identifier)
- self.assert_instance_count(stack, 5)
-
- def test_update_group_replace(self):
- """Test case for ensuring non-updatable props case a replacement.
-
- Make sure that during a group update the non-updatable
- properties cause a replacement.
- """
- files = {'provider.yaml': self.instance_template}
- env = {'resource_registry':
- {'AWS::EC2::Instance': 'provider.yaml'},
- 'parameters': {'size': '1',
- 'image': self.conf.minimal_image_ref,
- 'flavor': self.conf.instance_type}}
-
- stack_identifier = self.stack_create(template=self.template,
- files=files,
- environment=env)
- rsrc = self.client.resources.get(stack_identifier, 'JobServerGroup')
- orig_asg_id = rsrc.physical_resource_id
-
- env2 = {'resource_registry':
- {'AWS::EC2::Instance': 'provider.yaml'},
- 'parameters': {'size': '1',
- 'AZ': 'wibble',
- 'image': self.conf.minimal_image_ref,
- 'flavor': self.conf.instance_type,
- 'user_data': 'new data'}}
- self.update_stack(stack_identifier, self.template,
- environment=env2, files=files)
-
- # replacement will cause the resource physical_resource_id to change.
- rsrc = self.client.resources.get(stack_identifier, 'JobServerGroup')
- self.assertNotEqual(orig_asg_id, rsrc.physical_resource_id)
-
- def test_create_instance_error_causes_group_error(self):
- """Test create failing a resource in the instance group.
-
- If a resource in an instance group fails to be created, the instance
- group itself will fail and the broken inner resource will remain.
- """
- stack_name = self._stack_rand_name()
- files = {'provider.yaml': self.bad_instance_template}
- env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'},
- 'parameters': {'size': 2,
- 'image': self.conf.minimal_image_ref,
- 'flavor': self.conf.instance_type}}
-
- self.client.stacks.create(
- stack_name=stack_name,
- template=self.template,
- files=files,
- disable_rollback=True,
- parameters={},
- environment=env
- )
- self.addCleanup(self._stack_delete, stack_name)
- stack = self.client.stacks.get(stack_name)
- stack_identifier = '%s/%s' % (stack_name, stack.id)
- self._wait_for_stack_status(stack_identifier, 'CREATE_FAILED')
- initial_resources = {
- 'JobServerConfig': 'AWS::AutoScaling::LaunchConfiguration',
- 'JobServerGroup': 'AWS::AutoScaling::AutoScalingGroup'}
- self.assertEqual(initial_resources,
- self.list_resources(stack_identifier))
-
- nested_ident = self.assert_resource_is_a_stack(stack_identifier,
- 'JobServerGroup')
- self._assert_instance_state(nested_ident, 0, 2)
-
- def test_update_instance_error_causes_group_error(self):
- """Test update failing a resource in the instance group.
-
- If a resource in an instance group fails to be created during an
- update, the instance group itself will fail and the broken inner
- resource will remain.
- """
- files = {'provider.yaml': self.instance_template}
- env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'},
- 'parameters': {'size': 2,
- 'image': self.conf.minimal_image_ref,
- 'flavor': self.conf.instance_type}}
-
- stack_identifier = self.stack_create(template=self.template,
- files=files,
- environment=env)
- initial_resources = {
- 'JobServerConfig': 'AWS::AutoScaling::LaunchConfiguration',
- 'JobServerGroup': 'AWS::AutoScaling::AutoScalingGroup'}
- self.assertEqual(initial_resources,
- self.list_resources(stack_identifier))
-
- stack = self.client.stacks.get(stack_identifier)
- self.assert_instance_count(stack, 2)
- nested_ident = self.assert_resource_is_a_stack(stack_identifier,
- 'JobServerGroup')
- self._assert_instance_state(nested_ident, 2, 0)
- initial_list = [res.resource_name
- for res in self.client.resources.list(nested_ident)]
-
- env['parameters']['size'] = 3
- files2 = {'provider.yaml': self.bad_instance_template}
- self.client.stacks.update(
- stack_id=stack_identifier,
- template=self.template,
- files=files2,
- disable_rollback=True,
- parameters={},
- environment=env
- )
- self._wait_for_stack_status(stack_identifier, 'UPDATE_FAILED')
-
- # assert that there are 3 bad instances
- nested_ident = self.assert_resource_is_a_stack(stack_identifier,
- 'JobServerGroup')
-
- # 2 resources should be in update failed, and one create failed.
- for res in self.client.resources.list(nested_ident):
- if res.resource_name in initial_list:
- self._wait_for_resource_status(nested_ident,
- res.resource_name,
- 'UPDATE_FAILED')
- else:
- self._wait_for_resource_status(nested_ident,
- res.resource_name,
- 'CREATE_FAILED')
-
- def test_group_suspend_resume(self):
-
- files = {'provider.yaml': self.instance_template}
- env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'},
- 'parameters': {'size': 4,
- 'image': self.conf.minimal_image_ref,
- 'flavor': self.conf.instance_type}}
- stack_identifier = self.stack_create(template=self.template,
- files=files, environment=env)
-
- nested_ident = self.assert_resource_is_a_stack(stack_identifier,
- 'JobServerGroup')
-
- self.stack_suspend(stack_identifier)
- self._wait_for_all_resource_status(nested_ident, 'SUSPEND_COMPLETE')
-
- self.stack_resume(stack_identifier)
- self._wait_for_all_resource_status(nested_ident, 'RESUME_COMPLETE')
-
-
-class AutoscalingGroupUpdatePolicyTest(AutoscalingGroupTest):
-
- def ig_tmpl_with_updt_policy(self):
- templ = json.loads(copy.deepcopy(self.template))
- up = {"AutoScalingRollingUpdate": {
- "MinInstancesInService": "1",
- "MaxBatchSize": "2",
- "PauseTime": "PT1S"}}
- templ['Resources']['JobServerGroup']['UpdatePolicy'] = up
- return templ
-
- def update_instance_group(self, updt_template,
- num_updates_expected_on_updt,
- num_creates_expected_on_updt,
- num_deletes_expected_on_updt):
-
- # setup stack from the initial template
- files = {'provider.yaml': self.instance_template}
- size = 10
- env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'},
- 'parameters': {'size': size,
- 'image': self.conf.minimal_image_ref,
- 'flavor': self.conf.instance_type}}
- stack_name = self._stack_rand_name()
- stack_identifier = self.stack_create(
- stack_name=stack_name,
- template=self.ig_tmpl_with_updt_policy(),
- files=files,
- environment=env)
- stack = self.client.stacks.get(stack_identifier)
- nested_ident = self.assert_resource_is_a_stack(stack_identifier,
- 'JobServerGroup')
-
- # test that physical resource name of launch configuration is used
- conf_name = self._stack_output(stack, 'JobServerConfigRef')
- conf_name_pattern = '%s-JobServerConfig-[a-zA-Z0-9]+$' % stack_name
- self.assertThat(conf_name,
- matchers.MatchesRegex(conf_name_pattern))
-
- # test the number of instances created
- self.assert_instance_count(stack, size)
- # saves info from initial list of instances for comparison later
- init_instances = self.client.resources.list(nested_ident)
- init_names = [inst.resource_name for inst in init_instances]
-
- # test stack update
- self.update_stack(stack_identifier, updt_template,
- environment=env, files=files)
- updt_stack = self.client.stacks.get(stack_identifier)
-
- # test that the launch configuration is replaced
- updt_conf_name = self._stack_output(updt_stack, 'JobServerConfigRef')
- self.assertThat(updt_conf_name,
- matchers.MatchesRegex(conf_name_pattern))
- self.assertNotEqual(conf_name, updt_conf_name)
-
- # test that the group size are the same
- updt_instances = self.client.resources.list(nested_ident)
- updt_names = [inst.resource_name for inst in updt_instances]
- self.assertEqual(len(init_names), len(updt_names))
- for res in updt_instances:
- self.assertEqual('UPDATE_COMPLETE', res.resource_status)
-
- # test that the appropriate number of instance names are the same
- matched_names = set(updt_names) & set(init_names)
- self.assertEqual(num_updates_expected_on_updt, len(matched_names))
-
- # test that the appropriate number of new instances are created
- self.assertEqual(num_creates_expected_on_updt,
- len(set(updt_names) - set(init_names)))
-
- # test that the appropriate number of instances are deleted
- self.assertEqual(num_deletes_expected_on_updt,
- len(set(init_names) - set(updt_names)))
-
- # test that the older instances are the ones being deleted
- if num_deletes_expected_on_updt > 0:
- deletes_expected = init_names[:num_deletes_expected_on_updt]
- self.assertNotIn(deletes_expected, updt_names)
-
- def test_instance_group_update_replace(self):
- """Test simple update replace.
-
- Test update replace with no conflict in batch size and minimum
- instances in service.
- """
- updt_template = self.ig_tmpl_with_updt_policy()
- grp = updt_template['Resources']['JobServerGroup']
- policy = grp['UpdatePolicy']['AutoScalingRollingUpdate']
- policy['MinInstancesInService'] = '1'
- policy['MaxBatchSize'] = '3'
- config = updt_template['Resources']['JobServerConfig']
- config['Properties']['UserData'] = 'new data'
-
- self.update_instance_group(updt_template,
- num_updates_expected_on_updt=10,
- num_creates_expected_on_updt=0,
- num_deletes_expected_on_updt=0)
-
- def test_instance_group_update_replace_with_adjusted_capacity(self):
- """Test update replace with capacity adjustment.
-
- Test update replace with capacity adjustment due to conflict in batch
- size and minimum instances in service.
- """
- updt_template = self.ig_tmpl_with_updt_policy()
- grp = updt_template['Resources']['JobServerGroup']
- policy = grp['UpdatePolicy']['AutoScalingRollingUpdate']
- policy['MinInstancesInService'] = '8'
- policy['MaxBatchSize'] = '4'
- config = updt_template['Resources']['JobServerConfig']
- config['Properties']['UserData'] = 'new data'
-
- self.update_instance_group(updt_template,
- num_updates_expected_on_updt=8,
- num_creates_expected_on_updt=2,
- num_deletes_expected_on_updt=2)
-
- def test_instance_group_update_replace_huge_batch_size(self):
- """Test update replace with a huge batch size."""
- updt_template = self.ig_tmpl_with_updt_policy()
- group = updt_template['Resources']['JobServerGroup']
- policy = group['UpdatePolicy']['AutoScalingRollingUpdate']
- policy['MinInstancesInService'] = '0'
- policy['MaxBatchSize'] = '20'
- config = updt_template['Resources']['JobServerConfig']
- config['Properties']['UserData'] = 'new data'
-
- self.update_instance_group(updt_template,
- num_updates_expected_on_updt=10,
- num_creates_expected_on_updt=0,
- num_deletes_expected_on_updt=0)
-
- def test_instance_group_update_replace_huge_min_in_service(self):
- """Update replace with huge number of minimum instances in service."""
- updt_template = self.ig_tmpl_with_updt_policy()
- group = updt_template['Resources']['JobServerGroup']
- policy = group['UpdatePolicy']['AutoScalingRollingUpdate']
- policy['MinInstancesInService'] = '20'
- policy['MaxBatchSize'] = '1'
- policy['PauseTime'] = 'PT0S'
- config = updt_template['Resources']['JobServerConfig']
- config['Properties']['UserData'] = 'new data'
-
- self.update_instance_group(updt_template,
- num_updates_expected_on_updt=9,
- num_creates_expected_on_updt=1,
- num_deletes_expected_on_updt=1)
-
- def test_instance_group_update_no_replace(self):
- """Test simple update only and no replace.
-
- Test simple update only and no replace (i.e. updated instance flavor
- in Launch Configuration) with no conflict in batch size and
- minimum instances in service.
- """
- updt_template = self.ig_tmpl_with_updt_policy()
- group = updt_template['Resources']['JobServerGroup']
- policy = group['UpdatePolicy']['AutoScalingRollingUpdate']
- policy['MinInstancesInService'] = '1'
- policy['MaxBatchSize'] = '3'
- policy['PauseTime'] = 'PT0S'
- config = updt_template['Resources']['JobServerConfig']
- config['Properties']['InstanceType'] = self.conf.minimal_instance_type
-
- self.update_instance_group(updt_template,
- num_updates_expected_on_updt=10,
- num_creates_expected_on_updt=0,
- num_deletes_expected_on_updt=0)
-
- def test_instance_group_update_no_replace_with_adjusted_capacity(self):
- """Test update only and no replace with capacity adjustment.
-
- Test update only and no replace (i.e. updated instance flavor in
- Launch Configuration) with capacity adjustment due to conflict in
- batch size and minimum instances in service.
- """
- updt_template = self.ig_tmpl_with_updt_policy()
- group = updt_template['Resources']['JobServerGroup']
- policy = group['UpdatePolicy']['AutoScalingRollingUpdate']
- policy['MinInstancesInService'] = '8'
- policy['MaxBatchSize'] = '4'
- policy['PauseTime'] = 'PT0S'
- config = updt_template['Resources']['JobServerConfig']
- config['Properties']['InstanceType'] = self.conf.minimal_instance_type
-
- self.update_instance_group(updt_template,
- num_updates_expected_on_updt=8,
- num_creates_expected_on_updt=2,
- num_deletes_expected_on_updt=2)
-
-
-class AutoScalingSignalTest(AutoscalingGroupTest):
-
- template = '''
-{
- "AWSTemplateFormatVersion" : "2010-09-09",
- "Description" : "Template to create multiple instances.",
- "Parameters" : {"size": {"Type": "String", "Default": "1"},
- "AZ": {"Type": "String", "Default": "nova"},
- "image": {"Type": "String"},
- "flavor": {"Type": "String"}},
- "Resources": {
- "custom_lb": {
- "Type": "AWS::EC2::Instance",
- "Properties": {
- "ImageId": {"Ref": "image"},
- "InstanceType": {"Ref": "flavor"},
- "UserData": "foo",
- "SecurityGroups": [ "sg-1" ],
- "Tags": []
- },
- "Metadata": {
- "IPs": {"Fn::GetAtt": ["JobServerGroup", "InstanceList"]}
- }
- },
- "JobServerGroup": {
- "Type" : "AWS::AutoScaling::AutoScalingGroup",
- "Properties" : {
- "AvailabilityZones" : [{"Ref": "AZ"}],
- "LaunchConfigurationName" : { "Ref" : "JobServerConfig" },
- "DesiredCapacity" : {"Ref": "size"},
- "MinSize" : "0",
- "MaxSize" : "20"
- }
- },
- "JobServerConfig" : {
- "Type" : "AWS::AutoScaling::LaunchConfiguration",
- "Metadata": {"foo": "bar"},
- "Properties": {
- "ImageId" : {"Ref": "image"},
- "InstanceType" : {"Ref": "flavor"},
- "SecurityGroups" : [ "sg-1" ],
- "UserData" : "jsconfig data"
- }
- },
- "ScaleUpPolicy" : {
- "Type" : "AWS::AutoScaling::ScalingPolicy",
- "Properties" : {
- "AdjustmentType" : "ChangeInCapacity",
- "AutoScalingGroupName" : { "Ref" : "JobServerGroup" },
- "Cooldown" : "0",
- "ScalingAdjustment": "1"
- }
- },
- "ScaleDownPolicy" : {
- "Type" : "AWS::AutoScaling::ScalingPolicy",
- "Properties" : {
- "AdjustmentType" : "ChangeInCapacity",
- "AutoScalingGroupName" : { "Ref" : "JobServerGroup" },
- "Cooldown" : "0",
- "ScalingAdjustment" : "-2"
- }
- }
- },
- "Outputs": {
- "InstanceList": {"Value": {
- "Fn::GetAtt": ["JobServerGroup", "InstanceList"]}}
- }
-}
-'''
-
- lb_template = '''
-heat_template_version: 2013-05-23
-parameters:
- ImageId: {type: string}
- InstanceType: {type: string}
- SecurityGroups: {type: comma_delimited_list}
- UserData: {type: string}
- Tags: {type: comma_delimited_list, default: "x,y"}
-
-resources:
-outputs:
- PublicIp: {value: "not-used"}
- AvailabilityZone: {value: 'not-used1'}
- PrivateDnsName: {value: 'not-used2'}
- PublicDnsName: {value: 'not-used3'}
- PrivateIp: {value: 'not-used4'}
-
-'''
-
- def setUp(self):
- super(AutoScalingSignalTest, self).setUp()
- self.build_timeout = self.conf.build_timeout
- self.build_interval = self.conf.build_interval
- self.files = {'provider.yaml': self.instance_template,
- 'lb.yaml': self.lb_template}
- self.env = {'resource_registry':
- {'resources':
- {'custom_lb': {'AWS::EC2::Instance': 'lb.yaml'}},
- 'AWS::EC2::Instance': 'provider.yaml'},
- 'parameters': {'size': 2,
- 'image': self.conf.minimal_image_ref,
- 'flavor': self.conf.instance_type}}
-
- def check_instance_count(self, stack_identifier, expected):
- md = self.client.resources.metadata(stack_identifier, 'custom_lb')
- actual_md = len(md['IPs'].split(','))
- if actual_md != expected:
- LOG.warning('check_instance_count exp:%d, meta:%s' % (expected,
- md['IPs']))
- return False
-
- stack = self.client.stacks.get(stack_identifier)
- inst_list = self._stack_output(stack, 'InstanceList')
- actual = len(inst_list.split(','))
- if actual != expected:
- LOG.warning('check_instance_count exp:%d, act:%s' % (expected,
- inst_list))
- return actual == expected
-
- def test_scaling_meta_update(self):
- """Use heatclient to signal the up and down policy.
-
- Then confirm that the metadata in the custom_lb is updated each
- time.
- """
- stack_identifier = self.stack_create(template=self.template,
- files=self.files,
- environment=self.env)
-
- self.assertTrue(test.call_until_true(
- self.build_timeout, self.build_interval,
- self.check_instance_count, stack_identifier, 2))
-
- nested_ident = self.assert_resource_is_a_stack(stack_identifier,
- 'JobServerGroup')
- # Scale up one, Trigger alarm
- self.client.resources.signal(stack_identifier, 'ScaleUpPolicy')
- self._wait_for_stack_status(nested_ident, 'UPDATE_COMPLETE')
- self.assertTrue(test.call_until_true(
- self.build_timeout, self.build_interval,
- self.check_instance_count, stack_identifier, 3))
-
- # Scale down two, Trigger alarm
- self.client.resources.signal(stack_identifier, 'ScaleDownPolicy')
- self._wait_for_stack_status(nested_ident, 'UPDATE_COMPLETE')
- self.assertTrue(test.call_until_true(
- self.build_timeout, self.build_interval,
- self.check_instance_count, stack_identifier, 1))
-
- def test_signal_with_policy_update(self):
- """Prove that an updated policy is used in the next signal."""
-
- stack_identifier = self.stack_create(template=self.template,
- files=self.files,
- environment=self.env)
-
- self.assertTrue(test.call_until_true(
- self.build_timeout, self.build_interval,
- self.check_instance_count, stack_identifier, 2))
-
- nested_ident = self.assert_resource_is_a_stack(stack_identifier,
- 'JobServerGroup')
- # Scale up one, Trigger alarm
- self.client.resources.signal(stack_identifier, 'ScaleUpPolicy')
- self._wait_for_stack_status(nested_ident, 'UPDATE_COMPLETE')
- self.assertTrue(test.call_until_true(
- self.build_timeout, self.build_interval,
- self.check_instance_count, stack_identifier, 3))
-
- # increase the adjustment to "+2" and remove the DesiredCapacity
- # so we don't go from 3 to 2.
- new_template = self.template.replace(
- '"ScalingAdjustment": "1"',
- '"ScalingAdjustment": "2"').replace(
- '"DesiredCapacity" : {"Ref": "size"},', '')
-
- self.update_stack(stack_identifier, template=new_template,
- environment=self.env, files=self.files)
-
- # Scale up two, Trigger alarm
- self.client.resources.signal(stack_identifier, 'ScaleUpPolicy')
- self._wait_for_stack_status(nested_ident, 'UPDATE_COMPLETE')
- self.assertTrue(test.call_until_true(
- self.build_timeout, self.build_interval,
- self.check_instance_count, stack_identifier, 5))
-
- def test_signal_during_suspend(self):
- """Prove that a signal will fail when the stack is in suspend."""
-
- stack_identifier = self.stack_create(template=self.template,
- files=self.files,
- environment=self.env)
-
- self.assertTrue(test.call_until_true(
- self.build_timeout, self.build_interval,
- self.check_instance_count, stack_identifier, 2))
-
- nested_ident = self.assert_resource_is_a_stack(stack_identifier,
- 'JobServerGroup')
-
- # suspend the top level stack.
- self.client.actions.suspend(stack_id=stack_identifier)
-
- # Wait for stack to reach SUSPEND_COMPLETE
- self._wait_for_stack_status(stack_identifier, 'SUSPEND_COMPLETE')
-
- # Send a signal and an exception will raise
- ex = self.assertRaises(exc.BadRequest,
- self.client.resources.signal,
- stack_identifier, 'ScaleUpPolicy')
-
- error_msg = 'Signal resource during SUSPEND is not supported'
- self.assertIn(error_msg, six.text_type(ex))
- ev = self.wait_for_event_with_reason(
- stack_identifier,
- reason='Cannot signal resource during SUSPEND',
- rsrc_name='ScaleUpPolicy')
- self.assertEqual('SUSPEND_COMPLETE', ev[0].resource_status)
-
- # still SUSPEND_COMPLETE (not gone to UPDATE_COMPLETE)
- self._wait_for_stack_status(nested_ident, 'SUSPEND_COMPLETE')
- self._wait_for_stack_status(stack_identifier, 'SUSPEND_COMPLETE')
- # still 2 instances.
- self.assertTrue(test.call_until_true(
- self.build_timeout, self.build_interval,
- self.check_instance_count, stack_identifier, 2))
diff --git a/heat_tempest_plugin/tests/functional/test_aws_stack.py b/heat_tempest_plugin/tests/functional/test_aws_stack.py
deleted file mode 100644
index 03beb1f..0000000
--- a/heat_tempest_plugin/tests/functional/test_aws_stack.py
+++ /dev/null
@@ -1,201 +0,0 @@
-# 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 hashlib
-import json
-import random
-
-from six.moves.urllib import parse
-from swiftclient import utils as swiftclient_utils
-import yaml
-
-from heat_tempest_plugin.common import test
-from heat_tempest_plugin.tests.functional import functional_base
-
-
-class AwsStackTest(functional_base.FunctionalTestsBase):
- test_template = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Resources:
- the_nested:
- Type: AWS::CloudFormation::Stack
- Properties:
- TemplateURL: the.yaml
- Parameters:
- KeyName: foo
-Outputs:
- output_foo:
- Value: {"Fn::GetAtt": [the_nested, Outputs.Foo]}
-'''
-
- nested_template = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Parameters:
- KeyName:
- Type: String
-Outputs:
- Foo:
- Value: bar
-'''
-
- update_template = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Parameters:
- KeyName:
- Type: String
-Outputs:
- Foo:
- Value: foo
-'''
-
- nested_with_res_template = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Parameters:
- KeyName:
- Type: String
-Resources:
- NestedResource:
- Type: OS::Heat::RandomString
-Outputs:
- Foo:
- Value: {"Fn::GetAtt": [NestedResource, value]}
-'''
-
- def setUp(self):
- super(AwsStackTest, self).setUp()
- if not self.is_service_available('object-store'):
- self.skipTest('object-store service not available, skipping')
- self.object_container_name = test.rand_name()
- self.project_id = self.identity_client.project_id
- self.swift_key = hashlib.sha224(
- str(random.getrandbits(256)).encode('ascii')).hexdigest()[:32]
- key_header = 'x-container-meta-temp-url-key'
- self.object_client.put_container(self.object_container_name,
- {key_header: self.swift_key})
- self.addCleanup(self.object_client.delete_container,
- self.object_container_name)
-
- def publish_template(self, contents, cleanup=True):
- oc = self.object_client
-
- # post the object
- oc.put_object(self.object_container_name, 'template.yaml', contents)
- if cleanup:
- self.addCleanup(oc.delete_object,
- self.object_container_name,
- 'template.yaml')
- path = '/v1/AUTH_%s/%s/%s' % (self.project_id,
- self.object_container_name,
- 'template.yaml')
- timeout = self.conf.build_timeout * 10
- tempurl = swiftclient_utils.generate_temp_url(path, timeout,
- self.swift_key, 'GET')
- sw_url = parse.urlparse(oc.url)
- return '%s://%s%s' % (sw_url.scheme, sw_url.netloc, tempurl)
-
- def test_nested_stack_create(self):
- url = self.publish_template(self.nested_template)
- self.template = self.test_template.replace('the.yaml', url)
- stack_identifier = self.stack_create(template=self.template)
- stack = self.client.stacks.get(stack_identifier)
- self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
- self.assertEqual('bar', self._stack_output(stack, 'output_foo'))
-
- def test_nested_stack_create_with_timeout(self):
- url = self.publish_template(self.nested_template)
- self.template = self.test_template.replace('the.yaml', url)
- timeout_template = yaml.safe_load(self.template)
- props = timeout_template['Resources']['the_nested']['Properties']
- props['TimeoutInMinutes'] = '50'
-
- stack_identifier = self.stack_create(
- template=timeout_template)
- stack = self.client.stacks.get(stack_identifier)
- self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
- self.assertEqual('bar', self._stack_output(stack, 'output_foo'))
-
- def test_nested_stack_adopt_ok(self):
- url = self.publish_template(self.nested_with_res_template)
- self.template = self.test_template.replace('the.yaml', url)
- adopt_data = {
- "resources": {
- "the_nested": {
- "resource_id": "test-res-id",
- "resources": {
- "NestedResource": {
- "type": "OS::Heat::RandomString",
- "resource_id": "test-nested-res-id",
- "resource_data": {"value": "goopie"}
- }
- }
- }
- },
- "environment": {"parameters": {}},
- "template": yaml.safe_load(self.template)
- }
-
- stack_identifier = self.stack_adopt(adopt_data=json.dumps(adopt_data))
-
- self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
- stack = self.client.stacks.get(stack_identifier)
- self.assertEqual('goopie', self._stack_output(stack, 'output_foo'))
-
- def test_nested_stack_adopt_fail(self):
- url = self.publish_template(self.nested_with_res_template)
- self.template = self.test_template.replace('the.yaml', url)
- adopt_data = {
- "resources": {
- "the_nested": {
- "resource_id": "test-res-id",
- "resources": {
- }
- }
- },
- "environment": {"parameters": {}},
- "template": yaml.safe_load(self.template)
- }
-
- stack_identifier = self.stack_adopt(adopt_data=json.dumps(adopt_data),
- wait_for_status='ADOPT_FAILED')
- rsrc = self.client.resources.get(stack_identifier, 'the_nested')
- self.assertEqual('ADOPT_FAILED', rsrc.resource_status)
-
- def test_nested_stack_update(self):
- url = self.publish_template(self.nested_template)
- self.template = self.test_template.replace('the.yaml', url)
- stack_identifier = self.stack_create(template=self.template)
- original_nested_id = self.assert_resource_is_a_stack(
- stack_identifier, 'the_nested')
- stack = self.client.stacks.get(stack_identifier)
- self.assertEqual('bar', self._stack_output(stack, 'output_foo'))
-
- new_template = yaml.safe_load(self.template)
- props = new_template['Resources']['the_nested']['Properties']
- props['TemplateURL'] = self.publish_template(self.update_template,
- cleanup=False)
-
- self.update_stack(stack_identifier, new_template)
-
- # Expect the physical resource name staying the same after update,
- # so that the nested was actually updated instead of replaced.
- new_nested_id = self.assert_resource_is_a_stack(
- stack_identifier, 'the_nested')
- self.assertEqual(original_nested_id, new_nested_id)
- updt_stack = self.client.stacks.get(stack_identifier)
- self.assertEqual('foo', self._stack_output(updt_stack, 'output_foo'))
-
- def test_nested_stack_suspend_resume(self):
- url = self.publish_template(self.nested_template)
- self.template = self.test_template.replace('the.yaml', url)
- stack_identifier = self.stack_create(template=self.template)
- self.stack_suspend(stack_identifier)
- self.stack_resume(stack_identifier)
diff --git a/heat_tempest_plugin/tests/functional/test_cancel_update.py b/heat_tempest_plugin/tests/functional/test_cancel_update.py
deleted file mode 100644
index 4a8938a..0000000
--- a/heat_tempest_plugin/tests/functional/test_cancel_update.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# 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.
-
-from heat_tempest_plugin.tests.functional import functional_base
-
-
-class CancelUpdateTest(functional_base.FunctionalTestsBase):
-
- template = '''
-heat_template_version: '2013-05-23'
-parameters:
- InstanceType:
- type: string
- ImageId:
- type: string
- network:
- type: string
-resources:
- port:
- type: OS::Neutron::Port
- properties:
- network: {get_param: network}
- Server:
- type: OS::Nova::Server
- properties:
- flavor_update_policy: REPLACE
- image: {get_param: ImageId}
- flavor: {get_param: InstanceType}
- networks:
- - port: {get_resource: port}
-'''
-
- def setUp(self):
- super(CancelUpdateTest, self).setUp()
- if not self.conf.minimal_image_ref:
- raise self.skipException("No minimal image configured to test")
- if not self.conf.minimal_instance_type:
- raise self.skipException("No minimal flavor configured to test.")
-
- def test_cancel_update_server_with_port(self):
- parameters = {'InstanceType': self.conf.minimal_instance_type,
- 'ImageId': self.conf.minimal_image_ref,
- 'network': self.conf.fixed_network_name}
-
- stack_identifier = self.stack_create(template=self.template,
- parameters=parameters)
- parameters['InstanceType'] = self.conf.instance_type
- self.update_stack(stack_identifier, self.template,
- parameters=parameters,
- expected_status='UPDATE_IN_PROGRESS')
-
- self.cancel_update_stack(stack_identifier)
diff --git a/heat_tempest_plugin/tests/functional/test_conditional_exposure.py b/heat_tempest_plugin/tests/functional/test_conditional_exposure.py
deleted file mode 100644
index dd4329b..0000000
--- a/heat_tempest_plugin/tests/functional/test_conditional_exposure.py
+++ /dev/null
@@ -1,157 +0,0 @@
-# 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.
-
-from heatclient import exc
-import keystoneclient
-
-from heat_tempest_plugin.tests.functional import functional_base
-
-
-class ServiceBasedExposureTest(functional_base.FunctionalTestsBase):
- # NOTE(pas-ha) if we ever decide to install Sahara on Heat
- # functional gate, this must be changed to other not-installed
- # but in principle supported service
- unavailable_service = 'Sahara'
- unavailable_template = """
-heat_template_version: 2015-10-15
-parameters:
- instance_type:
- type: string
-resources:
- not_available:
- type: OS::Sahara::NodeGroupTemplate
- properties:
- plugin_name: fake
- hadoop_version: 0.1
- flavor: {get_param: instance_type}
- node_processes: []
-"""
-
- def setUp(self):
- super(ServiceBasedExposureTest, self).setUp()
- # check that Sahara endpoint is available
- if self._is_sahara_deployed():
- self.skipTest("Sahara is actually deployed, "
- "can not run negative tests on "
- "Sahara resources availability.")
-
- def _is_sahara_deployed(self):
- try:
- self.identity_client.get_endpoint_url('data-processing',
- self.conf.region)
- except keystoneclient.exceptions.EndpointNotFound:
- return False
- return True
-
- def test_unavailable_resources_not_listed(self):
- resources = self.client.resource_types.list()
- self.assertFalse(any(self.unavailable_service in r.resource_type
- for r in resources))
-
- def test_unavailable_resources_not_created(self):
- stack_name = self._stack_rand_name()
- parameters = {'instance_type': self.conf.minimal_instance_type}
- ex = self.assertRaises(exc.HTTPBadRequest,
- self.client.stacks.create,
- stack_name=stack_name,
- parameters=parameters,
- template=self.unavailable_template)
- self.assertIn('ResourceTypeUnavailable', ex.message.decode('utf-8'))
- self.assertIn('OS::Sahara::NodeGroupTemplate',
- ex.message.decode('utf-8'))
-
-
-class RoleBasedExposureTest(functional_base.FunctionalTestsBase):
-
- fl_tmpl = """
-heat_template_version: 2015-10-15
-
-resources:
- not4everyone:
- type: OS::Nova::Flavor
- properties:
- ram: 20000
- vcpus: 10
-"""
-
- cvt_tmpl = """
-heat_template_version: 2015-10-15
-
-resources:
- cvt:
- type: OS::Cinder::VolumeType
- properties:
- name: cvt_test
-"""
-
- host_aggr_tmpl = """
-heat_template_version: 2015-10-15
-parameters:
- az:
- type: string
- default: nova
-resources:
- cvt:
- type: OS::Nova::HostAggregate
- properties:
- name: aggregate_test
- availability_zone: {get_param: az}
-"""
-
- scenarios = [
- ('r_nova_flavor', dict(
- stack_name='s_nova_flavor',
- template=fl_tmpl,
- forbidden_r_type="OS::Nova::Flavor",
- test_creation=True)),
- ('r_nova_host_aggregate', dict(
- stack_name='s_nova_ost_aggregate',
- template=host_aggr_tmpl,
- forbidden_r_type="OS::Nova::HostAggregate",
- test_creation=True)),
- ('r_cinder_vtype', dict(
- stack_name='s_cinder_vtype',
- template=cvt_tmpl,
- forbidden_r_type="OS::Cinder::VolumeType",
- test_creation=True)),
- ('r_cinder_vtype_encrypt', dict(
- forbidden_r_type="OS::Cinder::EncryptedVolumeType",
- test_creation=False)),
- ('r_neutron_qos', dict(
- forbidden_r_type="OS::Neutron::QoSPolicy",
- test_creation=False)),
- ('r_neutron_qos_bandwidth_limit', dict(
- forbidden_r_type="OS::Neutron::QoSBandwidthLimitRule",
- test_creation=False)),
- ('r_manila_share_type', dict(
- forbidden_r_type="OS::Manila::ShareType",
- test_creation=False))
- ]
-
- def test_non_admin_forbidden_create_resources(self):
- """Fail to create resource w/o admin role.
-
- Integration tests job runs as normal OpenStack user,
- and the resources above are configured to require
- admin role in default policy file of Heat.
- """
- if self.test_creation:
- ex = self.assertRaises(exc.Forbidden,
- self.client.stacks.create,
- stack_name=self.stack_name,
- template=self.template)
- self.assertIn(self.forbidden_r_type, ex.message.decode('utf-8'))
-
- def test_forbidden_resource_not_listed(self):
- resources = self.client.resource_types.list()
- self.assertNotIn(self.forbidden_r_type,
- (r.resource_type for r in resources))
diff --git a/heat_tempest_plugin/tests/functional/test_conditions.py b/heat_tempest_plugin/tests/functional/test_conditions.py
deleted file mode 100644
index 106a4ca..0000000
--- a/heat_tempest_plugin/tests/functional/test_conditions.py
+++ /dev/null
@@ -1,619 +0,0 @@
-# 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.
-
-from heat_tempest_plugin.tests.functional import functional_base
-
-
-cfn_template = '''
-AWSTemplateFormatVersion: 2010-09-09
-Parameters:
- env_type:
- Default: test
- Type: String
- AllowedValues: [prod, test]
- zone:
- Type: String
- Default: beijing
-Conditions:
- Prod: {"Fn::Equals" : [{Ref: env_type}, "prod"]}
- Test:
- Fn::Not:
- - Fn::Equals:
- - Ref: env_type
- - prod
- Beijing_Prod:
- Fn::And:
- - Fn::Equals:
- - Ref: env_type
- - prod
- - Fn::Equals:
- - Ref: zone
- - beijing
- Xian_Zone:
- Fn::Equals:
- - Ref: zone
- - xian
- Xianyang_Zone:
- Fn::Equals:
- - Ref: zone
- - xianyang
- Fujian_Zone:
- Fn::Or:
- - Fn::Equals:
- - Ref: zone
- - fuzhou
- - Fn::Equals:
- - Ref: zone
- - xiamen
- Fujian_Prod:
- Fn::And:
- - Fujian_Zone
- - Prod
- Shannxi_Provice:
- Fn::Or:
- - Xian_Zone
- - Xianyang_Zone
- Not_Shannxi:
- Fn::Not: [Shannxi_Provice]
-Resources:
- test_res:
- Type: OS::Heat::TestResource
- Properties:
- value: {"Fn::If": ["Prod", "env_is_prod", "env_is_test"]}
- prod_res:
- Type: OS::Heat::TestResource
- Properties:
- value: prod_res
- Condition: Prod
- test_res1:
- Type: OS::Heat::TestResource
- Properties:
- value: just in test env
- Condition: Test
- beijing_prod_res:
- Type: OS::Heat::TestResource
- Properties:
- value: beijing_prod_res
- Condition: Beijing_Prod
- fujian_res:
- Type: OS::Heat::TestResource
- Condition: Fujian_Zone
- Properties:
- value: fujian_res
- fujian_prod_res:
- Type: OS::Heat::TestResource
- Condition: Fujian_Prod
- Properties:
- value: fujian_prod_res
- shannxi_res:
- Type: OS::Heat::TestResource
- Condition: Shannxi_Provice
- Properties:
- value: shannxi_res
- not_shannxi_res:
- Type: OS::Heat::TestResource
- Condition: Not_Shannxi
- Properties:
- value: not_shannxi_res
-Outputs:
- res_value:
- Value: {"Fn::GetAtt": [prod_res, output]}
- Condition: Prod
- test_res_value:
- Value: {"Fn::GetAtt": [test_res, output]}
- prod_resource:
- Value: {"Fn::If": [Prod, {Ref: prod_res}, 'no_prod_res']}
- test_res1_value:
- Value: {"Fn::If": [Test, {"Fn::GetAtt": [test_res1, output]},
- 'no_test_res1']}
- beijing_prod_res:
- Value: {"Fn::If": [Beijing_Prod, {Ref: beijing_prod_res}, 'no_prod_res']}
-'''
-
-hot_template = '''
-heat_template_version: 2016-10-14
-parameters:
- env_type:
- default: test
- type: string
- constraints:
- - allowed_values: [prod, test]
- zone:
- type: string
- default: beijing
-conditions:
- prod: {equals : [{get_param: env_type}, "prod"]}
- test:
- not:
- equals:
- - get_param: env_type
- - prod
- beijing_prod:
- and:
- - equals:
- - get_param: zone
- - beijing
- - equals:
- - get_param: env_type
- - prod
- xian_zone:
- equals:
- - get_param: zone
- - xian
- xianyang_zone:
- equals:
- - get_param: zone
- - xianyang
- fujian_zone:
- or:
- - equals:
- - get_param: zone
- - fuzhou
- - equals:
- - get_param: zone
- - xiamen
- fujian_prod:
- and:
- - fujian_zone
- - prod
- shannxi_provice:
- or:
- - xian_zone
- - xianyang_zone
- not_shannxi:
- not: shannxi_provice
-resources:
- test_res:
- type: OS::Heat::TestResource
- properties:
- value: {if: ["prod", "env_is_prod", "env_is_test"]}
- prod_res:
- type: OS::Heat::TestResource
- properties:
- value: prod_res
- condition: prod
- test_res1:
- type: OS::Heat::TestResource
- properties:
- value: just in test env
- condition: test
- beijing_prod_res:
- type: OS::Heat::TestResource
- properties:
- value: beijing_prod_res
- condition: beijing_prod
- fujian_res:
- type: OS::Heat::TestResource
- condition: fujian_zone
- properties:
- value: fujian_res
- fujian_prod_res:
- type: OS::Heat::TestResource
- condition: fujian_prod
- properties:
- value: fujian_prod_res
- shannxi_res:
- type: OS::Heat::TestResource
- condition: shannxi_provice
- properties:
- value: shannxi_res
- not_shannxi_res:
- type: OS::Heat::TestResource
- condition: not_shannxi
- properties:
- value: not_shannxi_res
-outputs:
- res_value:
- value: {get_attr: [prod_res, output]}
- condition: prod
- test_res_value:
- value: {get_attr: [test_res, output]}
- prod_resource:
- value: {if: [prod, {get_resource: prod_res}, 'no_prod_res']}
- test_res1_value:
- value: {if: [test, {get_attr: [test_res1, output]}, 'no_test_res1']}
- beijing_prod_res:
- value: {if: [beijing_prod, {get_resource: beijing_prod_res},
- 'no_prod_res']}
-'''
-
-before_rename_tmpl = '''
-heat_template_version: 2016-10-14
-parameters:
- env_type:
- default: test
- type: string
-conditions:
- cd1: {equals : [{get_param: env_type}, "prod"]}
-resources:
- test:
- type: OS::Heat::TestResource
- properties:
- value: {if: [cd1, 'prod', 'test']}
-'''
-
-after_rename_tmpl = '''
-heat_template_version: 2016-10-14
-parameters:
- env_type:
- default: prod
- type: string
-conditions:
- cd2: {equals : [{get_param: env_type}, "prod"]}
-resources:
- test:
- type: OS::Heat::TestResource
- properties:
- value: {if: [cd2, 'prod', 'test']}
- test2:
- type: OS::Heat::TestResource
- properties:
- value: {if: [cd2, 'prod', 'test']}
-'''
-
-fail_rename_tmpl = '''
-heat_template_version: 2016-10-14
-parameters:
- env_type:
- default: prod
- type: string
-conditions:
- cd3: {equals : [{get_param: env_type}, "prod"]}
-resources:
- test:
- type: OS::Heat::TestResource
- properties:
- value: {if: [cd3, 'prod', 'test']}
- test2:
- type: OS::Heat::TestResource
- properties:
- value: {if: [cd3, 'prod', 'test']}
- test_fail:
- type: OS::Heat::TestResource
- properties:
- fail: True
- depends_on: [test, test2]
-'''
-
-recover_rename_tmpl = '''
-heat_template_version: 2016-10-14
-parameters:
- env_type:
- default: prod
- type: string
-conditions:
- cd3: {equals : [{get_param: env_type}, "prod"]}
-resources:
- test2:
- type: OS::Heat::TestResource
- properties:
- value: {if: [cd3, 'prod', 'test']}
- test_fail:
- type: OS::Heat::TestResource
- properties:
- fail: False
- depends_on: [test2]
-'''
-
-
-class CreateUpdateResConditionTest(functional_base.FunctionalTestsBase):
-
- def res_assert_for_prod(self, resources, bj_prod=True, fj_zone=False,
- shannxi_provice=False):
- res_names = [res.resource_name for res in resources]
- if bj_prod:
- self.assertEqual(4, len(resources))
- self.assertIn('beijing_prod_res', res_names)
- self.assertIn('not_shannxi_res', res_names)
- elif fj_zone:
- self.assertEqual(5, len(resources))
- self.assertIn('fujian_res', res_names)
- self.assertNotIn('beijing_prod_res', res_names)
- self.assertIn('not_shannxi_res', res_names)
- self.assertIn('fujian_prod_res', res_names)
- elif shannxi_provice:
- self.assertEqual(3, len(resources))
- self.assertIn('shannxi_res', res_names)
- else:
- self.assertEqual(3, len(resources))
- self.assertIn('not_shannxi_res', res_names)
- self.assertIn('prod_res', res_names)
- self.assertIn('test_res', res_names)
-
- def res_assert_for_test(self, resources, fj_zone=False,
- shannxi_provice=False):
- res_names = [res.resource_name for res in resources]
-
- if fj_zone:
- self.assertEqual(4, len(resources))
- self.assertIn('fujian_res', res_names)
- self.assertIn('not_shannxi_res', res_names)
- elif shannxi_provice:
- self.assertEqual(3, len(resources))
- self.assertNotIn('fujian_res', res_names)
- self.assertIn('shannxi_res', res_names)
- else:
- self.assertEqual(3, len(resources))
- self.assertIn('not_shannxi_res', res_names)
- self.assertIn('test_res', res_names)
- self.assertIn('test_res1', res_names)
- self.assertNotIn('prod_res', res_names)
-
- def output_assert_for_prod(self, stack_id, bj_prod=True):
- output = self.client.stacks.output_show(stack_id,
- 'res_value')['output']
- self.assertEqual('prod_res', output['output_value'])
-
- test_res_value = self.client.stacks.output_show(
- stack_id, 'test_res_value')['output']
- self.assertEqual('env_is_prod', test_res_value['output_value'])
-
- prod_resource = self.client.stacks.output_show(
- stack_id, 'prod_resource')['output']
- self.assertNotEqual('no_prod_res', prod_resource['output_value'])
-
- test_res_output = self.client.stacks.output_show(
- stack_id, 'test_res1_value')['output']
- self.assertEqual('no_test_res1', test_res_output['output_value'])
-
- beijing_prod_res = self.client.stacks.output_show(
- stack_id, 'beijing_prod_res')['output']
- if bj_prod:
- self.assertNotEqual('no_prod_res',
- beijing_prod_res['output_value'])
- else:
- self.assertEqual('no_prod_res', beijing_prod_res['output_value'])
-
- def output_assert_for_test(self, stack_id):
- output = self.client.stacks.output_show(stack_id,
- 'res_value')['output']
- self.assertIsNone(output['output_value'])
-
- test_res_value = self.client.stacks.output_show(
- stack_id, 'test_res_value')['output']
- self.assertEqual('env_is_test', test_res_value['output_value'])
-
- prod_resource = self.client.stacks.output_show(
- stack_id, 'prod_resource')['output']
- self.assertEqual('no_prod_res', prod_resource['output_value'])
-
- test_res_output = self.client.stacks.output_show(
- stack_id, 'test_res1_value')['output']
- self.assertEqual('just in test env',
- test_res_output['output_value'])
-
- beijing_prod_res = self.client.stacks.output_show(
- stack_id, 'beijing_prod_res')['output']
- self.assertEqual('no_prod_res', beijing_prod_res['output_value'])
-
- def test_stack_create_update_cfn_template_test_to_prod(self):
- stack_identifier = self.stack_create(template=cfn_template)
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_test(resources)
- self.output_assert_for_test(stack_identifier)
-
- parms = {'zone': 'fuzhou'}
- self.update_stack(stack_identifier,
- template=cfn_template,
- parameters=parms)
-
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_test(resources, fj_zone=True)
- self.output_assert_for_test(stack_identifier)
-
- parms = {'zone': 'xianyang'}
- self.update_stack(stack_identifier,
- template=cfn_template,
- parameters=parms)
-
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_test(resources, shannxi_provice=True)
- self.output_assert_for_test(stack_identifier)
-
- parms = {'env_type': 'prod'}
- self.update_stack(stack_identifier,
- template=cfn_template,
- parameters=parms)
-
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_prod(resources)
- self.output_assert_for_prod(stack_identifier)
-
- parms = {'env_type': 'prod',
- 'zone': 'shanghai'}
- self.update_stack(stack_identifier,
- template=cfn_template,
- parameters=parms)
-
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_prod(resources, False)
- self.output_assert_for_prod(stack_identifier, False)
-
- parms = {'env_type': 'prod',
- 'zone': 'xiamen'}
- self.update_stack(stack_identifier,
- template=cfn_template,
- parameters=parms)
-
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_prod(resources, bj_prod=False, fj_zone=True)
- self.output_assert_for_prod(stack_identifier, False)
-
- parms = {'env_type': 'prod',
- 'zone': 'xianyang'}
- self.update_stack(stack_identifier,
- template=cfn_template,
- parameters=parms)
-
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_prod(resources, bj_prod=False, fj_zone=False,
- shannxi_provice=True)
- self.output_assert_for_prod(stack_identifier, False)
-
- def test_stack_create_update_cfn_template_prod_to_test(self):
- parms = {'env_type': 'prod'}
- stack_identifier = self.stack_create(template=cfn_template,
- parameters=parms)
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_prod(resources)
- self.output_assert_for_prod(stack_identifier)
-
- parms = {'zone': 'xiamen',
- 'env_type': 'prod'}
- self.update_stack(stack_identifier,
- template=cfn_template,
- parameters=parms)
-
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_prod(resources, bj_prod=False, fj_zone=True)
- self.output_assert_for_prod(stack_identifier, bj_prod=False)
-
- parms = {'zone': 'xianyang',
- 'env_type': 'prod'}
- self.update_stack(stack_identifier,
- template=cfn_template,
- parameters=parms)
-
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_prod(resources, bj_prod=False, fj_zone=False,
- shannxi_provice=True)
- self.output_assert_for_prod(stack_identifier, bj_prod=False)
-
- parms = {'zone': 'shanghai',
- 'env_type': 'prod'}
- self.update_stack(stack_identifier,
- template=cfn_template,
- parameters=parms)
-
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_prod(resources, bj_prod=False, fj_zone=False,
- shannxi_provice=False)
- self.output_assert_for_prod(stack_identifier, bj_prod=False)
-
- parms = {'env_type': 'test'}
- self.update_stack(stack_identifier,
- template=cfn_template,
- parameters=parms)
-
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_test(resources)
- self.output_assert_for_test(stack_identifier)
-
- parms = {'env_type': 'test',
- 'zone': 'fuzhou'}
- self.update_stack(stack_identifier,
- template=cfn_template,
- parameters=parms)
-
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_test(resources, fj_zone=True)
- self.output_assert_for_test(stack_identifier)
-
- parms = {'env_type': 'test',
- 'zone': 'xianyang'}
- self.update_stack(stack_identifier,
- template=cfn_template,
- parameters=parms)
-
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_test(resources, fj_zone=False,
- shannxi_provice=True)
- self.output_assert_for_test(stack_identifier)
-
- def test_stack_create_update_hot_template_test_to_prod(self):
- stack_identifier = self.stack_create(template=hot_template)
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_test(resources)
- self.output_assert_for_test(stack_identifier)
-
- parms = {'zone': 'xianyang'}
- self.update_stack(stack_identifier,
- template=hot_template,
- parameters=parms)
-
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_test(resources, shannxi_provice=True)
- self.output_assert_for_test(stack_identifier)
-
- parms = {'env_type': 'prod'}
- self.update_stack(stack_identifier,
- template=hot_template,
- parameters=parms)
-
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_prod(resources)
- self.output_assert_for_prod(stack_identifier)
-
- parms = {'env_type': 'prod',
- 'zone': 'shanghai'}
- self.update_stack(stack_identifier,
- template=hot_template,
- parameters=parms)
-
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_prod(resources, False)
- self.output_assert_for_prod(stack_identifier, False)
-
- parms = {'env_type': 'prod',
- 'zone': 'xianyang'}
- self.update_stack(stack_identifier,
- template=hot_template,
- parameters=parms)
-
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_prod(resources, False, shannxi_provice=True)
- self.output_assert_for_prod(stack_identifier, False)
-
- def test_stack_create_update_hot_template_prod_to_test(self):
- parms = {'env_type': 'prod'}
- stack_identifier = self.stack_create(template=hot_template,
- parameters=parms)
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_prod(resources)
- self.output_assert_for_prod(stack_identifier)
-
- parms = {'env_type': 'prod',
- 'zone': 'xianyang'}
- self.update_stack(stack_identifier,
- template=hot_template,
- parameters=parms)
-
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_prod(resources, False, shannxi_provice=True)
- self.output_assert_for_prod(stack_identifier, False)
-
- parms = {'env_type': 'test'}
- self.update_stack(stack_identifier,
- template=hot_template,
- parameters=parms)
-
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_test(resources)
- self.output_assert_for_test(stack_identifier)
-
- parms = {'env_type': 'test',
- 'zone': 'xianyang'}
- self.update_stack(stack_identifier,
- template=hot_template,
- parameters=parms)
-
- resources = self.client.resources.list(stack_identifier)
- self.res_assert_for_test(resources, fj_zone=False,
- shannxi_provice=True)
- self.output_assert_for_test(stack_identifier)
-
- def test_condition_rename(self):
- stack_identifier = self.stack_create(template=before_rename_tmpl)
- self.update_stack(stack_identifier, template=after_rename_tmpl)
- self.update_stack(stack_identifier, template=fail_rename_tmpl,
- expected_status='UPDATE_FAILED')
- self.update_stack(stack_identifier, template=recover_rename_tmpl)
diff --git a/heat_tempest_plugin/tests/functional/test_create_update.py b/heat_tempest_plugin/tests/functional/test_create_update.py
deleted file mode 100644
index 46b1837..0000000
--- a/heat_tempest_plugin/tests/functional/test_create_update.py
+++ /dev/null
@@ -1,710 +0,0 @@
-# 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 copy
-import json
-
-from heat_tempest_plugin.common import test
-from heat_tempest_plugin.tests.functional import functional_base
-
-test_template_one_resource = {
- 'heat_template_version': 'pike',
- 'description': 'Test template to create one instance.',
- 'resources': {
- 'test1': {
- 'type': 'OS::Heat::TestResource',
- 'properties': {
- 'value': 'Test1',
- 'fail': False,
- 'update_replace': False,
- 'wait_secs': 1,
- 'action_wait_secs': {'create': 1},
- 'client_name': 'nova',
- 'entity_name': 'servers',
- }
- }
- }
-}
-
-test_template_two_resource = {
- 'heat_template_version': 'pike',
- 'description': 'Test template to create two instance.',
- 'resources': {
- 'test1': {
- 'type': 'OS::Heat::TestResource',
- 'properties': {
- 'value': 'Test1',
- 'fail': False,
- 'update_replace': False,
- 'wait_secs': 0,
- 'action_wait_secs': {'update': 1}
- }
- },
- 'test2': {
- 'type': 'OS::Heat::TestResource',
- 'properties': {
- 'value': 'Test1',
- 'fail': False,
- 'update_replace': False,
- 'wait_secs': 0
- }
- }
- }
-}
-
-
-def _change_rsrc_properties(template, rsrcs, values):
- modified_template = copy.deepcopy(template)
- for rsrc_name in rsrcs:
- rsrc_prop = modified_template['resources'][
- rsrc_name]['properties']
- for prop in rsrc_prop:
- if prop in values:
- rsrc_prop[prop] = values[prop]
- return modified_template
-
-
-class CreateStackTest(functional_base.FunctionalTestsBase):
- def test_create_rollback(self):
- values = {'fail': True, 'value': 'test_create_rollback'}
- template = _change_rsrc_properties(test_template_one_resource,
- ['test1'], values)
-
- self.stack_create(
- template=template,
- expected_status='ROLLBACK_COMPLETE',
- disable_rollback=False)
-
-
-class UpdateStackTest(functional_base.FunctionalTestsBase):
-
- provider_template = {
- 'heat_template_version': '2013-05-23',
- 'description': 'foo',
- 'resources': {
- 'test1': {
- 'type': 'My::TestResource'
- }
- }
- }
-
- provider_group_template = '''
-heat_template_version: 2013-05-23
-parameters:
- count:
- type: number
- default: 2
-resources:
- test_group:
- type: OS::Heat::ResourceGroup
- properties:
- count: {get_param: count}
- resource_def:
- type: My::TestResource
-'''
-
- update_userdata_template = '''
-heat_template_version: 2014-10-16
-parameters:
- flavor:
- type: string
- user_data:
- type: string
- image:
- type: string
- network:
- type: string
-
-resources:
- server:
- type: OS::Nova::Server
- properties:
- image: {get_param: image}
- flavor: {get_param: flavor}
- networks: [{network: {get_param: network} }]
- user_data_format: SOFTWARE_CONFIG
- user_data: {get_param: user_data}
-'''
-
- fail_param_template = '''
-heat_template_version: 2014-10-16
-parameters:
- do_fail:
- type: boolean
- default: False
-resources:
- aresource:
- type: OS::Heat::TestResource
- properties:
- value: Test
- fail: {get_param: do_fail}
- wait_secs: 1
-'''
-
- def test_stack_update_nochange(self):
- template = _change_rsrc_properties(test_template_one_resource,
- ['test1'],
- {'value': 'test_no_change'})
- stack_identifier = self.stack_create(
- template=template)
- expected_resources = {'test1': 'OS::Heat::TestResource'}
- self.assertEqual(expected_resources,
- self.list_resources(stack_identifier))
-
- # Update with no changes, resources should be unchanged
- self.update_stack(stack_identifier, template)
- self.assertEqual(expected_resources,
- self.list_resources(stack_identifier))
-
- def test_stack_in_place_update(self):
- template = _change_rsrc_properties(test_template_one_resource,
- ['test1'],
- {'value': 'test_in_place'})
- stack_identifier = self.stack_create(
- template=template)
- expected_resources = {'test1': 'OS::Heat::TestResource'}
- self.assertEqual(expected_resources,
- self.list_resources(stack_identifier))
- resource = self.client.resources.list(stack_identifier)
- initial_phy_id = resource[0].physical_resource_id
-
- tmpl_update = _change_rsrc_properties(
- test_template_one_resource, ['test1'],
- {'value': 'test_in_place_update'})
- # Update the Value
- self.update_stack(stack_identifier, tmpl_update)
- resource = self.client.resources.list(stack_identifier)
- # By default update_in_place
- self.assertEqual(initial_phy_id,
- resource[0].physical_resource_id)
-
- def test_stack_update_replace(self):
- template = _change_rsrc_properties(test_template_one_resource,
- ['test1'],
- {'value': 'test_replace'})
- stack_identifier = self.stack_create(
- template=template)
- expected_resources = {'test1': 'OS::Heat::TestResource'}
- self.assertEqual(expected_resources,
- self.list_resources(stack_identifier))
- resource = self.client.resources.list(stack_identifier)
- initial_phy_id = resource[0].physical_resource_id
-
- # Update the value and also set update_replace prop
- tmpl_update = _change_rsrc_properties(
- test_template_one_resource, ['test1'],
- {'value': 'test_in_place_update', 'update_replace': True})
- self.update_stack(stack_identifier, tmpl_update)
- resource = self.client.resources.list(stack_identifier)
- # update Replace
- self.assertNotEqual(initial_phy_id,
- resource[0].physical_resource_id)
-
- def test_stack_update_add_remove(self):
- template = _change_rsrc_properties(test_template_one_resource,
- ['test1'],
- {'value': 'test_add_remove'})
- stack_identifier = self.stack_create(
- template=template)
- initial_resources = {'test1': 'OS::Heat::TestResource'}
- self.assertEqual(initial_resources,
- self.list_resources(stack_identifier))
-
- tmpl_update = _change_rsrc_properties(
- test_template_two_resource, ['test1', 'test2'],
- {'value': 'test_add_remove_update'})
- # Add one resource via a stack update
- self.update_stack(stack_identifier, tmpl_update)
- updated_resources = {'test1': 'OS::Heat::TestResource',
- 'test2': 'OS::Heat::TestResource'}
- self.assertEqual(updated_resources,
- self.list_resources(stack_identifier))
-
- # Then remove it by updating with the original template
- self.update_stack(stack_identifier, template)
- self.assertEqual(initial_resources,
- self.list_resources(stack_identifier))
-
- def test_stack_update_rollback(self):
- template = _change_rsrc_properties(test_template_one_resource,
- ['test1'],
- {'value': 'test_update_rollback'})
- stack_identifier = self.stack_create(
- template=template)
- initial_resources = {'test1': 'OS::Heat::TestResource'}
- self.assertEqual(initial_resources,
- self.list_resources(stack_identifier))
-
- tmpl_update = _change_rsrc_properties(
- test_template_two_resource, ['test1', 'test2'],
- {'value': 'test_update_rollback', 'fail': True})
- # stack update, also set failure
- self.update_stack(stack_identifier, tmpl_update,
- expected_status='ROLLBACK_COMPLETE',
- disable_rollback=False)
- # since stack update failed only the original resource is present
- updated_resources = {'test1': 'OS::Heat::TestResource'}
- self.assertEqual(updated_resources,
- self.list_resources(stack_identifier))
-
- def test_stack_update_from_failed(self):
- # Prove it's possible to update from an UPDATE_FAILED state
- template = _change_rsrc_properties(test_template_one_resource,
- ['test1'],
- {'value': 'test_update_failed'})
- stack_identifier = self.stack_create(
- template=template)
- initial_resources = {'test1': 'OS::Heat::TestResource'}
- self.assertEqual(initial_resources,
- self.list_resources(stack_identifier))
-
- tmpl_update = _change_rsrc_properties(
- test_template_one_resource, ['test1'], {'fail': True})
- # Update with bad template, we should fail
- self.update_stack(stack_identifier, tmpl_update,
- expected_status='UPDATE_FAILED')
- # but then passing a good template should succeed
- self.update_stack(stack_identifier, test_template_two_resource)
- updated_resources = {'test1': 'OS::Heat::TestResource',
- 'test2': 'OS::Heat::TestResource'}
- self.assertEqual(updated_resources,
- self.list_resources(stack_identifier))
-
- def test_stack_update_provider(self):
- template = _change_rsrc_properties(
- test_template_one_resource, ['test1'],
- {'value': 'test_provider_template'})
- files = {'provider.template': json.dumps(template)}
- env = {'resource_registry':
- {'My::TestResource': 'provider.template'}}
- stack_identifier = self.stack_create(
- template=self.provider_template,
- files=files,
- environment=env
- )
-
- initial_resources = {'test1': 'My::TestResource'}
- self.assertEqual(initial_resources,
- self.list_resources(stack_identifier))
-
- # Prove the resource is backed by a nested stack, save the ID
- nested_identifier = self.assert_resource_is_a_stack(stack_identifier,
- 'test1')
- nested_id = nested_identifier.split('/')[-1]
-
- # Then check the expected resources are in the nested stack
- nested_resources = {'test1': 'OS::Heat::TestResource'}
- self.assertEqual(nested_resources,
- self.list_resources(nested_identifier))
- tmpl_update = _change_rsrc_properties(
- test_template_two_resource, ['test1', 'test2'],
- {'value': 'test_provider_template'})
- # Add one resource via a stack update by changing the nested stack
- files['provider.template'] = json.dumps(tmpl_update)
- self.update_stack(stack_identifier, self.provider_template,
- environment=env, files=files)
-
- # Parent resources should be unchanged and the nested stack
- # should have been updated in-place without replacement
- self.assertEqual(initial_resources,
- self.list_resources(stack_identifier))
- rsrc = self.client.resources.get(stack_identifier, 'test1')
- self.assertEqual(rsrc.physical_resource_id, nested_id)
-
- # Then check the expected resources are in the nested stack
- nested_resources = {'test1': 'OS::Heat::TestResource',
- 'test2': 'OS::Heat::TestResource'}
- self.assertEqual(nested_resources,
- self.list_resources(nested_identifier))
-
- def test_stack_update_alias_type(self):
- env = {'resource_registry':
- {'My::TestResource': 'OS::Heat::RandomString',
- 'My::TestResource2': 'OS::Heat::RandomString'}}
- stack_identifier = self.stack_create(
- template=self.provider_template,
- environment=env
- )
- p_res = self.client.resources.get(stack_identifier, 'test1')
- self.assertEqual('My::TestResource', p_res.resource_type)
-
- initial_resources = {'test1': 'My::TestResource'}
- self.assertEqual(initial_resources,
- self.list_resources(stack_identifier))
- res = self.client.resources.get(stack_identifier, 'test1')
- # Modify the type of the resource alias to My::TestResource2
- tmpl_update = copy.deepcopy(self.provider_template)
- tmpl_update['resources']['test1']['type'] = 'My::TestResource2'
- self.update_stack(stack_identifier, tmpl_update, environment=env)
- res_a = self.client.resources.get(stack_identifier, 'test1')
- self.assertEqual(res.physical_resource_id, res_a.physical_resource_id)
- self.assertEqual(res.attributes['value'], res_a.attributes['value'])
-
- def test_stack_update_alias_changes(self):
- env = {'resource_registry':
- {'My::TestResource': 'OS::Heat::RandomString'}}
- stack_identifier = self.stack_create(
- template=self.provider_template,
- environment=env
- )
- p_res = self.client.resources.get(stack_identifier, 'test1')
- self.assertEqual('My::TestResource', p_res.resource_type)
-
- initial_resources = {'test1': 'My::TestResource'}
- self.assertEqual(initial_resources,
- self.list_resources(stack_identifier))
- res = self.client.resources.get(stack_identifier, 'test1')
- # Modify the resource alias to point to a different type
- env = {'resource_registry':
- {'My::TestResource': 'OS::Heat::TestResource'}}
- self.update_stack(stack_identifier, template=self.provider_template,
- environment=env)
- res_a = self.client.resources.get(stack_identifier, 'test1')
- self.assertNotEqual(res.physical_resource_id,
- res_a.physical_resource_id)
-
- def test_stack_update_provider_type(self):
- template = _change_rsrc_properties(
- test_template_one_resource, ['test1'],
- {'value': 'test_provider_template'})
- files = {'provider.template': json.dumps(template)}
- env = {'resource_registry':
- {'My::TestResource': 'provider.template',
- 'My::TestResource2': 'provider.template'}}
- stack_identifier = self.stack_create(
- template=self.provider_template,
- files=files,
- environment=env
- )
- p_res = self.client.resources.get(stack_identifier, 'test1')
- self.assertEqual('My::TestResource', p_res.resource_type)
-
- initial_resources = {'test1': 'My::TestResource'}
- self.assertEqual(initial_resources,
- self.list_resources(stack_identifier))
-
- # Prove the resource is backed by a nested stack, save the ID
- nested_identifier = self.assert_resource_is_a_stack(stack_identifier,
- 'test1')
- nested_id = nested_identifier.split('/')[-1]
-
- # Then check the expected resources are in the nested stack
- nested_resources = {'test1': 'OS::Heat::TestResource'}
- self.assertEqual(nested_resources,
- self.list_resources(nested_identifier))
- n_res = self.client.resources.get(nested_identifier, 'test1')
-
- # Modify the type of the provider resource to My::TestResource2
- tmpl_update = copy.deepcopy(self.provider_template)
- tmpl_update['resources']['test1']['type'] = 'My::TestResource2'
- self.update_stack(stack_identifier, tmpl_update,
- environment=env, files=files)
- p_res = self.client.resources.get(stack_identifier, 'test1')
- self.assertEqual('My::TestResource2', p_res.resource_type)
-
- # Parent resources should be unchanged and the nested stack
- # should have been updated in-place without replacement
- self.assertEqual({u'test1': u'My::TestResource2'},
- self.list_resources(stack_identifier))
- rsrc = self.client.resources.get(stack_identifier, 'test1')
- self.assertEqual(rsrc.physical_resource_id, nested_id)
-
- # Then check the expected resources are in the nested stack
- self.assertEqual(nested_resources,
- self.list_resources(nested_identifier))
- n_res2 = self.client.resources.get(nested_identifier, 'test1')
- self.assertEqual(n_res.physical_resource_id,
- n_res2.physical_resource_id)
-
- def test_stack_update_provider_group(self):
- """Test two-level nested update."""
-
- # Create a ResourceGroup (which creates a nested stack),
- # containing provider resources (which create a nested
- # stack), thus exercising an update which traverses
- # two levels of nesting.
- template = _change_rsrc_properties(
- test_template_one_resource, ['test1'],
- {'value': 'test_provider_group_template'})
- files = {'provider.template': json.dumps(template)}
- env = {'resource_registry':
- {'My::TestResource': 'provider.template'}}
-
- stack_identifier = self.stack_create(
- template=self.provider_group_template,
- files=files,
- environment=env
- )
-
- initial_resources = {'test_group': 'OS::Heat::ResourceGroup'}
- self.assertEqual(initial_resources,
- self.list_resources(stack_identifier))
-
- # Prove the resource is backed by a nested stack, save the ID
- nested_identifier = self.assert_resource_is_a_stack(stack_identifier,
- 'test_group')
-
- # Then check the expected resources are in the nested stack
- nested_resources = {'0': 'My::TestResource',
- '1': 'My::TestResource'}
- self.assertEqual(nested_resources,
- self.list_resources(nested_identifier))
-
- for n_rsrc in nested_resources:
- rsrc = self.client.resources.get(nested_identifier, n_rsrc)
- provider_stack = self.client.stacks.get(rsrc.physical_resource_id)
- provider_identifier = '%s/%s' % (provider_stack.stack_name,
- provider_stack.id)
- provider_resources = {u'test1': u'OS::Heat::TestResource'}
- self.assertEqual(provider_resources,
- self.list_resources(provider_identifier))
-
- tmpl_update = _change_rsrc_properties(
- test_template_two_resource, ['test1', 'test2'],
- {'value': 'test_provider_group_template'})
- # Add one resource via a stack update by changing the nested stack
- files['provider.template'] = json.dumps(tmpl_update)
- self.update_stack(stack_identifier, self.provider_group_template,
- environment=env, files=files)
-
- # Parent resources should be unchanged and the nested stack
- # should have been updated in-place without replacement
- self.assertEqual(initial_resources,
- self.list_resources(stack_identifier))
-
- # Resource group stack should also be unchanged (but updated)
- nested_stack = self.client.stacks.get(nested_identifier)
- self.assertEqual('UPDATE_COMPLETE', nested_stack.stack_status)
- self.assertEqual(nested_resources,
- self.list_resources(nested_identifier))
-
- for n_rsrc in nested_resources:
- rsrc = self.client.resources.get(nested_identifier, n_rsrc)
- provider_stack = self.client.stacks.get(rsrc.physical_resource_id)
- provider_identifier = '%s/%s' % (provider_stack.stack_name,
- provider_stack.id)
- provider_resources = {'test1': 'OS::Heat::TestResource',
- 'test2': 'OS::Heat::TestResource'}
- self.assertEqual(provider_resources,
- self.list_resources(provider_identifier))
-
- def test_stack_update_with_replacing_userdata(self):
- """Test case for updating userdata of instance.
-
- Confirm that we can update userdata of instance during updating stack
- by the user of member role.
-
- Make sure that a resource that inherits from StackUser can be deleted
- during updating stack.
- """
- if not self.conf.minimal_image_ref:
- raise self.skipException("No minimal image configured to test")
- if not self.conf.minimal_instance_type:
- raise self.skipException("No flavor configured to test")
-
- parms = {'flavor': self.conf.minimal_instance_type,
- 'image': self.conf.minimal_image_ref,
- 'network': self.conf.fixed_network_name,
- 'user_data': ''}
-
- stack_identifier = self.stack_create(
- template=self.update_userdata_template,
- parameters=parms
- )
-
- parms_updated = parms
- parms_updated['user_data'] = 'two'
- self.update_stack(
- stack_identifier,
- template=self.update_userdata_template,
- parameters=parms_updated)
-
- def test_stack_update_provider_group_patch(self):
- '''Test two-level nested update with PATCH'''
- template = _change_rsrc_properties(
- test_template_one_resource, ['test1'],
- {'value': 'test_provider_group_template'})
- files = {'provider.template': json.dumps(template)}
- env = {'resource_registry':
- {'My::TestResource': 'provider.template'}}
-
- stack_identifier = self.stack_create(
- template=self.provider_group_template,
- files=files,
- environment=env
- )
-
- initial_resources = {'test_group': 'OS::Heat::ResourceGroup'}
- self.assertEqual(initial_resources,
- self.list_resources(stack_identifier))
-
- # Prove the resource is backed by a nested stack, save the ID
- nested_identifier = self.assert_resource_is_a_stack(stack_identifier,
- 'test_group')
-
- # Then check the expected resources are in the nested stack
- nested_resources = {'0': 'My::TestResource',
- '1': 'My::TestResource'}
- self.assertEqual(nested_resources,
- self.list_resources(nested_identifier))
-
- # increase the count, pass only the paramter, no env or template
- params = {'count': 3}
- self.update_stack(stack_identifier, parameters=params, existing=True)
-
- # Parent resources should be unchanged and the nested stack
- # should have been updated in-place without replacement
- self.assertEqual(initial_resources,
- self.list_resources(stack_identifier))
-
- # Resource group stack should also be unchanged (but updated)
- nested_stack = self.client.stacks.get(nested_identifier)
- self.assertEqual('UPDATE_COMPLETE', nested_stack.stack_status)
- # Add a resource, as we should have added one
- nested_resources['2'] = 'My::TestResource'
- self.assertEqual(nested_resources,
- self.list_resources(nested_identifier))
-
- def test_stack_update_from_failed_patch(self):
- '''Test PATCH update from a failed state.'''
-
- # Start with empty template
- stack_identifier = self.stack_create(
- template='heat_template_version: 2014-10-16')
-
- # Update with a good template, but bad parameter
- self.update_stack(stack_identifier,
- template=self.fail_param_template,
- parameters={'do_fail': True},
- expected_status='UPDATE_FAILED')
-
- # PATCH update, only providing the parameter
- self.update_stack(stack_identifier,
- parameters={'do_fail': False},
- existing=True)
- self.assertEqual({u'aresource': u'OS::Heat::TestResource'},
- self.list_resources(stack_identifier))
-
- def test_stack_update_with_new_env(self):
- """Update handles new resource types in the environment.
-
- If a resource type appears during an update and the update fails,
- retrying the update is able to find the type properly in the
- environment.
- """
- stack_identifier = self.stack_create(
- template=test_template_one_resource)
-
- # Update with a new resource and make the update fails
- template = _change_rsrc_properties(test_template_one_resource,
- ['test1'], {'fail': True})
- template['resources']['test2'] = {'type': 'My::TestResource'}
- template['resources']['test1']['depends_on'] = 'test2'
- env = {'resource_registry':
- {'My::TestResource': 'OS::Heat::TestResource'}}
- self.update_stack(stack_identifier,
- template=template,
- environment=env,
- expected_status='UPDATE_FAILED')
-
- # Fixing the template should fix the stack
- template = _change_rsrc_properties(template,
- ['test1'], {'fail': False})
- self.update_stack(stack_identifier,
- template=template,
- environment=env)
- self.assertEqual({'test1': 'OS::Heat::TestResource',
- 'test2': 'My::TestResource'},
- self.list_resources(stack_identifier))
-
- def test_stack_update_with_new_version(self):
- """Update handles new template version in failure.
-
- If a stack update fails while changing the template version, update is
- able to handle the new version fine.
- """
- stack_identifier = self.stack_create(
- template=test_template_one_resource)
-
- # Update with a new function and make the update fails
- template = _change_rsrc_properties(test_template_two_resource,
- ['test1'], {'fail': True})
-
- template['heat_template_version'] = '2015-10-15'
- template['resources']['test2']['properties']['value'] = {
- 'list_join': [',', ['a'], ['b']]}
- self.update_stack(stack_identifier,
- template=template,
- expected_status='UPDATE_FAILED')
-
- template = _change_rsrc_properties(template,
- ['test2'], {'value': 'Test2'})
- self.update_stack(stack_identifier,
- template=template,
- expected_status='UPDATE_FAILED')
- self._stack_delete(stack_identifier)
-
- def test_stack_update_with_old_version(self):
- """Update handles old template version in failure.
-
- If a stack update fails while changing the template version, update is
- able to handle the old version fine.
- """
- template = _change_rsrc_properties(
- test_template_one_resource,
- ['test1'], {'value': {'list_join': [',', ['a'], ['b']]}})
- template['heat_template_version'] = '2015-10-15'
- stack_identifier = self.stack_create(
- template=template)
-
- # Update with a new function and make the update fails
- template = _change_rsrc_properties(test_template_one_resource,
- ['test1'], {'fail': True})
- self.update_stack(stack_identifier,
- template=template,
- expected_status='UPDATE_FAILED')
- self._stack_delete(stack_identifier)
-
- def test_stack_update_with_conditions(self):
- """Update manages new conditions added.
-
- When a new resource is added during updates, the stacks handles the new
- conditions correctly, and doesn't fail to load them while the update is
- still in progress.
- """
- stack_identifier = self.stack_create(
- template=test_template_one_resource)
-
- updated_template = copy.deepcopy(test_template_two_resource)
- updated_template['conditions'] = {'cond1': True}
- updated_template['resources']['test3'] = {
- 'type': 'OS::Heat::TestResource',
- 'properties': {
- 'value': {'if': ['cond1', 'val3', 'val4']}
- }
- }
- test2_props = updated_template['resources']['test2']['properties']
- test2_props['action_wait_secs'] = {'create': 30}
-
- self.update_stack(stack_identifier,
- template=updated_template,
- expected_status='UPDATE_IN_PROGRESS')
-
- def check_resources():
- resources = self.list_resources(stack_identifier)
- if len(resources) < 2:
- return False
- self.assertIn('test3', resources)
- return True
-
- self.assertTrue(test.call_until_true(20, 2, check_resources))
diff --git a/heat_tempest_plugin/tests/functional/test_default_parameters.py b/heat_tempest_plugin/tests/functional/test_default_parameters.py
deleted file mode 100644
index 24aa6e4..0000000
--- a/heat_tempest_plugin/tests/functional/test_default_parameters.py
+++ /dev/null
@@ -1,92 +0,0 @@
-# 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 yaml
-
-from heat_tempest_plugin.tests.functional import functional_base
-
-
-class DefaultParametersTest(functional_base.FunctionalTestsBase):
-
- template = '''
-heat_template_version: 2013-05-23
-parameters:
- length:
- type: string
- default: 40
-resources:
- random1:
- type: nested_random.yaml
- random2:
- type: OS::Heat::RandomString
- properties:
- length: {get_param: length}
-outputs:
- random1:
- value: {get_attr: [random1, random1_value]}
- random2:
- value: {get_resource: random2}
-'''
- nested_template = '''
-heat_template_version: 2013-05-23
-parameters:
- length:
- type: string
- default: 50
-resources:
- random1:
- type: OS::Heat::RandomString
- properties:
- length: {get_param: length}
-outputs:
- random1_value:
- value: {get_resource: random1}
-'''
-
- scenarios = [
- ('none', dict(param=None, default=None, temp_def=True,
- expect1=50, expect2=40)),
- ('default', dict(param=None, default=12, temp_def=True,
- expect1=12, expect2=12)),
- ('both', dict(param=15, default=12, temp_def=True,
- expect1=12, expect2=15)),
- ('no_temp_default', dict(param=None, default=12, temp_def=False,
- expect1=12, expect2=12)),
- ]
-
- def test_defaults(self):
- env = {'parameters': {}, 'parameter_defaults': {}}
- if self.param:
- env['parameters'] = {'length': self.param}
- if self.default:
- env['parameter_defaults'] = {'length': self.default}
-
- if not self.temp_def:
- # remove the default from the parameter in the nested template.
- ntempl = yaml.safe_load(self.nested_template)
- del ntempl['parameters']['length']['default']
- nested_template = yaml.safe_dump(ntempl)
- else:
- nested_template = self.nested_template
-
- stack_identifier = self.stack_create(
- template=self.template,
- files={'nested_random.yaml': nested_template},
- environment=env
- )
-
- stack = self.client.stacks.get(stack_identifier)
- for out in stack.outputs:
- if out['output_key'] == 'random1':
- self.assertEqual(self.expect1, len(out['output_value']))
- if out['output_key'] == 'random2':
- self.assertEqual(self.expect2, len(out['output_value']))
diff --git a/heat_tempest_plugin/tests/functional/test_delete.py b/heat_tempest_plugin/tests/functional/test_delete.py
deleted file mode 100644
index 20266d6..0000000
--- a/heat_tempest_plugin/tests/functional/test_delete.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# 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 time
-
-from heat_tempest_plugin.tests.functional import functional_base
-
-
-class DeleteInProgressTest(functional_base.FunctionalTestsBase):
-
- root_template = '''
-heat_template_version: 2013-05-23
-resources:
- rg:
- type: OS::Heat::ResourceGroup
- properties:
- count: 125
- resource_def:
- type: empty.yaml
-'''
-
- empty_template = '''
-heat_template_version: 2013-05-23
-resources:
-'''
-
- def test_delete_nested_stacks_create_in_progress(self):
- files = {'empty.yaml': self.empty_template}
- identifier = self.stack_create(template=self.root_template,
- files=files,
- expected_status='CREATE_IN_PROGRESS')
- time.sleep(20)
- self._stack_delete(identifier)
diff --git a/heat_tempest_plugin/tests/functional/test_env_merge.py b/heat_tempest_plugin/tests/functional/test_env_merge.py
deleted file mode 100644
index 68ec035..0000000
--- a/heat_tempest_plugin/tests/functional/test_env_merge.py
+++ /dev/null
@@ -1,95 +0,0 @@
-#
-# 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.
-
-from heat_tempest_plugin.tests.functional import functional_base
-
-
-TEMPLATE = '''
- heat_template_version: 2015-04-30
- parameters:
- p0:
- type: string
- default: CORRECT
- p1:
- type: string
- default: INCORRECT
- p2:
- type: string
- default: INCORRECT
- resources:
- r1:
- type: test::R1
- r2:
- type: test::R2
- r3a:
- type: test::R3
- r3b:
- type: test::R3
-'''
-
-ENV_1 = '''
- parameters:
- p1: CORRECT
- p2: INCORRECT-E1
- resource_registry:
- test::R1: OS::Heat::RandomString
- test::R2: BROKEN
- test::R3: OS::Heat::None
-'''
-
-ENV_2 = '''
- parameters:
- p2: CORRECT
- resource_registry:
- test::R2: OS::Heat::RandomString
- resources:
- r3b:
- test::R3: OS::Heat::RandomString
-'''
-
-
-class EnvironmentMergingTests(functional_base.FunctionalTestsBase):
-
- def test_server_environment_merging(self):
-
- # Setup
- files = {'env1.yaml': ENV_1, 'env2.yaml': ENV_2}
- environment_files = ['env1.yaml', 'env2.yaml']
-
- # Test
- stack_id = self.stack_create(stack_name='env_merge',
- template=TEMPLATE,
- files=files,
- environment_files=environment_files)
-
- # Verify
-
- # Since there is no environment show, the registry overriding
- # is partially verified by there being no error. If it wasn't
- # working, test::R2 would remain mapped to BROKEN in env1.
-
- # Sanity check
- resources = self.list_resources(stack_id)
- self.assertEqual(4, len(resources))
-
- # Verify the parameters are correctly set
- stack = self.client.stacks.get(stack_id)
- self.assertEqual('CORRECT', stack.parameters['p0'])
- self.assertEqual('CORRECT', stack.parameters['p1'])
- self.assertEqual('CORRECT', stack.parameters['p2'])
-
- # Verify that r3b has been overridden into a RandomString
- # by checking to see that it has a value
- r3b = self.client.resources.get(stack_id, 'r3b')
- r3b_attrs = r3b.attributes
- self.assertIn('value', r3b_attrs)
diff --git a/heat_tempest_plugin/tests/functional/test_heat_autoscaling.py b/heat_tempest_plugin/tests/functional/test_heat_autoscaling.py
deleted file mode 100644
index a83c7fe..0000000
--- a/heat_tempest_plugin/tests/functional/test_heat_autoscaling.py
+++ /dev/null
@@ -1,215 +0,0 @@
-# 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.
-
-from heat_tempest_plugin.common import test
-from heat_tempest_plugin.tests.functional import functional_base
-
-
-class HeatAutoscalingTest(functional_base.FunctionalTestsBase):
- template = '''
-heat_template_version: 2014-10-16
-
-resources:
- random_group:
- type: OS::Heat::AutoScalingGroup
- properties:
- cooldown: 0
- desired_capacity: 3
- max_size: 5
- min_size: 2
- resource:
- type: OS::Heat::RandomString
-
- scale_up_policy:
- type: OS::Heat::ScalingPolicy
- properties:
- adjustment_type: change_in_capacity
- auto_scaling_group_id: { get_resource: random_group }
- scaling_adjustment: 1
-
- scale_down_policy:
- type: OS::Heat::ScalingPolicy
- properties:
- adjustment_type: change_in_capacity
- auto_scaling_group_id: { get_resource: random_group }
- scaling_adjustment: -1
-
-outputs:
- all_values:
- value: {get_attr: [random_group, outputs_list, value]}
- value_0:
- value: {get_attr: [random_group, resource.0.value]}
- value_1:
- value: {get_attr: [random_group, resource.1.value]}
- value_2:
- value: {get_attr: [random_group, resource.2.value]}
- asg_size:
- value: {get_attr: [random_group, current_size]}
-'''
-
- template_nested = '''
-heat_template_version: 2014-10-16
-
-resources:
- random_group:
- type: OS::Heat::AutoScalingGroup
- properties:
- desired_capacity: 3
- max_size: 5
- min_size: 2
- resource:
- type: randomstr.yaml
-
-outputs:
- all_values:
- value: {get_attr: [random_group, outputs_list, random_str]}
- value_0:
- value: {get_attr: [random_group, resource.0.random_str]}
- value_1:
- value: {get_attr: [random_group, resource.1.random_str]}
- value_2:
- value: {get_attr: [random_group, resource.2.random_str]}
-'''
-
- template_randomstr = '''
-heat_template_version: 2013-05-23
-
-resources:
- random_str:
- type: OS::Heat::RandomString
-
-outputs:
- random_str:
- value: {get_attr: [random_str, value]}
-'''
-
- def _assert_output_values(self, stack_id):
- stack = self.client.stacks.get(stack_id)
- all_values = self._stack_output(stack, 'all_values')
- self.assertEqual(3, len(all_values))
- self.assertEqual(all_values[0], self._stack_output(stack, 'value_0'))
- self.assertEqual(all_values[1], self._stack_output(stack, 'value_1'))
- self.assertEqual(all_values[2], self._stack_output(stack, 'value_2'))
-
- def test_asg_scale_up_max_size(self):
- stack_id = self.stack_create(template=self.template,
- expected_status='CREATE_COMPLETE')
- stack = self.client.stacks.get(stack_id)
- asg_size = self._stack_output(stack, 'asg_size')
- # Ensure that initial desired capacity is met
- self.assertEqual(3, asg_size)
-
- # send scale up signals and ensure that asg honors max_size
- asg = self.client.resources.get(stack_id, 'random_group')
- max_size = 5
- for num in range(asg_size+1, max_size+2):
- expected_resources = num if num <= max_size else max_size
- self.client.resources.signal(stack_id, 'scale_up_policy')
- self.assertTrue(
- test.call_until_true(self.conf.build_timeout,
- self.conf.build_interval,
- self.check_autoscale_complete,
- asg.physical_resource_id,
- expected_resources, stack_id,
- 'scale_up_policy'))
-
- def test_asg_scale_down_min_size(self):
- stack_id = self.stack_create(template=self.template,
- expected_status='CREATE_COMPLETE')
- stack = self.client.stacks.get(stack_id)
- asg_size = self._stack_output(stack, 'asg_size')
- # Ensure that initial desired capacity is met
- self.assertEqual(3, asg_size)
-
- # send scale down signals and ensure that asg honors min_size
- asg = self.client.resources.get(stack_id, 'random_group')
- min_size = 2
- for num in range(asg_size-1, 0, -1):
- expected_resources = num if num >= min_size else min_size
- self.client.resources.signal(stack_id, 'scale_down_policy')
- self.assertTrue(
- test.call_until_true(self.conf.build_timeout,
- self.conf.build_interval,
- self.check_autoscale_complete,
- asg.physical_resource_id,
- expected_resources, stack_id,
- 'scale_down_policy'))
-
- def test_asg_cooldown(self):
- cooldown_tmpl = self.template.replace('cooldown: 0',
- 'cooldown: 60')
- stack_id = self.stack_create(template=cooldown_tmpl,
- expected_status='CREATE_COMPLETE')
- stack = self.client.stacks.get(stack_id)
- asg_size = self._stack_output(stack, 'asg_size')
- # Ensure that initial desired capacity is met
- self.assertEqual(3, asg_size)
-
- # send scale up signal.
- # Since cooldown is in effect, number of resources should not change
- asg = self.client.resources.get(stack_id, 'random_group')
- expected_resources = 3
- self.client.resources.signal(stack_id, 'scale_up_policy')
- self.assertTrue(
- test.call_until_true(self.conf.build_timeout,
- self.conf.build_interval,
- self.check_autoscale_complete,
- asg.physical_resource_id,
- expected_resources, stack_id,
- 'scale_up_policy'))
-
- def test_path_attrs(self):
- stack_id = self.stack_create(template=self.template)
- expected_resources = {'random_group': 'OS::Heat::AutoScalingGroup',
- 'scale_up_policy': 'OS::Heat::ScalingPolicy',
- 'scale_down_policy': 'OS::Heat::ScalingPolicy'}
- self.assertEqual(expected_resources, self.list_resources(stack_id))
- self._assert_output_values(stack_id)
-
- def test_path_attrs_nested(self):
- files = {'randomstr.yaml': self.template_randomstr}
- stack_id = self.stack_create(template=self.template_nested,
- files=files)
- expected_resources = {'random_group': 'OS::Heat::AutoScalingGroup'}
- self.assertEqual(expected_resources, self.list_resources(stack_id))
- self._assert_output_values(stack_id)
-
-
-class AutoScalingGroupUpdateWithNoChanges(functional_base.FunctionalTestsBase):
-
- template = '''
-heat_template_version: 2013-05-23
-
-resources:
- test_group:
- type: OS::Heat::AutoScalingGroup
- properties:
- desired_capacity: 0
- max_size: 0
- min_size: 0
- resource:
- type: OS::Heat::RandomString
- test_policy:
- type: OS::Heat::ScalingPolicy
- properties:
- adjustment_type: change_in_capacity
- auto_scaling_group_id: { get_resource: test_group }
- scaling_adjustment: 1
-'''
-
- def test_as_group_update_without_resource_changes(self):
- stack_identifier = self.stack_create(template=self.template)
- new_template = self.template.replace(
- 'scaling_adjustment: 1',
- 'scaling_adjustment: 2')
-
- self.update_stack(stack_identifier, template=new_template)
diff --git a/heat_tempest_plugin/tests/functional/test_immutable_parameters.py b/heat_tempest_plugin/tests/functional/test_immutable_parameters.py
deleted file mode 100644
index f031c01..0000000
--- a/heat_tempest_plugin/tests/functional/test_immutable_parameters.py
+++ /dev/null
@@ -1,141 +0,0 @@
-# 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.
-
-from heat_tempest_plugin.tests.functional import functional_base
-from heatclient import exc as heat_exceptions
-
-
-class ImmutableParametersTest(functional_base.FunctionalTestsBase):
-
- template_param_has_no_immutable_field = '''
-heat_template_version: 2014-10-16
-parameters:
- param1:
- type: string
- default: default_value
-outputs:
- param1_output:
- description: 'parameter 1 details'
- value: { get_param: param1 }
-'''
-
- template_param_has_immutable_field = '''
-heat_template_version: 2014-10-16
-parameters:
- param1:
- type: string
- default: default_value
- immutable: false
-outputs:
- param1_output:
- description: 'parameter 1 details'
- value: { get_param: param1 }
-'''
-
- def test_no_immutable_param_field(self):
- param1_create_value = 'value1'
- create_parameters = {"param1": param1_create_value}
-
- stack_identifier = self.stack_create(
- template=self.template_param_has_no_immutable_field,
- parameters=create_parameters
- )
- stack = self.client.stacks.get(stack_identifier)
-
- # Verify the value of the parameter
- self.assertEqual(param1_create_value,
- self._stack_output(stack, 'param1_output'))
-
- param1_update_value = 'value2'
- update_parameters = {"param1": param1_update_value}
-
- self.update_stack(
- stack_identifier,
- template=self.template_param_has_no_immutable_field,
- parameters=update_parameters)
-
- stack = self.client.stacks.get(stack_identifier)
-
- # Verify the value of the updated parameter
- self.assertEqual(param1_update_value,
- self._stack_output(stack, 'param1_output'))
-
- def test_immutable_param_field_allowed(self):
- param1_create_value = 'value1'
- create_parameters = {"param1": param1_create_value}
-
- stack_identifier = self.stack_create(
- template=self.template_param_has_immutable_field,
- parameters=create_parameters
- )
- stack = self.client.stacks.get(stack_identifier)
-
- # Verify the value of the parameter
- self.assertEqual(param1_create_value,
- self._stack_output(stack, 'param1_output'))
-
- param1_update_value = 'value2'
- update_parameters = {"param1": param1_update_value}
-
- self.update_stack(
- stack_identifier,
- template=self.template_param_has_immutable_field,
- parameters=update_parameters)
- stack = self.client.stacks.get(stack_identifier)
-
- # Verify the value of the updated parameter
- self.assertEqual(param1_update_value,
- self._stack_output(stack, 'param1_output'))
-
- # Ensure stack is not in a failed state
- self.assertEqual('UPDATE_COMPLETE', stack.stack_status)
-
- def test_immutable_param_field_error(self):
- param1_create_value = 'value1'
- create_parameters = {"param1": param1_create_value}
-
- # Toggle the immutable field to preclude updating
- immutable_true = self.template_param_has_immutable_field.replace(
- 'immutable: false', 'immutable: true')
-
- stack_identifier = self.stack_create(
- template=immutable_true,
- parameters=create_parameters
- )
- stack = self.client.stacks.get(stack_identifier)
-
- param1_update_value = 'value2'
- update_parameters = {"param1": param1_update_value}
-
- # Verify the value of the parameter
- self.assertEqual(param1_create_value,
- self._stack_output(stack, 'param1_output'))
-
- # Attempt to update the stack with a new parameter value
- try:
- self.update_stack(
- stack_identifier,
- template=immutable_true,
- parameters=update_parameters)
- except heat_exceptions.HTTPBadRequest as exc:
- exp = ('The following parameters are immutable and may not be '
- 'updated: param1')
- self.assertIn(exp, str(exc))
-
- stack = self.client.stacks.get(stack_identifier)
-
- # Ensure stack is not in a failed state
- self.assertEqual('CREATE_COMPLETE', stack.stack_status)
-
- # Ensure immutable parameter has not changed
- self.assertEqual(param1_create_value,
- self._stack_output(stack, 'param1_output'))
diff --git a/heat_tempest_plugin/tests/functional/test_instance_group.py b/heat_tempest_plugin/tests/functional/test_instance_group.py
deleted file mode 100644
index c0bb7e8..0000000
--- a/heat_tempest_plugin/tests/functional/test_instance_group.py
+++ /dev/null
@@ -1,500 +0,0 @@
-# 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 copy
-import json
-
-from testtools import matchers
-
-from heat_tempest_plugin.tests.functional import functional_base
-
-
-class InstanceGroupTest(functional_base.FunctionalTestsBase):
-
- template = '''
-{
- "AWSTemplateFormatVersion" : "2010-09-09",
- "Description" : "Template to create multiple instances.",
- "Parameters" : {"size": {"Type": "String", "Default": "1"},
- "AZ": {"Type": "String", "Default": "nova"},
- "image": {"Type": "String"},
- "flavor": {"Type": "String"},
- "user_data": {"Type": "String", "Default": "jsconfig data"}},
- "Resources": {
- "JobServerGroup": {
- "Type": "OS::Heat::InstanceGroup",
- "Properties": {
- "LaunchConfigurationName" : {"Ref": "JobServerConfig"},
- "Size" : {"Ref": "size"},
- "AvailabilityZones" : [{"Ref": "AZ"}]
- }
- },
-
- "JobServerConfig" : {
- "Type" : "AWS::AutoScaling::LaunchConfiguration",
- "Metadata": {"foo": "bar"},
- "Properties": {
- "ImageId" : {"Ref": "image"},
- "InstanceType" : {"Ref": "flavor"},
- "SecurityGroups" : [ "sg-1" ],
- "UserData" : {"Ref": "user_data"}
- }
- }
- },
- "Outputs": {
- "InstanceList": {"Value": {
- "Fn::GetAtt": ["JobServerGroup", "InstanceList"]}},
- "JobServerConfigRef": {"Value": {
- "Ref": "JobServerConfig"}}
- }
-}
-'''
-
- instance_template = '''
-heat_template_version: 2013-05-23
-parameters:
- ImageId: {type: string}
- InstanceType: {type: string}
- SecurityGroups: {type: comma_delimited_list}
- UserData: {type: string}
- Tags: {type: comma_delimited_list}
-
-resources:
- random1:
- type: OS::Heat::RandomString
- properties:
- salt: {get_param: UserData}
-outputs:
- PublicIp:
- value: {get_attr: [random1, value]}
-'''
-
- # This is designed to fail.
- bad_instance_template = '''
-heat_template_version: 2013-05-23
-parameters:
- ImageId: {type: string}
- InstanceType: {type: string}
- SecurityGroups: {type: comma_delimited_list}
- UserData: {type: string}
- Tags: {type: comma_delimited_list}
-
-resources:
- random1:
- type: OS::Heat::RandomString
- depends_on: waiter
- ready_poster:
- type: AWS::CloudFormation::WaitConditionHandle
- waiter:
- type: AWS::CloudFormation::WaitCondition
- properties:
- Handle: {Ref: ready_poster}
- Timeout: 1
-outputs:
- PublicIp:
- value: {get_attr: [random1, value]}
-'''
-
- def setUp(self):
- super(InstanceGroupTest, self).setUp()
- if not self.conf.minimal_image_ref:
- raise self.skipException("No minimal image configured to test")
- if not self.conf.instance_type:
- raise self.skipException("No flavor configured to test")
-
- def assert_instance_count(self, stack, expected_count):
- inst_list = self._stack_output(stack, 'InstanceList')
- self.assertEqual(expected_count, len(inst_list.split(',')))
-
- def _assert_instance_state(self, nested_identifier,
- num_complete, num_failed):
- for res in self.client.resources.list(nested_identifier):
- if 'COMPLETE' in res.resource_status:
- num_complete = num_complete - 1
- elif 'FAILED' in res.resource_status:
- num_failed = num_failed - 1
- self.assertEqual(0, num_failed)
- self.assertEqual(0, num_complete)
-
-
-class InstanceGroupBasicTest(InstanceGroupTest):
-
- def test_basic_create_works(self):
- """Make sure the working case is good.
-
- Note this combines test_override_aws_ec2_instance into this test as
- well, which is:
- If AWS::EC2::Instance is overridden, InstanceGroup will automatically
- use that overridden resource type.
- """
-
- files = {'provider.yaml': self.instance_template}
- env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'},
- 'parameters': {'size': 4,
- 'image': self.conf.minimal_image_ref,
- 'flavor': self.conf.instance_type}}
- stack_identifier = self.stack_create(template=self.template,
- files=files, environment=env)
- initial_resources = {
- 'JobServerConfig': 'AWS::AutoScaling::LaunchConfiguration',
- 'JobServerGroup': 'OS::Heat::InstanceGroup'}
- self.assertEqual(initial_resources,
- self.list_resources(stack_identifier))
-
- stack = self.client.stacks.get(stack_identifier)
- self.assert_instance_count(stack, 4)
-
- def test_size_updates_work(self):
- files = {'provider.yaml': self.instance_template}
- env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'},
- 'parameters': {'size': 2,
- 'image': self.conf.minimal_image_ref,
- 'flavor': self.conf.instance_type}}
-
- stack_identifier = self.stack_create(template=self.template,
- files=files,
- environment=env)
- stack = self.client.stacks.get(stack_identifier)
- self.assert_instance_count(stack, 2)
-
- # Increase min size to 5
- env2 = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'},
- 'parameters': {'size': 5,
- 'image': self.conf.minimal_image_ref,
- 'flavor': self.conf.instance_type}}
- self.update_stack(stack_identifier, self.template,
- environment=env2, files=files)
- stack = self.client.stacks.get(stack_identifier)
- self.assert_instance_count(stack, 5)
-
- def test_update_group_replace(self):
- """Test case for ensuring non-updatable props case a replacement.
-
- Make sure that during a group update the non-updatable properties cause
- a replacement.
- """
- files = {'provider.yaml': self.instance_template}
- env = {'resource_registry':
- {'AWS::EC2::Instance': 'provider.yaml'},
- 'parameters': {'size': 1,
- 'image': self.conf.minimal_image_ref,
- 'flavor': self.conf.instance_type}}
-
- stack_identifier = self.stack_create(template=self.template,
- files=files,
- environment=env)
- rsrc = self.client.resources.get(stack_identifier, 'JobServerGroup')
- orig_asg_id = rsrc.physical_resource_id
-
- env2 = {'resource_registry':
- {'AWS::EC2::Instance': 'provider.yaml'},
- 'parameters': {'size': '2',
- 'AZ': 'wibble',
- 'image': self.conf.minimal_image_ref,
- 'flavor': self.conf.instance_type,
- 'user_data': 'new data'}}
- self.update_stack(stack_identifier, self.template,
- environment=env2, files=files)
-
- # replacement will cause the resource physical_resource_id to change.
- rsrc = self.client.resources.get(stack_identifier, 'JobServerGroup')
- self.assertNotEqual(orig_asg_id, rsrc.physical_resource_id)
-
- def test_create_instance_error_causes_group_error(self):
- """Test create failing a resource in the instance group.
-
- If a resource in an instance group fails to be created, the instance
- group itself will fail and the broken inner resource will remain.
- """
- stack_name = self._stack_rand_name()
- files = {'provider.yaml': self.bad_instance_template}
- env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'},
- 'parameters': {'size': 2,
- 'image': self.conf.minimal_image_ref,
- 'flavor': self.conf.instance_type}}
-
- self.client.stacks.create(
- stack_name=stack_name,
- template=self.template,
- files=files,
- disable_rollback=True,
- parameters={},
- environment=env
- )
- self.addCleanup(self._stack_delete, stack_name)
- stack = self.client.stacks.get(stack_name)
- stack_identifier = '%s/%s' % (stack_name, stack.id)
- self._wait_for_stack_status(stack_identifier, 'CREATE_FAILED')
- initial_resources = {
- 'JobServerConfig': 'AWS::AutoScaling::LaunchConfiguration',
- 'JobServerGroup': 'OS::Heat::InstanceGroup'}
- self.assertEqual(initial_resources,
- self.list_resources(stack_identifier))
-
- nested_ident = self.assert_resource_is_a_stack(stack_identifier,
- 'JobServerGroup')
- self._assert_instance_state(nested_ident, 0, 2)
-
- def test_update_instance_error_causes_group_error(self):
- """Test update failing a resource in the instance group.
-
- If a resource in an instance group fails to be created during an
- update, the instance group itself will fail and the broken inner
- resource will remain.
- """
- files = {'provider.yaml': self.instance_template}
- env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'},
- 'parameters': {'size': 2,
- 'image': self.conf.minimal_image_ref,
- 'flavor': self.conf.instance_type}}
-
- stack_identifier = self.stack_create(template=self.template,
- files=files,
- environment=env)
- initial_resources = {
- 'JobServerConfig': 'AWS::AutoScaling::LaunchConfiguration',
- 'JobServerGroup': 'OS::Heat::InstanceGroup'}
- self.assertEqual(initial_resources,
- self.list_resources(stack_identifier))
-
- stack = self.client.stacks.get(stack_identifier)
- self.assert_instance_count(stack, 2)
- nested_ident = self.assert_resource_is_a_stack(stack_identifier,
- 'JobServerGroup')
- self._assert_instance_state(nested_ident, 2, 0)
- initial_list = [res.resource_name
- for res in self.client.resources.list(nested_ident)]
-
- env['parameters']['size'] = 3
- files2 = {'provider.yaml': self.bad_instance_template}
- self.client.stacks.update(
- stack_id=stack_identifier,
- template=self.template,
- files=files2,
- disable_rollback=True,
- parameters={},
- environment=env
- )
- self._wait_for_stack_status(stack_identifier, 'UPDATE_FAILED')
-
- nested_ident = self.assert_resource_is_a_stack(stack_identifier,
- 'JobServerGroup')
- # assert that there are 3 bad instances
- # 2 resources should be in update failed, and one create failed.
- for res in self.client.resources.list(nested_ident):
- if res.resource_name in initial_list:
- self._wait_for_resource_status(nested_ident,
- res.resource_name,
- 'UPDATE_FAILED')
- else:
- self._wait_for_resource_status(nested_ident,
- res.resource_name,
- 'CREATE_FAILED')
-
-
-class InstanceGroupUpdatePolicyTest(InstanceGroupTest):
-
- def ig_tmpl_with_updt_policy(self):
- templ = json.loads(copy.deepcopy(self.template))
- up = {"RollingUpdate": {
- "MinInstancesInService": "1",
- "MaxBatchSize": "2",
- "PauseTime": "PT1S"}}
- templ['Resources']['JobServerGroup']['UpdatePolicy'] = up
- return templ
-
- def update_instance_group(self, updt_template,
- num_updates_expected_on_updt,
- num_creates_expected_on_updt,
- num_deletes_expected_on_updt,
- update_replace):
-
- # setup stack from the initial template
- files = {'provider.yaml': self.instance_template}
- size = 5
- env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'},
- 'parameters': {'size': size,
- 'image': self.conf.minimal_image_ref,
- 'flavor': self.conf.minimal_instance_type}}
- stack_name = self._stack_rand_name()
- stack_identifier = self.stack_create(
- stack_name=stack_name,
- template=self.ig_tmpl_with_updt_policy(),
- files=files,
- environment=env)
- stack = self.client.stacks.get(stack_identifier)
- nested_ident = self.assert_resource_is_a_stack(stack_identifier,
- 'JobServerGroup')
-
- # test that physical resource name of launch configuration is used
- conf_name = self._stack_output(stack, 'JobServerConfigRef')
- conf_name_pattern = '%s-JobServerConfig-[a-zA-Z0-9]+$' % stack_name
- self.assertThat(conf_name,
- matchers.MatchesRegex(conf_name_pattern))
-
- # test the number of instances created
- self.assert_instance_count(stack, size)
- # saves info from initial list of instances for comparison later
- init_instances = self.client.resources.list(nested_ident)
- init_names = [inst.resource_name for inst in init_instances]
-
- # test stack update
- self.update_stack(stack_identifier, updt_template,
- environment=env, files=files)
- updt_stack = self.client.stacks.get(stack_identifier)
-
- # test that the launch configuration is replaced
- updt_conf_name = self._stack_output(updt_stack, 'JobServerConfigRef')
- self.assertThat(updt_conf_name,
- matchers.MatchesRegex(conf_name_pattern))
- self.assertNotEqual(conf_name, updt_conf_name)
-
- # test that the group size are the same
- updt_instances = self.client.resources.list(nested_ident)
- updt_names = [inst.resource_name for inst in updt_instances]
- self.assertEqual(len(init_names), len(updt_names))
- for res in updt_instances:
- self.assertEqual('UPDATE_COMPLETE', res.resource_status)
-
- # test that the appropriate number of instance names are the same
- matched_names = set(updt_names) & set(init_names)
- self.assertEqual(num_updates_expected_on_updt, len(matched_names))
-
- # test that the appropriate number of new instances are created
- self.assertEqual(num_creates_expected_on_updt,
- len(set(updt_names) - set(init_names)))
-
- # test that the appropriate number of instances are deleted
- self.assertEqual(num_deletes_expected_on_updt,
- len(set(init_names) - set(updt_names)))
-
- # test that the older instances are the ones being deleted
- if num_deletes_expected_on_updt > 0:
- deletes_expected = init_names[:num_deletes_expected_on_updt]
- self.assertNotIn(deletes_expected, updt_names)
-
- def test_instance_group_update_replace(self):
- """Test simple update replace with no conflict.
-
- Test simple update replace with no conflict in batch size and
- minimum instances in service.
- """
- updt_template = self.ig_tmpl_with_updt_policy()
- grp = updt_template['Resources']['JobServerGroup']
- policy = grp['UpdatePolicy']['RollingUpdate']
- policy['MinInstancesInService'] = '1'
- policy['MaxBatchSize'] = '3'
- config = updt_template['Resources']['JobServerConfig']
- config['Properties']['UserData'] = 'new data'
-
- self.update_instance_group(updt_template,
- num_updates_expected_on_updt=5,
- num_creates_expected_on_updt=0,
- num_deletes_expected_on_updt=0,
- update_replace=True)
-
- def test_instance_group_update_replace_with_adjusted_capacity(self):
- """Test update replace with capacity adjustment.
-
- Test update replace with capacity adjustment due to conflict in
- batch size and minimum instances in service.
- """
- updt_template = self.ig_tmpl_with_updt_policy()
- grp = updt_template['Resources']['JobServerGroup']
- policy = grp['UpdatePolicy']['RollingUpdate']
- policy['MinInstancesInService'] = '4'
- policy['MaxBatchSize'] = '4'
- config = updt_template['Resources']['JobServerConfig']
- config['Properties']['UserData'] = 'new data'
-
- self.update_instance_group(updt_template,
- num_updates_expected_on_updt=2,
- num_creates_expected_on_updt=3,
- num_deletes_expected_on_updt=3,
- update_replace=True)
-
- def test_instance_group_update_replace_huge_batch_size(self):
- """Test update replace with a huge batch size."""
- updt_template = self.ig_tmpl_with_updt_policy()
- group = updt_template['Resources']['JobServerGroup']
- policy = group['UpdatePolicy']['RollingUpdate']
- policy['MinInstancesInService'] = '0'
- policy['MaxBatchSize'] = '20'
- config = updt_template['Resources']['JobServerConfig']
- config['Properties']['UserData'] = 'new data'
-
- self.update_instance_group(updt_template,
- num_updates_expected_on_updt=5,
- num_creates_expected_on_updt=0,
- num_deletes_expected_on_updt=0,
- update_replace=True)
-
- def test_instance_group_update_replace_huge_min_in_service(self):
- """Update replace with huge number of minimum instances in service."""
- updt_template = self.ig_tmpl_with_updt_policy()
- group = updt_template['Resources']['JobServerGroup']
- policy = group['UpdatePolicy']['RollingUpdate']
- policy['MinInstancesInService'] = '20'
- policy['MaxBatchSize'] = '2'
- policy['PauseTime'] = 'PT0S'
- config = updt_template['Resources']['JobServerConfig']
- config['Properties']['UserData'] = 'new data'
-
- self.update_instance_group(updt_template,
- num_updates_expected_on_updt=3,
- num_creates_expected_on_updt=2,
- num_deletes_expected_on_updt=2,
- update_replace=True)
-
- def test_instance_group_update_no_replace(self):
- """Test simple update only and no replace with no conflict.
-
- Test simple update only and no replace (i.e. updated instance flavor
- in Launch Configuration) with no conflict in batch size and
- minimum instances in service.
- """
- updt_template = self.ig_tmpl_with_updt_policy()
- group = updt_template['Resources']['JobServerGroup']
- policy = group['UpdatePolicy']['RollingUpdate']
- policy['MinInstancesInService'] = '1'
- policy['MaxBatchSize'] = '3'
- policy['PauseTime'] = 'PT0S'
- config = updt_template['Resources']['JobServerConfig']
- config['Properties']['InstanceType'] = self.conf.instance_type
-
- self.update_instance_group(updt_template,
- num_updates_expected_on_updt=5,
- num_creates_expected_on_updt=0,
- num_deletes_expected_on_updt=0,
- update_replace=False)
-
- def test_instance_group_update_no_replace_with_adjusted_capacity(self):
- """Test update only and no replace with capacity adjustment.
-
- Test update only and no replace (i.e. updated instance flavor in
- Launch Configuration) with capacity adjustment due to conflict in
- batch size and minimum instances in service.
- """
- updt_template = self.ig_tmpl_with_updt_policy()
- group = updt_template['Resources']['JobServerGroup']
- policy = group['UpdatePolicy']['RollingUpdate']
- policy['MinInstancesInService'] = '4'
- policy['MaxBatchSize'] = '4'
- policy['PauseTime'] = 'PT0S'
- config = updt_template['Resources']['JobServerConfig']
- config['Properties']['InstanceType'] = self.conf.instance_type
-
- self.update_instance_group(updt_template,
- num_updates_expected_on_updt=2,
- num_creates_expected_on_updt=3,
- num_deletes_expected_on_updt=3,
- update_replace=False)
diff --git a/heat_tempest_plugin/tests/functional/test_nested_get_attr.py b/heat_tempest_plugin/tests/functional/test_nested_get_attr.py
deleted file mode 100644
index 57f65e2..0000000
--- a/heat_tempest_plugin/tests/functional/test_nested_get_attr.py
+++ /dev/null
@@ -1,165 +0,0 @@
-# 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.
-
-# Using nested get_attr functions isn't a good idea - in particular, this
-# actually working depends on correct dependencies between the two resources
-# whose attributes are being fetched, and these dependencies are non-local to
-# where the get_attr calls are used. Nevertheless, it did sort-of work, and
-# this test will help keep it that way.
-
-from heat_tempest_plugin.tests.functional import functional_base
-
-
-initial_template = '''
-heat_template_version: ocata
-resources:
- dict_resource:
- type: OS::Heat::Value
- properties:
- value:
- blarg: wibble
- foo: bar
- baz: quux
- fred: barney
- # These dependencies are required because we only want to read the
- # attribute values for a given resource once, and therefore we do so in
- # dependency order. This is necessarily true for a convergence traversal,
- # but also happens when we're fetching the resource attributes e.g. to show
- # the output values. The key1/key2 attribute values must be stored before
- # we attempt to calculate the dep_attrs for dict_resource in order to
- # correctly determine which attributes of dict_resource are used.
- depends_on:
- - key1
- - key2
- - indirect_key3_dep
- key1:
- type: OS::Heat::Value
- properties:
- value: blarg
- key2:
- type: OS::Heat::Value
- properties:
- value: foo
- key3:
- type: OS::Heat::Value
- properties:
- value: fred
- value1:
- type: OS::Heat::Value
- properties:
- value:
- get_attr:
- - dict_resource
- - value
- - {get_attr: [key1, value]}
- indirect_key3_dep:
- type: OS::Heat::Value
- properties:
- value: ignored
- depends_on: key3
-outputs:
- value1:
- value: {get_attr: [value1, value]}
- value2:
- value: {get_attr: [dict_resource, value, {get_attr: [key2, value]}]}
- value3:
- value: {get_attr: [dict_resource, value, {get_attr: [key3, value]}]}
-'''
-
-update_template = '''
-heat_template_version: ocata
-resources:
- dict_resource:
- type: OS::Heat::Value
- properties:
- value:
- blarg: wibble
- foo: bar
- baz: quux
- fred: barney
- depends_on:
- - key1
- - key2
- - indirect_key3_dep
- - key4
- key1:
- type: OS::Heat::Value
- properties:
- value: foo
- key2:
- type: OS::Heat::Value
- properties:
- value: fred
- key3:
- type: OS::Heat::Value
- properties:
- value: blarg
- key4:
- type: OS::Heat::Value
- properties:
- value: baz
- value1:
- type: OS::Heat::Value
- properties:
- value:
- get_attr:
- - dict_resource
- - value
- - {get_attr: [key1, value]}
- value4:
- type: OS::Heat::Value
- properties:
- value:
- get_attr:
- - dict_resource
- - value
- - {get_attr: [key4, value]}
- indirect_key3_dep:
- type: OS::Heat::Value
- properties:
- value: ignored
- depends_on: key3
-outputs:
- value1:
- value: {get_attr: [value1, value]}
- value2:
- value: {get_attr: [dict_resource, value, {get_attr: [key2, value]}]}
- value3:
- value: {get_attr: [dict_resource, value, {get_attr: [key3, value]}]}
- value4:
- value: {get_attr: [value4, value]}
-'''
-
-
-class NestedGetAttrTest(functional_base.FunctionalTestsBase):
- def assertOutput(self, value, stack_identifier, key):
- op = self.client.stacks.output_show(stack_identifier, key)['output']
- self.assertEqual(key, op['output_key'])
- if 'output_error' in op:
- raise Exception(op['output_error'])
- self.assertEqual(value, op['output_value'])
-
- def test_nested_get_attr_create(self):
- stack_identifier = self.stack_create(template=initial_template)
-
- self.assertOutput('wibble', stack_identifier, 'value1')
- self.assertOutput('bar', stack_identifier, 'value2')
- self.assertOutput('barney', stack_identifier, 'value3')
-
- def test_nested_get_attr_update(self):
- stack_identifier = self.stack_create(template=initial_template)
- self.update_stack(stack_identifier, template=update_template)
-
- self.assertOutput('bar', stack_identifier, 'value1')
- self.assertOutput('barney', stack_identifier, 'value2')
- self.assertOutput('wibble', stack_identifier, 'value3')
- self.assertOutput('quux', stack_identifier, 'value4')
diff --git a/heat_tempest_plugin/tests/functional/test_notifications.py b/heat_tempest_plugin/tests/functional/test_notifications.py
deleted file mode 100644
index 7a74cdb..0000000
--- a/heat_tempest_plugin/tests/functional/test_notifications.py
+++ /dev/null
@@ -1,194 +0,0 @@
-# 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 kombu
-from oslo_config import cfg
-from oslo_messaging._drivers import common
-from oslo_messaging import transport
-import requests
-
-from heat_tempest_plugin.common import test
-from heat_tempest_plugin.tests.functional import functional_base
-
-BASIC_NOTIFICATIONS = [
- 'orchestration.stack.create.start',
- 'orchestration.stack.create.end',
- 'orchestration.stack.update.start',
- 'orchestration.stack.update.end',
- 'orchestration.stack.suspend.start',
- 'orchestration.stack.suspend.end',
- 'orchestration.stack.resume.start',
- 'orchestration.stack.resume.end',
- 'orchestration.stack.delete.start',
- 'orchestration.stack.delete.end'
-]
-
-ASG_NOTIFICATIONS = [
- 'orchestration.autoscaling.start',
- 'orchestration.autoscaling.end'
-]
-
-
-def get_url(conf):
- conf = conf.oslo_messaging_rabbit
- return 'amqp://%s:%s@%s:%s/' % (conf.rabbit_userid,
- conf.rabbit_password,
- conf.rabbit_host,
- conf.rabbit_port)
-
-
-class NotificationHandler(object):
- def __init__(self, stack_id, events=None):
- self._notifications = []
- self.stack_id = stack_id
- self.events = events
-
- def process_message(self, body, message):
- notification = common.deserialize_msg(body)
- if notification['payload']['stack_name'] == self.stack_id:
- if self.events is not None:
- if notification['event_type'] in self.events:
- self.notifications.append(notification['event_type'])
- else:
- self.notifications.append(notification['event_type'])
- message.ack()
-
- def clear(self):
- self._notifications = []
-
- @property
- def notifications(self):
- return self._notifications
-
-
-class NotificationTest(functional_base.FunctionalTestsBase):
-
- basic_template = '''
-heat_template_version: 2013-05-23
-resources:
- random1:
- type: OS::Heat::RandomString
-'''
- update_basic_template = '''
-heat_template_version: 2013-05-23
-resources:
- random1:
- type: OS::Heat::RandomString
- random2:
- type: OS::Heat::RandomString
-'''
-
- asg_template = '''
-heat_template_version: 2013-05-23
-resources:
- asg:
- type: OS::Heat::AutoScalingGroup
- properties:
- resource:
- type: OS::Heat::RandomString
- min_size: 1
- desired_capacity: 2
- max_size: 3
-
- scale_up_policy:
- type: OS::Heat::ScalingPolicy
- properties:
- adjustment_type: change_in_capacity
- auto_scaling_group_id: {get_resource: asg}
- cooldown: 0
- scaling_adjustment: 1
-
- scale_down_policy:
- type: OS::Heat::ScalingPolicy
- properties:
- adjustment_type: change_in_capacity
- auto_scaling_group_id: {get_resource: asg}
- cooldown: 0
- scaling_adjustment: '-1'
-
-outputs:
- scale_up_url:
- value: {get_attr: [scale_up_policy, alarm_url]}
- scale_dn_url:
- value: {get_attr: [scale_down_policy, alarm_url]}
-'''
-
- def setUp(self):
- super(NotificationTest, self).setUp()
- self.exchange = kombu.Exchange('heat', 'topic', durable=False)
- queue = kombu.Queue(exchange=self.exchange,
- routing_key='notifications.info',
- exclusive=True)
- self.conn = kombu.Connection(get_url(
- transport.get_transport(cfg.CONF).conf))
- self.ch = self.conn.channel()
- self.queue = queue(self.ch)
- self.queue.declare()
-
- def consume_events(self, handler, count):
- self.conn.drain_events()
- return len(handler.notifications) == count
-
- def test_basic_notifications(self):
- # disable cleanup so we can call _stack_delete() directly.
- stack_identifier = self.stack_create(template=self.basic_template,
- enable_cleanup=False)
- self.update_stack(stack_identifier,
- template=self.update_basic_template)
- self.stack_suspend(stack_identifier)
- self.stack_resume(stack_identifier)
- self._stack_delete(stack_identifier)
-
- handler = NotificationHandler(stack_identifier.split('/')[0])
-
- with self.conn.Consumer(self.queue,
- callbacks=[handler.process_message],
- auto_declare=False):
- try:
- while True:
- self.conn.drain_events(timeout=1)
- except Exception:
- pass
-
- for n in BASIC_NOTIFICATIONS:
- self.assertIn(n, handler.notifications)
-
- def test_asg_notifications(self):
- stack_identifier = self.stack_create(template=self.asg_template)
-
- for output in self.client.stacks.get(stack_identifier).outputs:
- if output['output_key'] == 'scale_dn_url':
- scale_down_url = output['output_value']
- else:
- scale_up_url = output['output_value']
-
- notifications = []
- handler = NotificationHandler(stack_identifier.split('/')[0],
- ASG_NOTIFICATIONS)
-
- with self.conn.Consumer(self.queue,
- callbacks=[handler.process_message],
- auto_declare=False):
-
- requests.post(scale_up_url, verify=self.verify_cert)
- self.assertTrue(
- test.call_until_true(20, 0, self.consume_events, handler, 2))
- notifications += handler.notifications
-
- handler.clear()
- requests.post(scale_down_url, verify=self.verify_cert)
- self.assertTrue(
- test.call_until_true(20, 0, self.consume_events, handler, 2))
- notifications += handler.notifications
-
- self.assertEqual(2, notifications.count(ASG_NOTIFICATIONS[0]))
- self.assertEqual(2, notifications.count(ASG_NOTIFICATIONS[1]))
diff --git a/heat_tempest_plugin/tests/functional/test_nova_server_networks.py b/heat_tempest_plugin/tests/functional/test_nova_server_networks.py
index c0baeb4..9ab4eb1 100644
--- a/heat_tempest_plugin/tests/functional/test_nova_server_networks.py
+++ b/heat_tempest_plugin/tests/functional/test_nova_server_networks.py
@@ -90,6 +90,82 @@
- port: {get_resource: port}
'''
+server_with_multiple_subnets_no_ports_template = '''
+heat_template_version: 2016-04-08
+description: Test template to test nova server network updates.
+parameters:
+ flavor:
+ type: string
+ image:
+ type: string
+resources:
+ net:
+ type: OS::Neutron::Net
+ properties:
+ name: the_net
+ subnet_a:
+ type: OS::Neutron::Subnet
+ properties:
+ network: {get_resource: net}
+ cidr: 11.11.11.0/24
+ name: subnet_a
+ subnet_b:
+ type: OS::Neutron::Subnet
+ properties:
+ network: {get_resource: net}
+ cidr: 12.12.12.0/24
+ name: subnet_b
+ server:
+ type: OS::Nova::Server
+ properties:
+ image: {get_param: image}
+ flavor: {get_param: flavor}
+ networks: $NETWORKS
+outputs:
+ networks:
+ value: {get_attr: [server, networks]}
+'''
+
+server_with_no_nets_template = '''
+heat_template_version: 2016-04-08
+description: Test template to test nova server network updates.
+parameters:
+ flavor:
+ type: string
+ image:
+ type: string
+resources:
+ net:
+ type: OS::Neutron::Net
+ properties:
+ name: the_net
+ subnet:
+ type: OS::Neutron::Subnet
+ properties:
+ name: the_subnet
+ network: {get_resource: net}
+ cidr: 11.11.11.0/24
+ server:
+ type: OS::Nova::Server
+ properties:
+ image: {get_param: image}
+ flavor: {get_param: flavor}
+ networks: $NETWORKS
+outputs:
+ port0_id:
+ value: {get_attr: [server, addresses, the_net, 0, port]}
+ port1_id:
+ value: {get_attr: [server, addresses, the_net, 1, port]}
+ port2_id:
+ value: {get_attr: [server, addresses, the_net, 2, port]}
+ port0_ip_addr:
+ value: {get_attr: [server, addresses, the_net, 0, addr]}
+ port1_ip_addr:
+ value: {get_attr: [server, addresses, the_net, 1, addr]}
+ port2_ip_addr:
+ value: {get_attr: [server, addresses, the_net, 2, addr]}
+'''
+
class CreateServerTest(functional_base.FunctionalTestsBase):
@@ -117,26 +193,25 @@
def test_create_update_server_with_subnet(self):
parms = {'flavor': self.conf.minimal_instance_type,
'image': self.conf.minimal_image_ref}
- template = server_with_sub_fixed_ip_template.replace(
- 'fixed_ip: 11.11.11.11',
- 'fixed_ip: 11.11.11.22').replace(
- 'name: my_net', 'name: your_net')
+ template = server_with_multiple_subnets_no_ports_template.replace(
+ '$NETWORKS', ('[{subnet: {get_resource: subnet_a}}]'))
stack_identifier = self.stack_create(
template=template,
stack_name='create_server_with_sub_ip',
parameters=parms)
networks = self.get_outputs(stack_identifier, 'networks')
- self.assertEqual(['11.11.11.22'], networks['your_net'])
+ self.assertIn('11.11.11', networks['the_net'][0])
- # update the server only with subnet, we won't pass
+ # update the server using a different subnet, we won't pass
# both port_id and net_id to attach interface, then update success
- template_only_subnet = template.replace(
- 'fixed_ip: 11.11.11.22', '')
+ template = server_with_multiple_subnets_no_ports_template.replace(
+ '$NETWORKS', ('[{subnet: {get_resource: subnet_b}}]'))
self.update_stack(stack_identifier,
- template_only_subnet,
+ template,
parameters=parms)
new_networks = self.get_outputs(stack_identifier, 'networks')
- self.assertNotEqual(['11.11.11.22'], new_networks['your_net'])
+ self.assertNotIn('11.11.11', new_networks['the_net'][0])
+ self.assertIn('12.12.12', new_networks['the_net'][0])
def test_create_server_with_port(self):
parms = {'flavor': self.conf.minimal_instance_type,
@@ -147,3 +222,205 @@
template=server_with_port_template,
stack_name='server_with_port',
parameters=parms)
+
+
+class UpdateServerNetworksTest(functional_base.FunctionalTestsBase):
+ def setUp(self):
+ super(UpdateServerNetworksTest, self).setUp()
+ self.params = {'flavor': self.conf.minimal_instance_type,
+ 'image': self.conf.minimal_image_ref}
+
+ def get_outputs(self, stack_identifier, output_key):
+ stack = self.client.stacks.get(stack_identifier)
+ return self._stack_output(stack, output_key)
+
+ def test_create_update_server_swap_network_subnet(self):
+ '''Test updating stack with:
+
+ old_snippet
+ networks:
+ - network: {get_resource: net}
+ new_snippet
+ networks:
+ - subnet: {get_resource: subnet}
+ '''
+ template = server_with_no_nets_template.replace(
+ '$NETWORKS', '[{network: {get_resource: net}}]')
+ stack_identifier = self.stack_create(
+ template=template,
+ stack_name='swap_network_subnet',
+ parameters=self.params)
+ port0 = self.get_outputs(stack_identifier, 'port0_id')
+ template_update = server_with_no_nets_template.replace(
+ '$NETWORKS', '[{subnet: {get_resource: subnet}}]')
+ self.update_stack(stack_identifier, template_update,
+ parameters=self.params)
+ self.assertEqual(port0, self.get_outputs(stack_identifier, 'port0_id'))
+
+ def test_create_update_server_swap_network_port(self):
+ '''Test updating stack with:
+
+ old_snippet
+ networks:
+ - network: {get_resource: net}
+ new_snippet
+ networks:
+ - port: <the_port_created_on_stack_create>
+ '''
+ template = server_with_no_nets_template.replace(
+ '$NETWORKS', '[{network: {get_resource: net}}]')
+ stack_identifier = self.stack_create(
+ template=template,
+ stack_name='swap_network_port',
+ parameters=self.params)
+ port0 = self.get_outputs(stack_identifier, 'port0_id')
+ template_update = server_with_no_nets_template.replace(
+ '$NETWORKS', '[{port: ' + port0 + '}]')
+ self.update_stack(stack_identifier, template_update,
+ parameters=self.params)
+ self.assertEqual(port0, self.get_outputs(stack_identifier, 'port0_id'))
+
+ def test_create_update_server_swap_subnet_network(self):
+ '''Test updating stack with:
+
+ old_snippet
+ networks:
+ - subnet: {get_resource: subnet}
+ new_snippet
+ networks:
+ - network: {get_resource: net}
+ '''
+ template = server_with_no_nets_template.replace(
+ '$NETWORKS', '[{subnet: {get_resource: subnet}}]')
+ stack_identifier = self.stack_create(
+ template=template,
+ stack_name='swap_subnet_network',
+ parameters=self.params)
+ port0 = self.get_outputs(stack_identifier, 'port0_id')
+ template_update = server_with_no_nets_template.replace(
+ '$NETWORKS', '[{network: {get_resource: net}}]')
+ self.update_stack(stack_identifier, template_update,
+ parameters=self.params)
+ self.assertEqual(port0, self.get_outputs(stack_identifier, 'port0_id'))
+
+ def test_create_update_server_add_subnet(self):
+ '''Test updating stack with:
+
+ old_snippet
+ networks:
+ - network: {get_resource: net}
+ new_snippet
+ networks:
+ - network: {get_resource: net}
+ subnet: {get_resource: subnet}
+ '''
+ template = server_with_no_nets_template.replace(
+ '$NETWORKS', '[{network: {get_resource: net}}]')
+ stack_identifier = self.stack_create(
+ template=template,
+ stack_name='add_subnet',
+ parameters=self.params)
+ port0 = self.get_outputs(stack_identifier, 'port0_id')
+ template_update = server_with_no_nets_template.replace(
+ '$NETWORKS',
+ '[{network: {get_resource: net}, subnet: {get_resource: subnet}}]')
+ self.update_stack(stack_identifier, template_update,
+ parameters=self.params)
+ self.assertEqual(port0, self.get_outputs(stack_identifier, 'port0_id'))
+
+ def test_create_update_server_add_same_fixed_ip(self):
+ '''Test updating stack with:
+
+ old_snippet
+ networks:
+ - network: {get_resource: net}
+ new_snippet
+ networks:
+ - network: {get_resource: net}
+ fixed_ip: <the_same_ip_already_allocated>
+ '''
+ template = server_with_no_nets_template.replace(
+ '$NETWORKS',
+ '[{network: {get_resource: net}}]')
+ stack_identifier = self.stack_create(
+ template=template,
+ stack_name='same_fixed_ip',
+ parameters=self.params)
+ port0 = self.get_outputs(stack_identifier, 'port0_id')
+ port0_ip = self.get_outputs(stack_identifier, 'port0_ip_addr')
+ template_update = server_with_no_nets_template.replace(
+ '$NETWORKS',
+ '[{network: {get_resource: net}, fixed_ip: ' + port0_ip + '}]')
+ self.update_stack(stack_identifier, template_update,
+ parameters=self.params)
+ self.assertEqual(port0, self.get_outputs(stack_identifier, 'port0_id'))
+
+ def test_create_update_server_add_network(self):
+ '''Test updating stack with:
+
+ old_snippet
+ networks:
+ - subnet: {get_resource: subnet}
+ new_snippet
+ networks:
+ - network: {get_resource: net}
+ subnet: {get_resource: subnet}
+ '''
+ template = server_with_no_nets_template.replace(
+ '$NETWORKS', '[{subnet: {get_resource: subnet}}]')
+ stack_identifier = self.stack_create(
+ template=template,
+ stack_name='add_network',
+ parameters=self.params)
+ port0 = self.get_outputs(stack_identifier, 'port0_id')
+ template_update = server_with_no_nets_template.replace(
+ '$NETWORKS',
+ '[{network: {get_resource: net}, subnet: {get_resource: subnet}}]')
+ self.update_stack(stack_identifier, template_update,
+ parameters=self.params)
+ self.assertEqual(port0, self.get_outputs(stack_identifier, 'port0_id'))
+
+ def test_create_update_server_multi_networks_swaps(self):
+ '''Test updating stack with:
+
+ old_snippet:
+ networks:
+ - network: {get_resource: net}
+ - network: {get_resource: net}
+ fixed_ip: 11.11.11.33
+ - subnet: {get_resource: subnet}
+ new_snippet:
+ networks:
+ - subnet: {get_resource: subnet}
+ - network: {get_resource: net}
+ - network: {get_resource: net}
+ subnet: {get_resource: subnet}
+ '''
+ old_snippet = """
+ - network: {get_resource: net}
+ - network: {get_resource: net}
+ fixed_ip: 11.11.11.33
+ - subnet: {get_resource: subnet}
+"""
+ new_snippet = """
+ - subnet: {get_resource: subnet}
+ - network: {get_resource: net}
+ - network: {get_resource: net}
+ subnet: {get_resource: subnet}
+"""
+ template = server_with_no_nets_template.replace(
+ '$NETWORKS', old_snippet)
+ stack_identifier = self.stack_create(
+ template=template,
+ stack_name='multi_networks_swaps',
+ parameters=self.params)
+ port0 = self.get_outputs(stack_identifier, 'port0_id')
+ port1 = self.get_outputs(stack_identifier, 'port1_id')
+ port2 = self.get_outputs(stack_identifier, 'port2_id')
+ template_update = server_with_no_nets_template.replace(
+ '$NETWORKS', new_snippet)
+ self.update_stack(stack_identifier, template_update,
+ parameters=self.params)
+ self.assertEqual(port0, self.get_outputs(stack_identifier, 'port0_id'))
+ self.assertEqual(port1, self.get_outputs(stack_identifier, 'port1_id'))
+ self.assertEqual(port2, self.get_outputs(stack_identifier, 'port2_id'))
diff --git a/heat_tempest_plugin/tests/functional/test_preview_update.py b/heat_tempest_plugin/tests/functional/test_preview_update.py
deleted file mode 100644
index a4d293f..0000000
--- a/heat_tempest_plugin/tests/functional/test_preview_update.py
+++ /dev/null
@@ -1,298 +0,0 @@
-# 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.
-
-from heat_tempest_plugin.tests.functional import functional_base
-
-test_template_one_resource = {
- 'heat_template_version': '2013-05-23',
- 'description': 'Test template to create one instance.',
- 'resources': {
- 'test1': {
- 'type': 'OS::Heat::TestResource',
- 'properties': {
- 'value': 'Test1',
- 'fail': False,
- 'update_replace': False,
- 'wait_secs': 0
- }
- }
- }
-}
-
-test_template_two_resource = {
- 'heat_template_version': '2013-05-23',
- 'description': 'Test template to create two instance.',
- 'resources': {
- 'test1': {
- 'type': 'OS::Heat::TestResource',
- 'properties': {
- 'value': 'Test1',
- 'fail': False,
- 'update_replace': False,
- 'wait_secs': 0
- }
- },
- 'test2': {
- 'type': 'OS::Heat::TestResource',
- 'properties': {
- 'value': 'Test1',
- 'fail': False,
- 'update_replace': False,
- 'wait_secs': 0
- }
- }
- }
-}
-
-
-class UpdatePreviewBase(functional_base.FunctionalTestsBase):
-
- def assert_empty_sections(self, changes, empty_sections):
- for section in empty_sections:
- self.assertEqual([], changes[section])
-
-
-class UpdatePreviewStackTest(UpdatePreviewBase):
-
- def test_add_resource(self):
- self.stack_identifier = self.stack_create(
- template=test_template_one_resource)
- result = self.preview_update_stack(self.stack_identifier,
- test_template_two_resource)
- changes = result['resource_changes']
-
- unchanged = changes['unchanged'][0]['resource_name']
- self.assertEqual('test1', unchanged)
-
- added = changes['added'][0]['resource_name']
- self.assertEqual('test2', added)
-
- self.assert_empty_sections(changes, ['updated', 'replaced', 'deleted'])
-
- def test_no_change(self):
- self.stack_identifier = self.stack_create(
- template=test_template_one_resource)
- result = self.preview_update_stack(self.stack_identifier,
- test_template_one_resource)
- changes = result['resource_changes']
-
- unchanged = changes['unchanged'][0]['resource_name']
- self.assertEqual('test1', unchanged)
-
- self.assert_empty_sections(
- changes, ['updated', 'replaced', 'deleted', 'added'])
-
- def test_update_resource(self):
- self.stack_identifier = self.stack_create(
- template=test_template_one_resource)
- test_template_updated_resource = {
- 'heat_template_version': '2013-05-23',
- 'description': 'Test template to create one instance.',
- 'resources': {
- 'test1': {
- 'type': 'OS::Heat::TestResource',
- 'properties': {
- 'value': 'Test1 foo',
- 'fail': False,
- 'update_replace': False,
- 'wait_secs': 0
- }
- }
- }
- }
-
- result = self.preview_update_stack(self.stack_identifier,
- test_template_updated_resource)
- changes = result['resource_changes']
-
- updated = changes['updated'][0]['resource_name']
- self.assertEqual('test1', updated)
-
- self.assert_empty_sections(
- changes, ['added', 'unchanged', 'replaced', 'deleted'])
-
- def test_replaced_resource(self):
- self.stack_identifier = self.stack_create(
- template=test_template_one_resource)
- new_template = {
- 'heat_template_version': '2013-05-23',
- 'description': 'Test template to create one instance.',
- 'resources': {
- 'test1': {
- 'type': 'OS::Heat::TestResource',
- 'properties': {
- 'update_replace': True,
- }
- }
- }
- }
-
- result = self.preview_update_stack(self.stack_identifier, new_template)
- changes = result['resource_changes']
-
- replaced = changes['replaced'][0]['resource_name']
- self.assertEqual('test1', replaced)
-
- self.assert_empty_sections(
- changes, ['added', 'unchanged', 'updated', 'deleted'])
-
- def test_delete_resource(self):
- self.stack_identifier = self.stack_create(
- template=test_template_two_resource)
- result = self.preview_update_stack(self.stack_identifier,
- test_template_one_resource)
- changes = result['resource_changes']
-
- unchanged = changes['unchanged'][0]['resource_name']
- self.assertEqual('test1', unchanged)
-
- deleted = changes['deleted'][0]['resource_name']
- self.assertEqual('test2', deleted)
-
- self.assert_empty_sections(changes, ['updated', 'replaced', 'added'])
-
-
-class UpdatePreviewStackTestNested(UpdatePreviewBase):
- template_nested_parent = '''
-heat_template_version: 2016-04-08
-resources:
- nested1:
- type: nested1.yaml
-'''
-
- template_nested1 = '''
-heat_template_version: 2016-04-08
-resources:
- nested2:
- type: nested2.yaml
-'''
-
- template_nested2 = '''
-heat_template_version: 2016-04-08
-resources:
- random:
- type: OS::Heat::RandomString
-'''
-
- template_nested2_2 = '''
-heat_template_version: 2016-04-08
-resources:
- random:
- type: OS::Heat::RandomString
- random2:
- type: OS::Heat::RandomString
-'''
-
- def _get_by_resource_name(self, changes, name, action):
- filtered_l = [x for x in changes[action]
- if x['resource_name'] == name]
- self.assertEqual(1, len(filtered_l))
- return filtered_l[0]
-
- def test_nested_resources_nochange(self):
- files = {'nested1.yaml': self.template_nested1,
- 'nested2.yaml': self.template_nested2}
- self.stack_identifier = self.stack_create(
- template=self.template_nested_parent, files=files)
- result = self.preview_update_stack(
- self.stack_identifier,
- template=self.template_nested_parent,
- files=files, show_nested=True)
- changes = result['resource_changes']
-
- # The nested random resource should be unchanged, but we always
- # update nested stacks even when there are no changes
- self.assertEqual(1, len(changes['unchanged']))
- self.assertEqual('random', changes['unchanged'][0]['resource_name'])
- self.assertEqual('nested2', changes['unchanged'][0]['parent_resource'])
-
- self.assertEqual(2, len(changes['updated']))
- u_nested1 = self._get_by_resource_name(changes, 'nested1', 'updated')
- self.assertNotIn('parent_resource', u_nested1)
- u_nested2 = self._get_by_resource_name(changes, 'nested2', 'updated')
- self.assertEqual('nested1', u_nested2['parent_resource'])
-
- self.assert_empty_sections(changes, ['replaced', 'deleted', 'added'])
-
- def test_nested_resources_add(self):
- files = {'nested1.yaml': self.template_nested1,
- 'nested2.yaml': self.template_nested2}
- self.stack_identifier = self.stack_create(
- template=self.template_nested_parent, files=files)
- files['nested2.yaml'] = self.template_nested2_2
- result = self.preview_update_stack(
- self.stack_identifier,
- template=self.template_nested_parent,
- files=files, show_nested=True)
- changes = result['resource_changes']
-
- # The nested random resource should be unchanged, but we always
- # update nested stacks even when there are no changes
- self.assertEqual(1, len(changes['unchanged']))
- self.assertEqual('random', changes['unchanged'][0]['resource_name'])
- self.assertEqual('nested2', changes['unchanged'][0]['parent_resource'])
-
- self.assertEqual(1, len(changes['added']))
- self.assertEqual('random2', changes['added'][0]['resource_name'])
- self.assertEqual('nested2', changes['added'][0]['parent_resource'])
-
- self.assert_empty_sections(changes, ['replaced', 'deleted'])
-
- def test_nested_resources_delete(self):
- files = {'nested1.yaml': self.template_nested1,
- 'nested2.yaml': self.template_nested2_2}
- self.stack_identifier = self.stack_create(
- template=self.template_nested_parent, files=files)
- files['nested2.yaml'] = self.template_nested2
- result = self.preview_update_stack(
- self.stack_identifier,
- template=self.template_nested_parent,
- files=files, show_nested=True)
- changes = result['resource_changes']
-
- # The nested random resource should be unchanged, but we always
- # update nested stacks even when there are no changes
- self.assertEqual(1, len(changes['unchanged']))
- self.assertEqual('random', changes['unchanged'][0]['resource_name'])
- self.assertEqual('nested2', changes['unchanged'][0]['parent_resource'])
-
- self.assertEqual(1, len(changes['deleted']))
- self.assertEqual('random2', changes['deleted'][0]['resource_name'])
- self.assertEqual('nested2', changes['deleted'][0]['parent_resource'])
-
- self.assert_empty_sections(changes, ['replaced', 'added'])
-
- def test_nested_resources_replace(self):
- files = {'nested1.yaml': self.template_nested1,
- 'nested2.yaml': self.template_nested2}
- self.stack_identifier = self.stack_create(
- template=self.template_nested_parent, files=files)
- parent_none = self.template_nested_parent.replace(
- 'nested1.yaml', 'OS::Heat::None')
- result = self.preview_update_stack(
- self.stack_identifier,
- template=parent_none,
- show_nested=True)
- changes = result['resource_changes']
-
- # The nested random resource should be unchanged, but we always
- # update nested stacks even when there are no changes
- self.assertEqual(1, len(changes['replaced']))
- self.assertEqual('nested1', changes['replaced'][0]['resource_name'])
-
- self.assertEqual(2, len(changes['deleted']))
- d_random = self._get_by_resource_name(changes, 'random', 'deleted')
- self.assertEqual('nested2', d_random['parent_resource'])
- d_nested2 = self._get_by_resource_name(changes, 'nested2', 'deleted')
- self.assertEqual('nested1', d_nested2['parent_resource'])
-
- self.assert_empty_sections(changes, ['updated', 'unchanged', 'added'])
diff --git a/heat_tempest_plugin/tests/functional/test_purge.py b/heat_tempest_plugin/tests/functional/test_purge.py
deleted file mode 100644
index 1dd4ff8..0000000
--- a/heat_tempest_plugin/tests/functional/test_purge.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# 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 time
-
-from oslo_concurrency import processutils
-
-from heat_tempest_plugin.tests.functional import functional_base
-
-
-class PurgeTest(functional_base.FunctionalTestsBase):
- template = '''
-heat_template_version: 2014-10-16
-parameters:
-resources:
- test_resource:
- type: OS::Heat::TestResource
-'''
-
- def test_purge(self):
- stack_identifier = self.stack_create(template=self.template)
- self._stack_delete(stack_identifier)
- stacks = dict((stack.id, stack) for stack in
- self.client.stacks.list(show_deleted=True))
- self.assertIn(stack_identifier.split('/')[1], stacks)
- time.sleep(1)
- cmd = "heat-manage purge_deleted 0"
- processutils.execute(cmd, shell=True)
- stacks = dict((stack.id, stack) for stack in
- self.client.stacks.list(show_deleted=True))
- self.assertNotIn(stack_identifier.split('/')[1], stacks)
-
- # Test with tags
- stack_identifier = self.stack_create(template=self.template,
- tags="foo,bar")
- self._stack_delete(stack_identifier)
- time.sleep(1)
- cmd = "heat-manage purge_deleted 0"
- processutils.execute(cmd, shell=True)
- stacks = dict((stack.id, stack) for stack in
- self.client.stacks.list(show_deleted=True))
- self.assertNotIn(stack_identifier.split('/')[1], stacks)
diff --git a/heat_tempest_plugin/tests/functional/test_reload_on_sighup.py b/heat_tempest_plugin/tests/functional/test_reload_on_sighup.py
deleted file mode 100644
index 81da958..0000000
--- a/heat_tempest_plugin/tests/functional/test_reload_on_sighup.py
+++ /dev/null
@@ -1,142 +0,0 @@
-# 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 re
-import subprocess
-import time
-
-import eventlet
-
-from oslo_concurrency import processutils
-from six.moves import configparser
-
-from heat_tempest_plugin.tests.functional import functional_base
-
-
-class ReloadOnSighupTest(functional_base.FunctionalTestsBase):
-
- def setUp(self):
- self.config_file = "/etc/heat/heat.conf"
- super(ReloadOnSighupTest, self).setUp()
-
- def _is_mod_wsgi_daemon(self, service):
- process = ''.join(['wsgi:',
- service[:9]]).replace('_', '-').encode('utf-8')
- s = subprocess.Popen(["ps", "ax"], stdout=subprocess.PIPE)
- for x in s.stdout:
- if re.search(process, x):
- return True
-
- def _set_config_value(self, service, key, value):
- config = configparser.ConfigParser()
-
- # NOTE(prazumovsky): If there are several workers, there can be
- # situation, when one thread opens self.config_file for writing
- # (so config_file erases with opening), in that moment other thread
- # intercepts to this file and try to set config option value, i.e.
- # write to file, which is already erased by first thread, so,
- # NoSectionError raised. So, should wait until first thread writes to
- # config_file.
- retries_count = self.conf.sighup_config_edit_retries
- while True:
- config.read(self.config_file)
- try:
- config.set(service, key, str(value))
- except configparser.NoSectionError:
- if retries_count <= 0:
- raise
- retries_count -= 1
- eventlet.sleep(1)
- else:
- break
-
- with open(self.config_file, 'w') as f:
- config.write(f)
-
- def _get_config_value(self, service, key):
- config = configparser.ConfigParser()
- config.read(self.config_file)
- val = config.get(service, key)
- return val
-
- def _get_heat_api_pids(self, service):
- # get the pids of all heat-api processes
- if service == "heat_api":
- process = "heat-api|grep -Ev 'grep|cloudwatch|cfn'"
- else:
- process = "%s|grep -Ev 'grep'" % service.replace('_', '-')
- cmd = "ps -ef|grep %s|awk '{print $2}'" % process
- out, err = processutils.execute(cmd, shell=True)
- self.assertIsNotNone(out, "heat-api service not running. %s" % err)
- pids = filter(None, out.split('\n'))
-
- # get the parent pids of all heat-api processes
- cmd = "ps -ef|grep %s|awk '{print $3}'" % process
- out, _ = processutils.execute(cmd, shell=True)
- parent_pids = filter(None, out.split('\n'))
-
- heat_api_parent = list(set(pids) & set(parent_pids))[0]
- heat_api_children = list(set(pids) - set(parent_pids))
-
- return heat_api_parent, heat_api_children
-
- def _change_config(self, service, old_workers, new_workers):
- pre_reload_parent, pre_reload_children = self._get_heat_api_pids(
- service)
- self.assertEqual(old_workers, len(pre_reload_children))
-
- # change the config values
- self._set_config_value(service, 'workers', new_workers)
- cmd = "kill -HUP %s" % pre_reload_parent
- processutils.execute(cmd, shell=True)
-
- # wait till heat-api reloads
- start_time = time.time()
- while time.time() - start_time < self.conf.sighup_timeout:
- post_reload_parent, post_reload_children = self._get_heat_api_pids(
- service)
- intersect = set(post_reload_children) & set(pre_reload_children)
- if (new_workers == len(post_reload_children)
- and pre_reload_parent == post_reload_parent
- and intersect == set()):
- break
- eventlet.sleep(1)
- self.assertEqual(pre_reload_parent, post_reload_parent)
- self.assertEqual(new_workers, len(post_reload_children))
- # test if all child processes are newly created
- self.assertEqual(set(post_reload_children) & set(pre_reload_children),
- set())
-
- def _reload(self, service):
- old_workers = int(self._get_config_value(service, 'workers'))
- new_workers = old_workers + 1
- self.addCleanup(self._set_config_value, service, 'workers',
- old_workers)
-
- self._change_config(service, old_workers, new_workers)
- # revert all the changes made
- self._change_config(service, new_workers, old_workers)
-
- def _reload_on_sighup(self, service):
- if not self._is_mod_wsgi_daemon(service):
- self._reload(service)
- else:
- self.skipTest('Skipping Test, Service running under httpd.')
-
- def test_api_reload_on_sighup(self):
- self._reload_on_sighup('heat_api')
-
- def test_api_cfn_reload_on_sighup(self):
- self._reload_on_sighup('heat_api_cfn')
-
- def test_api_cloudwatch_on_sighup(self):
- self._reload_on_sighup('heat_api_cloudwatch')
diff --git a/heat_tempest_plugin/tests/functional/test_replace_deprecated.py b/heat_tempest_plugin/tests/functional/test_replace_deprecated.py
deleted file mode 100644
index 0eee3f1..0000000
--- a/heat_tempest_plugin/tests/functional/test_replace_deprecated.py
+++ /dev/null
@@ -1,92 +0,0 @@
-# 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 yaml
-
-from heat_tempest_plugin.tests.functional import functional_base
-
-
-class ReplaceDeprecatedResourceTest(functional_base.FunctionalTestsBase):
- template = '''
-heat_template_version: "2013-05-23"
-parameters:
- flavor:
- type: string
- image:
- type: string
- network:
- type: string
-
-resources:
- config:
- type: OS::Heat::SoftwareConfig
- properties:
- config: xxxx
-
- server:
- type: OS::Nova::Server
- properties:
- image: {get_param: image}
- flavor: {get_param: flavor}
- networks: [{network: {get_param: network} }]
- user_data_format: SOFTWARE_CONFIG
- dep:
- type: OS::Heat::SoftwareDeployments
- properties:
- config: {get_resource: config}
- servers: {'0': {get_resource: server}}
- signal_transport: NO_SIGNAL
-outputs:
- server:
- value: {get_resource: server}
-'''
-
- deployment_group_snippet = '''
-type: OS::Heat::SoftwareDeploymentGroup
-properties:
- config: {get_resource: config}
- servers: {'0': {get_resource: server}}
- signal_transport: NO_SIGNAL
-'''
- enable_cleanup = True
-
- def test_replace_software_deployments(self):
- parms = {'flavor': self.conf.minimal_instance_type,
- 'network': self.conf.fixed_network_name,
- 'image': self.conf.minimal_image_ref
- }
- deployments_template = yaml.safe_load(self.template)
- stack_identifier = self.stack_create(
- parameters=parms,
- template=deployments_template,
- enable_cleanup=self.enable_cleanup)
- expected_resources = {'config': 'OS::Heat::SoftwareConfig',
- 'dep': 'OS::Heat::SoftwareDeployments',
- 'server': 'OS::Nova::Server'}
- resource = self.client.resources.get(stack_identifier, 'server')
- self.assertEqual(expected_resources,
- self.list_resources(stack_identifier))
- initial_phy_id = resource.physical_resource_id
- resources = deployments_template['resources']
- resources['dep'] = yaml.safe_load(self.deployment_group_snippet)
- self.update_stack(
- stack_identifier,
- deployments_template,
- parameters=parms)
- resource = self.client.resources.get(stack_identifier, 'server')
- self.assertEqual(initial_phy_id,
- resource.physical_resource_id)
- expected_new_resources = {'config': 'OS::Heat::SoftwareConfig',
- 'dep': 'OS::Heat::SoftwareDeploymentGroup',
- 'server': 'OS::Nova::Server'}
- self.assertEqual(expected_new_resources,
- self.list_resources(stack_identifier))
diff --git a/heat_tempest_plugin/tests/functional/test_resource_chain.py b/heat_tempest_plugin/tests/functional/test_resource_chain.py
deleted file mode 100644
index 06ec8ff..0000000
--- a/heat_tempest_plugin/tests/functional/test_resource_chain.py
+++ /dev/null
@@ -1,167 +0,0 @@
-#
-# 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.
-
-from heat_tempest_plugin.tests.functional import functional_base
-
-
-TEMPLATE_SIMPLE = '''
-heat_template_version: 2016-04-08
-parameters:
- string-length:
- type: number
-resources:
- my-chain:
- type: OS::Heat::ResourceChain
- properties:
- resources: ['OS::Heat::RandomString', 'OS::Heat::RandomString']
- resource_properties:
- length: { get_param: string-length }
-outputs:
- resource-ids:
- value: { get_attr: [my-chain, refs] }
- resource-0-value:
- value: { get_attr: [my-chain, resource.0, value] }
- all-resource-attrs:
- value: { get_attr: [my-chain, attributes, value] }
-'''
-
-TEMPLATE_PARAM_DRIVEN = '''
-heat_template_version: 2016-04-08
-parameters:
- chain-types:
- type: comma_delimited_list
-resources:
- my-chain:
- type: OS::Heat::ResourceChain
- properties:
- resources: { get_param: chain-types }
-'''
-
-
-class ResourceChainTests(functional_base.FunctionalTestsBase):
-
- def test_create(self):
- # Test
- params = {'string-length': 8}
- stack_id = self.stack_create(template=TEMPLATE_SIMPLE,
- parameters=params)
-
- # Verify
- stack = self.client.stacks.get(stack_id)
- self.assertIsNotNone(stack)
-
- # Top-level resource for chain
- expected = {'my-chain': 'OS::Heat::ResourceChain'}
- found = self.list_resources(stack_id)
- self.assertEqual(expected, found)
-
- # Nested stack exists and has two resources
- nested_id = self.group_nested_identifier(stack_id, 'my-chain')
- expected = {'0': 'OS::Heat::RandomString',
- '1': 'OS::Heat::RandomString'}
- found = self.list_resources(nested_id)
- self.assertEqual(expected, found)
-
- # Outputs
- resource_ids = self._stack_output(stack, 'resource-ids')
- self.assertIsNotNone(resource_ids)
- self.assertEqual(2, len(resource_ids))
-
- resource_value = self._stack_output(stack, 'resource-0-value')
- self.assertIsNotNone(resource_value)
- self.assertEqual(8, len(resource_value)) # from parameter
-
- resource_attrs = self._stack_output(stack, 'all-resource-attrs')
- self.assertIsNotNone(resource_attrs)
- self.assertIsInstance(resource_attrs, dict)
- self.assertEqual(2, len(resource_attrs))
- self.assertEqual(8, len(resource_attrs['0']))
- self.assertEqual(8, len(resource_attrs['1']))
-
- def test_update(self):
- # Setup
- params = {'string-length': 8}
- stack_id = self.stack_create(template=TEMPLATE_SIMPLE,
- parameters=params)
-
- update_tmpl = '''
- heat_template_version: 2016-04-08
- parameters:
- string-length:
- type: number
- resources:
- my-chain:
- type: OS::Heat::ResourceChain
- properties:
- resources: ['OS::Heat::None']
- '''
-
- # Test
- self.update_stack(stack_id, template=update_tmpl, parameters=params)
-
- # Verify
- # Nested stack only has the None resource
- nested_id = self.group_nested_identifier(stack_id, 'my-chain')
- expected = {'0': 'OS::Heat::None'}
- found = self.list_resources(nested_id)
- self.assertEqual(expected, found)
-
- def test_update_resources(self):
- params = {'chain-types': 'OS::Heat::None'}
-
- stack_id = self.stack_create(template=TEMPLATE_PARAM_DRIVEN,
- parameters=params)
-
- nested_id = self.group_nested_identifier(stack_id, 'my-chain')
- expected = {'0': 'OS::Heat::None'}
- found = self.list_resources(nested_id)
- self.assertEqual(expected, found)
-
- params = {'chain-types': 'OS::Heat::None,OS::Heat::None'}
- self.update_stack(stack_id, template=TEMPLATE_PARAM_DRIVEN,
- parameters=params)
-
- expected = {'0': 'OS::Heat::None', '1': 'OS::Heat::None'}
- found = self.list_resources(nested_id)
- self.assertEqual(expected, found)
-
- def test_resources_param_driven(self):
- # Setup
- params = {'chain-types':
- 'OS::Heat::None,OS::Heat::RandomString,OS::Heat::None'}
-
- # Test
- stack_id = self.stack_create(template=TEMPLATE_PARAM_DRIVEN,
- parameters=params)
-
- # Verify
- nested_id = self.group_nested_identifier(stack_id, 'my-chain')
- expected = {'0': 'OS::Heat::None',
- '1': 'OS::Heat::RandomString',
- '2': 'OS::Heat::None'}
- found = self.list_resources(nested_id)
- self.assertEqual(expected, found)
-
- def test_resources_env_defined(self):
- # Setup
- env = {'parameters': {'chain-types': 'OS::Heat::None'}}
-
- # Test
- stack_id = self.stack_create(template=TEMPLATE_PARAM_DRIVEN,
- environment=env)
-
- # Verify
- nested_id = self.group_nested_identifier(stack_id, 'my-chain')
- expected = {'0': 'OS::Heat::None'}
- found = self.list_resources(nested_id)
- self.assertEqual(expected, found)
diff --git a/heat_tempest_plugin/tests/functional/test_resource_group.py b/heat_tempest_plugin/tests/functional/test_resource_group.py
deleted file mode 100644
index aea1bda..0000000
--- a/heat_tempest_plugin/tests/functional/test_resource_group.py
+++ /dev/null
@@ -1,695 +0,0 @@
-# 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 copy
-import json
-
-from heatclient import exc
-import six
-import yaml
-
-from heat_tempest_plugin.tests.functional import functional_base
-
-
-class ResourceGroupTest(functional_base.FunctionalTestsBase):
- template = '''
-heat_template_version: 2013-05-23
-resources:
- random_group:
- type: OS::Heat::ResourceGroup
- properties:
- count: 0
- resource_def:
- type: My::RandomString
- properties:
- length: 30
- salt: initial
-outputs:
- random1:
- value: {get_attr: [random_group, resource.0.value]}
- random2:
- value: {get_attr: [random_group, resource.1.value]}
- all_values:
- value: {get_attr: [random_group, value]}
-'''
-
- def test_resource_group_zero_novalidate(self):
- # Nested resources should be validated only when size > 0
- # This allows features to be disabled via size=0 without
- # triggering validation of nested resource custom constraints
- # e.g images etc in the nested schema.
- nested_template_fail = '''
-heat_template_version: 2013-05-23
-parameters:
- length:
- type: string
- default: 50
- salt:
- type: string
- default: initial
-resources:
- random:
- type: OS::Heat::RandomString
- properties:
- length: BAD
-'''
-
- files = {'provider.yaml': nested_template_fail}
- env = {'resource_registry':
- {'My::RandomString': 'provider.yaml'}}
- stack_identifier = self.stack_create(
- template=self.template,
- files=files,
- environment=env
- )
-
- self.assertEqual({u'random_group': u'OS::Heat::ResourceGroup'},
- self.list_resources(stack_identifier))
-
- # Check we created an empty nested stack
- nested_identifier = self.group_nested_identifier(stack_identifier,
- 'random_group')
- self.assertEqual({}, self.list_resources(nested_identifier))
-
- # Prove validation works for non-zero create/update
- template_two_nested = self.template.replace("count: 0", "count: 2")
- expected_err = ("resources.random_group<nested_stack>.resources."
- "0<provider.yaml>.resources.random: : "
- "Value 'BAD' is not an integer")
- ex = self.assertRaises(exc.HTTPBadRequest, self.update_stack,
- stack_identifier, template_two_nested,
- environment=env, files=files)
- self.assertIn(expected_err, six.text_type(ex))
-
- ex = self.assertRaises(exc.HTTPBadRequest, self.stack_create,
- template=template_two_nested,
- environment=env, files=files)
- self.assertIn(expected_err, six.text_type(ex))
-
- def _validate_resources(self, stack_identifier, expected_count):
- resources = self.list_group_resources(stack_identifier,
- 'random_group')
- self.assertEqual(expected_count, len(resources))
- expected_resources = dict(
- (str(idx), 'My::RandomString')
- for idx in range(expected_count))
-
- self.assertEqual(expected_resources, resources)
-
- def test_create(self):
- def validate_output(stack, output_key, length):
- output_value = self._stack_output(stack, output_key)
- self.assertEqual(length, len(output_value))
- return output_value
- # verify that the resources in resource group are identically
- # configured, resource names and outputs are appropriate.
- env = {'resource_registry':
- {'My::RandomString': 'OS::Heat::RandomString'}}
- create_template = self.template.replace("count: 0", "count: 2")
- stack_identifier = self.stack_create(template=create_template,
- environment=env)
- self.assertEqual({u'random_group': u'OS::Heat::ResourceGroup'},
- self.list_resources(stack_identifier))
-
- # validate count, type and name of resources in a resource group.
- self._validate_resources(stack_identifier, 2)
-
- # validate outputs
- stack = self.client.stacks.get(stack_identifier)
- outputs = []
- outputs.append(validate_output(stack, 'random1', 30))
- outputs.append(validate_output(stack, 'random2', 30))
- self.assertEqual(outputs, self._stack_output(stack, 'all_values'))
-
- def test_update_increase_decrease_count(self):
- # create stack with resource group count 2
- env = {'resource_registry':
- {'My::RandomString': 'OS::Heat::RandomString'}}
- create_template = self.template.replace("count: 0", "count: 2")
- stack_identifier = self.stack_create(template=create_template,
- environment=env)
- self.assertEqual({u'random_group': u'OS::Heat::ResourceGroup'},
- self.list_resources(stack_identifier))
- # verify that the resource group has 2 resources
- self._validate_resources(stack_identifier, 2)
-
- # increase the resource group count to 5
- update_template = self.template.replace("count: 0", "count: 5")
- self.update_stack(stack_identifier, update_template, environment=env)
- # verify that the resource group has 5 resources
- self._validate_resources(stack_identifier, 5)
-
- # decrease the resource group count to 3
- update_template = self.template.replace("count: 0", "count: 3")
- self.update_stack(stack_identifier, update_template, environment=env)
- # verify that the resource group has 3 resources
- self._validate_resources(stack_identifier, 3)
-
- def test_update_removal_policies(self):
- rp_template = '''
-heat_template_version: 2014-10-16
-resources:
- random_group:
- type: OS::Heat::ResourceGroup
- properties:
- count: 5
- removal_policies: []
- resource_def:
- type: OS::Heat::RandomString
-'''
-
- # create stack with resource group, initial count 5
- stack_identifier = self.stack_create(template=rp_template)
- self.assertEqual({u'random_group': u'OS::Heat::ResourceGroup'},
- self.list_resources(stack_identifier))
- group_resources = self.list_group_resources(stack_identifier,
- 'random_group')
- expected_resources = {u'0': u'OS::Heat::RandomString',
- u'1': u'OS::Heat::RandomString',
- u'2': u'OS::Heat::RandomString',
- u'3': u'OS::Heat::RandomString',
- u'4': u'OS::Heat::RandomString'}
- self.assertEqual(expected_resources, group_resources)
-
- # Remove three, specifying the middle resources to be removed
- update_template = rp_template.replace(
- 'removal_policies: []',
- 'removal_policies: [{resource_list: [\'1\', \'2\', \'3\']}]')
- self.update_stack(stack_identifier, update_template)
- group_resources = self.list_group_resources(stack_identifier,
- 'random_group')
- expected_resources = {u'0': u'OS::Heat::RandomString',
- u'4': u'OS::Heat::RandomString',
- u'5': u'OS::Heat::RandomString',
- u'6': u'OS::Heat::RandomString',
- u'7': u'OS::Heat::RandomString'}
- self.assertEqual(expected_resources, group_resources)
-
- def test_props_update(self):
- """Test update of resource_def properties behaves as expected."""
-
- env = {'resource_registry':
- {'My::RandomString': 'OS::Heat::RandomString'}}
- template_one = self.template.replace("count: 0", "count: 1")
- stack_identifier = self.stack_create(template=template_one,
- environment=env)
- self.assertEqual({u'random_group': u'OS::Heat::ResourceGroup'},
- self.list_resources(stack_identifier))
-
- initial_nested_ident = self.group_nested_identifier(stack_identifier,
- 'random_group')
- self.assertEqual({'0': 'My::RandomString'},
- self.list_resources(initial_nested_ident))
- # get the resource id
- res = self.client.resources.get(initial_nested_ident, '0')
- initial_res_id = res.physical_resource_id
-
- # change the salt (this should replace the RandomString but
- # not the nested stack or resource group.
- template_salt = template_one.replace("salt: initial", "salt: more")
- self.update_stack(stack_identifier, template_salt, environment=env)
- updated_nested_ident = self.group_nested_identifier(stack_identifier,
- 'random_group')
- self.assertEqual(initial_nested_ident, updated_nested_ident)
-
- # compare the resource id, we expect a change.
- res = self.client.resources.get(updated_nested_ident, '0')
- updated_res_id = res.physical_resource_id
- self.assertNotEqual(initial_res_id, updated_res_id)
-
- def test_update_nochange(self):
- """Test update with no properties change."""
-
- env = {'resource_registry':
- {'My::RandomString': 'OS::Heat::RandomString'}}
- template_one = self.template.replace("count: 0", "count: 2")
- stack_identifier = self.stack_create(template=template_one,
- environment=env)
- self.assertEqual({u'random_group': u'OS::Heat::ResourceGroup'},
- self.list_resources(stack_identifier))
-
- initial_nested_ident = self.group_nested_identifier(stack_identifier,
- 'random_group')
- self.assertEqual({'0': 'My::RandomString', '1': 'My::RandomString'},
- self.list_resources(initial_nested_ident))
- # get the output
- stack0 = self.client.stacks.get(stack_identifier)
- initial_rand = self._stack_output(stack0, 'random1')
-
- template_copy = copy.deepcopy(template_one)
- self.update_stack(stack_identifier, template_copy, environment=env)
- updated_nested_ident = self.group_nested_identifier(stack_identifier,
- 'random_group')
- self.assertEqual(initial_nested_ident, updated_nested_ident)
-
- # compare the random number, we expect no change.
- stack1 = self.client.stacks.get(stack_identifier)
- updated_rand = self._stack_output(stack1, 'random1')
- self.assertEqual(initial_rand, updated_rand)
-
- def test_update_nochange_resource_needs_update(self):
- """Test update when the resource definition has changed.
-
- Test the scenario when the ResourceGroup update happens without
- any changed properties, this can happen if the definition of
- a contained provider resource changes (files map changes), then
- the group and underlying nested stack should end up updated.
- """
-
- random_templ1 = '''
-heat_template_version: 2013-05-23
-parameters:
- length:
- type: string
- default: not-used
- salt:
- type: string
- default: not-used
-resources:
- random1:
- type: OS::Heat::RandomString
- properties:
- salt: initial
-outputs:
- value:
- value: {get_attr: [random1, value]}
-'''
- files1 = {'my_random.yaml': random_templ1}
-
- random_templ2 = random_templ1.replace('salt: initial',
- 'salt: more')
- files2 = {'my_random.yaml': random_templ2}
-
- env = {'resource_registry':
- {'My::RandomString': 'my_random.yaml'}}
-
- template_one = self.template.replace("count: 0", "count: 2")
- stack_identifier = self.stack_create(template=template_one,
- environment=env,
- files=files1)
- self.assertEqual({u'random_group': u'OS::Heat::ResourceGroup'},
- self.list_resources(stack_identifier))
- self.assertEqual(files1, self.client.stacks.files(stack_identifier))
-
- initial_nested_ident = self.group_nested_identifier(stack_identifier,
- 'random_group')
- self.assertEqual({'0': 'My::RandomString', '1': 'My::RandomString'},
- self.list_resources(initial_nested_ident))
- # get the output
- stack0 = self.client.stacks.get(stack_identifier)
- initial_rand = self._stack_output(stack0, 'random1')
-
- # change the environment so we use a different TemplateResource.
- # note "files2".
- self.update_stack(stack_identifier, template_one,
- environment=env, files=files2)
- updated_nested_ident = self.group_nested_identifier(stack_identifier,
- 'random_group')
- self.assertEqual(initial_nested_ident, updated_nested_ident)
- self.assertEqual(files2, self.client.stacks.files(stack_identifier))
-
- # compare the output, we expect a change.
- stack1 = self.client.stacks.get(stack_identifier)
- updated_rand = self._stack_output(stack1, 'random1')
- self.assertNotEqual(initial_rand, updated_rand)
-
-
-class ResourceGroupTestNullParams(functional_base.FunctionalTestsBase):
- template = '''
-heat_template_version: 2013-05-23
-parameters:
- param:
- type: empty
-resources:
- random_group:
- type: OS::Heat::ResourceGroup
- properties:
- count: 1
- resource_def:
- type: My::RandomString
- properties:
- param: {get_param: param}
-outputs:
- val:
- value: {get_attr: [random_group, val]}
-'''
-
- nested_template_file = '''
-heat_template_version: 2013-05-23
-parameters:
- param:
- type: empty
-outputs:
- val:
- value: {get_param: param}
-'''
-
- scenarios = [
- ('string_empty', dict(
- param='',
- p_type='string',
- )),
- ('boolean_false', dict(
- param=False,
- p_type='boolean',
- )),
- ('number_zero', dict(
- param=0,
- p_type='number',
- )),
- ('comma_delimited_list', dict(
- param=[],
- p_type='comma_delimited_list',
- )),
- ('json_empty', dict(
- param={},
- p_type='json',
- )),
- ]
-
- def test_create_pass_zero_parameter(self):
- templ = self.template.replace('type: empty',
- 'type: %s' % self.p_type)
- n_t_f = self.nested_template_file.replace('type: empty',
- 'type: %s' % self.p_type)
- files = {'provider.yaml': n_t_f}
- env = {'resource_registry':
- {'My::RandomString': 'provider.yaml'}}
- stack_identifier = self.stack_create(
- template=templ,
- files=files,
- environment=env,
- parameters={'param': self.param}
- )
- stack = self.client.stacks.get(stack_identifier)
- self.assertEqual(self.param, self._stack_output(stack, 'val')[0])
-
-
-class ResourceGroupAdoptTest(functional_base.FunctionalTestsBase):
- """Prove that we can do resource group adopt."""
-
- main_template = '''
-heat_template_version: "2013-05-23"
-resources:
- group1:
- type: OS::Heat::ResourceGroup
- properties:
- count: 2
- resource_def:
- type: OS::Heat::RandomString
-outputs:
- test0:
- value: {get_attr: [group1, resource.0.value]}
- test1:
- value: {get_attr: [group1, resource.1.value]}
-'''
-
- def _yaml_to_json(self, yaml_templ):
- return yaml.safe_load(yaml_templ)
-
- def test_adopt(self):
- data = {
- "resources": {
- "group1": {
- "status": "COMPLETE",
- "name": "group1",
- "resource_data": {},
- "metadata": {},
- "resource_id": "test-group1-id",
- "action": "CREATE",
- "type": "OS::Heat::ResourceGroup",
- "resources": {
- "0": {
- "status": "COMPLETE",
- "name": "0",
- "resource_data": {"value": "goopie"},
- "resource_id": "ID-0",
- "action": "CREATE",
- "type": "OS::Heat::RandomString",
- "metadata": {}
- },
- "1": {
- "status": "COMPLETE",
- "name": "1",
- "resource_data": {"value": "different"},
- "resource_id": "ID-1",
- "action": "CREATE",
- "type": "OS::Heat::RandomString",
- "metadata": {}
- }
- }
- }
- },
- "environment": {"parameters": {}},
- "template": yaml.safe_load(self.main_template)
- }
- stack_identifier = self.stack_adopt(
- adopt_data=json.dumps(data))
-
- self.assert_resource_is_a_stack(stack_identifier, 'group1')
- stack = self.client.stacks.get(stack_identifier)
- self.assertEqual('goopie', self._stack_output(stack, 'test0'))
- self.assertEqual('different', self._stack_output(stack, 'test1'))
-
-
-class ResourceGroupErrorResourceTest(functional_base.FunctionalTestsBase):
- template = '''
-heat_template_version: "2013-05-23"
-resources:
- group1:
- type: OS::Heat::ResourceGroup
- properties:
- count: 2
- resource_def:
- type: fail.yaml
-'''
- nested_templ = '''
-heat_template_version: "2013-05-23"
-resources:
- oops:
- type: OS::Heat::TestResource
- properties:
- fail: true
- wait_secs: 2
-'''
-
- def test_fail(self):
- stack_identifier = self.stack_create(
- template=self.template,
- files={'fail.yaml': self.nested_templ},
- expected_status='CREATE_FAILED',
- enable_cleanup=False)
- stack = self.client.stacks.get(stack_identifier)
-
- self.assertEqual('CREATE_FAILED', stack.stack_status)
- self.client.stacks.delete(stack_identifier)
- self._wait_for_stack_status(
- stack_identifier, 'DELETE_COMPLETE',
- success_on_not_found=True)
-
-
-class ResourceGroupUpdatePolicyTest(functional_base.FunctionalTestsBase):
-
- template = '''
-heat_template_version: '2015-04-30'
-resources:
- random_group:
- type: OS::Heat::ResourceGroup
- update_policy:
- rolling_update:
- min_in_service: 1
- max_batch_size: 2
- pause_time: 1
- properties:
- count: 10
- resource_def:
- type: OS::Heat::TestResource
- properties:
- value: initial
- update_replace: False
-'''
-
- def update_resource_group(self, update_template,
- updated, created, deleted):
- stack_identifier = self.stack_create(template=self.template)
- group_resources = self.list_group_resources(stack_identifier,
- 'random_group',
- minimal=False)
-
- init_names = [res.physical_resource_id for res in group_resources]
-
- self.update_stack(stack_identifier, update_template)
- group_resources = self.list_group_resources(stack_identifier,
- 'random_group',
- minimal=False)
-
- updt_names = [res.physical_resource_id for res in group_resources]
-
- matched_names = set(updt_names) & set(init_names)
-
- self.assertEqual(updated, len(matched_names))
-
- self.assertEqual(created, len(set(updt_names) - set(init_names)))
-
- self.assertEqual(deleted, len(set(init_names) - set(updt_names)))
-
- def test_resource_group_update(self):
- """Test rolling update with no conflict.
-
- Simple rolling update with no conflict in batch size
- and minimum instances in service.
- """
- updt_template = yaml.safe_load(copy.deepcopy(self.template))
- grp = updt_template['resources']['random_group']
- policy = grp['update_policy']['rolling_update']
- policy['min_in_service'] = '1'
- policy['max_batch_size'] = '3'
- res_def = grp['properties']['resource_def']
- res_def['properties']['value'] = 'updated'
-
- self.update_resource_group(updt_template,
- updated=10,
- created=0,
- deleted=0)
-
- def test_resource_group_update_replace(self):
- """Test rolling update(replace)with no conflict.
-
- Simple rolling update replace with no conflict in batch size
- and minimum instances in service.
- """
- updt_template = yaml.safe_load(copy.deepcopy(self.template))
- grp = updt_template['resources']['random_group']
- policy = grp['update_policy']['rolling_update']
- policy['min_in_service'] = '1'
- policy['max_batch_size'] = '3'
- res_def = grp['properties']['resource_def']
- res_def['properties']['value'] = 'updated'
- res_def['properties']['update_replace'] = True
-
- self.update_resource_group(updt_template,
- updated=0,
- created=10,
- deleted=10)
-
- def test_resource_group_update_scaledown(self):
- """Test rolling update with scaledown.
-
- Simple rolling update with reduced size.
- """
- updt_template = yaml.safe_load(copy.deepcopy(self.template))
- grp = updt_template['resources']['random_group']
- policy = grp['update_policy']['rolling_update']
- policy['min_in_service'] = '1'
- policy['max_batch_size'] = '3'
- grp['properties']['count'] = 6
- res_def = grp['properties']['resource_def']
- res_def['properties']['value'] = 'updated'
-
- self.update_resource_group(updt_template,
- updated=6,
- created=0,
- deleted=4)
-
- def test_resource_group_update_scaleup(self):
- """Test rolling update with scaleup.
-
- Simple rolling update with increased size.
- """
- updt_template = yaml.safe_load(copy.deepcopy(self.template))
- grp = updt_template['resources']['random_group']
- policy = grp['update_policy']['rolling_update']
- policy['min_in_service'] = '1'
- policy['max_batch_size'] = '3'
- grp['properties']['count'] = 12
- res_def = grp['properties']['resource_def']
- res_def['properties']['value'] = 'updated'
-
- self.update_resource_group(updt_template,
- updated=10,
- created=2,
- deleted=0)
-
- def test_resource_group_update_adjusted(self):
- """Test rolling update with enough available resources
-
- Update with capacity adjustment with enough resources.
- """
- updt_template = yaml.safe_load(copy.deepcopy(self.template))
- grp = updt_template['resources']['random_group']
- policy = grp['update_policy']['rolling_update']
- policy['min_in_service'] = '8'
- policy['max_batch_size'] = '4'
- grp['properties']['count'] = 6
- res_def = grp['properties']['resource_def']
- res_def['properties']['value'] = 'updated'
-
- self.update_resource_group(updt_template,
- updated=6,
- created=0,
- deleted=4)
-
- def test_resource_group_update_with_adjusted_capacity(self):
- """Test rolling update with capacity adjustment.
-
- Rolling update with capacity adjustment due to conflict in
- batch size and minimum instances in service.
- """
- updt_template = yaml.safe_load(copy.deepcopy(self.template))
- grp = updt_template['resources']['random_group']
- policy = grp['update_policy']['rolling_update']
- policy['min_in_service'] = '8'
- policy['max_batch_size'] = '4'
- res_def = grp['properties']['resource_def']
- res_def['properties']['value'] = 'updated'
-
- self.update_resource_group(updt_template,
- updated=10,
- created=0,
- deleted=0)
-
- def test_resource_group_update_huge_batch_size(self):
- """Test rolling update with huge batch size.
-
- Rolling Update with a huge batch size(more than
- current size).
- """
- updt_template = yaml.safe_load(copy.deepcopy(self.template))
- grp = updt_template['resources']['random_group']
- policy = grp['update_policy']['rolling_update']
- policy['min_in_service'] = '0'
- policy['max_batch_size'] = '20'
- res_def = grp['properties']['resource_def']
- res_def['properties']['value'] = 'updated'
- self.update_resource_group(updt_template,
- updated=10,
- created=0,
- deleted=0)
-
- def test_resource_group_update_huge_min_in_service(self):
- """Test rolling update with huge minimum capacity.
-
- Rolling Update with a huge number of minimum instances
- in service.
- """
- updt_template = yaml.safe_load(copy.deepcopy(self.template))
- grp = updt_template['resources']['random_group']
- policy = grp['update_policy']['rolling_update']
- policy['min_in_service'] = '20'
- policy['max_batch_size'] = '1'
- res_def = grp['properties']['resource_def']
- res_def['properties']['value'] = 'updated'
-
- self.update_resource_group(updt_template,
- updated=10,
- created=0,
- deleted=0)
diff --git a/heat_tempest_plugin/tests/functional/test_simultaneous_update.py b/heat_tempest_plugin/tests/functional/test_simultaneous_update.py
deleted file mode 100644
index 3cfbeaa..0000000
--- a/heat_tempest_plugin/tests/functional/test_simultaneous_update.py
+++ /dev/null
@@ -1,93 +0,0 @@
-# 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 copy
-import time
-
-from heat_tempest_plugin.common import test
-from heat_tempest_plugin.tests.functional import functional_base
-
-_test_template = {
- 'heat_template_version': 'pike',
- 'description': 'Test template to create two resources.',
- 'resources': {
- 'test1': {
- 'type': 'OS::Heat::TestResource',
- 'properties': {
- 'value': 'Test1',
- 'fail': False,
- 'update_replace': False,
- 'wait_secs': 0,
- }
- },
- 'test2': {
- 'type': 'OS::Heat::TestResource',
- 'properties': {
- 'value': 'Test1',
- 'fail': False,
- 'update_replace': False,
- 'wait_secs': 0,
- 'action_wait_secs': {
- 'create': 30,
- }
- },
- 'depends_on': ['test1']
- }
- }
-}
-
-
-def get_templates(fail=False, delay_s=None):
- before = copy.deepcopy(_test_template)
-
- after = copy.deepcopy(before)
- for r in after['resources'].values():
- r['properties']['value'] = 'Test2'
-
- before_props = before['resources']['test2']['properties']
- before_props['fail'] = fail
- if delay_s is not None:
- before_props['action_wait_secs']['create'] = delay_s
-
- return before, after
-
-
-class SimultaneousUpdateStackTest(functional_base.FunctionalTestsBase):
-
- @test.requires_convergence
- def test_retrigger_success(self):
- before, after = get_templates()
- stack_id = self.stack_create(template=before,
- expected_status='CREATE_IN_PROGRESS')
- time.sleep(10)
-
- self.update_stack(stack_id, after)
-
- @test.requires_convergence
- def test_retrigger_failure(self):
- before, after = get_templates(fail=True)
- stack_id = self.stack_create(template=before,
- expected_status='CREATE_IN_PROGRESS')
- time.sleep(10)
-
- self.update_stack(stack_id, after)
-
- @test.requires_convergence
- def test_retrigger_timeout(self):
- before, after = get_templates(delay_s=70)
- stack_id = self.stack_create(template=before,
- expected_status='CREATE_IN_PROGRESS',
- timeout=1)
- time.sleep(50)
-
- self.update_stack(stack_id, after)
diff --git a/heat_tempest_plugin/tests/functional/test_snapshot_restore.py b/heat_tempest_plugin/tests/functional/test_snapshot_restore.py
deleted file mode 100644
index 3616c8f..0000000
--- a/heat_tempest_plugin/tests/functional/test_snapshot_restore.py
+++ /dev/null
@@ -1,76 +0,0 @@
-# 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.
-
-
-from heat_tempest_plugin.tests.functional import functional_base
-
-
-class StackSnapshotRestoreTest(functional_base.FunctionalTestsBase):
-
- def setUp(self):
- super(StackSnapshotRestoreTest, self).setUp()
- if not self.conf.minimal_image_ref:
- raise self.skipException("No image configured to test")
-
- if not self.conf.minimal_instance_type:
- raise self.skipException(
- "No minimal_instance_type configured to test")
-
- self.assign_keypair()
-
- def test_stack_snapshot_restore(self):
- template = '''
-heat_template_version: ocata
-parameters:
- keyname:
- type: string
- flavor:
- type: string
- image:
- type: string
- network:
- type: string
-resources:
- my_port:
- type: OS::Neutron::Port
- properties:
- network: {get_param: network}
- my_server:
- type: OS::Nova::Server
- properties:
- image: {get_param: image}
- flavor: {get_param: flavor}
- key_name: {get_param: keyname}
- networks: [{port: {get_resource: my_port} }]
-
-'''
-
- def get_server_image(server_id):
- server = self.compute_client.servers.get(server_id)
- return server.image['id']
-
- parameters = {'keyname': self.keypair_name,
- 'flavor': self.conf.minimal_instance_type,
- 'image': self.conf.minimal_image_ref,
- 'network': self.conf.fixed_network_name}
- stack_identifier = self.stack_create(template=template,
- parameters=parameters)
- server_resource = self.client.resources.get(
- stack_identifier, 'my_server')
- server_id = server_resource.physical_resource_id
- prev_image_id = get_server_image(server_id)
-
- # Do snapshot and restore
- snapshot_id = self.stack_snapshot(stack_identifier)
- self.stack_restore(stack_identifier, snapshot_id)
-
- self.assertNotEqual(prev_image_id, get_server_image(server_id))
diff --git a/heat_tempest_plugin/tests/functional/test_software_deployment_group.py b/heat_tempest_plugin/tests/functional/test_software_deployment_group.py
deleted file mode 100644
index a298419..0000000
--- a/heat_tempest_plugin/tests/functional/test_software_deployment_group.py
+++ /dev/null
@@ -1,150 +0,0 @@
-# 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.
-
-from heat_tempest_plugin.tests.functional import functional_base
-
-
-class SoftwareDeploymentGroupTest(functional_base.FunctionalTestsBase):
- sd_template = '''
-heat_template_version: 2016-10-14
-
-parameters:
- input:
- type: string
- default: foo_input
-
-resources:
- config:
- type: OS::Heat::SoftwareConfig
- properties:
- group: script
- inputs:
- - name: foo
-
- deployment:
- type: OS::Heat::SoftwareDeploymentGroup
- properties:
- config: {get_resource: config}
- input_values:
- foo: {get_param: input}
- servers:
- '0': dummy0
- '1': dummy1
- '2': dummy2
- '3': dummy3
-'''
-
- sd_template_with_upd_policy = '''
-heat_template_version: 2016-10-14
-
-parameters:
- input:
- type: string
- default: foo_input
-
-resources:
- config:
- type: OS::Heat::SoftwareConfig
- properties:
- group: script
- inputs:
- - name: foo
-
- deployment:
- type: OS::Heat::SoftwareDeploymentGroup
- update_policy:
- rolling_update:
- max_batch_size: 2
- pause_time: 1
- properties:
- config: {get_resource: config}
- input_values:
- foo: {get_param: input}
- servers:
- '0': dummy0
- '1': dummy1
- '2': dummy2
- '3': dummy3
-'''
- enable_cleanup = True
-
- def deployment_crud(self, template):
- stack_identifier = self.stack_create(
- template=template,
- enable_cleanup=self.enable_cleanup,
- expected_status='CREATE_IN_PROGRESS')
- self._wait_for_resource_status(
- stack_identifier, 'deployment', 'CREATE_IN_PROGRESS')
-
- # Wait for all deployment resources to become IN_PROGRESS, since only
- # IN_PROGRESS resources get signalled
- nested_identifier = self.assert_resource_is_a_stack(
- stack_identifier, 'deployment')
- self._wait_for_stack_status(nested_identifier, 'CREATE_IN_PROGRESS')
- self._wait_for_all_resource_status(nested_identifier,
- 'CREATE_IN_PROGRESS')
- group_resources = self.list_group_resources(
- stack_identifier, 'deployment', minimal=False)
-
- self.assertEqual(4, len(group_resources))
- self._wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE',
- signal_required=True,
- resources_to_signal=group_resources)
-
- created_group_resources = self.list_group_resources(
- stack_identifier, 'deployment', minimal=False)
- self.assertEqual(4, len(created_group_resources))
- self.check_input_values(created_group_resources, 'foo', 'foo_input')
-
- self.update_stack(stack_identifier,
- template=template,
- environment={'parameters': {'input': 'input2'}},
- expected_status='UPDATE_IN_PROGRESS')
- nested_identifier = self.assert_resource_is_a_stack(
- stack_identifier, 'deployment')
- self._wait_for_stack_status(stack_identifier, 'UPDATE_COMPLETE',
- signal_required=True,
- resources_to_signal=group_resources)
-
- self.check_input_values(created_group_resources, 'foo', 'input2')
-
- # We explicitly test delete here, vs just via cleanup and check
- # the nested stack is gone
- self._stack_delete(stack_identifier)
- self._wait_for_stack_status(
- nested_identifier, 'DELETE_COMPLETE',
- success_on_not_found=True)
-
- def test_deployment_crud(self):
- self.deployment_crud(self.sd_template)
-
- def test_deployment_crud_with_rolling_update(self):
- self.deployment_crud(self.sd_template_with_upd_policy)
-
- def test_deployments_create_delete_in_progress(self):
- stack_identifier = self.stack_create(
- template=self.sd_template,
- enable_cleanup=self.enable_cleanup,
- expected_status='CREATE_IN_PROGRESS')
- self._wait_for_resource_status(
- stack_identifier, 'deployment', 'CREATE_IN_PROGRESS')
- nested_identifier = self.assert_resource_is_a_stack(
- stack_identifier, 'deployment')
- group_resources = self.list_group_resources(
- stack_identifier, 'deployment', minimal=False)
-
- self.assertEqual(4, len(group_resources))
- # Now test delete while the stacks are still IN_PROGRESS
- self._stack_delete(stack_identifier)
- self._wait_for_stack_status(
- nested_identifier, 'DELETE_COMPLETE',
- success_on_not_found=True)
diff --git a/heat_tempest_plugin/tests/functional/test_stack_cancel.py b/heat_tempest_plugin/tests/functional/test_stack_cancel.py
deleted file mode 100644
index ba5e989..0000000
--- a/heat_tempest_plugin/tests/functional/test_stack_cancel.py
+++ /dev/null
@@ -1,92 +0,0 @@
-# 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 copy
-import eventlet
-
-from heat_tempest_plugin.common import test
-from heat_tempest_plugin.tests.functional import functional_base
-
-
-template = {
- 'heat_template_version': 'pike',
- 'resources': {
- 'test1': {
- 'type': 'OS::Heat::TestResource',
- 'properties': {
- 'value': 'Test1',
- 'action_wait_secs': {
- 'update': 30,
- }
- }
- },
- 'test2': {
- 'type': 'OS::Heat::TestResource',
- 'properties': {
- 'value': 'Test1',
- },
- 'depends_on': ['test1']
- },
- }
-}
-
-
-def get_templates(delay_s=None):
- before = copy.deepcopy(template)
- after = copy.deepcopy(before)
- for r in after['resources'].values():
- r['properties']['value'] = 'Test2'
-
- if delay_s:
- before_props = before['resources']['test1']['properties']
- before_props['action_wait_secs']['create'] = delay_s
- return before, after
-
-
-class StackCancelTest(functional_base.FunctionalTestsBase):
-
- def _test_cancel_update(self, rollback=True,
- expected_status='ROLLBACK_COMPLETE'):
- before, after = get_templates()
- stack_id = self.stack_create(template=before)
- self.update_stack(stack_id, template=after,
- expected_status='UPDATE_IN_PROGRESS')
- self._wait_for_resource_status(stack_id, 'test1', 'UPDATE_IN_PROGRESS')
- self.cancel_update_stack(stack_id, rollback, expected_status)
- return stack_id
-
- def test_cancel_update_with_rollback(self):
- self._test_cancel_update()
-
- def test_cancel_update_without_rollback(self):
- stack_id = self._test_cancel_update(rollback=False,
- expected_status='UPDATE_FAILED')
- self.assertTrue(test.call_until_true(
- 60, 2, self.verify_resource_status,
- stack_id, 'test1', 'UPDATE_COMPLETE'))
- eventlet.sleep(2)
- self.assertTrue(self.verify_resource_status(stack_id, 'test2',
- 'CREATE_COMPLETE'))
-
- def test_cancel_create_without_rollback(self):
- before, after = get_templates(delay_s=30)
- stack_id = self.stack_create(template=before,
- expected_status='CREATE_IN_PROGRESS')
- self._wait_for_resource_status(stack_id, 'test1', 'CREATE_IN_PROGRESS')
- self.cancel_update_stack(stack_id, rollback=False,
- expected_status='CREATE_FAILED')
- self.assertTrue(test.call_until_true(
- 60, 2, self.verify_resource_status,
- stack_id, 'test1', 'CREATE_COMPLETE'))
- eventlet.sleep(2)
- self.assertTrue(self.verify_resource_status(stack_id, 'test2',
- 'INIT_COMPLETE'))
diff --git a/heat_tempest_plugin/tests/functional/test_swiftsignal_update.py b/heat_tempest_plugin/tests/functional/test_swiftsignal_update.py
deleted file mode 100644
index 604e592..0000000
--- a/heat_tempest_plugin/tests/functional/test_swiftsignal_update.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# 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.
-
-
-from heat_tempest_plugin.tests.functional import functional_base
-
-test_template = '''
-heat_template_version: 2014-10-16
-
-resources:
- signal_handle:
- type: "OS::Heat::SwiftSignalHandle"
-
-outputs:
- signal_curl:
- value: { get_attr: ['signal_handle', 'curl_cli'] }
- description: Swift signal cURL
-
- signal_url:
- value: { get_attr: ['signal_handle', 'endpoint'] }
- description: Swift signal URL
-'''
-
-
-class SwiftSignalHandleUpdateTest(functional_base.FunctionalTestsBase):
-
- def test_stack_update_same_template_replace_no_url(self):
- if not self.is_service_available('object-store'):
- self.skipTest('object-store service not available, skipping')
- stack_identifier = self.stack_create(template=test_template)
- stack = self.client.stacks.get(stack_identifier)
- orig_url = self._stack_output(stack, 'signal_url')
- orig_curl = self._stack_output(stack, 'signal_curl')
- self.update_stack(stack_identifier, test_template)
- stack = self.client.stacks.get(stack_identifier)
- self.assertEqual(orig_url, self._stack_output(stack, 'signal_url'))
- self.assertEqual(orig_curl, self._stack_output(stack, 'signal_curl'))
diff --git a/heat_tempest_plugin/tests/functional/test_template_resource.py b/heat_tempest_plugin/tests/functional/test_template_resource.py
deleted file mode 100644
index a7cc808..0000000
--- a/heat_tempest_plugin/tests/functional/test_template_resource.py
+++ /dev/null
@@ -1,982 +0,0 @@
-# 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 json
-
-from heatclient import exc as heat_exceptions
-import six
-import yaml
-
-from heat_tempest_plugin.common import test
-from heat_tempest_plugin.tests.functional import functional_base
-
-
-class TemplateResourceTest(functional_base.FunctionalTestsBase):
- """Prove that we can use the registry in a nested provider."""
-
- template = '''
-heat_template_version: 2013-05-23
-resources:
- secret1:
- type: OS::Heat::RandomString
-outputs:
- secret-out:
- value: { get_attr: [secret1, value] }
-'''
- nested_templ = '''
-heat_template_version: 2013-05-23
-resources:
- secret2:
- type: OS::Heat::RandomString
-outputs:
- value:
- value: { get_attr: [secret2, value] }
-'''
-
- env_templ = '''
-resource_registry:
- "OS::Heat::RandomString": nested.yaml
-'''
-
- def test_nested_env(self):
- main_templ = '''
-heat_template_version: 2013-05-23
-resources:
- secret1:
- type: My::NestedSecret
-outputs:
- secret-out:
- value: { get_attr: [secret1, value] }
-'''
-
- nested_templ = '''
-heat_template_version: 2013-05-23
-resources:
- secret2:
- type: My::Secret
-outputs:
- value:
- value: { get_attr: [secret2, value] }
-'''
-
- env_templ = '''
-resource_registry:
- "My::Secret": "OS::Heat::RandomString"
- "My::NestedSecret": nested.yaml
-'''
-
- stack_identifier = self.stack_create(
- template=main_templ,
- files={'nested.yaml': nested_templ},
- environment=env_templ)
- 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):
- """Prove that we can override a python resource.
-
- And use that resource within the template resource.
- """
- stack_identifier = self.stack_create(
- template=self.template,
- files={'nested.yaml': self.nested_templ},
- environment=self.env_templ)
- self.assert_resource_is_a_stack(stack_identifier, 'secret1')
-
- def test_nested_stack_delete_then_delete_parent_stack(self):
- """Check the robustness of stack deletion.
-
- This tests that if you manually delete a nested
- stack, the parent stack is still deletable.
- """
- # disable cleanup so we can call _stack_delete() directly.
- stack_identifier = self.stack_create(
- template=self.template,
- files={'nested.yaml': self.nested_templ},
- environment=self.env_templ,
- enable_cleanup=False)
-
- nested_ident = self.assert_resource_is_a_stack(stack_identifier,
- 'secret1')
-
- self._stack_delete(nested_ident)
- self._stack_delete(stack_identifier)
-
- def test_change_in_file_path(self):
- stack_identifier = self.stack_create(
- template=self.template,
- files={'nested.yaml': self.nested_templ},
- environment=self.env_templ)
- stack = self.client.stacks.get(stack_identifier)
- secret_out1 = self._stack_output(stack, 'secret-out')
-
- nested_templ_2 = '''
-heat_template_version: 2013-05-23
-resources:
- secret2:
- type: OS::Heat::RandomString
-outputs:
- value:
- value: freddy
-'''
- env_templ_2 = '''
-resource_registry:
- "OS::Heat::RandomString": new/nested.yaml
-'''
- self.update_stack(stack_identifier,
- template=self.template,
- files={'new/nested.yaml': nested_templ_2},
- environment=env_templ_2)
- stack = self.client.stacks.get(stack_identifier)
- secret_out2 = self._stack_output(stack, 'secret-out')
- self.assertNotEqual(secret_out1, secret_out2)
- self.assertEqual('freddy', secret_out2)
-
-
-class NestedAttributesTest(functional_base.FunctionalTestsBase):
- """Prove that we can use the template resource references."""
-
- main_templ = '''
-heat_template_version: 2014-10-16
-resources:
- secret2:
- type: My::NestedSecret
-outputs:
- old_way:
- value: { get_attr: [secret2, nested_str]}
- test_attr1:
- value: { get_attr: [secret2, resource.secret1, value]}
- test_attr2:
- value: { get_attr: [secret2, resource.secret1.value]}
- test_ref:
- value: { get_resource: secret2 }
-'''
-
- env_templ = '''
-resource_registry:
- "My::NestedSecret": nested.yaml
-'''
-
- def test_stack_ref(self):
- nested_templ = '''
-heat_template_version: 2014-10-16
-resources:
- secret1:
- type: OS::Heat::RandomString
-outputs:
- nested_str:
- value: {get_attr: [secret1, value]}
-'''
- stack_identifier = self.stack_create(
- template=self.main_templ,
- files={'nested.yaml': nested_templ},
- environment=self.env_templ)
- self.assert_resource_is_a_stack(stack_identifier, 'secret2')
- stack = self.client.stacks.get(stack_identifier)
- test_ref = self._stack_output(stack, 'test_ref')
- self.assertIn('arn:openstack:heat:', test_ref)
-
- def test_transparent_ref(self):
- """Test using nested resource more transparently.
-
- With the addition of OS::stack_id we can now use the nested resource
- more transparently.
- """
-
- nested_templ = '''
-heat_template_version: 2014-10-16
-resources:
- secret1:
- type: OS::Heat::RandomString
-outputs:
- OS::stack_id:
- value: {get_resource: secret1}
- nested_str:
- value: {get_attr: [secret1, value]}
-'''
- stack_identifier = self.stack_create(
- template=self.main_templ,
- files={'nested.yaml': nested_templ},
- environment=self.env_templ)
- self.assert_resource_is_a_stack(stack_identifier, 'secret2')
- stack = self.client.stacks.get(stack_identifier)
- test_ref = self._stack_output(stack, 'test_ref')
- test_attr = self._stack_output(stack, 'old_way')
-
- self.assertNotIn('arn:openstack:heat', test_ref)
- self.assertEqual(test_attr, test_ref)
-
- def test_nested_attributes(self):
- nested_templ = '''
-heat_template_version: 2014-10-16
-resources:
- secret1:
- type: OS::Heat::RandomString
-outputs:
- nested_str:
- value: {get_attr: [secret1, value]}
-'''
- stack_identifier = self.stack_create(
- template=self.main_templ,
- files={'nested.yaml': nested_templ},
- environment=self.env_templ)
- self.assert_resource_is_a_stack(stack_identifier, 'secret2')
- stack = self.client.stacks.get(stack_identifier)
- old_way = self._stack_output(stack, 'old_way')
- test_attr1 = self._stack_output(stack, 'test_attr1')
- test_attr2 = self._stack_output(stack, 'test_attr2')
-
- self.assertEqual(old_way, test_attr1)
- self.assertEqual(old_way, test_attr2)
-
-
-class TemplateResourceFacadeTest(functional_base.FunctionalTestsBase):
- """Prove that we can use ResourceFacade in a HOT template."""
-
- main_template = '''
-heat_template_version: 2013-05-23
-resources:
- the_nested:
- type: the.yaml
- metadata:
- foo: bar
-outputs:
- value:
- value: {get_attr: [the_nested, output]}
-'''
-
- nested_templ = '''
-heat_template_version: 2013-05-23
-resources:
- test:
- type: OS::Heat::TestResource
- properties:
- value: {"Fn::Select": [foo, {resource_facade: metadata}]}
-outputs:
- output:
- value: {get_attr: [test, output]}
- '''
-
- def test_metadata(self):
- stack_identifier = self.stack_create(
- template=self.main_template,
- files={'the.yaml': self.nested_templ})
- stack = self.client.stacks.get(stack_identifier)
- value = self._stack_output(stack, 'value')
- self.assertEqual('bar', value)
-
-
-class TemplateResourceUpdateTest(functional_base.FunctionalTestsBase):
- """Prove that we can do template resource updates."""
-
- main_template = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Resources:
- the_nested:
- Type: the.yaml
- Properties:
- one: my_name
- two: your_name
-Outputs:
- identifier:
- Value: {Ref: the_nested}
- value:
- Value: {'Fn::GetAtt': [the_nested, the_str]}
-'''
-
- main_template_change_prop = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Resources:
- the_nested:
- Type: the.yaml
- Properties:
- one: updated_name
- two: your_name
-
-Outputs:
- identifier:
- Value: {Ref: the_nested}
- value:
- Value: {'Fn::GetAtt': [the_nested, the_str]}
-'''
-
- main_template_add_prop = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Resources:
- the_nested:
- Type: the.yaml
- Properties:
- one: my_name
- two: your_name
- three: third_name
-
-Outputs:
- identifier:
- Value: {Ref: the_nested}
- value:
- Value: {'Fn::GetAtt': [the_nested, the_str]}
-'''
-
- main_template_remove_prop = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Resources:
- the_nested:
- Type: the.yaml
- Properties:
- one: my_name
-
-Outputs:
- identifier:
- Value: {Ref: the_nested}
- value:
- Value: {'Fn::GetAtt': [the_nested, the_str]}
-'''
-
- initial_tmpl = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Parameters:
- one:
- Default: foo
- Type: String
- two:
- Default: bar
- Type: String
-
-Resources:
- NestedResource:
- Type: OS::Heat::RandomString
- Properties:
- salt: {Ref: one}
-Outputs:
- the_str:
- Value: {'Fn::GetAtt': [NestedResource, value]}
-'''
-
- prop_change_tmpl = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Parameters:
- one:
- Default: yikes
- Type: String
- two:
- Default: foo
- Type: String
-Resources:
- NestedResource:
- Type: OS::Heat::RandomString
- Properties:
- salt: {Ref: two}
-Outputs:
- the_str:
- Value: {'Fn::GetAtt': [NestedResource, value]}
-'''
-
- prop_add_tmpl = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Parameters:
- one:
- Default: yikes
- Type: String
- two:
- Default: foo
- Type: String
- three:
- Default: bar
- Type: String
-
-Resources:
- NestedResource:
- Type: OS::Heat::RandomString
- Properties:
- salt: {Ref: three}
-Outputs:
- the_str:
- Value: {'Fn::GetAtt': [NestedResource, value]}
-'''
-
- prop_remove_tmpl = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Parameters:
- one:
- Default: yikes
- Type: String
-
-Resources:
- NestedResource:
- Type: OS::Heat::RandomString
- Properties:
- salt: {Ref: one}
-Outputs:
- the_str:
- Value: {'Fn::GetAtt': [NestedResource, value]}
-'''
-
- attr_change_tmpl = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Parameters:
- one:
- Default: foo
- Type: String
- two:
- Default: bar
- Type: String
-
-Resources:
- NestedResource:
- Type: OS::Heat::RandomString
- Properties:
- salt: {Ref: one}
-Outputs:
- the_str:
- Value: {'Fn::GetAtt': [NestedResource, value]}
- something_else:
- Value: just_a_string
-'''
-
- content_change_tmpl = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Parameters:
- one:
- Default: foo
- Type: String
- two:
- Default: bar
- Type: String
-
-Resources:
- NestedResource:
- Type: OS::Heat::RandomString
- Properties:
- salt: yum
-Outputs:
- the_str:
- Value: {'Fn::GetAtt': [NestedResource, value]}
-'''
-
- EXPECTED = (UPDATE, NOCHANGE) = ('update', 'nochange')
- scenarios = [
- ('no_changes', dict(template=main_template,
- provider=initial_tmpl,
- expect=NOCHANGE)),
- ('main_tmpl_change', dict(template=main_template_change_prop,
- provider=initial_tmpl,
- expect=UPDATE)),
- ('provider_change', dict(template=main_template,
- provider=content_change_tmpl,
- expect=UPDATE)),
- ('provider_props_change', dict(template=main_template,
- provider=prop_change_tmpl,
- expect=UPDATE)),
- ('provider_props_add', dict(template=main_template_add_prop,
- provider=prop_add_tmpl,
- expect=UPDATE)),
- ('provider_props_remove', dict(template=main_template_remove_prop,
- provider=prop_remove_tmpl,
- expect=NOCHANGE)),
- ('provider_attr_change', dict(template=main_template,
- provider=attr_change_tmpl,
- expect=NOCHANGE)),
- ]
-
- def test_template_resource_update_template_schema(self):
- stack_identifier = self.stack_create(
- template=self.main_template,
- files={'the.yaml': self.initial_tmpl})
- stack = self.client.stacks.get(stack_identifier)
- initial_id = self._stack_output(stack, 'identifier')
- initial_val = self._stack_output(stack, 'value')
-
- self.update_stack(stack_identifier,
- self.template,
- files={'the.yaml': self.provider})
- stack = self.client.stacks.get(stack_identifier)
- self.assertEqual(initial_id,
- self._stack_output(stack, 'identifier'))
- if self.expect == self.NOCHANGE:
- self.assertEqual(initial_val,
- self._stack_output(stack, 'value'))
- else:
- self.assertNotEqual(initial_val,
- self._stack_output(stack, 'value'))
-
-
-class TemplateResourceUpdateFailedTest(functional_base.FunctionalTestsBase):
- """Prove that we can do updates on a nested stack to fix a stack."""
-
- main_template = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Resources:
- keypair:
- Type: OS::Nova::KeyPair
- Properties:
- name: replace-this
- save_private_key: false
- server:
- Type: server_fail.yaml
- DependsOn: keypair
-'''
- nested_templ = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Resources:
- RealRandom:
- Type: OS::Heat::RandomString
-'''
-
- def setUp(self):
- super(TemplateResourceUpdateFailedTest, self).setUp()
- self.assign_keypair()
-
- def test_update_on_failed_create(self):
- # create a stack with "server" dependent on "keypair", but
- # keypair fails, so "server" is not created properly.
- # We then fix the template and it should succeed.
- broken_templ = self.main_template.replace('replace-this',
- self.keypair_name)
- stack_identifier = self.stack_create(
- template=broken_templ,
- files={'server_fail.yaml': self.nested_templ},
- expected_status='CREATE_FAILED')
-
- fixed_templ = self.main_template.replace('replace-this',
- test.rand_name())
- self.update_stack(stack_identifier,
- fixed_templ,
- files={'server_fail.yaml': self.nested_templ})
-
-
-class TemplateResourceAdoptTest(functional_base.FunctionalTestsBase):
- """Prove that we can do template resource adopt/abandon."""
-
- main_template = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Resources:
- the_nested:
- Type: the.yaml
- Properties:
- one: my_name
-Outputs:
- identifier:
- Value: {Ref: the_nested}
- value:
- Value: {'Fn::GetAtt': [the_nested, the_str]}
-'''
-
- nested_templ = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Parameters:
- one:
- Default: foo
- Type: String
-Resources:
- RealRandom:
- Type: OS::Heat::RandomString
- Properties:
- salt: {Ref: one}
-Outputs:
- the_str:
- Value: {'Fn::GetAtt': [RealRandom, value]}
-'''
-
- def _yaml_to_json(self, yaml_templ):
- return yaml.safe_load(yaml_templ)
-
- def test_abandon(self):
- stack_identifier = self.stack_create(
- template=self.main_template,
- files={'the.yaml': self.nested_templ},
- enable_cleanup=False
- )
-
- info = self.stack_abandon(stack_id=stack_identifier)
- self.assertEqual(self._yaml_to_json(self.main_template),
- info['template'])
- self.assertEqual(self._yaml_to_json(self.nested_templ),
- info['resources']['the_nested']['template'])
- # TODO(james combs): Implement separate test cases for export
- # once export REST API is available. Also test reverse order
- # of invocation: export -> abandon AND abandon -> export
-
- def test_adopt(self):
- data = {
- 'resources': {
- 'the_nested': {
- "type": "the.yaml",
- "resources": {
- "RealRandom": {
- "type": "OS::Heat::RandomString",
- 'resource_data': {'value': 'goopie'},
- 'resource_id': 'froggy'
- }
- }
- }
- },
- "environment": {"parameters": {}},
- "template": yaml.safe_load(self.main_template)
- }
-
- stack_identifier = self.stack_adopt(
- adopt_data=json.dumps(data),
- files={'the.yaml': self.nested_templ})
-
- self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
- stack = self.client.stacks.get(stack_identifier)
- self.assertEqual('goopie', self._stack_output(stack, 'value'))
-
-
-class TemplateResourceCheckTest(functional_base.FunctionalTestsBase):
- """Prove that we can do template resource check."""
-
- main_template = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Resources:
- the_nested:
- Type: the.yaml
- Properties:
- one: my_name
-Outputs:
- identifier:
- Value: {Ref: the_nested}
- value:
- Value: {'Fn::GetAtt': [the_nested, the_str]}
-'''
-
- nested_templ = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Parameters:
- one:
- Default: foo
- Type: String
-Resources:
- RealRandom:
- Type: OS::Heat::RandomString
- Properties:
- salt: {Ref: one}
-Outputs:
- the_str:
- Value: {'Fn::GetAtt': [RealRandom, value]}
-'''
-
- def test_check(self):
- stack_identifier = self.stack_create(
- template=self.main_template,
- files={'the.yaml': self.nested_templ}
- )
-
- self.client.actions.check(stack_id=stack_identifier)
- self._wait_for_stack_status(stack_identifier, 'CHECK_COMPLETE')
-
-
-class TemplateResourceErrorMessageTest(functional_base.FunctionalTestsBase):
- """Prove that nested stack errors don't suck."""
-
- template = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Resources:
- victim:
- Type: fail.yaml
-'''
- nested_templ = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Resources:
- oops:
- Type: OS::Heat::TestResource
- Properties:
- fail: true
- wait_secs: 2
-'''
-
- def test_fail(self):
- stack_identifier = self.stack_create(
- template=self.template,
- files={'fail.yaml': self.nested_templ},
- expected_status='CREATE_FAILED')
- stack = self.client.stacks.get(stack_identifier)
-
- exp_path = 'resources.victim.resources.oops'
- exp_msg = 'Test Resource failed oops'
- exp = 'Resource CREATE failed: ValueError: %s: %s' % (exp_path,
- exp_msg)
- self.assertEqual(exp, stack.stack_status_reason)
-
-
-class TemplateResourceSuspendResumeTest(functional_base.FunctionalTestsBase):
- """Prove that we can do template resource suspend/resume."""
-
- main_template = '''
-heat_template_version: 2014-10-16
-parameters:
-resources:
- the_nested:
- type: the.yaml
-'''
-
- nested_templ = '''
-heat_template_version: 2014-10-16
-resources:
- test_random_string:
- type: OS::Heat::RandomString
-'''
-
- def test_suspend_resume(self):
- """Basic test for template resource suspend resume."""
- stack_identifier = self.stack_create(
- template=self.main_template,
- files={'the.yaml': self.nested_templ}
- )
-
- self.stack_suspend(stack_identifier=stack_identifier)
- self.stack_resume(stack_identifier=stack_identifier)
-
-
-class ValidateFacadeTest(functional_base.FunctionalTestsBase):
- """Prove that nested stack errors don't suck."""
-
- template = '''
-heat_template_version: 2015-10-15
-resources:
- thisone:
- type: OS::Thingy
- properties:
- one: pre
- two: post
-outputs:
- one:
- value: {get_attr: [thisone, here-it-is]}
-'''
- templ_facade = '''
-heat_template_version: 2015-04-30
-parameters:
- one:
- type: string
- two:
- type: string
-outputs:
- here-it-is:
- value: noop
-'''
- env = '''
-resource_registry:
- OS::Thingy: facade.yaml
- resources:
- thisone:
- OS::Thingy: concrete.yaml
-'''
-
- def setUp(self):
- super(ValidateFacadeTest, self).setUp()
- self.client = self.orchestration_client
-
- def test_missing_param(self):
- templ_missing_parameter = '''
-heat_template_version: 2015-04-30
-parameters:
- one:
- type: string
-resources:
- str:
- type: OS::Heat::RandomString
-outputs:
- here-it-is:
- value:
- not-important
-'''
- try:
- self.stack_create(
- template=self.template,
- environment=self.env,
- files={'facade.yaml': self.templ_facade,
- 'concrete.yaml': templ_missing_parameter},
- expected_status='CREATE_FAILED')
- except heat_exceptions.HTTPBadRequest as exc:
- exp = ('ERROR: Required property two for facade '
- 'OS::Thingy missing in provider')
- self.assertEqual(exp, six.text_type(exc))
-
- def test_missing_output(self):
- templ_missing_output = '''
-heat_template_version: 2015-04-30
-parameters:
- one:
- type: string
- two:
- type: string
-resources:
- str:
- type: OS::Heat::RandomString
-'''
- try:
- self.stack_create(
- template=self.template,
- environment=self.env,
- files={'facade.yaml': self.templ_facade,
- 'concrete.yaml': templ_missing_output},
- expected_status='CREATE_FAILED')
- except heat_exceptions.HTTPBadRequest as exc:
- exp = ('ERROR: Attribute here-it-is for facade '
- 'OS::Thingy missing in provider')
- self.assertEqual(exp, six.text_type(exc))
-
-
-class TemplateResourceNewParamTest(functional_base.FunctionalTestsBase):
-
- main_template = '''
-heat_template_version: 2013-05-23
-resources:
- my_resource:
- type: resource.yaml
- properties:
- value1: foo
-'''
- nested_templ = '''
-heat_template_version: 2013-05-23
-parameters:
- value1:
- type: string
-resources:
- test:
- type: OS::Heat::TestResource
- properties:
- value: {get_param: value1}
-'''
- main_template_update = '''
-heat_template_version: 2013-05-23
-resources:
- my_resource:
- type: resource.yaml
- properties:
- value1: foo
- value2: foo
-'''
- nested_templ_update_fail = '''
-heat_template_version: 2013-05-23
-parameters:
- value1:
- type: string
- value2:
- type: string
-resources:
- test:
- type: OS::Heat::TestResource
- properties:
- fail: True
- value:
- str_replace:
- template: VAL1-VAL2
- params:
- VAL1: {get_param: value1}
- VAL2: {get_param: value2}
-'''
- nested_templ_update = '''
-heat_template_version: 2013-05-23
-parameters:
- value1:
- type: string
- value2:
- type: string
-resources:
- test:
- type: OS::Heat::TestResource
- properties:
- value:
- str_replace:
- template: VAL1-VAL2
- params:
- VAL1: {get_param: value1}
- VAL2: {get_param: value2}
-'''
-
- def test_update(self):
- stack_identifier = self.stack_create(
- template=self.main_template,
- files={'resource.yaml': self.nested_templ})
-
- # Make the update fails with the new parameter inserted.
- self.update_stack(
- stack_identifier,
- self.main_template_update,
- files={'resource.yaml': self.nested_templ_update_fail},
- expected_status='UPDATE_FAILED')
-
- # Fix the update, it should succeed now.
- self.update_stack(
- stack_identifier,
- self.main_template_update,
- files={'resource.yaml': self.nested_templ_update})
-
-
-class TemplateResourceRemovedParamTest(functional_base.FunctionalTestsBase):
-
- main_template = '''
-heat_template_version: 2013-05-23
-parameters:
- value1:
- type: string
- default: foo
-resources:
- my_resource:
- type: resource.yaml
- properties:
- value1: {get_param: value1}
-'''
- nested_templ = '''
-heat_template_version: 2013-05-23
-parameters:
- value1:
- type: string
- default: foo
-resources:
- test:
- type: OS::Heat::TestResource
- properties:
- value: {get_param: value1}
-'''
- main_template_update = '''
-heat_template_version: 2013-05-23
-resources:
- my_resource:
- type: resource.yaml
-'''
- nested_templ_update = '''
-heat_template_version: 2013-05-23
-parameters:
- value1:
- type: string
- default: foo
- value2:
- type: string
- default: bar
-resources:
- test:
- type: OS::Heat::TestResource
- properties:
- value:
- str_replace:
- template: VAL1-VAL2
- params:
- VAL1: {get_param: value1}
- VAL2: {get_param: value2}
-'''
-
- def test_update(self):
- stack_identifier = self.stack_create(
- template=self.main_template,
- environment={'parameters': {'value1': 'spam'}},
- files={'resource.yaml': self.nested_templ})
-
- self.update_stack(
- stack_identifier,
- self.main_template_update,
- environment={'parameter_defaults': {'value2': 'egg'}},
- files={'resource.yaml': self.nested_templ_update}, existing=True)
diff --git a/heat_tempest_plugin/tests/functional/test_templates.py b/heat_tempest_plugin/tests/functional/test_templates.py
index bfcf8bf..95c6a01 100644
--- a/heat_tempest_plugin/tests/functional/test_templates.py
+++ b/heat_tempest_plugin/tests/functional/test_templates.py
@@ -18,9 +18,8 @@
"""This will test the following template calls:
1. Get the template content for the specific stack
- 2. List template versions
- 3. List resource types
- 4. Show resource details for OS::Heat::TestResource
+ 2. List resource types
+ 3. Show resource details for OS::Heat::TestResource
"""
template = {
@@ -46,19 +45,6 @@
template_from_client = self.client.stacks.template(stack_identifier)
self.assertEqual(self.template, template_from_client)
- def test_template_version(self):
- template_versions = self.client.template_versions.list()
- supported_template_versions = ["2013-05-23", "2014-10-16",
- "2015-04-30", "2015-10-15",
- "2012-12-12", "2010-09-09",
- "2016-04-08", "2016-10-14", "newton",
- "2017-02-24", "ocata",
- "2017-09-01", "pike",
- "2018-03-02", "queens"]
- for template in template_versions:
- self.assertIn(template.version.split(".")[1],
- supported_template_versions)
-
def test_resource_types(self):
resource_types = self.client.resource_types.list()
self.assertTrue(any(resource.resource_type == "OS::Heat::TestResource"
diff --git a/heat_tempest_plugin/tests/functional/test_translation.py b/heat_tempest_plugin/tests/functional/test_translation.py
deleted file mode 100644
index 484663b..0000000
--- a/heat_tempest_plugin/tests/functional/test_translation.py
+++ /dev/null
@@ -1,117 +0,0 @@
-# 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.
-
-from heat_tempest_plugin.tests.functional import functional_base
-
-template_subnet_old_network = """
-heat_template_version: 2016-10-14
-parameters:
- net_cidr:
- type: string
-resources:
- net:
- type: OS::Neutron::Net
- subnet:
- type: OS::Neutron::Subnet
- properties:
- cidr: { get_param: net_cidr }
- network_id: { get_resource: net }
-"""
-
-template_with_get_attr = """
-heat_template_version: 2016-10-14
-description: Test template to create/update subnet with translation
-parameters:
- net_cidr:
- type: string
-resources:
- net:
- type: OS::Neutron::Net
- net_value:
- type: OS::Heat::Value
- properties:
- value: { get_resource: net }
- subnet:
- type: OS::Neutron::Subnet
- properties:
- network: { get_attr: [net_value, value] }
- cidr: { get_param: net_cidr }
-"""
-
-template_value_from_nested_stack_main = """
-heat_template_version: 2016-10-14
-parameters:
- flavor:
- type: string
- image:
- type: string
- public_net:
- type: string
-resources:
- network_settings:
- type: network.yaml
- properties:
- public_net: { get_param: public_net }
- server:
- type: OS::Nova::Server
- properties:
- flavor: { get_param: flavor }
- image: { get_param: image }
- networks: { get_attr: [network_settings, networks] }
-"""
-
-template_value_from_nested_stack_network = """
-heat_template_version: 2016-10-14
-parameters:
- public_net:
- type: string
-outputs:
- networks:
- value:
- - uuid: { get_param: public_net }
-"""
-
-
-class TestTranslation(functional_base.FunctionalTestsBase):
-
- def test_create_update_subnet_old_network(self):
- # Just create and update where network is translated properly.
- env = {'parameters': {'net_cidr': '11.11.11.0/24'}}
- stack_identifier = self.stack_create(
- template=template_subnet_old_network,
- environment=env)
- env = {'parameters': {'net_cidr': '11.11.12.0/24'}}
- self.update_stack(stack_identifier,
- template=template_subnet_old_network,
- environment=env)
-
- def test_create_update_translation_with_get_attr(self):
- # Check create and update successful for translation function value.
- env = {'parameters': {'net_cidr': '11.11.11.0/24'}}
- stack_identifier = self.stack_create(
- template=template_with_get_attr,
- environment=env)
- env = {'parameters': {'net_cidr': '11.11.12.0/24'}}
- self.update_stack(stack_identifier,
- template=template_with_get_attr,
- environment=env)
-
- def test_value_from_nested_stack(self):
- env = {'parameters': {
- 'flavor': self.conf.minimal_instance_type,
- 'image': self.conf.minimal_image_ref,
- 'public_net': self.conf.fixed_network_name
- }}
- self.stack_create(
- template=template_value_from_nested_stack_main,
- environment=env,
- files={'network.yaml': template_value_from_nested_stack_network})
diff --git a/heat_tempest_plugin/tests/functional/test_update_restricted.py b/heat_tempest_plugin/tests/functional/test_update_restricted.py
deleted file mode 100644
index 83cb280..0000000
--- a/heat_tempest_plugin/tests/functional/test_update_restricted.py
+++ /dev/null
@@ -1,166 +0,0 @@
-# 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 time
-
-from heat_tempest_plugin.tests.functional import functional_base
-
-test_template = {
- 'heat_template_version': '2013-05-23',
- 'description': 'Test template to create one instance.',
- 'resources': {
- 'bar': {
- 'type': 'OS::Heat::TestResource',
- 'properties': {
- 'value': '1234',
- 'update_replace': False,
- }
- }
- }
-}
-
-env_both_restrict = {u'resource_registry': {
- u'resources': {
- 'bar': {'restricted_actions': ['update', 'replace']}
- }
-}
-}
-
-env_replace_restrict = {u'resource_registry': {
- u'resources': {
- '*ar': {'restricted_actions': 'replace'}
- }
-}
-}
-
-reason_update_restrict = 'update is restricted for resource.'
-reason_replace_restrict = 'replace is restricted for resource.'
-
-
-class UpdateRestrictedStackTest(functional_base.FunctionalTestsBase):
-
- def _check_for_restriction_reason(self, events,
- reason, num_expected=1):
- matched = [e for e in events
- if e.resource_status_reason == reason]
- return len(matched) == num_expected
-
- def test_update(self):
- stack_identifier = self.stack_create(template=test_template)
-
- update_template = test_template.copy()
- props = update_template['resources']['bar']['properties']
- props['value'] = '4567'
-
- # check update fails - with 'both' restricted
- self.update_stack(stack_identifier, update_template,
- env_both_restrict,
- expected_status='UPDATE_FAILED')
-
- self.assertTrue(self.verify_resource_status(stack_identifier, 'bar',
- 'CREATE_COMPLETE'))
- resource_events = self.client.events.list(stack_identifier, 'bar')
- self.assertTrue(
- self._check_for_restriction_reason(resource_events,
- reason_update_restrict))
-
- # Ensure the timestamp changes, since this will be very quick
- time.sleep(1)
-
- # check update succeeds - with only 'replace' restricted
- self.update_stack(stack_identifier, update_template,
- env_replace_restrict,
- expected_status='UPDATE_COMPLETE')
-
- self.assertTrue(self.verify_resource_status(stack_identifier, 'bar',
- 'UPDATE_COMPLETE'))
- resource_events = self.client.events.list(stack_identifier, 'bar')
- self.assertFalse(
- self._check_for_restriction_reason(resource_events,
- reason_update_restrict, 2))
- self.assertTrue(
- self._check_for_restriction_reason(resource_events,
- reason_replace_restrict, 0))
-
- def test_replace(self):
- stack_identifier = self.stack_create(template=test_template)
-
- update_template = test_template.copy()
- props = update_template['resources']['bar']['properties']
- props['update_replace'] = True
-
- # check replace fails - with 'both' restricted
- self.update_stack(stack_identifier, update_template,
- env_both_restrict,
- expected_status='UPDATE_FAILED')
-
- self.assertTrue(self.verify_resource_status(stack_identifier, 'bar',
- 'CREATE_COMPLETE'))
- resource_events = self.client.events.list(stack_identifier, 'bar')
- self.assertTrue(
- self._check_for_restriction_reason(resource_events,
- reason_replace_restrict))
-
- # Ensure the timestamp changes, since this will be very quick
- time.sleep(1)
-
- # check replace fails - with only 'replace' restricted
- self.update_stack(stack_identifier, update_template,
- env_replace_restrict,
- expected_status='UPDATE_FAILED')
-
- self.assertTrue(self.verify_resource_status(stack_identifier, 'bar',
- 'CREATE_COMPLETE'))
- resource_events = self.client.events.list(stack_identifier, 'bar')
- self.assertTrue(
- self._check_for_restriction_reason(resource_events,
- reason_replace_restrict, 2))
- self.assertTrue(
- self._check_for_restriction_reason(resource_events,
- reason_update_restrict, 0))
-
- def test_update_type_changed(self):
- stack_identifier = self.stack_create(template=test_template)
-
- update_template = test_template.copy()
- rsrc = update_template['resources']['bar']
- rsrc['type'] = 'OS::Heat::None'
-
- # check replace fails - with 'both' restricted
- self.update_stack(stack_identifier, update_template,
- env_both_restrict,
- expected_status='UPDATE_FAILED')
-
- self.assertTrue(self.verify_resource_status(stack_identifier, 'bar',
- 'CREATE_COMPLETE'))
- resource_events = self.client.events.list(stack_identifier, 'bar')
- self.assertTrue(
- self._check_for_restriction_reason(resource_events,
- reason_replace_restrict))
-
- # Ensure the timestamp changes, since this will be very quick
- time.sleep(1)
-
- # check replace fails - with only 'replace' restricted
- self.update_stack(stack_identifier, update_template,
- env_replace_restrict,
- expected_status='UPDATE_FAILED')
-
- self.assertTrue(self.verify_resource_status(stack_identifier, 'bar',
- 'CREATE_COMPLETE'))
- resource_events = self.client.events.list(stack_identifier, 'bar')
- self.assertTrue(
- self._check_for_restriction_reason(resource_events,
- reason_replace_restrict, 2))
- self.assertTrue(
- self._check_for_restriction_reason(resource_events,
- reason_update_restrict, 0))
diff --git a/heat_tempest_plugin/tests/functional/test_validation.py b/heat_tempest_plugin/tests/functional/test_validation.py
deleted file mode 100644
index ab1762e..0000000
--- a/heat_tempest_plugin/tests/functional/test_validation.py
+++ /dev/null
@@ -1,92 +0,0 @@
-# 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.
-
-
-from heat_tempest_plugin.tests.functional import functional_base
-
-
-class StackValidationTest(functional_base.FunctionalTestsBase):
-
- def setUp(self):
- super(StackValidationTest, self).setUp()
- if not self.conf.minimal_image_ref:
- raise self.skipException("No image configured to test")
-
- if not self.conf.minimal_instance_type:
- raise self.skipException(
- "No minimal_instance_type configured to test")
-
- self.assign_keypair()
-
- 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
- network:
- 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}
- networks: [{network: {get_param: network} }]
- 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.minimal_instance_type,
- 'image': self.conf.minimal_image_ref,
- 'network': self.conf.fixed_network_name}
- # 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')
diff --git a/requirements.txt b/requirements.txt
index f030897..34fa1fd 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,6 +6,7 @@
oslo.config>=5.1.0 # Apache-2.0
oslo.log>=3.36.0 # Apache-2.0
oslo.messaging>=5.29.0 # Apache-2.0
+os-collect-config>=5.0.0 # Apache-2.0
paramiko>=2.0.0 # LGPLv2.1+
python-cinderclient>=3.3.0 # Apache-2.0
gnocchiclient>=3.3.1 # Apache-2.0