blob: 8c78951bfb6971cdb8c631cc17d43704ed991127 [file] [log] [blame]
Rakesh H Sa3325d62015-04-04 19:42:29 +05301# 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
13
14import copy
Rakesh H Sa3325d62015-04-04 19:42:29 +053015import json
16
Rabi Mishra477efc92015-07-31 13:01:45 +053017from heat_integrationtests.functional import functional_base
18
Rakesh H Sa3325d62015-04-04 19:42:29 +053019test_template_one_resource = {
20 'heat_template_version': '2013-05-23',
21 'description': 'Test template to create one instance.',
22 'resources': {
23 'test1': {
24 'type': 'OS::Heat::TestResource',
25 'properties': {
26 'value': 'Test1',
27 'fail': False,
28 'update_replace': False,
Angus Salkeld73dcbc62015-08-31 09:02:58 +100029 'wait_secs': 0,
30 'action_wait_secs': {'create': 1},
31 'client_name': 'nova',
32 'entity_name': 'servers',
Rakesh H Sa3325d62015-04-04 19:42:29 +053033 }
34 }
35 }
36}
37
38test_template_two_resource = {
39 'heat_template_version': '2013-05-23',
40 'description': 'Test template to create two instance.',
41 'resources': {
42 'test1': {
43 'type': 'OS::Heat::TestResource',
44 'properties': {
45 'value': 'Test1',
46 'fail': False,
47 'update_replace': False,
Angus Salkeld73dcbc62015-08-31 09:02:58 +100048 'wait_secs': 0,
49 'action_wait_secs': {'update': 1}
Rakesh H Sa3325d62015-04-04 19:42:29 +053050 }
51 },
52 'test2': {
53 'type': 'OS::Heat::TestResource',
54 'properties': {
55 'value': 'Test1',
56 'fail': False,
57 'update_replace': False,
58 'wait_secs': 0
59 }
60 }
61 }
62}
63
64
65def _change_rsrc_properties(template, rsrcs, values):
66 modified_template = copy.deepcopy(template)
67 for rsrc_name in rsrcs:
68 rsrc_prop = modified_template['resources'][
69 rsrc_name]['properties']
70 for prop in rsrc_prop:
71 if prop in values:
72 rsrc_prop[prop] = values[prop]
73 return modified_template
74
75
Rabi Mishra477efc92015-07-31 13:01:45 +053076class CreateStackTest(functional_base.FunctionalTestsBase):
Rakesh H Sa3325d62015-04-04 19:42:29 +053077 def setUp(self):
78 super(CreateStackTest, self).setUp()
Rakesh H Sa3325d62015-04-04 19:42:29 +053079
80 def test_create_rollback(self):
81 values = {'fail': True, 'value': 'test_create_rollback'}
82 template = _change_rsrc_properties(test_template_one_resource,
83 ['test1'], values)
84
85 self.stack_create(
86 template=template,
87 expected_status='ROLLBACK_COMPLETE',
88 disable_rollback=False)
89
90
Rabi Mishra477efc92015-07-31 13:01:45 +053091class UpdateStackTest(functional_base.FunctionalTestsBase):
Rakesh H Sa3325d62015-04-04 19:42:29 +053092
93 provider_template = {
94 'heat_template_version': '2013-05-23',
95 'description': 'foo',
96 'resources': {
97 'test1': {
98 'type': 'My::TestResource'
99 }
100 }
101 }
102
103 provider_group_template = '''
104heat_template_version: 2013-05-23
Steven Hardy23284b62015-10-01 19:03:42 +0100105parameters:
106 count:
107 type: number
108 default: 2
Rakesh H Sa3325d62015-04-04 19:42:29 +0530109resources:
110 test_group:
111 type: OS::Heat::ResourceGroup
112 properties:
Steven Hardy23284b62015-10-01 19:03:42 +0100113 count: {get_param: count}
Rakesh H Sa3325d62015-04-04 19:42:29 +0530114 resource_def:
115 type: My::TestResource
116'''
117
118 update_userdata_template = '''
119heat_template_version: 2014-10-16
120parameters:
121 flavor:
122 type: string
123 user_data:
124 type: string
125 image:
126 type: string
Rabi Mishraec4b03b2015-05-23 02:20:47 +0530127 network:
128 type: string
Rakesh H Sa3325d62015-04-04 19:42:29 +0530129
130resources:
131 server:
132 type: OS::Nova::Server
133 properties:
134 image: {get_param: image}
135 flavor: {get_param: flavor}
Rabi Mishraec4b03b2015-05-23 02:20:47 +0530136 networks: [{network: {get_param: network} }]
Rakesh H Sa3325d62015-04-04 19:42:29 +0530137 user_data_format: SOFTWARE_CONFIG
138 user_data: {get_param: user_data}
139'''
140
Steven Hardy23284b62015-10-01 19:03:42 +0100141 fail_param_template = '''
142heat_template_version: 2014-10-16
143parameters:
144 do_fail:
145 type: boolean
146 default: False
147resources:
148 aresource:
149 type: OS::Heat::TestResource
150 properties:
151 value: Test
152 fail: {get_param: do_fail}
153'''
154
Rakesh H Sa3325d62015-04-04 19:42:29 +0530155 def setUp(self):
156 super(UpdateStackTest, self).setUp()
Rakesh H Sa3325d62015-04-04 19:42:29 +0530157
158 def test_stack_update_nochange(self):
159 template = _change_rsrc_properties(test_template_one_resource,
160 ['test1'],
161 {'value': 'test_no_change'})
162 stack_identifier = self.stack_create(
163 template=template)
164 expected_resources = {'test1': 'OS::Heat::TestResource'}
165 self.assertEqual(expected_resources,
166 self.list_resources(stack_identifier))
167
168 # Update with no changes, resources should be unchanged
169 self.update_stack(stack_identifier, template)
170 self.assertEqual(expected_resources,
171 self.list_resources(stack_identifier))
172
173 def test_stack_in_place_update(self):
174 template = _change_rsrc_properties(test_template_one_resource,
175 ['test1'],
176 {'value': 'test_in_place'})
177 stack_identifier = self.stack_create(
178 template=template)
179 expected_resources = {'test1': 'OS::Heat::TestResource'}
180 self.assertEqual(expected_resources,
181 self.list_resources(stack_identifier))
182 resource = self.client.resources.list(stack_identifier)
183 initial_phy_id = resource[0].physical_resource_id
184
185 tmpl_update = _change_rsrc_properties(
186 test_template_one_resource, ['test1'],
187 {'value': 'test_in_place_update'})
188 # Update the Value
189 self.update_stack(stack_identifier, tmpl_update)
190 resource = self.client.resources.list(stack_identifier)
191 # By default update_in_place
192 self.assertEqual(initial_phy_id,
193 resource[0].physical_resource_id)
194
195 def test_stack_update_replace(self):
196 template = _change_rsrc_properties(test_template_one_resource,
197 ['test1'],
198 {'value': 'test_replace'})
199 stack_identifier = self.stack_create(
200 template=template)
201 expected_resources = {'test1': 'OS::Heat::TestResource'}
202 self.assertEqual(expected_resources,
203 self.list_resources(stack_identifier))
204 resource = self.client.resources.list(stack_identifier)
205 initial_phy_id = resource[0].physical_resource_id
206
207 # Update the value and also set update_replace prop
208 tmpl_update = _change_rsrc_properties(
209 test_template_one_resource, ['test1'],
210 {'value': 'test_in_place_update', 'update_replace': True})
211 self.update_stack(stack_identifier, tmpl_update)
212 resource = self.client.resources.list(stack_identifier)
213 # update Replace
214 self.assertNotEqual(initial_phy_id,
215 resource[0].physical_resource_id)
216
217 def test_stack_update_add_remove(self):
218 template = _change_rsrc_properties(test_template_one_resource,
219 ['test1'],
220 {'value': 'test_add_remove'})
221 stack_identifier = self.stack_create(
222 template=template)
223 initial_resources = {'test1': 'OS::Heat::TestResource'}
224 self.assertEqual(initial_resources,
225 self.list_resources(stack_identifier))
226
227 tmpl_update = _change_rsrc_properties(
228 test_template_two_resource, ['test1', 'test2'],
229 {'value': 'test_add_remove_update'})
230 # Add one resource via a stack update
231 self.update_stack(stack_identifier, tmpl_update)
232 updated_resources = {'test1': 'OS::Heat::TestResource',
233 'test2': 'OS::Heat::TestResource'}
234 self.assertEqual(updated_resources,
235 self.list_resources(stack_identifier))
236
237 # Then remove it by updating with the original template
238 self.update_stack(stack_identifier, template)
239 self.assertEqual(initial_resources,
240 self.list_resources(stack_identifier))
241
242 def test_stack_update_rollback(self):
243 template = _change_rsrc_properties(test_template_one_resource,
244 ['test1'],
245 {'value': 'test_update_rollback'})
246 stack_identifier = self.stack_create(
247 template=template)
248 initial_resources = {'test1': 'OS::Heat::TestResource'}
249 self.assertEqual(initial_resources,
250 self.list_resources(stack_identifier))
251
252 tmpl_update = _change_rsrc_properties(
253 test_template_two_resource, ['test1', 'test2'],
254 {'value': 'test_update_rollback', 'fail': True})
255 # stack update, also set failure
256 self.update_stack(stack_identifier, tmpl_update,
257 expected_status='ROLLBACK_COMPLETE',
258 disable_rollback=False)
259 # since stack update failed only the original resource is present
260 updated_resources = {'test1': 'OS::Heat::TestResource'}
261 self.assertEqual(updated_resources,
262 self.list_resources(stack_identifier))
263
Sergey Kraynev89082a32015-09-04 04:42:33 -0400264 def test_stack_update_from_failed(self):
265 # Prove it's possible to update from an UPDATE_FAILED state
266 template = _change_rsrc_properties(test_template_one_resource,
267 ['test1'],
268 {'value': 'test_update_failed'})
269 stack_identifier = self.stack_create(
270 template=template)
271 initial_resources = {'test1': 'OS::Heat::TestResource'}
272 self.assertEqual(initial_resources,
273 self.list_resources(stack_identifier))
274
275 tmpl_update = _change_rsrc_properties(
276 test_template_one_resource, ['test1'], {'fail': True})
277 # Update with bad template, we should fail
278 self.update_stack(stack_identifier, tmpl_update,
279 expected_status='UPDATE_FAILED')
280 # but then passing a good template should succeed
281 self.update_stack(stack_identifier, test_template_two_resource)
282 updated_resources = {'test1': 'OS::Heat::TestResource',
283 'test2': 'OS::Heat::TestResource'}
284 self.assertEqual(updated_resources,
285 self.list_resources(stack_identifier))
286
Rakesh H Sa3325d62015-04-04 19:42:29 +0530287 def test_stack_update_provider(self):
288 template = _change_rsrc_properties(
289 test_template_one_resource, ['test1'],
290 {'value': 'test_provider_template'})
291 files = {'provider.template': json.dumps(template)}
292 env = {'resource_registry':
293 {'My::TestResource': 'provider.template'}}
294 stack_identifier = self.stack_create(
295 template=self.provider_template,
296 files=files,
297 environment=env
298 )
299
300 initial_resources = {'test1': 'My::TestResource'}
301 self.assertEqual(initial_resources,
302 self.list_resources(stack_identifier))
303
304 # Prove the resource is backed by a nested stack, save the ID
305 nested_identifier = self.assert_resource_is_a_stack(stack_identifier,
306 'test1')
307 nested_id = nested_identifier.split('/')[-1]
308
309 # Then check the expected resources are in the nested stack
310 nested_resources = {'test1': 'OS::Heat::TestResource'}
311 self.assertEqual(nested_resources,
312 self.list_resources(nested_identifier))
313 tmpl_update = _change_rsrc_properties(
314 test_template_two_resource, ['test1', 'test2'],
315 {'value': 'test_provider_template'})
316 # Add one resource via a stack update by changing the nested stack
317 files['provider.template'] = json.dumps(tmpl_update)
318 self.update_stack(stack_identifier, self.provider_template,
319 environment=env, files=files)
320
321 # Parent resources should be unchanged and the nested stack
322 # should have been updated in-place without replacement
323 self.assertEqual(initial_resources,
324 self.list_resources(stack_identifier))
325 rsrc = self.client.resources.get(stack_identifier, 'test1')
326 self.assertEqual(rsrc.physical_resource_id, nested_id)
327
328 # Then check the expected resources are in the nested stack
329 nested_resources = {'test1': 'OS::Heat::TestResource',
330 'test2': 'OS::Heat::TestResource'}
331 self.assertEqual(nested_resources,
332 self.list_resources(nested_identifier))
333
Steven Hardy8a3c1ec2015-10-21 18:56:01 +0100334 def test_stack_update_alias_type(self):
335 env = {'resource_registry':
336 {'My::TestResource': 'OS::Heat::RandomString',
337 'My::TestResource2': 'OS::Heat::RandomString'}}
338 stack_identifier = self.stack_create(
339 template=self.provider_template,
340 environment=env
341 )
342 p_res = self.client.resources.get(stack_identifier, 'test1')
343 self.assertEqual('My::TestResource', p_res.resource_type)
344
345 initial_resources = {'test1': 'My::TestResource'}
346 self.assertEqual(initial_resources,
347 self.list_resources(stack_identifier))
348 res = self.client.resources.get(stack_identifier, 'test1')
349 # Modify the type of the resource alias to My::TestResource2
350 tmpl_update = copy.deepcopy(self.provider_template)
351 tmpl_update['resources']['test1']['type'] = 'My::TestResource2'
352 self.update_stack(stack_identifier, tmpl_update, environment=env)
353 res_a = self.client.resources.get(stack_identifier, 'test1')
354 self.assertEqual(res.physical_resource_id, res_a.physical_resource_id)
355 self.assertEqual(res.attributes['value'], res_a.attributes['value'])
356
357 def test_stack_update_alias_changes(self):
358 env = {'resource_registry':
359 {'My::TestResource': 'OS::Heat::RandomString'}}
360 stack_identifier = self.stack_create(
361 template=self.provider_template,
362 environment=env
363 )
364 p_res = self.client.resources.get(stack_identifier, 'test1')
365 self.assertEqual('My::TestResource', p_res.resource_type)
366
367 initial_resources = {'test1': 'My::TestResource'}
368 self.assertEqual(initial_resources,
369 self.list_resources(stack_identifier))
370 res = self.client.resources.get(stack_identifier, 'test1')
371 # Modify the resource alias to point to a different type
372 env = {'resource_registry':
373 {'My::TestResource': 'OS::Heat::TestResource'}}
374 self.update_stack(stack_identifier, template=self.provider_template,
375 environment=env)
376 res_a = self.client.resources.get(stack_identifier, 'test1')
377 self.assertNotEqual(res.physical_resource_id,
378 res_a.physical_resource_id)
379
380 def test_stack_update_provider_type(self):
381 template = _change_rsrc_properties(
382 test_template_one_resource, ['test1'],
383 {'value': 'test_provider_template'})
384 files = {'provider.template': json.dumps(template)}
385 env = {'resource_registry':
386 {'My::TestResource': 'provider.template',
387 'My::TestResource2': 'provider.template'}}
388 stack_identifier = self.stack_create(
389 template=self.provider_template,
390 files=files,
391 environment=env
392 )
393 p_res = self.client.resources.get(stack_identifier, 'test1')
394 self.assertEqual('My::TestResource', p_res.resource_type)
395
396 initial_resources = {'test1': 'My::TestResource'}
397 self.assertEqual(initial_resources,
398 self.list_resources(stack_identifier))
399
400 # Prove the resource is backed by a nested stack, save the ID
401 nested_identifier = self.assert_resource_is_a_stack(stack_identifier,
402 'test1')
403 nested_id = nested_identifier.split('/')[-1]
404
405 # Then check the expected resources are in the nested stack
406 nested_resources = {'test1': 'OS::Heat::TestResource'}
407 self.assertEqual(nested_resources,
408 self.list_resources(nested_identifier))
409 n_res = self.client.resources.get(nested_identifier, 'test1')
410
411 # Modify the type of the provider resource to My::TestResource2
412 tmpl_update = copy.deepcopy(self.provider_template)
413 tmpl_update['resources']['test1']['type'] = 'My::TestResource2'
414 self.update_stack(stack_identifier, tmpl_update,
415 environment=env, files=files)
416 p_res = self.client.resources.get(stack_identifier, 'test1')
417 self.assertEqual('My::TestResource2', p_res.resource_type)
418
419 # Parent resources should be unchanged and the nested stack
420 # should have been updated in-place without replacement
421 self.assertEqual({u'test1': u'My::TestResource2'},
422 self.list_resources(stack_identifier))
423 rsrc = self.client.resources.get(stack_identifier, 'test1')
424 self.assertEqual(rsrc.physical_resource_id, nested_id)
425
426 # Then check the expected resources are in the nested stack
427 self.assertEqual(nested_resources,
428 self.list_resources(nested_identifier))
429 n_res2 = self.client.resources.get(nested_identifier, 'test1')
430 self.assertEqual(n_res.physical_resource_id,
431 n_res2.physical_resource_id)
432
Rakesh H Sa3325d62015-04-04 19:42:29 +0530433 def test_stack_update_provider_group(self):
Peter Razumovskyf0ac9582015-09-24 16:49:03 +0300434 """Test two-level nested update."""
435
Rakesh H Sa3325d62015-04-04 19:42:29 +0530436 # Create a ResourceGroup (which creates a nested stack),
437 # containing provider resources (which create a nested
Steven Hardy23284b62015-10-01 19:03:42 +0100438 # stack), thus exercising an update which traverses
Rakesh H Sa3325d62015-04-04 19:42:29 +0530439 # two levels of nesting.
440 template = _change_rsrc_properties(
441 test_template_one_resource, ['test1'],
442 {'value': 'test_provider_group_template'})
443 files = {'provider.template': json.dumps(template)}
444 env = {'resource_registry':
445 {'My::TestResource': 'provider.template'}}
446
447 stack_identifier = self.stack_create(
448 template=self.provider_group_template,
449 files=files,
450 environment=env
451 )
452
453 initial_resources = {'test_group': 'OS::Heat::ResourceGroup'}
454 self.assertEqual(initial_resources,
455 self.list_resources(stack_identifier))
456
457 # Prove the resource is backed by a nested stack, save the ID
458 nested_identifier = self.assert_resource_is_a_stack(stack_identifier,
459 'test_group')
460
461 # Then check the expected resources are in the nested stack
462 nested_resources = {'0': 'My::TestResource',
463 '1': 'My::TestResource'}
464 self.assertEqual(nested_resources,
465 self.list_resources(nested_identifier))
466
467 for n_rsrc in nested_resources:
468 rsrc = self.client.resources.get(nested_identifier, n_rsrc)
469 provider_stack = self.client.stacks.get(rsrc.physical_resource_id)
470 provider_identifier = '%s/%s' % (provider_stack.stack_name,
471 provider_stack.id)
472 provider_resources = {u'test1': u'OS::Heat::TestResource'}
473 self.assertEqual(provider_resources,
474 self.list_resources(provider_identifier))
475
476 tmpl_update = _change_rsrc_properties(
477 test_template_two_resource, ['test1', 'test2'],
478 {'value': 'test_provider_group_template'})
479 # Add one resource via a stack update by changing the nested stack
480 files['provider.template'] = json.dumps(tmpl_update)
481 self.update_stack(stack_identifier, self.provider_group_template,
482 environment=env, files=files)
483
484 # Parent resources should be unchanged and the nested stack
485 # should have been updated in-place without replacement
486 self.assertEqual(initial_resources,
487 self.list_resources(stack_identifier))
488
489 # Resource group stack should also be unchanged (but updated)
490 nested_stack = self.client.stacks.get(nested_identifier)
491 self.assertEqual('UPDATE_COMPLETE', nested_stack.stack_status)
492 self.assertEqual(nested_resources,
493 self.list_resources(nested_identifier))
494
495 for n_rsrc in nested_resources:
496 rsrc = self.client.resources.get(nested_identifier, n_rsrc)
497 provider_stack = self.client.stacks.get(rsrc.physical_resource_id)
498 provider_identifier = '%s/%s' % (provider_stack.stack_name,
499 provider_stack.id)
500 provider_resources = {'test1': 'OS::Heat::TestResource',
501 'test2': 'OS::Heat::TestResource'}
502 self.assertEqual(provider_resources,
503 self.list_resources(provider_identifier))
504
505 def test_stack_update_with_replacing_userdata(self):
Peter Razumovskyf0ac9582015-09-24 16:49:03 +0300506 """Test case for updating userdata of instance.
Rakesh H Sa3325d62015-04-04 19:42:29 +0530507
Peter Razumovskyf0ac9582015-09-24 16:49:03 +0300508 Confirm that we can update userdata of instance during updating stack
509 by the user of member role.
510
511 Make sure that a resource that inherits from StackUser can be deleted
Rakesh H Sa3325d62015-04-04 19:42:29 +0530512 during updating stack.
513 """
514 if not self.conf.minimal_image_ref:
515 raise self.skipException("No minimal image configured to test")
516 if not self.conf.minimal_instance_type:
517 raise self.skipException("No flavor configured to test")
518
519 parms = {'flavor': self.conf.minimal_instance_type,
520 'image': self.conf.minimal_image_ref,
Rabi Mishraec4b03b2015-05-23 02:20:47 +0530521 'network': self.conf.fixed_network_name,
Rakesh H Sa3325d62015-04-04 19:42:29 +0530522 'user_data': ''}
Rakesh H Sa3325d62015-04-04 19:42:29 +0530523
524 stack_identifier = self.stack_create(
Rakesh H Sa3325d62015-04-04 19:42:29 +0530525 template=self.update_userdata_template,
526 parameters=parms
527 )
528
529 parms_updated = parms
530 parms_updated['user_data'] = 'two'
531 self.update_stack(
532 stack_identifier,
533 template=self.update_userdata_template,
534 parameters=parms_updated)
Steven Hardy23284b62015-10-01 19:03:42 +0100535
536 def test_stack_update_provider_group_patch(self):
537 '''Test two-level nested update with PATCH'''
538 template = _change_rsrc_properties(
539 test_template_one_resource, ['test1'],
540 {'value': 'test_provider_group_template'})
541 files = {'provider.template': json.dumps(template)}
542 env = {'resource_registry':
543 {'My::TestResource': 'provider.template'}}
544
545 stack_identifier = self.stack_create(
546 template=self.provider_group_template,
547 files=files,
548 environment=env
549 )
550
551 initial_resources = {'test_group': 'OS::Heat::ResourceGroup'}
552 self.assertEqual(initial_resources,
553 self.list_resources(stack_identifier))
554
555 # Prove the resource is backed by a nested stack, save the ID
556 nested_identifier = self.assert_resource_is_a_stack(stack_identifier,
557 'test_group')
558
559 # Then check the expected resources are in the nested stack
560 nested_resources = {'0': 'My::TestResource',
561 '1': 'My::TestResource'}
562 self.assertEqual(nested_resources,
563 self.list_resources(nested_identifier))
564
565 # increase the count, pass only the paramter, no env or template
566 params = {'count': 3}
567 self.update_stack(stack_identifier, parameters=params, existing=True)
568
569 # Parent resources should be unchanged and the nested stack
570 # should have been updated in-place without replacement
571 self.assertEqual(initial_resources,
572 self.list_resources(stack_identifier))
573
574 # Resource group stack should also be unchanged (but updated)
575 nested_stack = self.client.stacks.get(nested_identifier)
576 self.assertEqual('UPDATE_COMPLETE', nested_stack.stack_status)
577 # Add a resource, as we should have added one
578 nested_resources['2'] = 'My::TestResource'
579 self.assertEqual(nested_resources,
580 self.list_resources(nested_identifier))
581
582 def test_stack_update_from_failed_patch(self):
583 '''Test PATCH update from a failed state.'''
584
585 # Start with empty template
586 stack_identifier = self.stack_create(
587 template='heat_template_version: 2014-10-16')
588
589 # Update with a good template, but bad parameter
590 self.update_stack(stack_identifier,
591 template=self.fail_param_template,
592 parameters={'do_fail': True},
593 expected_status='UPDATE_FAILED')
594
595 # PATCH update, only providing the parameter
596 self.update_stack(stack_identifier,
597 parameters={'do_fail': False},
598 existing=True)
599 self.assertEqual({u'aresource': u'OS::Heat::TestResource'},
600 self.list_resources(stack_identifier))
Thomas Herveb0cccac2015-11-13 09:35:55 +0100601
602 def test_stack_update_with_new_env(self):
603 """Update handles new resource types in the environment.
604
605 If a resource type appears during an update and the update fails,
606 retrying the update is able to find the type properly in the
607 environment.
608 """
609 stack_identifier = self.stack_create(
610 template=test_template_one_resource)
611
612 # Update with a new resource and make the update fails
613 template = _change_rsrc_properties(test_template_one_resource,
614 ['test1'], {'fail': True})
615 template['resources']['test2'] = {'type': 'My::TestResource'}
616 template['resources']['test1']['depends_on'] = 'test2'
617 env = {'resource_registry':
618 {'My::TestResource': 'OS::Heat::TestResource'}}
619 self.update_stack(stack_identifier,
620 template=template,
621 environment=env,
622 expected_status='UPDATE_FAILED')
623
624 # Fixing the template should fix the stack
625 template = _change_rsrc_properties(template,
626 ['test1'], {'fail': False})
627 self.update_stack(stack_identifier,
628 template=template,
629 environment=env)
630 self.assertEqual({'test1': 'OS::Heat::TestResource',
631 'test2': 'My::TestResource'},
632 self.list_resources(stack_identifier))