blob: dba6f5c7b69f504424ad39e739ecbb8b40a51257 [file] [log] [blame]
Steven Hardy6f0bda82014-12-12 17:49:10 +00001# 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
Angus Salkeld011acc72015-01-16 20:26:34 +100013import json
14
Steven Hardy6f0bda82014-12-12 17:49:10 +000015from heatclient import exc
Pavlo Shchelokovskyy60e0ecd2014-12-14 22:17:21 +020016import six
Angus Salkeld011acc72015-01-16 20:26:34 +100017import yaml
Steven Hardy6f0bda82014-12-12 17:49:10 +000018
19from heat_integrationtests.common import test
20
21
Unmesh Gurjar0a25a732014-12-23 17:28:33 +053022template = '''
23heat_template_version: 2013-05-23
24resources:
25 random_group:
26 type: OS::Heat::ResourceGroup
27 properties:
28 count: 2
29 resource_def:
30 type: OS::Heat::RandomString
31 properties:
32 length: 30
33outputs:
34 random1:
35 value: {get_attr: [random_group, resource.0.value]}
36 random2:
37 value: {get_attr: [random_group, resource.1.value]}
38 all_values:
39 value: {get_attr: [random_group, value]}
40'''
41
42
Steven Hardy6f0bda82014-12-12 17:49:10 +000043class ResourceGroupTest(test.HeatIntegrationTest):
44
45 def setUp(self):
46 super(ResourceGroupTest, self).setUp()
47 self.client = self.orchestration_client
48
49 def _group_nested_identifier(self, stack_identifier,
50 group_name='random_group'):
51 # Get the nested stack identifier from the group
52 rsrc = self.client.resources.get(stack_identifier, group_name)
53 physical_resource_id = rsrc.physical_resource_id
54
55 nested_stack = self.client.stacks.get(physical_resource_id)
56 nested_identifier = '%s/%s' % (nested_stack.stack_name,
57 nested_stack.id)
58 parent_id = stack_identifier.split("/")[-1]
59 self.assertEqual(parent_id, nested_stack.parent)
60 return nested_identifier
61
62 def test_resource_group_zero_novalidate(self):
63 # Nested resources should be validated only when size > 0
64 # This allows features to be disabled via size=0 without
65 # triggering validation of nested resource custom contraints
66 # e.g images etc in the nested schema.
67 nested_template_fail = '''
68heat_template_version: 2013-05-23
69resources:
70 random:
71 type: OS::Heat::RandomString
72 properties:
73 length: BAD
74'''
75
76 template_zero_nested = '''
77heat_template_version: 2013-05-23
78resources:
79 random_group:
80 type: OS::Heat::ResourceGroup
81 properties:
82 count: 0
83 resource_def:
84 type: My::RandomString
85'''
86
87 files = {'provider.yaml': nested_template_fail}
88 env = {'resource_registry':
89 {'My::RandomString': 'provider.yaml'}}
90 stack_identifier = self.stack_create(
91 template=template_zero_nested,
92 files=files,
93 environment=env
94 )
95
96 self.assertEqual({u'random_group': u'OS::Heat::ResourceGroup'},
97 self.list_resources(stack_identifier))
98
99 # Check we created an empty nested stack
100 nested_identifier = self._group_nested_identifier(stack_identifier)
101 self.assertEqual({}, self.list_resources(nested_identifier))
102
103 # Prove validation works for non-zero create/update
104 template_two_nested = template_zero_nested.replace("count: 0",
105 "count: 2")
106 expected_err = "length Value 'BAD' is not an integer"
107 ex = self.assertRaises(exc.HTTPBadRequest, self.update_stack,
108 stack_identifier, template_two_nested,
109 environment=env, files=files)
110 self.assertIn(expected_err, six.text_type(ex))
111
112 ex = self.assertRaises(exc.HTTPBadRequest, self.stack_create,
113 template=template_two_nested,
114 environment=env, files=files)
115 self.assertIn(expected_err, six.text_type(ex))
Unmesh Gurjar0a25a732014-12-23 17:28:33 +0530116
117 def _validate_resources(self, stack_identifier, expected_count):
118 nested_identifier = self._group_nested_identifier(stack_identifier)
119 resources = self.list_resources(nested_identifier)
120 self.assertEqual(expected_count, len(resources))
121 expected_resources = dict(
122 (str(idx), 'OS::Heat::RandomString')
123 for idx in range(expected_count))
124
125 self.assertEqual(expected_resources, resources)
126
127 def test_create(self):
128 def validate_output(stack, output_key, length):
129 output_value = self._stack_output(stack, output_key)
130 self.assertEqual(length, len(output_value))
131 return output_value
132 # verify that the resources in resource group are identically
133 # configured, resource names and outputs are appropriate.
Angus Salkeld011acc72015-01-16 20:26:34 +1000134 stack_identifier = self.stack_create(template=template)
Unmesh Gurjar0a25a732014-12-23 17:28:33 +0530135 self.assertEqual({u'random_group': u'OS::Heat::ResourceGroup'},
136 self.list_resources(stack_identifier))
137
138 # validate count, type and name of resources in a resource group.
139 self._validate_resources(stack_identifier, 2)
140
141 # validate outputs
142 stack = self.client.stacks.get(stack_identifier)
143 outputs = []
144 outputs.append(validate_output(stack, 'random1', 30))
145 outputs.append(validate_output(stack, 'random2', 30))
146 self.assertEqual(outputs, self._stack_output(stack, 'all_values'))
147
148 def test_update_increase_decrease_count(self):
149 # create stack with resource group count 2
Angus Salkeld011acc72015-01-16 20:26:34 +1000150 stack_identifier = self.stack_create(template=template)
Unmesh Gurjar0a25a732014-12-23 17:28:33 +0530151 self.assertEqual({u'random_group': u'OS::Heat::ResourceGroup'},
152 self.list_resources(stack_identifier))
153 # verify that the resource group has 2 resources
154 self._validate_resources(stack_identifier, 2)
155
156 # increase the resource group count to 5
157 update_template = template.replace("count: 2", "count: 5")
158 self.update_stack(stack_identifier, update_template)
159 # verify that the resource group has 5 resources
160 self._validate_resources(stack_identifier, 5)
161
162 # decrease the resource group count to 3
163 update_template = template.replace("count: 2", "count: 3")
164 self.update_stack(stack_identifier, update_template)
165 # verify that the resource group has 3 resources
166 self._validate_resources(stack_identifier, 3)
Angus Salkeld011acc72015-01-16 20:26:34 +1000167
168
169class ResourceGroupAdoptTest(test.HeatIntegrationTest):
170 """Prove that we can do resource group adopt."""
171
172 main_template = '''
173heat_template_version: "2013-05-23"
174resources:
175 group1:
176 type: OS::Heat::ResourceGroup
177 properties:
178 count: 2
179 resource_def:
180 type: OS::Heat::RandomString
181outputs:
182 test0:
183 value: {get_attr: [group1, resource.0.value]}
184 test1:
185 value: {get_attr: [group1, resource.1.value]}
186'''
187
188 def setUp(self):
189 super(ResourceGroupAdoptTest, self).setUp()
190 self.client = self.orchestration_client
191
192 def _yaml_to_json(self, yaml_templ):
193 return yaml.load(yaml_templ)
194
195 def test_adopt(self):
196 data = {
197 "resources": {
198 "group1": {
199 "status": "COMPLETE",
200 "name": "group1",
201 "resource_data": {},
202 "metadata": {},
203 "resource_id": "test-group1-id",
204 "action": "CREATE",
205 "type": "OS::Heat::ResourceGroup",
206 "resources": {
207 "0": {
208 "status": "COMPLETE",
209 "name": "0",
210 "resource_data": {"value": "goopie"},
211 "resource_id": "ID-0",
212 "action": "CREATE",
213 "type": "OS::Heat::RandomString",
214 "metadata": {}
215 },
216 "1": {
217 "status": "COMPLETE",
218 "name": "1",
219 "resource_data": {"value": "different"},
220 "resource_id": "ID-1",
221 "action": "CREATE",
222 "type": "OS::Heat::RandomString",
223 "metadata": {}
224 }
225 }
226 }
227 },
228 "environment": {"parameters": {}},
229 "template": yaml.load(self.main_template)
230 }
231 stack_identifier = self.stack_adopt(
232 adopt_data=json.dumps(data))
233
234 self.assert_resource_is_a_stack(stack_identifier, 'group1')
235 stack = self.client.stacks.get(stack_identifier)
236 self.assertEqual('goopie', self._stack_output(stack, 'test0'))
237 self.assertEqual('different', self._stack_output(stack, 'test1'))