1 # Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs")
2 # and others. All rights reserved.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
17 from heatclient.exc import HTTPBadRequest
18 from snaps import file_utils
20 from snaps.openstack.create_flavor import OpenStackFlavor, FlavorSettings
22 from snaps.openstack.create_image import OpenStackImage
25 from urllib.request import URLError
27 from urllib2 import URLError
33 from snaps.openstack import create_stack
34 from snaps.openstack.create_stack import StackSettings, StackSettingsError
35 from snaps.openstack.tests import openstack_tests
36 from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase
37 from snaps.openstack.utils import heat_utils
39 __author__ = 'spisarski'
41 logger = logging.getLogger('create_stack_tests')
44 class StackSettingsUnitTests(unittest.TestCase):
46 Tests the construction of the StackSettings class
48 def test_no_params(self):
49 with self.assertRaises(StackSettingsError):
52 def test_empty_config(self):
53 with self.assertRaises(StackSettingsError):
54 StackSettings(config=dict())
56 def test_name_only(self):
57 with self.assertRaises(StackSettingsError):
58 StackSettings(name='foo')
60 def test_config_with_name_only(self):
61 with self.assertRaises(StackSettingsError):
62 StackSettings(config={'name': 'foo'})
64 def test_config_minimum_template(self):
65 settings = StackSettings(config={'name': 'stack', 'template': 'foo'})
66 self.assertEqual('stack', settings.name)
67 self.assertEqual('foo', settings.template)
68 self.assertIsNone(settings.template_path)
69 self.assertIsNone(settings.env_values)
70 self.assertEqual(create_stack.STACK_COMPLETE_TIMEOUT, settings.stack_create_timeout)
72 def test_config_minimum_template_path(self):
73 settings = StackSettings(config={'name': 'stack', 'template_path': 'foo'})
74 self.assertEqual('stack', settings.name)
75 self.assertIsNone(settings.template)
76 self.assertEqual('foo', settings.template_path)
77 self.assertIsNone(settings.env_values)
78 self.assertEqual(create_stack.STACK_COMPLETE_TIMEOUT, settings.stack_create_timeout)
80 def test_minimum_template(self):
81 settings = StackSettings(name='stack', template='foo')
82 self.assertEqual('stack', settings.name)
83 self.assertEqual('foo', settings.template)
84 self.assertIsNone(settings.template_path)
85 self.assertIsNone(settings.env_values)
86 self.assertEqual(create_stack.STACK_COMPLETE_TIMEOUT, settings.stack_create_timeout)
88 def test_minimum_template_path(self):
89 settings = StackSettings(name='stack', template_path='foo')
90 self.assertEqual('stack', settings.name)
91 self.assertEqual('foo', settings.template_path)
92 self.assertIsNone(settings.template)
93 self.assertIsNone(settings.env_values)
94 self.assertEqual(create_stack.STACK_COMPLETE_TIMEOUT, settings.stack_create_timeout)
97 env_values = {'foo': 'bar'}
98 settings = StackSettings(name='stack', template='bar', template_path='foo', env_values=env_values,
99 stack_create_timeout=999)
100 self.assertEqual('stack', settings.name)
101 self.assertEqual('bar', settings.template)
102 self.assertEqual('foo', settings.template_path)
103 self.assertEqual(env_values, settings.env_values)
104 self.assertEqual(999, settings.stack_create_timeout)
106 def test_config_all(self):
107 env_values = {'foo': 'bar'}
108 settings = StackSettings(
109 config={'name': 'stack', 'template': 'bar', 'template_path': 'foo',
110 'env_values': env_values, 'stack_create_timeout': 999})
111 self.assertEqual('stack', settings.name)
112 self.assertEqual('bar', settings.template)
113 self.assertEqual('foo', settings.template_path)
114 self.assertEqual(env_values, settings.env_values)
115 self.assertEqual(999, settings.stack_create_timeout)
118 class CreateStackSuccessTests(OSIntegrationTestCase):
120 Test for the CreateStack class defined in create_stack.py
125 Instantiates the CreateStack object that is responsible for downloading and creating an OS stack file
128 super(self.__class__, self).__start__()
130 self.guid = str(uuid.uuid4())
131 self.heat_cli = heat_utils.heat_client(self.os_creds)
132 self.stack_creator = None
134 self.image_creator = OpenStackImage(
135 self.os_creds, openstack_tests.cirros_image_settings(
136 name=self.__class__.__name__ + '-' + str(self.guid) + '-image'))
137 self.image_creator.create()
140 self.flavor_creator = OpenStackFlavor(
142 FlavorSettings(name=self.guid + '-flavor-name', ram=128, disk=10, vcpus=1))
143 self.flavor_creator.create()
145 self.env_values = {'image_name': self.image_creator.image_settings.name,
146 'flavor_name': self.flavor_creator.flavor_settings.name}
150 Cleans the stack and downloaded stack file
152 if self.stack_creator:
153 self.stack_creator.clean()
155 if self.image_creator:
157 self.image_creator.clean()
161 if self.flavor_creator:
163 self.flavor_creator.clean()
167 super(self.__class__, self).__clean__()
169 def test_create_stack_template_file(self):
171 Tests the creation of an OpenStack stack from Heat template file.
174 # Set the default stack settings, then set any custom parameters sent from the app
175 stack_settings = StackSettings(name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
176 template_path='../examples/heat/test_heat_template.yaml',
177 env_values=self.env_values)
178 self.stack_creator = create_stack.OpenStackHeatStack(self.os_creds, stack_settings)
179 created_stack = self.stack_creator.create()
180 self.assertIsNotNone(created_stack)
182 retrieved_stack = heat_utils.get_stack_by_id(self.heat_cli, created_stack.id)
183 self.assertIsNotNone(retrieved_stack)
184 self.assertEqual(created_stack.name, retrieved_stack.name)
185 self.assertEqual(created_stack.id, retrieved_stack.id)
186 self.assertIsNotNone(self.stack_creator.get_outputs())
187 self.assertEquals(0, len(self.stack_creator.get_outputs()))
189 def test_create_stack_template_dict(self):
191 Tests the creation of an OpenStack stack from a heat dict() object.
194 # Set the default stack settings, then set any custom parameters sent from the app
195 template_dict = heat_utils.parse_heat_template_str(
196 file_utils.read_file('../examples/heat/test_heat_template.yaml'))
197 stack_settings = StackSettings(name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
198 template=template_dict,
199 env_values=self.env_values)
200 self.stack_creator = create_stack.OpenStackHeatStack(self.os_creds, stack_settings)
201 created_stack = self.stack_creator.create()
202 self.assertIsNotNone(created_stack)
204 retrieved_stack = heat_utils.get_stack_by_id(self.heat_cli, created_stack.id)
205 self.assertIsNotNone(retrieved_stack)
206 self.assertEqual(created_stack.name, retrieved_stack.name)
207 self.assertEqual(created_stack.id, retrieved_stack.id)
208 self.assertIsNotNone(self.stack_creator.get_outputs())
209 self.assertEquals(0, len(self.stack_creator.get_outputs()))
211 def test_create_delete_stack(self):
213 Tests the creation then deletion of an OpenStack stack to ensure clean() does not raise an Exception.
216 template_dict = heat_utils.parse_heat_template_str(
217 file_utils.read_file('../examples/heat/test_heat_template.yaml'))
218 stack_settings = StackSettings(name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
219 template=template_dict,
220 env_values=self.env_values)
221 self.stack_creator = create_stack.OpenStackHeatStack(self.os_creds, stack_settings)
222 created_stack = self.stack_creator.create()
223 self.assertIsNotNone(created_stack)
225 retrieved_stack = heat_utils.get_stack_by_id(self.heat_cli, created_stack.id)
226 self.assertIsNotNone(retrieved_stack)
227 self.assertEqual(created_stack.name, retrieved_stack.name)
228 self.assertEqual(created_stack.id, retrieved_stack.id)
229 self.assertIsNotNone(self.stack_creator.get_outputs())
230 self.assertEquals(0, len(self.stack_creator.get_outputs()))
231 self.assertEqual(create_stack.STATUS_CREATE_COMPLETE, self.stack_creator.get_status())
233 # Delete Stack manually
234 heat_utils.delete_stack(self.heat_cli, created_stack)
236 end_time = time.time() + 90
238 while time.time() < end_time:
239 status = heat_utils.get_stack_status(self.heat_cli, retrieved_stack.id)
240 if status == create_stack.STATUS_DELETE_COMPLETE:
244 self.assertTrue(deleted)
246 # Must not throw an exception when attempting to cleanup non-existent stack
247 self.stack_creator.clean()
248 self.assertIsNone(self.stack_creator.get_stack())
250 def test_create_same_stack(self):
252 Tests the creation of an OpenStack stack when the stack already exists.
255 template_dict = heat_utils.parse_heat_template_str(
256 file_utils.read_file('../examples/heat/test_heat_template.yaml'))
257 stack_settings = StackSettings(name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
258 template=template_dict,
259 env_values=self.env_values)
260 self.stack_creator = create_stack.OpenStackHeatStack(self.os_creds, stack_settings)
261 created_stack1 = self.stack_creator.create()
263 retrieved_stack = heat_utils.get_stack_by_id(self.heat_cli, created_stack1.id)
264 self.assertIsNotNone(retrieved_stack)
265 self.assertEqual(created_stack1.name, retrieved_stack.name)
266 self.assertEqual(created_stack1.id, retrieved_stack.id)
267 self.assertIsNotNone(self.stack_creator.get_outputs())
268 self.assertEqual(0, len(self.stack_creator.get_outputs()))
270 # Should be retrieving the instance data
271 stack_creator2 = create_stack.OpenStackHeatStack(self.os_creds, stack_settings)
272 stack2 = stack_creator2.create()
273 self.assertEqual(created_stack1.id, stack2.id)
276 class CreateStackNegativeTests(OSIntegrationTestCase):
278 Negative test cases for the CreateStack class
282 super(self.__class__, self).__start__()
284 self.stack_name = self.__class__.__name__ + '-' + str(uuid.uuid4())
285 self.stack_creator = None
288 if self.stack_creator:
289 self.stack_creator.clean()
290 super(self.__class__, self).__clean__()
292 def test_missing_dependencies(self):
294 Expect an StackCreationError when the stack file does not exist
296 stack_settings = StackSettings(name=self.stack_name, template_path='../examples/heat/test_heat_template.yaml')
297 self.stack_creator = create_stack.OpenStackHeatStack(self.os_creds, stack_settings)
298 with self.assertRaises(HTTPBadRequest):
299 self.stack_creator.create()
301 def test_bad_stack_file(self):
303 Expect an StackCreationError when the stack file does not exist
305 stack_settings = StackSettings(name=self.stack_name, template_path='foo')
306 self.stack_creator = create_stack.OpenStackHeatStack(self.os_creds, stack_settings)
307 with self.assertRaises(IOError):
308 self.stack_creator.create()