blob: 9249a6e7b976869cfd08ce607bb47cc6b3b8c1ad [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 setUp(self):
51 super(TemplateResourceTest, self).setUp()
Angus Salkeld2bd63a42015-01-07 11:11:29 +100052
53 def test_nested_env(self):
54 main_templ = '''
55heat_template_version: 2013-05-23
56resources:
57 secret1:
58 type: My::NestedSecret
59outputs:
60 secret-out:
61 value: { get_attr: [secret1, value] }
62'''
63
64 nested_templ = '''
65heat_template_version: 2013-05-23
66resources:
67 secret2:
68 type: My::Secret
69outputs:
70 value:
71 value: { get_attr: [secret2, value] }
72'''
73
74 env_templ = '''
75resource_registry:
76 "My::Secret": "OS::Heat::RandomString"
77 "My::NestedSecret": nested.yaml
78'''
79
80 stack_identifier = self.stack_create(
81 template=main_templ,
82 files={'nested.yaml': nested_templ},
83 environment=env_templ)
Angus Salkeld2e61f9f2015-04-07 09:25:50 +100084 nested_ident = self.assert_resource_is_a_stack(stack_identifier,
85 'secret1')
86 # prove that resource.parent_resource is populated.
87 sec2 = self.client.resources.get(nested_ident, 'secret2')
88 self.assertEqual('secret1', sec2.parent_resource)
Angus Salkeld2bd63a42015-01-07 11:11:29 +100089
90 def test_no_infinite_recursion(self):
91 """Prove that we can override a python resource.
92
93 And use that resource within the template resource.
94 """
Angus Salkeld2bd63a42015-01-07 11:11:29 +100095 stack_identifier = self.stack_create(
Angus Salkeld95403d82015-02-12 14:06:01 +100096 template=self.template,
97 files={'nested.yaml': self.nested_templ},
98 environment=self.env_templ)
Angus Salkeld2bd63a42015-01-07 11:11:29 +100099 self.assert_resource_is_a_stack(stack_identifier, 'secret1')
100
Angus Salkeld95403d82015-02-12 14:06:01 +1000101 def test_nested_stack_delete_then_delete_parent_stack(self):
102 """Check the robustness of stack deletion.
103
104 This tests that if you manually delete a nested
105 stack, the parent stack is still deletable.
106 """
Sergey Kraynevbf67ce32015-04-17 10:54:20 -0400107 # disable cleanup so we can call _stack_delete() directly.
108 stack_identifier = self.stack_create(
Angus Salkeld95403d82015-02-12 14:06:01 +1000109 template=self.template,
110 files={'nested.yaml': self.nested_templ},
111 environment=self.env_templ,
Sergey Kraynevbf67ce32015-04-17 10:54:20 -0400112 enable_cleanup=False)
Angus Salkeld95403d82015-02-12 14:06:01 +1000113
114 nested_ident = self.assert_resource_is_a_stack(stack_identifier,
115 'secret1')
116
117 self._stack_delete(nested_ident)
118 self._stack_delete(stack_identifier)
119
Angus Salkeld19b9e1d2015-05-08 11:02:38 +1000120 def test_change_in_file_path(self):
121 stack_identifier = self.stack_create(
122 template=self.template,
123 files={'nested.yaml': self.nested_templ},
124 environment=self.env_templ)
125 stack = self.client.stacks.get(stack_identifier)
126 secret_out1 = self._stack_output(stack, 'secret-out')
127
128 nested_templ_2 = '''
129heat_template_version: 2013-05-23
130resources:
131 secret2:
132 type: OS::Heat::RandomString
133outputs:
134 value:
135 value: freddy
136'''
137 env_templ_2 = '''
138resource_registry:
139 "OS::Heat::RandomString": new/nested.yaml
140'''
141 self.update_stack(stack_identifier,
142 template=self.template,
143 files={'new/nested.yaml': nested_templ_2},
144 environment=env_templ_2)
145 stack = self.client.stacks.get(stack_identifier)
146 secret_out2 = self._stack_output(stack, 'secret-out')
147 self.assertNotEqual(secret_out1, secret_out2)
148 self.assertEqual('freddy', secret_out2)
149
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000150
Rabi Mishra477efc92015-07-31 13:01:45 +0530151class NestedAttributesTest(functional_base.FunctionalTestsBase):
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000152 """Prove that we can use the template resource references."""
153
154 main_templ = '''
155heat_template_version: 2014-10-16
156resources:
157 secret2:
158 type: My::NestedSecret
159outputs:
160 old_way:
161 value: { get_attr: [secret2, nested_str]}
162 test_attr1:
163 value: { get_attr: [secret2, resource.secret1, value]}
164 test_attr2:
165 value: { get_attr: [secret2, resource.secret1.value]}
166 test_ref:
167 value: { get_resource: secret2 }
168'''
169
170 env_templ = '''
171resource_registry:
172 "My::NestedSecret": nested.yaml
173'''
174
175 def setUp(self):
176 super(NestedAttributesTest, self).setUp()
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000177
178 def test_stack_ref(self):
179 nested_templ = '''
180heat_template_version: 2014-10-16
181resources:
182 secret1:
183 type: OS::Heat::RandomString
Angus Salkelda89a0282015-07-24 15:47:38 +1000184outputs:
185 nested_str:
186 value: {get_attr: [secret1, value]}
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000187'''
188 stack_identifier = self.stack_create(
189 template=self.main_templ,
190 files={'nested.yaml': nested_templ},
191 environment=self.env_templ)
192 self.assert_resource_is_a_stack(stack_identifier, 'secret2')
193 stack = self.client.stacks.get(stack_identifier)
194 test_ref = self._stack_output(stack, 'test_ref')
195 self.assertIn('arn:openstack:heat:', test_ref)
196
197 def test_transparent_ref(self):
Peter Razumovskyf0ac9582015-09-24 16:49:03 +0300198 """Test using nested resource more transparently.
199
200 With the addition of OS::stack_id we can now use the nested resource
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000201 more transparently.
202 """
Peter Razumovskyf0ac9582015-09-24 16:49:03 +0300203
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000204 nested_templ = '''
205heat_template_version: 2014-10-16
206resources:
207 secret1:
208 type: OS::Heat::RandomString
209outputs:
210 OS::stack_id:
211 value: {get_resource: secret1}
212 nested_str:
213 value: {get_attr: [secret1, value]}
214'''
215 stack_identifier = self.stack_create(
216 template=self.main_templ,
217 files={'nested.yaml': nested_templ},
218 environment=self.env_templ)
219 self.assert_resource_is_a_stack(stack_identifier, 'secret2')
220 stack = self.client.stacks.get(stack_identifier)
221 test_ref = self._stack_output(stack, 'test_ref')
222 test_attr = self._stack_output(stack, 'old_way')
223
224 self.assertNotIn('arn:openstack:heat', test_ref)
225 self.assertEqual(test_attr, test_ref)
226
227 def test_nested_attributes(self):
228 nested_templ = '''
229heat_template_version: 2014-10-16
230resources:
231 secret1:
232 type: OS::Heat::RandomString
233outputs:
234 nested_str:
235 value: {get_attr: [secret1, value]}
236'''
237 stack_identifier = self.stack_create(
238 template=self.main_templ,
239 files={'nested.yaml': nested_templ},
240 environment=self.env_templ)
241 self.assert_resource_is_a_stack(stack_identifier, 'secret2')
242 stack = self.client.stacks.get(stack_identifier)
243 old_way = self._stack_output(stack, 'old_way')
244 test_attr1 = self._stack_output(stack, 'test_attr1')
245 test_attr2 = self._stack_output(stack, 'test_attr2')
246
247 self.assertEqual(old_way, test_attr1)
248 self.assertEqual(old_way, test_attr2)
249
250
Angus Salkelddd5a6072015-09-02 09:10:04 +1000251class TemplateResourceFacadeTest(functional_base.FunctionalTestsBase):
252 """Prove that we can use ResourceFacade in a HOT template."""
253
254 main_template = '''
255heat_template_version: 2013-05-23
256resources:
257 the_nested:
258 type: the.yaml
259 metadata:
260 foo: bar
261outputs:
262 value:
263 value: {get_attr: [the_nested, output]}
264'''
265
266 nested_templ = '''
267heat_template_version: 2013-05-23
268resources:
269 test:
270 type: OS::Heat::TestResource
271 properties:
272 value: {"Fn::Select": [foo, {resource_facade: metadata}]}
273outputs:
274 output:
275 value: {get_attr: [test, output]}
276 '''
277
278 def test_metadata(self):
279 stack_identifier = self.stack_create(
280 template=self.main_template,
281 files={'the.yaml': self.nested_templ})
282 stack = self.client.stacks.get(stack_identifier)
283 value = self._stack_output(stack, 'value')
284 self.assertEqual('bar', value)
285
286
Rabi Mishra477efc92015-07-31 13:01:45 +0530287class TemplateResourceUpdateTest(functional_base.FunctionalTestsBase):
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000288 """Prove that we can do template resource updates."""
289
290 main_template = '''
291HeatTemplateFormatVersion: '2012-12-12'
292Resources:
293 the_nested:
294 Type: the.yaml
295 Properties:
296 one: my_name
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530297 two: your_name
298Outputs:
299 identifier:
300 Value: {Ref: the_nested}
301 value:
302 Value: {'Fn::GetAtt': [the_nested, the_str]}
303'''
304
305 main_template_change_prop = '''
306HeatTemplateFormatVersion: '2012-12-12'
307Resources:
308 the_nested:
309 Type: the.yaml
310 Properties:
311 one: updated_name
312 two: your_name
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000313
314Outputs:
315 identifier:
316 Value: {Ref: the_nested}
317 value:
318 Value: {'Fn::GetAtt': [the_nested, the_str]}
319'''
320
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530321 main_template_add_prop = '''
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000322HeatTemplateFormatVersion: '2012-12-12'
323Resources:
324 the_nested:
325 Type: the.yaml
326 Properties:
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530327 one: my_name
328 two: your_name
329 three: third_name
330
331Outputs:
332 identifier:
333 Value: {Ref: the_nested}
334 value:
335 Value: {'Fn::GetAtt': [the_nested, the_str]}
336'''
337
338 main_template_remove_prop = '''
339HeatTemplateFormatVersion: '2012-12-12'
340Resources:
341 the_nested:
342 Type: the.yaml
343 Properties:
344 one: my_name
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000345
346Outputs:
347 identifier:
348 Value: {Ref: the_nested}
349 value:
350 Value: {'Fn::GetAtt': [the_nested, the_str]}
351'''
352
353 initial_tmpl = '''
354HeatTemplateFormatVersion: '2012-12-12'
355Parameters:
356 one:
357 Default: foo
358 Type: String
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530359 two:
360 Default: bar
361 Type: String
362
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000363Resources:
364 NestedResource:
365 Type: OS::Heat::RandomString
366 Properties:
367 salt: {Ref: one}
368Outputs:
369 the_str:
370 Value: {'Fn::GetAtt': [NestedResource, value]}
371'''
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530372
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000373 prop_change_tmpl = '''
374HeatTemplateFormatVersion: '2012-12-12'
375Parameters:
376 one:
377 Default: yikes
378 Type: String
379 two:
380 Default: foo
381 Type: String
382Resources:
383 NestedResource:
384 Type: OS::Heat::RandomString
385 Properties:
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530386 salt: {Ref: two}
387Outputs:
388 the_str:
389 Value: {'Fn::GetAtt': [NestedResource, value]}
390'''
391
392 prop_add_tmpl = '''
393HeatTemplateFormatVersion: '2012-12-12'
394Parameters:
395 one:
396 Default: yikes
397 Type: String
398 two:
399 Default: foo
400 Type: String
401 three:
402 Default: bar
403 Type: String
404
405Resources:
406 NestedResource:
407 Type: OS::Heat::RandomString
408 Properties:
409 salt: {Ref: three}
410Outputs:
411 the_str:
412 Value: {'Fn::GetAtt': [NestedResource, value]}
413'''
414
415 prop_remove_tmpl = '''
416HeatTemplateFormatVersion: '2012-12-12'
417Parameters:
418 one:
419 Default: yikes
420 Type: String
421
422Resources:
423 NestedResource:
424 Type: OS::Heat::RandomString
425 Properties:
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000426 salt: {Ref: one}
427Outputs:
428 the_str:
429 Value: {'Fn::GetAtt': [NestedResource, value]}
430'''
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530431
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000432 attr_change_tmpl = '''
433HeatTemplateFormatVersion: '2012-12-12'
434Parameters:
435 one:
436 Default: foo
437 Type: String
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530438 two:
439 Default: bar
440 Type: String
441
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000442Resources:
443 NestedResource:
444 Type: OS::Heat::RandomString
445 Properties:
446 salt: {Ref: one}
447Outputs:
448 the_str:
449 Value: {'Fn::GetAtt': [NestedResource, value]}
450 something_else:
451 Value: just_a_string
452'''
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530453
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000454 content_change_tmpl = '''
455HeatTemplateFormatVersion: '2012-12-12'
456Parameters:
457 one:
458 Default: foo
459 Type: String
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530460 two:
461 Default: bar
462 Type: String
463
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000464Resources:
465 NestedResource:
466 Type: OS::Heat::RandomString
467 Properties:
468 salt: yum
469Outputs:
470 the_str:
471 Value: {'Fn::GetAtt': [NestedResource, value]}
472'''
473
474 EXPECTED = (UPDATE, NOCHANGE) = ('update', 'nochange')
475 scenarios = [
476 ('no_changes', dict(template=main_template,
477 provider=initial_tmpl,
478 expect=NOCHANGE)),
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530479 ('main_tmpl_change', dict(template=main_template_change_prop,
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000480 provider=initial_tmpl,
481 expect=UPDATE)),
482 ('provider_change', dict(template=main_template,
483 provider=content_change_tmpl,
484 expect=UPDATE)),
485 ('provider_props_change', dict(template=main_template,
486 provider=prop_change_tmpl,
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530487 expect=UPDATE)),
488 ('provider_props_add', dict(template=main_template_add_prop,
489 provider=prop_add_tmpl,
490 expect=UPDATE)),
491 ('provider_props_remove', dict(template=main_template_remove_prop,
492 provider=prop_remove_tmpl,
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000493 expect=NOCHANGE)),
494 ('provider_attr_change', dict(template=main_template,
495 provider=attr_change_tmpl,
496 expect=NOCHANGE)),
497 ]
498
499 def setUp(self):
500 super(TemplateResourceUpdateTest, self).setUp()
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000501
502 def test_template_resource_update_template_schema(self):
503 stack_identifier = self.stack_create(
504 template=self.main_template,
505 files={'the.yaml': self.initial_tmpl})
506 stack = self.client.stacks.get(stack_identifier)
507 initial_id = self._stack_output(stack, 'identifier')
508 initial_val = self._stack_output(stack, 'value')
509
510 self.update_stack(stack_identifier,
511 self.template,
512 files={'the.yaml': self.provider})
513 stack = self.client.stacks.get(stack_identifier)
514 self.assertEqual(initial_id,
515 self._stack_output(stack, 'identifier'))
516 if self.expect == self.NOCHANGE:
517 self.assertEqual(initial_val,
518 self._stack_output(stack, 'value'))
519 else:
520 self.assertNotEqual(initial_val,
521 self._stack_output(stack, 'value'))
522
523
Rabi Mishra477efc92015-07-31 13:01:45 +0530524class TemplateResourceUpdateFailedTest(functional_base.FunctionalTestsBase):
Angus Salkeld5a3e1dd2015-02-03 15:31:47 +1000525 """Prove that we can do updates on a nested stack to fix a stack."""
Peter Razumovskyf0ac9582015-09-24 16:49:03 +0300526
Angus Salkeld5a3e1dd2015-02-03 15:31:47 +1000527 main_template = '''
528HeatTemplateFormatVersion: '2012-12-12'
529Resources:
530 keypair:
531 Type: OS::Nova::KeyPair
532 Properties:
533 name: replace-this
534 save_private_key: false
535 server:
536 Type: server_fail.yaml
537 DependsOn: keypair
538'''
539 nested_templ = '''
540HeatTemplateFormatVersion: '2012-12-12'
541Resources:
542 RealRandom:
543 Type: OS::Heat::RandomString
544'''
545
546 def setUp(self):
547 super(TemplateResourceUpdateFailedTest, self).setUp()
Sergey Krayneva265c132015-02-13 03:51:03 -0500548 self.assign_keypair()
Angus Salkeld5a3e1dd2015-02-03 15:31:47 +1000549
550 def test_update_on_failed_create(self):
Vikas Jainac6b02f2015-02-11 11:31:46 -0800551 # create a stack with "server" dependent on "keypair", but
Angus Salkeld5a3e1dd2015-02-03 15:31:47 +1000552 # keypair fails, so "server" is not created properly.
553 # We then fix the template and it should succeed.
554 broken_templ = self.main_template.replace('replace-this',
555 self.keypair_name)
556 stack_identifier = self.stack_create(
557 template=broken_templ,
558 files={'server_fail.yaml': self.nested_templ},
559 expected_status='CREATE_FAILED')
560
561 fixed_templ = self.main_template.replace('replace-this',
562 test.rand_name())
563 self.update_stack(stack_identifier,
564 fixed_templ,
565 files={'server_fail.yaml': self.nested_templ})
566
567
Rabi Mishra477efc92015-07-31 13:01:45 +0530568class TemplateResourceAdoptTest(functional_base.FunctionalTestsBase):
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000569 """Prove that we can do template resource adopt/abandon."""
570
571 main_template = '''
572HeatTemplateFormatVersion: '2012-12-12'
573Resources:
574 the_nested:
575 Type: the.yaml
576 Properties:
577 one: my_name
578Outputs:
579 identifier:
580 Value: {Ref: the_nested}
581 value:
582 Value: {'Fn::GetAtt': [the_nested, the_str]}
583'''
584
585 nested_templ = '''
586HeatTemplateFormatVersion: '2012-12-12'
587Parameters:
588 one:
589 Default: foo
590 Type: String
591Resources:
592 RealRandom:
593 Type: OS::Heat::RandomString
594 Properties:
595 salt: {Ref: one}
596Outputs:
597 the_str:
598 Value: {'Fn::GetAtt': [RealRandom, value]}
599'''
600
601 def setUp(self):
602 super(TemplateResourceAdoptTest, self).setUp()
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000603
604 def _yaml_to_json(self, yaml_templ):
605 return yaml.load(yaml_templ)
606
607 def test_abandon(self):
Sergey Kraynevbf67ce32015-04-17 10:54:20 -0400608 stack_identifier = self.stack_create(
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000609 template=self.main_template,
610 files={'the.yaml': self.nested_templ},
Sergey Kraynevbf67ce32015-04-17 10:54:20 -0400611 enable_cleanup=False
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000612 )
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000613
Sirushti Murugesan04ee8022015-02-02 23:00:23 +0530614 info = self.stack_abandon(stack_id=stack_identifier)
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000615 self.assertEqual(self._yaml_to_json(self.main_template),
616 info['template'])
617 self.assertEqual(self._yaml_to_json(self.nested_templ),
618 info['resources']['the_nested']['template'])
Kanagaraj Manickam6b378ab2015-05-11 17:34:43 +0530619 # TODO(james combs): Implement separate test cases for export
620 # once export REST API is available. Also test reverse order
621 # of invocation: export -> abandon AND abandon -> export
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000622
623 def test_adopt(self):
624 data = {
625 'resources': {
626 'the_nested': {
627 "type": "the.yaml",
628 "resources": {
629 "RealRandom": {
630 "type": "OS::Heat::RandomString",
631 'resource_data': {'value': 'goopie'},
632 'resource_id': 'froggy'
633 }
634 }
635 }
636 },
637 "environment": {"parameters": {}},
638 "template": yaml.load(self.main_template)
639 }
640
641 stack_identifier = self.stack_adopt(
642 adopt_data=json.dumps(data),
643 files={'the.yaml': self.nested_templ})
644
645 self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
646 stack = self.client.stacks.get(stack_identifier)
647 self.assertEqual('goopie', self._stack_output(stack, 'value'))
Angus Salkeld87601722015-01-05 14:57:27 +1000648
649
Rabi Mishra477efc92015-07-31 13:01:45 +0530650class TemplateResourceCheckTest(functional_base.FunctionalTestsBase):
Angus Salkeld87601722015-01-05 14:57:27 +1000651 """Prove that we can do template resource check."""
652
653 main_template = '''
654HeatTemplateFormatVersion: '2012-12-12'
655Resources:
656 the_nested:
657 Type: the.yaml
658 Properties:
659 one: my_name
660Outputs:
661 identifier:
662 Value: {Ref: the_nested}
663 value:
664 Value: {'Fn::GetAtt': [the_nested, the_str]}
665'''
666
667 nested_templ = '''
668HeatTemplateFormatVersion: '2012-12-12'
669Parameters:
670 one:
671 Default: foo
672 Type: String
673Resources:
674 RealRandom:
675 Type: OS::Heat::RandomString
676 Properties:
677 salt: {Ref: one}
678Outputs:
679 the_str:
680 Value: {'Fn::GetAtt': [RealRandom, value]}
681'''
682
683 def setUp(self):
684 super(TemplateResourceCheckTest, self).setUp()
Angus Salkeld87601722015-01-05 14:57:27 +1000685
686 def test_check(self):
Sergey Kraynevbf67ce32015-04-17 10:54:20 -0400687 stack_identifier = self.stack_create(
Angus Salkeld87601722015-01-05 14:57:27 +1000688 template=self.main_template,
Sergey Kraynevbf67ce32015-04-17 10:54:20 -0400689 files={'the.yaml': self.nested_templ}
Angus Salkeld87601722015-01-05 14:57:27 +1000690 )
Angus Salkeld87601722015-01-05 14:57:27 +1000691
692 self.client.actions.check(stack_id=stack_identifier)
693 self._wait_for_stack_status(stack_identifier, 'CHECK_COMPLETE')
Angus Salkeld793b0fc2015-06-24 08:52:08 +1000694
695
Rabi Mishra477efc92015-07-31 13:01:45 +0530696class TemplateResourceErrorMessageTest(functional_base.FunctionalTestsBase):
Angus Salkeld793b0fc2015-06-24 08:52:08 +1000697 """Prove that nested stack errors don't suck."""
Peter Razumovskyf0ac9582015-09-24 16:49:03 +0300698
Angus Salkeld793b0fc2015-06-24 08:52:08 +1000699 template = '''
700HeatTemplateFormatVersion: '2012-12-12'
701Resources:
702 victim:
703 Type: fail.yaml
704'''
705 nested_templ = '''
706HeatTemplateFormatVersion: '2012-12-12'
707Resources:
708 oops:
709 Type: OS::Heat::TestResource
710 Properties:
711 fail: true
712 wait_secs: 2
713'''
714
715 def setUp(self):
716 super(TemplateResourceErrorMessageTest, self).setUp()
Angus Salkeld793b0fc2015-06-24 08:52:08 +1000717
718 def test_fail(self):
719 stack_identifier = self.stack_create(
720 template=self.template,
721 files={'fail.yaml': self.nested_templ},
722 expected_status='CREATE_FAILED')
723 stack = self.client.stacks.get(stack_identifier)
724
725 exp_path = 'resources.victim.resources.oops'
726 exp_msg = 'Test Resource failed oops'
727 exp = 'Resource CREATE failed: ValueError: %s: %s' % (exp_path,
728 exp_msg)
729 self.assertEqual(exp, stack.stack_status_reason)
kairat_kushaev61a99e12015-07-31 16:22:45 +0300730
731
Rabi Mishra477efc92015-07-31 13:01:45 +0530732class TemplateResourceSuspendResumeTest(functional_base.FunctionalTestsBase):
kairat_kushaev61a99e12015-07-31 16:22:45 +0300733 """Prove that we can do template resource suspend/resume."""
734
735 main_template = '''
736heat_template_version: 2014-10-16
737parameters:
738resources:
739 the_nested:
740 type: the.yaml
741'''
742
743 nested_templ = '''
744heat_template_version: 2014-10-16
745resources:
746 test_random_string:
747 type: OS::Heat::RandomString
748'''
749
750 def setUp(self):
751 super(TemplateResourceSuspendResumeTest, self).setUp()
kairat_kushaev61a99e12015-07-31 16:22:45 +0300752
753 def test_suspend_resume(self):
Peter Razumovskyf0ac9582015-09-24 16:49:03 +0300754 """Basic test for template resource suspend resume."""
kairat_kushaev61a99e12015-07-31 16:22:45 +0300755 stack_identifier = self.stack_create(
756 template=self.main_template,
757 files={'the.yaml': self.nested_templ}
758 )
759
760 self.stack_suspend(stack_identifier=stack_identifier)
761 self.stack_resume(stack_identifier=stack_identifier)
Angus Salkeld6a20e3b2015-08-05 13:30:26 +1000762
763
764class ValidateFacadeTest(test.HeatIntegrationTest):
765 """Prove that nested stack errors don't suck."""
Peter Razumovskyf0ac9582015-09-24 16:49:03 +0300766
Angus Salkeld6a20e3b2015-08-05 13:30:26 +1000767 template = '''
768heat_template_version: 2015-10-15
769resources:
770 thisone:
771 type: OS::Thingy
772 properties:
773 one: pre
774 two: post
775outputs:
776 one:
777 value: {get_attr: [thisone, here-it-is]}
778'''
779 templ_facade = '''
780heat_template_version: 2015-04-30
781parameters:
782 one:
783 type: string
784 two:
785 type: string
786outputs:
787 here-it-is:
788 value: noop
789'''
790 env = '''
791resource_registry:
792 OS::Thingy: facade.yaml
793 resources:
794 thisone:
795 OS::Thingy: concrete.yaml
796'''
797
798 def setUp(self):
799 super(ValidateFacadeTest, self).setUp()
800 self.client = self.orchestration_client
801
802 def test_missing_param(self):
803 templ_missing_parameter = '''
804heat_template_version: 2015-04-30
805parameters:
806 one:
807 type: string
808resources:
809 str:
810 type: OS::Heat::RandomString
811outputs:
812 here-it-is:
813 value:
814 not-important
815'''
816 try:
817 self.stack_create(
818 template=self.template,
819 environment=self.env,
820 files={'facade.yaml': self.templ_facade,
821 'concrete.yaml': templ_missing_parameter},
822 expected_status='CREATE_FAILED')
823 except heat_exceptions.HTTPBadRequest as exc:
824 exp = ('ERROR: Required property two for facade '
825 'OS::Thingy missing in provider')
826 self.assertEqual(exp, six.text_type(exc))
827
828 def test_missing_output(self):
829 templ_missing_output = '''
830heat_template_version: 2015-04-30
831parameters:
832 one:
833 type: string
834 two:
835 type: string
836resources:
837 str:
838 type: OS::Heat::RandomString
839'''
840 try:
841 self.stack_create(
842 template=self.template,
843 environment=self.env,
844 files={'facade.yaml': self.templ_facade,
845 'concrete.yaml': templ_missing_output},
846 expected_status='CREATE_FAILED')
847 except heat_exceptions.HTTPBadRequest as exc:
848 exp = ('ERROR: Attribute here-it-is for facade '
849 'OS::Thingy missing in provider')
850 self.assertEqual(exp, six.text_type(exc))