blob: 296ed8d4120f50826bc5d24eeedc7ebf990c02d5 [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
Sirushti Murugesan4920fda2015-04-22 00:35:26 +053017from six.moves.urllib import parse
Angus Salkeld4408da32015-02-03 18:53:30 +100018from swiftclient import utils as swiftclient_utils
19import yaml
20
21from heat_integrationtests.common import test
Rabi Mishra477efc92015-07-31 13:01:45 +053022from heat_integrationtests.functional import functional_base
Angus Salkeld4408da32015-02-03 18:53:30 +100023
Angus Salkeld4408da32015-02-03 18:53:30 +100024
Rabi Mishra477efc92015-07-31 13:01:45 +053025class AwsStackTest(functional_base.FunctionalTestsBase):
Angus Salkeld4408da32015-02-03 18:53:30 +100026 test_template = '''
27HeatTemplateFormatVersion: '2012-12-12'
28Resources:
29 the_nested:
30 Type: AWS::CloudFormation::Stack
31 Properties:
32 TemplateURL: the.yaml
33 Parameters:
34 KeyName: foo
35Outputs:
36 output_foo:
37 Value: {"Fn::GetAtt": [the_nested, Outputs.Foo]}
38'''
39
40 nested_template = '''
41HeatTemplateFormatVersion: '2012-12-12'
42Parameters:
43 KeyName:
44 Type: String
45Outputs:
46 Foo:
47 Value: bar
48'''
49
50 update_template = '''
51HeatTemplateFormatVersion: '2012-12-12'
52Parameters:
53 KeyName:
54 Type: String
55Outputs:
56 Foo:
57 Value: foo
58'''
59
60 nested_with_res_template = '''
61HeatTemplateFormatVersion: '2012-12-12'
62Parameters:
63 KeyName:
64 Type: String
65Resources:
66 NestedResource:
67 Type: OS::Heat::RandomString
68Outputs:
69 Foo:
70 Value: {"Fn::GetAtt": [NestedResource, value]}
71'''
72
73 def setUp(self):
74 super(AwsStackTest, self).setUp()
Thomas Hervefb53d422016-01-05 15:29:03 +010075 self.object_container_name = test.rand_name()
Rabi Mishra65493fb2016-01-29 22:23:21 +053076 self.project_id = self.identity_client.project_id
Thomas Hervefb53d422016-01-05 15:29:03 +010077 self.swift_key = hashlib.sha224(
78 str(random.getrandbits(256))).hexdigest()[:32]
79 key_header = 'x-container-meta-temp-url-key'
80 self.object_client.put_container(self.object_container_name,
81 {key_header: self.swift_key})
82 self.addCleanup(self.object_client.delete_container,
83 self.object_container_name)
Angus Salkeld4408da32015-02-03 18:53:30 +100084
Thomas Hervefb53d422016-01-05 15:29:03 +010085 def publish_template(self, contents, cleanup=True):
Angus Salkeld4408da32015-02-03 18:53:30 +100086 oc = self.object_client
87
88 # post the object
Thomas Hervefb53d422016-01-05 15:29:03 +010089 oc.put_object(self.object_container_name, 'template.yaml', contents)
90 if cleanup:
91 self.addCleanup(oc.delete_object,
92 self.object_container_name,
93 'template.yaml')
Angus Salkeld4408da32015-02-03 18:53:30 +100094 path = '/v1/AUTH_%s/%s/%s' % (self.project_id,
Thomas Hervefb53d422016-01-05 15:29:03 +010095 self.object_container_name,
96 'template.yaml')
Angus Salkeld4408da32015-02-03 18:53:30 +100097 timeout = self.conf.build_timeout * 10
98 tempurl = swiftclient_utils.generate_temp_url(path, timeout,
Thomas Hervefb53d422016-01-05 15:29:03 +010099 self.swift_key, 'GET')
Sirushti Murugesan4920fda2015-04-22 00:35:26 +0530100 sw_url = parse.urlparse(oc.url)
Thomas Hervefb53d422016-01-05 15:29:03 +0100101 return '%s://%s%s' % (sw_url.scheme, sw_url.netloc, tempurl)
Angus Salkeld4408da32015-02-03 18:53:30 +1000102
103 def test_nested_stack_create(self):
Thomas Hervefb53d422016-01-05 15:29:03 +0100104 url = self.publish_template(self.nested_template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000105 self.template = self.test_template.replace('the.yaml', url)
106 stack_identifier = self.stack_create(template=self.template)
107 stack = self.client.stacks.get(stack_identifier)
108 self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
109 self.assertEqual('bar', self._stack_output(stack, 'output_foo'))
110
111 def test_nested_stack_create_with_timeout(self):
Thomas Hervefb53d422016-01-05 15:29:03 +0100112 url = self.publish_template(self.nested_template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000113 self.template = self.test_template.replace('the.yaml', url)
Bo Wangd8df4dd2016-02-16 21:23:53 +0800114 timeout_template = yaml.safe_load(self.template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000115 props = timeout_template['Resources']['the_nested']['Properties']
116 props['TimeoutInMinutes'] = '50'
117
118 stack_identifier = self.stack_create(
119 template=timeout_template)
120 stack = self.client.stacks.get(stack_identifier)
121 self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
122 self.assertEqual('bar', self._stack_output(stack, 'output_foo'))
123
124 def test_nested_stack_adopt_ok(self):
Thomas Hervefb53d422016-01-05 15:29:03 +0100125 url = self.publish_template(self.nested_with_res_template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000126 self.template = self.test_template.replace('the.yaml', url)
127 adopt_data = {
128 "resources": {
129 "the_nested": {
130 "resource_id": "test-res-id",
131 "resources": {
132 "NestedResource": {
133 "type": "OS::Heat::RandomString",
134 "resource_id": "test-nested-res-id",
135 "resource_data": {"value": "goopie"}
136 }
137 }
138 }
139 },
140 "environment": {"parameters": {}},
Bo Wangd8df4dd2016-02-16 21:23:53 +0800141 "template": yaml.safe_load(self.template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000142 }
143
144 stack_identifier = self.stack_adopt(adopt_data=json.dumps(adopt_data))
145
146 self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
147 stack = self.client.stacks.get(stack_identifier)
148 self.assertEqual('goopie', self._stack_output(stack, 'output_foo'))
149
150 def test_nested_stack_adopt_fail(self):
Thomas Hervefb53d422016-01-05 15:29:03 +0100151 url = self.publish_template(self.nested_with_res_template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000152 self.template = self.test_template.replace('the.yaml', url)
153 adopt_data = {
154 "resources": {
155 "the_nested": {
156 "resource_id": "test-res-id",
157 "resources": {
158 }
159 }
160 },
161 "environment": {"parameters": {}},
Bo Wangd8df4dd2016-02-16 21:23:53 +0800162 "template": yaml.safe_load(self.template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000163 }
164
165 stack_identifier = self.stack_adopt(adopt_data=json.dumps(adopt_data),
166 wait_for_status='ADOPT_FAILED')
167 rsrc = self.client.resources.get(stack_identifier, 'the_nested')
168 self.assertEqual('ADOPT_FAILED', rsrc.resource_status)
169
170 def test_nested_stack_update(self):
Thomas Hervefb53d422016-01-05 15:29:03 +0100171 url = self.publish_template(self.nested_template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000172 self.template = self.test_template.replace('the.yaml', url)
173 stack_identifier = self.stack_create(template=self.template)
174 original_nested_id = self.assert_resource_is_a_stack(
175 stack_identifier, 'the_nested')
176 stack = self.client.stacks.get(stack_identifier)
177 self.assertEqual('bar', self._stack_output(stack, 'output_foo'))
178
Bo Wangd8df4dd2016-02-16 21:23:53 +0800179 new_template = yaml.safe_load(self.template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000180 props = new_template['Resources']['the_nested']['Properties']
Thomas Hervefb53d422016-01-05 15:29:03 +0100181 props['TemplateURL'] = self.publish_template(self.update_template,
182 cleanup=False)
Angus Salkeld4408da32015-02-03 18:53:30 +1000183
184 self.update_stack(stack_identifier, new_template)
185
186 # Expect the physical resource name staying the same after update,
187 # so that the nested was actually updated instead of replaced.
188 new_nested_id = self.assert_resource_is_a_stack(
189 stack_identifier, 'the_nested')
190 self.assertEqual(original_nested_id, new_nested_id)
191 updt_stack = self.client.stacks.get(stack_identifier)
192 self.assertEqual('foo', self._stack_output(updt_stack, 'output_foo'))
193
194 def test_nested_stack_suspend_resume(self):
Thomas Hervefb53d422016-01-05 15:29:03 +0100195 url = self.publish_template(self.nested_template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000196 self.template = self.test_template.replace('the.yaml', url)
197 stack_identifier = self.stack_create(template=self.template)
Angus Salkelda7500d12015-04-10 15:44:07 +1000198 self.stack_suspend(stack_identifier)
199 self.stack_resume(stack_identifier)