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