blob: e047da1fe57bd4b70b9cfe77e6eca4e1f33ab3be [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
20
21
Angus Salkeld2bd63a42015-01-07 11:11:29 +100022class TemplateResourceTest(test.HeatIntegrationTest):
23 """Prove that we can use the registry in a nested provider."""
Angus Salkeld95403d82015-02-12 14:06:01 +100024
25 template = '''
26heat_template_version: 2013-05-23
27resources:
28 secret1:
29 type: OS::Heat::RandomString
30outputs:
31 secret-out:
32 value: { get_attr: [secret1, value] }
33'''
34 nested_templ = '''
35heat_template_version: 2013-05-23
36resources:
37 secret2:
38 type: OS::Heat::RandomString
39outputs:
40 value:
41 value: { get_attr: [secret2, value] }
42'''
43
44 env_templ = '''
45resource_registry:
46 "OS::Heat::RandomString": nested.yaml
47'''
48
Angus Salkeld2bd63a42015-01-07 11:11:29 +100049 def setUp(self):
50 super(TemplateResourceTest, self).setUp()
51 self.client = self.orchestration_client
52
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
151class NestedAttributesTest(test.HeatIntegrationTest):
152 """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()
177 self.client = self.orchestration_client
178
179 def test_stack_ref(self):
180 nested_templ = '''
181heat_template_version: 2014-10-16
182resources:
183 secret1:
184 type: OS::Heat::RandomString
Angus Salkelda89a0282015-07-24 15:47:38 +1000185outputs:
186 nested_str:
187 value: {get_attr: [secret1, value]}
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000188'''
189 stack_identifier = self.stack_create(
190 template=self.main_templ,
191 files={'nested.yaml': nested_templ},
192 environment=self.env_templ)
193 self.assert_resource_is_a_stack(stack_identifier, 'secret2')
194 stack = self.client.stacks.get(stack_identifier)
195 test_ref = self._stack_output(stack, 'test_ref')
196 self.assertIn('arn:openstack:heat:', test_ref)
197
198 def test_transparent_ref(self):
199 """With the addition of OS::stack_id we can now use the nested resource
200 more transparently.
201 """
202 nested_templ = '''
203heat_template_version: 2014-10-16
204resources:
205 secret1:
206 type: OS::Heat::RandomString
207outputs:
208 OS::stack_id:
209 value: {get_resource: secret1}
210 nested_str:
211 value: {get_attr: [secret1, value]}
212'''
213 stack_identifier = self.stack_create(
214 template=self.main_templ,
215 files={'nested.yaml': nested_templ},
216 environment=self.env_templ)
217 self.assert_resource_is_a_stack(stack_identifier, 'secret2')
218 stack = self.client.stacks.get(stack_identifier)
219 test_ref = self._stack_output(stack, 'test_ref')
220 test_attr = self._stack_output(stack, 'old_way')
221
222 self.assertNotIn('arn:openstack:heat', test_ref)
223 self.assertEqual(test_attr, test_ref)
224
225 def test_nested_attributes(self):
226 nested_templ = '''
227heat_template_version: 2014-10-16
228resources:
229 secret1:
230 type: OS::Heat::RandomString
231outputs:
232 nested_str:
233 value: {get_attr: [secret1, value]}
234'''
235 stack_identifier = self.stack_create(
236 template=self.main_templ,
237 files={'nested.yaml': nested_templ},
238 environment=self.env_templ)
239 self.assert_resource_is_a_stack(stack_identifier, 'secret2')
240 stack = self.client.stacks.get(stack_identifier)
241 old_way = self._stack_output(stack, 'old_way')
242 test_attr1 = self._stack_output(stack, 'test_attr1')
243 test_attr2 = self._stack_output(stack, 'test_attr2')
244
245 self.assertEqual(old_way, test_attr1)
246 self.assertEqual(old_way, test_attr2)
247
248
249class TemplateResourceUpdateTest(test.HeatIntegrationTest):
250 """Prove that we can do template resource updates."""
251
252 main_template = '''
253HeatTemplateFormatVersion: '2012-12-12'
254Resources:
255 the_nested:
256 Type: the.yaml
257 Properties:
258 one: my_name
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530259 two: your_name
260Outputs:
261 identifier:
262 Value: {Ref: the_nested}
263 value:
264 Value: {'Fn::GetAtt': [the_nested, the_str]}
265'''
266
267 main_template_change_prop = '''
268HeatTemplateFormatVersion: '2012-12-12'
269Resources:
270 the_nested:
271 Type: the.yaml
272 Properties:
273 one: updated_name
274 two: your_name
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000275
276Outputs:
277 identifier:
278 Value: {Ref: the_nested}
279 value:
280 Value: {'Fn::GetAtt': [the_nested, the_str]}
281'''
282
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530283 main_template_add_prop = '''
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000284HeatTemplateFormatVersion: '2012-12-12'
285Resources:
286 the_nested:
287 Type: the.yaml
288 Properties:
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530289 one: my_name
290 two: your_name
291 three: third_name
292
293Outputs:
294 identifier:
295 Value: {Ref: the_nested}
296 value:
297 Value: {'Fn::GetAtt': [the_nested, the_str]}
298'''
299
300 main_template_remove_prop = '''
301HeatTemplateFormatVersion: '2012-12-12'
302Resources:
303 the_nested:
304 Type: the.yaml
305 Properties:
306 one: my_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
315 initial_tmpl = '''
316HeatTemplateFormatVersion: '2012-12-12'
317Parameters:
318 one:
319 Default: foo
320 Type: String
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530321 two:
322 Default: bar
323 Type: String
324
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000325Resources:
326 NestedResource:
327 Type: OS::Heat::RandomString
328 Properties:
329 salt: {Ref: one}
330Outputs:
331 the_str:
332 Value: {'Fn::GetAtt': [NestedResource, value]}
333'''
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530334
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000335 prop_change_tmpl = '''
336HeatTemplateFormatVersion: '2012-12-12'
337Parameters:
338 one:
339 Default: yikes
340 Type: String
341 two:
342 Default: foo
343 Type: String
344Resources:
345 NestedResource:
346 Type: OS::Heat::RandomString
347 Properties:
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530348 salt: {Ref: two}
349Outputs:
350 the_str:
351 Value: {'Fn::GetAtt': [NestedResource, value]}
352'''
353
354 prop_add_tmpl = '''
355HeatTemplateFormatVersion: '2012-12-12'
356Parameters:
357 one:
358 Default: yikes
359 Type: String
360 two:
361 Default: foo
362 Type: String
363 three:
364 Default: bar
365 Type: String
366
367Resources:
368 NestedResource:
369 Type: OS::Heat::RandomString
370 Properties:
371 salt: {Ref: three}
372Outputs:
373 the_str:
374 Value: {'Fn::GetAtt': [NestedResource, value]}
375'''
376
377 prop_remove_tmpl = '''
378HeatTemplateFormatVersion: '2012-12-12'
379Parameters:
380 one:
381 Default: yikes
382 Type: String
383
384Resources:
385 NestedResource:
386 Type: OS::Heat::RandomString
387 Properties:
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000388 salt: {Ref: one}
389Outputs:
390 the_str:
391 Value: {'Fn::GetAtt': [NestedResource, value]}
392'''
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530393
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000394 attr_change_tmpl = '''
395HeatTemplateFormatVersion: '2012-12-12'
396Parameters:
397 one:
398 Default: foo
399 Type: String
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530400 two:
401 Default: bar
402 Type: String
403
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000404Resources:
405 NestedResource:
406 Type: OS::Heat::RandomString
407 Properties:
408 salt: {Ref: one}
409Outputs:
410 the_str:
411 Value: {'Fn::GetAtt': [NestedResource, value]}
412 something_else:
413 Value: just_a_string
414'''
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530415
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000416 content_change_tmpl = '''
417HeatTemplateFormatVersion: '2012-12-12'
418Parameters:
419 one:
420 Default: foo
421 Type: String
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530422 two:
423 Default: bar
424 Type: String
425
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000426Resources:
427 NestedResource:
428 Type: OS::Heat::RandomString
429 Properties:
430 salt: yum
431Outputs:
432 the_str:
433 Value: {'Fn::GetAtt': [NestedResource, value]}
434'''
435
436 EXPECTED = (UPDATE, NOCHANGE) = ('update', 'nochange')
437 scenarios = [
438 ('no_changes', dict(template=main_template,
439 provider=initial_tmpl,
440 expect=NOCHANGE)),
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530441 ('main_tmpl_change', dict(template=main_template_change_prop,
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000442 provider=initial_tmpl,
443 expect=UPDATE)),
444 ('provider_change', dict(template=main_template,
445 provider=content_change_tmpl,
446 expect=UPDATE)),
447 ('provider_props_change', dict(template=main_template,
448 provider=prop_change_tmpl,
Rabi Mishrab1293ae2015-05-13 16:39:04 +0530449 expect=UPDATE)),
450 ('provider_props_add', dict(template=main_template_add_prop,
451 provider=prop_add_tmpl,
452 expect=UPDATE)),
453 ('provider_props_remove', dict(template=main_template_remove_prop,
454 provider=prop_remove_tmpl,
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000455 expect=NOCHANGE)),
456 ('provider_attr_change', dict(template=main_template,
457 provider=attr_change_tmpl,
458 expect=NOCHANGE)),
459 ]
460
461 def setUp(self):
462 super(TemplateResourceUpdateTest, self).setUp()
463 self.client = self.orchestration_client
464
465 def test_template_resource_update_template_schema(self):
466 stack_identifier = self.stack_create(
467 template=self.main_template,
468 files={'the.yaml': self.initial_tmpl})
469 stack = self.client.stacks.get(stack_identifier)
470 initial_id = self._stack_output(stack, 'identifier')
471 initial_val = self._stack_output(stack, 'value')
472
473 self.update_stack(stack_identifier,
474 self.template,
475 files={'the.yaml': self.provider})
476 stack = self.client.stacks.get(stack_identifier)
477 self.assertEqual(initial_id,
478 self._stack_output(stack, 'identifier'))
479 if self.expect == self.NOCHANGE:
480 self.assertEqual(initial_val,
481 self._stack_output(stack, 'value'))
482 else:
483 self.assertNotEqual(initial_val,
484 self._stack_output(stack, 'value'))
485
486
Angus Salkeld5a3e1dd2015-02-03 15:31:47 +1000487class TemplateResourceUpdateFailedTest(test.HeatIntegrationTest):
488 """Prove that we can do updates on a nested stack to fix a stack."""
489 main_template = '''
490HeatTemplateFormatVersion: '2012-12-12'
491Resources:
492 keypair:
493 Type: OS::Nova::KeyPair
494 Properties:
495 name: replace-this
496 save_private_key: false
497 server:
498 Type: server_fail.yaml
499 DependsOn: keypair
500'''
501 nested_templ = '''
502HeatTemplateFormatVersion: '2012-12-12'
503Resources:
504 RealRandom:
505 Type: OS::Heat::RandomString
506'''
507
508 def setUp(self):
509 super(TemplateResourceUpdateFailedTest, self).setUp()
510 self.client = self.orchestration_client
Sergey Krayneva265c132015-02-13 03:51:03 -0500511 self.assign_keypair()
Angus Salkeld5a3e1dd2015-02-03 15:31:47 +1000512
513 def test_update_on_failed_create(self):
Vikas Jainac6b02f2015-02-11 11:31:46 -0800514 # create a stack with "server" dependent on "keypair", but
Angus Salkeld5a3e1dd2015-02-03 15:31:47 +1000515 # keypair fails, so "server" is not created properly.
516 # We then fix the template and it should succeed.
517 broken_templ = self.main_template.replace('replace-this',
518 self.keypair_name)
519 stack_identifier = self.stack_create(
520 template=broken_templ,
521 files={'server_fail.yaml': self.nested_templ},
522 expected_status='CREATE_FAILED')
523
524 fixed_templ = self.main_template.replace('replace-this',
525 test.rand_name())
526 self.update_stack(stack_identifier,
527 fixed_templ,
528 files={'server_fail.yaml': self.nested_templ})
529
530
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000531class TemplateResourceAdoptTest(test.HeatIntegrationTest):
532 """Prove that we can do template resource adopt/abandon."""
533
534 main_template = '''
535HeatTemplateFormatVersion: '2012-12-12'
536Resources:
537 the_nested:
538 Type: the.yaml
539 Properties:
540 one: my_name
541Outputs:
542 identifier:
543 Value: {Ref: the_nested}
544 value:
545 Value: {'Fn::GetAtt': [the_nested, the_str]}
546'''
547
548 nested_templ = '''
549HeatTemplateFormatVersion: '2012-12-12'
550Parameters:
551 one:
552 Default: foo
553 Type: String
554Resources:
555 RealRandom:
556 Type: OS::Heat::RandomString
557 Properties:
558 salt: {Ref: one}
559Outputs:
560 the_str:
561 Value: {'Fn::GetAtt': [RealRandom, value]}
562'''
563
564 def setUp(self):
565 super(TemplateResourceAdoptTest, self).setUp()
566 self.client = self.orchestration_client
567
568 def _yaml_to_json(self, yaml_templ):
569 return yaml.load(yaml_templ)
570
571 def test_abandon(self):
Sergey Kraynevbf67ce32015-04-17 10:54:20 -0400572 stack_identifier = self.stack_create(
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000573 template=self.main_template,
574 files={'the.yaml': self.nested_templ},
Sergey Kraynevbf67ce32015-04-17 10:54:20 -0400575 enable_cleanup=False
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000576 )
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000577
Sirushti Murugesan04ee8022015-02-02 23:00:23 +0530578 info = self.stack_abandon(stack_id=stack_identifier)
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000579 self.assertEqual(self._yaml_to_json(self.main_template),
580 info['template'])
581 self.assertEqual(self._yaml_to_json(self.nested_templ),
582 info['resources']['the_nested']['template'])
583
584 def test_adopt(self):
585 data = {
586 'resources': {
587 'the_nested': {
588 "type": "the.yaml",
589 "resources": {
590 "RealRandom": {
591 "type": "OS::Heat::RandomString",
592 'resource_data': {'value': 'goopie'},
593 'resource_id': 'froggy'
594 }
595 }
596 }
597 },
598 "environment": {"parameters": {}},
599 "template": yaml.load(self.main_template)
600 }
601
602 stack_identifier = self.stack_adopt(
603 adopt_data=json.dumps(data),
604 files={'the.yaml': self.nested_templ})
605
606 self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
607 stack = self.client.stacks.get(stack_identifier)
608 self.assertEqual('goopie', self._stack_output(stack, 'value'))
Angus Salkeld87601722015-01-05 14:57:27 +1000609
610
611class TemplateResourceCheckTest(test.HeatIntegrationTest):
612 """Prove that we can do template resource check."""
613
614 main_template = '''
615HeatTemplateFormatVersion: '2012-12-12'
616Resources:
617 the_nested:
618 Type: the.yaml
619 Properties:
620 one: my_name
621Outputs:
622 identifier:
623 Value: {Ref: the_nested}
624 value:
625 Value: {'Fn::GetAtt': [the_nested, the_str]}
626'''
627
628 nested_templ = '''
629HeatTemplateFormatVersion: '2012-12-12'
630Parameters:
631 one:
632 Default: foo
633 Type: String
634Resources:
635 RealRandom:
636 Type: OS::Heat::RandomString
637 Properties:
638 salt: {Ref: one}
639Outputs:
640 the_str:
641 Value: {'Fn::GetAtt': [RealRandom, value]}
642'''
643
644 def setUp(self):
645 super(TemplateResourceCheckTest, self).setUp()
646 self.client = self.orchestration_client
647
648 def test_check(self):
Sergey Kraynevbf67ce32015-04-17 10:54:20 -0400649 stack_identifier = self.stack_create(
Angus Salkeld87601722015-01-05 14:57:27 +1000650 template=self.main_template,
Sergey Kraynevbf67ce32015-04-17 10:54:20 -0400651 files={'the.yaml': self.nested_templ}
Angus Salkeld87601722015-01-05 14:57:27 +1000652 )
Angus Salkeld87601722015-01-05 14:57:27 +1000653
654 self.client.actions.check(stack_id=stack_identifier)
655 self._wait_for_stack_status(stack_identifier, 'CHECK_COMPLETE')
Angus Salkeld793b0fc2015-06-24 08:52:08 +1000656
657
658class TemplateResourceErrorMessageTest(test.HeatIntegrationTest):
659 """Prove that nested stack errors don't suck."""
660 template = '''
661HeatTemplateFormatVersion: '2012-12-12'
662Resources:
663 victim:
664 Type: fail.yaml
665'''
666 nested_templ = '''
667HeatTemplateFormatVersion: '2012-12-12'
668Resources:
669 oops:
670 Type: OS::Heat::TestResource
671 Properties:
672 fail: true
673 wait_secs: 2
674'''
675
676 def setUp(self):
677 super(TemplateResourceErrorMessageTest, self).setUp()
678 self.client = self.orchestration_client
679
680 def test_fail(self):
681 stack_identifier = self.stack_create(
682 template=self.template,
683 files={'fail.yaml': self.nested_templ},
684 expected_status='CREATE_FAILED')
685 stack = self.client.stacks.get(stack_identifier)
686
687 exp_path = 'resources.victim.resources.oops'
688 exp_msg = 'Test Resource failed oops'
689 exp = 'Resource CREATE failed: ValueError: %s: %s' % (exp_path,
690 exp_msg)
691 self.assertEqual(exp, stack.stack_status_reason)
kairat_kushaev61a99e12015-07-31 16:22:45 +0300692
693
694class TemplateResourceSuspendResumeTest(test.HeatIntegrationTest):
695 """Prove that we can do template resource suspend/resume."""
696
697 main_template = '''
698heat_template_version: 2014-10-16
699parameters:
700resources:
701 the_nested:
702 type: the.yaml
703'''
704
705 nested_templ = '''
706heat_template_version: 2014-10-16
707resources:
708 test_random_string:
709 type: OS::Heat::RandomString
710'''
711
712 def setUp(self):
713 super(TemplateResourceSuspendResumeTest, self).setUp()
714 self.client = self.orchestration_client
715
716 def test_suspend_resume(self):
717 """Basic test for template resource suspend resume"""
718 stack_identifier = self.stack_create(
719 template=self.main_template,
720 files={'the.yaml': self.nested_templ}
721 )
722
723 self.stack_suspend(stack_identifier=stack_identifier)
724 self.stack_resume(stack_identifier=stack_identifier)
Angus Salkeld6a20e3b2015-08-05 13:30:26 +1000725
726
727class ValidateFacadeTest(test.HeatIntegrationTest):
728 """Prove that nested stack errors don't suck."""
729 template = '''
730heat_template_version: 2015-10-15
731resources:
732 thisone:
733 type: OS::Thingy
734 properties:
735 one: pre
736 two: post
737outputs:
738 one:
739 value: {get_attr: [thisone, here-it-is]}
740'''
741 templ_facade = '''
742heat_template_version: 2015-04-30
743parameters:
744 one:
745 type: string
746 two:
747 type: string
748outputs:
749 here-it-is:
750 value: noop
751'''
752 env = '''
753resource_registry:
754 OS::Thingy: facade.yaml
755 resources:
756 thisone:
757 OS::Thingy: concrete.yaml
758'''
759
760 def setUp(self):
761 super(ValidateFacadeTest, self).setUp()
762 self.client = self.orchestration_client
763
764 def test_missing_param(self):
765 templ_missing_parameter = '''
766heat_template_version: 2015-04-30
767parameters:
768 one:
769 type: string
770resources:
771 str:
772 type: OS::Heat::RandomString
773outputs:
774 here-it-is:
775 value:
776 not-important
777'''
778 try:
779 self.stack_create(
780 template=self.template,
781 environment=self.env,
782 files={'facade.yaml': self.templ_facade,
783 'concrete.yaml': templ_missing_parameter},
784 expected_status='CREATE_FAILED')
785 except heat_exceptions.HTTPBadRequest as exc:
786 exp = ('ERROR: Required property two for facade '
787 'OS::Thingy missing in provider')
788 self.assertEqual(exp, six.text_type(exc))
789
790 def test_missing_output(self):
791 templ_missing_output = '''
792heat_template_version: 2015-04-30
793parameters:
794 one:
795 type: string
796 two:
797 type: string
798resources:
799 str:
800 type: OS::Heat::RandomString
801'''
802 try:
803 self.stack_create(
804 template=self.template,
805 environment=self.env,
806 files={'facade.yaml': self.templ_facade,
807 'concrete.yaml': templ_missing_output},
808 expected_status='CREATE_FAILED')
809 except heat_exceptions.HTTPBadRequest as exc:
810 exp = ('ERROR: Attribute here-it-is for facade '
811 'OS::Thingy missing in provider')
812 self.assertEqual(exp, six.text_type(exc))