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