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.
18 from heatclient.exc import HTTPBadRequest
19 from snaps import file_utils
20 from snaps.openstack.create_flavor import OpenStackFlavor, FlavorSettings
21 from snaps.openstack.create_image import OpenStackImage
24 from urllib.request import URLError
26 from urllib2 import URLError
32 from snaps.openstack import create_stack
33 from snaps.openstack.create_stack import StackSettings, StackSettingsError
34 from snaps.openstack.tests import openstack_tests
35 from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase
36 from snaps.openstack.utils import heat_utils, neutron_utils
38 __author__ = 'spisarski'
40 logger = logging.getLogger('create_stack_tests')
43 class StackSettingsUnitTests(unittest.TestCase):
45 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(**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(**{'name': 'foo'})
64 def test_config_minimum_template(self):
65 settings = StackSettings(**{'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,
71 settings.stack_create_timeout)
73 def test_config_minimum_template_path(self):
74 settings = StackSettings(**{'name': 'stack', 'template_path': 'foo'})
75 self.assertEqual('stack', settings.name)
76 self.assertIsNone(settings.template)
77 self.assertEqual('foo', settings.template_path)
78 self.assertIsNone(settings.env_values)
79 self.assertEqual(create_stack.STACK_COMPLETE_TIMEOUT,
80 settings.stack_create_timeout)
82 def test_minimum_template(self):
83 settings = StackSettings(name='stack', template='foo')
84 self.assertEqual('stack', settings.name)
85 self.assertEqual('foo', settings.template)
86 self.assertIsNone(settings.template_path)
87 self.assertIsNone(settings.env_values)
88 self.assertEqual(create_stack.STACK_COMPLETE_TIMEOUT,
89 settings.stack_create_timeout)
91 def test_minimum_template_path(self):
92 settings = StackSettings(name='stack', template_path='foo')
93 self.assertEqual('stack', settings.name)
94 self.assertEqual('foo', settings.template_path)
95 self.assertIsNone(settings.template)
96 self.assertIsNone(settings.env_values)
97 self.assertEqual(create_stack.STACK_COMPLETE_TIMEOUT,
98 settings.stack_create_timeout)
101 env_values = {'foo': 'bar'}
102 settings = StackSettings(name='stack', template='bar',
103 template_path='foo', env_values=env_values,
104 stack_create_timeout=999)
105 self.assertEqual('stack', settings.name)
106 self.assertEqual('bar', settings.template)
107 self.assertEqual('foo', settings.template_path)
108 self.assertEqual(env_values, settings.env_values)
109 self.assertEqual(999, settings.stack_create_timeout)
111 def test_config_all(self):
112 env_values = {'foo': 'bar'}
113 settings = StackSettings(
114 **{'name': 'stack', 'template': 'bar', 'template_path': 'foo',
115 'env_values': env_values, 'stack_create_timeout': 999})
116 self.assertEqual('stack', settings.name)
117 self.assertEqual('bar', settings.template)
118 self.assertEqual('foo', settings.template_path)
119 self.assertEqual(env_values, settings.env_values)
120 self.assertEqual(999, settings.stack_create_timeout)
123 class CreateStackSuccessTests(OSIntegrationTestCase):
125 Test for the CreateStack class defined in create_stack.py
130 Instantiates the CreateStack object that is responsible for downloading
131 and creating an OS stack file within OpenStack
133 super(self.__class__, self).__start__()
135 self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
137 self.heat_creds = self.admin_os_creds
138 self.heat_creds.project_name = self.admin_os_creds.project_name
140 self.heat_cli = heat_utils.heat_client(self.heat_creds)
141 self.stack_creator = None
143 self.image_creator = OpenStackImage(
144 self.heat_creds, openstack_tests.cirros_image_settings(
145 name=self.guid + '-image',
146 image_metadata=self.image_metadata))
147 self.image_creator.create()
150 self.flavor_creator = OpenStackFlavor(
152 FlavorSettings(name=self.guid + '-flavor-name', ram=256, disk=10,
154 self.flavor_creator.create()
156 self.network_name = self.guid + '-net'
157 self.subnet_name = self.guid + '-subnet'
159 'image_name': self.image_creator.image_settings.name,
160 'flavor_name': self.flavor_creator.flavor_settings.name,
161 'net_name': self.network_name,
162 'subnet_name': self.subnet_name}
164 self.heat_tmplt_path = pkg_resources.resource_filename(
165 'snaps.openstack.tests.heat', 'test_heat_template.yaml')
169 Cleans the stack and downloaded stack file
171 if self.stack_creator:
173 self.stack_creator.clean()
177 if self.image_creator:
179 self.image_creator.clean()
183 if self.flavor_creator:
185 self.flavor_creator.clean()
189 super(self.__class__, self).__clean__()
191 def test_create_stack_template_file(self):
193 Tests the creation of an OpenStack stack from Heat template file.
196 # Set the default stack settings, then set any custom parameters sent
198 stack_settings = StackSettings(
199 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
200 template_path=self.heat_tmplt_path,
201 env_values=self.env_values)
202 self.stack_creator = create_stack.OpenStackHeatStack(self.heat_creds,
204 created_stack = self.stack_creator.create()
205 self.assertIsNotNone(created_stack)
207 retrieved_stack = heat_utils.get_stack_by_id(self.heat_cli,
209 self.assertIsNotNone(retrieved_stack)
210 self.assertEqual(created_stack.name, retrieved_stack.name)
211 self.assertEqual(created_stack.id, retrieved_stack.id)
212 self.assertIsNotNone(self.stack_creator.get_outputs())
213 self.assertEquals(0, len(self.stack_creator.get_outputs()))
215 resources = heat_utils.get_resources(
216 self.heat_cli, self.stack_creator.get_stack())
217 self.assertIsNotNone(resources)
218 self.assertEqual(4, len(resources))
220 def test_create_stack_template_dict(self):
222 Tests the creation of an OpenStack stack from a heat dict() object.
225 # Set the default stack settings, then set any custom parameters sent
227 template_dict = heat_utils.parse_heat_template_str(
228 file_utils.read_file(self.heat_tmplt_path))
229 stack_settings = StackSettings(
230 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
231 template=template_dict,
232 env_values=self.env_values)
233 self.stack_creator = create_stack.OpenStackHeatStack(self.heat_creds,
235 created_stack = self.stack_creator.create()
236 self.assertIsNotNone(created_stack)
238 retrieved_stack = heat_utils.get_stack_by_id(self.heat_cli,
240 self.assertIsNotNone(retrieved_stack)
241 self.assertEqual(created_stack.name, retrieved_stack.name)
242 self.assertEqual(created_stack.id, retrieved_stack.id)
243 self.assertIsNotNone(self.stack_creator.get_outputs())
244 self.assertEquals(0, len(self.stack_creator.get_outputs()))
246 def test_create_delete_stack(self):
248 Tests the creation then deletion of an OpenStack stack to ensure
249 clean() does not raise an Exception.
252 template_dict = heat_utils.parse_heat_template_str(
253 file_utils.read_file(self.heat_tmplt_path))
254 stack_settings = StackSettings(
255 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
256 template=template_dict,
257 env_values=self.env_values)
258 self.stack_creator = create_stack.OpenStackHeatStack(self.heat_creds,
260 created_stack = self.stack_creator.create()
261 self.assertIsNotNone(created_stack)
263 retrieved_stack = heat_utils.get_stack_by_id(self.heat_cli,
265 self.assertIsNotNone(retrieved_stack)
266 self.assertEqual(created_stack.name, retrieved_stack.name)
267 self.assertEqual(created_stack.id, retrieved_stack.id)
268 self.assertIsNotNone(self.stack_creator.get_outputs())
269 self.assertEquals(0, len(self.stack_creator.get_outputs()))
270 self.assertEqual(create_stack.STATUS_CREATE_COMPLETE,
271 self.stack_creator.get_status())
273 # Delete Stack manually
274 heat_utils.delete_stack(self.heat_cli, created_stack)
276 end_time = time.time() + 90
278 while time.time() < end_time:
279 status = heat_utils.get_stack_status(self.heat_cli,
281 if status == create_stack.STATUS_DELETE_COMPLETE:
285 self.assertTrue(deleted)
287 # Must not throw an exception when attempting to cleanup non-existent
289 self.stack_creator.clean()
290 self.assertIsNone(self.stack_creator.get_stack())
292 def test_create_same_stack(self):
294 Tests the creation of an OpenStack stack when the stack already exists.
297 template_dict = heat_utils.parse_heat_template_str(
298 file_utils.read_file(self.heat_tmplt_path))
299 stack_settings = StackSettings(
300 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
301 template=template_dict,
302 env_values=self.env_values)
303 self.stack_creator = create_stack.OpenStackHeatStack(self.heat_creds,
305 created_stack1 = self.stack_creator.create()
307 retrieved_stack = heat_utils.get_stack_by_id(self.heat_cli,
309 self.assertIsNotNone(retrieved_stack)
310 self.assertEqual(created_stack1.name, retrieved_stack.name)
311 self.assertEqual(created_stack1.id, retrieved_stack.id)
312 self.assertIsNotNone(self.stack_creator.get_outputs())
313 self.assertEqual(0, len(self.stack_creator.get_outputs()))
315 # Should be retrieving the instance data
316 stack_creator2 = create_stack.OpenStackHeatStack(self.heat_creds,
318 stack2 = stack_creator2.create()
319 self.assertEqual(created_stack1.id, stack2.id)
321 def test_retrieve_network_creators(self):
323 Tests the creation of an OpenStack stack from Heat template file and
324 the retrieval of the network creator.
326 stack_settings = StackSettings(
327 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
328 template_path=self.heat_tmplt_path,
329 env_values=self.env_values)
330 self.stack_creator = create_stack.OpenStackHeatStack(self.heat_creds,
332 created_stack = self.stack_creator.create()
333 self.assertIsNotNone(created_stack)
335 net_creators = self.stack_creator.get_network_creators()
336 self.assertIsNotNone(net_creators)
337 self.assertEqual(1, len(net_creators))
338 self.assertEqual(self.network_name, net_creators[0].get_network().name)
340 neutron = neutron_utils.neutron_client(self.os_creds)
341 net_by_name = neutron_utils.get_network(
342 neutron, network_name=net_creators[0].get_network().name)
343 self.assertEqual(net_creators[0].get_network(), net_by_name)
344 self.assertIsNotNone(neutron_utils.get_network_by_id(
345 neutron, net_creators[0].get_network().id))
347 self.assertEqual(1, len(net_creators[0].get_subnets()))
348 subnet = net_creators[0].get_subnets()[0]
349 subnet_by_name = neutron_utils.get_subnet(
350 neutron, subnet_name=subnet.name)
351 self.assertEqual(subnet, subnet_by_name)
353 subnet_by_id = neutron_utils.get_subnet_by_id(neutron, subnet.id)
354 self.assertIsNotNone(subnet_by_id)
355 self.assertEqual(subnet_by_name, subnet_by_id)
358 class CreateStackNegativeTests(OSIntegrationTestCase):
360 Negative test cases for the CreateStack class
364 super(self.__class__, self).__start__()
366 self.heat_creds = self.admin_os_creds
367 self.heat_creds.project_name = self.admin_os_creds.project_name
369 self.stack_name = self.__class__.__name__ + '-' + str(uuid.uuid4())
370 self.stack_creator = None
371 self.heat_tmplt_path = pkg_resources.resource_filename(
372 'snaps.openstack.tests.heat', 'test_heat_template.yaml')
375 if self.stack_creator:
376 self.stack_creator.clean()
377 super(self.__class__, self).__clean__()
379 def test_missing_dependencies(self):
381 Expect an StackCreationError when the stack file does not exist
383 stack_settings = StackSettings(name=self.stack_name,
384 template_path=self.heat_tmplt_path)
385 self.stack_creator = create_stack.OpenStackHeatStack(self.heat_creds,
387 with self.assertRaises(HTTPBadRequest):
388 self.stack_creator.create()
390 def test_bad_stack_file(self):
392 Expect an StackCreationError when the stack file does not exist
394 stack_settings = StackSettings(name=self.stack_name,
396 self.stack_creator = create_stack.OpenStackHeatStack(self.heat_creds,
398 with self.assertRaises(IOError):
399 self.stack_creator.create()