blob: 05539dca85d8059e16bef6b7633975404db2bf94 [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 Hervedb36c092017-03-23 11:20:14 +010075 if not self.is_service_available('object-store'):
76 self.skipTest('object-store service not available, skipping')
Thomas Hervefb53d422016-01-05 15:29:03 +010077 self.object_container_name = test.rand_name()
Rabi Mishra65493fb2016-01-29 22:23:21 +053078 self.project_id = self.identity_client.project_id
Thomas Hervefb53d422016-01-05 15:29:03 +010079 self.swift_key = hashlib.sha224(
Thomas Herved1757c52017-02-01 13:52:58 +010080 str(random.getrandbits(256)).encode('ascii')).hexdigest()[:32]
Thomas Hervefb53d422016-01-05 15:29:03 +010081 key_header = 'x-container-meta-temp-url-key'
82 self.object_client.put_container(self.object_container_name,
83 {key_header: self.swift_key})
84 self.addCleanup(self.object_client.delete_container,
85 self.object_container_name)
Angus Salkeld4408da32015-02-03 18:53:30 +100086
Thomas Hervefb53d422016-01-05 15:29:03 +010087 def publish_template(self, contents, cleanup=True):
Angus Salkeld4408da32015-02-03 18:53:30 +100088 oc = self.object_client
89
90 # post the object
Thomas Hervefb53d422016-01-05 15:29:03 +010091 oc.put_object(self.object_container_name, 'template.yaml', contents)
92 if cleanup:
93 self.addCleanup(oc.delete_object,
94 self.object_container_name,
95 'template.yaml')
Angus Salkeld4408da32015-02-03 18:53:30 +100096 path = '/v1/AUTH_%s/%s/%s' % (self.project_id,
Thomas Hervefb53d422016-01-05 15:29:03 +010097 self.object_container_name,
98 'template.yaml')
Angus Salkeld4408da32015-02-03 18:53:30 +100099 timeout = self.conf.build_timeout * 10
100 tempurl = swiftclient_utils.generate_temp_url(path, timeout,
Thomas Hervefb53d422016-01-05 15:29:03 +0100101 self.swift_key, 'GET')
Sirushti Murugesan4920fda2015-04-22 00:35:26 +0530102 sw_url = parse.urlparse(oc.url)
Thomas Hervefb53d422016-01-05 15:29:03 +0100103 return '%s://%s%s' % (sw_url.scheme, sw_url.netloc, tempurl)
Angus Salkeld4408da32015-02-03 18:53:30 +1000104
105 def test_nested_stack_create(self):
Thomas Hervefb53d422016-01-05 15:29:03 +0100106 url = self.publish_template(self.nested_template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000107 self.template = self.test_template.replace('the.yaml', url)
108 stack_identifier = self.stack_create(template=self.template)
109 stack = self.client.stacks.get(stack_identifier)
110 self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
111 self.assertEqual('bar', self._stack_output(stack, 'output_foo'))
112
113 def test_nested_stack_create_with_timeout(self):
Thomas Hervefb53d422016-01-05 15:29:03 +0100114 url = self.publish_template(self.nested_template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000115 self.template = self.test_template.replace('the.yaml', url)
Bo Wangd8df4dd2016-02-16 21:23:53 +0800116 timeout_template = yaml.safe_load(self.template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000117 props = timeout_template['Resources']['the_nested']['Properties']
118 props['TimeoutInMinutes'] = '50'
119
120 stack_identifier = self.stack_create(
121 template=timeout_template)
122 stack = self.client.stacks.get(stack_identifier)
123 self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
124 self.assertEqual('bar', self._stack_output(stack, 'output_foo'))
125
126 def test_nested_stack_adopt_ok(self):
Thomas Hervefb53d422016-01-05 15:29:03 +0100127 url = self.publish_template(self.nested_with_res_template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000128 self.template = self.test_template.replace('the.yaml', url)
129 adopt_data = {
130 "resources": {
131 "the_nested": {
132 "resource_id": "test-res-id",
133 "resources": {
134 "NestedResource": {
135 "type": "OS::Heat::RandomString",
136 "resource_id": "test-nested-res-id",
137 "resource_data": {"value": "goopie"}
138 }
139 }
140 }
141 },
142 "environment": {"parameters": {}},
Bo Wangd8df4dd2016-02-16 21:23:53 +0800143 "template": yaml.safe_load(self.template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000144 }
145
146 stack_identifier = self.stack_adopt(adopt_data=json.dumps(adopt_data))
147
148 self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
149 stack = self.client.stacks.get(stack_identifier)
150 self.assertEqual('goopie', self._stack_output(stack, 'output_foo'))
151
152 def test_nested_stack_adopt_fail(self):
Thomas Hervefb53d422016-01-05 15:29:03 +0100153 url = self.publish_template(self.nested_with_res_template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000154 self.template = self.test_template.replace('the.yaml', url)
155 adopt_data = {
156 "resources": {
157 "the_nested": {
158 "resource_id": "test-res-id",
159 "resources": {
160 }
161 }
162 },
163 "environment": {"parameters": {}},
Bo Wangd8df4dd2016-02-16 21:23:53 +0800164 "template": yaml.safe_load(self.template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000165 }
166
167 stack_identifier = self.stack_adopt(adopt_data=json.dumps(adopt_data),
168 wait_for_status='ADOPT_FAILED')
169 rsrc = self.client.resources.get(stack_identifier, 'the_nested')
170 self.assertEqual('ADOPT_FAILED', rsrc.resource_status)
171
172 def test_nested_stack_update(self):
Thomas Hervefb53d422016-01-05 15:29:03 +0100173 url = self.publish_template(self.nested_template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000174 self.template = self.test_template.replace('the.yaml', url)
175 stack_identifier = self.stack_create(template=self.template)
176 original_nested_id = self.assert_resource_is_a_stack(
177 stack_identifier, 'the_nested')
178 stack = self.client.stacks.get(stack_identifier)
179 self.assertEqual('bar', self._stack_output(stack, 'output_foo'))
180
Bo Wangd8df4dd2016-02-16 21:23:53 +0800181 new_template = yaml.safe_load(self.template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000182 props = new_template['Resources']['the_nested']['Properties']
Thomas Hervefb53d422016-01-05 15:29:03 +0100183 props['TemplateURL'] = self.publish_template(self.update_template,
184 cleanup=False)
Angus Salkeld4408da32015-02-03 18:53:30 +1000185
186 self.update_stack(stack_identifier, new_template)
187
188 # Expect the physical resource name staying the same after update,
189 # so that the nested was actually updated instead of replaced.
190 new_nested_id = self.assert_resource_is_a_stack(
191 stack_identifier, 'the_nested')
192 self.assertEqual(original_nested_id, new_nested_id)
193 updt_stack = self.client.stacks.get(stack_identifier)
194 self.assertEqual('foo', self._stack_output(updt_stack, 'output_foo'))
195
196 def test_nested_stack_suspend_resume(self):
Thomas Hervefb53d422016-01-05 15:29:03 +0100197 url = self.publish_template(self.nested_template)
Angus Salkeld4408da32015-02-03 18:53:30 +1000198 self.template = self.test_template.replace('the.yaml', url)
199 stack_identifier = self.stack_create(template=self.template)
Angus Salkelda7500d12015-04-10 15:44:07 +1000200 self.stack_suspend(stack_identifier)
201 self.stack_resume(stack_identifier)