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.
21 from snaps.openstack import create_stack
22 from snaps.openstack.create_flavor import OpenStackFlavor, FlavorSettings
24 from snaps.openstack.create_image import OpenStackImage
25 from snaps.openstack.create_instance import OpenStackVmInstance
26 from snaps.openstack.create_stack import StackSettings
27 from snaps.openstack.tests import openstack_tests
28 from snaps.openstack.tests.os_source_file_test import OSComponentTestCase
29 from snaps.openstack.utils import (
30 heat_utils, neutron_utils, nova_utils, settings_utils, glance_utils,
33 __author__ = 'spisarski'
35 logger = logging.getLogger('heat_utils_tests')
38 class HeatSmokeTests(OSComponentTestCase):
40 Tests to ensure that the heat client can communicate with the cloud
43 def test_heat_connect_success(self):
45 Tests to ensure that the proper credentials can connect.
47 heat = heat_utils.heat_client(self.os_creds)
49 # This should not throw an exception
50 stacks = heat.stacks.list()
54 def test_heat_connect_fail(self):
56 Tests to ensure that the improper credentials cannot connect.
58 from snaps.openstack.os_credentials import OSCreds
60 heat = heat_utils.heat_client(
61 OSCreds(username='user', password='pass',
62 auth_url=self.os_creds.auth_url,
63 project_name=self.os_creds.project_name,
64 proxy_settings=self.os_creds.proxy_settings))
65 stacks = heat.stacks.list()
67 # This should throw an exception
68 with self.assertRaises(Exception):
73 class HeatUtilsCreateSimpleStackTests(OSComponentTestCase):
75 Test basic Heat functionality
80 Instantiates OpenStack instances that cannot be spawned by Heat
82 guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
83 stack_name1 = guid + '-stack1'
84 stack_name2 = guid + '-stack2'
85 self.network_name = guid + '-net'
86 self.subnet_name = guid + '-subnet'
87 self.vm_inst_name = guid + '-inst'
89 self.image_creator = OpenStackImage(
90 self.os_creds, openstack_tests.cirros_image_settings(
91 name=guid + '-image', image_metadata=self.image_metadata))
92 self.image_creator.create()
95 self.flavor_creator = OpenStackFlavor(
97 FlavorSettings(name=guid + '-flavor', ram=256, disk=10, vcpus=1))
98 self.flavor_creator.create()
100 env_values = {'image_name': self.image_creator.image_settings.name,
101 'flavor_name': self.flavor_creator.flavor_settings.name,
102 'net_name': self.network_name,
103 'subnet_name': self.subnet_name,
104 'inst_name': self.vm_inst_name}
105 heat_tmplt_path = pkg_resources.resource_filename(
106 'snaps.openstack.tests.heat', 'test_heat_template.yaml')
107 self.stack_settings1 = StackSettings(
108 name=stack_name1, template_path=heat_tmplt_path,
109 env_values=env_values)
110 self.stack_settings2 = StackSettings(
111 name=stack_name2, template_path=heat_tmplt_path,
112 env_values=env_values)
115 self.heat_client = heat_utils.heat_client(self.os_creds)
119 Cleans the image and downloaded image file
123 heat_utils.delete_stack(self.heat_client, self.stack1)
129 heat_utils.delete_stack(self.heat_client, self.stack2)
133 if self.image_creator:
135 self.image_creator.clean()
139 if self.flavor_creator:
141 self.flavor_creator.clean()
145 def test_create_stack(self):
147 Tests the creation of an OpenStack Heat stack1 that does not exist.
149 self.stack1 = heat_utils.create_stack(self.heat_client,
150 self.stack_settings1)
152 stack_query_1 = heat_utils.get_stack(
153 self.heat_client, stack_settings=self.stack_settings1)
154 self.assertEqual(self.stack1, stack_query_1)
156 stack_query_2 = heat_utils.get_stack(
157 self.heat_client, stack_name=self.stack_settings1.name)
158 self.assertEqual(self.stack1, stack_query_2)
160 stack_query_3 = heat_utils.get_stack_by_id(self.heat_client,
162 self.assertEqual(self.stack1, stack_query_3)
164 resources = heat_utils.get_resources(self.heat_client, self.stack1)
165 self.assertIsNotNone(resources)
166 self.assertEqual(4, len(resources))
168 outputs = heat_utils.get_outputs(self.heat_client, self.stack1)
169 self.assertIsNotNone(outputs)
170 self.assertEqual(0, len(outputs))
172 # Wait until stack deployment has completed
173 end_time = time.time() + create_stack.STACK_COMPLETE_TIMEOUT
175 while time.time() < end_time:
176 status = heat_utils.get_stack_status(self.heat_client,
178 if status == create_stack.STATUS_CREATE_COMPLETE:
181 elif status == create_stack.STATUS_CREATE_FAILED:
187 self.assertTrue(is_active)
189 neutron = neutron_utils.neutron_client(self.os_creds)
190 networks = heat_utils.get_stack_networks(
191 self.heat_client, neutron, self.stack1)
192 self.assertIsNotNone(networks)
193 self.assertEqual(1, len(networks))
194 self.assertEqual(self.network_name, networks[0].name)
196 subnets = neutron_utils.get_subnets_by_network(neutron, networks[0])
197 self.assertEqual(1, len(subnets))
198 self.assertEqual(self.subnet_name, subnets[0].name)
200 nova = nova_utils.nova_client(self.os_creds)
201 servers = heat_utils.get_stack_servers(
202 self.heat_client, nova, self.stack1)
203 self.assertIsNotNone(servers)
204 self.assertEqual(1, len(servers))
205 self.assertEqual(self.vm_inst_name, servers[0].name)
207 def test_create_stack_x2(self):
209 Tests the creation of an OpenStack keypair that does not exist.
211 self.stack1 = heat_utils.create_stack(self.heat_client,
212 self.stack_settings1)
214 stack1_query_1 = heat_utils.get_stack(
215 self.heat_client, stack_settings=self.stack_settings1)
216 self.assertEqual(self.stack1, stack1_query_1)
218 stack1_query_2 = heat_utils.get_stack(
219 self.heat_client, stack_name=self.stack_settings1.name)
220 self.assertEqual(self.stack1, stack1_query_2)
222 stack1_query_3 = heat_utils.get_stack_by_id(self.heat_client,
224 self.assertEqual(self.stack1, stack1_query_3)
226 end_time = time.time() + create_stack.STACK_COMPLETE_TIMEOUT
228 while time.time() < end_time:
229 status = heat_utils.get_stack_status(self.heat_client,
231 if status == create_stack.STATUS_CREATE_COMPLETE:
234 elif status == create_stack.STATUS_CREATE_FAILED:
240 self.assertTrue(is_active)
242 self.stack2 = heat_utils.create_stack(self.heat_client,
243 self.stack_settings2)
245 stack2_query_1 = heat_utils.get_stack(
246 self.heat_client, stack_settings=self.stack_settings2)
247 self.assertEqual(self.stack2, stack2_query_1)
249 stack2_query_2 = heat_utils.get_stack(
250 self.heat_client, stack_name=self.stack_settings2.name)
251 self.assertEqual(self.stack2, stack2_query_2)
253 stack2_query_3 = heat_utils.get_stack_by_id(self.heat_client,
255 self.assertEqual(self.stack2, stack2_query_3)
257 end_time = time.time() + create_stack.STACK_COMPLETE_TIMEOUT
260 while time.time() < end_time:
261 status = heat_utils.get_stack_status(self.heat_client,
263 if status == create_stack.STATUS_CREATE_COMPLETE:
266 elif status == create_stack.STATUS_CREATE_FAILED:
272 self.assertTrue(is_active)
275 class HeatUtilsCreateComplexStackTests(OSComponentTestCase):
277 Test basic Heat functionality
282 Instantiates OpenStack instances that cannot be spawned by Heat
284 guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
285 stack_name = guid + '-stack'
286 self.network_name = guid + '-net'
287 self.subnet_name = guid + '-subnet'
288 self.vm_inst1_name = guid + '-inst1'
289 self.vm_inst2_name = guid + '-inst2'
290 self.flavor1_name = guid + '-flavor1'
291 self.flavor2_name = guid + '-flavor2'
292 self.keypair_name = guid + '-keypair'
294 self.image_creator1 = OpenStackImage(
295 self.os_creds, openstack_tests.cirros_image_settings(
296 name=guid + '-image1', image_metadata=self.image_metadata))
297 self.image_creator1.create()
299 self.image_creator2 = OpenStackImage(
300 self.os_creds, openstack_tests.cirros_image_settings(
301 name=guid + '-image2', image_metadata=self.image_metadata))
302 self.image_creator2.create()
304 env_values = {'image1_name': self.image_creator1.image_settings.name,
305 'image2_name': self.image_creator2.image_settings.name,
306 'flavor1_name': self.flavor1_name,
307 'flavor2_name': self.flavor2_name,
308 'net_name': self.network_name,
309 'subnet_name': self.subnet_name,
310 'keypair_name': self.keypair_name,
311 'inst1_name': self.vm_inst1_name,
312 'inst2_name': self.vm_inst2_name,
313 'external_net_name': self.ext_net_name}
314 heat_tmplt_path = pkg_resources.resource_filename(
315 'snaps.openstack.tests.heat', 'floating_ip_heat_template.yaml')
316 stack_settings = StackSettings(
317 name=stack_name, template_path=heat_tmplt_path,
318 env_values=env_values)
319 self.heat_client = heat_utils.heat_client(self.os_creds)
320 self.stack = heat_utils.create_stack(self.heat_client, stack_settings)
322 # Wait until stack deployment has completed
323 end_time = time.time() + create_stack.STACK_COMPLETE_TIMEOUT
325 while time.time() < end_time:
326 status = heat_utils.get_stack_status(self.heat_client,
328 if status == create_stack.STATUS_CREATE_COMPLETE:
331 elif status == create_stack.STATUS_CREATE_FAILED:
336 self.assertTrue(is_active)
340 Cleans the image and downloaded image file
344 heat_utils.delete_stack(self.heat_client, self.stack)
345 # Wait until stack deployment has completed
346 end_time = time.time() + create_stack.STACK_COMPLETE_TIMEOUT
348 while time.time() < end_time:
349 status = heat_utils.get_stack_status(self.heat_client,
351 if status == create_stack.STATUS_DELETE_COMPLETE:
354 elif status == create_stack.STATUS_DELETE_FAILED:
361 nova = nova_utils.nova_client(self.os_creds)
362 neutron = neutron_utils.neutron_client(self.os_creds)
363 glance = glance_utils.glance_client(self.os_creds)
364 servers = heat_utils.get_stack_servers(
365 self.heat_client, nova, self.stack)
366 for server in servers:
367 vm_settings = settings_utils.create_vm_inst_settings(
368 nova, neutron, server)
369 img_settings = settings_utils.determine_image_settings(
371 [self.image_creator1.image_settings,
372 self.image_creator2.image_settings])
373 vm_creator = OpenStackVmInstance(
374 self.os_creds, vm_settings, img_settings)
375 vm_creator.initialize()
377 vm_creator.vm_deleted(block=True)
379 heat_utils.delete_stack(self.heat_client, self.stack)
384 if self.image_creator1:
386 self.image_creator1.clean()
390 if self.image_creator2:
392 self.image_creator2.clean()
396 def test_get_settings_from_stack(self):
398 Tests that a heat template with floating IPs and can have the proper
399 settings derived from settings_utils.py.
401 resources = heat_utils.get_resources(self.heat_client, self.stack)
402 self.assertIsNotNone(resources)
403 self.assertEqual(12, len(resources))
405 options = heat_utils.get_outputs(self.heat_client, self.stack)
406 self.assertIsNotNone(options)
407 self.assertEqual(1, len(options))
409 neutron = neutron_utils.neutron_client(self.os_creds)
410 networks = heat_utils.get_stack_networks(
411 self.heat_client, neutron, self.stack)
412 self.assertIsNotNone(networks)
413 self.assertEqual(1, len(networks))
414 self.assertEqual(self.network_name, networks[0].name)
416 network_settings = settings_utils.create_network_settings(
417 neutron, networks[0])
418 self.assertIsNotNone(network_settings)
419 self.assertEqual(self.network_name, network_settings.name)
421 nova = nova_utils.nova_client(self.os_creds)
422 glance = glance_utils.glance_client(self.os_creds)
424 servers = heat_utils.get_stack_servers(
425 self.heat_client, nova, self.stack)
426 self.assertIsNotNone(servers)
427 self.assertEqual(2, len(servers))
429 image_settings = settings_utils.determine_image_settings(
431 [self.image_creator1.image_settings,
432 self.image_creator2.image_settings])
434 self.assertIsNotNone(image_settings)
435 if image_settings.name.endswith('1'):
437 self.image_creator1.image_settings.name, image_settings.name)
440 self.image_creator2.image_settings.name, image_settings.name)
442 image_settings = settings_utils.determine_image_settings(
444 [self.image_creator1.image_settings,
445 self.image_creator2.image_settings])
446 if image_settings.name.endswith('1'):
448 self.image_creator1.image_settings.name, image_settings.name)
451 self.image_creator2.image_settings.name, image_settings.name)
453 keypair1_settings = settings_utils.determine_keypair_settings(
454 self.heat_client, self.stack, servers[0],
455 priv_key_key='private_key')
456 self.assertIsNotNone(keypair1_settings)
457 self.assertEqual(self.keypair_name, keypair1_settings.name)
459 keypair2_settings = settings_utils.determine_keypair_settings(
460 self.heat_client, self.stack, servers[1],
461 priv_key_key='private_key')
462 self.assertIsNotNone(keypair2_settings)
463 self.assertEqual(self.keypair_name, keypair2_settings.name)
466 class HeatUtilsVolumeTests(OSComponentTestCase):
468 Test Heat volume functionality
473 Instantiates OpenStack instances that cannot be spawned by Heat
475 guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
476 stack_name = guid + '-stack'
477 self.volume_name = guid + '-vol'
478 self.volume_type_name = guid + '-vol-type'
481 'volume_name': self.volume_name,
482 'volume_type_name': self.volume_type_name}
484 heat_tmplt_path = pkg_resources.resource_filename(
485 'snaps.openstack.tests.heat', 'volume_heat_template.yaml')
486 self.stack_settings = StackSettings(
487 name=stack_name, template_path=heat_tmplt_path,
488 env_values=env_values)
490 self.heat_client = heat_utils.heat_client(self.os_creds)
491 self.cinder = cinder_utils.cinder_client(self.os_creds)
495 Cleans the image and downloaded image file
499 heat_utils.delete_stack(self.heat_client, self.stack)
503 def test_create_vol_with_stack(self):
505 Tests the creation of an OpenStack volume with Heat.
507 self.stack = heat_utils.create_stack(
508 self.heat_client, self.stack_settings)
510 # Wait until stack deployment has completed
511 end_time = time.time() + create_stack.STACK_COMPLETE_TIMEOUT
513 while time.time() < end_time:
514 status = heat_utils.get_stack_status(self.heat_client,
516 if status == create_stack.STATUS_CREATE_COMPLETE:
519 elif status == create_stack.STATUS_CREATE_FAILED:
525 self.assertTrue(is_active)
527 volumes = heat_utils.get_stack_volumes(
528 self.heat_client, self.cinder, self.stack)
530 self.assertEqual(1, len(volumes))
533 self.assertEqual(self.volume_name, volume.name)
534 self.assertEqual(self.volume_type_name, volume.type)
535 self.assertEqual(1, volume.size)
536 self.assertEqual(False, volume.multi_attach)
538 def test_create_vol_types_with_stack(self):
540 Tests the creation of an OpenStack volume with Heat.
542 self.stack = heat_utils.create_stack(
543 self.heat_client, self.stack_settings)
545 # Wait until stack deployment has completed
546 end_time = time.time() + create_stack.STACK_COMPLETE_TIMEOUT
548 while time.time() < end_time:
549 status = heat_utils.get_stack_status(self.heat_client,
551 if status == create_stack.STATUS_CREATE_COMPLETE:
554 elif status == create_stack.STATUS_CREATE_FAILED:
560 self.assertTrue(is_active)
562 volume_types = heat_utils.get_stack_volume_types(
563 self.heat_client, self.cinder, self.stack)
565 self.assertEqual(1, len(volume_types))
567 volume_type = volume_types[0]
569 self.assertEqual(self.volume_type_name, volume_type.name)
570 self.assertTrue(volume_type.public)
571 self.assertIsNone(volume_type.qos_spec)
573 encryption = volume_type.encryption
574 self.assertIsNotNone(encryption)
575 self.assertIsNone(encryption.cipher)
576 self.assertEqual('front-end', encryption.control_location)
577 self.assertIsNone(encryption.key_size)
578 self.assertEqual(u'nova.volume.encryptors.luks.LuksEncryptor',
580 self.assertEqual(volume_type.id, encryption.volume_type_id)