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