bbb18e76f3
These wait for the stack state to get to complete, this wasn't done consistently. In test_autoscaling we were only waiting for the resource state to get to SUSPEND_COMPLETE and this lead to a time sensitive bug. Change-Id: Id985d833dc0b4cab1e3cb9d8f67d5d8cc94b5863 Closes-bug: #1438717
208 lines
7.7 KiB
Python
208 lines
7.7 KiB
Python
# 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
|
|
import urlparse
|
|
|
|
from oslo_log import log as logging
|
|
from swiftclient import utils as swiftclient_utils
|
|
import yaml
|
|
|
|
from heat_integrationtests.common import test
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class AwsStackTest(test.HeatIntegrationTest):
|
|
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()
|
|
self.client = self.orchestration_client
|
|
self.object_container_name = AwsStackTest.__name__
|
|
self.project_id = self.identity_client.auth_ref.project_id
|
|
self.object_client.put_container(self.object_container_name)
|
|
self.nested_name = '%s.yaml' % test.rand_name()
|
|
|
|
def publish_template(self, name, contents):
|
|
oc = self.object_client
|
|
|
|
# post the object
|
|
oc.put_object(self.object_container_name, name, contents)
|
|
# TODO(asalkeld) see if this is causing problems.
|
|
# self.addCleanup(self.object_client.delete_object,
|
|
# self.object_container_name, name)
|
|
|
|
# make the tempurl
|
|
key_header = 'x-account-meta-temp-url-key'
|
|
if key_header not in oc.head_account():
|
|
swift_key = hashlib.sha224(
|
|
str(random.getrandbits(256))).hexdigest()[:32]
|
|
LOG.warn('setting swift key to %s' % swift_key)
|
|
oc.post_account({key_header: swift_key})
|
|
key = oc.head_account()[key_header]
|
|
path = '/v1/AUTH_%s/%s/%s' % (self.project_id,
|
|
self.object_container_name, name)
|
|
timeout = self.conf.build_timeout * 10
|
|
tempurl = swiftclient_utils.generate_temp_url(path, timeout,
|
|
key, 'GET')
|
|
sw_url = urlparse.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_name, 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_name, self.nested_template)
|
|
self.template = self.test_template.replace('the.yaml', url)
|
|
timeout_template = yaml.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_name,
|
|
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.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_name,
|
|
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.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_name, 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.load(self.template)
|
|
props = new_template['Resources']['the_nested']['Properties']
|
|
props['TemplateURL'] = self.publish_template(self.nested_name,
|
|
self.update_template)
|
|
|
|
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_name, 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)
|