blob: 8ccddd88b4e3c744701f3b1d325d961fee88fdfc [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
13import six
14
15from heatclient import exc
16
17from heat_integrationtests.common import test
18
19
Unmesh Gurjar0a25a732014-12-23 17:28:33 +053020template = '''
21heat_template_version: 2013-05-23
22resources:
23 random_group:
24 type: OS::Heat::ResourceGroup
25 properties:
26 count: 2
27 resource_def:
28 type: OS::Heat::RandomString
29 properties:
30 length: 30
31outputs:
32 random1:
33 value: {get_attr: [random_group, resource.0.value]}
34 random2:
35 value: {get_attr: [random_group, resource.1.value]}
36 all_values:
37 value: {get_attr: [random_group, value]}
38'''
39
40
Steven Hardy6f0bda82014-12-12 17:49:10 +000041class ResourceGroupTest(test.HeatIntegrationTest):
42
43 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
67resources:
68 random:
69 type: OS::Heat::RandomString
70 properties:
71 length: BAD
72'''
73
74 template_zero_nested = '''
75heat_template_version: 2013-05-23
76resources:
77 random_group:
78 type: OS::Heat::ResourceGroup
79 properties:
80 count: 0
81 resource_def:
82 type: My::RandomString
83'''
84
85 files = {'provider.yaml': nested_template_fail}
86 env = {'resource_registry':
87 {'My::RandomString': 'provider.yaml'}}
88 stack_identifier = self.stack_create(
89 template=template_zero_nested,
90 files=files,
91 environment=env
92 )
93
94 self.assertEqual({u'random_group': u'OS::Heat::ResourceGroup'},
95 self.list_resources(stack_identifier))
96
97 # Check we created an empty nested stack
98 nested_identifier = self._group_nested_identifier(stack_identifier)
99 self.assertEqual({}, self.list_resources(nested_identifier))
100
101 # Prove validation works for non-zero create/update
102 template_two_nested = template_zero_nested.replace("count: 0",
103 "count: 2")
104 expected_err = "length Value 'BAD' is not an integer"
105 ex = self.assertRaises(exc.HTTPBadRequest, self.update_stack,
106 stack_identifier, template_two_nested,
107 environment=env, files=files)
108 self.assertIn(expected_err, six.text_type(ex))
109
110 ex = self.assertRaises(exc.HTTPBadRequest, self.stack_create,
111 template=template_two_nested,
112 environment=env, files=files)
113 self.assertIn(expected_err, six.text_type(ex))
Unmesh Gurjar0a25a732014-12-23 17:28:33 +0530114
115 def _validate_resources(self, stack_identifier, expected_count):
116 nested_identifier = self._group_nested_identifier(stack_identifier)
117 resources = self.list_resources(nested_identifier)
118 self.assertEqual(expected_count, len(resources))
119 expected_resources = dict(
120 (str(idx), 'OS::Heat::RandomString')
121 for idx in range(expected_count))
122
123 self.assertEqual(expected_resources, resources)
124
125 def test_create(self):
126 def validate_output(stack, output_key, length):
127 output_value = self._stack_output(stack, output_key)
128 self.assertEqual(length, len(output_value))
129 return output_value
130 # verify that the resources in resource group are identically
131 # configured, resource names and outputs are appropriate.
132 stack_identifier = self.stack_create('create_stack', template=template)
133 self.assertEqual({u'random_group': u'OS::Heat::ResourceGroup'},
134 self.list_resources(stack_identifier))
135
136 # validate count, type and name of resources in a resource group.
137 self._validate_resources(stack_identifier, 2)
138
139 # validate outputs
140 stack = self.client.stacks.get(stack_identifier)
141 outputs = []
142 outputs.append(validate_output(stack, 'random1', 30))
143 outputs.append(validate_output(stack, 'random2', 30))
144 self.assertEqual(outputs, self._stack_output(stack, 'all_values'))
145
146 def test_update_increase_decrease_count(self):
147 # create stack with resource group count 2
148 stack_identifier = self.stack_create('update_stack', template=template)
149 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
155 update_template = template.replace("count: 2", "count: 5")
156 self.update_stack(stack_identifier, update_template)
157 # verify that the resource group has 5 resources
158 self._validate_resources(stack_identifier, 5)
159
160 # decrease the resource group count to 3
161 update_template = template.replace("count: 2", "count: 3")
162 self.update_stack(stack_identifier, update_template)
163 # verify that the resource group has 3 resources
164 self._validate_resources(stack_identifier, 3)