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 @@ HeatGroup = [ 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 @@ HeatGroup = [ 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_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.resources." - "0.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 @@ class TemplateAPITest(functional_base.FunctionalTestsBase): """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 @@ class TemplateAPITest(functional_base.FunctionalTestsBase): 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')