blob: b329ddc04900a38bae14c8ed21b3ef721b3e45c4 [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
Steve Bakerf547ec32014-10-20 14:34:41 +130013
14from heat_integrationtests.common import test
15
16
Steve Bakerf547ec32014-10-20 14:34:41 +130017class UpdateStackTest(test.HeatIntegrationTest):
18
19 template = '''
20heat_template_version: 2013-05-23
21resources:
22 random1:
23 type: OS::Heat::RandomString
24'''
25 update_template = '''
26heat_template_version: 2013-05-23
27resources:
28 random1:
29 type: OS::Heat::RandomString
30 random2:
31 type: OS::Heat::RandomString
32'''
33
Steven Hardybe1ce2d2014-11-18 12:54:50 +000034 provider_template = '''
35heat_template_version: 2013-05-23
36resources:
37 random1:
38 type: My::RandomString
39'''
40
Steven Hardy417097e2014-11-18 16:30:35 +000041 provider_group_template = '''
42heat_template_version: 2013-05-23
43resources:
44 random_group:
45 type: OS::Heat::ResourceGroup
46 properties:
47 count: 2
48 resource_def:
49 type: My::RandomString
50'''
51
Deliang Fane3bee732015-03-30 14:33:15 +080052 update_userdata_template = '''
53heat_template_version: 2014-10-16
54parameters:
55 flavor:
56 type: string
57 user_data:
58 type: string
59 image:
60 type: string
61
62resources:
63 server:
64 type: OS::Nova::Server
65 properties:
66 image: {get_param: image}
67 flavor: {get_param: flavor}
68 user_data_format: SOFTWARE_CONFIG
69 user_data: {get_param: user_data}
70'''
71
Steve Bakerf547ec32014-10-20 14:34:41 +130072 def setUp(self):
73 super(UpdateStackTest, self).setUp()
74 self.client = self.orchestration_client
75
Steve Bakerf547ec32014-10-20 14:34:41 +130076 def test_stack_update_nochange(self):
Steven Hardyf2c82c02014-11-20 14:02:17 +000077 stack_identifier = self.stack_create()
Steve Bakerf547ec32014-10-20 14:34:41 +130078 expected_resources = {'random1': 'OS::Heat::RandomString'}
79 self.assertEqual(expected_resources,
80 self.list_resources(stack_identifier))
81
82 # Update with no changes, resources should be unchanged
83 self.update_stack(stack_identifier, self.template)
84 self.assertEqual(expected_resources,
85 self.list_resources(stack_identifier))
86
87 def test_stack_update_add_remove(self):
Steven Hardyf2c82c02014-11-20 14:02:17 +000088 stack_identifier = self.stack_create()
Steve Bakerf547ec32014-10-20 14:34:41 +130089 initial_resources = {'random1': 'OS::Heat::RandomString'}
90 self.assertEqual(initial_resources,
91 self.list_resources(stack_identifier))
92
93 # Add one resource via a stack update
94 self.update_stack(stack_identifier, self.update_template)
Steve Bakerf547ec32014-10-20 14:34:41 +130095 updated_resources = {'random1': 'OS::Heat::RandomString',
96 'random2': 'OS::Heat::RandomString'}
97 self.assertEqual(updated_resources,
98 self.list_resources(stack_identifier))
99
100 # Then remove it by updating with the original template
101 self.update_stack(stack_identifier, self.template)
102 self.assertEqual(initial_resources,
103 self.list_resources(stack_identifier))
Steven Hardybe1ce2d2014-11-18 12:54:50 +0000104
105 def test_stack_update_provider(self):
Steven Hardybe1ce2d2014-11-18 12:54:50 +0000106 files = {'provider.yaml': self.template}
107 env = {'resource_registry':
108 {'My::RandomString': 'provider.yaml'}}
Steven Hardyf2c82c02014-11-20 14:02:17 +0000109 stack_identifier = self.stack_create(
Steven Hardybe1ce2d2014-11-18 12:54:50 +0000110 template=self.provider_template,
111 files=files,
Steven Hardybe1ce2d2014-11-18 12:54:50 +0000112 environment=env
113 )
Steven Hardybe1ce2d2014-11-18 12:54:50 +0000114
Steven Hardybe1ce2d2014-11-18 12:54:50 +0000115 initial_resources = {'random1': 'My::RandomString'}
116 self.assertEqual(initial_resources,
117 self.list_resources(stack_identifier))
118
119 # Prove the resource is backed by a nested stack, save the ID
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000120 nested_identifier = self.assert_resource_is_a_stack(stack_identifier,
121 'random1')
122 nested_id = nested_identifier.split('/')[-1]
Steven Hardybe1ce2d2014-11-18 12:54:50 +0000123
124 # Then check the expected resources are in the nested stack
125 nested_resources = {'random1': 'OS::Heat::RandomString'}
126 self.assertEqual(nested_resources,
127 self.list_resources(nested_identifier))
128
129 # Add one resource via a stack update by changing the nested stack
130 files['provider.yaml'] = self.update_template
131 self.update_stack(stack_identifier, self.provider_template,
132 environment=env, files=files)
Steven Hardybe1ce2d2014-11-18 12:54:50 +0000133
134 # Parent resources should be unchanged and the nested stack
135 # should have been updated in-place without replacement
136 self.assertEqual(initial_resources,
137 self.list_resources(stack_identifier))
138 rsrc = self.client.resources.get(stack_identifier, 'random1')
139 self.assertEqual(rsrc.physical_resource_id, nested_id)
140
141 # Then check the expected resources are in the nested stack
142 nested_resources = {'random1': 'OS::Heat::RandomString',
143 'random2': 'OS::Heat::RandomString'}
144 self.assertEqual(nested_resources,
145 self.list_resources(nested_identifier))
Steven Hardy417097e2014-11-18 16:30:35 +0000146
147 def test_stack_update_provider_group(self):
148 '''Test two-level nested update.'''
149 # Create a ResourceGroup (which creates a nested stack),
150 # containing provider resources (which create a nested
151 # stack), thus excercising an update which traverses
152 # two levels of nesting.
Steven Hardy417097e2014-11-18 16:30:35 +0000153 files = {'provider.yaml': self.template}
154 env = {'resource_registry':
155 {'My::RandomString': 'provider.yaml'}}
156
Steven Hardyf2c82c02014-11-20 14:02:17 +0000157 stack_identifier = self.stack_create(
Steven Hardy417097e2014-11-18 16:30:35 +0000158 template=self.provider_group_template,
159 files=files,
Steven Hardy417097e2014-11-18 16:30:35 +0000160 environment=env
161 )
Steven Hardy417097e2014-11-18 16:30:35 +0000162
Steven Hardy417097e2014-11-18 16:30:35 +0000163 initial_resources = {'random_group': 'OS::Heat::ResourceGroup'}
164 self.assertEqual(initial_resources,
165 self.list_resources(stack_identifier))
166
167 # Prove the resource is backed by a nested stack, save the ID
Angus Salkeld2bd63a42015-01-07 11:11:29 +1000168 nested_identifier = self.assert_resource_is_a_stack(stack_identifier,
169 'random_group')
Steven Hardy417097e2014-11-18 16:30:35 +0000170
171 # Then check the expected resources are in the nested stack
172 nested_resources = {'0': 'My::RandomString',
173 '1': 'My::RandomString'}
174 self.assertEqual(nested_resources,
175 self.list_resources(nested_identifier))
176
177 for n_rsrc in nested_resources:
178 rsrc = self.client.resources.get(nested_identifier, n_rsrc)
179 provider_stack = self.client.stacks.get(rsrc.physical_resource_id)
180 provider_identifier = '%s/%s' % (provider_stack.stack_name,
181 provider_stack.id)
182 provider_resources = {u'random1': u'OS::Heat::RandomString'}
183 self.assertEqual(provider_resources,
184 self.list_resources(provider_identifier))
185
186 # Add one resource via a stack update by changing the nested stack
187 files['provider.yaml'] = self.update_template
188 self.update_stack(stack_identifier, self.provider_group_template,
189 environment=env, files=files)
Steven Hardy417097e2014-11-18 16:30:35 +0000190
191 # Parent resources should be unchanged and the nested stack
192 # should have been updated in-place without replacement
193 self.assertEqual(initial_resources,
194 self.list_resources(stack_identifier))
195
196 # Resource group stack should also be unchanged (but updated)
197 nested_stack = self.client.stacks.get(nested_identifier)
198 self.assertEqual('UPDATE_COMPLETE', nested_stack.stack_status)
199 self.assertEqual(nested_resources,
200 self.list_resources(nested_identifier))
201
202 for n_rsrc in nested_resources:
203 rsrc = self.client.resources.get(nested_identifier, n_rsrc)
204 provider_stack = self.client.stacks.get(rsrc.physical_resource_id)
205 provider_identifier = '%s/%s' % (provider_stack.stack_name,
206 provider_stack.id)
207 provider_resources = {'random1': 'OS::Heat::RandomString',
208 'random2': 'OS::Heat::RandomString'}
209 self.assertEqual(provider_resources,
210 self.list_resources(provider_identifier))
Deliang Fane3bee732015-03-30 14:33:15 +0800211
212 def test_stack_update_with_replacing_userdata(self):
213 """Confirm that we can update userdata of instance during updating
214 stack by the user of member role.
215
216 Make sure that a resource that inherites from StackUser can be deleted
217 during updating stack.
218 """
219 if not self.conf.minimal_image_ref:
220 raise self.skipException("No minimal image configured to test")
221 if not self.conf.minimal_instance_type:
222 raise self.skipException("No flavor configured to test")
223
224 parms = {'flavor': self.conf.minimal_instance_type,
225 'image': self.conf.minimal_image_ref,
226 'user_data': ''}
227 name = self._stack_rand_name()
228
229 stack_identifier = self.stack_create(
230 stack_name=name,
231 template=self.update_userdata_template,
232 parameters=parms
233 )
234
235 parms_updated = parms
236 parms_updated['user_data'] = 'two'
237 self.update_stack(
238 stack_identifier,
239 template=self.update_userdata_template,
240 parameters=parms_updated)