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