blob: 65f2ae82ad8cd708d1bd4a17243ce7366da20fbd [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
Angus Salkeldd1ab9c62015-10-06 13:58:34 +100018import requests
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()
Angus Salkeld4408da32015-02-03 18:53:30 +100079 self.object_container_name = AwsStackTest.__name__
80 self.project_id = self.identity_client.auth_ref.project_id
81 self.object_client.put_container(self.object_container_name)
82 self.nested_name = '%s.yaml' % test.rand_name()
83
84 def publish_template(self, name, contents):
85 oc = self.object_client
86
87 # post the object
88 oc.put_object(self.object_container_name, name, contents)
89 # TODO(asalkeld) see if this is causing problems.
90 # self.addCleanup(self.object_client.delete_object,
91 # self.object_container_name, name)
92
93 # make the tempurl
94 key_header = 'x-account-meta-temp-url-key'
95 if key_header not in oc.head_account():
96 swift_key = hashlib.sha224(
97 str(random.getrandbits(256))).hexdigest()[:32]
LiuNankec7e36ed2015-12-29 12:54:49 +080098 LOG.warning('setting swift key to %s' % swift_key)
Angus Salkeld4408da32015-02-03 18:53:30 +100099 oc.post_account({key_header: swift_key})
100 key = oc.head_account()[key_header]
101 path = '/v1/AUTH_%s/%s/%s' % (self.project_id,
102 self.object_container_name, name)
103 timeout = self.conf.build_timeout * 10
104 tempurl = swiftclient_utils.generate_temp_url(path, timeout,
105 key, 'GET')
Sirushti Murugesan4920fda2015-04-22 00:35:26 +0530106 sw_url = parse.urlparse(oc.url)
Angus Salkeldd1ab9c62015-10-06 13:58:34 +1000107 full_url = '%s://%s%s' % (sw_url.scheme, sw_url.netloc, tempurl)
108
109 def download():
110 r = requests.get(full_url)
111 LOG.info('GET: %s -> %s' % (full_url, r.status_code))
112 return r.status_code == requests.codes.ok
113
114 # make sure that the object is available.
115 test.call_until_true(self.conf.build_timeout,
116 self.conf.build_interval, download)
117
118 return full_url
Angus Salkeld4408da32015-02-03 18:53:30 +1000119
120 def test_nested_stack_create(self):
121 url = self.publish_template(self.nested_name, self.nested_template)
122 self.template = self.test_template.replace('the.yaml', url)
123 stack_identifier = self.stack_create(template=self.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_create_with_timeout(self):
129 url = self.publish_template(self.nested_name, self.nested_template)
130 self.template = self.test_template.replace('the.yaml', url)
131 timeout_template = yaml.load(self.template)
132 props = timeout_template['Resources']['the_nested']['Properties']
133 props['TimeoutInMinutes'] = '50'
134
135 stack_identifier = self.stack_create(
136 template=timeout_template)
137 stack = self.client.stacks.get(stack_identifier)
138 self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
139 self.assertEqual('bar', self._stack_output(stack, 'output_foo'))
140
141 def test_nested_stack_adopt_ok(self):
142 url = self.publish_template(self.nested_name,
143 self.nested_with_res_template)
144 self.template = self.test_template.replace('the.yaml', url)
145 adopt_data = {
146 "resources": {
147 "the_nested": {
148 "resource_id": "test-res-id",
149 "resources": {
150 "NestedResource": {
151 "type": "OS::Heat::RandomString",
152 "resource_id": "test-nested-res-id",
153 "resource_data": {"value": "goopie"}
154 }
155 }
156 }
157 },
158 "environment": {"parameters": {}},
159 "template": yaml.load(self.template)
160 }
161
162 stack_identifier = self.stack_adopt(adopt_data=json.dumps(adopt_data))
163
164 self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
165 stack = self.client.stacks.get(stack_identifier)
166 self.assertEqual('goopie', self._stack_output(stack, 'output_foo'))
167
168 def test_nested_stack_adopt_fail(self):
169 url = self.publish_template(self.nested_name,
170 self.nested_with_res_template)
171 self.template = self.test_template.replace('the.yaml', url)
172 adopt_data = {
173 "resources": {
174 "the_nested": {
175 "resource_id": "test-res-id",
176 "resources": {
177 }
178 }
179 },
180 "environment": {"parameters": {}},
181 "template": yaml.load(self.template)
182 }
183
184 stack_identifier = self.stack_adopt(adopt_data=json.dumps(adopt_data),
185 wait_for_status='ADOPT_FAILED')
186 rsrc = self.client.resources.get(stack_identifier, 'the_nested')
187 self.assertEqual('ADOPT_FAILED', rsrc.resource_status)
188
189 def test_nested_stack_update(self):
190 url = self.publish_template(self.nested_name, self.nested_template)
191 self.template = self.test_template.replace('the.yaml', url)
192 stack_identifier = self.stack_create(template=self.template)
193 original_nested_id = self.assert_resource_is_a_stack(
194 stack_identifier, 'the_nested')
195 stack = self.client.stacks.get(stack_identifier)
196 self.assertEqual('bar', self._stack_output(stack, 'output_foo'))
197
198 new_template = yaml.load(self.template)
199 props = new_template['Resources']['the_nested']['Properties']
200 props['TemplateURL'] = self.publish_template(self.nested_name,
201 self.update_template)
202
203 self.update_stack(stack_identifier, new_template)
204
205 # Expect the physical resource name staying the same after update,
206 # so that the nested was actually updated instead of replaced.
207 new_nested_id = self.assert_resource_is_a_stack(
208 stack_identifier, 'the_nested')
209 self.assertEqual(original_nested_id, new_nested_id)
210 updt_stack = self.client.stacks.get(stack_identifier)
211 self.assertEqual('foo', self._stack_output(updt_stack, 'output_foo'))
212
213 def test_nested_stack_suspend_resume(self):
214 url = self.publish_template(self.nested_name, self.nested_template)
215 self.template = self.test_template.replace('the.yaml', url)
216 stack_identifier = self.stack_create(template=self.template)
Angus Salkelda7500d12015-04-10 15:44:07 +1000217 self.stack_suspend(stack_identifier)
218 self.stack_resume(stack_identifier)