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