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