blob: ea436ad10de308e2fdf13bc40d6019cac79d3dd1 [file] [log] [blame]
Steve Bakerf547ec32014-10-20 14:34:41 +13001# 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 logging
14
15from heat_integrationtests.common import test
16
17
18LOG = logging.getLogger(__name__)
19
20
21class UpdateStackTest(test.HeatIntegrationTest):
22
23 template = '''
24heat_template_version: 2013-05-23
25resources:
26 random1:
27 type: OS::Heat::RandomString
28'''
29 update_template = '''
30heat_template_version: 2013-05-23
31resources:
32 random1:
33 type: OS::Heat::RandomString
34 random2:
35 type: OS::Heat::RandomString
36'''
37
Steven Hardybe1ce2d2014-11-18 12:54:50 +000038 provider_template = '''
39heat_template_version: 2013-05-23
40resources:
41 random1:
42 type: My::RandomString
43'''
44
Steven Hardy417097e2014-11-18 16:30:35 +000045 provider_group_template = '''
46heat_template_version: 2013-05-23
47resources:
48 random_group:
49 type: OS::Heat::ResourceGroup
50 properties:
51 count: 2
52 resource_def:
53 type: My::RandomString
54'''
55
Steve Bakerf547ec32014-10-20 14:34:41 +130056 def setUp(self):
57 super(UpdateStackTest, self).setUp()
58 self.client = self.orchestration_client
59
Steve Bakerf547ec32014-10-20 14:34:41 +130060 def test_stack_update_nochange(self):
Steven Hardyf2c82c02014-11-20 14:02:17 +000061 stack_identifier = self.stack_create()
Steve Bakerf547ec32014-10-20 14:34:41 +130062 expected_resources = {'random1': 'OS::Heat::RandomString'}
63 self.assertEqual(expected_resources,
64 self.list_resources(stack_identifier))
65
66 # Update with no changes, resources should be unchanged
67 self.update_stack(stack_identifier, self.template)
68 self.assertEqual(expected_resources,
69 self.list_resources(stack_identifier))
70
71 def test_stack_update_add_remove(self):
Steven Hardyf2c82c02014-11-20 14:02:17 +000072 stack_identifier = self.stack_create()
Steve Bakerf547ec32014-10-20 14:34:41 +130073 initial_resources = {'random1': 'OS::Heat::RandomString'}
74 self.assertEqual(initial_resources,
75 self.list_resources(stack_identifier))
76
77 # Add one resource via a stack update
78 self.update_stack(stack_identifier, self.update_template)
Steve Bakerf547ec32014-10-20 14:34:41 +130079 updated_resources = {'random1': 'OS::Heat::RandomString',
80 'random2': 'OS::Heat::RandomString'}
81 self.assertEqual(updated_resources,
82 self.list_resources(stack_identifier))
83
84 # Then remove it by updating with the original template
85 self.update_stack(stack_identifier, self.template)
86 self.assertEqual(initial_resources,
87 self.list_resources(stack_identifier))
Steven Hardybe1ce2d2014-11-18 12:54:50 +000088
89 def test_stack_update_provider(self):
Steven Hardybe1ce2d2014-11-18 12:54:50 +000090 files = {'provider.yaml': self.template}
91 env = {'resource_registry':
92 {'My::RandomString': 'provider.yaml'}}
Steven Hardyf2c82c02014-11-20 14:02:17 +000093 stack_identifier = self.stack_create(
Steven Hardybe1ce2d2014-11-18 12:54:50 +000094 template=self.provider_template,
95 files=files,
Steven Hardybe1ce2d2014-11-18 12:54:50 +000096 environment=env
97 )
Steven Hardybe1ce2d2014-11-18 12:54:50 +000098
Steven Hardybe1ce2d2014-11-18 12:54:50 +000099 initial_resources = {'random1': 'My::RandomString'}
100 self.assertEqual(initial_resources,
101 self.list_resources(stack_identifier))
102
103 # Prove the resource is backed by a nested stack, save the ID
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000104 nested_identifier = self.assert_resource_is_a_stack(stack_identifier,
105 'random1')
106 nested_id = nested_identifier.split('/')[-1]
Steven Hardybe1ce2d2014-11-18 12:54:50 +0000107
108 # Then check the expected resources are in the nested stack
109 nested_resources = {'random1': 'OS::Heat::RandomString'}
110 self.assertEqual(nested_resources,
111 self.list_resources(nested_identifier))
112
113 # Add one resource via a stack update by changing the nested stack
114 files['provider.yaml'] = self.update_template
115 self.update_stack(stack_identifier, self.provider_template,
116 environment=env, files=files)
Steven Hardybe1ce2d2014-11-18 12:54:50 +0000117
118 # Parent resources should be unchanged and the nested stack
119 # should have been updated in-place without replacement
120 self.assertEqual(initial_resources,
121 self.list_resources(stack_identifier))
122 rsrc = self.client.resources.get(stack_identifier, 'random1')
123 self.assertEqual(rsrc.physical_resource_id, nested_id)
124
125 # Then check the expected resources are in the nested stack
126 nested_resources = {'random1': 'OS::Heat::RandomString',
127 'random2': 'OS::Heat::RandomString'}
128 self.assertEqual(nested_resources,
129 self.list_resources(nested_identifier))
Steven Hardy417097e2014-11-18 16:30:35 +0000130
131 def test_stack_update_provider_group(self):
132 '''Test two-level nested update.'''
133 # Create a ResourceGroup (which creates a nested stack),
134 # containing provider resources (which create a nested
135 # stack), thus excercising an update which traverses
136 # two levels of nesting.
Steven Hardy417097e2014-11-18 16:30:35 +0000137 files = {'provider.yaml': self.template}
138 env = {'resource_registry':
139 {'My::RandomString': 'provider.yaml'}}
140
Steven Hardyf2c82c02014-11-20 14:02:17 +0000141 stack_identifier = self.stack_create(
Steven Hardy417097e2014-11-18 16:30:35 +0000142 template=self.provider_group_template,
143 files=files,
Steven Hardy417097e2014-11-18 16:30:35 +0000144 environment=env
145 )
Steven Hardy417097e2014-11-18 16:30:35 +0000146
Steven Hardy417097e2014-11-18 16:30:35 +0000147 initial_resources = {'random_group': 'OS::Heat::ResourceGroup'}
148 self.assertEqual(initial_resources,
149 self.list_resources(stack_identifier))
150
151 # Prove the resource is backed by a nested stack, save the ID
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000152 nested_identifier = self.assert_resource_is_a_stack(stack_identifier,
153 'random_group')
Steven Hardy417097e2014-11-18 16:30:35 +0000154
155 # Then check the expected resources are in the nested stack
156 nested_resources = {'0': 'My::RandomString',
157 '1': 'My::RandomString'}
158 self.assertEqual(nested_resources,
159 self.list_resources(nested_identifier))
160
161 for n_rsrc in nested_resources:
162 rsrc = self.client.resources.get(nested_identifier, n_rsrc)
163 provider_stack = self.client.stacks.get(rsrc.physical_resource_id)
164 provider_identifier = '%s/%s' % (provider_stack.stack_name,
165 provider_stack.id)
166 provider_resources = {u'random1': u'OS::Heat::RandomString'}
167 self.assertEqual(provider_resources,
168 self.list_resources(provider_identifier))
169
170 # Add one resource via a stack update by changing the nested stack
171 files['provider.yaml'] = self.update_template
172 self.update_stack(stack_identifier, self.provider_group_template,
173 environment=env, files=files)
Steven Hardy417097e2014-11-18 16:30:35 +0000174
175 # Parent resources should be unchanged and the nested stack
176 # should have been updated in-place without replacement
177 self.assertEqual(initial_resources,
178 self.list_resources(stack_identifier))
179
180 # Resource group stack should also be unchanged (but updated)
181 nested_stack = self.client.stacks.get(nested_identifier)
182 self.assertEqual('UPDATE_COMPLETE', nested_stack.stack_status)
183 self.assertEqual(nested_resources,
184 self.list_resources(nested_identifier))
185
186 for n_rsrc in nested_resources:
187 rsrc = self.client.resources.get(nested_identifier, n_rsrc)
188 provider_stack = self.client.stacks.get(rsrc.physical_resource_id)
189 provider_identifier = '%s/%s' % (provider_stack.stack_name,
190 provider_stack.id)
191 provider_resources = {'random1': 'OS::Heat::RandomString',
192 'random2': 'OS::Heat::RandomString'}
193 self.assertEqual(provider_resources,
194 self.list_resources(provider_identifier))