blob: 3d4ca764872a90af756e70f9e53b6acaa010c958 [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
Thomas Herve4bc75ee2017-07-05 11:46:49 +020017from heat_integrationtests.common import test
Rabi Mishra477efc92015-07-31 13:01:45 +053018from heat_integrationtests.functional import functional_base
19
Rakesh H Sa3325d62015-04-04 19:42:29 +053020test_template_one_resource = {
Thomas Herve92902b82017-06-22 22:40:50 +020021 'heat_template_version': 'pike',
Rakesh H Sa3325d62015-04-04 19:42:29 +053022 'description': 'Test template to create one instance.',
23 'resources': {
24 'test1': {
25 'type': 'OS::Heat::TestResource',
26 'properties': {
27 'value': 'Test1',
28 'fail': False,
29 'update_replace': False,
Rabi Mishrabe7a59e2016-06-15 08:41:29 +053030 'wait_secs': 1,
Angus Salkeld73dcbc62015-08-31 09:02:58 +100031 'action_wait_secs': {'create': 1},
32 'client_name': 'nova',
33 'entity_name': 'servers',
Rakesh H Sa3325d62015-04-04 19:42:29 +053034 }
35 }
36 }
37}
38
39test_template_two_resource = {
Thomas Herve92902b82017-06-22 22:40:50 +020040 'heat_template_version': 'pike',
Rakesh H Sa3325d62015-04-04 19:42:29 +053041 'description': 'Test template to create two instance.',
42 'resources': {
43 'test1': {
44 'type': 'OS::Heat::TestResource',
45 'properties': {
46 'value': 'Test1',
47 'fail': False,
48 'update_replace': False,
Angus Salkeld73dcbc62015-08-31 09:02:58 +100049 'wait_secs': 0,
50 'action_wait_secs': {'update': 1}
Rakesh H Sa3325d62015-04-04 19:42:29 +053051 }
52 },
53 'test2': {
54 'type': 'OS::Heat::TestResource',
55 'properties': {
56 'value': 'Test1',
57 'fail': False,
58 'update_replace': False,
59 'wait_secs': 0
60 }
61 }
62 }
63}
64
65
66def _change_rsrc_properties(template, rsrcs, values):
67 modified_template = copy.deepcopy(template)
68 for rsrc_name in rsrcs:
69 rsrc_prop = modified_template['resources'][
70 rsrc_name]['properties']
71 for prop in rsrc_prop:
72 if prop in values:
73 rsrc_prop[prop] = values[prop]
74 return modified_template
75
76
Rabi Mishra477efc92015-07-31 13:01:45 +053077class CreateStackTest(functional_base.FunctionalTestsBase):
Rakesh H Sa3325d62015-04-04 19:42:29 +053078 def test_create_rollback(self):
79 values = {'fail': True, 'value': 'test_create_rollback'}
80 template = _change_rsrc_properties(test_template_one_resource,
81 ['test1'], values)
82
83 self.stack_create(
84 template=template,
85 expected_status='ROLLBACK_COMPLETE',
86 disable_rollback=False)
87
88
Rabi Mishra477efc92015-07-31 13:01:45 +053089class UpdateStackTest(functional_base.FunctionalTestsBase):
Rakesh H Sa3325d62015-04-04 19:42:29 +053090
91 provider_template = {
92 'heat_template_version': '2013-05-23',
93 'description': 'foo',
94 'resources': {
95 'test1': {
96 'type': 'My::TestResource'
97 }
98 }
99 }
100
101 provider_group_template = '''
102heat_template_version: 2013-05-23
Steven Hardy23284b62015-10-01 19:03:42 +0100103parameters:
104 count:
105 type: number
106 default: 2
Rakesh H Sa3325d62015-04-04 19:42:29 +0530107resources:
108 test_group:
109 type: OS::Heat::ResourceGroup
110 properties:
Steven Hardy23284b62015-10-01 19:03:42 +0100111 count: {get_param: count}
Rakesh H Sa3325d62015-04-04 19:42:29 +0530112 resource_def:
113 type: My::TestResource
114'''
115
116 update_userdata_template = '''
117heat_template_version: 2014-10-16
118parameters:
119 flavor:
120 type: string
121 user_data:
122 type: string
123 image:
124 type: string
Rabi Mishraec4b03b2015-05-23 02:20:47 +0530125 network:
126 type: string
Rakesh H Sa3325d62015-04-04 19:42:29 +0530127
128resources:
129 server:
130 type: OS::Nova::Server
131 properties:
132 image: {get_param: image}
133 flavor: {get_param: flavor}
Rabi Mishraec4b03b2015-05-23 02:20:47 +0530134 networks: [{network: {get_param: network} }]
Rakesh H Sa3325d62015-04-04 19:42:29 +0530135 user_data_format: SOFTWARE_CONFIG
136 user_data: {get_param: user_data}
137'''
138
Steven Hardy23284b62015-10-01 19:03:42 +0100139 fail_param_template = '''
140heat_template_version: 2014-10-16
141parameters:
142 do_fail:
143 type: boolean
144 default: False
145resources:
146 aresource:
147 type: OS::Heat::TestResource
148 properties:
149 value: Test
150 fail: {get_param: do_fail}
Jaime Guerrero93a2da82016-05-23 21:31:43 +0000151 wait_secs: 1
Steven Hardy23284b62015-10-01 19:03:42 +0100152'''
153
Rakesh H Sa3325d62015-04-04 19:42:29 +0530154 def test_stack_update_nochange(self):
155 template = _change_rsrc_properties(test_template_one_resource,
156 ['test1'],
157 {'value': 'test_no_change'})
158 stack_identifier = self.stack_create(
159 template=template)
160 expected_resources = {'test1': 'OS::Heat::TestResource'}
161 self.assertEqual(expected_resources,
162 self.list_resources(stack_identifier))
163
164 # Update with no changes, resources should be unchanged
165 self.update_stack(stack_identifier, template)
166 self.assertEqual(expected_resources,
167 self.list_resources(stack_identifier))
168
169 def test_stack_in_place_update(self):
170 template = _change_rsrc_properties(test_template_one_resource,
171 ['test1'],
172 {'value': 'test_in_place'})
173 stack_identifier = self.stack_create(
174 template=template)
175 expected_resources = {'test1': 'OS::Heat::TestResource'}
176 self.assertEqual(expected_resources,
177 self.list_resources(stack_identifier))
178 resource = self.client.resources.list(stack_identifier)
179 initial_phy_id = resource[0].physical_resource_id
180
181 tmpl_update = _change_rsrc_properties(
182 test_template_one_resource, ['test1'],
183 {'value': 'test_in_place_update'})
184 # Update the Value
185 self.update_stack(stack_identifier, tmpl_update)
186 resource = self.client.resources.list(stack_identifier)
187 # By default update_in_place
188 self.assertEqual(initial_phy_id,
189 resource[0].physical_resource_id)
190
191 def test_stack_update_replace(self):
192 template = _change_rsrc_properties(test_template_one_resource,
193 ['test1'],
194 {'value': 'test_replace'})
195 stack_identifier = self.stack_create(
196 template=template)
197 expected_resources = {'test1': 'OS::Heat::TestResource'}
198 self.assertEqual(expected_resources,
199 self.list_resources(stack_identifier))
200 resource = self.client.resources.list(stack_identifier)
201 initial_phy_id = resource[0].physical_resource_id
202
203 # Update the value and also set update_replace prop
204 tmpl_update = _change_rsrc_properties(
205 test_template_one_resource, ['test1'],
206 {'value': 'test_in_place_update', 'update_replace': True})
207 self.update_stack(stack_identifier, tmpl_update)
208 resource = self.client.resources.list(stack_identifier)
209 # update Replace
210 self.assertNotEqual(initial_phy_id,
211 resource[0].physical_resource_id)
212
213 def test_stack_update_add_remove(self):
214 template = _change_rsrc_properties(test_template_one_resource,
215 ['test1'],
216 {'value': 'test_add_remove'})
217 stack_identifier = self.stack_create(
218 template=template)
219 initial_resources = {'test1': 'OS::Heat::TestResource'}
220 self.assertEqual(initial_resources,
221 self.list_resources(stack_identifier))
222
223 tmpl_update = _change_rsrc_properties(
224 test_template_two_resource, ['test1', 'test2'],
225 {'value': 'test_add_remove_update'})
226 # Add one resource via a stack update
227 self.update_stack(stack_identifier, tmpl_update)
228 updated_resources = {'test1': 'OS::Heat::TestResource',
229 'test2': 'OS::Heat::TestResource'}
230 self.assertEqual(updated_resources,
231 self.list_resources(stack_identifier))
232
233 # Then remove it by updating with the original template
234 self.update_stack(stack_identifier, template)
235 self.assertEqual(initial_resources,
236 self.list_resources(stack_identifier))
237
238 def test_stack_update_rollback(self):
239 template = _change_rsrc_properties(test_template_one_resource,
240 ['test1'],
241 {'value': 'test_update_rollback'})
242 stack_identifier = self.stack_create(
243 template=template)
244 initial_resources = {'test1': 'OS::Heat::TestResource'}
245 self.assertEqual(initial_resources,
246 self.list_resources(stack_identifier))
247
248 tmpl_update = _change_rsrc_properties(
249 test_template_two_resource, ['test1', 'test2'],
250 {'value': 'test_update_rollback', 'fail': True})
251 # stack update, also set failure
252 self.update_stack(stack_identifier, tmpl_update,
253 expected_status='ROLLBACK_COMPLETE',
254 disable_rollback=False)
255 # since stack update failed only the original resource is present
256 updated_resources = {'test1': 'OS::Heat::TestResource'}
257 self.assertEqual(updated_resources,
258 self.list_resources(stack_identifier))
259
Sergey Kraynev89082a32015-09-04 04:42:33 -0400260 def test_stack_update_from_failed(self):
261 # Prove it's possible to update from an UPDATE_FAILED state
262 template = _change_rsrc_properties(test_template_one_resource,
263 ['test1'],
264 {'value': 'test_update_failed'})
265 stack_identifier = self.stack_create(
266 template=template)
267 initial_resources = {'test1': 'OS::Heat::TestResource'}
268 self.assertEqual(initial_resources,
269 self.list_resources(stack_identifier))
270
271 tmpl_update = _change_rsrc_properties(
272 test_template_one_resource, ['test1'], {'fail': True})
273 # Update with bad template, we should fail
274 self.update_stack(stack_identifier, tmpl_update,
275 expected_status='UPDATE_FAILED')
276 # but then passing a good template should succeed
277 self.update_stack(stack_identifier, test_template_two_resource)
278 updated_resources = {'test1': 'OS::Heat::TestResource',
279 'test2': 'OS::Heat::TestResource'}
280 self.assertEqual(updated_resources,
281 self.list_resources(stack_identifier))
282
Rakesh H Sa3325d62015-04-04 19:42:29 +0530283 def test_stack_update_provider(self):
284 template = _change_rsrc_properties(
285 test_template_one_resource, ['test1'],
286 {'value': 'test_provider_template'})
287 files = {'provider.template': json.dumps(template)}
288 env = {'resource_registry':
289 {'My::TestResource': 'provider.template'}}
290 stack_identifier = self.stack_create(
291 template=self.provider_template,
292 files=files,
293 environment=env
294 )
295
296 initial_resources = {'test1': 'My::TestResource'}
297 self.assertEqual(initial_resources,
298 self.list_resources(stack_identifier))
299
300 # Prove the resource is backed by a nested stack, save the ID
301 nested_identifier = self.assert_resource_is_a_stack(stack_identifier,
302 'test1')
303 nested_id = nested_identifier.split('/')[-1]
304
305 # Then check the expected resources are in the nested stack
306 nested_resources = {'test1': 'OS::Heat::TestResource'}
307 self.assertEqual(nested_resources,
308 self.list_resources(nested_identifier))
309 tmpl_update = _change_rsrc_properties(
310 test_template_two_resource, ['test1', 'test2'],
311 {'value': 'test_provider_template'})
312 # Add one resource via a stack update by changing the nested stack
313 files['provider.template'] = json.dumps(tmpl_update)
314 self.update_stack(stack_identifier, self.provider_template,
315 environment=env, files=files)
316
317 # Parent resources should be unchanged and the nested stack
318 # should have been updated in-place without replacement
319 self.assertEqual(initial_resources,
320 self.list_resources(stack_identifier))
321 rsrc = self.client.resources.get(stack_identifier, 'test1')
322 self.assertEqual(rsrc.physical_resource_id, nested_id)
323
324 # Then check the expected resources are in the nested stack
325 nested_resources = {'test1': 'OS::Heat::TestResource',
326 'test2': 'OS::Heat::TestResource'}
327 self.assertEqual(nested_resources,
328 self.list_resources(nested_identifier))
329
Steven Hardy8a3c1ec2015-10-21 18:56:01 +0100330 def test_stack_update_alias_type(self):
331 env = {'resource_registry':
332 {'My::TestResource': 'OS::Heat::RandomString',
333 'My::TestResource2': 'OS::Heat::RandomString'}}
334 stack_identifier = self.stack_create(
335 template=self.provider_template,
336 environment=env
337 )
338 p_res = self.client.resources.get(stack_identifier, 'test1')
339 self.assertEqual('My::TestResource', p_res.resource_type)
340
341 initial_resources = {'test1': 'My::TestResource'}
342 self.assertEqual(initial_resources,
343 self.list_resources(stack_identifier))
344 res = self.client.resources.get(stack_identifier, 'test1')
345 # Modify the type of the resource alias to My::TestResource2
346 tmpl_update = copy.deepcopy(self.provider_template)
347 tmpl_update['resources']['test1']['type'] = 'My::TestResource2'
348 self.update_stack(stack_identifier, tmpl_update, environment=env)
349 res_a = self.client.resources.get(stack_identifier, 'test1')
350 self.assertEqual(res.physical_resource_id, res_a.physical_resource_id)
351 self.assertEqual(res.attributes['value'], res_a.attributes['value'])
352
353 def test_stack_update_alias_changes(self):
354 env = {'resource_registry':
355 {'My::TestResource': 'OS::Heat::RandomString'}}
356 stack_identifier = self.stack_create(
357 template=self.provider_template,
358 environment=env
359 )
360 p_res = self.client.resources.get(stack_identifier, 'test1')
361 self.assertEqual('My::TestResource', p_res.resource_type)
362
363 initial_resources = {'test1': 'My::TestResource'}
364 self.assertEqual(initial_resources,
365 self.list_resources(stack_identifier))
366 res = self.client.resources.get(stack_identifier, 'test1')
367 # Modify the resource alias to point to a different type
368 env = {'resource_registry':
369 {'My::TestResource': 'OS::Heat::TestResource'}}
370 self.update_stack(stack_identifier, template=self.provider_template,
371 environment=env)
372 res_a = self.client.resources.get(stack_identifier, 'test1')
373 self.assertNotEqual(res.physical_resource_id,
374 res_a.physical_resource_id)
375
376 def test_stack_update_provider_type(self):
377 template = _change_rsrc_properties(
378 test_template_one_resource, ['test1'],
379 {'value': 'test_provider_template'})
380 files = {'provider.template': json.dumps(template)}
381 env = {'resource_registry':
382 {'My::TestResource': 'provider.template',
383 'My::TestResource2': 'provider.template'}}
384 stack_identifier = self.stack_create(
385 template=self.provider_template,
386 files=files,
387 environment=env
388 )
389 p_res = self.client.resources.get(stack_identifier, 'test1')
390 self.assertEqual('My::TestResource', p_res.resource_type)
391
392 initial_resources = {'test1': 'My::TestResource'}
393 self.assertEqual(initial_resources,
394 self.list_resources(stack_identifier))
395
396 # Prove the resource is backed by a nested stack, save the ID
397 nested_identifier = self.assert_resource_is_a_stack(stack_identifier,
398 'test1')
399 nested_id = nested_identifier.split('/')[-1]
400
401 # Then check the expected resources are in the nested stack
402 nested_resources = {'test1': 'OS::Heat::TestResource'}
403 self.assertEqual(nested_resources,
404 self.list_resources(nested_identifier))
405 n_res = self.client.resources.get(nested_identifier, 'test1')
406
407 # Modify the type of the provider resource to My::TestResource2
408 tmpl_update = copy.deepcopy(self.provider_template)
409 tmpl_update['resources']['test1']['type'] = 'My::TestResource2'
410 self.update_stack(stack_identifier, tmpl_update,
411 environment=env, files=files)
412 p_res = self.client.resources.get(stack_identifier, 'test1')
413 self.assertEqual('My::TestResource2', p_res.resource_type)
414
415 # Parent resources should be unchanged and the nested stack
416 # should have been updated in-place without replacement
417 self.assertEqual({u'test1': u'My::TestResource2'},
418 self.list_resources(stack_identifier))
419 rsrc = self.client.resources.get(stack_identifier, 'test1')
420 self.assertEqual(rsrc.physical_resource_id, nested_id)
421
422 # Then check the expected resources are in the nested stack
423 self.assertEqual(nested_resources,
424 self.list_resources(nested_identifier))
425 n_res2 = self.client.resources.get(nested_identifier, 'test1')
426 self.assertEqual(n_res.physical_resource_id,
427 n_res2.physical_resource_id)
428
Rakesh H Sa3325d62015-04-04 19:42:29 +0530429 def test_stack_update_provider_group(self):
Peter Razumovskyf0ac9582015-09-24 16:49:03 +0300430 """Test two-level nested update."""
431
Rakesh H Sa3325d62015-04-04 19:42:29 +0530432 # Create a ResourceGroup (which creates a nested stack),
433 # containing provider resources (which create a nested
Steven Hardy23284b62015-10-01 19:03:42 +0100434 # stack), thus exercising an update which traverses
Rakesh H Sa3325d62015-04-04 19:42:29 +0530435 # two levels of nesting.
436 template = _change_rsrc_properties(
437 test_template_one_resource, ['test1'],
438 {'value': 'test_provider_group_template'})
439 files = {'provider.template': json.dumps(template)}
440 env = {'resource_registry':
441 {'My::TestResource': 'provider.template'}}
442
443 stack_identifier = self.stack_create(
444 template=self.provider_group_template,
445 files=files,
446 environment=env
447 )
448
449 initial_resources = {'test_group': 'OS::Heat::ResourceGroup'}
450 self.assertEqual(initial_resources,
451 self.list_resources(stack_identifier))
452
453 # Prove the resource is backed by a nested stack, save the ID
454 nested_identifier = self.assert_resource_is_a_stack(stack_identifier,
455 'test_group')
456
457 # Then check the expected resources are in the nested stack
458 nested_resources = {'0': 'My::TestResource',
459 '1': 'My::TestResource'}
460 self.assertEqual(nested_resources,
461 self.list_resources(nested_identifier))
462
463 for n_rsrc in nested_resources:
464 rsrc = self.client.resources.get(nested_identifier, n_rsrc)
465 provider_stack = self.client.stacks.get(rsrc.physical_resource_id)
466 provider_identifier = '%s/%s' % (provider_stack.stack_name,
467 provider_stack.id)
468 provider_resources = {u'test1': u'OS::Heat::TestResource'}
469 self.assertEqual(provider_resources,
470 self.list_resources(provider_identifier))
471
472 tmpl_update = _change_rsrc_properties(
473 test_template_two_resource, ['test1', 'test2'],
474 {'value': 'test_provider_group_template'})
475 # Add one resource via a stack update by changing the nested stack
476 files['provider.template'] = json.dumps(tmpl_update)
477 self.update_stack(stack_identifier, self.provider_group_template,
478 environment=env, files=files)
479
480 # Parent resources should be unchanged and the nested stack
481 # should have been updated in-place without replacement
482 self.assertEqual(initial_resources,
483 self.list_resources(stack_identifier))
484
485 # Resource group stack should also be unchanged (but updated)
486 nested_stack = self.client.stacks.get(nested_identifier)
487 self.assertEqual('UPDATE_COMPLETE', nested_stack.stack_status)
488 self.assertEqual(nested_resources,
489 self.list_resources(nested_identifier))
490
491 for n_rsrc in nested_resources:
492 rsrc = self.client.resources.get(nested_identifier, n_rsrc)
493 provider_stack = self.client.stacks.get(rsrc.physical_resource_id)
494 provider_identifier = '%s/%s' % (provider_stack.stack_name,
495 provider_stack.id)
496 provider_resources = {'test1': 'OS::Heat::TestResource',
497 'test2': 'OS::Heat::TestResource'}
498 self.assertEqual(provider_resources,
499 self.list_resources(provider_identifier))
500
501 def test_stack_update_with_replacing_userdata(self):
Peter Razumovskyf0ac9582015-09-24 16:49:03 +0300502 """Test case for updating userdata of instance.
Rakesh H Sa3325d62015-04-04 19:42:29 +0530503
Peter Razumovskyf0ac9582015-09-24 16:49:03 +0300504 Confirm that we can update userdata of instance during updating stack
505 by the user of member role.
506
507 Make sure that a resource that inherits from StackUser can be deleted
Rakesh H Sa3325d62015-04-04 19:42:29 +0530508 during updating stack.
509 """
510 if not self.conf.minimal_image_ref:
511 raise self.skipException("No minimal image configured to test")
512 if not self.conf.minimal_instance_type:
513 raise self.skipException("No flavor configured to test")
514
515 parms = {'flavor': self.conf.minimal_instance_type,
516 'image': self.conf.minimal_image_ref,
Rabi Mishraec4b03b2015-05-23 02:20:47 +0530517 'network': self.conf.fixed_network_name,
Rakesh H Sa3325d62015-04-04 19:42:29 +0530518 'user_data': ''}
Rakesh H Sa3325d62015-04-04 19:42:29 +0530519
520 stack_identifier = self.stack_create(
Rakesh H Sa3325d62015-04-04 19:42:29 +0530521 template=self.update_userdata_template,
522 parameters=parms
523 )
524
525 parms_updated = parms
526 parms_updated['user_data'] = 'two'
527 self.update_stack(
528 stack_identifier,
529 template=self.update_userdata_template,
530 parameters=parms_updated)
Steven Hardy23284b62015-10-01 19:03:42 +0100531
532 def test_stack_update_provider_group_patch(self):
533 '''Test two-level nested update with PATCH'''
534 template = _change_rsrc_properties(
535 test_template_one_resource, ['test1'],
536 {'value': 'test_provider_group_template'})
537 files = {'provider.template': json.dumps(template)}
538 env = {'resource_registry':
539 {'My::TestResource': 'provider.template'}}
540
541 stack_identifier = self.stack_create(
542 template=self.provider_group_template,
543 files=files,
544 environment=env
545 )
546
547 initial_resources = {'test_group': 'OS::Heat::ResourceGroup'}
548 self.assertEqual(initial_resources,
549 self.list_resources(stack_identifier))
550
551 # Prove the resource is backed by a nested stack, save the ID
552 nested_identifier = self.assert_resource_is_a_stack(stack_identifier,
553 'test_group')
554
555 # Then check the expected resources are in the nested stack
556 nested_resources = {'0': 'My::TestResource',
557 '1': 'My::TestResource'}
558 self.assertEqual(nested_resources,
559 self.list_resources(nested_identifier))
560
561 # increase the count, pass only the paramter, no env or template
562 params = {'count': 3}
563 self.update_stack(stack_identifier, parameters=params, existing=True)
564
565 # Parent resources should be unchanged and the nested stack
566 # should have been updated in-place without replacement
567 self.assertEqual(initial_resources,
568 self.list_resources(stack_identifier))
569
570 # Resource group stack should also be unchanged (but updated)
571 nested_stack = self.client.stacks.get(nested_identifier)
572 self.assertEqual('UPDATE_COMPLETE', nested_stack.stack_status)
573 # Add a resource, as we should have added one
574 nested_resources['2'] = 'My::TestResource'
575 self.assertEqual(nested_resources,
576 self.list_resources(nested_identifier))
577
578 def test_stack_update_from_failed_patch(self):
579 '''Test PATCH update from a failed state.'''
580
581 # Start with empty template
582 stack_identifier = self.stack_create(
583 template='heat_template_version: 2014-10-16')
584
585 # Update with a good template, but bad parameter
586 self.update_stack(stack_identifier,
587 template=self.fail_param_template,
588 parameters={'do_fail': True},
589 expected_status='UPDATE_FAILED')
590
591 # PATCH update, only providing the parameter
592 self.update_stack(stack_identifier,
593 parameters={'do_fail': False},
594 existing=True)
595 self.assertEqual({u'aresource': u'OS::Heat::TestResource'},
596 self.list_resources(stack_identifier))
Thomas Herveb0cccac2015-11-13 09:35:55 +0100597
598 def test_stack_update_with_new_env(self):
599 """Update handles new resource types in the environment.
600
601 If a resource type appears during an update and the update fails,
602 retrying the update is able to find the type properly in the
603 environment.
604 """
605 stack_identifier = self.stack_create(
606 template=test_template_one_resource)
607
608 # Update with a new resource and make the update fails
609 template = _change_rsrc_properties(test_template_one_resource,
610 ['test1'], {'fail': True})
611 template['resources']['test2'] = {'type': 'My::TestResource'}
612 template['resources']['test1']['depends_on'] = 'test2'
613 env = {'resource_registry':
614 {'My::TestResource': 'OS::Heat::TestResource'}}
615 self.update_stack(stack_identifier,
616 template=template,
617 environment=env,
618 expected_status='UPDATE_FAILED')
619
620 # Fixing the template should fix the stack
621 template = _change_rsrc_properties(template,
622 ['test1'], {'fail': False})
623 self.update_stack(stack_identifier,
624 template=template,
625 environment=env)
626 self.assertEqual({'test1': 'OS::Heat::TestResource',
627 'test2': 'My::TestResource'},
628 self.list_resources(stack_identifier))
Thomas Herveab243752017-04-20 15:11:08 +0200629
630 def test_stack_update_with_new_version(self):
631 """Update handles new template version in failure.
632
633 If a stack update fails while changing the template version, update is
634 able to handle the new version fine.
635 """
636 stack_identifier = self.stack_create(
637 template=test_template_one_resource)
638
639 # Update with a new function and make the update fails
640 template = _change_rsrc_properties(test_template_two_resource,
641 ['test1'], {'fail': True})
642
643 template['heat_template_version'] = '2015-10-15'
644 template['resources']['test2']['properties']['value'] = {
645 'list_join': [',', ['a'], ['b']]}
646 self.update_stack(stack_identifier,
647 template=template,
648 expected_status='UPDATE_FAILED')
649
650 template = _change_rsrc_properties(template,
651 ['test2'], {'value': 'Test2'})
652 self.update_stack(stack_identifier,
653 template=template,
654 expected_status='UPDATE_FAILED')
655 self._stack_delete(stack_identifier)
656
657 def test_stack_update_with_old_version(self):
658 """Update handles old template version in failure.
659
660 If a stack update fails while changing the template version, update is
661 able to handle the old version fine.
662 """
663 template = _change_rsrc_properties(
664 test_template_one_resource,
665 ['test1'], {'value': {'list_join': [',', ['a'], ['b']]}})
666 template['heat_template_version'] = '2015-10-15'
667 stack_identifier = self.stack_create(
668 template=template)
669
670 # Update with a new function and make the update fails
671 template = _change_rsrc_properties(test_template_one_resource,
672 ['test1'], {'fail': True})
673 self.update_stack(stack_identifier,
674 template=template,
675 expected_status='UPDATE_FAILED')
676 self._stack_delete(stack_identifier)
Thomas Herve92902b82017-06-22 22:40:50 +0200677
678 def test_stack_update_with_conditions(self):
679 """Update manages new conditions added.
680
681 When a new resource is added during updates, the stacks handles the new
682 conditions correctly, and doesn't fail to load them while the update is
683 still in progress.
684 """
685 stack_identifier = self.stack_create(
686 template=test_template_one_resource)
687
688 updated_template = copy.deepcopy(test_template_two_resource)
689 updated_template['conditions'] = {'cond1': True}
690 updated_template['resources']['test3'] = {
691 'type': 'OS::Heat::TestResource',
692 'properties': {
693 'value': {'if': ['cond1', 'val3', 'val4']}
694 }
695 }
696 test2_props = updated_template['resources']['test2']['properties']
697 test2_props['action_wait_secs'] = {'create': 30}
698
699 self.update_stack(stack_identifier,
700 template=updated_template,
701 expected_status='UPDATE_IN_PROGRESS')
702
Thomas Herve4bc75ee2017-07-05 11:46:49 +0200703 def check_resources():
704 resources = self.list_resources(stack_identifier)
705 if len(resources) < 2:
706 return False
707 self.assertIn('test3', resources)
708 return True
709
710 self.assertTrue(test.call_until_true(20, 2, check_resources))