blob: 828ff7486277da61b4626fd2fb415797f362952c [file] [log] [blame]
Angus Salkeld2bd63a42015-01-07 11:11:29 +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 json
14import logging
15import yaml
16
17from heat_integrationtests.common import test
18
19
20LOG = logging.getLogger(__name__)
21
22
23class TemplateResourceTest(test.HeatIntegrationTest):
24 """Prove that we can use the registry in a nested provider."""
25 def setUp(self):
26 super(TemplateResourceTest, self).setUp()
27 self.client = self.orchestration_client
28
29 def test_nested_env(self):
30 main_templ = '''
31heat_template_version: 2013-05-23
32resources:
33 secret1:
34 type: My::NestedSecret
35outputs:
36 secret-out:
37 value: { get_attr: [secret1, value] }
38'''
39
40 nested_templ = '''
41heat_template_version: 2013-05-23
42resources:
43 secret2:
44 type: My::Secret
45outputs:
46 value:
47 value: { get_attr: [secret2, value] }
48'''
49
50 env_templ = '''
51resource_registry:
52 "My::Secret": "OS::Heat::RandomString"
53 "My::NestedSecret": nested.yaml
54'''
55
56 stack_identifier = self.stack_create(
57 template=main_templ,
58 files={'nested.yaml': nested_templ},
59 environment=env_templ)
60 self.assert_resource_is_a_stack(stack_identifier, 'secret1')
61
62 def test_no_infinite_recursion(self):
63 """Prove that we can override a python resource.
64
65 And use that resource within the template resource.
66 """
67
68 main_templ = '''
69heat_template_version: 2013-05-23
70resources:
71 secret1:
72 type: OS::Heat::RandomString
73outputs:
74 secret-out:
75 value: { get_attr: [secret1, value] }
76'''
77
78 nested_templ = '''
79heat_template_version: 2013-05-23
80resources:
81 secret2:
82 type: OS::Heat::RandomString
83outputs:
84 value:
85 value: { get_attr: [secret2, value] }
86'''
87
88 env_templ = '''
89resource_registry:
90 "OS::Heat::RandomString": nested.yaml
91'''
92
93 stack_identifier = self.stack_create(
94 template=main_templ,
95 files={'nested.yaml': nested_templ},
96 environment=env_templ)
97 self.assert_resource_is_a_stack(stack_identifier, 'secret1')
98
99
100class NestedAttributesTest(test.HeatIntegrationTest):
101 """Prove that we can use the template resource references."""
102
103 main_templ = '''
104heat_template_version: 2014-10-16
105resources:
106 secret2:
107 type: My::NestedSecret
108outputs:
109 old_way:
110 value: { get_attr: [secret2, nested_str]}
111 test_attr1:
112 value: { get_attr: [secret2, resource.secret1, value]}
113 test_attr2:
114 value: { get_attr: [secret2, resource.secret1.value]}
115 test_ref:
116 value: { get_resource: secret2 }
117'''
118
119 env_templ = '''
120resource_registry:
121 "My::NestedSecret": nested.yaml
122'''
123
124 def setUp(self):
125 super(NestedAttributesTest, self).setUp()
126 self.client = self.orchestration_client
127
128 def test_stack_ref(self):
129 nested_templ = '''
130heat_template_version: 2014-10-16
131resources:
132 secret1:
133 type: OS::Heat::RandomString
134'''
135 stack_identifier = self.stack_create(
136 template=self.main_templ,
137 files={'nested.yaml': nested_templ},
138 environment=self.env_templ)
139 self.assert_resource_is_a_stack(stack_identifier, 'secret2')
140 stack = self.client.stacks.get(stack_identifier)
141 test_ref = self._stack_output(stack, 'test_ref')
142 self.assertIn('arn:openstack:heat:', test_ref)
143
144 def test_transparent_ref(self):
145 """With the addition of OS::stack_id we can now use the nested resource
146 more transparently.
147 """
148 nested_templ = '''
149heat_template_version: 2014-10-16
150resources:
151 secret1:
152 type: OS::Heat::RandomString
153outputs:
154 OS::stack_id:
155 value: {get_resource: secret1}
156 nested_str:
157 value: {get_attr: [secret1, value]}
158'''
159 stack_identifier = self.stack_create(
160 template=self.main_templ,
161 files={'nested.yaml': nested_templ},
162 environment=self.env_templ)
163 self.assert_resource_is_a_stack(stack_identifier, 'secret2')
164 stack = self.client.stacks.get(stack_identifier)
165 test_ref = self._stack_output(stack, 'test_ref')
166 test_attr = self._stack_output(stack, 'old_way')
167
168 self.assertNotIn('arn:openstack:heat', test_ref)
169 self.assertEqual(test_attr, test_ref)
170
171 def test_nested_attributes(self):
172 nested_templ = '''
173heat_template_version: 2014-10-16
174resources:
175 secret1:
176 type: OS::Heat::RandomString
177outputs:
178 nested_str:
179 value: {get_attr: [secret1, value]}
180'''
181 stack_identifier = self.stack_create(
182 template=self.main_templ,
183 files={'nested.yaml': nested_templ},
184 environment=self.env_templ)
185 self.assert_resource_is_a_stack(stack_identifier, 'secret2')
186 stack = self.client.stacks.get(stack_identifier)
187 old_way = self._stack_output(stack, 'old_way')
188 test_attr1 = self._stack_output(stack, 'test_attr1')
189 test_attr2 = self._stack_output(stack, 'test_attr2')
190
191 self.assertEqual(old_way, test_attr1)
192 self.assertEqual(old_way, test_attr2)
193
194
195class TemplateResourceUpdateTest(test.HeatIntegrationTest):
196 """Prove that we can do template resource updates."""
197
198 main_template = '''
199HeatTemplateFormatVersion: '2012-12-12'
200Resources:
201 the_nested:
202 Type: the.yaml
203 Properties:
204 one: my_name
205
206Outputs:
207 identifier:
208 Value: {Ref: the_nested}
209 value:
210 Value: {'Fn::GetAtt': [the_nested, the_str]}
211'''
212
213 main_template_2 = '''
214HeatTemplateFormatVersion: '2012-12-12'
215Resources:
216 the_nested:
217 Type: the.yaml
218 Properties:
219 one: updated_name
220
221Outputs:
222 identifier:
223 Value: {Ref: the_nested}
224 value:
225 Value: {'Fn::GetAtt': [the_nested, the_str]}
226'''
227
228 initial_tmpl = '''
229HeatTemplateFormatVersion: '2012-12-12'
230Parameters:
231 one:
232 Default: foo
233 Type: String
234Resources:
235 NestedResource:
236 Type: OS::Heat::RandomString
237 Properties:
238 salt: {Ref: one}
239Outputs:
240 the_str:
241 Value: {'Fn::GetAtt': [NestedResource, value]}
242'''
243 prop_change_tmpl = '''
244HeatTemplateFormatVersion: '2012-12-12'
245Parameters:
246 one:
247 Default: yikes
248 Type: String
249 two:
250 Default: foo
251 Type: String
252Resources:
253 NestedResource:
254 Type: OS::Heat::RandomString
255 Properties:
256 salt: {Ref: one}
257Outputs:
258 the_str:
259 Value: {'Fn::GetAtt': [NestedResource, value]}
260'''
261 attr_change_tmpl = '''
262HeatTemplateFormatVersion: '2012-12-12'
263Parameters:
264 one:
265 Default: foo
266 Type: String
267Resources:
268 NestedResource:
269 Type: OS::Heat::RandomString
270 Properties:
271 salt: {Ref: one}
272Outputs:
273 the_str:
274 Value: {'Fn::GetAtt': [NestedResource, value]}
275 something_else:
276 Value: just_a_string
277'''
278 content_change_tmpl = '''
279HeatTemplateFormatVersion: '2012-12-12'
280Parameters:
281 one:
282 Default: foo
283 Type: String
284Resources:
285 NestedResource:
286 Type: OS::Heat::RandomString
287 Properties:
288 salt: yum
289Outputs:
290 the_str:
291 Value: {'Fn::GetAtt': [NestedResource, value]}
292'''
293
294 EXPECTED = (UPDATE, NOCHANGE) = ('update', 'nochange')
295 scenarios = [
296 ('no_changes', dict(template=main_template,
297 provider=initial_tmpl,
298 expect=NOCHANGE)),
299 ('main_tmpl_change', dict(template=main_template_2,
300 provider=initial_tmpl,
301 expect=UPDATE)),
302 ('provider_change', dict(template=main_template,
303 provider=content_change_tmpl,
304 expect=UPDATE)),
305 ('provider_props_change', dict(template=main_template,
306 provider=prop_change_tmpl,
307 expect=NOCHANGE)),
308 ('provider_attr_change', dict(template=main_template,
309 provider=attr_change_tmpl,
310 expect=NOCHANGE)),
311 ]
312
313 def setUp(self):
314 super(TemplateResourceUpdateTest, self).setUp()
315 self.client = self.orchestration_client
316
317 def test_template_resource_update_template_schema(self):
318 stack_identifier = self.stack_create(
319 template=self.main_template,
320 files={'the.yaml': self.initial_tmpl})
321 stack = self.client.stacks.get(stack_identifier)
322 initial_id = self._stack_output(stack, 'identifier')
323 initial_val = self._stack_output(stack, 'value')
324
325 self.update_stack(stack_identifier,
326 self.template,
327 files={'the.yaml': self.provider})
328 stack = self.client.stacks.get(stack_identifier)
329 self.assertEqual(initial_id,
330 self._stack_output(stack, 'identifier'))
331 if self.expect == self.NOCHANGE:
332 self.assertEqual(initial_val,
333 self._stack_output(stack, 'value'))
334 else:
335 self.assertNotEqual(initial_val,
336 self._stack_output(stack, 'value'))
337
338
339class TemplateResourceAdoptTest(test.HeatIntegrationTest):
340 """Prove that we can do template resource adopt/abandon."""
341
342 main_template = '''
343HeatTemplateFormatVersion: '2012-12-12'
344Resources:
345 the_nested:
346 Type: the.yaml
347 Properties:
348 one: my_name
349Outputs:
350 identifier:
351 Value: {Ref: the_nested}
352 value:
353 Value: {'Fn::GetAtt': [the_nested, the_str]}
354'''
355
356 nested_templ = '''
357HeatTemplateFormatVersion: '2012-12-12'
358Parameters:
359 one:
360 Default: foo
361 Type: String
362Resources:
363 RealRandom:
364 Type: OS::Heat::RandomString
365 Properties:
366 salt: {Ref: one}
367Outputs:
368 the_str:
369 Value: {'Fn::GetAtt': [RealRandom, value]}
370'''
371
372 def setUp(self):
373 super(TemplateResourceAdoptTest, self).setUp()
374 self.client = self.orchestration_client
375
376 def _yaml_to_json(self, yaml_templ):
377 return yaml.load(yaml_templ)
378
379 def test_abandon(self):
380 stack_name = self._stack_rand_name()
381 self.client.stacks.create(
382 stack_name=stack_name,
383 template=self.main_template,
384 files={'the.yaml': self.nested_templ},
385 disable_rollback=True,
386 )
387 stack = self.client.stacks.get(stack_name)
388 stack_identifier = '%s/%s' % (stack_name, stack.id)
389 self._wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
390
391 info = self.client.stacks.abandon(stack_id=stack_identifier)
392 self.assertEqual(self._yaml_to_json(self.main_template),
393 info['template'])
394 self.assertEqual(self._yaml_to_json(self.nested_templ),
395 info['resources']['the_nested']['template'])
396
397 def test_adopt(self):
398 data = {
399 'resources': {
400 'the_nested': {
401 "type": "the.yaml",
402 "resources": {
403 "RealRandom": {
404 "type": "OS::Heat::RandomString",
405 'resource_data': {'value': 'goopie'},
406 'resource_id': 'froggy'
407 }
408 }
409 }
410 },
411 "environment": {"parameters": {}},
412 "template": yaml.load(self.main_template)
413 }
414
415 stack_identifier = self.stack_adopt(
416 adopt_data=json.dumps(data),
417 files={'the.yaml': self.nested_templ})
418
419 self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
420 stack = self.client.stacks.get(stack_identifier)
421 self.assertEqual('goopie', self._stack_output(stack, 'value'))