blob: 13c427893768fbb411ca0e3fe8dac95b4ab85369 [file] [log] [blame]
Angus Salkeld4408da32015-02-03 18:53:30 +10001# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
13import hashlib
14import json
Angus Salkeld4408da32015-02-03 18:53:30 +100015import random
Angus Salkeld4408da32015-02-03 18:53:30 +100016
Steve Baker24641292015-03-13 10:47:50 +130017from oslo_log import log as logging
Thomas Hervefb53d422016-01-05 15:29:03 +010018
Sirushti Murugesan4920fda2015-04-22 00:35:26 +053019from six.moves.urllib import parse
Angus Salkeld4408da32015-02-03 18:53:30 +100020from swiftclient import utils as swiftclient_utils
21import yaml
22
23from heat_integrationtests.common import test
Rabi Mishra477efc92015-07-31 13:01:45 +053024from heat_integrationtests.functional import functional_base
Angus Salkeld4408da32015-02-03 18:53:30 +100025
26LOG = logging.getLogger(__name__)
27
28
Rabi Mishra477efc92015-07-31 13:01:45 +053029class AwsStackTest(functional_base.FunctionalTestsBase):
Angus Salkeld4408da32015-02-03 18:53:30 +100030 test_template = '''
31HeatTemplateFormatVersion: '2012-12-12'
32Resources:
33 the_nested:
34 Type: AWS::CloudFormation::Stack
35 Properties:
36 TemplateURL: the.yaml
37 Parameters:
38 KeyName: foo
39Outputs:
40 output_foo:
41 Value: {"Fn::GetAtt": [the_nested, Outputs.Foo]}
42'''
43
44 nested_template = '''
45HeatTemplateFormatVersion: '2012-12-12'
46Parameters:
47 KeyName:
48 Type: String
49Outputs:
50 Foo:
51 Value: bar
52'''
53
54 update_template = '''
55HeatTemplateFormatVersion: '2012-12-12'
56Parameters:
57 KeyName:
58 Type: String
59Outputs:
60 Foo:
61 Value: foo
62'''
63
64 nested_with_res_template = '''
65HeatTemplateFormatVersion: '2012-12-12'
66Parameters:
67 KeyName:
68 Type: String
69Resources:
70 NestedResource:
71 Type: OS::Heat::RandomString
72Outputs:
73 Foo:
74 Value: {"Fn::GetAtt": [NestedResource, value]}
75'''
76
77 def setUp(self):
78 super(AwsStackTest, self).setUp()
Thomas Hervefb53d422016-01-05 15:29:03 +010079 self.object_container_name = test.rand_name()
Rabi Mishra65493fb2016-01-29 22:23:21 +053080 self.project_id = self.identity_client.project_id
Thomas Hervefb53d422016-01-05 15:29:03 +010081 self.swift_key = hashlib.sha224(
82 str(random.getrandbits(256))).hexdigest()[:32]
83 key_header = 'x-container-meta-temp-url-key'
84 self.object_client.put_container(self.object_container_name,
85 {key_header: self.swift_key})
86 self.addCleanup(self.object_client.delete_container,
87 self.object_container_name)
Angus Salkeld4408da32015-02-03 18:53:30 +100088
Thomas Hervefb53d422016-01-05 15:29:03 +010089 def publish_template(self, contents, cleanup=True):
Angus Salkeld4408da32015-02-03 18:53:30 +100090 oc = self.object_client
91
92 # post the object
Thomas Hervefb53d422016-01-05 15:29:03 +010093 oc.put_object(self.object_container_name, 'template.yaml', contents)
94 if cleanup:
95 self.addCleanup(oc.delete_object,
96 self.object_container_name,
97 'template.yaml')
Angus Salkeld4408da32015-02-03 18:53:30 +100098 path = '/v1/AUTH_%s/%s/%s' % (self.project_id,
Thomas Hervefb53d422016-01-05 15:29:03 +010099 self.object_container_name,
100 'template.yaml')
Angus Salkeld4408da32015-02-03 18:53:30 +1000101 timeout = self.conf.build_timeout * 10
102 tempurl = swiftclient_utils.generate_temp_url(path, timeout,
Thomas Hervefb53d422016-01-05 15:29:03 +0100103 self.swift_key, 'GET')
Sirushti Murugesan4920fda2015-04-22 00:35:26 +0530104 sw_url = parse.urlparse(oc.url)
Thomas Hervefb53d422016-01-05 15:29:03 +0100105 return '%s://%s%s' % (sw_url.scheme, sw_url.netloc, tempurl)
Angus Salkeld4408da32015-02-03 18:53:30 +1000106
107 def test_nested_stack_create(self):
Thomas Hervefb53d422016-01-05 15:29:03 +0100108 url = self.publish_template(self.nested_template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000109 self.template = self.test_template.replace('the.yaml', url)
110 stack_identifier = self.stack_create(template=self.template)
111 stack = self.client.stacks.get(stack_identifier)
112 self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
113 self.assertEqual('bar', self._stack_output(stack, 'output_foo'))
114
115 def test_nested_stack_create_with_timeout(self):
Thomas Hervefb53d422016-01-05 15:29:03 +0100116 url = self.publish_template(self.nested_template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000117 self.template = self.test_template.replace('the.yaml', url)
Bo Wangd8df4dd2016-02-16 21:23:53 +0800118 timeout_template = yaml.safe_load(self.template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000119 props = timeout_template['Resources']['the_nested']['Properties']
120 props['TimeoutInMinutes'] = '50'
121
122 stack_identifier = self.stack_create(
123 template=timeout_template)
124 stack = self.client.stacks.get(stack_identifier)
125 self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
126 self.assertEqual('bar', self._stack_output(stack, 'output_foo'))
127
128 def test_nested_stack_adopt_ok(self):
Thomas Hervefb53d422016-01-05 15:29:03 +0100129 url = self.publish_template(self.nested_with_res_template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000130 self.template = self.test_template.replace('the.yaml', url)
131 adopt_data = {
132 "resources": {
133 "the_nested": {
134 "resource_id": "test-res-id",
135 "resources": {
136 "NestedResource": {
137 "type": "OS::Heat::RandomString",
138 "resource_id": "test-nested-res-id",
139 "resource_data": {"value": "goopie"}
140 }
141 }
142 }
143 },
144 "environment": {"parameters": {}},
Bo Wangd8df4dd2016-02-16 21:23:53 +0800145 "template": yaml.safe_load(self.template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000146 }
147
148 stack_identifier = self.stack_adopt(adopt_data=json.dumps(adopt_data))
149
150 self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
151 stack = self.client.stacks.get(stack_identifier)
152 self.assertEqual('goopie', self._stack_output(stack, 'output_foo'))
153
154 def test_nested_stack_adopt_fail(self):
Thomas Hervefb53d422016-01-05 15:29:03 +0100155 url = self.publish_template(self.nested_with_res_template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000156 self.template = self.test_template.replace('the.yaml', url)
157 adopt_data = {
158 "resources": {
159 "the_nested": {
160 "resource_id": "test-res-id",
161 "resources": {
162 }
163 }
164 },
165 "environment": {"parameters": {}},
Bo Wangd8df4dd2016-02-16 21:23:53 +0800166 "template": yaml.safe_load(self.template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000167 }
168
169 stack_identifier = self.stack_adopt(adopt_data=json.dumps(adopt_data),
170 wait_for_status='ADOPT_FAILED')
171 rsrc = self.client.resources.get(stack_identifier, 'the_nested')
172 self.assertEqual('ADOPT_FAILED', rsrc.resource_status)
173
174 def test_nested_stack_update(self):
Thomas Hervefb53d422016-01-05 15:29:03 +0100175 url = self.publish_template(self.nested_template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000176 self.template = self.test_template.replace('the.yaml', url)
177 stack_identifier = self.stack_create(template=self.template)
178 original_nested_id = self.assert_resource_is_a_stack(
179 stack_identifier, 'the_nested')
180 stack = self.client.stacks.get(stack_identifier)
181 self.assertEqual('bar', self._stack_output(stack, 'output_foo'))
182
Bo Wangd8df4dd2016-02-16 21:23:53 +0800183 new_template = yaml.safe_load(self.template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000184 props = new_template['Resources']['the_nested']['Properties']
Thomas Hervefb53d422016-01-05 15:29:03 +0100185 props['TemplateURL'] = self.publish_template(self.update_template,
186 cleanup=False)
Angus Salkeld4408da32015-02-03 18:53:30 +1000187
188 self.update_stack(stack_identifier, new_template)
189
190 # Expect the physical resource name staying the same after update,
191 # so that the nested was actually updated instead of replaced.
192 new_nested_id = self.assert_resource_is_a_stack(
193 stack_identifier, 'the_nested')
194 self.assertEqual(original_nested_id, new_nested_id)
195 updt_stack = self.client.stacks.get(stack_identifier)
196 self.assertEqual('foo', self._stack_output(updt_stack, 'output_foo'))
197
198 def test_nested_stack_suspend_resume(self):
Thomas Hervefb53d422016-01-05 15:29:03 +0100199 url = self.publish_template(self.nested_template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000200 self.template = self.test_template.replace('the.yaml', url)
201 stack_identifier = self.stack_create(template=self.template)
Angus Salkelda7500d12015-04-10 15:44:07 +1000202 self.stack_suspend(stack_identifier)
203 self.stack_resume(stack_identifier)