Merge "Added logging when a heat stack fails."
[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_subnets()))
358         subnet = net_creators[0].get_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     def tearDown(self):
445         """
446         Cleans the stack and downloaded stack file
447         """
448         if self.stack_creator:
449             try:
450                 self.stack_creator.clean()
451             except:
452                 pass
453
454         if self.image_creator:
455             try:
456                 self.image_creator.clean()
457             except:
458                 pass
459
460         super(self.__class__, self).__clean__()
461
462     def test_connect_via_ssh_heat_vm(self):
463         """
464         Tests the creation of an OpenStack stack from Heat template file and
465         the retrieval of two VM instance creators and attempt to connect via
466         SSH to the first one with a floating IP.
467         """
468         stack_settings = StackSettings(
469             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
470             template_path=self.heat_tmplt_path,
471             env_values=self.env_values)
472         self.stack_creator = create_stack.OpenStackHeatStack(
473             self.heat_creds, stack_settings,
474             [self.image_creator.image_settings])
475         created_stack = self.stack_creator.create()
476         self.assertIsNotNone(created_stack)
477
478         vm_inst_creators = self.stack_creator.get_vm_inst_creators(
479             heat_keypair_option='private_key')
480         self.assertIsNotNone(vm_inst_creators)
481         self.assertEqual(2, len(vm_inst_creators))
482
483         for vm_inst_creator in vm_inst_creators:
484             if vm_inst_creator.get_vm_inst().name == self.vm_inst1_name:
485                 self.assertTrue(
486                     create_instance_tests.validate_ssh_client(vm_inst_creator))
487             else:
488                 vm_settings = vm_inst_creator.instance_settings
489                 self.assertEqual(0, len(vm_settings.floating_ip_settings))
490
491
492 class CreateStackRouterTests(OSIntegrationTestCase):
493     """
494     Tests for the CreateStack class defined in create_stack.py where the
495     target is a Network, Subnet, and Router
496     """
497
498     def setUp(self):
499         """
500         Instantiates the CreateStack object that is responsible for downloading
501         and creating an OS stack file within OpenStack
502         """
503         super(self.__class__, self).__start__()
504
505         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
506
507         self.heat_creds = self.admin_os_creds
508         self.heat_creds.project_name = self.admin_os_creds.project_name
509
510         self.heat_cli = heat_utils.heat_client(self.heat_creds)
511         self.neutron = neutron_utils.neutron_client(self.os_creds)
512         self.stack_creator = None
513
514         self.net_name = self.guid + '-net'
515         self.subnet_name = self.guid + '-subnet'
516         self.router_name = self.guid + '-router'
517
518         self.env_values = {
519             'net_name': self.net_name,
520             'subnet_name': self.subnet_name,
521             'router_name': self.router_name,
522             'external_net_name': self.ext_net_name}
523
524         self.heat_tmplt_path = pkg_resources.resource_filename(
525             'snaps.openstack.tests.heat', 'router_heat_template.yaml')
526
527         stack_settings = StackSettings(
528             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
529             template_path=self.heat_tmplt_path,
530             env_values=self.env_values)
531         self.stack_creator = create_stack.OpenStackHeatStack(
532             self.heat_creds, stack_settings)
533         self.created_stack = self.stack_creator.create()
534         self.assertIsNotNone(self.created_stack)
535
536     def tearDown(self):
537         """
538         Cleans the stack and downloaded stack file
539         """
540         if self.stack_creator:
541             try:
542                 self.stack_creator.clean()
543             except:
544                 pass
545
546         super(self.__class__, self).__clean__()
547
548     def test_retrieve_router_creator(self):
549         """
550         Tests the creation of an OpenStack stack from Heat template file and
551         the retrieval of an OpenStackRouter creator/state machine instance
552         """
553         router_creators = self.stack_creator.get_router_creators()
554         self.assertEqual(1, len(router_creators))
555
556         creator = router_creators[0]
557         self.assertEqual(self.router_name, creator.router_settings.name)
558
559         router = creator.get_router()
560
561         ext_net = neutron_utils.get_network(
562             self.neutron, network_name=self.ext_net_name)
563         self.assertEqual(ext_net.id, router.external_network_id)
564
565
566 class CreateStackVolumeTests(OSIntegrationTestCase):
567     """
568     Tests to ensure that floating IPs can be accessed via an
569     OpenStackVolume object obtained from the OpenStackHeatStack instance
570     """
571
572     def setUp(self):
573
574         super(self.__class__, self).__start__()
575
576         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
577
578         self.heat_creds = self.admin_os_creds
579         self.heat_creds.project_name = self.admin_os_creds.project_name
580
581         self.heat_cli = heat_utils.heat_client(self.heat_creds)
582         self.stack_creator = None
583
584         self.volume_name = self.guid + '-volume'
585         self.volume_type_name = self.guid + '-volume-type'
586
587         self.env_values = {
588             'volume_name': self.volume_name,
589             'volume_type_name': self.volume_type_name}
590
591         self.heat_tmplt_path = pkg_resources.resource_filename(
592             'snaps.openstack.tests.heat', 'volume_heat_template.yaml')
593
594         stack_settings = StackSettings(
595             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
596             template_path=self.heat_tmplt_path,
597             env_values=self.env_values)
598         self.stack_creator = create_stack.OpenStackHeatStack(
599             self.heat_creds, stack_settings)
600         self.created_stack = self.stack_creator.create()
601         self.assertIsNotNone(self.created_stack)
602
603     def tearDown(self):
604         """
605         Cleans the stack and downloaded stack file
606         """
607         if self.stack_creator:
608             try:
609                 self.stack_creator.clean()
610             except:
611                 pass
612
613         super(self.__class__, self).__clean__()
614
615     def test_retrieve_volume_creator(self):
616         """
617         Tests the creation of an OpenStack stack from Heat template file and
618         the retrieval of an OpenStackVolume creator/state machine instance
619         """
620         volume_creators = self.stack_creator.get_volume_creators()
621         self.assertEqual(1, len(volume_creators))
622
623         creator = volume_creators[0]
624         self.assertEqual(self.volume_name, creator.volume_settings.name)
625         self.assertEqual(self.volume_name, creator.get_volume().name)
626         self.assertEqual(self.volume_type_name,
627                          creator.volume_settings.type_name)
628         self.assertEqual(self.volume_type_name, creator.get_volume().type)
629         self.assertEqual(1, creator.volume_settings.size)
630         self.assertEqual(1, creator.get_volume().size)
631
632     def test_retrieve_volume_type_creator(self):
633         """
634         Tests the creation of an OpenStack stack from Heat template file and
635         the retrieval of an OpenStackVolume creator/state machine instance
636         """
637         volume_type_creators = self.stack_creator.get_volume_type_creators()
638         self.assertEqual(1, len(volume_type_creators))
639
640         creator = volume_type_creators[0]
641         self.assertIsNotNone(creator)
642
643         volume_type = creator.get_volume_type()
644         self.assertIsNotNone(volume_type)
645
646         self.assertEqual(self.volume_type_name, volume_type.name)
647         self.assertTrue(volume_type.public)
648         self.assertIsNone(volume_type.qos_spec)
649
650         encryption = volume_type.encryption
651         self.assertIsNotNone(encryption)
652         self.assertIsNone(encryption.cipher)
653         self.assertEqual('front-end', encryption.control_location)
654         self.assertIsNone(encryption.key_size)
655         self.assertEqual(u'nova.volume.encryptors.luks.LuksEncryptor',
656                          encryption.provider)
657         self.assertEqual(volume_type.id, encryption.volume_type_id)
658
659
660 class CreateStackFlavorTests(OSIntegrationTestCase):
661     """
662     Tests to ensure that floating IPs can be accessed via an
663     OpenStackFlavor object obtained from the OpenStackHeatStack instance
664     """
665
666     def setUp(self):
667
668         super(self.__class__, self).__start__()
669
670         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
671
672         self.heat_creds = self.admin_os_creds
673         self.heat_creds.project_name = self.admin_os_creds.project_name
674
675         self.heat_cli = heat_utils.heat_client(self.heat_creds)
676         self.stack_creator = None
677
678         self.heat_tmplt_path = pkg_resources.resource_filename(
679             'snaps.openstack.tests.heat', 'flavor_heat_template.yaml')
680
681         stack_settings = StackSettings(
682             name=self.guid + '-stack',
683             template_path=self.heat_tmplt_path)
684         self.stack_creator = create_stack.OpenStackHeatStack(
685             self.heat_creds, stack_settings)
686         self.created_stack = self.stack_creator.create()
687         self.assertIsNotNone(self.created_stack)
688
689     def tearDown(self):
690         """
691         Cleans the stack and downloaded stack file
692         """
693         if self.stack_creator:
694             try:
695                 self.stack_creator.clean()
696             except:
697                 pass
698
699         super(self.__class__, self).__clean__()
700
701     def test_retrieve_flavor_creator(self):
702         """
703         Tests the creation of an OpenStack stack from Heat template file and
704         the retrieval of an OpenStackVolume creator/state machine instance
705         """
706         flavor_creators = self.stack_creator.get_flavor_creators()
707         self.assertEqual(1, len(flavor_creators))
708
709         creator = flavor_creators[0]
710         self.assertTrue(creator.get_flavor().name.startswith(self.guid))
711         self.assertEqual(1024, creator.get_flavor().ram)
712         self.assertEqual(200, creator.get_flavor().disk)
713         self.assertEqual(8, creator.get_flavor().vcpus)
714         self.assertEqual(0, creator.get_flavor().ephemeral)
715         self.assertIsNone(creator.get_flavor().swap)
716         self.assertEqual(1.0, creator.get_flavor().rxtx_factor)
717         self.assertTrue(creator.get_flavor().is_public)
718
719
720 class CreateStackKeypairTests(OSIntegrationTestCase):
721     """
722     Tests to ensure that floating IPs can be accessed via an
723     OpenStackKeypair object obtained from the OpenStackHeatStack instance
724     """
725
726     def setUp(self):
727
728         super(self.__class__, self).__start__()
729
730         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
731
732         self.heat_creds = self.admin_os_creds
733         self.heat_creds.project_name = self.admin_os_creds.project_name
734
735         self.heat_cli = heat_utils.heat_client(self.heat_creds)
736         self.nova = nova_utils.nova_client(self.heat_creds)
737         self.stack_creator = None
738
739         self.keypair_name = self.guid + '-kp'
740
741         self.env_values = {
742             'keypair_name': self.keypair_name}
743
744         self.heat_tmplt_path = pkg_resources.resource_filename(
745             'snaps.openstack.tests.heat', 'keypair_heat_template.yaml')
746
747         stack_settings = StackSettings(
748             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
749             template_path=self.heat_tmplt_path,
750             env_values=self.env_values)
751         self.stack_creator = create_stack.OpenStackHeatStack(
752             self.heat_creds, stack_settings)
753         self.created_stack = self.stack_creator.create()
754         self.assertIsNotNone(self.created_stack)
755
756     def tearDown(self):
757         """
758         Cleans the stack and downloaded stack file
759         """
760         if self.stack_creator:
761             try:
762                 self.stack_creator.clean()
763             except:
764                 pass
765
766         super(self.__class__, self).__clean__()
767
768     def test_retrieve_keypair_creator(self):
769         """
770         Tests the creation of an OpenStack stack from Heat template file and
771         the retrieval of an OpenStackKeypair creator/state machine instance
772         """
773         kp_creators = self.stack_creator.get_keypair_creators('private_key')
774         self.assertEqual(1, len(kp_creators))
775
776         creator = kp_creators[0]
777
778         self.assertEqual(self.keypair_name, creator.get_keypair().name)
779         self.assertIsNotNone(creator.keypair_settings.private_filepath)
780
781         private_file_contents = file_utils.read_file(
782             creator.keypair_settings.private_filepath)
783         self.assertTrue(private_file_contents.startswith(
784             '-----BEGIN RSA PRIVATE KEY-----'))
785
786         keypair = nova_utils.get_keypair_by_id(
787             self.nova, creator.get_keypair().id)
788         self.assertIsNotNone(keypair)
789         self.assertEqual(creator.get_keypair(), keypair)
790
791
792 class CreateStackNegativeTests(OSIntegrationTestCase):
793     """
794     Negative test cases for the OpenStackHeatStack class with poor
795     configuration
796     """
797
798     def setUp(self):
799
800         super(self.__class__, self).__start__()
801
802         self.heat_creds = self.admin_os_creds
803         self.heat_creds.project_name = self.admin_os_creds.project_name
804
805         self.stack_name = self.__class__.__name__ + '-' + str(uuid.uuid4())
806         self.stack_creator = None
807         self.heat_tmplt_path = pkg_resources.resource_filename(
808             'snaps.openstack.tests.heat', 'test_heat_template.yaml')
809
810     def tearDown(self):
811         if self.stack_creator:
812             self.stack_creator.clean()
813         super(self.__class__, self).__clean__()
814
815     def test_missing_dependencies(self):
816         """
817         Expect an StackCreationError when the stack file does not exist
818         """
819         stack_settings = StackSettings(name=self.stack_name,
820                                        template_path=self.heat_tmplt_path)
821         self.stack_creator = create_stack.OpenStackHeatStack(self.heat_creds,
822                                                              stack_settings)
823         with self.assertRaises(HTTPBadRequest):
824             self.stack_creator.create()
825
826     def test_bad_stack_file(self):
827         """
828         Expect an StackCreationError when the stack file does not exist
829         """
830         stack_settings = StackSettings(name=self.stack_name,
831                                        template_path='foo')
832         self.stack_creator = create_stack.OpenStackHeatStack(self.heat_creds,
833                                                              stack_settings)
834         with self.assertRaises(IOError):
835             self.stack_creator.create()
836
837
838 class CreateStackFailureTests(OSIntegrationTestCase):
839     """
840     Tests for the OpenStackHeatStack class defined in create_stack.py for
841     when failures occur. Failures are being triggered by allocating 1 million
842     CPUs.
843     """
844
845     def setUp(self):
846
847         super(self.__class__, self).__start__()
848
849         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
850
851         self.heat_creds = self.admin_os_creds
852         self.heat_creds.project_name = self.admin_os_creds.project_name
853
854         self.heat_cli = heat_utils.heat_client(self.heat_creds)
855         self.stack_creator = None
856
857         self.tmp_file = file_utils.save_string_to_file(
858             ' ', str(uuid.uuid4()) + '-bad-image')
859         self.image_creator = OpenStackImage(
860             self.heat_creds, ImageSettings(
861                 name=self.guid + 'image', image_file=self.tmp_file.name,
862                 image_user='foo', img_format='qcow2'))
863         self.image_creator.create()
864
865         # Create Flavor
866         self.flavor_creator = OpenStackFlavor(
867             self.admin_os_creds,
868             FlavorSettings(name=self.guid + '-flavor-name', ram=256, disk=10,
869                            vcpus=1000000))
870         self.flavor_creator.create()
871
872         self.network_name = self.guid + '-net'
873         self.subnet_name = self.guid + '-subnet'
874         self.vm_inst_name = self.guid + '-inst'
875
876         self.env_values = {
877             'image_name': self.image_creator.image_settings.name,
878             'flavor_name': self.flavor_creator.flavor_settings.name,
879             'net_name': self.network_name,
880             'subnet_name': self.subnet_name,
881             'inst_name': self.vm_inst_name}
882
883         self.heat_tmplt_path = pkg_resources.resource_filename(
884             'snaps.openstack.tests.heat', 'test_heat_template.yaml')
885
886     def tearDown(self):
887         """
888         Cleans the stack and downloaded stack file
889         """
890         if self.stack_creator:
891             try:
892                 self.stack_creator.clean()
893             except:
894                 pass
895
896         if self.image_creator:
897             try:
898                 self.image_creator.clean()
899             except:
900                 pass
901
902         if self.flavor_creator:
903             try:
904                 self.flavor_creator.clean()
905             except:
906                 pass
907
908         if self.tmp_file:
909             try:
910                 os.remove(self.tmp_file.name)
911             except:
912                 pass
913
914         super(self.__class__, self).__clean__()
915
916     def test_stack_failure(self):
917         """
918         Tests the creation of an OpenStack stack from Heat template file that
919         should always fail due to too many CPU cores
920         """
921         # Create Stack
922         # Set the default stack settings, then set any custom parameters sent
923         # from the app
924         stack_settings = StackSettings(
925             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
926             template_path=self.heat_tmplt_path,
927             env_values=self.env_values)
928         self.stack_creator = create_stack.OpenStackHeatStack(self.heat_creds,
929                                                              stack_settings)
930
931         with self.assertRaises(StackError):
932             try:
933                 self.stack_creator.create()
934             except StackError:
935                 resources = heat_utils.get_resources(
936                     self.heat_cli, self.stack_creator.get_stack())
937
938                 found = False
939                 for resource in resources:
940                     if resource.status == create_stack.STATUS_CREATE_COMPLETE:
941                         found = True
942                 self.assertTrue(found)
943                 raise