Merge "Supporting the protocol string value of 'any' for security group rules."
[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         vm_inst_by_name = nova_utils.get_server(
392             nova, server_name=vm_inst_creators[0].get_vm_inst().name)
393         self.assertEqual(vm_inst_creators[0].get_vm_inst(), vm_inst_by_name)
394         self.assertIsNotNone(nova_utils.get_server_object_by_id(
395             nova, vm_inst_creators[0].get_vm_inst().id))
396
397
398 class CreateStackFloatingIpTests(OSIntegrationTestCase):
399     """
400     Tests to ensure that floating IPs can be accessed via an
401     OpenStackVmInstance object obtained from the OpenStackHeatStack instance
402     """
403
404     def setUp(self):
405
406         super(self.__class__, self).__start__()
407
408         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
409
410         self.heat_creds = self.admin_os_creds
411         self.heat_creds.project_name = self.admin_os_creds.project_name
412
413         self.heat_cli = heat_utils.heat_client(self.heat_creds)
414         self.stack_creator = None
415
416         self.image_creator = OpenStackImage(
417             self.heat_creds, openstack_tests.cirros_image_settings(
418                 name=self.guid + '-image',
419                 image_metadata=self.image_metadata))
420         self.image_creator.create()
421
422         self.network_name = self.guid + '-net'
423         self.subnet_name = self.guid + '-subnet'
424         self.flavor1_name = self.guid + '-flavor1'
425         self.flavor2_name = self.guid + '-flavor2'
426         self.sec_grp_name = self.guid + '-sec_grp'
427         self.vm_inst1_name = self.guid + '-inst1'
428         self.vm_inst2_name = self.guid + '-inst2'
429         self.keypair_name = self.guid + '-kp'
430
431         self.env_values = {
432             'image1_name': self.image_creator.image_settings.name,
433             'image2_name': self.image_creator.image_settings.name,
434             'flavor1_name': self.flavor1_name,
435             'flavor2_name': self.flavor2_name,
436             'net_name': self.network_name,
437             'subnet_name': self.subnet_name,
438             'inst1_name': self.vm_inst1_name,
439             'inst2_name': self.vm_inst2_name,
440             'keypair_name': self.keypair_name,
441             'external_net_name': self.ext_net_name,
442             'security_group_name': self.sec_grp_name}
443
444         self.heat_tmplt_path = pkg_resources.resource_filename(
445             'snaps.openstack.tests.heat', 'floating_ip_heat_template.yaml')
446
447         self.vm_inst_creators = list()
448
449     def tearDown(self):
450         """
451         Cleans the stack and downloaded stack file
452         """
453         if self.stack_creator:
454             try:
455                 self.stack_creator.clean()
456             except:
457                 pass
458
459         if self.image_creator:
460             try:
461                 self.image_creator.clean()
462             except:
463                 pass
464
465         for vm_inst_creator in self.vm_inst_creators:
466             try:
467                 keypair_settings = vm_inst_creator.keypair_settings
468                 if keypair_settings and keypair_settings.private_filepath:
469                     expanded_path = os.path.expanduser(
470                         keypair_settings.private_filepath)
471                     os.chmod(expanded_path, 0o755)
472                     os.remove(expanded_path)
473             except:
474                 pass
475
476         super(self.__class__, self).__clean__()
477
478     def test_connect_via_ssh_heat_vm(self):
479         """
480         Tests the creation of an OpenStack stack from Heat template file and
481         the retrieval of two VM instance creators and attempt to connect via
482         SSH to the first one with a floating IP.
483         """
484         stack_settings = StackConfig(
485             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
486             template_path=self.heat_tmplt_path,
487             env_values=self.env_values)
488         self.stack_creator = OpenStackHeatStack(
489             self.heat_creds, stack_settings,
490             [self.image_creator.image_settings])
491         created_stack = self.stack_creator.create()
492         self.assertIsNotNone(created_stack)
493
494         self.vm_inst_creators = self.stack_creator.get_vm_inst_creators(
495             heat_keypair_option='private_key')
496         self.assertIsNotNone(self.vm_inst_creators)
497         self.assertEqual(2, len(self.vm_inst_creators))
498
499         for vm_inst_creator in self.vm_inst_creators:
500             if vm_inst_creator.get_vm_inst().name == self.vm_inst1_name:
501                 self.assertTrue(
502                     create_instance_tests.validate_ssh_client(vm_inst_creator))
503             else:
504                 vm_settings = vm_inst_creator.instance_settings
505                 self.assertEqual(0, len(vm_settings.floating_ip_settings))
506
507
508 class CreateStackRouterTests(OSIntegrationTestCase):
509     """
510     Tests for the CreateStack class defined in create_stack.py where the
511     target is a Network, Subnet, and Router
512     """
513
514     def setUp(self):
515         """
516         Instantiates the CreateStack object that is responsible for downloading
517         and creating an OS stack file within OpenStack
518         """
519         super(self.__class__, self).__start__()
520
521         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
522
523         self.heat_creds = self.admin_os_creds
524         self.heat_creds.project_name = self.admin_os_creds.project_name
525
526         self.heat_cli = heat_utils.heat_client(self.heat_creds)
527         self.neutron = neutron_utils.neutron_client(self.os_creds)
528         self.stack_creator = None
529
530         self.net_name = self.guid + '-net'
531         self.subnet_name = self.guid + '-subnet'
532         self.router_name = self.guid + '-router'
533
534         self.env_values = {
535             'net_name': self.net_name,
536             'subnet_name': self.subnet_name,
537             'router_name': self.router_name,
538             'external_net_name': self.ext_net_name}
539
540         self.heat_tmplt_path = pkg_resources.resource_filename(
541             'snaps.openstack.tests.heat', 'router_heat_template.yaml')
542
543         stack_settings = StackConfig(
544             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
545             template_path=self.heat_tmplt_path,
546             env_values=self.env_values)
547         self.stack_creator = OpenStackHeatStack(
548             self.heat_creds, stack_settings)
549         self.created_stack = self.stack_creator.create()
550         self.assertIsNotNone(self.created_stack)
551
552     def tearDown(self):
553         """
554         Cleans the stack and downloaded stack file
555         """
556         if self.stack_creator:
557             try:
558                 self.stack_creator.clean()
559             except:
560                 pass
561
562         super(self.__class__, self).__clean__()
563
564     def test_retrieve_router_creator(self):
565         """
566         Tests the creation of an OpenStack stack from Heat template file and
567         the retrieval of an OpenStackRouter creator/state machine instance
568         """
569         router_creators = self.stack_creator.get_router_creators()
570         self.assertEqual(1, len(router_creators))
571
572         creator = router_creators[0]
573         self.assertEqual(self.router_name, creator.router_settings.name)
574
575         router = creator.get_router()
576
577         ext_net = neutron_utils.get_network(
578             self.neutron, network_name=self.ext_net_name)
579         self.assertEqual(ext_net.id, router.external_network_id)
580
581
582 class CreateStackVolumeTests(OSIntegrationTestCase):
583     """
584     Tests to ensure that floating IPs can be accessed via an
585     OpenStackVolume object obtained from the OpenStackHeatStack instance
586     """
587
588     def setUp(self):
589
590         super(self.__class__, self).__start__()
591
592         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
593
594         self.heat_creds = self.admin_os_creds
595         self.heat_creds.project_name = self.admin_os_creds.project_name
596
597         self.heat_cli = heat_utils.heat_client(self.heat_creds)
598         self.stack_creator = None
599
600         self.volume_name = self.guid + '-volume'
601         self.volume_type_name = self.guid + '-volume-type'
602
603         self.env_values = {
604             'volume_name': self.volume_name,
605             'volume_type_name': self.volume_type_name}
606
607         self.heat_tmplt_path = pkg_resources.resource_filename(
608             'snaps.openstack.tests.heat', 'volume_heat_template.yaml')
609
610         stack_settings = StackConfig(
611             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
612             template_path=self.heat_tmplt_path,
613             env_values=self.env_values)
614         self.stack_creator = OpenStackHeatStack(
615             self.heat_creds, stack_settings)
616         self.created_stack = self.stack_creator.create()
617         self.assertIsNotNone(self.created_stack)
618
619     def tearDown(self):
620         """
621         Cleans the stack and downloaded stack file
622         """
623         if self.stack_creator:
624             try:
625                 self.stack_creator.clean()
626             except:
627                 pass
628
629         super(self.__class__, self).__clean__()
630
631     def test_retrieve_volume_creator(self):
632         """
633         Tests the creation of an OpenStack stack from Heat template file and
634         the retrieval of an OpenStackVolume creator/state machine instance
635         """
636         volume_creators = self.stack_creator.get_volume_creators()
637         self.assertEqual(1, len(volume_creators))
638
639         creator = volume_creators[0]
640         self.assertEqual(self.volume_name, creator.volume_settings.name)
641         self.assertEqual(self.volume_name, creator.get_volume().name)
642         self.assertEqual(self.volume_type_name,
643                          creator.volume_settings.type_name)
644         self.assertEqual(self.volume_type_name, creator.get_volume().type)
645         self.assertEqual(1, creator.volume_settings.size)
646         self.assertEqual(1, creator.get_volume().size)
647
648     def test_retrieve_volume_type_creator(self):
649         """
650         Tests the creation of an OpenStack stack from Heat template file and
651         the retrieval of an OpenStackVolume creator/state machine instance
652         """
653         volume_type_creators = self.stack_creator.get_volume_type_creators()
654         self.assertEqual(1, len(volume_type_creators))
655
656         creator = volume_type_creators[0]
657         self.assertIsNotNone(creator)
658
659         volume_type = creator.get_volume_type()
660         self.assertIsNotNone(volume_type)
661
662         self.assertEqual(self.volume_type_name, volume_type.name)
663         self.assertTrue(volume_type.public)
664         self.assertIsNone(volume_type.qos_spec)
665
666         encryption = volume_type.encryption
667         self.assertIsNotNone(encryption)
668         self.assertIsNone(encryption.cipher)
669         self.assertEqual('front-end', encryption.control_location)
670         self.assertIsNone(encryption.key_size)
671         self.assertEqual(u'nova.volume.encryptors.luks.LuksEncryptor',
672                          encryption.provider)
673         self.assertEqual(volume_type.id, encryption.volume_type_id)
674
675
676 class CreateStackFlavorTests(OSIntegrationTestCase):
677     """
678     Tests to ensure that floating IPs can be accessed via an
679     OpenStackFlavor object obtained from the OpenStackHeatStack instance
680     """
681
682     def setUp(self):
683
684         super(self.__class__, self).__start__()
685
686         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
687
688         self.heat_creds = self.admin_os_creds
689         self.heat_creds.project_name = self.admin_os_creds.project_name
690
691         self.heat_cli = heat_utils.heat_client(self.heat_creds)
692         self.stack_creator = None
693
694         self.heat_tmplt_path = pkg_resources.resource_filename(
695             'snaps.openstack.tests.heat', 'flavor_heat_template.yaml')
696
697         stack_settings = StackConfig(
698             name=self.guid + '-stack',
699             template_path=self.heat_tmplt_path)
700         self.stack_creator = OpenStackHeatStack(
701             self.heat_creds, stack_settings)
702         self.created_stack = self.stack_creator.create()
703         self.assertIsNotNone(self.created_stack)
704
705     def tearDown(self):
706         """
707         Cleans the stack and downloaded stack file
708         """
709         if self.stack_creator:
710             try:
711                 self.stack_creator.clean()
712             except:
713                 pass
714
715         super(self.__class__, self).__clean__()
716
717     def test_retrieve_flavor_creator(self):
718         """
719         Tests the creation of an OpenStack stack from Heat template file and
720         the retrieval of an OpenStackVolume creator/state machine instance
721         """
722         flavor_creators = self.stack_creator.get_flavor_creators()
723         self.assertEqual(1, len(flavor_creators))
724
725         creator = flavor_creators[0]
726         self.assertTrue(creator.get_flavor().name.startswith(self.guid))
727         self.assertEqual(1024, creator.get_flavor().ram)
728         self.assertEqual(200, creator.get_flavor().disk)
729         self.assertEqual(8, creator.get_flavor().vcpus)
730         self.assertEqual(0, creator.get_flavor().ephemeral)
731         self.assertIsNone(creator.get_flavor().swap)
732         self.assertEqual(1.0, creator.get_flavor().rxtx_factor)
733         self.assertTrue(creator.get_flavor().is_public)
734
735
736 class CreateStackKeypairTests(OSIntegrationTestCase):
737     """
738     Tests to ensure that floating IPs can be accessed via an
739     OpenStackKeypair object obtained from the OpenStackHeatStack instance
740     """
741
742     def setUp(self):
743
744         super(self.__class__, self).__start__()
745
746         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
747
748         self.heat_creds = self.admin_os_creds
749         self.heat_creds.project_name = self.admin_os_creds.project_name
750
751         self.heat_cli = heat_utils.heat_client(self.heat_creds)
752         self.nova = nova_utils.nova_client(self.heat_creds)
753         self.stack_creator = None
754
755         self.keypair_name = self.guid + '-kp'
756
757         self.env_values = {
758             'keypair_name': self.keypair_name}
759
760         self.heat_tmplt_path = pkg_resources.resource_filename(
761             'snaps.openstack.tests.heat', 'keypair_heat_template.yaml')
762
763         stack_settings = StackConfig(
764             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
765             template_path=self.heat_tmplt_path,
766             env_values=self.env_values)
767         self.stack_creator = OpenStackHeatStack(
768             self.heat_creds, stack_settings)
769         self.created_stack = self.stack_creator.create()
770         self.assertIsNotNone(self.created_stack)
771
772         self.keypair_creators = list()
773
774     def tearDown(self):
775         """
776         Cleans the stack and downloaded stack file
777         """
778         if self.stack_creator:
779             try:
780                 self.stack_creator.clean()
781             except:
782                 pass
783         for keypair_creator in self.keypair_creators:
784             try:
785                 keypair_creator.clean()
786             except:
787                 pass
788
789         super(self.__class__, self).__clean__()
790
791     def test_retrieve_keypair_creator(self):
792         """
793         Tests the creation of an OpenStack stack from Heat template file and
794         the retrieval of an OpenStackKeypair creator/state machine instance
795         """
796         self.kp_creators = self.stack_creator.get_keypair_creators(
797             'private_key')
798         self.assertEqual(1, len(self.kp_creators))
799
800         self.keypair_creator = self.kp_creators[0]
801
802         self.assertEqual(self.keypair_name,
803                          self.keypair_creator.get_keypair().name)
804         self.assertIsNotNone(
805             self.keypair_creator.keypair_settings.private_filepath)
806
807         private_file_contents = file_utils.read_file(
808             self.keypair_creator.keypair_settings.private_filepath)
809         self.assertTrue(private_file_contents.startswith(
810             '-----BEGIN RSA PRIVATE KEY-----'))
811
812         keypair = nova_utils.get_keypair_by_id(
813             self.nova, self.keypair_creator.get_keypair().id)
814         self.assertIsNotNone(keypair)
815         self.assertEqual(self.keypair_creator.get_keypair(), keypair)
816
817
818 class CreateStackSecurityGroupTests(OSIntegrationTestCase):
819     """
820     Tests for the OpenStackHeatStack class to ensure it returns an
821     OpenStackSecurityGroup object
822     """
823
824     def setUp(self):
825         """
826         Instantiates the CreateStack object that is responsible for downloading
827         and creating an OS stack file within OpenStack
828         """
829         super(self.__class__, self).__start__()
830
831         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
832
833         self.heat_creds = self.admin_os_creds
834         self.heat_creds.project_name = self.admin_os_creds.project_name
835
836         self.heat_cli = heat_utils.heat_client(self.heat_creds)
837         self.nova = nova_utils.nova_client(self.heat_creds)
838         self.stack_creator = None
839
840         self.security_group_name = self.guid + '-sec-grp'
841
842         self.env_values = {
843             'security_group_name': self.security_group_name}
844
845         self.heat_tmplt_path = pkg_resources.resource_filename(
846             'snaps.openstack.tests.heat', 'security_group_heat_template.yaml')
847
848         stack_settings = StackConfig(
849             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
850             template_path=self.heat_tmplt_path,
851             env_values=self.env_values)
852         self.stack_creator = OpenStackHeatStack(
853             self.heat_creds, stack_settings)
854         self.created_stack = self.stack_creator.create()
855         self.assertIsNotNone(self.created_stack)
856
857     def tearDown(self):
858         """
859         Cleans the stack and downloaded stack file
860         """
861         if self.stack_creator:
862             try:
863                 self.stack_creator.clean()
864             except:
865                 pass
866
867         super(self.__class__, self).__clean__()
868
869     def test_retrieve_security_group_creator(self):
870         """
871         Tests the creation of an OpenStack stack from Heat template file and
872         the retrieval of an OpenStackSecurityGroup creator/state machine
873         instance
874         """
875         sec_grp_creators = self.stack_creator.get_security_group_creators()
876         self.assertEqual(1, len(sec_grp_creators))
877
878         creator = sec_grp_creators[0]
879         sec_grp = creator.get_security_group()
880
881         self.assertEqual(self.security_group_name, sec_grp.name)
882         self.assertEqual('Test description', sec_grp.description)
883         self.assertEqual(2, len(sec_grp.rules))
884
885         has_ssh_rule = False
886         has_icmp_rule = False
887
888         for rule in sec_grp.rules:
889             if (rule.security_group_id == sec_grp.id
890                     and rule.direction == 'egress'
891                     and rule.ethertype == 'IPv4'
892                     and rule.port_range_min == 22
893                     and rule.port_range_max == 22
894                     and rule.protocol == 'tcp'
895                     and rule.remote_group_id is None
896                     and rule.remote_ip_prefix == '0.0.0.0/0'):
897                 has_ssh_rule = True
898             if (rule.security_group_id == sec_grp.id
899                     and rule.direction == 'ingress'
900                     and rule.ethertype == 'IPv4'
901                     and rule.port_range_min is None
902                     and rule.port_range_max is None
903                     and rule.protocol == 'icmp'
904                     and rule.remote_group_id is None
905                     and rule.remote_ip_prefix == '0.0.0.0/0'):
906                 has_icmp_rule = True
907
908         self.assertTrue(has_ssh_rule)
909         self.assertTrue(has_icmp_rule)
910
911
912 class CreateStackNegativeTests(OSIntegrationTestCase):
913     """
914     Negative test cases for the OpenStackHeatStack class with poor
915     configuration
916     """
917
918     def setUp(self):
919
920         super(self.__class__, self).__start__()
921
922         self.heat_creds = self.admin_os_creds
923         self.heat_creds.project_name = self.admin_os_creds.project_name
924
925         self.stack_name = self.__class__.__name__ + '-' + str(uuid.uuid4())
926         self.stack_creator = None
927         self.heat_tmplt_path = pkg_resources.resource_filename(
928             'snaps.openstack.tests.heat', 'test_heat_template.yaml')
929
930     def tearDown(self):
931         if self.stack_creator:
932             self.stack_creator.clean()
933         super(self.__class__, self).__clean__()
934
935     def test_missing_dependencies(self):
936         """
937         Expect an StackCreationError when the stack file does not exist
938         """
939         stack_settings = StackConfig(name=self.stack_name,
940                                      template_path=self.heat_tmplt_path)
941         self.stack_creator = OpenStackHeatStack(
942             self.heat_creds, stack_settings)
943         with self.assertRaises(HTTPBadRequest):
944             self.stack_creator.create()
945
946     def test_bad_stack_file(self):
947         """
948         Expect an StackCreationError when the stack file does not exist
949         """
950         stack_settings = StackConfig(
951             name=self.stack_name, template_path='foo')
952         self.stack_creator = OpenStackHeatStack(
953             self.heat_creds, stack_settings)
954         with self.assertRaises(IOError):
955             self.stack_creator.create()
956
957
958 class CreateStackFailureTests(OSIntegrationTestCase):
959     """
960     Tests for the OpenStackHeatStack class defined in create_stack.py for
961     when failures occur. Failures are being triggered by allocating 1 million
962     CPUs.
963     """
964
965     def setUp(self):
966
967         super(self.__class__, self).__start__()
968
969         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
970
971         self.heat_creds = self.admin_os_creds
972         self.heat_creds.project_name = self.admin_os_creds.project_name
973
974         self.heat_cli = heat_utils.heat_client(self.heat_creds)
975         self.stack_creator = None
976
977         self.tmp_file = file_utils.save_string_to_file(
978             ' ', str(uuid.uuid4()) + '-bad-image')
979         self.image_creator = OpenStackImage(
980             self.heat_creds, ImageConfig(
981                 name=self.guid + 'image', image_file=self.tmp_file.name,
982                 image_user='foo', img_format='qcow2'))
983         self.image_creator.create()
984
985         # Create Flavor
986         self.flavor_creator = OpenStackFlavor(
987             self.admin_os_creds,
988             FlavorConfig(
989                 name=self.guid + '-flavor-name', ram=256, disk=10,
990                 vcpus=1000000))
991         self.flavor_creator.create()
992
993         self.network_name = self.guid + '-net'
994         self.subnet_name = self.guid + '-subnet'
995         self.vm_inst_name = self.guid + '-inst'
996
997         self.env_values = {
998             'image_name': self.image_creator.image_settings.name,
999             'flavor_name': self.flavor_creator.flavor_settings.name,
1000             'net_name': self.network_name,
1001             'subnet_name': self.subnet_name,
1002             'inst_name': self.vm_inst_name}
1003
1004         self.heat_tmplt_path = pkg_resources.resource_filename(
1005             'snaps.openstack.tests.heat', 'test_heat_template.yaml')
1006
1007     def tearDown(self):
1008         """
1009         Cleans the stack and downloaded stack file
1010         """
1011         if self.stack_creator:
1012             try:
1013                 self.stack_creator.clean()
1014             except:
1015                 pass
1016
1017         if self.image_creator:
1018             try:
1019                 self.image_creator.clean()
1020             except:
1021                 pass
1022
1023         if self.flavor_creator:
1024             try:
1025                 self.flavor_creator.clean()
1026             except:
1027                 pass
1028
1029         if self.tmp_file:
1030             try:
1031                 os.remove(self.tmp_file.name)
1032             except:
1033                 pass
1034
1035         super(self.__class__, self).__clean__()
1036
1037     def test_stack_failure(self):
1038         """
1039         Tests the creation of an OpenStack stack from Heat template file that
1040         should always fail due to too many CPU cores
1041         """
1042         # Create Stack
1043         # Set the default stack settings, then set any custom parameters sent
1044         # from the app
1045         stack_settings = StackConfig(
1046             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
1047             template_path=self.heat_tmplt_path,
1048             env_values=self.env_values)
1049         self.stack_creator = OpenStackHeatStack(
1050             self.heat_creds, stack_settings)
1051
1052         with self.assertRaises(StackError):
1053             try:
1054                 self.stack_creator.create()
1055             except StackError:
1056                 resources = heat_utils.get_resources(
1057                     self.heat_cli, self.stack_creator.get_stack())
1058
1059                 found = False
1060                 for resource in resources:
1061                     if (resource.status ==
1062                             snaps.config.stack.STATUS_CREATE_COMPLETE):
1063                         found = True
1064                 self.assertTrue(found)
1065                 raise