blob: 610fe10608afef3b5ccaeae1640eeab2d06789cf [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
104 rsrc = self.client.resources.get(stack_identifier, 'random1')
105 nested_link = [l for l in rsrc.links if l['rel'] == 'nested']
106 nested_href = nested_link[0]['href']
107 nested_id = nested_href.split('/')[-1]
108 nested_identifier = '/'.join(nested_href.split('/')[-2:])
109 physical_resource_id = rsrc.physical_resource_id
110 self.assertEqual(physical_resource_id, nested_id)
111
112 # Then check the expected resources are in the nested stack
113 nested_resources = {'random1': 'OS::Heat::RandomString'}
114 self.assertEqual(nested_resources,
115 self.list_resources(nested_identifier))
116
117 # Add one resource via a stack update by changing the nested stack
118 files['provider.yaml'] = self.update_template
119 self.update_stack(stack_identifier, self.provider_template,
120 environment=env, files=files)
Steven Hardybe1ce2d2014-11-18 12:54:50 +0000121
122 # Parent resources should be unchanged and the nested stack
123 # should have been updated in-place without replacement
124 self.assertEqual(initial_resources,
125 self.list_resources(stack_identifier))
126 rsrc = self.client.resources.get(stack_identifier, 'random1')
127 self.assertEqual(rsrc.physical_resource_id, nested_id)
128
129 # Then check the expected resources are in the nested stack
130 nested_resources = {'random1': 'OS::Heat::RandomString',
131 'random2': 'OS::Heat::RandomString'}
132 self.assertEqual(nested_resources,
133 self.list_resources(nested_identifier))
Steven Hardy417097e2014-11-18 16:30:35 +0000134
135 def test_stack_update_provider_group(self):
136 '''Test two-level nested update.'''
137 # Create a ResourceGroup (which creates a nested stack),
138 # containing provider resources (which create a nested
139 # stack), thus excercising an update which traverses
140 # two levels of nesting.
Steven Hardy417097e2014-11-18 16:30:35 +0000141 files = {'provider.yaml': self.template}
142 env = {'resource_registry':
143 {'My::RandomString': 'provider.yaml'}}
144
Steven Hardyf2c82c02014-11-20 14:02:17 +0000145 stack_identifier = self.stack_create(
Steven Hardy417097e2014-11-18 16:30:35 +0000146 template=self.provider_group_template,
147 files=files,
Steven Hardy417097e2014-11-18 16:30:35 +0000148 environment=env
149 )
Steven Hardy417097e2014-11-18 16:30:35 +0000150
Steven Hardy417097e2014-11-18 16:30:35 +0000151 initial_resources = {'random_group': 'OS::Heat::ResourceGroup'}
152 self.assertEqual(initial_resources,
153 self.list_resources(stack_identifier))
154
155 # Prove the resource is backed by a nested stack, save the ID
156 rsrc = self.client.resources.get(stack_identifier, 'random_group')
157 physical_resource_id = rsrc.physical_resource_id
158
159 nested_stack = self.client.stacks.get(physical_resource_id)
160 nested_identifier = '%s/%s' % (nested_stack.stack_name,
161 nested_stack.id)
Steven Hardyf2c82c02014-11-20 14:02:17 +0000162 parent_id = stack_identifier.split("/")[-1]
163 self.assertEqual(parent_id, nested_stack.parent)
Steven Hardy417097e2014-11-18 16:30:35 +0000164
165 # Then check the expected resources are in the nested stack
166 nested_resources = {'0': 'My::RandomString',
167 '1': 'My::RandomString'}
168 self.assertEqual(nested_resources,
169 self.list_resources(nested_identifier))
170
171 for n_rsrc in nested_resources:
172 rsrc = self.client.resources.get(nested_identifier, n_rsrc)
173 provider_stack = self.client.stacks.get(rsrc.physical_resource_id)
174 provider_identifier = '%s/%s' % (provider_stack.stack_name,
175 provider_stack.id)
176 provider_resources = {u'random1': u'OS::Heat::RandomString'}
177 self.assertEqual(provider_resources,
178 self.list_resources(provider_identifier))
179
180 # Add one resource via a stack update by changing the nested stack
181 files['provider.yaml'] = self.update_template
182 self.update_stack(stack_identifier, self.provider_group_template,
183 environment=env, files=files)
Steven Hardy417097e2014-11-18 16:30:35 +0000184
185 # Parent resources should be unchanged and the nested stack
186 # should have been updated in-place without replacement
187 self.assertEqual(initial_resources,
188 self.list_resources(stack_identifier))
189
190 # Resource group stack should also be unchanged (but updated)
191 nested_stack = self.client.stacks.get(nested_identifier)
192 self.assertEqual('UPDATE_COMPLETE', nested_stack.stack_status)
193 self.assertEqual(nested_resources,
194 self.list_resources(nested_identifier))
195
196 for n_rsrc in nested_resources:
197 rsrc = self.client.resources.get(nested_identifier, n_rsrc)
198 provider_stack = self.client.stacks.get(rsrc.physical_resource_id)
199 provider_identifier = '%s/%s' % (provider_stack.stack_name,
200 provider_stack.id)
201 provider_resources = {'random1': 'OS::Heat::RandomString',
202 'random2': 'OS::Heat::RandomString'}
203 self.assertEqual(provider_resources,
204 self.list_resources(provider_identifier))