blob: c05912c4ce3c15b9b91f3ae414071f57ad5617ca [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
Pavlo Shchelokovskyy60e0ecd2014-12-14 22:17:21 +020014
Angus Salkeld6a20e3b2015-08-05 13:30:26 +100015from heatclient import exc as heat_exceptions
16import six
Angus Salkeld2bd63a42015-01-07 11:11:29 +100017import yaml
18
19from heat_integrationtests.common import test
Rabi Mishra477efc92015-07-31 13:01:45 +053020from heat_integrationtests.functional import functional_base
Angus Salkeld2bd63a42015-01-07 11:11:29 +100021
22
Rabi Mishra477efc92015-07-31 13:01:45 +053023class TemplateResourceTest(functional_base.FunctionalTestsBase):
Angus Salkeld2bd63a42015-01-07 11:11:29 +100024 """Prove that we can use the registry in a nested provider."""
Angus Salkeld95403d82015-02-12 14:06:01 +100025
26 template = '''
27heat_template_version: 2013-05-23
28resources:
29 secret1:
30 type: OS::Heat::RandomString
31outputs:
32 secret-out:
33 value: { get_attr: [secret1, value] }
34'''
35 nested_templ = '''
36heat_template_version: 2013-05-23
37resources:
38 secret2:
39 type: OS::Heat::RandomString
40outputs:
41 value:
42 value: { get_attr: [secret2, value] }
43'''
44
45 env_templ = '''
46resource_registry:
47 "OS::Heat::RandomString": nested.yaml
48'''
49
Angus Salkeld2bd63a42015-01-07 11:11:29 +100050 def test_nested_env(self):
51 main_templ = '''
52heat_template_version: 2013-05-23
53resources:
54 secret1:
55 type: My::NestedSecret
56outputs:
57 secret-out:
58 value: { get_attr: [secret1, value] }
59'''
60
61 nested_templ = '''
62heat_template_version: 2013-05-23
63resources:
64 secret2:
65 type: My::Secret
66outputs:
67 value:
68 value: { get_attr: [secret2, value] }
69'''
70
71 env_templ = '''
72resource_registry:
73 "My::Secret": "OS::Heat::RandomString"
74 "My::NestedSecret": nested.yaml
75'''
76
77 stack_identifier = self.stack_create(
78 template=main_templ,
79 files={'nested.yaml': nested_templ},
80 environment=env_templ)
Angus Salkeld2e61f9f2015-04-07 09:25:50 +100081 nested_ident = self.assert_resource_is_a_stack(stack_identifier,
82 'secret1')
83 # prove that resource.parent_resource is populated.
84 sec2 = self.client.resources.get(nested_ident, 'secret2')
85 self.assertEqual('secret1', sec2.parent_resource)
Angus Salkeld2bd63a42015-01-07 11:11:29 +100086
87 def test_no_infinite_recursion(self):
88 """Prove that we can override a python resource.
89
90 And use that resource within the template resource.
91 """
Angus Salkeld2bd63a42015-01-07 11:11:29 +100092 stack_identifier = self.stack_create(
Angus Salkeld95403d82015-02-12 14:06:01 +100093 template=self.template,
94 files={'nested.yaml': self.nested_templ},
95 environment=self.env_templ)
Angus Salkeld2bd63a42015-01-07 11:11:29 +100096 self.assert_resource_is_a_stack(stack_identifier, 'secret1')
97
Angus Salkeld95403d82015-02-12 14:06:01 +100098 def test_nested_stack_delete_then_delete_parent_stack(self):
99 """Check the robustness of stack deletion.
100
101 This tests that if you manually delete a nested
102 stack, the parent stack is still deletable.
103 """
Sergey Kraynevbf67ce32015-04-17 10:54:20 -0400104 # disable cleanup so we can call _stack_delete() directly.
105 stack_identifier = self.stack_create(
Angus Salkeld95403d82015-02-12 14:06:01 +1000106 template=self.template,
107 files={'nested.yaml': self.nested_templ},
108 environment=self.env_templ,
Sergey Kraynevbf67ce32015-04-17 10:54:20 -0400109 enable_cleanup=False)
Angus Salkeld95403d82015-02-12 14:06:01 +1000110
111 nested_ident = self.assert_resource_is_a_stack(stack_identifier,
112 'secret1')
113
114 self._stack_delete(nested_ident)
115 self._stack_delete(stack_identifier)
116
Angus Salkeld19b9e1d2015-05-08 11:02:38 +1000117 def test_change_in_file_path(self):
118 stack_identifier = self.stack_create(
119 template=self.template,
120 files={'nested.yaml': self.nested_templ},
121 environment=self.env_templ)
122 stack = self.client.stacks.get(stack_identifier)
123 secret_out1 = self._stack_output(stack, 'secret-out')
124
125 nested_templ_2 = '''
126heat_template_version: 2013-05-23
127resources:
128 secret2:
129 type: OS::Heat::RandomString
130outputs:
131 value:
132 value: freddy
133'''
134 env_templ_2 = '''
135resource_registry:
136 "OS::Heat::RandomString": new/nested.yaml
137'''
138 self.update_stack(stack_identifier,
139 template=self.template,
140 files={'new/nested.yaml': nested_templ_2},
141 environment=env_templ_2)
142 stack = self.client.stacks.get(stack_identifier)
143 secret_out2 = self._stack_output(stack, 'secret-out')
144 self.assertNotEqual(secret_out1, secret_out2)
145 self.assertEqual('freddy', secret_out2)
146
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000147
Rabi Mishra477efc92015-07-31 13:01:45 +0530148class NestedAttributesTest(functional_base.FunctionalTestsBase):
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000149 """Prove that we can use the template resource references."""
150
151 main_templ = '''
152heat_template_version: 2014-10-16
153resources:
154 secret2:
155 type: My::NestedSecret
156outputs:
157 old_way:
158 value: { get_attr: [secret2, nested_str]}
159 test_attr1:
160 value: { get_attr: [secret2, resource.secret1, value]}
161 test_attr2:
162 value: { get_attr: [secret2, resource.secret1.value]}
163 test_ref:
164 value: { get_resource: secret2 }
165'''
166
167 env_templ = '''
168resource_registry:
169 "My::NestedSecret": nested.yaml
170'''
171
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000172 def test_stack_ref(self):
173 nested_templ = '''
174heat_template_version: 2014-10-16
175resources:
176 secret1:
177 type: OS::Heat::RandomString
Angus Salkelda89a0282015-07-24 15:47:38 +1000178outputs:
179 nested_str:
180 value: {get_attr: [secret1, value]}
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000181'''
182 stack_identifier = self.stack_create(
183 template=self.main_templ,
184 files={'nested.yaml': nested_templ},
185 environment=self.env_templ)
186 self.assert_resource_is_a_stack(stack_identifier, 'secret2')
187 stack = self.client.stacks.get(stack_identifier)
188 test_ref = self._stack_output(stack, 'test_ref')
189 self.assertIn('arn:openstack:heat:', test_ref)
190
191 def test_transparent_ref(self):
Peter Razumovskyf0ac9582015-09-24 16:49:03 +0300192 """Test using nested resource more transparently.
193
194 With the addition of OS::stack_id we can now use the nested resource
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000195 more transparently.
196 """
Peter Razumovskyf0ac9582015-09-24 16:49:03 +0300197
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000198 nested_templ = '''
199heat_template_version: 2014-10-16
200resources:
201 secret1:
202 type: OS::Heat::RandomString
203outputs:
204 OS::stack_id:
205 value: {get_resource: secret1}
206 nested_str:
207 value: {get_attr: [secret1, value]}
208'''
209 stack_identifier = self.stack_create(
210 template=self.main_templ,
211 files={'nested.yaml': nested_templ},
212 environment=self.env_templ)
213 self.assert_resource_is_a_stack(stack_identifier, 'secret2')
214 stack = self.client.stacks.get(stack_identifier)
215 test_ref = self._stack_output(stack, 'test_ref')
216 test_attr = self._stack_output(stack, 'old_way')
217
218 self.assertNotIn('arn:openstack:heat', test_ref)
219 self.assertEqual(test_attr, test_ref)
220
221 def test_nested_attributes(self):
222 nested_templ = '''
223heat_template_version: 2014-10-16
224resources:
225 secret1:
226 type: OS::Heat::RandomString
227outputs:
228 nested_str:
229 value: {get_attr: [secret1, value]}
230'''
231 stack_identifier = self.stack_create(
232 template=self.main_templ,
233 files={'nested.yaml': nested_templ},
234 environment=self.env_templ)
235 self.assert_resource_is_a_stack(stack_identifier, 'secret2')
236 stack = self.client.stacks.get(stack_identifier)
237 old_way = self._stack_output(stack, 'old_way')
238 test_attr1 = self._stack_output(stack, 'test_attr1')
239 test_attr2 = self._stack_output(stack, 'test_attr2')
240
241 self.assertEqual(old_way, test_attr1)
242 self.assertEqual(old_way, test_attr2)
243
244
Angus Salkelddd5a6072015-09-02 09:10:04 +1000245class TemplateResourceFacadeTest(functional_base.FunctionalTestsBase):
246 """Prove that we can use ResourceFacade in a HOT template."""
247
248 main_template = '''
249heat_template_version: 2013-05-23
250resources:
251 the_nested:
252 type: the.yaml
253 metadata:
254 foo: bar
255outputs:
256 value:
257 value: {get_attr: [the_nested, output]}
258'''
259
260 nested_templ = '''
261heat_template_version: 2013-05-23
262resources:
263 test:
264 type: OS::Heat::TestResource
265 properties:
266 value: {"Fn::Select": [foo, {resource_facade: metadata}]}
267outputs:
268 output:
269 value: {get_attr: [test, output]}
270 '''
271
272 def test_metadata(self):
273 stack_identifier = self.stack_create(
274 template=self.main_template,
275 files={'the.yaml': self.nested_templ})
276 stack = self.client.stacks.get(stack_identifier)
277 value = self._stack_output(stack, 'value')
278 self.assertEqual('bar', value)
279
280
Rabi Mishra477efc92015-07-31 13:01:45 +0530281class TemplateResourceUpdateTest(functional_base.FunctionalTestsBase):
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000282 """Prove that we can do template resource updates."""
283
284 main_template = '''
285HeatTemplateFormatVersion: '2012-12-12'
286Resources:
287 the_nested:
288 Type: the.yaml
289 Properties:
290 one: my_name
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530291 two: your_name
292Outputs:
293 identifier:
294 Value: {Ref: the_nested}
295 value:
296 Value: {'Fn::GetAtt': [the_nested, the_str]}
297'''
298
299 main_template_change_prop = '''
300HeatTemplateFormatVersion: '2012-12-12'
301Resources:
302 the_nested:
303 Type: the.yaml
304 Properties:
305 one: updated_name
306 two: your_name
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000307
308Outputs:
309 identifier:
310 Value: {Ref: the_nested}
311 value:
312 Value: {'Fn::GetAtt': [the_nested, the_str]}
313'''
314
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530315 main_template_add_prop = '''
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000316HeatTemplateFormatVersion: '2012-12-12'
317Resources:
318 the_nested:
319 Type: the.yaml
320 Properties:
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530321 one: my_name
322 two: your_name
323 three: third_name
324
325Outputs:
326 identifier:
327 Value: {Ref: the_nested}
328 value:
329 Value: {'Fn::GetAtt': [the_nested, the_str]}
330'''
331
332 main_template_remove_prop = '''
333HeatTemplateFormatVersion: '2012-12-12'
334Resources:
335 the_nested:
336 Type: the.yaml
337 Properties:
338 one: my_name
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000339
340Outputs:
341 identifier:
342 Value: {Ref: the_nested}
343 value:
344 Value: {'Fn::GetAtt': [the_nested, the_str]}
345'''
346
347 initial_tmpl = '''
348HeatTemplateFormatVersion: '2012-12-12'
349Parameters:
350 one:
351 Default: foo
352 Type: String
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530353 two:
354 Default: bar
355 Type: String
356
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000357Resources:
358 NestedResource:
359 Type: OS::Heat::RandomString
360 Properties:
361 salt: {Ref: one}
362Outputs:
363 the_str:
364 Value: {'Fn::GetAtt': [NestedResource, value]}
365'''
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530366
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000367 prop_change_tmpl = '''
368HeatTemplateFormatVersion: '2012-12-12'
369Parameters:
370 one:
371 Default: yikes
372 Type: String
373 two:
374 Default: foo
375 Type: String
376Resources:
377 NestedResource:
378 Type: OS::Heat::RandomString
379 Properties:
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530380 salt: {Ref: two}
381Outputs:
382 the_str:
383 Value: {'Fn::GetAtt': [NestedResource, value]}
384'''
385
386 prop_add_tmpl = '''
387HeatTemplateFormatVersion: '2012-12-12'
388Parameters:
389 one:
390 Default: yikes
391 Type: String
392 two:
393 Default: foo
394 Type: String
395 three:
396 Default: bar
397 Type: String
398
399Resources:
400 NestedResource:
401 Type: OS::Heat::RandomString
402 Properties:
403 salt: {Ref: three}
404Outputs:
405 the_str:
406 Value: {'Fn::GetAtt': [NestedResource, value]}
407'''
408
409 prop_remove_tmpl = '''
410HeatTemplateFormatVersion: '2012-12-12'
411Parameters:
412 one:
413 Default: yikes
414 Type: String
415
416Resources:
417 NestedResource:
418 Type: OS::Heat::RandomString
419 Properties:
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000420 salt: {Ref: one}
421Outputs:
422 the_str:
423 Value: {'Fn::GetAtt': [NestedResource, value]}
424'''
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530425
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000426 attr_change_tmpl = '''
427HeatTemplateFormatVersion: '2012-12-12'
428Parameters:
429 one:
430 Default: foo
431 Type: String
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530432 two:
433 Default: bar
434 Type: String
435
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000436Resources:
437 NestedResource:
438 Type: OS::Heat::RandomString
439 Properties:
440 salt: {Ref: one}
441Outputs:
442 the_str:
443 Value: {'Fn::GetAtt': [NestedResource, value]}
444 something_else:
445 Value: just_a_string
446'''
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530447
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000448 content_change_tmpl = '''
449HeatTemplateFormatVersion: '2012-12-12'
450Parameters:
451 one:
452 Default: foo
453 Type: String
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530454 two:
455 Default: bar
456 Type: String
457
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000458Resources:
459 NestedResource:
460 Type: OS::Heat::RandomString
461 Properties:
462 salt: yum
463Outputs:
464 the_str:
465 Value: {'Fn::GetAtt': [NestedResource, value]}
466'''
467
468 EXPECTED = (UPDATE, NOCHANGE) = ('update', 'nochange')
469 scenarios = [
470 ('no_changes', dict(template=main_template,
471 provider=initial_tmpl,
472 expect=NOCHANGE)),
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530473 ('main_tmpl_change', dict(template=main_template_change_prop,
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000474 provider=initial_tmpl,
475 expect=UPDATE)),
476 ('provider_change', dict(template=main_template,
477 provider=content_change_tmpl,
478 expect=UPDATE)),
479 ('provider_props_change', dict(template=main_template,
480 provider=prop_change_tmpl,
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530481 expect=UPDATE)),
482 ('provider_props_add', dict(template=main_template_add_prop,
483 provider=prop_add_tmpl,
484 expect=UPDATE)),
485 ('provider_props_remove', dict(template=main_template_remove_prop,
486 provider=prop_remove_tmpl,
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000487 expect=NOCHANGE)),
488 ('provider_attr_change', dict(template=main_template,
489 provider=attr_change_tmpl,
490 expect=NOCHANGE)),
491 ]
492
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000493 def test_template_resource_update_template_schema(self):
494 stack_identifier = self.stack_create(
495 template=self.main_template,
496 files={'the.yaml': self.initial_tmpl})
497 stack = self.client.stacks.get(stack_identifier)
498 initial_id = self._stack_output(stack, 'identifier')
499 initial_val = self._stack_output(stack, 'value')
500
501 self.update_stack(stack_identifier,
502 self.template,
503 files={'the.yaml': self.provider})
504 stack = self.client.stacks.get(stack_identifier)
505 self.assertEqual(initial_id,
506 self._stack_output(stack, 'identifier'))
507 if self.expect == self.NOCHANGE:
508 self.assertEqual(initial_val,
509 self._stack_output(stack, 'value'))
510 else:
511 self.assertNotEqual(initial_val,
512 self._stack_output(stack, 'value'))
513
514
Rabi Mishra477efc92015-07-31 13:01:45 +0530515class TemplateResourceUpdateFailedTest(functional_base.FunctionalTestsBase):
Angus Salkeld5a3e1dd2015-02-03 15:31:47 +1000516 """Prove that we can do updates on a nested stack to fix a stack."""
Peter Razumovskyf0ac9582015-09-24 16:49:03 +0300517
Angus Salkeld5a3e1dd2015-02-03 15:31:47 +1000518 main_template = '''
519HeatTemplateFormatVersion: '2012-12-12'
520Resources:
521 keypair:
522 Type: OS::Nova::KeyPair
523 Properties:
524 name: replace-this
525 save_private_key: false
526 server:
527 Type: server_fail.yaml
528 DependsOn: keypair
529'''
530 nested_templ = '''
531HeatTemplateFormatVersion: '2012-12-12'
532Resources:
533 RealRandom:
534 Type: OS::Heat::RandomString
535'''
536
537 def setUp(self):
538 super(TemplateResourceUpdateFailedTest, self).setUp()
Sergey Krayneva265c132015-02-13 03:51:03 -0500539 self.assign_keypair()
Angus Salkeld5a3e1dd2015-02-03 15:31:47 +1000540
541 def test_update_on_failed_create(self):
Vikas Jainac6b02f2015-02-11 11:31:46 -0800542 # create a stack with "server" dependent on "keypair", but
Angus Salkeld5a3e1dd2015-02-03 15:31:47 +1000543 # keypair fails, so "server" is not created properly.
544 # We then fix the template and it should succeed.
545 broken_templ = self.main_template.replace('replace-this',
546 self.keypair_name)
547 stack_identifier = self.stack_create(
548 template=broken_templ,
549 files={'server_fail.yaml': self.nested_templ},
550 expected_status='CREATE_FAILED')
551
552 fixed_templ = self.main_template.replace('replace-this',
553 test.rand_name())
554 self.update_stack(stack_identifier,
555 fixed_templ,
556 files={'server_fail.yaml': self.nested_templ})
557
558
Rabi Mishra477efc92015-07-31 13:01:45 +0530559class TemplateResourceAdoptTest(functional_base.FunctionalTestsBase):
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000560 """Prove that we can do template resource adopt/abandon."""
561
562 main_template = '''
563HeatTemplateFormatVersion: '2012-12-12'
564Resources:
565 the_nested:
566 Type: the.yaml
567 Properties:
568 one: my_name
569Outputs:
570 identifier:
571 Value: {Ref: the_nested}
572 value:
573 Value: {'Fn::GetAtt': [the_nested, the_str]}
574'''
575
576 nested_templ = '''
577HeatTemplateFormatVersion: '2012-12-12'
578Parameters:
579 one:
580 Default: foo
581 Type: String
582Resources:
583 RealRandom:
584 Type: OS::Heat::RandomString
585 Properties:
586 salt: {Ref: one}
587Outputs:
588 the_str:
589 Value: {'Fn::GetAtt': [RealRandom, value]}
590'''
591
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000592 def _yaml_to_json(self, yaml_templ):
Bo Wangd8df4dd2016-02-16 21:23:53 +0800593 return yaml.safe_load(yaml_templ)
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000594
595 def test_abandon(self):
Sergey Kraynevbf67ce32015-04-17 10:54:20 -0400596 stack_identifier = self.stack_create(
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000597 template=self.main_template,
598 files={'the.yaml': self.nested_templ},
Sergey Kraynevbf67ce32015-04-17 10:54:20 -0400599 enable_cleanup=False
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000600 )
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000601
Sirushti Murugesan04ee8022015-02-02 23:00:23 +0530602 info = self.stack_abandon(stack_id=stack_identifier)
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000603 self.assertEqual(self._yaml_to_json(self.main_template),
604 info['template'])
605 self.assertEqual(self._yaml_to_json(self.nested_templ),
606 info['resources']['the_nested']['template'])
Kanagaraj Manickam6b378ab2015-05-11 17:34:43 +0530607 # TODO(james combs): Implement separate test cases for export
608 # once export REST API is available. Also test reverse order
609 # of invocation: export -> abandon AND abandon -> export
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000610
611 def test_adopt(self):
612 data = {
613 'resources': {
614 'the_nested': {
615 "type": "the.yaml",
616 "resources": {
617 "RealRandom": {
618 "type": "OS::Heat::RandomString",
619 'resource_data': {'value': 'goopie'},
620 'resource_id': 'froggy'
621 }
622 }
623 }
624 },
625 "environment": {"parameters": {}},
Bo Wangd8df4dd2016-02-16 21:23:53 +0800626 "template": yaml.safe_load(self.main_template)
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000627 }
628
629 stack_identifier = self.stack_adopt(
630 adopt_data=json.dumps(data),
631 files={'the.yaml': self.nested_templ})
632
633 self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
634 stack = self.client.stacks.get(stack_identifier)
635 self.assertEqual('goopie', self._stack_output(stack, 'value'))
Angus Salkeld87601722015-01-05 14:57:27 +1000636
637
Rabi Mishra477efc92015-07-31 13:01:45 +0530638class TemplateResourceCheckTest(functional_base.FunctionalTestsBase):
Angus Salkeld87601722015-01-05 14:57:27 +1000639 """Prove that we can do template resource check."""
640
641 main_template = '''
642HeatTemplateFormatVersion: '2012-12-12'
643Resources:
644 the_nested:
645 Type: the.yaml
646 Properties:
647 one: my_name
648Outputs:
649 identifier:
650 Value: {Ref: the_nested}
651 value:
652 Value: {'Fn::GetAtt': [the_nested, the_str]}
653'''
654
655 nested_templ = '''
656HeatTemplateFormatVersion: '2012-12-12'
657Parameters:
658 one:
659 Default: foo
660 Type: String
661Resources:
662 RealRandom:
663 Type: OS::Heat::RandomString
664 Properties:
665 salt: {Ref: one}
666Outputs:
667 the_str:
668 Value: {'Fn::GetAtt': [RealRandom, value]}
669'''
670
Angus Salkeld87601722015-01-05 14:57:27 +1000671 def test_check(self):
Sergey Kraynevbf67ce32015-04-17 10:54:20 -0400672 stack_identifier = self.stack_create(
Angus Salkeld87601722015-01-05 14:57:27 +1000673 template=self.main_template,
Sergey Kraynevbf67ce32015-04-17 10:54:20 -0400674 files={'the.yaml': self.nested_templ}
Angus Salkeld87601722015-01-05 14:57:27 +1000675 )
Angus Salkeld87601722015-01-05 14:57:27 +1000676
677 self.client.actions.check(stack_id=stack_identifier)
678 self._wait_for_stack_status(stack_identifier, 'CHECK_COMPLETE')
Angus Salkeld793b0fc2015-06-24 08:52:08 +1000679
680
Rabi Mishra477efc92015-07-31 13:01:45 +0530681class TemplateResourceErrorMessageTest(functional_base.FunctionalTestsBase):
Angus Salkeld793b0fc2015-06-24 08:52:08 +1000682 """Prove that nested stack errors don't suck."""
Peter Razumovskyf0ac9582015-09-24 16:49:03 +0300683
Angus Salkeld793b0fc2015-06-24 08:52:08 +1000684 template = '''
685HeatTemplateFormatVersion: '2012-12-12'
686Resources:
687 victim:
688 Type: fail.yaml
689'''
690 nested_templ = '''
691HeatTemplateFormatVersion: '2012-12-12'
692Resources:
693 oops:
694 Type: OS::Heat::TestResource
695 Properties:
696 fail: true
697 wait_secs: 2
698'''
699
Angus Salkeld793b0fc2015-06-24 08:52:08 +1000700 def test_fail(self):
701 stack_identifier = self.stack_create(
702 template=self.template,
703 files={'fail.yaml': self.nested_templ},
704 expected_status='CREATE_FAILED')
705 stack = self.client.stacks.get(stack_identifier)
706
707 exp_path = 'resources.victim.resources.oops'
708 exp_msg = 'Test Resource failed oops'
709 exp = 'Resource CREATE failed: ValueError: %s: %s' % (exp_path,
710 exp_msg)
711 self.assertEqual(exp, stack.stack_status_reason)
kairat_kushaev61a99e12015-07-31 16:22:45 +0300712
713
Rabi Mishra477efc92015-07-31 13:01:45 +0530714class TemplateResourceSuspendResumeTest(functional_base.FunctionalTestsBase):
kairat_kushaev61a99e12015-07-31 16:22:45 +0300715 """Prove that we can do template resource suspend/resume."""
716
717 main_template = '''
718heat_template_version: 2014-10-16
719parameters:
720resources:
721 the_nested:
722 type: the.yaml
723'''
724
725 nested_templ = '''
726heat_template_version: 2014-10-16
727resources:
728 test_random_string:
729 type: OS::Heat::RandomString
730'''
731
kairat_kushaev61a99e12015-07-31 16:22:45 +0300732 def test_suspend_resume(self):
Peter Razumovskyf0ac9582015-09-24 16:49:03 +0300733 """Basic test for template resource suspend resume."""
kairat_kushaev61a99e12015-07-31 16:22:45 +0300734 stack_identifier = self.stack_create(
735 template=self.main_template,
736 files={'the.yaml': self.nested_templ}
737 )
738
739 self.stack_suspend(stack_identifier=stack_identifier)
740 self.stack_resume(stack_identifier=stack_identifier)
Angus Salkeld6a20e3b2015-08-05 13:30:26 +1000741
742
Stefan Nica4750ea42017-06-20 14:45:14 +0200743class ValidateFacadeTest(functional_base.FunctionalTestsBase):
Angus Salkeld6a20e3b2015-08-05 13:30:26 +1000744 """Prove that nested stack errors don't suck."""
Peter Razumovskyf0ac9582015-09-24 16:49:03 +0300745
Angus Salkeld6a20e3b2015-08-05 13:30:26 +1000746 template = '''
747heat_template_version: 2015-10-15
748resources:
749 thisone:
750 type: OS::Thingy
751 properties:
752 one: pre
753 two: post
754outputs:
755 one:
756 value: {get_attr: [thisone, here-it-is]}
757'''
758 templ_facade = '''
759heat_template_version: 2015-04-30
760parameters:
761 one:
762 type: string
763 two:
764 type: string
765outputs:
766 here-it-is:
767 value: noop
768'''
769 env = '''
770resource_registry:
771 OS::Thingy: facade.yaml
772 resources:
773 thisone:
774 OS::Thingy: concrete.yaml
775'''
776
777 def setUp(self):
778 super(ValidateFacadeTest, self).setUp()
779 self.client = self.orchestration_client
780
781 def test_missing_param(self):
782 templ_missing_parameter = '''
783heat_template_version: 2015-04-30
784parameters:
785 one:
786 type: string
787resources:
788 str:
789 type: OS::Heat::RandomString
790outputs:
791 here-it-is:
792 value:
793 not-important
794'''
795 try:
796 self.stack_create(
797 template=self.template,
798 environment=self.env,
799 files={'facade.yaml': self.templ_facade,
800 'concrete.yaml': templ_missing_parameter},
801 expected_status='CREATE_FAILED')
802 except heat_exceptions.HTTPBadRequest as exc:
803 exp = ('ERROR: Required property two for facade '
804 'OS::Thingy missing in provider')
805 self.assertEqual(exp, six.text_type(exc))
806
807 def test_missing_output(self):
808 templ_missing_output = '''
809heat_template_version: 2015-04-30
810parameters:
811 one:
812 type: string
813 two:
814 type: string
815resources:
816 str:
817 type: OS::Heat::RandomString
818'''
819 try:
820 self.stack_create(
821 template=self.template,
822 environment=self.env,
823 files={'facade.yaml': self.templ_facade,
824 'concrete.yaml': templ_missing_output},
825 expected_status='CREATE_FAILED')
826 except heat_exceptions.HTTPBadRequest as exc:
827 exp = ('ERROR: Attribute here-it-is for facade '
828 'OS::Thingy missing in provider')
829 self.assertEqual(exp, six.text_type(exc))
Thomas Herve35571422016-02-09 18:33:19 +0100830
831
832class TemplateResourceNewParamTest(functional_base.FunctionalTestsBase):
833
834 main_template = '''
835heat_template_version: 2013-05-23
836resources:
837 my_resource:
838 type: resource.yaml
839 properties:
840 value1: foo
841'''
842 nested_templ = '''
843heat_template_version: 2013-05-23
844parameters:
845 value1:
846 type: string
847resources:
848 test:
849 type: OS::Heat::TestResource
850 properties:
851 value: {get_param: value1}
852'''
853 main_template_update = '''
854heat_template_version: 2013-05-23
855resources:
856 my_resource:
857 type: resource.yaml
858 properties:
859 value1: foo
860 value2: foo
861'''
862 nested_templ_update_fail = '''
863heat_template_version: 2013-05-23
864parameters:
865 value1:
866 type: string
867 value2:
868 type: string
869resources:
870 test:
871 type: OS::Heat::TestResource
872 properties:
873 fail: True
874 value:
875 str_replace:
876 template: VAL1-VAL2
877 params:
878 VAL1: {get_param: value1}
879 VAL2: {get_param: value2}
880'''
881 nested_templ_update = '''
882heat_template_version: 2013-05-23
883parameters:
884 value1:
885 type: string
886 value2:
887 type: string
888resources:
889 test:
890 type: OS::Heat::TestResource
891 properties:
892 value:
893 str_replace:
894 template: VAL1-VAL2
895 params:
896 VAL1: {get_param: value1}
897 VAL2: {get_param: value2}
898'''
899
900 def test_update(self):
901 stack_identifier = self.stack_create(
902 template=self.main_template,
903 files={'resource.yaml': self.nested_templ})
904
905 # Make the update fails with the new parameter inserted.
906 self.update_stack(
907 stack_identifier,
908 self.main_template_update,
909 files={'resource.yaml': self.nested_templ_update_fail},
910 expected_status='UPDATE_FAILED')
911
912 # Fix the update, it should succeed now.
913 self.update_stack(
914 stack_identifier,
915 self.main_template_update,
916 files={'resource.yaml': self.nested_templ_update})
Thomas Herved3e82372016-03-17 16:03:08 +0100917
918
919class TemplateResourceRemovedParamTest(functional_base.FunctionalTestsBase):
920
921 main_template = '''
922heat_template_version: 2013-05-23
923parameters:
924 value1:
925 type: string
926 default: foo
927resources:
928 my_resource:
929 type: resource.yaml
930 properties:
931 value1: {get_param: value1}
932'''
933 nested_templ = '''
934heat_template_version: 2013-05-23
935parameters:
936 value1:
937 type: string
938 default: foo
939resources:
940 test:
941 type: OS::Heat::TestResource
942 properties:
943 value: {get_param: value1}
944'''
945 main_template_update = '''
946heat_template_version: 2013-05-23
947resources:
948 my_resource:
949 type: resource.yaml
950'''
951 nested_templ_update = '''
952heat_template_version: 2013-05-23
953parameters:
954 value1:
955 type: string
956 default: foo
957 value2:
958 type: string
959 default: bar
960resources:
961 test:
962 type: OS::Heat::TestResource
963 properties:
964 value:
965 str_replace:
966 template: VAL1-VAL2
967 params:
968 VAL1: {get_param: value1}
969 VAL2: {get_param: value2}
970'''
971
972 def test_update(self):
973 stack_identifier = self.stack_create(
974 template=self.main_template,
975 environment={'parameters': {'value1': 'spam'}},
976 files={'resource.yaml': self.nested_templ})
977
978 self.update_stack(
979 stack_identifier,
980 self.main_template_update,
981 environment={'parameter_defaults': {'value2': 'egg'}},
982 files={'resource.yaml': self.nested_templ_update}, existing=True)