6d472d05caec85a89b9f09ba16999debb1a7a294
[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 CreateStackVolumeTests(OSIntegrationTestCase):
493     """
494     Tests to ensure that floating IPs can be accessed via an
495     OpenStackVolume object obtained from the OpenStackHeatStack instance
496     """
497
498     def setUp(self):
499
500         super(self.__class__, self).__start__()
501
502         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
503
504         self.heat_creds = self.admin_os_creds
505         self.heat_creds.project_name = self.admin_os_creds.project_name
506
507         self.heat_cli = heat_utils.heat_client(self.heat_creds)
508         self.stack_creator = None
509
510         self.volume_name = self.guid + '-volume'
511         self.volume_type_name = self.guid + '-volume-type'
512
513         self.env_values = {
514             'volume_name': self.volume_name,
515             'volume_type_name': self.volume_type_name}
516
517         self.heat_tmplt_path = pkg_resources.resource_filename(
518             'snaps.openstack.tests.heat', 'volume_heat_template.yaml')
519
520         stack_settings = StackSettings(
521             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
522             template_path=self.heat_tmplt_path,
523             env_values=self.env_values)
524         self.stack_creator = create_stack.OpenStackHeatStack(
525             self.heat_creds, stack_settings)
526         self.created_stack = self.stack_creator.create()
527         self.assertIsNotNone(self.created_stack)
528
529     def tearDown(self):
530         """
531         Cleans the stack and downloaded stack file
532         """
533         if self.stack_creator:
534             try:
535                 self.stack_creator.clean()
536             except:
537                 pass
538
539         super(self.__class__, self).__clean__()
540
541     def test_retrieve_volume_creator(self):
542         """
543         Tests the creation of an OpenStack stack from Heat template file and
544         the retrieval of an OpenStackVolume creator/state machine instance
545         """
546         volume_creators = self.stack_creator.get_volume_creators()
547         self.assertEqual(1, len(volume_creators))
548
549         creator = volume_creators[0]
550         self.assertEqual(self.volume_name, creator.volume_settings.name)
551         self.assertEqual(self.volume_name, creator.get_volume().name)
552         self.assertEqual(self.volume_type_name,
553                          creator.volume_settings.type_name)
554         self.assertEqual(self.volume_type_name, creator.get_volume().type)
555         self.assertEqual(1, creator.volume_settings.size)
556         self.assertEqual(1, creator.get_volume().size)
557
558     def test_retrieve_volume_type_creator(self):
559         """
560         Tests the creation of an OpenStack stack from Heat template file and
561         the retrieval of an OpenStackVolume creator/state machine instance
562         """
563         volume_type_creators = self.stack_creator.get_volume_type_creators()
564         self.assertEqual(1, len(volume_type_creators))
565
566         creator = volume_type_creators[0]
567         self.assertIsNotNone(creator)
568
569         volume_type = creator.get_volume_type()
570         self.assertIsNotNone(volume_type)
571
572         self.assertEqual(self.volume_type_name, volume_type.name)
573         self.assertTrue(volume_type.public)
574         self.assertIsNone(volume_type.qos_spec)
575
576         encryption = volume_type.encryption
577         self.assertIsNotNone(encryption)
578         self.assertIsNone(encryption.cipher)
579         self.assertEqual('front-end', encryption.control_location)
580         self.assertIsNone(encryption.key_size)
581         self.assertEqual(u'nova.volume.encryptors.luks.LuksEncryptor',
582                          encryption.provider)
583         self.assertEqual(volume_type.id, encryption.volume_type_id)
584
585
586 class CreateStackFlavorTests(OSIntegrationTestCase):
587     """
588     Tests to ensure that floating IPs can be accessed via an
589     OpenStackFlavor object obtained from the OpenStackHeatStack instance
590     """
591
592     def setUp(self):
593
594         super(self.__class__, self).__start__()
595
596         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
597
598         self.heat_creds = self.admin_os_creds
599         self.heat_creds.project_name = self.admin_os_creds.project_name
600
601         self.heat_cli = heat_utils.heat_client(self.heat_creds)
602         self.stack_creator = None
603
604         self.heat_tmplt_path = pkg_resources.resource_filename(
605             'snaps.openstack.tests.heat', 'flavor_heat_template.yaml')
606
607         stack_settings = StackSettings(
608             name=self.guid + '-stack',
609             template_path=self.heat_tmplt_path)
610         self.stack_creator = create_stack.OpenStackHeatStack(
611             self.heat_creds, stack_settings)
612         self.created_stack = self.stack_creator.create()
613         self.assertIsNotNone(self.created_stack)
614
615     def tearDown(self):
616         """
617         Cleans the stack and downloaded stack file
618         """
619         if self.stack_creator:
620             try:
621                 self.stack_creator.clean()
622             except:
623                 pass
624
625         super(self.__class__, self).__clean__()
626
627     def test_retrieve_flavor_creator(self):
628         """
629         Tests the creation of an OpenStack stack from Heat template file and
630         the retrieval of an OpenStackVolume creator/state machine instance
631         """
632         flavor_creators = self.stack_creator.get_flavor_creators()
633         self.assertEqual(1, len(flavor_creators))
634
635         creator = flavor_creators[0]
636         self.assertTrue(creator.get_flavor().name.startswith(self.guid))
637         self.assertEqual(1024, creator.get_flavor().ram)
638         self.assertEqual(200, creator.get_flavor().disk)
639         self.assertEqual(8, creator.get_flavor().vcpus)
640         self.assertEqual(0, creator.get_flavor().ephemeral)
641         self.assertIsNone(creator.get_flavor().swap)
642         self.assertEqual(1.0, creator.get_flavor().rxtx_factor)
643         self.assertTrue(creator.get_flavor().is_public)
644
645
646 class CreateStackKeypairTests(OSIntegrationTestCase):
647     """
648     Tests to ensure that floating IPs can be accessed via an
649     OpenStackKeypair object obtained from the OpenStackHeatStack instance
650     """
651
652     def setUp(self):
653
654         super(self.__class__, self).__start__()
655
656         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
657
658         self.heat_creds = self.admin_os_creds
659         self.heat_creds.project_name = self.admin_os_creds.project_name
660
661         self.heat_cli = heat_utils.heat_client(self.heat_creds)
662         self.nova = nova_utils.nova_client(self.heat_creds)
663         self.stack_creator = None
664
665         self.keypair_name = self.guid + '-kp'
666
667         self.env_values = {
668             'keypair_name': self.keypair_name}
669
670         self.heat_tmplt_path = pkg_resources.resource_filename(
671             'snaps.openstack.tests.heat', 'keypair_heat_template.yaml')
672
673         stack_settings = StackSettings(
674             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
675             template_path=self.heat_tmplt_path,
676             env_values=self.env_values)
677         self.stack_creator = create_stack.OpenStackHeatStack(
678             self.heat_creds, stack_settings)
679         self.created_stack = self.stack_creator.create()
680         self.assertIsNotNone(self.created_stack)
681
682     def tearDown(self):
683         """
684         Cleans the stack and downloaded stack file
685         """
686         if self.stack_creator:
687             try:
688                 self.stack_creator.clean()
689             except:
690                 pass
691
692         super(self.__class__, self).__clean__()
693
694     def test_retrieve_keypair_creator(self):
695         """
696         Tests the creation of an OpenStack stack from Heat template file and
697         the retrieval of an OpenStackKeypair creator/state machine instance
698         """
699         kp_creators = self.stack_creator.get_keypair_creators('private_key')
700         self.assertEqual(1, len(kp_creators))
701
702         creator = kp_creators[0]
703
704         self.assertEqual(self.keypair_name, creator.get_keypair().name)
705         self.assertIsNotNone(creator.keypair_settings.private_filepath)
706
707         private_file_contents = file_utils.read_file(
708             creator.keypair_settings.private_filepath)
709         self.assertTrue(private_file_contents.startswith(
710             '-----BEGIN RSA PRIVATE KEY-----'))
711
712         keypair = nova_utils.get_keypair_by_id(
713             self.nova, creator.get_keypair().id)
714         self.assertIsNotNone(keypair)
715         self.assertEqual(creator.get_keypair(), keypair)
716
717
718 class CreateStackNegativeTests(OSIntegrationTestCase):
719     """
720     Negative test cases for the OpenStackHeatStack class with poor
721     configuration
722     """
723
724     def setUp(self):
725
726         super(self.__class__, self).__start__()
727
728         self.heat_creds = self.admin_os_creds
729         self.heat_creds.project_name = self.admin_os_creds.project_name
730
731         self.stack_name = self.__class__.__name__ + '-' + str(uuid.uuid4())
732         self.stack_creator = None
733         self.heat_tmplt_path = pkg_resources.resource_filename(
734             'snaps.openstack.tests.heat', 'test_heat_template.yaml')
735
736     def tearDown(self):
737         if self.stack_creator:
738             self.stack_creator.clean()
739         super(self.__class__, self).__clean__()
740
741     def test_missing_dependencies(self):
742         """
743         Expect an StackCreationError when the stack file does not exist
744         """
745         stack_settings = StackSettings(name=self.stack_name,
746                                        template_path=self.heat_tmplt_path)
747         self.stack_creator = create_stack.OpenStackHeatStack(self.heat_creds,
748                                                              stack_settings)
749         with self.assertRaises(HTTPBadRequest):
750             self.stack_creator.create()
751
752     def test_bad_stack_file(self):
753         """
754         Expect an StackCreationError when the stack file does not exist
755         """
756         stack_settings = StackSettings(name=self.stack_name,
757                                        template_path='foo')
758         self.stack_creator = create_stack.OpenStackHeatStack(self.heat_creds,
759                                                              stack_settings)
760         with self.assertRaises(IOError):
761             self.stack_creator.create()
762
763
764 class CreateStackFailureTests(OSIntegrationTestCase):
765     """
766     Tests for the OpenStackHeatStack class defined in create_stack.py for
767     when failures occur. Failures are being triggered by allocating 1 million
768     CPUs.
769     """
770
771     def setUp(self):
772
773         super(self.__class__, self).__start__()
774
775         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
776
777         self.heat_creds = self.admin_os_creds
778         self.heat_creds.project_name = self.admin_os_creds.project_name
779
780         self.heat_cli = heat_utils.heat_client(self.heat_creds)
781         self.stack_creator = None
782
783         self.tmp_file = file_utils.save_string_to_file(
784             ' ', str(uuid.uuid4()) + '-bad-image')
785         self.image_creator = OpenStackImage(
786             self.heat_creds, ImageSettings(
787                 name=self.guid + 'image', image_file=self.tmp_file.name,
788                 image_user='foo', img_format='qcow2'))
789         self.image_creator.create()
790
791         # Create Flavor
792         self.flavor_creator = OpenStackFlavor(
793             self.admin_os_creds,
794             FlavorSettings(name=self.guid + '-flavor-name', ram=256, disk=10,
795                            vcpus=1000000))
796         self.flavor_creator.create()
797
798         self.network_name = self.guid + '-net'
799         self.subnet_name = self.guid + '-subnet'
800         self.vm_inst_name = self.guid + '-inst'
801
802         self.env_values = {
803             'image_name': self.image_creator.image_settings.name,
804             'flavor_name': self.flavor_creator.flavor_settings.name,
805             'net_name': self.network_name,
806             'subnet_name': self.subnet_name,
807             'inst_name': self.vm_inst_name}
808
809         self.heat_tmplt_path = pkg_resources.resource_filename(
810             'snaps.openstack.tests.heat', 'test_heat_template.yaml')
811
812     def tearDown(self):
813         """
814         Cleans the stack and downloaded stack file
815         """
816         if self.stack_creator:
817             try:
818                 self.stack_creator.clean()
819             except:
820                 pass
821
822         if self.image_creator:
823             try:
824                 self.image_creator.clean()
825             except:
826                 pass
827
828         if self.flavor_creator:
829             try:
830                 self.flavor_creator.clean()
831             except:
832                 pass
833
834         if self.tmp_file:
835             try:
836                 os.remove(self.tmp_file.name)
837             except:
838                 pass
839
840         super(self.__class__, self).__clean__()
841
842     def test_stack_failure(self):
843         """
844         Tests the creation of an OpenStack stack from Heat template file that
845         should always fail due to too many CPU cores
846         """
847         # Create Stack
848         # Set the default stack settings, then set any custom parameters sent
849         # from the app
850         stack_settings = StackSettings(
851             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
852             template_path=self.heat_tmplt_path,
853             env_values=self.env_values)
854         self.stack_creator = create_stack.OpenStackHeatStack(self.heat_creds,
855                                                              stack_settings)
856
857         with self.assertRaises(StackError):
858             try:
859                 self.stack_creator.create()
860             except StackError:
861                 resources = heat_utils.get_resources(
862                     self.heat_cli, self.stack_creator.get_stack())
863
864                 found = False
865                 for resource in resources:
866                     if resource.status == create_stack.STATUS_CREATE_COMPLETE:
867                         found = True
868                 self.assertTrue(found)
869                 raise