Modified code to support both Python 2.7 and 3.x
[snaps.git] / snaps / openstack / tests / create_instance_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 logging
16 import os
17 import re
18 import time
19 import unittest
20 import uuid
21
22 from snaps.openstack.create_instance import VmInstanceSettings, OpenStackVmInstance, FloatingIpSettings
23 from snaps.openstack.create_flavor import OpenStackFlavor, FlavorSettings
24 from snaps.openstack.create_keypairs import OpenStackKeypair, KeypairSettings
25 from snaps.openstack.create_network import OpenStackNetwork, PortSettings
26 from snaps.openstack.create_router import OpenStackRouter
27 from snaps.openstack.create_image import OpenStackImage
28 from snaps.openstack.create_security_group import SecurityGroupSettings, OpenStackSecurityGroup
29 from snaps.openstack.tests import openstack_tests, validation_utils
30 from snaps.openstack.utils import nova_utils
31 from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase
32
33 __author__ = 'spisarski'
34
35 VM_BOOT_TIMEOUT = 600
36
37 logger = logging.getLogger('create_instance_tests')
38
39
40 class VmInstanceSettingsUnitTests(unittest.TestCase):
41     """
42     Tests the construction of the VmInstanceSettings class
43     """
44
45     def test_no_params(self):
46         with self.assertRaises(Exception):
47             VmInstanceSettings()
48
49     def test_empty_config(self):
50         with self.assertRaises(Exception):
51             VmInstanceSettings(config=dict())
52
53     def test_name_only(self):
54         with self.assertRaises(Exception):
55             VmInstanceSettings(name='foo')
56
57     def test_config_with_name_only(self):
58         with self.assertRaises(Exception):
59             VmInstanceSettings(config={'name': 'foo'})
60
61     def test_name_flavor_only(self):
62         with self.assertRaises(Exception):
63             VmInstanceSettings(name='foo', flavor='bar')
64
65     def test_config_with_name_flavor_only(self):
66         with self.assertRaises(Exception):
67             VmInstanceSettings(config={'name': 'foo', 'flavor': 'bar'})
68
69     def test_name_flavor_port_only(self):
70         port_settings = PortSettings(name='foo-port', network_name='bar-net')
71         settings = VmInstanceSettings(name='foo', flavor='bar', port_settings=[port_settings])
72         self.assertEqual('foo', settings.name)
73         self.assertEqual('bar', settings.flavor)
74         self.assertEqual(1, len(settings.port_settings))
75         self.assertEqual('foo-port', settings.port_settings[0].name)
76         self.assertEqual('bar-net', settings.port_settings[0].network_name)
77         self.assertEqual(0, len(settings.security_group_names))
78         self.assertEqual(0, len(settings.floating_ip_settings))
79         self.assertIsNone(settings.sudo_user)
80         self.assertEqual(900, settings.vm_boot_timeout)
81         self.assertEqual(300, settings.vm_delete_timeout)
82         self.assertEqual(180, settings.ssh_connect_timeout)
83         self.assertIsNone(settings.availability_zone)
84
85     def test_config_with_name_flavor_port_only(self):
86         port_settings = PortSettings(name='foo-port', network_name='bar-net')
87         settings = VmInstanceSettings(config={'name': 'foo', 'flavor': 'bar', 'ports': [port_settings]})
88         self.assertEqual('foo', settings.name)
89         self.assertEqual('bar', settings.flavor)
90         self.assertEqual(1, len(settings.port_settings))
91         self.assertEqual('foo-port', settings.port_settings[0].name)
92         self.assertEqual('bar-net', settings.port_settings[0].network_name)
93         self.assertEqual(0, len(settings.security_group_names))
94         self.assertEqual(0, len(settings.floating_ip_settings))
95         self.assertIsNone(settings.sudo_user)
96         self.assertEqual(900, settings.vm_boot_timeout)
97         self.assertEqual(300, settings.vm_delete_timeout)
98         self.assertEqual(180, settings.ssh_connect_timeout)
99         self.assertIsNone(settings.availability_zone)
100
101     def test_all(self):
102         port_settings = PortSettings(name='foo-port', network_name='bar-net')
103         fip_settings = FloatingIpSettings(name='foo-fip', port_name='bar-port', router_name='foo-bar-router')
104
105         settings = VmInstanceSettings(name='foo', flavor='bar', port_settings=[port_settings],
106                                       security_group_names=['sec_grp_1'], floating_ip_settings=[fip_settings],
107                                       sudo_user='joe', vm_boot_timeout=999, vm_delete_timeout=333,
108                                       ssh_connect_timeout=111, availability_zone='server name')
109         self.assertEqual('foo', settings.name)
110         self.assertEqual('bar', settings.flavor)
111         self.assertEqual(1, len(settings.port_settings))
112         self.assertEqual('foo-port', settings.port_settings[0].name)
113         self.assertEqual('bar-net', settings.port_settings[0].network_name)
114         self.assertEqual(1, len(settings.security_group_names))
115         self.assertEqual('sec_grp_1', settings.security_group_names[0])
116         self.assertEqual(1, len(settings.floating_ip_settings))
117         self.assertEqual('foo-fip', settings.floating_ip_settings[0].name)
118         self.assertEqual('bar-port', settings.floating_ip_settings[0].port_name)
119         self.assertEqual('foo-bar-router', settings.floating_ip_settings[0].router_name)
120         self.assertEqual('joe', settings.sudo_user)
121         self.assertEqual(999, settings.vm_boot_timeout)
122         self.assertEqual(333, settings.vm_delete_timeout)
123         self.assertEqual(111, settings.ssh_connect_timeout)
124         self.assertEqual('server name', settings.availability_zone)
125
126     def test_config_all(self):
127         port_settings = PortSettings(name='foo-port', network_name='bar-net')
128         fip_settings = FloatingIpSettings(name='foo-fip', port_name='bar-port', router_name='foo-bar-router')
129
130         settings = VmInstanceSettings(config={'name': 'foo', 'flavor': 'bar', 'ports': [port_settings],
131                                               'security_group_names': ['sec_grp_1'],
132                                               'floating_ips': [fip_settings], 'sudo_user': 'joe',
133                                               'vm_boot_timeout': 999, 'vm_delete_timeout': 333,
134                                               'ssh_connect_timeout': 111, 'availability_zone': 'server name'})
135         self.assertEqual('foo', settings.name)
136         self.assertEqual('bar', settings.flavor)
137         self.assertEqual(1, len(settings.port_settings))
138         self.assertEqual('foo-port', settings.port_settings[0].name)
139         self.assertEqual('bar-net', settings.port_settings[0].network_name)
140         self.assertEqual(1, len(settings.security_group_names))
141         self.assertEqual(1, len(settings.floating_ip_settings))
142         self.assertEqual('foo-fip', settings.floating_ip_settings[0].name)
143         self.assertEqual('bar-port', settings.floating_ip_settings[0].port_name)
144         self.assertEqual('foo-bar-router', settings.floating_ip_settings[0].router_name)
145         self.assertEqual('joe', settings.sudo_user)
146         self.assertEqual(999, settings.vm_boot_timeout)
147         self.assertEqual(333, settings.vm_delete_timeout)
148         self.assertEqual(111, settings.ssh_connect_timeout)
149         self.assertEqual('server name', settings.availability_zone)
150
151
152 class FloatingIpSettingsUnitTests(unittest.TestCase):
153     """
154     Tests the construction of the FloatingIpSettings class
155     """
156
157     def test_no_params(self):
158         with self.assertRaises(Exception):
159             FloatingIpSettings()
160
161     def test_empty_config(self):
162         with self.assertRaises(Exception):
163             FloatingIpSettings(config=dict())
164
165     def test_name_only(self):
166         with self.assertRaises(Exception):
167             FloatingIpSettings(name='foo')
168
169     def test_config_with_name_only(self):
170         with self.assertRaises(Exception):
171             FloatingIpSettings(config={'name': 'foo'})
172
173     def test_name_port_only(self):
174         with self.assertRaises(Exception):
175             FloatingIpSettings(name='foo', port_name='bar')
176
177     def test_config_with_name_port_only(self):
178         with self.assertRaises(Exception):
179             FloatingIpSettings(config={'name': 'foo', 'port_name': 'bar'})
180
181     def test_name_router_only(self):
182         with self.assertRaises(Exception):
183             FloatingIpSettings(name='foo', router_name='bar')
184
185     def test_config_with_name_router_only(self):
186         with self.assertRaises(Exception):
187             FloatingIpSettings(config={'name': 'foo', 'router_name': 'bar'})
188
189     def test_name_port_router_only(self):
190         settings = FloatingIpSettings(name='foo', port_name='foo-port', router_name='bar-router')
191         self.assertEqual('foo', settings.name)
192         self.assertEqual('foo-port', settings.port_name)
193         self.assertEqual('bar-router', settings.router_name)
194         self.assertIsNone(settings.subnet_name)
195         self.assertTrue(settings.provisioning)
196
197     def test_config_with_name_port_router_only(self):
198         settings = FloatingIpSettings(config={'name': 'foo', 'port_name': 'foo-port', 'router_name': 'bar-router'})
199         self.assertEqual('foo', settings.name)
200         self.assertEqual('foo-port', settings.port_name)
201         self.assertEqual('bar-router', settings.router_name)
202         self.assertIsNone(settings.subnet_name)
203         self.assertTrue(settings.provisioning)
204
205     def test_all(self):
206         settings = FloatingIpSettings(name='foo', port_name='foo-port', router_name='bar-router',
207                                       subnet_name='bar-subnet', provisioning=False)
208         self.assertEqual('foo', settings.name)
209         self.assertEqual('foo-port', settings.port_name)
210         self.assertEqual('bar-router', settings.router_name)
211         self.assertEqual('bar-subnet', settings.subnet_name)
212         self.assertFalse(settings.provisioning)
213
214     def test_config_all(self):
215         settings = FloatingIpSettings(config={'name': 'foo', 'port_name': 'foo-port', 'router_name': 'bar-router',
216                                               'subnet_name': 'bar-subnet', 'provisioning': False})
217         self.assertEqual('foo', settings.name)
218         self.assertEqual('foo-port', settings.port_name)
219         self.assertEqual('bar-router', settings.router_name)
220         self.assertEqual('bar-subnet', settings.subnet_name)
221         self.assertFalse(settings.provisioning)
222
223
224 class SimpleHealthCheck(OSIntegrationTestCase):
225     """
226     Test for the CreateInstance class with a single NIC/Port with Floating IPs
227     """
228
229     def setUp(self):
230         """
231         Instantiates the CreateImage object that is responsible for downloading and creating an OS image file
232         within OpenStack
233         """
234         super(self.__class__, self).__start__()
235
236         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
237         self.keypair_priv_filepath = 'tmp/' + guid
238         self.keypair_pub_filepath = self.keypair_priv_filepath + '.pub'
239         self.keypair_name = guid + '-kp'
240         self.vm_inst_name = guid + '-inst'
241         self.port_1_name = guid + 'port-1'
242         self.port_2_name = guid + 'port-2'
243         self.floating_ip_name = guid + 'fip1'
244
245         # Initialize for tearDown()
246         self.image_creator = None
247         self.network_creator = None
248         self.flavor_creator = None
249         self.inst_creator = None
250
251         self.priv_net_config = openstack_tests.get_priv_net_config(
252             net_name=guid + '-priv-net', subnet_name=guid + '-priv-subnet')
253         self.port_settings = PortSettings(
254             name=self.port_1_name, network_name=self.priv_net_config.network_settings.name)
255
256         # Create Image
257         # Set the default image settings, then set any custom parameters sent from the app
258         self.os_image_settings = openstack_tests.cirros_image_settings(
259             name=guid + '-image', image_metadata=self.image_metadata)
260
261         try:
262             self.image_creator = OpenStackImage(self.os_creds, self.os_image_settings)
263             self.image_creator.create()
264
265             # Create Network
266             self.network_creator = OpenStackNetwork(self.os_creds, self.priv_net_config.network_settings)
267             self.network_creator.create()
268
269             # Create Flavor
270             self.flavor_creator = OpenStackFlavor(
271                 self.admin_os_creds,
272                 FlavorSettings(name=guid + '-flavor-name', ram=128, disk=10, vcpus=1, metadata=self.flavor_metadata))
273             self.flavor_creator.create()
274         except Exception as e:
275             self.tearDown()
276             raise e
277
278     def tearDown(self):
279         """
280         Cleans the created object
281         """
282         if self.inst_creator:
283             try:
284                 self.inst_creator.clean()
285             except Exception as e:
286                 logger.error('Unexpected exception cleaning VM instance with message - ' + str(e))
287
288         if os.path.isfile(self.keypair_pub_filepath):
289             os.remove(self.keypair_pub_filepath)
290
291         if os.path.isfile(self.keypair_priv_filepath):
292             os.remove(self.keypair_priv_filepath)
293
294         if self.network_creator:
295             try:
296                 self.network_creator.clean()
297             except Exception as e:
298                 logger.error('Unexpected exception cleaning network with message - ' + str(e))
299
300         if self.flavor_creator:
301             try:
302                 self.flavor_creator.clean()
303             except Exception as e:
304                 logger.error('Unexpected exception cleaning flavor with message - ' + str(e))
305
306         if self.image_creator:
307             try:
308                 self.image_creator.clean()
309             except Exception as e:
310                 logger.error('Unexpected exception cleaning image with message - ' + str(e))
311
312         super(self.__class__, self).__clean__()
313
314     def test_check_vm_ip_dhcp(self):
315         """
316         Tests the creation of an OpenStack instance with a single port and ensures that it's assigned IP address is
317         the actual.
318         """
319         instance_settings = VmInstanceSettings(
320             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[self.port_settings])
321
322         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings,
323                                                 self.image_creator.image_settings)
324         vm = self.inst_creator.create()
325
326         ip = self.inst_creator.get_port_ip(self.port_settings.name)
327         self.assertIsNotNone(ip)
328
329         self.assertTrue(self.inst_creator.vm_active(block=True))
330
331         found = False
332         timeout = 160
333         start_time = time.time()
334
335         logger.info("Looking for IP %s in the console log" % ip)
336         full_log = ''
337         while timeout > time.time() - start_time:
338             output = vm.get_console_output()
339             full_log = full_log + output
340             if re.search(ip, output):
341                 logger.info('DHCP lease obtained logged in console')
342                 found = True
343                 break
344
345         if not found:
346             logger.error('Full console output -\n' + full_log)
347         else:
348             logger.debug('Full console output -\n' + full_log)
349
350         self.assertTrue(found)
351
352
353 class CreateInstanceSimpleTests(OSIntegrationTestCase):
354     """
355     Simple instance creation tests without any other objects
356     """
357     def setUp(self):
358         """
359         Instantiates the CreateImage object that is responsible for downloading and creating an OS image file
360         within OpenStack
361         """
362         super(self.__class__, self).__start__()
363
364         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
365         self.vm_inst_name = guid + '-inst'
366         self.nova = nova_utils.nova_client(self.os_creds)
367         self.os_image_settings = openstack_tests.cirros_image_settings(
368             name=guid + '-image', image_metadata=self.image_metadata)
369
370         net_config = openstack_tests.get_priv_net_config(
371             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
372             router_name=guid + '-pub-router', external_net=self.ext_net_name)
373
374         # Initialize for tearDown()
375         self.image_creator = None
376         self.flavor_creator = None
377
378         self.network_creator = None
379         self.inst_creator = None
380
381         try:
382             # Create Image
383             self.image_creator = OpenStackImage(self.os_creds, self.os_image_settings)
384             self.image_creator.create()
385
386             # Create Flavor
387             self.flavor_creator = OpenStackFlavor(
388                 self.admin_os_creds,
389                 FlavorSettings(name=guid + '-flavor-name', ram=128, disk=10, vcpus=2, metadata=self.flavor_metadata))
390             self.flavor_creator.create()
391
392             # Create Network
393             self.network_creator = OpenStackNetwork(self.os_creds, net_config.network_settings)
394             self.network_creator.create()
395
396             self.port_settings = PortSettings(name=guid + '-port',
397                                               network_name=net_config.network_settings.name)
398
399         except Exception as e:
400             self.tearDown()
401             raise e
402
403     def tearDown(self):
404         """
405         Cleans the created object
406         """
407         if self.inst_creator:
408             try:
409                 self.inst_creator.clean()
410             except Exception as e:
411                 logger.error('Unexpected exception cleaning VM instance with message - ' + str(e))
412
413         if self.flavor_creator:
414             try:
415                 self.flavor_creator.clean()
416             except Exception as e:
417                 logger.error('Unexpected exception cleaning flavor with message - ' + str(e))
418
419         if self.network_creator:
420             try:
421                 self.network_creator.clean()
422             except Exception as e:
423                 logger.error('Unexpected exception cleaning network with message - ' + str(e))
424
425         if self.image_creator:
426             try:
427                 self.image_creator.clean()
428             except Exception as e:
429                 logger.error('Unexpected exception cleaning image with message - ' + str(e))
430
431         super(self.__class__, self).__clean__()
432
433     def test_create_delete_instance(self):
434         """
435         Tests the creation of an OpenStack instance with a single port with a static IP without a Floating IP.
436         """
437         instance_settings = VmInstanceSettings(name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name,
438                                                port_settings=[self.port_settings])
439
440         self.inst_creator = OpenStackVmInstance(
441             self.os_creds, instance_settings, self.image_creator.image_settings)
442
443         vm_inst = self.inst_creator.create()
444         self.assertEqual(1, len(nova_utils.get_servers_by_name(self.nova, instance_settings.name)))
445
446         # Delete instance
447         nova_utils.delete_vm_instance(self.nova, vm_inst)
448
449         self.assertTrue(self.inst_creator.vm_deleted(block=True))
450         self.assertEqual(0, len(nova_utils.get_servers_by_name(self.nova, instance_settings.name)))
451
452         # Exception should not be thrown
453         self.inst_creator.clean()
454
455
456 class CreateInstanceSingleNetworkTests(OSIntegrationTestCase):
457     """
458     Test for the CreateInstance class with a single NIC/Port with Floating IPs
459     """
460
461     def setUp(self):
462         """
463         Instantiates the CreateImage object that is responsible for downloading and creating an OS image file
464         within OpenStack
465         """
466         super(self.__class__, self).__start__()
467
468         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
469         self.keypair_priv_filepath = 'tmp/' + guid
470         self.keypair_pub_filepath = self.keypair_priv_filepath + '.pub'
471         self.keypair_name = guid + '-kp'
472         self.vm_inst_name = guid + '-inst'
473         self.port_1_name = guid + 'port-1'
474         self.port_2_name = guid + 'port-2'
475         self.floating_ip_name = guid + 'fip1'
476
477         # Initialize for tearDown()
478         self.image_creator = None
479         self.network_creator = None
480         self.router_creator = None
481         self.flavor_creator = None
482         self.keypair_creator = None
483         self.inst_creators = list()
484
485         self.pub_net_config = openstack_tests.get_pub_net_config(
486             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
487             router_name=guid + '-pub-router', external_net=self.ext_net_name)
488         self.os_image_settings = openstack_tests.cirros_image_settings(
489             name=guid + '-image', image_metadata=self.image_metadata)
490         try:
491             # Create Image
492             self.image_creator = OpenStackImage(self.os_creds, self.os_image_settings)
493             self.image_creator.create()
494
495             # Create Network
496             self.network_creator = OpenStackNetwork(self.os_creds, self.pub_net_config.network_settings)
497             self.network_creator.create()
498
499             # Create Router
500             self.router_creator = OpenStackRouter(self.os_creds, self.pub_net_config.router_settings)
501             self.router_creator.create()
502
503             # Create Flavor
504             self.flavor_creator = OpenStackFlavor(
505                 self.admin_os_creds,
506                 FlavorSettings(name=guid + '-flavor-name', ram=128, disk=10, vcpus=2, metadata=self.flavor_metadata))
507             self.flavor_creator.create()
508
509             self.keypair_creator = OpenStackKeypair(
510                 self.os_creds, KeypairSettings(
511                     name=self.keypair_name, public_filepath=self.keypair_pub_filepath,
512                     private_filepath=self.keypair_priv_filepath))
513             self.keypair_creator.create()
514         except Exception as e:
515             self.tearDown()
516             raise e
517
518     def tearDown(self):
519         """
520         Cleans the created object
521         """
522         for inst_creator in self.inst_creators:
523             try:
524                 inst_creator.clean()
525             except Exception as e:
526                 logger.error('Unexpected exception cleaning VM instance with message - ' + str(e))
527
528         if self.keypair_creator:
529             try:
530                 self.keypair_creator.clean()
531             except Exception as e:
532                 logger.error('Unexpected exception cleaning keypair with message - ' + str(e))
533
534         if os.path.isfile(self.keypair_pub_filepath):
535             os.remove(self.keypair_pub_filepath)
536
537         if os.path.isfile(self.keypair_priv_filepath):
538             os.remove(self.keypair_priv_filepath)
539
540         if self.flavor_creator:
541             try:
542                 self.flavor_creator.clean()
543             except Exception as e:
544                 logger.error('Unexpected exception cleaning flavor with message - ' + str(e))
545
546         if self.router_creator:
547             try:
548                 self.router_creator.clean()
549             except Exception as e:
550                 logger.error('Unexpected exception cleaning router with message - ' + str(e))
551
552         if self.network_creator:
553             try:
554                 self.network_creator.clean()
555             except Exception as e:
556                 logger.error('Unexpected exception cleaning network with message - ' + str(e))
557
558         if self.image_creator:
559             try:
560                 self.image_creator.clean()
561             except Exception as e:
562                 logger.error('Unexpected exception cleaning image with message - ' + str(e))
563
564         super(self.__class__, self).__clean__()
565
566     def test_single_port_static(self):
567         """
568         Tests the creation of an OpenStack instance with a single port with a static IP without a Floating IP.
569         """
570         ip_1 = '10.55.1.100'
571
572         port_settings = PortSettings(
573             name=self.port_1_name, network_name=self.pub_net_config.network_settings.name,
574             ip_addrs=[{'subnet_name': self.pub_net_config.network_settings.subnet_settings[0].name, 'ip': ip_1}])
575
576         instance_settings = VmInstanceSettings(
577             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings],
578             floating_ip_settings=[FloatingIpSettings(
579                 name=self.floating_ip_name, port_name=self.port_1_name,
580                 router_name=self.pub_net_config.router_settings.name)])
581
582         inst_creator = OpenStackVmInstance(
583             self.os_creds, instance_settings, self.image_creator.image_settings,
584             keypair_settings=self.keypair_creator.keypair_settings)
585         self.inst_creators.append(inst_creator)
586         vm_inst = inst_creator.create()
587
588         self.assertEqual(ip_1, inst_creator.get_port_ip(self.port_1_name))
589         self.assertTrue(inst_creator.vm_active(block=True))
590         self.assertEqual(vm_inst, inst_creator.get_vm_inst())
591
592     def test_ssh_client_fip_before_active(self):
593         """
594         Tests the ability to access a VM via SSH and a floating IP when it has been assigned prior to being active.
595         """
596         port_settings = PortSettings(
597             name=self.port_1_name, network_name=self.pub_net_config.network_settings.name)
598
599         instance_settings = VmInstanceSettings(
600             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings],
601             floating_ip_settings=[FloatingIpSettings(
602                 name=self.floating_ip_name, port_name=self.port_1_name,
603                 router_name=self.pub_net_config.router_settings.name)])
604
605         inst_creator = OpenStackVmInstance(
606             self.os_creds, instance_settings, self.image_creator.image_settings,
607             keypair_settings=self.keypair_creator.keypair_settings)
608         self.inst_creators.append(inst_creator)
609         vm_inst = inst_creator.create()
610         self.assertIsNotNone(vm_inst)
611
612         self.assertTrue(inst_creator.vm_active(block=True))
613         self.assertEqual(vm_inst, inst_creator.get_vm_inst())
614
615         self.assertTrue(validate_ssh_client(inst_creator))
616
617     def test_ssh_client_fip_after_active(self):
618         """
619         Tests the ability to access a VM via SSH and a floating IP when it has been assigned prior to being active.
620         """
621         port_settings = PortSettings(
622             name=self.port_1_name, network_name=self.pub_net_config.network_settings.name)
623
624         instance_settings = VmInstanceSettings(
625             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings],
626             floating_ip_settings=[FloatingIpSettings(
627                 name=self.floating_ip_name, port_name=self.port_1_name,
628                 router_name=self.pub_net_config.router_settings.name)])
629
630         inst_creator = OpenStackVmInstance(
631             self.os_creds, instance_settings, self.image_creator.image_settings,
632             keypair_settings=self.keypair_creator.keypair_settings)
633         self.inst_creators.append(inst_creator)
634
635         # block=True will force the create() method to block until the
636         vm_inst = inst_creator.create(block=True)
637         self.assertIsNotNone(vm_inst)
638
639         self.assertTrue(inst_creator.vm_active(block=True))
640         self.assertEqual(vm_inst, inst_creator.get_vm_inst())
641
642         self.assertTrue(validate_ssh_client(inst_creator))
643
644
645 class CreateInstancePortManipulationTests(OSIntegrationTestCase):
646     """
647     Test for the CreateInstance class with a single NIC/Port where mac and IP values are manually set
648     """
649
650     def setUp(self):
651         """
652         Instantiates the CreateImage object that is responsible for downloading and creating an OS image file
653         within OpenStack
654         """
655         super(self.__class__, self).__start__()
656
657         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
658         self.vm_inst_name = guid + '-inst'
659         self.port_1_name = guid + 'port-1'
660         self.port_2_name = guid + 'port-2'
661         self.floating_ip_name = guid + 'fip1'
662
663         # Initialize for tearDown()
664         self.image_creator = None
665         self.network_creator = None
666         self.flavor_creator = None
667         self.inst_creator = None
668
669         self.net_config = openstack_tests.get_priv_net_config(
670             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
671             router_name=guid + '-pub-router', external_net=self.ext_net_name)
672         self.os_image_settings = openstack_tests.cirros_image_settings(
673             name=guid + '-image', image_metadata=self.image_metadata)
674
675         try:
676             # Create Image
677             self.image_creator = OpenStackImage(self.os_creds, self.os_image_settings)
678             self.image_creator.create()
679
680             # Create Network
681             self.network_creator = OpenStackNetwork(self.os_creds, self.net_config.network_settings)
682             self.network_creator.create()
683
684             # Create Flavor
685             self.flavor_creator = OpenStackFlavor(
686                 self.admin_os_creds,
687                 FlavorSettings(name=guid + '-flavor-name', ram=128, disk=10, vcpus=2, metadata=self.flavor_metadata))
688             self.flavor_creator.create()
689         except Exception as e:
690             self.tearDown()
691             raise e
692
693     def tearDown(self):
694         """
695         Cleans the created object
696         """
697         if self.inst_creator:
698             try:
699                 self.inst_creator.clean()
700             except Exception as e:
701                 logger.error('Unexpected exception cleaning VM instance with message - ' + str(e))
702
703         if self.flavor_creator:
704             try:
705                 self.flavor_creator.clean()
706             except Exception as e:
707                 logger.error('Unexpected exception cleaning flavor with message - ' + str(e))
708
709         if self.network_creator:
710             try:
711                 self.network_creator.clean()
712             except Exception as e:
713                 logger.error('Unexpected exception cleaning network with message - ' + str(e))
714
715         if self.image_creator:
716             try:
717                 self.image_creator.clean()
718             except Exception as e:
719                 logger.error('Unexpected exception cleaning image with message - ' + str(e))
720
721         super(self.__class__, self).__clean__()
722
723     def test_set_custom_valid_ip_one_subnet(self):
724         """
725         Tests the creation of an OpenStack instance with a single port with a static IP on a network with one subnet.
726         """
727         ip = '10.55.0.101'
728         port_settings = PortSettings(
729             name=self.port_1_name, network_name=self.net_config.network_settings.name,
730             ip_addrs=[{'subnet_name': self.net_config.network_settings.subnet_settings[0].name, 'ip': ip}])
731
732         instance_settings = VmInstanceSettings(
733             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
734
735         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings,
736                                                 self.image_creator.image_settings)
737         self.inst_creator.create(block=True)
738
739         self.assertEqual(ip, self.inst_creator.get_port_ip(
740             self.port_1_name, subnet_name=self.net_config.network_settings.subnet_settings[0].name))
741
742     def test_set_custom_invalid_ip_one_subnet(self):
743         """
744         Tests the creation of an OpenStack instance with a single port with a static IP on a network with one subnet.
745         """
746         ip = '10.66.0.101'
747         port_settings = PortSettings(
748             name=self.port_1_name, network_name=self.net_config.network_settings.name,
749             ip_addrs=[{'subnet_name': self.net_config.network_settings.subnet_settings[0].name, 'ip': ip}])
750
751         instance_settings = VmInstanceSettings(
752             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
753
754         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings,
755                                                 self.image_creator.image_settings)
756
757         with self.assertRaises(Exception):
758             self.inst_creator.create()
759
760     def test_set_custom_valid_mac(self):
761         """
762         Tests the creation of an OpenStack instance with a single port where the MAC address is assigned.
763         """
764         mac_addr = '0a:1b:2c:3d:4e:5f'
765         port_settings = PortSettings(
766             name=self.port_1_name, network_name=self.net_config.network_settings.name, mac_address=mac_addr)
767
768         instance_settings = VmInstanceSettings(
769             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
770
771         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings,
772                                                 self.image_creator.image_settings)
773         self.inst_creator.create(block=True)
774
775         self.assertEqual(mac_addr, self.inst_creator.get_port_mac(self.port_1_name))
776
777     def test_set_custom_invalid_mac(self):
778         """
779         Tests the creation of an OpenStack instance with a single port where an invalid MAC address value is being
780         assigned. This should raise an Exception
781         """
782         port_settings = PortSettings(
783             name=self.port_1_name, network_name=self.net_config.network_settings.name, mac_address='foo')
784
785         instance_settings = VmInstanceSettings(
786             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
787
788         self.inst_creator = OpenStackVmInstance(
789             self.os_creds, instance_settings, self.image_creator.image_settings)
790
791         with self.assertRaises(Exception):
792             self.inst_creator.create()
793
794     def test_set_custom_mac_and_ip(self):
795         """
796         Tests the creation of an OpenStack instance with a single port where the IP and MAC address is assigned.
797         """
798         ip = '10.55.0.101'
799         mac_addr = '0a:1b:2c:3d:4e:5f'
800         port_settings = PortSettings(
801             name=self.port_1_name, network_name=self.net_config.network_settings.name, mac_address=mac_addr,
802             ip_addrs=[{'subnet_name': self.net_config.network_settings.subnet_settings[0].name, 'ip': ip}])
803
804         instance_settings = VmInstanceSettings(
805             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
806
807         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings,
808                                                 self.image_creator.image_settings)
809         self.inst_creator.create(block=True)
810
811         self.assertEqual(ip, self.inst_creator.get_port_ip(
812             self.port_1_name, subnet_name=self.net_config.network_settings.subnet_settings[0].name))
813         self.assertEqual(mac_addr, self.inst_creator.get_port_mac(self.port_1_name))
814
815     def test_set_allowed_address_pairs(self):
816         """
817         Tests the creation of an OpenStack instance with a single port where max_allowed_address_pair is set.
818         """
819         ip = '10.55.0.101'
820         mac_addr = '0a:1b:2c:3d:4e:5f'
821         pair = {'ip_address': ip, 'mac_address': mac_addr}
822         port_settings = PortSettings(
823             name=self.port_1_name, network_name=self.net_config.network_settings.name, allowed_address_pairs=[pair])
824
825         instance_settings = VmInstanceSettings(
826             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
827
828         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings,
829                                                 self.image_creator.image_settings)
830         self.inst_creator.create(block=True)
831
832         port = self.inst_creator.get_port_by_name(port_settings.name)
833         self.assertIsNotNone(port)
834         self.assertIsNotNone(port['port'].get('allowed_address_pairs'))
835         self.assertEqual(1, len(port['port']['allowed_address_pairs']))
836         validation_utils.objects_equivalent(pair, port['port']['allowed_address_pairs'][0])
837
838     def test_set_allowed_address_pairs_bad_mac(self):
839         """
840         Tests the creation of an OpenStack instance with a single port where max_allowed_address_pair is set with an
841         invalid MAC address.
842         """
843         ip = '10.55.0.101'
844         mac_addr = 'foo'
845         pair = {'ip_address': ip, 'mac_address': mac_addr}
846         pairs = set()
847         pairs.add((ip, mac_addr))
848         port_settings = PortSettings(
849             name=self.port_1_name, network_name=self.net_config.network_settings.name, allowed_address_pairs=[pair])
850
851         instance_settings = VmInstanceSettings(
852             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
853
854         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings,
855                                                 self.image_creator.image_settings)
856         with self.assertRaises(Exception):
857             self.inst_creator.create()
858
859     def test_set_allowed_address_pairs_bad_ip(self):
860         """
861         Tests the creation of an OpenStack instance with a single port where max_allowed_address_pair is set with an
862         invalid MAC address.
863         """
864         ip = 'foo'
865         mac_addr = '0a:1b:2c:3d:4e:5f'
866         pair = {'ip_address': ip, 'mac_address': mac_addr}
867         pairs = set()
868         pairs.add((ip, mac_addr))
869         port_settings = PortSettings(
870             name=self.port_1_name, network_name=self.net_config.network_settings.name, allowed_address_pairs=[pair])
871
872         instance_settings = VmInstanceSettings(
873             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
874
875         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings,
876                                                 self.image_creator.image_settings)
877         with self.assertRaises(Exception):
878             self.inst_creator.create()
879
880
881 class CreateInstanceOnComputeHost(OSIntegrationTestCase):
882     """
883     Test for the CreateInstance where one VM is deployed to each compute node
884     """
885
886     def setUp(self):
887         """
888         Instantiates the CreateImage object that is responsible for downloading and creating an OS image file
889         within OpenStack
890         """
891         super(self.__class__, self).__start__()
892
893         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
894         self.vm_inst_name = guid + '-inst'
895         self.port_base_name = guid + 'port'
896
897         # Initialize for tearDown()
898         self.image_creator = None
899         self.flavor_creator = None
900         self.network_creator = None
901         self.inst_creators = list()
902
903         self.priv_net_config = openstack_tests.get_priv_net_config(
904             net_name=guid + '-priv-net', subnet_name=guid + '-priv-subnet')
905
906         self.os_image_settings = openstack_tests.cirros_image_settings(
907             name=guid + '-image', image_metadata=self.image_metadata)
908
909         try:
910             # Create Network
911             self.network_creator = OpenStackNetwork(self.admin_os_creds, self.priv_net_config.network_settings)
912             self.network_creator.create()
913
914             # Create Flavor
915             self.flavor_creator = OpenStackFlavor(
916                 self.admin_os_creds,
917                 FlavorSettings(name=guid + '-flavor-name', ram=512, disk=1, vcpus=1, metadata=self.flavor_metadata))
918             self.flavor_creator.create()
919
920             # Create Image
921             self.image_creator = OpenStackImage(self.os_creds, self.os_image_settings)
922             self.image_creator.create()
923
924         except Exception as e:
925             self.tearDown()
926             raise e
927
928     def tearDown(self):
929         """
930         Cleans the created object
931         """
932         for inst_creator in self.inst_creators:
933             try:
934                 inst_creator.clean()
935             except Exception as e:
936                 logger.error('Unexpected exception cleaning VM instance with message - ' + str(e))
937
938         if self.flavor_creator:
939             try:
940                 self.flavor_creator.clean()
941             except Exception as e:
942                 logger.error('Unexpected exception cleaning flavor with message - ' + str(e))
943
944         if self.network_creator:
945             try:
946                 self.network_creator.clean()
947             except Exception as e:
948                 logger.error('Unexpected exception cleaning network with message - ' + str(e))
949
950         if self.image_creator:
951             try:
952                 self.image_creator.clean()
953             except Exception as e:
954                 logger.error('Unexpected exception cleaning image with message - ' + str(e))
955
956         super(self.__class__, self).__clean__()
957
958     def test_deploy_vm_to_each_compute_node(self):
959         """
960         Tests the creation of OpenStack VM instances to each compute node.
961         """
962         from snaps.openstack.utils import nova_utils
963         nova = nova_utils.nova_client(self.admin_os_creds)
964         zones = nova_utils.get_nova_availability_zones(nova)
965
966         # Create Instance on each server/zone
967         ctr = 0
968         for zone in zones:
969             inst_name = self.vm_inst_name + '-' + zone
970             ctr += 1
971             port_settings = PortSettings(name=self.port_base_name + '-' + str(ctr),
972                                          network_name=self.priv_net_config.network_settings.name)
973
974             instance_settings = VmInstanceSettings(
975                 name=inst_name, flavor=self.flavor_creator.flavor_settings.name, availability_zone=zone,
976                 port_settings=[port_settings])
977             inst_creator = OpenStackVmInstance(
978                 self.admin_os_creds, instance_settings, self.image_creator.image_settings)
979             self.inst_creators.append(inst_creator)
980             inst_creator.create()
981
982         # Validate instances to ensure they've been deployed to the correct server
983         index = 0
984         for zone in zones:
985             creator = self.inst_creators[index]
986             self.assertTrue(creator.vm_active(block=True))
987             vm = creator.get_vm_inst()
988             deployed_zone = vm._info['OS-EXT-AZ:availability_zone']
989             deployed_host = vm._info['OS-EXT-SRV-ATTR:host']
990             self.assertEqual(zone, deployed_zone + ':' + deployed_host)
991             index += 1
992
993
994 class CreateInstancePubPrivNetTests(OSIntegrationTestCase):
995     """
996     Test for the CreateInstance class with two NIC/Ports, eth0 with floating IP and eth1 w/o
997     These tests require a Centos image
998     """
999
1000     def setUp(self):
1001         """
1002         Instantiates the CreateImage object that is responsible for downloading and creating an OS image file
1003         within OpenStack
1004         """
1005         super(self.__class__, self).__start__()
1006
1007         # Initialize for tearDown()
1008         self.image_creator = None
1009         self.network_creators = list()
1010         self.router_creators = list()
1011         self.flavor_creator = None
1012         self.keypair_creator = None
1013         self.inst_creator = None
1014
1015         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1016         self.keypair_priv_filepath = 'tmp/' + self.guid
1017         self.keypair_pub_filepath = self.keypair_priv_filepath + '.pub'
1018         self.keypair_name = self.guid + '-kp'
1019         self.vm_inst_name = self.guid + '-inst'
1020         self.port_1_name = self.guid + '-port-1'
1021         self.port_2_name = self.guid + '-port-2'
1022         self.floating_ip_name = self.guid + 'fip1'
1023         self.priv_net_config = openstack_tests.get_priv_net_config(
1024             net_name=self.guid + '-priv-net', subnet_name=self.guid + '-priv-subnet',
1025             router_name=self.guid + '-priv-router', external_net=self.ext_net_name)
1026         self.pub_net_config = openstack_tests.get_pub_net_config(
1027             net_name=self.guid + '-pub-net', subnet_name=self.guid + '-pub-subnet',
1028             router_name=self.guid + '-pub-router', external_net=self.ext_net_name)
1029
1030         image_name = self.__class__.__name__ + '-' + str(uuid.uuid4())
1031         self.os_image_settings = openstack_tests.centos_image_settings(name=image_name,
1032                                                                        image_metadata=self.image_metadata)
1033
1034         try:
1035             # Create Image
1036             self.image_creator = OpenStackImage(self.os_creds, self.os_image_settings)
1037             self.image_creator.create()
1038
1039             # First network is public
1040             self.network_creators.append(OpenStackNetwork(self.os_creds, self.pub_net_config.network_settings))
1041             # Second network is private
1042             self.network_creators.append(OpenStackNetwork(self.os_creds, self.priv_net_config.network_settings))
1043             for network_creator in self.network_creators:
1044                 network_creator.create()
1045
1046             self.router_creators.append(OpenStackRouter(self.os_creds, self.pub_net_config.router_settings))
1047             self.router_creators.append(OpenStackRouter(self.os_creds, self.priv_net_config.router_settings))
1048
1049             # Create Routers
1050             for router_creator in self.router_creators:
1051                 router_creator.create()
1052
1053             # Create Flavor
1054             self.flavor_creator = OpenStackFlavor(
1055                 self.admin_os_creds,
1056                 FlavorSettings(name=self.guid + '-flavor-name', ram=512, disk=10, vcpus=2,
1057                                metadata=self.flavor_metadata))
1058             self.flavor_creator.create()
1059
1060             # Create Keypair
1061             self.keypair_creator = OpenStackKeypair(
1062                 self.os_creds, KeypairSettings(
1063                     name=self.keypair_name, public_filepath=self.keypair_pub_filepath,
1064                     private_filepath=self.keypair_priv_filepath))
1065             self.keypair_creator.create()
1066         except Exception as e:
1067             self.tearDown()
1068             raise Exception(str(e))
1069
1070     def tearDown(self):
1071         """
1072         Cleans the created objects
1073         """
1074         if self.inst_creator:
1075             try:
1076                 self.inst_creator.clean()
1077             except Exception as e:
1078                 logger.error('Unexpected exception cleaning VM instance with message - ' + str(e))
1079
1080         if self.keypair_creator:
1081             try:
1082                 self.keypair_creator.clean()
1083             except Exception as e:
1084                 logger.error('Unexpected exception cleaning keypair with message - ' + str(e))
1085
1086         if os.path.isfile(self.keypair_pub_filepath):
1087             os.remove(self.keypair_pub_filepath)
1088
1089         if os.path.isfile(self.keypair_priv_filepath):
1090             os.remove(self.keypair_priv_filepath)
1091
1092         if self.flavor_creator:
1093             try:
1094                 self.flavor_creator.clean()
1095             except Exception as e:
1096                 logger.error('Unexpected exception cleaning flavor with message - ' + str(e))
1097
1098         for router_creator in self.router_creators:
1099             try:
1100                 router_creator.clean()
1101             except Exception as e:
1102                 logger.error('Unexpected exception cleaning router with message - ' + str(e))
1103
1104         for network_creator in self.network_creators:
1105             try:
1106                 network_creator.clean()
1107             except Exception as e:
1108                 logger.error('Unexpected exception cleaning network with message - ' + str(e))
1109
1110         if self.image_creator:
1111             try:
1112                 self.image_creator.clean()
1113             except Exception as e:
1114                 logger.error('Unexpected exception cleaning image with message - ' + str(e))
1115
1116         super(self.__class__, self).__clean__()
1117
1118     def test_dual_ports_dhcp(self):
1119         """
1120         Tests the creation of an OpenStack instance with a dual ports/NICs with a DHCP assigned IP.
1121         NOTE: This test and any others that call ansible will most likely fail unless you do one of
1122         two things:
1123         1. Have a ~/.ansible.cfg (or alternate means) to set host_key_checking = False
1124         2. Set the following environment variable in your executing shell: ANSIBLE_HOST_KEY_CHECKING=False
1125         Should this not be performed, the creation of the host ssh key will cause your ansible calls to fail.
1126         """
1127         # Create ports/NICs for instance
1128         ports_settings = []
1129         ctr = 1
1130         for network_creator in self.network_creators:
1131             ports_settings.append(PortSettings(
1132                 name=self.guid + '-port-' + str(ctr),
1133                 network_name=network_creator.network_settings.name))
1134             ctr += 1
1135
1136         # Create instance
1137         instance_settings = VmInstanceSettings(
1138             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=ports_settings,
1139             floating_ip_settings=[FloatingIpSettings(
1140                 name=self.floating_ip_name, port_name=self.port_1_name,
1141                 router_name=self.pub_net_config.router_settings.name)])
1142
1143         self.inst_creator = OpenStackVmInstance(
1144             self.os_creds, instance_settings, self.image_creator.image_settings,
1145             keypair_settings=self.keypair_creator.keypair_settings)
1146
1147         vm_inst = self.inst_creator.create(block=True)
1148
1149         self.assertEqual(vm_inst, self.inst_creator.get_vm_inst())
1150
1151         # Effectively blocks until VM has been properly activated
1152         self.assertTrue(self.inst_creator.vm_active(block=True))
1153
1154         # Effectively blocks until VM's ssh port has been opened
1155         self.assertTrue(self.inst_creator.vm_ssh_active(block=True))
1156
1157         # TODO - Refactor config_nics() to return a status that can be validated here.
1158         self.inst_creator.config_nics()
1159
1160         # TODO - *** ADD VALIDATION HERE ***
1161         # TODO - Add validation that both floating IPs work
1162         # TODO - Add tests where only one NIC has a floating IP
1163         # TODO - Add tests where one attempts to place a floating IP on a network/router without an external gateway
1164
1165
1166 class InstanceSecurityGroupTests(OSIntegrationTestCase):
1167     """
1168     Tests that include, add, and remove security groups from VM instances
1169     """
1170     def setUp(self):
1171         """
1172         Instantiates the CreateImage object that is responsible for downloading and creating an OS image file
1173         within OpenStack
1174         """
1175         super(self.__class__, self).__start__()
1176
1177         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1178         self.vm_inst_name = self.guid + '-inst'
1179         self.nova = nova_utils.nova_client(self.os_creds)
1180         self.os_image_settings = openstack_tests.cirros_image_settings(
1181             name=self.guid + '-image', image_metadata=self.image_metadata)
1182
1183         self.vm_inst_name = self.guid + '-inst'
1184         self.port_1_name = self.guid + 'port-1'
1185         self.port_2_name = self.guid + 'port-2'
1186         self.floating_ip_name = self.guid + 'fip1'
1187
1188         net_config = openstack_tests.get_priv_net_config(
1189             net_name=self.guid + '-pub-net', subnet_name=self.guid + '-pub-subnet',
1190             router_name=self.guid + '-pub-router', external_net=self.ext_net_name)
1191
1192         # Initialize for tearDown()
1193         self.image_creator = None
1194         self.flavor_creator = None
1195         self.network_creator = None
1196         self.router_creator = None
1197         self.inst_creator = None
1198         self.sec_grp_creators = list()
1199
1200         try:
1201             # Create Image
1202             self.image_creator = OpenStackImage(self.os_creds, self.os_image_settings)
1203             self.image_creator.create()
1204
1205             # Create Network
1206             self.network_creator = OpenStackNetwork(self.os_creds, net_config.network_settings)
1207             self.network_creator.create()
1208
1209             # Create Flavor
1210             self.flavor_creator = OpenStackFlavor(
1211                 self.admin_os_creds,
1212                 FlavorSettings(name=self.guid + '-flavor-name', ram=128, disk=10, vcpus=2,
1213                                metadata=self.flavor_metadata))
1214             self.flavor_creator.create()
1215
1216             self.port_settings = PortSettings(name=self.guid + '-port',
1217                                               network_name=net_config.network_settings.name)
1218         except Exception as e:
1219             self.tearDown()
1220             raise e
1221
1222     def tearDown(self):
1223         """
1224         Cleans the created object
1225         """
1226         if self.inst_creator:
1227             try:
1228                 self.inst_creator.clean()
1229             except Exception as e:
1230                 logger.error('Unexpected exception cleaning VM instance with message - ' + str(e))
1231
1232         for sec_grp_creator in self.sec_grp_creators:
1233             try:
1234                 sec_grp_creator.clean()
1235             except Exception as e:
1236                 logger.error('Unexpected exception cleaning security group with message - ' + str(e))
1237
1238         if self.flavor_creator:
1239             try:
1240                 self.flavor_creator.clean()
1241             except Exception as e:
1242                 logger.error('Unexpected exception cleaning flavor with message - ' + str(e))
1243
1244         if self.network_creator:
1245             try:
1246                 self.network_creator.clean()
1247             except Exception as e:
1248                 logger.error('Unexpected exception cleaning network with message - ' + str(e))
1249
1250         if self.image_creator:
1251             try:
1252                 self.image_creator.clean()
1253             except Exception as e:
1254                 logger.error('Unexpected exception cleaning image with message - ' + str(e))
1255
1256         super(self.__class__, self).__clean__()
1257
1258     def test_add_security_group(self):
1259         """
1260         Tests the addition of a security group created after the instance.
1261         """
1262         # Create instance
1263         instance_settings = VmInstanceSettings(
1264             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[self.port_settings])
1265         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings,
1266                                                 self.image_creator.image_settings)
1267         vm_inst = self.inst_creator.create(block=True)
1268         self.assertIsNotNone(vm_inst)
1269
1270         # Create security group object to add to instance
1271         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name', description='hello group')
1272         sec_grp_creator = OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
1273         sec_grp = sec_grp_creator.create()
1274         self.sec_grp_creators.append(sec_grp_creator)
1275
1276         # Check that group has not been added
1277         self.assertFalse(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1278
1279         # Add security group to instance after activated
1280         self.inst_creator.add_security_group(sec_grp)
1281
1282         # Validate that security group has been added
1283         self.assertTrue(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1284
1285     def test_add_invalid_security_group(self):
1286         """
1287         Tests the addition of a security group that no longer exists.
1288         """
1289         # Create instance
1290         instance_settings = VmInstanceSettings(
1291             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[self.port_settings])
1292         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings,
1293                                                 self.image_creator.image_settings)
1294         vm_inst = self.inst_creator.create(block=True)
1295         self.assertIsNotNone(vm_inst)
1296
1297         # Create security group object to add to instance
1298         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name', description='hello group')
1299         sec_grp_creator = OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
1300         sec_grp = sec_grp_creator.create()
1301         sec_grp_creator.clean()
1302         self.sec_grp_creators.append(sec_grp_creator)
1303
1304         # Check that group has not been added
1305         self.assertFalse(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1306
1307         # Add security group to instance after activated
1308         self.assertFalse(self.inst_creator.add_security_group(sec_grp))
1309
1310         # Validate that security group has been added
1311         self.assertFalse(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1312
1313     def test_remove_security_group(self):
1314         """
1315         Tests the removal of a security group created before and added to the instance.
1316         """
1317         # Create security group object to add to instance
1318         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name', description='hello group')
1319         sec_grp_creator = OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
1320         sec_grp = sec_grp_creator.create()
1321         self.sec_grp_creators.append(sec_grp_creator)
1322
1323         # Create instance
1324         instance_settings = VmInstanceSettings(
1325             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name,
1326             security_group_names=[sec_grp_settings.name], port_settings=[self.port_settings])
1327         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings,
1328                                                 self.image_creator.image_settings)
1329         vm_inst = self.inst_creator.create(block=True)
1330         self.assertIsNotNone(vm_inst)
1331
1332         # Check that group has been added
1333         self.assertTrue(inst_has_sec_grp(vm_inst, sec_grp_settings.name))
1334
1335         # Add security group to instance after activated
1336         self.assertTrue(self.inst_creator.remove_security_group(sec_grp))
1337
1338         # Validate that security group has been added
1339         self.assertFalse(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1340
1341     def test_remove_security_group_never_added(self):
1342         """
1343         Tests the removal of a security group that was never added in the first place.
1344         """
1345         # Create security group object to add to instance
1346         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name', description='hello group')
1347         sec_grp_creator = OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
1348         sec_grp = sec_grp_creator.create()
1349         self.sec_grp_creators.append(sec_grp_creator)
1350
1351         # Create instance
1352         instance_settings = VmInstanceSettings(
1353             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[self.port_settings])
1354         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings,
1355                                                 self.image_creator.image_settings)
1356         vm_inst = self.inst_creator.create(block=True)
1357         self.assertIsNotNone(vm_inst)
1358
1359         # Check that group has been added
1360         self.assertFalse(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1361
1362         # Add security group to instance after activated
1363         self.assertFalse(self.inst_creator.remove_security_group(sec_grp))
1364
1365         # Validate that security group has been added
1366         self.assertFalse(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1367
1368     def test_add_same_security_group(self):
1369         """
1370         Tests the addition of a security group created before add added to the instance.
1371         """
1372         # Create security group object to add to instance
1373         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name', description='hello group')
1374         sec_grp_creator = OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
1375         sec_grp = sec_grp_creator.create()
1376         self.sec_grp_creators.append(sec_grp_creator)
1377
1378         # Create instance
1379         instance_settings = VmInstanceSettings(
1380             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name,
1381             security_group_names=[sec_grp_settings.name], port_settings=[self.port_settings])
1382         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings,
1383                                                 self.image_creator.image_settings)
1384         vm_inst = self.inst_creator.create(block=True)
1385         self.assertIsNotNone(vm_inst)
1386
1387         # Check that group has been added
1388         self.assertTrue(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1389
1390         # Add security group to instance after activated
1391         self.assertTrue(self.inst_creator.add_security_group(sec_grp))
1392
1393         # Validate that security group has been added
1394         self.assertTrue(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1395
1396
1397 def inst_has_sec_grp(vm_inst, sec_grp_name):
1398     """
1399     Returns true if instance has a security group of a given name
1400     :return:
1401     """
1402     if not hasattr(vm_inst, 'security_groups'):
1403         return False
1404
1405     found = False
1406     for sec_grp_dict in vm_inst.security_groups:
1407         if sec_grp_name in sec_grp_dict['name']:
1408             found = True
1409             break
1410     return found
1411
1412
1413 def validate_ssh_client(instance_creator):
1414     """
1415     Returns True if instance_creator returns an SSH client that is valid
1416     :param instance_creator: the object responsible for creating the VM instance
1417     :return: T/F
1418     """
1419     ssh_active = instance_creator.vm_ssh_active(block=True)
1420
1421     if ssh_active:
1422         ssh_client = instance_creator.ssh_client()
1423         if ssh_client:
1424             out = ssh_client.exec_command('pwd')[1]
1425         else:
1426             return False
1427
1428         channel = out.channel
1429         in_buffer = channel.in_buffer
1430         pwd_out = in_buffer.read(1024)
1431         if not pwd_out or len(pwd_out) < 10:
1432             return False
1433         return True
1434
1435     return False
1436
1437
1438 class CreateInstanceFromThreePartImage(OSIntegrationTestCase):
1439     """
1440     Test for the CreateInstance class for creating an image from a 3-part image
1441     """
1442
1443     def setUp(self):
1444         """
1445         Instantiates the CreateImage object that is responsible for downloading and creating an OS image file
1446         within OpenStack
1447         """
1448         super(self.__class__, self).__start__()
1449
1450         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1451         self.image_name = guid
1452         self.vm_inst_name = guid + '-inst'
1453         self.nova = nova_utils.nova_client(self.os_creds)
1454
1455         net_config = openstack_tests.get_priv_net_config(
1456             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
1457             router_name=guid + '-pub-router', external_net=self.ext_net_name)
1458
1459         # Initialize for tearDown()
1460         self.image_creator = None
1461         self.network_creator = None
1462         self.flavor_creator = None
1463         self.inst_creator = None
1464
1465         try:
1466             image_settings = openstack_tests.cirros_image_settings(
1467                 name=self.image_name,
1468                 image_metadata={'disk_url': 'http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-disk.img',
1469                                 'kernel_url': 'http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-kernel',
1470                                 'ramdisk_url': 'http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-initramfs'})
1471
1472             self.image_creator = OpenStackImage(self.os_creds, image_settings)
1473             self.image_creator.create()
1474
1475             # Create Flavor
1476             self.flavor_creator = OpenStackFlavor(
1477                 self.admin_os_creds,
1478                 FlavorSettings(name=guid + '-flavor-name', ram=128, disk=10, vcpus=2, metadata=self.flavor_metadata))
1479             self.flavor_creator.create()
1480
1481             # Create Network
1482             self.network_creator = OpenStackNetwork(self.os_creds, net_config.network_settings)
1483             self.network_creator.create()
1484
1485             self.port_settings = PortSettings(name=guid + '-port',
1486                                               network_name=net_config.network_settings.name)
1487         except Exception as e:
1488             self.tearDown()
1489             raise e
1490
1491     def tearDown(self):
1492         """
1493         Cleans the created object
1494         """
1495         if self.inst_creator:
1496             try:
1497                 self.inst_creator.clean()
1498             except Exception as e:
1499                 logger.error('Unexpected exception cleaning VM instance with message - ' + str(e))
1500
1501         if self.flavor_creator:
1502             try:
1503                 self.flavor_creator.clean()
1504             except Exception as e:
1505                 logger.error('Unexpected exception cleaning flavor with message - ' + str(e))
1506
1507         if self.network_creator:
1508             try:
1509                 self.network_creator.clean()
1510             except Exception as e:
1511                 logger.error('Unexpected exception cleaning network with message - ' + str(e))
1512
1513         if self.image_creator:
1514             try:
1515                 self.image_creator.clean()
1516             except Exception as e:
1517                 logger.error('Unexpected exception cleaning image with message - ' + str(e))
1518
1519         super(self.__class__, self).__clean__()
1520
1521     def test_create_instance_from_three_part_image(self):
1522         """
1523         Tests the creation of an OpenStack instance from a 3-part image.
1524         """
1525         instance_settings = VmInstanceSettings(name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name,
1526                                                port_settings=[self.port_settings])
1527
1528         # The last created image is the main image from which we create the instance
1529         self.inst_creator = OpenStackVmInstance(
1530             self.os_creds, instance_settings, self.image_creator.image_settings)
1531
1532         vm_inst = self.inst_creator.create()
1533         self.assertIsNotNone(vm_inst)
1534         self.assertTrue(self.inst_creator.vm_active(block=True))