Added members to VmInst that will contain the availability_zone
[snaps.git] / snaps / openstack / utils / tests / heat_utils_tests.py
1 # Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs")
2 #                    and others.  All rights reserved.
3 #
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:
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
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.
15 import logging
16 import os
17
18 import pkg_resources
19 import uuid
20
21 import time
22
23 import snaps.config.stack as stack_config
24 from snaps.config.flavor import FlavorConfig
25 from snaps.openstack.create_flavor import OpenStackFlavor
26
27 from snaps.openstack.create_image import OpenStackImage
28 from snaps.openstack.create_instance import OpenStackVmInstance
29 from snaps.openstack.create_stack import StackConfig
30 from snaps.openstack.tests import openstack_tests
31 from snaps.openstack.tests.os_source_file_test import OSComponentTestCase
32 from snaps.openstack.utils import (
33     heat_utils, neutron_utils, nova_utils, settings_utils, glance_utils,
34     cinder_utils, keystone_utils)
35
36 __author__ = 'spisarski'
37
38 logger = logging.getLogger('heat_utils_tests')
39
40
41 class HeatSmokeTests(OSComponentTestCase):
42     """
43     Tests to ensure that the heat client can communicate with the cloud
44     """
45
46     def test_heat_connect_success(self):
47         """
48         Tests to ensure that the proper credentials can connect.
49         """
50         heat = heat_utils.heat_client(self.os_creds)
51
52         # This should not throw an exception
53         stacks = heat.stacks.list()
54         for stack in stacks:
55             print stack
56
57     def test_heat_connect_fail(self):
58         """
59         Tests to ensure that the improper credentials cannot connect.
60         """
61         from snaps.openstack.os_credentials import OSCreds
62
63         heat = heat_utils.heat_client(
64             OSCreds(username='user', password='pass',
65                     auth_url=self.os_creds.auth_url,
66                     project_name=self.os_creds.project_name,
67                     proxy_settings=self.os_creds.proxy_settings))
68         stacks = heat.stacks.list()
69
70         # This should throw an exception
71         with self.assertRaises(Exception):
72             for stack in stacks:
73                 print stack
74
75
76 class HeatUtilsCreateSimpleStackTests(OSComponentTestCase):
77     """
78     Test basic Heat functionality
79     """
80
81     def setUp(self):
82         """
83         Instantiates OpenStack instances that cannot be spawned by Heat
84         """
85         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
86         stack_name1 = guid + '-stack1'
87         stack_name2 = guid + '-stack2'
88         self.network_name = guid + '-net'
89         self.subnet_name = guid + '-subnet'
90         self.vm_inst_name = guid + '-inst'
91
92         self.image_creator = OpenStackImage(
93             self.os_creds, openstack_tests.cirros_image_settings(
94                 name=guid + '-image', image_metadata=self.image_metadata))
95         self.image_creator.create()
96
97         # Create Flavor
98         self.flavor_creator = OpenStackFlavor(
99             self.os_creds,
100             FlavorConfig(name=guid + '-flavor', ram=256, disk=10, vcpus=1))
101         self.flavor_creator.create()
102
103         env_values = {'image_name': self.image_creator.image_settings.name,
104                       'flavor_name': self.flavor_creator.flavor_settings.name,
105                       'net_name': self.network_name,
106                       'subnet_name': self.subnet_name,
107                       'inst_name': self.vm_inst_name}
108         heat_tmplt_path = pkg_resources.resource_filename(
109             'snaps.openstack.tests.heat', 'test_heat_template.yaml')
110         self.stack_settings1 = StackConfig(
111             name=stack_name1, template_path=heat_tmplt_path,
112             env_values=env_values)
113         self.stack_settings2 = StackConfig(
114             name=stack_name2, template_path=heat_tmplt_path,
115             env_values=env_values)
116         self.stack1 = None
117         self.stack2 = None
118         self.heat_client = heat_utils.heat_client(self.os_creds)
119
120     def tearDown(self):
121         """
122         Cleans the stack and image
123         """
124         if self.stack1:
125             try:
126                 heat_utils.delete_stack(self.heat_client, self.stack1)
127             except:
128                 pass
129
130         if self.stack2:
131             try:
132                 heat_utils.delete_stack(self.heat_client, self.stack2)
133             except:
134                 pass
135
136         if self.image_creator:
137             try:
138                 self.image_creator.clean()
139             except:
140                 pass
141
142         if self.flavor_creator:
143             try:
144                 self.flavor_creator.clean()
145             except:
146                 pass
147
148     def test_create_stack(self):
149         """
150         Tests the creation of an OpenStack Heat stack1 that does not exist.
151         """
152         self.stack1 = heat_utils.create_stack(self.heat_client,
153                                               self.stack_settings1)
154
155         stack_query_1 = heat_utils.get_stack(
156             self.heat_client, stack_settings=self.stack_settings1)
157         self.assertEqual(self.stack1, stack_query_1)
158
159         stack_query_2 = heat_utils.get_stack(
160             self.heat_client, stack_name=self.stack_settings1.name)
161         self.assertEqual(self.stack1, stack_query_2)
162
163         stack_query_3 = heat_utils.get_stack_by_id(self.heat_client,
164                                                    self.stack1.id)
165         self.assertEqual(self.stack1, stack_query_3)
166
167         resources = heat_utils.get_resources(self.heat_client, self.stack1.id)
168         self.assertIsNotNone(resources)
169         self.assertEqual(4, len(resources))
170
171         outputs = heat_utils.get_outputs(self.heat_client, self.stack1)
172         self.assertIsNotNone(outputs)
173         self.assertEqual(0, len(outputs))
174
175         self.assertTrue(stack_active(self.heat_client, self.stack1))
176
177         neutron = neutron_utils.neutron_client(self.os_creds)
178         networks = heat_utils.get_stack_networks(
179             self.heat_client, neutron, self.stack1)
180         self.assertIsNotNone(networks)
181         self.assertEqual(1, len(networks))
182         self.assertEqual(self.network_name, networks[0].name)
183
184         subnets = neutron_utils.get_subnets_by_network(neutron, networks[0])
185         self.assertEqual(1, len(subnets))
186         self.assertEqual(self.subnet_name, subnets[0].name)
187
188         nova = nova_utils.nova_client(self.os_creds)
189         keystone = keystone_utils.keystone_client(self.os_creds)
190         servers = heat_utils.get_stack_servers(
191             self.heat_client, nova, neutron, keystone, self.stack1,
192             self.os_creds.project_name)
193         self.assertIsNotNone(servers)
194         self.assertEqual(1, len(servers))
195         self.assertEqual(self.vm_inst_name, servers[0].name)
196
197     def test_create_stack_x2(self):
198         """
199         Tests the creation of an OpenStack keypair that does not exist.
200         """
201         self.stack1 = heat_utils.create_stack(self.heat_client,
202                                               self.stack_settings1)
203
204         stack1_query_1 = heat_utils.get_stack(
205             self.heat_client, stack_settings=self.stack_settings1)
206         self.assertEqual(self.stack1, stack1_query_1)
207
208         stack1_query_2 = heat_utils.get_stack(
209             self.heat_client, stack_name=self.stack_settings1.name)
210         self.assertEqual(self.stack1, stack1_query_2)
211
212         stack1_query_3 = heat_utils.get_stack_by_id(self.heat_client,
213                                                     self.stack1.id)
214         self.assertEqual(self.stack1, stack1_query_3)
215
216         self.assertTrue(stack_active(self.heat_client, self.stack1))
217
218         self.stack2 = heat_utils.create_stack(self.heat_client,
219                                               self.stack_settings2)
220
221         stack2_query_1 = heat_utils.get_stack(
222             self.heat_client, stack_settings=self.stack_settings2)
223         self.assertEqual(self.stack2, stack2_query_1)
224
225         stack2_query_2 = heat_utils.get_stack(
226             self.heat_client, stack_name=self.stack_settings2.name)
227         self.assertEqual(self.stack2, stack2_query_2)
228
229         stack2_query_3 = heat_utils.get_stack_by_id(self.heat_client,
230                                                     self.stack2.id)
231         self.assertEqual(self.stack2, stack2_query_3)
232
233         self.assertTrue(stack_active(self.heat_client, self.stack2))
234
235
236 class HeatUtilsCreateComplexStackTests(OSComponentTestCase):
237     """
238     Test basic Heat functionality
239     """
240
241     def setUp(self):
242         """
243         Instantiates OpenStack instances that cannot be spawned by Heat
244         """
245         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
246         stack_name = guid + '-stack'
247         self.network_name = guid + '-net'
248         self.subnet_name = guid + '-subnet'
249         self.vm_inst1_name = guid + '-inst1'
250         self.vm_inst2_name = guid + '-inst2'
251         self.flavor1_name = guid + '-flavor1'
252         self.flavor2_name = guid + '-flavor2'
253         self.keypair_name = guid + '-keypair'
254
255         self.image_creator1 = OpenStackImage(
256             self.os_creds, openstack_tests.cirros_image_settings(
257                 name=guid + '-image1', image_metadata=self.image_metadata))
258         self.image_creator1.create()
259
260         self.image_creator2 = OpenStackImage(
261             self.os_creds, openstack_tests.cirros_image_settings(
262                 name=guid + '-image2', image_metadata=self.image_metadata))
263         self.image_creator2.create()
264
265         env_values = {'image1_name': self.image_creator1.image_settings.name,
266                       'image2_name': self.image_creator2.image_settings.name,
267                       'flavor1_name': self.flavor1_name,
268                       'flavor2_name': self.flavor2_name,
269                       'net_name': self.network_name,
270                       'subnet_name': self.subnet_name,
271                       'keypair_name': self.keypair_name,
272                       'inst1_name': self.vm_inst1_name,
273                       'inst2_name': self.vm_inst2_name,
274                       'external_net_name': self.ext_net_name}
275         heat_tmplt_path = pkg_resources.resource_filename(
276             'snaps.openstack.tests.heat', 'floating_ip_heat_template.yaml')
277         stack_settings = StackConfig(
278             name=stack_name, template_path=heat_tmplt_path,
279             env_values=env_values)
280         self.heat_client = heat_utils.heat_client(self.os_creds)
281         self.stack = heat_utils.create_stack(self.heat_client, stack_settings)
282
283         self.assertTrue(stack_active(self.heat_client, self.stack))
284
285         self.keypair1_settings = None
286         self.keypair2_settings = None
287
288     def tearDown(self):
289         """
290         Cleans the stack and image
291         """
292         if self.stack:
293             try:
294                 heat_utils.delete_stack(self.heat_client, self.stack)
295                 # Wait until stack deployment has completed
296                 end_time = (time.time() +
297                             stack_config.STACK_COMPLETE_TIMEOUT)
298                 is_deleted = False
299                 while time.time() < end_time:
300                     status = heat_utils.get_stack_status(self.heat_client,
301                                                          self.stack.id)
302                     if status == stack_config.STATUS_DELETE_COMPLETE:
303                         is_deleted = True
304                         break
305                     elif status == stack_config.STATUS_DELETE_FAILED:
306                         is_deleted = False
307                         break
308
309                     time.sleep(3)
310
311                 if not is_deleted:
312                     nova = nova_utils.nova_client(self.os_creds)
313                     keystone = keystone_utils.keystone_client(self.os_creds)
314                     neutron = neutron_utils.neutron_client(self.os_creds)
315                     glance = glance_utils.glance_client(self.os_creds)
316                     servers = heat_utils.get_stack_servers(
317                         self.heat_client, nova, neutron, keystone, self.stack,
318                         self.os_creds.project_name)
319                     for server in servers:
320                         vm_settings = settings_utils.create_vm_inst_config(
321                             nova, keystone, neutron, server,
322                             self.os_creds.project_name)
323                         img_settings = settings_utils.determine_image_config(
324                             glance, server,
325                             [self.image_creator1.image_settings,
326                              self.image_creator2.image_settings])
327                         vm_creator = OpenStackVmInstance(
328                             self.os_creds, vm_settings, img_settings)
329                         vm_creator.initialize()
330                         vm_creator.clean()
331                         vm_creator.vm_deleted(block=True)
332
333                     heat_utils.delete_stack(self.heat_client, self.stack)
334                     time.sleep(20)
335             except:
336                     raise
337
338         if self.image_creator1:
339             try:
340                 self.image_creator1.clean()
341             except:
342                 pass
343
344         if self.image_creator2:
345             try:
346                 self.image_creator2.clean()
347             except:
348                 pass
349
350         if self.keypair1_settings:
351             expanded_path = os.path.expanduser(
352                 self.keypair1_settings.private_filepath)
353             os.chmod(expanded_path, 0o755)
354             os.remove(expanded_path)
355
356         if self.keypair2_settings:
357             expanded_path = os.path.expanduser(
358                 self.keypair2_settings.private_filepath)
359             os.chmod(expanded_path, 0o755)
360             os.remove(expanded_path)
361
362     def test_get_settings_from_stack(self):
363         """
364         Tests that a heat template with floating IPs and can have the proper
365         settings derived from settings_utils.py.
366         """
367         resources = heat_utils.get_resources(self.heat_client, self.stack.id)
368         self.assertIsNotNone(resources)
369         self.assertEqual(12, len(resources))
370
371         options = heat_utils.get_outputs(self.heat_client, self.stack)
372         self.assertIsNotNone(options)
373         self.assertEqual(1, len(options))
374
375         neutron = neutron_utils.neutron_client(self.os_creds)
376         networks = heat_utils.get_stack_networks(
377             self.heat_client, neutron, self.stack)
378         self.assertIsNotNone(networks)
379         self.assertEqual(1, len(networks))
380         self.assertEqual(self.network_name, networks[0].name)
381
382         network_settings = settings_utils.create_network_config(
383             neutron, networks[0])
384         self.assertIsNotNone(network_settings)
385         self.assertEqual(self.network_name, network_settings.name)
386
387         nova = nova_utils.nova_client(self.os_creds)
388         glance = glance_utils.glance_client(self.os_creds)
389         keystone = keystone_utils.keystone_client(self.os_creds)
390         servers = heat_utils.get_stack_servers(
391             self.heat_client, nova, neutron, keystone, self.stack,
392             self.os_creds.project_name)
393         self.assertIsNotNone(servers)
394         self.assertEqual(2, len(servers))
395
396         image_settings = settings_utils.determine_image_config(
397             glance, servers[0],
398             [self.image_creator1.image_settings,
399              self.image_creator2.image_settings])
400
401         self.assertIsNotNone(image_settings)
402         if image_settings.name.endswith('1'):
403             self.assertEqual(
404                 self.image_creator1.image_settings.name, image_settings.name)
405         else:
406             self.assertEqual(
407                 self.image_creator2.image_settings.name, image_settings.name)
408
409         image_settings = settings_utils.determine_image_config(
410             glance, servers[1],
411             [self.image_creator1.image_settings,
412              self.image_creator2.image_settings])
413         if image_settings.name.endswith('1'):
414             self.assertEqual(
415                 self.image_creator1.image_settings.name, image_settings.name)
416         else:
417             self.assertEqual(
418                 self.image_creator2.image_settings.name, image_settings.name)
419
420         self.keypair1_settings = settings_utils.determine_keypair_config(
421             self.heat_client, self.stack, servers[0],
422             priv_key_key='private_key')
423         self.assertIsNotNone(self.keypair1_settings)
424         self.assertEqual(self.keypair_name, self.keypair1_settings.name)
425
426         self.keypair2_settings = settings_utils.determine_keypair_config(
427             self.heat_client, self.stack, servers[1],
428             priv_key_key='private_key')
429         self.assertIsNotNone(self.keypair2_settings)
430         self.assertEqual(self.keypair_name, self.keypair2_settings.name)
431
432
433 class HeatUtilsRouterTests(OSComponentTestCase):
434     """
435     Test Heat volume functionality
436     """
437
438     def setUp(self):
439         """
440         Instantiates OpenStack instances that cannot be spawned by Heat
441         """
442         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
443         stack_name = guid + '-stack'
444
445         self.net_name = guid + '-net'
446         self.subnet_name = guid + '-subnet'
447         self.router_name = guid + '-router'
448
449         env_values = {
450             'net_name': self.net_name,
451             'subnet_name': self.subnet_name,
452             'router_name': self.router_name,
453             'external_net_name': self.ext_net_name}
454
455         heat_tmplt_path = pkg_resources.resource_filename(
456             'snaps.openstack.tests.heat', 'router_heat_template.yaml')
457         self.stack_settings = StackConfig(
458             name=stack_name, template_path=heat_tmplt_path,
459             env_values=env_values)
460         self.stack = None
461         self.heat_client = heat_utils.heat_client(self.os_creds)
462         self.neutron = neutron_utils.neutron_client(self.os_creds)
463
464     def tearDown(self):
465         """
466         Cleans the image and downloaded image file
467         """
468         if self.stack:
469             try:
470                 heat_utils.delete_stack(self.heat_client, self.stack)
471             except:
472                 pass
473
474     def test_create_router_with_stack(self):
475         """
476         Tests the creation of an OpenStack router with Heat and the retrieval
477         of the Router Domain objects from heat_utils#get_stack_routers().
478         """
479         self.stack = heat_utils.create_stack(
480             self.heat_client, self.stack_settings)
481
482         # Wait until stack deployment has completed
483         end_time = time.time() + stack_config.STACK_COMPLETE_TIMEOUT
484         is_active = False
485         while time.time() < end_time:
486             status = heat_utils.get_stack_status(self.heat_client,
487                                                  self.stack.id)
488             if status == stack_config.STATUS_CREATE_COMPLETE:
489                 is_active = True
490                 break
491             elif status == stack_config.STATUS_CREATE_FAILED:
492                 is_active = False
493                 break
494
495             time.sleep(3)
496
497         self.assertTrue(is_active)
498
499         routers = heat_utils.get_stack_routers(
500             self.heat_client, self.neutron, self.stack)
501
502         self.assertEqual(1, len(routers))
503
504         router = routers[0]
505         self.assertEqual(self.router_name, router.name)
506
507         keystone = keystone_utils.keystone_client(self.os_creds)
508         ext_net = neutron_utils.get_network(
509             self.neutron, keystone, network_name=self.ext_net_name)
510         self.assertEqual(ext_net.id, router.external_network_id)
511
512
513 class HeatUtilsVolumeTests(OSComponentTestCase):
514     """
515     Test Heat volume functionality
516     """
517
518     def setUp(self):
519         """
520         Instantiates OpenStack instances that cannot be spawned by Heat
521         """
522         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
523         stack_name = guid + '-stack'
524         self.volume_name = guid + '-vol'
525         self.volume_type_name = guid + '-vol-type'
526
527         env_values = {
528             'volume_name': self.volume_name,
529             'volume_type_name': self.volume_type_name}
530
531         heat_tmplt_path = pkg_resources.resource_filename(
532             'snaps.openstack.tests.heat', 'volume_heat_template.yaml')
533         self.stack_settings = StackConfig(
534             name=stack_name, template_path=heat_tmplt_path,
535             env_values=env_values)
536         self.stack = None
537         self.heat_client = heat_utils.heat_client(self.os_creds)
538         self.cinder = cinder_utils.cinder_client(self.os_creds)
539
540     def tearDown(self):
541         """
542         Cleans the stack
543         """
544         if self.stack:
545             try:
546                 heat_utils.delete_stack(self.heat_client, self.stack)
547             except:
548                 pass
549
550     def test_create_vol_with_stack(self):
551         """
552         Tests the creation of an OpenStack volume with Heat.
553         """
554         self.stack = heat_utils.create_stack(
555             self.heat_client, self.stack_settings)
556         self.assertTrue(stack_active(self.heat_client, self.stack))
557
558         volumes = heat_utils.get_stack_volumes(
559             self.heat_client, self.cinder, self.stack)
560
561         self.assertEqual(1, len(volumes))
562
563         volume = volumes[0]
564         self.assertEqual(self.volume_name, volume.name)
565         self.assertEqual(self.volume_type_name, volume.type)
566         self.assertEqual(1, volume.size)
567         self.assertEqual(False, volume.multi_attach)
568
569     def test_create_vol_types_with_stack(self):
570         """
571         Tests the creation of an OpenStack volume with Heat.
572         """
573         self.stack = heat_utils.create_stack(
574             self.heat_client, self.stack_settings)
575         self.assertTrue(stack_active(self.heat_client, self.stack))
576
577         volume_types = heat_utils.get_stack_volume_types(
578             self.heat_client, self.cinder, self.stack)
579
580         self.assertEqual(1, len(volume_types))
581
582         volume_type = volume_types[0]
583
584         self.assertEqual(self.volume_type_name, volume_type.name)
585         self.assertTrue(volume_type.public)
586         self.assertIsNone(volume_type.qos_spec)
587
588         # TODO - Add encryption back and find out why it broke in Pike
589         # encryption = volume_type.encryption
590         # self.assertIsNotNone(encryption)
591         # self.assertIsNone(encryption.cipher)
592         # self.assertEqual('front-end', encryption.control_location)
593         # self.assertIsNone(encryption.key_size)
594         # self.assertEqual(u'nova.volume.encryptors.luks.LuksEncryptor',
595         #                  encryption.provider)
596         # self.assertEqual(volume_type.id, encryption.volume_type_id)
597
598
599 class HeatUtilsFlavorTests(OSComponentTestCase):
600     """
601     Test Heat volume functionality
602     """
603
604     def setUp(self):
605         """
606         Instantiates OpenStack instances that cannot be spawned by Heat
607         """
608         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
609         self.name_prefix = guid
610         stack_name = guid + '-stack'
611
612         heat_tmplt_path = pkg_resources.resource_filename(
613             'snaps.openstack.tests.heat', 'flavor_heat_template.yaml')
614         self.stack_settings = StackConfig(
615             name=stack_name, template_path=heat_tmplt_path)
616         self.stack = None
617         self.heat_client = heat_utils.heat_client(self.os_creds)
618         self.nova = nova_utils.nova_client(self.os_creds)
619
620     def tearDown(self):
621         """
622         Cleans the stack
623         """
624         if self.stack:
625             try:
626                 heat_utils.delete_stack(self.heat_client, self.stack)
627             except:
628                 pass
629
630     def test_create_flavor_with_stack(self):
631         """
632         Tests the creation of an OpenStack volume with Heat.
633         """
634         self.stack = heat_utils.create_stack(
635             self.heat_client, self.stack_settings)
636
637         self.assertTrue(stack_active(self.heat_client, self.stack))
638
639         flavors = heat_utils.get_stack_flavors(
640             self.heat_client, self.nova, self.stack)
641
642         self.assertEqual(1, len(flavors))
643
644         flavor = flavors[0]
645         self.assertTrue(flavor.name.startswith(self.name_prefix))
646         self.assertEqual(1024, flavor.ram)
647         self.assertEqual(200, flavor.disk)
648         self.assertEqual(8, flavor.vcpus)
649         self.assertEqual(0, flavor.ephemeral)
650         self.assertIsNone(flavor.swap)
651         self.assertEqual(1.0, flavor.rxtx_factor)
652         self.assertTrue(flavor.is_public)
653
654
655 class HeatUtilsKeypairTests(OSComponentTestCase):
656     """
657     Test Heat volume functionality
658     """
659
660     def setUp(self):
661         """
662         Instantiates OpenStack instances that cannot be spawned by Heat
663         """
664         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
665         stack_name = guid + '-stack'
666         self.keypair_name = guid + '-kp'
667
668         env_values = {'keypair_name': self.keypair_name}
669
670         heat_tmplt_path = pkg_resources.resource_filename(
671             'snaps.openstack.tests.heat', 'keypair_heat_template.yaml')
672         self.stack_settings = StackConfig(
673             name=stack_name, template_path=heat_tmplt_path,
674             env_values=env_values)
675         self.stack = None
676         self.heat_client = heat_utils.heat_client(self.os_creds)
677         self.nova = nova_utils.nova_client(self.os_creds)
678
679     def tearDown(self):
680         """
681         Cleans the stack
682         """
683         if self.stack:
684             try:
685                 heat_utils.delete_stack(self.heat_client, self.stack)
686             except:
687                 pass
688
689     def test_create_keypair_with_stack(self):
690         """
691         Tests the creation of an OpenStack keypair with Heat.
692         """
693         self.stack = heat_utils.create_stack(
694             self.heat_client, self.stack_settings)
695         self.assertTrue(stack_active(self.heat_client, self.stack))
696
697         keypairs = heat_utils.get_stack_keypairs(
698             self.heat_client, self.nova, self.stack)
699
700         self.assertEqual(1, len(keypairs))
701         keypair = keypairs[0]
702
703         self.assertEqual(self.keypair_name, keypair.name)
704
705         outputs = heat_utils.get_outputs(self.heat_client, self.stack)
706
707         for output in outputs:
708             if output.key == 'private_key':
709                 self.assertTrue(output.value.startswith(
710                     '-----BEGIN RSA PRIVATE KEY-----'))
711
712         keypair = nova_utils.get_keypair_by_id(self.nova, keypair.id)
713         self.assertIsNotNone(keypair)
714
715         self.assertEqual(self.keypair_name, keypair.name)
716
717
718 class HeatUtilsSecurityGroupTests(OSComponentTestCase):
719     """
720     Test Heat volume functionality
721     """
722
723     def setUp(self):
724         """
725         Instantiates OpenStack instances that cannot be spawned by Heat
726         """
727         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
728         stack_name = guid + '-stack'
729         self.sec_grp_name = guid + '-sec-grp'
730
731         env_values = {'security_group_name': self.sec_grp_name}
732
733         heat_tmplt_path = pkg_resources.resource_filename(
734             'snaps.openstack.tests.heat', 'security_group_heat_template.yaml')
735         self.stack_settings = StackConfig(
736             name=stack_name, template_path=heat_tmplt_path,
737             env_values=env_values)
738         self.stack = None
739         self.heat_client = heat_utils.heat_client(self.os_creds)
740         self.neutron = neutron_utils.neutron_client(self.os_creds)
741
742     def tearDown(self):
743         """
744         Cleans the stack
745         """
746         if self.stack:
747             try:
748                 heat_utils.delete_stack(self.heat_client, self.stack)
749             except:
750                 pass
751
752     def test_create_security_group_with_stack(self):
753         """
754         Tests the creation of an OpenStack SecurityGroup with Heat.
755         """
756         self.stack = heat_utils.create_stack(
757             self.heat_client, self.stack_settings)
758         self.assertTrue(stack_active(self.heat_client, self.stack))
759
760         sec_grp = heat_utils.get_stack_security_groups(
761             self.heat_client, self.neutron, self.stack)[0]
762
763         self.assertEqual(self.sec_grp_name, sec_grp.name)
764         self.assertEqual('Test description', sec_grp.description)
765         self.assertEqual(2, len(sec_grp.rules))
766
767         has_ssh_rule = False
768         has_icmp_rule = False
769
770         for rule in sec_grp.rules:
771             if (rule.security_group_id == sec_grp.id
772                     and rule.direction == 'egress'
773                     and rule.ethertype == 'IPv4'
774                     and rule.port_range_min == 22
775                     and rule.port_range_max == 22
776                     and rule.protocol == 'tcp'
777                     and rule.remote_group_id is None
778                     and rule.remote_ip_prefix == '0.0.0.0/0'):
779                 has_ssh_rule = True
780             if (rule.security_group_id == sec_grp.id
781                     and rule.direction == 'ingress'
782                     and rule.ethertype == 'IPv4'
783                     and rule.port_range_min is None
784                     and rule.port_range_max is None
785                     and rule.protocol == 'icmp'
786                     and rule.remote_group_id is None
787                     and rule.remote_ip_prefix == '0.0.0.0/0'):
788                 has_icmp_rule = True
789
790         self.assertTrue(has_ssh_rule)
791         self.assertTrue(has_icmp_rule)
792
793
794 def stack_active(heat_cli, stack):
795     """
796     Blocks until stack application has successfully completed or failed
797     :param heat_cli: the Heat client
798     :param stack: the Stack domain object
799     :return: T/F
800     """
801     # Wait until stack deployment has completed
802     end_time = time.time() + stack_config.STACK_COMPLETE_TIMEOUT
803     is_active = False
804     while time.time() < end_time:
805         status = heat_utils.get_stack_status(heat_cli, stack.id)
806         if status == stack_config.STATUS_CREATE_COMPLETE:
807             is_active = True
808             break
809         elif status == stack_config.STATUS_CREATE_FAILED:
810             is_active = False
811             break
812
813         time.sleep(3)
814
815     return is_active