blob: de8c6b8f412fd6673ee2a0c51767f07b34292645 [file] [log] [blame]
Angus Salkeld4408da32015-02-03 18:53:30 +10001# 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 hashlib
14import json
Angus Salkeld4408da32015-02-03 18:53:30 +100015import random
Angus Salkeld4408da32015-02-03 18:53:30 +100016
Steve Baker24641292015-03-13 10:47:50 +130017from oslo_log import log as logging
Sirushti Murugesan4920fda2015-04-22 00:35:26 +053018from six.moves.urllib import parse
Angus Salkeld4408da32015-02-03 18:53:30 +100019from swiftclient import utils as swiftclient_utils
20import yaml
21
22from heat_integrationtests.common import test
Rabi Mishra477efc92015-07-31 13:01:45 +053023from heat_integrationtests.functional import functional_base
Angus Salkeld4408da32015-02-03 18:53:30 +100024
25LOG = logging.getLogger(__name__)
26
27
Rabi Mishra477efc92015-07-31 13:01:45 +053028class AwsStackTest(functional_base.FunctionalTestsBase):
Angus Salkeld4408da32015-02-03 18:53:30 +100029 test_template = '''
30HeatTemplateFormatVersion: '2012-12-12'
31Resources:
32 the_nested:
33 Type: AWS::CloudFormation::Stack
34 Properties:
35 TemplateURL: the.yaml
36 Parameters:
37 KeyName: foo
38Outputs:
39 output_foo:
40 Value: {"Fn::GetAtt": [the_nested, Outputs.Foo]}
41'''
42
43 nested_template = '''
44HeatTemplateFormatVersion: '2012-12-12'
45Parameters:
46 KeyName:
47 Type: String
48Outputs:
49 Foo:
50 Value: bar
51'''
52
53 update_template = '''
54HeatTemplateFormatVersion: '2012-12-12'
55Parameters:
56 KeyName:
57 Type: String
58Outputs:
59 Foo:
60 Value: foo
61'''
62
63 nested_with_res_template = '''
64HeatTemplateFormatVersion: '2012-12-12'
65Parameters:
66 KeyName:
67 Type: String
68Resources:
69 NestedResource:
70 Type: OS::Heat::RandomString
71Outputs:
72 Foo:
73 Value: {"Fn::GetAtt": [NestedResource, value]}
74'''
75
76 def setUp(self):
77 super(AwsStackTest, self).setUp()
Angus Salkeld4408da32015-02-03 18:53:30 +100078 self.object_container_name = AwsStackTest.__name__
79 self.project_id = self.identity_client.auth_ref.project_id
80 self.object_client.put_container(self.object_container_name)
81 self.nested_name = '%s.yaml' % test.rand_name()
82
83 def publish_template(self, name, contents):
84 oc = self.object_client
85
86 # post the object
87 oc.put_object(self.object_container_name, name, contents)
88 # TODO(asalkeld) see if this is causing problems.
89 # self.addCleanup(self.object_client.delete_object,
90 # self.object_container_name, name)
91
92 # make the tempurl
93 key_header = 'x-account-meta-temp-url-key'
94 if key_header not in oc.head_account():
95 swift_key = hashlib.sha224(
96 str(random.getrandbits(256))).hexdigest()[:32]
97 LOG.warn('setting swift key to %s' % swift_key)
98 oc.post_account({key_header: swift_key})
99 key = oc.head_account()[key_header]
100 path = '/v1/AUTH_%s/%s/%s' % (self.project_id,
101 self.object_container_name, name)
102 timeout = self.conf.build_timeout * 10
103 tempurl = swiftclient_utils.generate_temp_url(path, timeout,
104 key, 'GET')
Sirushti Murugesan4920fda2015-04-22 00:35:26 +0530105 sw_url = parse.urlparse(oc.url)
Angus Salkeld4408da32015-02-03 18:53:30 +1000106 return '%s://%s%s' % (sw_url.scheme, sw_url.netloc, tempurl)
107
108 def test_nested_stack_create(self):
109 url = self.publish_template(self.nested_name, self.nested_template)
110 self.template = self.test_template.replace('the.yaml', url)
111 stack_identifier = self.stack_create(template=self.template)
112 stack = self.client.stacks.get(stack_identifier)
113 self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
114 self.assertEqual('bar', self._stack_output(stack, 'output_foo'))
115
116 def test_nested_stack_create_with_timeout(self):
117 url = self.publish_template(self.nested_name, self.nested_template)
118 self.template = self.test_template.replace('the.yaml', url)
119 timeout_template = yaml.load(self.template)
120 props = timeout_template['Resources']['the_nested']['Properties']
121 props['TimeoutInMinutes'] = '50'
122
123 stack_identifier = self.stack_create(
124 template=timeout_template)
125 stack = self.client.stacks.get(stack_identifier)
126 self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
127 self.assertEqual('bar', self._stack_output(stack, 'output_foo'))
128
129 def test_nested_stack_adopt_ok(self):
130 url = self.publish_template(self.nested_name,
131 self.nested_with_res_template)
132 self.template = self.test_template.replace('the.yaml', url)
133 adopt_data = {
134 "resources": {
135 "the_nested": {
136 "resource_id": "test-res-id",
137 "resources": {
138 "NestedResource": {
139 "type": "OS::Heat::RandomString",
140 "resource_id": "test-nested-res-id",
141 "resource_data": {"value": "goopie"}
142 }
143 }
144 }
145 },
146 "environment": {"parameters": {}},
147 "template": yaml.load(self.template)
148 }
149
150 stack_identifier = self.stack_adopt(adopt_data=json.dumps(adopt_data))
151
152 self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
153 stack = self.client.stacks.get(stack_identifier)
154 self.assertEqual('goopie', self._stack_output(stack, 'output_foo'))
155
156 def test_nested_stack_adopt_fail(self):
157 url = self.publish_template(self.nested_name,
158 self.nested_with_res_template)
159 self.template = self.test_template.replace('the.yaml', url)
160 adopt_data = {
161 "resources": {
162 "the_nested": {
163 "resource_id": "test-res-id",
164 "resources": {
165 }
166 }
167 },
168 "environment": {"parameters": {}},
169 "template": yaml.load(self.template)
170 }
171
172 stack_identifier = self.stack_adopt(adopt_data=json.dumps(adopt_data),
173 wait_for_status='ADOPT_FAILED')
174 rsrc = self.client.resources.get(stack_identifier, 'the_nested')
175 self.assertEqual('ADOPT_FAILED', rsrc.resource_status)
176
177 def test_nested_stack_update(self):
178 url = self.publish_template(self.nested_name, self.nested_template)
179 self.template = self.test_template.replace('the.yaml', url)
180 stack_identifier = self.stack_create(template=self.template)
181 original_nested_id = self.assert_resource_is_a_stack(
182 stack_identifier, 'the_nested')
183 stack = self.client.stacks.get(stack_identifier)
184 self.assertEqual('bar', self._stack_output(stack, 'output_foo'))
185
186 new_template = yaml.load(self.template)
187 props = new_template['Resources']['the_nested']['Properties']
188 props['TemplateURL'] = self.publish_template(self.nested_name,
189 self.update_template)
190
191 self.update_stack(stack_identifier, new_template)
192
193 # Expect the physical resource name staying the same after update,
194 # so that the nested was actually updated instead of replaced.
195 new_nested_id = self.assert_resource_is_a_stack(
196 stack_identifier, 'the_nested')
197 self.assertEqual(original_nested_id, new_nested_id)
198 updt_stack = self.client.stacks.get(stack_identifier)
199 self.assertEqual('foo', self._stack_output(updt_stack, 'output_foo'))
200
201 def test_nested_stack_suspend_resume(self):
202 url = self.publish_template(self.nested_name, self.nested_template)
203 self.template = self.test_template.replace('the.yaml', url)
204 stack_identifier = self.stack_create(template=self.template)
Angus Salkelda7500d12015-04-10 15:44:07 +1000205 self.stack_suspend(stack_identifier)
206 self.stack_resume(stack_identifier)