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