Closing keystone sessions after done with them.
[snaps.git] / snaps / openstack / tests / create_stack_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 os
16 import time
17
18 import pkg_resources
19 from heatclient.exc import HTTPBadRequest
20
21 import snaps
22 from snaps import file_utils
23 from snaps.config.flavor import FlavorConfig
24 from snaps.config.image import ImageConfig
25 from snaps.config.stack import StackConfigError, StackConfig
26 from snaps.openstack.create_flavor import OpenStackFlavor
27 from snaps.openstack.create_image import OpenStackImage
28
29 try:
30     from urllib.request import URLError
31 except ImportError:
32     from urllib2 import URLError
33
34 import logging
35 import unittest
36 import uuid
37
38 from snaps.openstack.create_stack import (
39     StackSettings, StackCreationError, StackError, OpenStackHeatStack)
40 from snaps.openstack.tests import openstack_tests, create_instance_tests
41 from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase
42 from snaps.openstack.utils import (
43     heat_utils, neutron_utils, nova_utils, keystone_utils)
44
45 __author__ = 'spisarski'
46
47 logger = logging.getLogger('create_stack_tests')
48
49
50 class StackSettingsUnitTests(unittest.TestCase):
51     """
52     Tests the construction of the StackSettings class
53     """
54
55     def test_no_params(self):
56         with self.assertRaises(StackConfigError):
57             StackSettings()
58
59     def test_empty_config(self):
60         with self.assertRaises(StackConfigError):
61             StackSettings(**dict())
62
63     def test_name_only(self):
64         with self.assertRaises(StackConfigError):
65             StackSettings(name='foo')
66
67     def test_config_with_name_only(self):
68         with self.assertRaises(StackConfigError):
69             StackSettings(**{'name': 'foo'})
70
71     def test_config_minimum_template(self):
72         settings = StackSettings(**{'name': 'stack', 'template': 'foo'})
73         self.assertEqual('stack', settings.name)
74         self.assertEqual('foo', settings.template)
75         self.assertIsNone(settings.template_path)
76         self.assertIsNone(settings.env_values)
77         self.assertEqual(snaps.config.stack.STACK_COMPLETE_TIMEOUT,
78                          settings.stack_create_timeout)
79
80     def test_config_minimum_template_path(self):
81         settings = StackSettings(**{'name': 'stack', 'template_path': 'foo'})
82         self.assertEqual('stack', settings.name)
83         self.assertIsNone(settings.template)
84         self.assertEqual('foo', settings.template_path)
85         self.assertIsNone(settings.env_values)
86         self.assertEqual(snaps.config.stack.STACK_COMPLETE_TIMEOUT,
87                          settings.stack_create_timeout)
88
89     def test_minimum_template(self):
90         settings = StackSettings(name='stack', template='foo')
91         self.assertEqual('stack', settings.name)
92         self.assertEqual('foo', settings.template)
93         self.assertIsNone(settings.template_path)
94         self.assertIsNone(settings.env_values)
95         self.assertEqual(snaps.config.stack.STACK_COMPLETE_TIMEOUT,
96                          settings.stack_create_timeout)
97
98     def test_minimum_template_path(self):
99         settings = StackSettings(name='stack', template_path='foo')
100         self.assertEqual('stack', settings.name)
101         self.assertEqual('foo', settings.template_path)
102         self.assertIsNone(settings.template)
103         self.assertIsNone(settings.env_values)
104         self.assertEqual(snaps.config.stack.STACK_COMPLETE_TIMEOUT,
105                          settings.stack_create_timeout)
106
107     def test_all(self):
108         env_values = {'foo': 'bar'}
109         settings = StackSettings(name='stack', template='bar',
110                                  template_path='foo', env_values=env_values,
111                                  stack_create_timeout=999)
112         self.assertEqual('stack', settings.name)
113         self.assertEqual('bar', settings.template)
114         self.assertEqual('foo', settings.template_path)
115         self.assertEqual(env_values, settings.env_values)
116         self.assertEqual(999, settings.stack_create_timeout)
117
118     def test_config_all(self):
119         env_values = {'foo': 'bar'}
120         settings = StackSettings(
121             **{'name': 'stack', 'template': 'bar', 'template_path': 'foo',
122                'env_values': env_values, 'stack_create_timeout': 999})
123         self.assertEqual('stack', settings.name)
124         self.assertEqual('bar', settings.template)
125         self.assertEqual('foo', settings.template_path)
126         self.assertEqual(env_values, settings.env_values)
127         self.assertEqual(999, settings.stack_create_timeout)
128
129
130 class CreateStackSuccessTests(OSIntegrationTestCase):
131     """
132     Tests for the OpenStackHeatStack class defined in create_stack.py
133     """
134
135     def setUp(self):
136         self.user_roles = ['heat_stack_owner']
137
138         super(self.__class__, self).__start__()
139
140         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
141
142         self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
143         self.stack_creator = None
144
145         self.image_creator = OpenStackImage(
146             self.os_creds, openstack_tests.cirros_image_settings(
147                 name=self.guid + '-image',
148                 image_metadata=self.image_metadata))
149         self.image_creator.create()
150
151         # Create Flavor
152         self.flavor_creator = OpenStackFlavor(
153             self.admin_os_creds,
154             FlavorConfig(
155                 name=self.guid + '-flavor-name', ram=256, disk=10, vcpus=1))
156         self.flavor_creator.create()
157
158         self.network_name = self.guid + '-net'
159         self.subnet_name = self.guid + '-subnet'
160         self.vm_inst_name = self.guid + '-inst'
161
162         self.env_values = {
163             'image_name': self.image_creator.image_settings.name,
164             'flavor_name': self.flavor_creator.flavor_settings.name,
165             'net_name': self.network_name,
166             'subnet_name': self.subnet_name,
167             'inst_name': self.vm_inst_name}
168
169         self.heat_tmplt_path = pkg_resources.resource_filename(
170             'snaps.openstack.tests.heat', 'test_heat_template.yaml')
171
172     def tearDown(self):
173         """
174         Cleans the stack and downloaded stack file
175         """
176         if self.stack_creator:
177             try:
178                 self.stack_creator.clean()
179             except:
180                 pass
181
182         if self.image_creator:
183             try:
184                 self.image_creator.clean()
185             except:
186                 pass
187
188         if self.flavor_creator:
189             try:
190                 self.flavor_creator.clean()
191             except:
192                 pass
193
194         super(self.__class__, self).__clean__()
195
196     def test_create_stack_template_file(self):
197         """
198         Tests the creation of an OpenStack stack from Heat template file.
199         """
200         # Create Stack
201         # Set the default stack settings, then set any custom parameters sent
202         # from the app
203         stack_settings = StackConfig(
204             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
205             template_path=self.heat_tmplt_path,
206             env_values=self.env_values)
207         self.stack_creator = OpenStackHeatStack(
208             self.os_creds, stack_settings)
209         created_stack = self.stack_creator.create()
210         self.assertIsNotNone(created_stack)
211
212         retrieved_stack = heat_utils.get_stack_by_id(self.heat_cli,
213                                                      created_stack.id)
214         self.assertIsNotNone(retrieved_stack)
215         self.assertEqual(created_stack.name, retrieved_stack.name)
216         self.assertEqual(created_stack.id, retrieved_stack.id)
217         self.assertEqual(0, len(self.stack_creator.get_outputs()))
218
219     def test_create_stack_short_timeout(self):
220         """
221         Tests the creation of an OpenStack stack from Heat template file.
222         """
223         # Create Stack
224         # Set the default stack settings, then set any custom parameters sent
225         # from the app
226         stack_settings = StackConfig(
227             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
228             template_path=self.heat_tmplt_path,
229             env_values=self.env_values, stack_create_timeout=0)
230
231         self.stack_creator = OpenStackHeatStack(
232             self.os_creds, stack_settings)
233         with self.assertRaises(StackCreationError):
234             self.stack_creator.create()
235
236     def test_create_stack_template_dict(self):
237         """
238         Tests the creation of an OpenStack stack from a heat dict() object.
239         """
240         # Create Stack
241         # Set the default stack settings, then set any custom parameters sent
242         # from the app
243         template_dict = heat_utils.parse_heat_template_str(
244             file_utils.read_file(self.heat_tmplt_path))
245         stack_settings = StackConfig(
246             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
247             template=template_dict,
248             env_values=self.env_values)
249         self.stack_creator = OpenStackHeatStack(
250             self.os_creds, stack_settings)
251         created_stack = self.stack_creator.create()
252         self.assertIsNotNone(created_stack)
253
254         retrieved_stack = heat_utils.get_stack_by_id(self.heat_cli,
255                                                      created_stack.id)
256         self.assertIsNotNone(retrieved_stack)
257         self.assertEqual(created_stack.name, retrieved_stack.name)
258         self.assertEqual(created_stack.id, retrieved_stack.id)
259         self.assertEqual(0, len(self.stack_creator.get_outputs()))
260
261     def test_create_delete_stack(self):
262         """
263         Tests the creation then deletion of an OpenStack stack to ensure
264         clean() does not raise an Exception.
265         """
266         # Create Stack
267         template_dict = heat_utils.parse_heat_template_str(
268             file_utils.read_file(self.heat_tmplt_path))
269         stack_settings = StackConfig(
270             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
271             template=template_dict,
272             env_values=self.env_values)
273         self.stack_creator = OpenStackHeatStack(
274             self.os_creds, stack_settings)
275         created_stack = self.stack_creator.create()
276         self.assertIsNotNone(created_stack)
277
278         retrieved_stack = heat_utils.get_stack_by_id(self.heat_cli,
279                                                      created_stack.id)
280         self.assertIsNotNone(retrieved_stack)
281         self.assertEqual(created_stack.name, retrieved_stack.name)
282         self.assertEqual(created_stack.id, retrieved_stack.id)
283         self.assertEqual(0, len(self.stack_creator.get_outputs()))
284         self.assertEqual(snaps.config.stack.STATUS_CREATE_COMPLETE,
285                          self.stack_creator.get_status())
286
287         # Delete Stack manually
288         heat_utils.delete_stack(self.heat_cli, created_stack)
289
290         end_time = time.time() + 90
291         deleted = False
292         while time.time() < end_time:
293             status = heat_utils.get_stack_status(self.heat_cli,
294                                                  retrieved_stack.id)
295             if status == snaps.config.stack.STATUS_DELETE_COMPLETE:
296                 deleted = True
297                 break
298
299         self.assertTrue(deleted)
300
301         # Must not throw an exception when attempting to cleanup non-existent
302         # stack
303         self.stack_creator.clean()
304         self.assertIsNone(self.stack_creator.get_stack())
305
306     def test_create_same_stack(self):
307         """
308         Tests the creation of an OpenStack stack when the stack already exists.
309         """
310         # Create Stack
311         template_dict = heat_utils.parse_heat_template_str(
312             file_utils.read_file(self.heat_tmplt_path))
313         stack_settings = StackConfig(
314             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
315             template=template_dict,
316             env_values=self.env_values)
317         self.stack_creator = OpenStackHeatStack(
318             self.os_creds, stack_settings)
319         created_stack1 = self.stack_creator.create()
320
321         retrieved_stack = heat_utils.get_stack_by_id(self.heat_cli,
322                                                      created_stack1.id)
323         self.assertIsNotNone(retrieved_stack)
324         self.assertEqual(created_stack1.name, retrieved_stack.name)
325         self.assertEqual(created_stack1.id, retrieved_stack.id)
326         self.assertEqual(0, len(self.stack_creator.get_outputs()))
327
328         # Should be retrieving the instance data
329         stack_creator2 = OpenStackHeatStack(self.os_creds, stack_settings)
330         stack2 = stack_creator2.create()
331         self.assertEqual(created_stack1.id, stack2.id)
332
333     def test_retrieve_network_creators(self):
334         """
335         Tests the creation of an OpenStack stack from Heat template file and
336         the retrieval of the network creator.
337         """
338         stack_settings = StackConfig(
339             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
340             template_path=self.heat_tmplt_path,
341             env_values=self.env_values)
342         self.stack_creator = OpenStackHeatStack(
343             self.os_creds, stack_settings)
344         created_stack = self.stack_creator.create()
345         self.assertIsNotNone(created_stack)
346
347         net_creators = self.stack_creator.get_network_creators()
348         self.assertIsNotNone(net_creators)
349         self.assertEqual(1, len(net_creators))
350         self.assertEqual(self.network_name, net_creators[0].get_network().name)
351
352         # Need to use 'admin' creds as heat creates objects under it's own
353         # project/tenant
354         neutron = neutron_utils.neutron_client(
355             self.os_creds, self.os_session)
356         keystone = keystone_utils.keystone_client(
357             self.os_creds, self.os_session)
358         net_by_name = neutron_utils.get_network(
359             neutron, keystone, network_name=net_creators[0].get_network().name)
360         self.assertEqual(net_creators[0].get_network(), net_by_name)
361         self.assertIsNotNone(neutron_utils.get_network_by_id(
362             neutron, net_creators[0].get_network().id))
363
364         self.assertEqual(1, len(net_creators[0].get_network().subnets))
365         subnet = net_creators[0].get_network().subnets[0]
366         subnet_by_name = neutron_utils.get_subnet(
367             neutron, subnet_name=subnet.name)
368         self.assertEqual(subnet, subnet_by_name)
369
370         subnet_by_id = neutron_utils.get_subnet_by_id(neutron, subnet.id)
371         self.assertIsNotNone(subnet_by_id)
372         self.assertEqual(subnet_by_name, subnet_by_id)
373
374     def test_retrieve_vm_inst_creators(self):
375         """
376         Tests the creation of an OpenStack stack from Heat template file and
377         the retrieval of the network creator.
378         """
379         stack_settings = StackConfig(
380             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
381             template_path=self.heat_tmplt_path,
382             env_values=self.env_values)
383         self.stack_creator = OpenStackHeatStack(
384             self.os_creds, stack_settings)
385         created_stack = self.stack_creator.create()
386         self.assertIsNotNone(created_stack)
387
388         vm_inst_creators = self.stack_creator.get_vm_inst_creators()
389         self.assertIsNotNone(vm_inst_creators)
390         self.assertEqual(1, len(vm_inst_creators))
391         self.assertEqual(self.vm_inst_name,
392                          vm_inst_creators[0].get_vm_inst().name)
393
394         nova = nova_utils.nova_client(self.os_creds, self.os_session)
395         neutron = neutron_utils.neutron_client(self.os_creds, self.os_session)
396         keystone = keystone_utils.keystone_client(self.os_creds, self.os_session)
397         vm_inst_by_name = nova_utils.get_server(
398             nova, neutron, keystone,
399             server_name=vm_inst_creators[0].get_vm_inst().name)
400
401         self.assertEqual(vm_inst_creators[0].get_vm_inst(), vm_inst_by_name)
402         self.assertIsNotNone(nova_utils.get_server_object_by_id(
403             nova, neutron, keystone, vm_inst_creators[0].get_vm_inst().id))
404
405
406 class CreateStackFloatingIpTests(OSIntegrationTestCase):
407     """
408     Tests to ensure that floating IPs can be accessed via an
409     OpenStackVmInstance object obtained from the OpenStackHeatStack instance
410     """
411
412     def setUp(self):
413         self.user_roles = ['heat_stack_owner', 'admin']
414
415         super(self.__class__, self).__start__()
416
417         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
418
419         self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
420         self.stack_creator = None
421
422         self.image_creator = OpenStackImage(
423             self.os_creds, openstack_tests.cirros_image_settings(
424                 name=self.guid + '-image',
425                 image_metadata=self.image_metadata))
426         self.image_creator.create()
427
428         self.network_name = self.guid + '-net'
429         self.subnet_name = self.guid + '-subnet'
430         self.flavor1_name = self.guid + '-flavor1'
431         self.flavor2_name = self.guid + '-flavor2'
432         self.sec_grp_name = self.guid + '-sec_grp'
433         self.vm_inst1_name = self.guid + '-inst1'
434         self.vm_inst2_name = self.guid + '-inst2'
435         self.keypair_name = self.guid + '-kp'
436
437         self.env_values = {
438             'image1_name': self.image_creator.image_settings.name,
439             'image2_name': self.image_creator.image_settings.name,
440             'flavor1_name': self.flavor1_name,
441             'flavor2_name': self.flavor2_name,
442             'net_name': self.network_name,
443             'subnet_name': self.subnet_name,
444             'inst1_name': self.vm_inst1_name,
445             'inst2_name': self.vm_inst2_name,
446             'keypair_name': self.keypair_name,
447             'external_net_name': self.ext_net_name,
448             'security_group_name': self.sec_grp_name}
449
450         self.heat_tmplt_path = pkg_resources.resource_filename(
451             'snaps.openstack.tests.heat', 'floating_ip_heat_template.yaml')
452
453         self.vm_inst_creators = list()
454
455     def tearDown(self):
456         """
457         Cleans the stack and downloaded stack file
458         """
459         if self.stack_creator:
460             try:
461                 self.stack_creator.clean()
462             except:
463                 pass
464
465         if self.image_creator:
466             try:
467                 self.image_creator.clean()
468             except:
469                 pass
470
471         for vm_inst_creator in self.vm_inst_creators:
472             try:
473                 keypair_settings = vm_inst_creator.keypair_settings
474                 if keypair_settings and keypair_settings.private_filepath:
475                     expanded_path = os.path.expanduser(
476                         keypair_settings.private_filepath)
477                     os.chmod(expanded_path, 0o755)
478                     os.remove(expanded_path)
479             except:
480                 pass
481
482         super(self.__class__, self).__clean__()
483
484     def test_connect_via_ssh_heat_vm(self):
485         """
486         Tests the creation of an OpenStack stack from Heat template file and
487         the retrieval of two VM instance creators and attempt to connect via
488         SSH to the first one with a floating IP.
489         """
490         stack_settings = StackConfig(
491             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
492             template_path=self.heat_tmplt_path,
493             env_values=self.env_values)
494         self.stack_creator = OpenStackHeatStack(
495             self.os_creds, stack_settings,
496             [self.image_creator.image_settings])
497         created_stack = self.stack_creator.create()
498         self.assertIsNotNone(created_stack)
499
500         self.vm_inst_creators = self.stack_creator.get_vm_inst_creators(
501             heat_keypair_option='private_key')
502         self.assertIsNotNone(self.vm_inst_creators)
503         self.assertEqual(2, len(self.vm_inst_creators))
504
505         for vm_inst_creator in self.vm_inst_creators:
506             if vm_inst_creator.get_vm_inst().name == self.vm_inst1_name:
507                 self.assertTrue(
508                     create_instance_tests.validate_ssh_client(vm_inst_creator))
509             else:
510                 vm_settings = vm_inst_creator.instance_settings
511                 self.assertEqual(0, len(vm_settings.floating_ip_settings))
512
513
514 class CreateStackNestedResourceTests(OSIntegrationTestCase):
515     """
516     Tests to ensure that nested heat templates work
517     """
518
519     def setUp(self):
520         self.user_roles = ['heat_stack_owner']
521
522         super(self.__class__, self).__start__()
523
524         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
525
526         self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
527         self.stack_creator = None
528
529         self.image_creator = OpenStackImage(
530             self.os_creds, openstack_tests.cirros_image_settings(
531                 name=self.guid + '-image',
532                 image_metadata=self.image_metadata))
533         self.image_creator.create()
534
535         self.flavor_creator = OpenStackFlavor(
536             self.admin_os_creds,
537             FlavorConfig(
538                 name=self.guid + '-flavor-name', ram=256, disk=10, vcpus=1))
539         self.flavor_creator.create()
540
541         env_values = {
542             'network_name': self.guid + '-network',
543             'public_network': self.ext_net_name,
544             'agent_image': self.image_creator.image_settings.name,
545             'agent_flavor': self.flavor_creator.flavor_settings.name,
546             'key_name': self.guid + '-key',
547         }
548
549         heat_tmplt_path = pkg_resources.resource_filename(
550             'snaps.openstack.tests.heat', 'agent-group.yaml')
551         heat_resource_path = pkg_resources.resource_filename(
552             'snaps.openstack.tests.heat', 'agent.yaml')
553
554         stack_settings = StackConfig(
555             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
556             template_path=heat_tmplt_path,
557             resource_files=[heat_resource_path],
558             env_values=env_values)
559
560         self.stack_creator = OpenStackHeatStack(
561             self.os_creds, stack_settings,
562             [self.image_creator.image_settings])
563
564         self.vm_inst_creators = list()
565
566     def tearDown(self):
567         """
568         Cleans the stack and downloaded stack file
569         """
570         if self.stack_creator:
571             try:
572                 self.stack_creator.clean()
573             except:
574                 pass
575
576         if self.image_creator:
577             try:
578                 self.image_creator.clean()
579             except:
580                 pass
581
582         if self.flavor_creator:
583             try:
584                 self.flavor_creator.clean()
585             except:
586                 pass
587
588         for vm_inst_creator in self.vm_inst_creators:
589             try:
590                 keypair_settings = vm_inst_creator.keypair_settings
591                 if keypair_settings and keypair_settings.private_filepath:
592                     expanded_path = os.path.expanduser(
593                         keypair_settings.private_filepath)
594                     os.chmod(expanded_path, 0o755)
595                     os.remove(expanded_path)
596             except:
597                 pass
598
599         super(self.__class__, self).__clean__()
600
601     def test_nested(self):
602         """
603         Tests the creation of an OpenStack stack from Heat template file and
604         the retrieval of two VM instance creators and attempt to connect via
605         SSH to the first one with a floating IP.
606         """
607         created_stack = self.stack_creator.create()
608         self.assertIsNotNone(created_stack)
609
610         self.vm_inst_creators = self.stack_creator.get_vm_inst_creators(
611             heat_keypair_option='private_key')
612         self.assertIsNotNone(self.vm_inst_creators)
613         self.assertEqual(1, len(self.vm_inst_creators))
614
615         for vm_inst_creator in self.vm_inst_creators:
616             self.assertTrue(
617                 create_instance_tests.validate_ssh_client(vm_inst_creator))
618
619
620 class CreateStackRouterTests(OSIntegrationTestCase):
621     """
622     Tests for the CreateStack class defined in create_stack.py where the
623     target is a Network, Subnet, and Router
624     """
625
626     def setUp(self):
627         """
628         Instantiates the CreateStack object that is responsible for downloading
629         and creating an OS stack file within OpenStack
630         """
631         self.user_roles = ['heat_stack_owner']
632
633         super(self.__class__, self).__start__()
634
635         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
636
637         self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
638         self.neutron = neutron_utils.neutron_client(
639             self.os_creds, self.os_session)
640         self.stack_creator = None
641
642         self.net_name = self.guid + '-net'
643         self.subnet_name = self.guid + '-subnet'
644         self.router_name = self.guid + '-router'
645
646         self.env_values = {
647             'net_name': self.net_name,
648             'subnet_name': self.subnet_name,
649             'router_name': self.router_name,
650             'external_net_name': self.ext_net_name}
651
652         self.heat_tmplt_path = pkg_resources.resource_filename(
653             'snaps.openstack.tests.heat', 'router_heat_template.yaml')
654
655         stack_settings = StackConfig(
656             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
657             template_path=self.heat_tmplt_path,
658             env_values=self.env_values)
659         self.stack_creator = OpenStackHeatStack(
660             self.os_creds, stack_settings)
661         self.created_stack = self.stack_creator.create()
662         self.assertIsNotNone(self.created_stack)
663
664     def tearDown(self):
665         """
666         Cleans the stack and downloaded stack file
667         """
668         if self.stack_creator:
669             try:
670                 self.stack_creator.clean()
671             except:
672                 pass
673
674         super(self.__class__, self).__clean__()
675
676     def test_retrieve_router_creator(self):
677         """
678         Tests the creation of an OpenStack stack from Heat template file and
679         the retrieval of an OpenStackRouter creator/state machine instance
680         """
681         router_creators = self.stack_creator.get_router_creators()
682         self.assertEqual(1, len(router_creators))
683
684         creator = router_creators[0]
685         self.assertEqual(self.router_name, creator.router_settings.name)
686
687         router = creator.get_router()
688
689         ext_net = neutron_utils.get_network(
690             self.neutron, self.keystone, network_name=self.ext_net_name)
691         self.assertEqual(ext_net.id, router.external_network_id)
692
693
694 class CreateStackVolumeTests(OSIntegrationTestCase):
695     """
696     Tests to ensure that floating IPs can be accessed via an
697     OpenStackVolume object obtained from the OpenStackHeatStack instance
698     """
699
700     def setUp(self):
701
702         self.user_roles = ['heat_stack_owner', 'admin']
703
704         super(self.__class__, self).__start__()
705
706         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
707
708         self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
709         self.stack_creator = None
710
711         self.volume_name = self.guid + '-volume'
712         self.volume_type_name = self.guid + '-volume-type'
713
714         self.env_values = {
715             'volume_name': self.volume_name,
716             'volume_type_name': self.volume_type_name}
717
718         self.heat_tmplt_path = pkg_resources.resource_filename(
719             'snaps.openstack.tests.heat', 'volume_heat_template.yaml')
720
721         stack_settings = StackConfig(
722             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
723             template_path=self.heat_tmplt_path,
724             env_values=self.env_values)
725         self.stack_creator = OpenStackHeatStack(
726             self.os_creds, stack_settings)
727         self.created_stack = self.stack_creator.create()
728         self.assertIsNotNone(self.created_stack)
729
730     def tearDown(self):
731         """
732         Cleans the stack and downloaded stack file
733         """
734         if self.stack_creator:
735             try:
736                 self.stack_creator.clean()
737             except:
738                 pass
739
740         super(self.__class__, self).__clean__()
741
742     def test_retrieve_volume_creator(self):
743         """
744         Tests the creation of an OpenStack stack from Heat template file and
745         the retrieval of an OpenStackVolume creator/state machine instance
746         """
747         volume_creators = self.stack_creator.get_volume_creators()
748         self.assertEqual(1, len(volume_creators))
749
750         creator = volume_creators[0]
751         self.assertEqual(self.volume_name, creator.volume_settings.name)
752         self.assertEqual(self.volume_name, creator.get_volume().name)
753         self.assertEqual(self.volume_type_name,
754                          creator.volume_settings.type_name)
755         self.assertEqual(self.volume_type_name, creator.get_volume().type)
756         self.assertEqual(1, creator.volume_settings.size)
757         self.assertEqual(1, creator.get_volume().size)
758
759     def test_retrieve_volume_type_creator(self):
760         """
761         Tests the creation of an OpenStack stack from Heat template file and
762         the retrieval of an OpenStackVolume creator/state machine instance
763         """
764         volume_type_creators = self.stack_creator.get_volume_type_creators()
765         self.assertEqual(1, len(volume_type_creators))
766
767         creator = volume_type_creators[0]
768         self.assertIsNotNone(creator)
769
770         volume_type = creator.get_volume_type()
771         self.assertIsNotNone(volume_type)
772
773         self.assertEqual(self.volume_type_name, volume_type.name)
774         self.assertTrue(volume_type.public)
775         self.assertIsNone(volume_type.qos_spec)
776
777         # TODO - Add encryption back and find out why it broke in Pike
778         # encryption = volume_type.encryption
779         # self.assertIsNotNone(encryption)
780         # self.assertIsNone(encryption.cipher)
781         # self.assertEqual('front-end', encryption.control_location)
782         # self.assertIsNone(encryption.key_size)
783         # self.assertEqual(u'nova.volume.encryptors.luks.LuksEncryptor',
784         #                  encryption.provider)
785         # self.assertEqual(volume_type.id, encryption.volume_type_id)
786
787
788 class CreateStackFlavorTests(OSIntegrationTestCase):
789     """
790     Tests to ensure that floating IPs can be accessed via an
791     OpenStackFlavor object obtained from the OpenStackHeatStack instance
792     """
793
794     def setUp(self):
795
796         self.user_roles = ['heat_stack_owner', 'admin']
797
798         super(self.__class__, self).__start__()
799
800         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
801
802         self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
803         self.stack_creator = None
804
805         self.heat_tmplt_path = pkg_resources.resource_filename(
806             'snaps.openstack.tests.heat', 'flavor_heat_template.yaml')
807
808         stack_settings = StackConfig(
809             name=self.guid + '-stack',
810             template_path=self.heat_tmplt_path)
811         self.stack_creator = OpenStackHeatStack(
812             self.os_creds, stack_settings)
813         self.created_stack = self.stack_creator.create()
814         self.assertIsNotNone(self.created_stack)
815
816     def tearDown(self):
817         """
818         Cleans the stack and downloaded stack file
819         """
820         if self.stack_creator:
821             try:
822                 self.stack_creator.clean()
823             except:
824                 pass
825
826         super(self.__class__, self).__clean__()
827
828     def test_retrieve_flavor_creator(self):
829         """
830         Tests the creation of an OpenStack stack from Heat template file and
831         the retrieval of an OpenStackVolume creator/state machine instance
832         """
833         flavor_creators = self.stack_creator.get_flavor_creators()
834         self.assertEqual(1, len(flavor_creators))
835
836         creator = flavor_creators[0]
837         self.assertTrue(creator.get_flavor().name.startswith(self.guid))
838         self.assertEqual(1024, creator.get_flavor().ram)
839         self.assertEqual(200, creator.get_flavor().disk)
840         self.assertEqual(8, creator.get_flavor().vcpus)
841         self.assertEqual(0, creator.get_flavor().ephemeral)
842         self.assertIsNone(creator.get_flavor().swap)
843         self.assertEqual(1.0, creator.get_flavor().rxtx_factor)
844         self.assertTrue(creator.get_flavor().is_public)
845
846
847 class CreateStackKeypairTests(OSIntegrationTestCase):
848     """
849     Tests to ensure that floating IPs can be accessed via an
850     OpenStackKeypair object obtained from the OpenStackHeatStack instance
851     """
852
853     def setUp(self):
854
855         self.user_roles = ['heat_stack_owner']
856
857         super(self.__class__, self).__start__()
858
859         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
860
861         self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
862         self.nova = nova_utils.nova_client(self.os_creds, self.os_session)
863         self.stack_creator = None
864
865         self.keypair_name = self.guid + '-kp'
866
867         self.env_values = {
868             'keypair_name': self.keypair_name}
869
870         self.heat_tmplt_path = pkg_resources.resource_filename(
871             'snaps.openstack.tests.heat', 'keypair_heat_template.yaml')
872
873         stack_settings = StackConfig(
874             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
875             template_path=self.heat_tmplt_path,
876             env_values=self.env_values)
877         self.stack_creator = OpenStackHeatStack(
878             self.os_creds, stack_settings)
879         self.created_stack = self.stack_creator.create()
880         self.assertIsNotNone(self.created_stack)
881
882         self.keypair_creators = list()
883
884     def tearDown(self):
885         """
886         Cleans the stack and downloaded stack file
887         """
888         if self.stack_creator:
889             try:
890                 self.stack_creator.clean()
891             except:
892                 pass
893         for keypair_creator in self.keypair_creators:
894             try:
895                 keypair_creator.clean()
896             except:
897                 pass
898
899         super(self.__class__, self).__clean__()
900
901     def test_retrieve_keypair_creator(self):
902         """
903         Tests the creation of an OpenStack stack from Heat template file and
904         the retrieval of an OpenStackKeypair creator/state machine instance
905         """
906         self.kp_creators = self.stack_creator.get_keypair_creators(
907             'private_key')
908         self.assertEqual(1, len(self.kp_creators))
909
910         self.keypair_creator = self.kp_creators[0]
911
912         self.assertEqual(self.keypair_name,
913                          self.keypair_creator.get_keypair().name)
914         self.assertIsNotNone(
915             self.keypair_creator.keypair_settings.private_filepath)
916
917         private_file_contents = file_utils.read_file(
918             self.keypair_creator.keypair_settings.private_filepath)
919         self.assertTrue(private_file_contents.startswith(
920             '-----BEGIN RSA PRIVATE KEY-----'))
921
922         keypair = nova_utils.get_keypair_by_id(
923             self.nova, self.keypair_creator.get_keypair().id)
924         self.assertIsNotNone(keypair)
925         self.assertEqual(self.keypair_creator.get_keypair(), keypair)
926
927
928 class CreateStackSecurityGroupTests(OSIntegrationTestCase):
929     """
930     Tests for the OpenStackHeatStack class to ensure it returns an
931     OpenStackSecurityGroup object
932     """
933
934     def setUp(self):
935         """
936         Instantiates the CreateStack object that is responsible for downloading
937         and creating an OS stack file within OpenStack
938         """
939         self.user_roles = ['heat_stack_owner']
940
941         super(self.__class__, self).__start__()
942
943         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
944
945         self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
946         self.nova = nova_utils.nova_client(self.os_creds, self.os_session)
947         self.stack_creator = None
948
949         self.security_group_name = self.guid + '-sec-grp'
950
951         self.env_values = {
952             'security_group_name': self.security_group_name}
953
954         self.heat_tmplt_path = pkg_resources.resource_filename(
955             'snaps.openstack.tests.heat', 'security_group_heat_template.yaml')
956
957         stack_settings = StackConfig(
958             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
959             template_path=self.heat_tmplt_path,
960             env_values=self.env_values)
961         self.stack_creator = OpenStackHeatStack(
962             self.os_creds, stack_settings)
963         self.created_stack = self.stack_creator.create()
964         self.assertIsNotNone(self.created_stack)
965
966     def tearDown(self):
967         """
968         Cleans the stack and downloaded stack file
969         """
970         if self.stack_creator:
971             try:
972                 self.stack_creator.clean()
973             except:
974                 pass
975
976         super(self.__class__, self).__clean__()
977
978     def test_retrieve_security_group_creator(self):
979         """
980         Tests the creation of an OpenStack stack from Heat template file and
981         the retrieval of an OpenStackSecurityGroup creator/state machine
982         instance
983         """
984         sec_grp_creators = self.stack_creator.get_security_group_creators()
985         self.assertEqual(1, len(sec_grp_creators))
986
987         creator = sec_grp_creators[0]
988         sec_grp = creator.get_security_group()
989
990         self.assertEqual(self.security_group_name, sec_grp.name)
991         self.assertEqual('Test description', sec_grp.description)
992         self.assertEqual(2, len(sec_grp.rules))
993
994         has_ssh_rule = False
995         has_icmp_rule = False
996
997         for rule in sec_grp.rules:
998             if (rule.security_group_id == sec_grp.id
999                     and rule.direction == 'egress'
1000                     and rule.ethertype == 'IPv4'
1001                     and rule.port_range_min == 22
1002                     and rule.port_range_max == 22
1003                     and rule.protocol == 'tcp'
1004                     and rule.remote_group_id is None
1005                     and rule.remote_ip_prefix == '0.0.0.0/0'):
1006                 has_ssh_rule = True
1007             if (rule.security_group_id == sec_grp.id
1008                     and rule.direction == 'ingress'
1009                     and rule.ethertype == 'IPv4'
1010                     and rule.port_range_min is None
1011                     and rule.port_range_max is None
1012                     and rule.protocol == 'icmp'
1013                     and rule.remote_group_id is None
1014                     and rule.remote_ip_prefix == '0.0.0.0/0'):
1015                 has_icmp_rule = True
1016
1017         self.assertTrue(has_ssh_rule)
1018         self.assertTrue(has_icmp_rule)
1019
1020
1021 class CreateStackNegativeTests(OSIntegrationTestCase):
1022     """
1023     Negative test cases for the OpenStackHeatStack class with poor
1024     configuration
1025     """
1026
1027     def setUp(self):
1028         self.user_roles = ['heat_stack_owner']
1029
1030         super(self.__class__, self).__start__()
1031
1032         self.stack_name = self.__class__.__name__ + '-' + str(uuid.uuid4())
1033         self.stack_creator = None
1034         self.heat_tmplt_path = pkg_resources.resource_filename(
1035             'snaps.openstack.tests.heat', 'test_heat_template.yaml')
1036
1037     def tearDown(self):
1038         if self.stack_creator:
1039             self.stack_creator.clean()
1040
1041         super(self.__class__, self).__clean__()
1042
1043     def test_missing_dependencies(self):
1044         """
1045         Expect an StackCreationError when the stack file does not exist
1046         """
1047         stack_settings = StackConfig(name=self.stack_name,
1048                                      template_path=self.heat_tmplt_path)
1049         self.stack_creator = OpenStackHeatStack(
1050             self.os_creds, stack_settings)
1051         with self.assertRaises(HTTPBadRequest):
1052             self.stack_creator.create()
1053
1054     def test_bad_stack_file(self):
1055         """
1056         Expect an StackCreationError when the stack file does not exist
1057         """
1058         stack_settings = StackConfig(
1059             name=self.stack_name, template_path='foo')
1060         self.stack_creator = OpenStackHeatStack(
1061             self.os_creds, stack_settings)
1062         with self.assertRaises(IOError):
1063             self.stack_creator.create()
1064
1065
1066 class CreateStackFailureTests(OSIntegrationTestCase):
1067     """
1068     Tests for the OpenStackHeatStack class defined in create_stack.py for
1069     when failures occur. Failures are being triggered by allocating 1 million
1070     CPUs.
1071     """
1072
1073     def setUp(self):
1074         self.user_roles = ['heat_stack_owner']
1075
1076         super(self.__class__, self).__start__()
1077
1078         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1079
1080         self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
1081         self.stack_creator = None
1082
1083         self.tmp_file = file_utils.save_string_to_file(
1084             ' ', str(uuid.uuid4()) + '-bad-image')
1085         self.image_creator = OpenStackImage(
1086             self.os_creds, ImageConfig(
1087                 name=self.guid + 'image', image_file=self.tmp_file.name,
1088                 image_user='foo', img_format='qcow2'))
1089         self.image_creator.create()
1090
1091         # Create Flavor
1092         self.flavor_creator = OpenStackFlavor(
1093             self.admin_os_creds,
1094             FlavorConfig(
1095                 name=self.guid + '-flavor-name', ram=256, disk=10,
1096                 vcpus=1000000))
1097         self.flavor_creator.create()
1098
1099         self.network_name = self.guid + '-net'
1100         self.subnet_name = self.guid + '-subnet'
1101         self.vm_inst_name = self.guid + '-inst'
1102
1103         self.env_values = {
1104             'image_name': self.image_creator.image_settings.name,
1105             'flavor_name': self.flavor_creator.flavor_settings.name,
1106             'net_name': self.network_name,
1107             'subnet_name': self.subnet_name,
1108             'inst_name': self.vm_inst_name}
1109
1110         self.heat_tmplt_path = pkg_resources.resource_filename(
1111             'snaps.openstack.tests.heat', 'test_heat_template.yaml')
1112
1113     def tearDown(self):
1114         """
1115         Cleans the stack and downloaded stack file
1116         """
1117         if self.stack_creator:
1118             try:
1119                 self.stack_creator.clean()
1120             except:
1121                 pass
1122
1123         if self.image_creator:
1124             try:
1125                 self.image_creator.clean()
1126             except:
1127                 pass
1128
1129         if self.flavor_creator:
1130             try:
1131                 self.flavor_creator.clean()
1132             except:
1133                 pass
1134
1135         if self.tmp_file:
1136             try:
1137                 os.remove(self.tmp_file.name)
1138             except:
1139                 pass
1140
1141         super(self.__class__, self).__clean__()
1142
1143     def test_stack_failure(self):
1144         """
1145         Tests the creation of an OpenStack stack from Heat template file that
1146         should always fail due to too many CPU cores
1147         """
1148         # Create Stack
1149         # Set the default stack settings, then set any custom parameters sent
1150         # from the app
1151         stack_settings = StackConfig(
1152             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
1153             template_path=self.heat_tmplt_path,
1154             env_values=self.env_values)
1155         self.stack_creator = OpenStackHeatStack(
1156             self.os_creds, stack_settings)
1157
1158         with self.assertRaises(StackError):
1159             try:
1160                 self.stack_creator.create()
1161             except StackError:
1162                 resources = heat_utils.get_resources(
1163                     self.heat_cli, self.stack_creator.get_stack().id)
1164
1165                 found = False
1166                 for resource in resources:
1167                     if (resource.status ==
1168                             snaps.config.stack.STATUS_CREATE_COMPLETE):
1169                         found = True
1170                 self.assertTrue(found)
1171                 raise