blob: 446c9a36acae223d0191e21d7d3b5d483bf98711 [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,
Rabi Mishrabe7a59e2016-06-15 08:41:29 +053029 'wait_secs': 1,
Angus Salkeld73dcbc62015-08-31 09:02:58 +100030 '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}
Jaime Guerrero93a2da82016-05-23 21:31:43 +0000153 wait_secs: 1
Steven Hardy23284b62015-10-01 19:03:42 +0100154'''
155
Rakesh H Sa3325d62015-04-04 19:42:29 +0530156 def setUp(self):
157 super(UpdateStackTest, self).setUp()
Rakesh H Sa3325d62015-04-04 19:42:29 +0530158
159 def test_stack_update_nochange(self):
160 template = _change_rsrc_properties(test_template_one_resource,
161 ['test1'],
162 {'value': 'test_no_change'})
163 stack_identifier = self.stack_create(
164 template=template)
165 expected_resources = {'test1': 'OS::Heat::TestResource'}
166 self.assertEqual(expected_resources,
167 self.list_resources(stack_identifier))
168
169 # Update with no changes, resources should be unchanged
170 self.update_stack(stack_identifier, template)
171 self.assertEqual(expected_resources,
172 self.list_resources(stack_identifier))
173
174 def test_stack_in_place_update(self):
175 template = _change_rsrc_properties(test_template_one_resource,
176 ['test1'],
177 {'value': 'test_in_place'})
178 stack_identifier = self.stack_create(
179 template=template)
180 expected_resources = {'test1': 'OS::Heat::TestResource'}
181 self.assertEqual(expected_resources,
182 self.list_resources(stack_identifier))
183 resource = self.client.resources.list(stack_identifier)
184 initial_phy_id = resource[0].physical_resource_id
185
186 tmpl_update = _change_rsrc_properties(
187 test_template_one_resource, ['test1'],
188 {'value': 'test_in_place_update'})
189 # Update the Value
190 self.update_stack(stack_identifier, tmpl_update)
191 resource = self.client.resources.list(stack_identifier)
192 # By default update_in_place
193 self.assertEqual(initial_phy_id,
194 resource[0].physical_resource_id)
195
196 def test_stack_update_replace(self):
197 template = _change_rsrc_properties(test_template_one_resource,
198 ['test1'],
199 {'value': 'test_replace'})
200 stack_identifier = self.stack_create(
201 template=template)
202 expected_resources = {'test1': 'OS::Heat::TestResource'}
203 self.assertEqual(expected_resources,
204 self.list_resources(stack_identifier))
205 resource = self.client.resources.list(stack_identifier)
206 initial_phy_id = resource[0].physical_resource_id
207
208 # Update the value and also set update_replace prop
209 tmpl_update = _change_rsrc_properties(
210 test_template_one_resource, ['test1'],
211 {'value': 'test_in_place_update', 'update_replace': True})
212 self.update_stack(stack_identifier, tmpl_update)
213 resource = self.client.resources.list(stack_identifier)
214 # update Replace
215 self.assertNotEqual(initial_phy_id,
216 resource[0].physical_resource_id)
217
218 def test_stack_update_add_remove(self):
219 template = _change_rsrc_properties(test_template_one_resource,
220 ['test1'],
221 {'value': 'test_add_remove'})
222 stack_identifier = self.stack_create(
223 template=template)
224 initial_resources = {'test1': 'OS::Heat::TestResource'}
225 self.assertEqual(initial_resources,
226 self.list_resources(stack_identifier))
227
228 tmpl_update = _change_rsrc_properties(
229 test_template_two_resource, ['test1', 'test2'],
230 {'value': 'test_add_remove_update'})
231 # Add one resource via a stack update
232 self.update_stack(stack_identifier, tmpl_update)
233 updated_resources = {'test1': 'OS::Heat::TestResource',
234 'test2': 'OS::Heat::TestResource'}
235 self.assertEqual(updated_resources,
236 self.list_resources(stack_identifier))
237
238 # Then remove it by updating with the original template
239 self.update_stack(stack_identifier, template)
240 self.assertEqual(initial_resources,
241 self.list_resources(stack_identifier))
242
243 def test_stack_update_rollback(self):
244 template = _change_rsrc_properties(test_template_one_resource,
245 ['test1'],
246 {'value': 'test_update_rollback'})
247 stack_identifier = self.stack_create(
248 template=template)
249 initial_resources = {'test1': 'OS::Heat::TestResource'}
250 self.assertEqual(initial_resources,
251 self.list_resources(stack_identifier))
252
253 tmpl_update = _change_rsrc_properties(
254 test_template_two_resource, ['test1', 'test2'],
255 {'value': 'test_update_rollback', 'fail': True})
256 # stack update, also set failure
257 self.update_stack(stack_identifier, tmpl_update,
258 expected_status='ROLLBACK_COMPLETE',
259 disable_rollback=False)
260 # since stack update failed only the original resource is present
261 updated_resources = {'test1': 'OS::Heat::TestResource'}
262 self.assertEqual(updated_resources,
263 self.list_resources(stack_identifier))
264
Sergey Kraynev89082a32015-09-04 04:42:33 -0400265 def test_stack_update_from_failed(self):
266 # Prove it's possible to update from an UPDATE_FAILED state
267 template = _change_rsrc_properties(test_template_one_resource,
268 ['test1'],
269 {'value': 'test_update_failed'})
270 stack_identifier = self.stack_create(
271 template=template)
272 initial_resources = {'test1': 'OS::Heat::TestResource'}
273 self.assertEqual(initial_resources,
274 self.list_resources(stack_identifier))
275
276 tmpl_update = _change_rsrc_properties(
277 test_template_one_resource, ['test1'], {'fail': True})
278 # Update with bad template, we should fail
279 self.update_stack(stack_identifier, tmpl_update,
280 expected_status='UPDATE_FAILED')
281 # but then passing a good template should succeed
282 self.update_stack(stack_identifier, test_template_two_resource)
283 updated_resources = {'test1': 'OS::Heat::TestResource',
284 'test2': 'OS::Heat::TestResource'}
285 self.assertEqual(updated_resources,
286 self.list_resources(stack_identifier))
287
Rakesh H Sa3325d62015-04-04 19:42:29 +0530288 def test_stack_update_provider(self):
289 template = _change_rsrc_properties(
290 test_template_one_resource, ['test1'],
291 {'value': 'test_provider_template'})
292 files = {'provider.template': json.dumps(template)}
293 env = {'resource_registry':
294 {'My::TestResource': 'provider.template'}}
295 stack_identifier = self.stack_create(
296 template=self.provider_template,
297 files=files,
298 environment=env
299 )
300
301 initial_resources = {'test1': 'My::TestResource'}
302 self.assertEqual(initial_resources,
303 self.list_resources(stack_identifier))
304
305 # Prove the resource is backed by a nested stack, save the ID
306 nested_identifier = self.assert_resource_is_a_stack(stack_identifier,
307 'test1')
308 nested_id = nested_identifier.split('/')[-1]
309
310 # Then check the expected resources are in the nested stack
311 nested_resources = {'test1': 'OS::Heat::TestResource'}
312 self.assertEqual(nested_resources,
313 self.list_resources(nested_identifier))
314 tmpl_update = _change_rsrc_properties(
315 test_template_two_resource, ['test1', 'test2'],
316 {'value': 'test_provider_template'})
317 # Add one resource via a stack update by changing the nested stack
318 files['provider.template'] = json.dumps(tmpl_update)
319 self.update_stack(stack_identifier, self.provider_template,
320 environment=env, files=files)
321
322 # Parent resources should be unchanged and the nested stack
323 # should have been updated in-place without replacement
324 self.assertEqual(initial_resources,
325 self.list_resources(stack_identifier))
326 rsrc = self.client.resources.get(stack_identifier, 'test1')
327 self.assertEqual(rsrc.physical_resource_id, nested_id)
328
329 # Then check the expected resources are in the nested stack
330 nested_resources = {'test1': 'OS::Heat::TestResource',
331 'test2': 'OS::Heat::TestResource'}
332 self.assertEqual(nested_resources,
333 self.list_resources(nested_identifier))
334
Steven Hardy8a3c1ec2015-10-21 18:56:01 +0100335 def test_stack_update_alias_type(self):
336 env = {'resource_registry':
337 {'My::TestResource': 'OS::Heat::RandomString',
338 'My::TestResource2': 'OS::Heat::RandomString'}}
339 stack_identifier = self.stack_create(
340 template=self.provider_template,
341 environment=env
342 )
343 p_res = self.client.resources.get(stack_identifier, 'test1')
344 self.assertEqual('My::TestResource', p_res.resource_type)
345
346 initial_resources = {'test1': 'My::TestResource'}
347 self.assertEqual(initial_resources,
348 self.list_resources(stack_identifier))
349 res = self.client.resources.get(stack_identifier, 'test1')
350 # Modify the type of the resource alias to My::TestResource2
351 tmpl_update = copy.deepcopy(self.provider_template)
352 tmpl_update['resources']['test1']['type'] = 'My::TestResource2'
353 self.update_stack(stack_identifier, tmpl_update, environment=env)
354 res_a = self.client.resources.get(stack_identifier, 'test1')
355 self.assertEqual(res.physical_resource_id, res_a.physical_resource_id)
356 self.assertEqual(res.attributes['value'], res_a.attributes['value'])
357
358 def test_stack_update_alias_changes(self):
359 env = {'resource_registry':
360 {'My::TestResource': 'OS::Heat::RandomString'}}
361 stack_identifier = self.stack_create(
362 template=self.provider_template,
363 environment=env
364 )
365 p_res = self.client.resources.get(stack_identifier, 'test1')
366 self.assertEqual('My::TestResource', p_res.resource_type)
367
368 initial_resources = {'test1': 'My::TestResource'}
369 self.assertEqual(initial_resources,
370 self.list_resources(stack_identifier))
371 res = self.client.resources.get(stack_identifier, 'test1')
372 # Modify the resource alias to point to a different type
373 env = {'resource_registry':
374 {'My::TestResource': 'OS::Heat::TestResource'}}
375 self.update_stack(stack_identifier, template=self.provider_template,
376 environment=env)
377 res_a = self.client.resources.get(stack_identifier, 'test1')
378 self.assertNotEqual(res.physical_resource_id,
379 res_a.physical_resource_id)
380
381 def test_stack_update_provider_type(self):
382 template = _change_rsrc_properties(
383 test_template_one_resource, ['test1'],
384 {'value': 'test_provider_template'})
385 files = {'provider.template': json.dumps(template)}
386 env = {'resource_registry':
387 {'My::TestResource': 'provider.template',
388 'My::TestResource2': 'provider.template'}}
389 stack_identifier = self.stack_create(
390 template=self.provider_template,
391 files=files,
392 environment=env
393 )
394 p_res = self.client.resources.get(stack_identifier, 'test1')
395 self.assertEqual('My::TestResource', p_res.resource_type)
396
397 initial_resources = {'test1': 'My::TestResource'}
398 self.assertEqual(initial_resources,
399 self.list_resources(stack_identifier))
400
401 # Prove the resource is backed by a nested stack, save the ID
402 nested_identifier = self.assert_resource_is_a_stack(stack_identifier,
403 'test1')
404 nested_id = nested_identifier.split('/')[-1]
405
406 # Then check the expected resources are in the nested stack
407 nested_resources = {'test1': 'OS::Heat::TestResource'}
408 self.assertEqual(nested_resources,
409 self.list_resources(nested_identifier))
410 n_res = self.client.resources.get(nested_identifier, 'test1')
411
412 # Modify the type of the provider resource to My::TestResource2
413 tmpl_update = copy.deepcopy(self.provider_template)
414 tmpl_update['resources']['test1']['type'] = 'My::TestResource2'
415 self.update_stack(stack_identifier, tmpl_update,
416 environment=env, files=files)
417 p_res = self.client.resources.get(stack_identifier, 'test1')
418 self.assertEqual('My::TestResource2', p_res.resource_type)
419
420 # Parent resources should be unchanged and the nested stack
421 # should have been updated in-place without replacement
422 self.assertEqual({u'test1': u'My::TestResource2'},
423 self.list_resources(stack_identifier))
424 rsrc = self.client.resources.get(stack_identifier, 'test1')
425 self.assertEqual(rsrc.physical_resource_id, nested_id)
426
427 # Then check the expected resources are in the nested stack
428 self.assertEqual(nested_resources,
429 self.list_resources(nested_identifier))
430 n_res2 = self.client.resources.get(nested_identifier, 'test1')
431 self.assertEqual(n_res.physical_resource_id,
432 n_res2.physical_resource_id)
433
Rakesh H Sa3325d62015-04-04 19:42:29 +0530434 def test_stack_update_provider_group(self):
Peter Razumovskyf0ac9582015-09-24 16:49:03 +0300435 """Test two-level nested update."""
436
Rakesh H Sa3325d62015-04-04 19:42:29 +0530437 # Create a ResourceGroup (which creates a nested stack),
438 # containing provider resources (which create a nested
Steven Hardy23284b62015-10-01 19:03:42 +0100439 # stack), thus exercising an update which traverses
Rakesh H Sa3325d62015-04-04 19:42:29 +0530440 # two levels of nesting.
441 template = _change_rsrc_properties(
442 test_template_one_resource, ['test1'],
443 {'value': 'test_provider_group_template'})
444 files = {'provider.template': json.dumps(template)}
445 env = {'resource_registry':
446 {'My::TestResource': 'provider.template'}}
447
448 stack_identifier = self.stack_create(
449 template=self.provider_group_template,
450 files=files,
451 environment=env
452 )
453
454 initial_resources = {'test_group': 'OS::Heat::ResourceGroup'}
455 self.assertEqual(initial_resources,
456 self.list_resources(stack_identifier))
457
458 # Prove the resource is backed by a nested stack, save the ID
459 nested_identifier = self.assert_resource_is_a_stack(stack_identifier,
460 'test_group')
461
462 # Then check the expected resources are in the nested stack
463 nested_resources = {'0': 'My::TestResource',
464 '1': 'My::TestResource'}
465 self.assertEqual(nested_resources,
466 self.list_resources(nested_identifier))
467
468 for n_rsrc in nested_resources:
469 rsrc = self.client.resources.get(nested_identifier, n_rsrc)
470 provider_stack = self.client.stacks.get(rsrc.physical_resource_id)
471 provider_identifier = '%s/%s' % (provider_stack.stack_name,
472 provider_stack.id)
473 provider_resources = {u'test1': u'OS::Heat::TestResource'}
474 self.assertEqual(provider_resources,
475 self.list_resources(provider_identifier))
476
477 tmpl_update = _change_rsrc_properties(
478 test_template_two_resource, ['test1', 'test2'],
479 {'value': 'test_provider_group_template'})
480 # Add one resource via a stack update by changing the nested stack
481 files['provider.template'] = json.dumps(tmpl_update)
482 self.update_stack(stack_identifier, self.provider_group_template,
483 environment=env, files=files)
484
485 # Parent resources should be unchanged and the nested stack
486 # should have been updated in-place without replacement
487 self.assertEqual(initial_resources,
488 self.list_resources(stack_identifier))
489
490 # Resource group stack should also be unchanged (but updated)
491 nested_stack = self.client.stacks.get(nested_identifier)
492 self.assertEqual('UPDATE_COMPLETE', nested_stack.stack_status)
493 self.assertEqual(nested_resources,
494 self.list_resources(nested_identifier))
495
496 for n_rsrc in nested_resources:
497 rsrc = self.client.resources.get(nested_identifier, n_rsrc)
498 provider_stack = self.client.stacks.get(rsrc.physical_resource_id)
499 provider_identifier = '%s/%s' % (provider_stack.stack_name,
500 provider_stack.id)
501 provider_resources = {'test1': 'OS::Heat::TestResource',
502 'test2': 'OS::Heat::TestResource'}
503 self.assertEqual(provider_resources,
504 self.list_resources(provider_identifier))
505
506 def test_stack_update_with_replacing_userdata(self):
Peter Razumovskyf0ac9582015-09-24 16:49:03 +0300507 """Test case for updating userdata of instance.
Rakesh H Sa3325d62015-04-04 19:42:29 +0530508
Peter Razumovskyf0ac9582015-09-24 16:49:03 +0300509 Confirm that we can update userdata of instance during updating stack
510 by the user of member role.
511
512 Make sure that a resource that inherits from StackUser can be deleted
Rakesh H Sa3325d62015-04-04 19:42:29 +0530513 during updating stack.
514 """
515 if not self.conf.minimal_image_ref:
516 raise self.skipException("No minimal image configured to test")
517 if not self.conf.minimal_instance_type:
518 raise self.skipException("No flavor configured to test")
519
520 parms = {'flavor': self.conf.minimal_instance_type,
521 'image': self.conf.minimal_image_ref,
Rabi Mishraec4b03b2015-05-23 02:20:47 +0530522 'network': self.conf.fixed_network_name,
Rakesh H Sa3325d62015-04-04 19:42:29 +0530523 'user_data': ''}
Rakesh H Sa3325d62015-04-04 19:42:29 +0530524
525 stack_identifier = self.stack_create(
Rakesh H Sa3325d62015-04-04 19:42:29 +0530526 template=self.update_userdata_template,
527 parameters=parms
528 )
529
530 parms_updated = parms
531 parms_updated['user_data'] = 'two'
532 self.update_stack(
533 stack_identifier,
534 template=self.update_userdata_template,
535 parameters=parms_updated)
Steven Hardy23284b62015-10-01 19:03:42 +0100536
537 def test_stack_update_provider_group_patch(self):
538 '''Test two-level nested update with PATCH'''
539 template = _change_rsrc_properties(
540 test_template_one_resource, ['test1'],
541 {'value': 'test_provider_group_template'})
542 files = {'provider.template': json.dumps(template)}
543 env = {'resource_registry':
544 {'My::TestResource': 'provider.template'}}
545
546 stack_identifier = self.stack_create(
547 template=self.provider_group_template,
548 files=files,
549 environment=env
550 )
551
552 initial_resources = {'test_group': 'OS::Heat::ResourceGroup'}
553 self.assertEqual(initial_resources,
554 self.list_resources(stack_identifier))
555
556 # Prove the resource is backed by a nested stack, save the ID
557 nested_identifier = self.assert_resource_is_a_stack(stack_identifier,
558 'test_group')
559
560 # Then check the expected resources are in the nested stack
561 nested_resources = {'0': 'My::TestResource',
562 '1': 'My::TestResource'}
563 self.assertEqual(nested_resources,
564 self.list_resources(nested_identifier))
565
566 # increase the count, pass only the paramter, no env or template
567 params = {'count': 3}
568 self.update_stack(stack_identifier, parameters=params, existing=True)
569
570 # Parent resources should be unchanged and the nested stack
571 # should have been updated in-place without replacement
572 self.assertEqual(initial_resources,
573 self.list_resources(stack_identifier))
574
575 # Resource group stack should also be unchanged (but updated)
576 nested_stack = self.client.stacks.get(nested_identifier)
577 self.assertEqual('UPDATE_COMPLETE', nested_stack.stack_status)
578 # Add a resource, as we should have added one
579 nested_resources['2'] = 'My::TestResource'
580 self.assertEqual(nested_resources,
581 self.list_resources(nested_identifier))
582
583 def test_stack_update_from_failed_patch(self):
584 '''Test PATCH update from a failed state.'''
585
586 # Start with empty template
587 stack_identifier = self.stack_create(
588 template='heat_template_version: 2014-10-16')
589
590 # Update with a good template, but bad parameter
591 self.update_stack(stack_identifier,
592 template=self.fail_param_template,
593 parameters={'do_fail': True},
594 expected_status='UPDATE_FAILED')
595
596 # PATCH update, only providing the parameter
597 self.update_stack(stack_identifier,
598 parameters={'do_fail': False},
599 existing=True)
600 self.assertEqual({u'aresource': u'OS::Heat::TestResource'},
601 self.list_resources(stack_identifier))
Thomas Herveb0cccac2015-11-13 09:35:55 +0100602
603 def test_stack_update_with_new_env(self):
604 """Update handles new resource types in the environment.
605
606 If a resource type appears during an update and the update fails,
607 retrying the update is able to find the type properly in the
608 environment.
609 """
610 stack_identifier = self.stack_create(
611 template=test_template_one_resource)
612
613 # Update with a new resource and make the update fails
614 template = _change_rsrc_properties(test_template_one_resource,
615 ['test1'], {'fail': True})
616 template['resources']['test2'] = {'type': 'My::TestResource'}
617 template['resources']['test1']['depends_on'] = 'test2'
618 env = {'resource_registry':
619 {'My::TestResource': 'OS::Heat::TestResource'}}
620 self.update_stack(stack_identifier,
621 template=template,
622 environment=env,
623 expected_status='UPDATE_FAILED')
624
625 # Fixing the template should fix the stack
626 template = _change_rsrc_properties(template,
627 ['test1'], {'fail': False})
628 self.update_stack(stack_identifier,
629 template=template,
630 environment=env)
631 self.assertEqual({'test1': 'OS::Heat::TestResource',
632 'test2': 'My::TestResource'},
633 self.list_resources(stack_identifier))