ff24efb7ce1d6693bc6b3453b34439f124c4064b
[snaps.git] / snaps / openstack / tests / create_instance_tests.py
1 # Copyright (c) 2016 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.assertEquals('foo', settings.name)
73         self.assertEquals('bar', settings.flavor)
74         self.assertEquals(1, len(settings.port_settings))
75         self.assertEquals('foo-port', settings.port_settings[0].name)
76         self.assertEquals('bar-net', settings.port_settings[0].network_name)
77         self.assertEquals(0, len(settings.security_group_names))
78         self.assertEquals(0, len(settings.floating_ip_settings))
79         self.assertIsNone(settings.sudo_user)
80         self.assertEquals(900, settings.vm_boot_timeout)
81         self.assertEquals(300, settings.vm_delete_timeout)
82         self.assertEquals(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.assertEquals('foo', settings.name)
89         self.assertEquals('bar', settings.flavor)
90         self.assertEquals(1, len(settings.port_settings))
91         self.assertEquals('foo-port', settings.port_settings[0].name)
92         self.assertEquals('bar-net', settings.port_settings[0].network_name)
93         self.assertEquals(0, len(settings.security_group_names))
94         self.assertEquals(0, len(settings.floating_ip_settings))
95         self.assertIsNone(settings.sudo_user)
96         self.assertEquals(900, settings.vm_boot_timeout)
97         self.assertEquals(300, settings.vm_delete_timeout)
98         self.assertEquals(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.assertEquals('foo', settings.name)
110         self.assertEquals('bar', settings.flavor)
111         self.assertEquals(1, len(settings.port_settings))
112         self.assertEquals('foo-port', settings.port_settings[0].name)
113         self.assertEquals('bar-net', settings.port_settings[0].network_name)
114         self.assertEquals(1, len(settings.security_group_names))
115         self.assertEquals('sec_grp_1', settings.security_group_names[0])
116         self.assertEquals(1, len(settings.floating_ip_settings))
117         self.assertEquals('foo-fip', settings.floating_ip_settings[0].name)
118         self.assertEquals('bar-port', settings.floating_ip_settings[0].port_name)
119         self.assertEquals('foo-bar-router', settings.floating_ip_settings[0].router_name)
120         self.assertEquals('joe', settings.sudo_user)
121         self.assertEquals(999, settings.vm_boot_timeout)
122         self.assertEquals(333, settings.vm_delete_timeout)
123         self.assertEquals(111, settings.ssh_connect_timeout)
124         self.assertEquals('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.assertEquals('foo', settings.name)
136         self.assertEquals('bar', settings.flavor)
137         self.assertEquals(1, len(settings.port_settings))
138         self.assertEquals('foo-port', settings.port_settings[0].name)
139         self.assertEquals('bar-net', settings.port_settings[0].network_name)
140         self.assertEquals(1, len(settings.security_group_names))
141         self.assertEquals(1, len(settings.floating_ip_settings))
142         self.assertEquals('foo-fip', settings.floating_ip_settings[0].name)
143         self.assertEquals('bar-port', settings.floating_ip_settings[0].port_name)
144         self.assertEquals('foo-bar-router', settings.floating_ip_settings[0].router_name)
145         self.assertEquals('joe', settings.sudo_user)
146         self.assertEquals(999, settings.vm_boot_timeout)
147         self.assertEquals(333, settings.vm_delete_timeout)
148         self.assertEquals(111, settings.ssh_connect_timeout)
149         self.assertEquals('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.assertEquals('foo', settings.name)
192         self.assertEquals('foo-port', settings.port_name)
193         self.assertEquals('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.assertEquals('foo', settings.name)
200         self.assertEquals('foo-port', settings.port_name)
201         self.assertEquals('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.assertEquals('foo', settings.name)
209         self.assertEquals('foo-port', settings.port_name)
210         self.assertEquals('bar-router', settings.router_name)
211         self.assertEquals('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.assertEquals('foo', settings.name)
218         self.assertEquals('foo-port', settings.port_name)
219         self.assertEquals('bar-router', settings.router_name)
220         self.assertEquals('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_url_image(
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 - ' + e.message)
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 - ' + e.message)
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 - ' + e.message)
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 - ' + e.message)
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_url_image(
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 - ' + e.message)
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 - ' + e.message)
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 - ' + e.message)
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 - ' + e.message)
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.assertEquals(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.assertEquals(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_url_image(
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 - ' + e.message)
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 - ' + e.message)
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 - ' + e.message)
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 - ' + e.message)
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 - ' + e.message)
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 - ' + e.message)
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.assertEquals(ip_1, inst_creator.get_port_ip(self.port_1_name))
589         self.assertTrue(inst_creator.vm_active(block=True))
590         self.assertEquals(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.assertEquals(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.assertEquals(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_url_image(
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 - ' + e.message)
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 - ' + e.message)
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 - ' + e.message)
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 - ' + e.message)
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.assertEquals(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.assertEquals(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.assertEquals(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.assertEquals(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.assertEquals(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_url_image(
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 - ' + e.message)
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 - ' + e.message)
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 - ' + e.message)
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 - ' + e.message)
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.assertEquals(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_url_image(name=image_name, image_metadata=self.image_metadata)
1032
1033         try:
1034             # Create Image
1035             self.image_creator = OpenStackImage(self.os_creds, self.os_image_settings)
1036             self.image_creator.create()
1037
1038             # First network is public
1039             self.network_creators.append(OpenStackNetwork(self.os_creds, self.pub_net_config.network_settings))
1040             # Second network is private
1041             self.network_creators.append(OpenStackNetwork(self.os_creds, self.priv_net_config.network_settings))
1042             for network_creator in self.network_creators:
1043                 network_creator.create()
1044
1045             self.router_creators.append(OpenStackRouter(self.os_creds, self.pub_net_config.router_settings))
1046             self.router_creators.append(OpenStackRouter(self.os_creds, self.priv_net_config.router_settings))
1047
1048             # Create Routers
1049             for router_creator in self.router_creators:
1050                 router_creator.create()
1051
1052             # Create Flavor
1053             self.flavor_creator = OpenStackFlavor(
1054                 self.admin_os_creds,
1055                 FlavorSettings(name=self.guid + '-flavor-name', ram=512, disk=10, vcpus=2,
1056                                metadata=self.flavor_metadata))
1057             self.flavor_creator.create()
1058
1059             # Create Keypair
1060             self.keypair_creator = OpenStackKeypair(
1061                 self.os_creds, KeypairSettings(
1062                     name=self.keypair_name, public_filepath=self.keypair_pub_filepath,
1063                     private_filepath=self.keypair_priv_filepath))
1064             self.keypair_creator.create()
1065         except Exception as e:
1066             self.tearDown()
1067             raise Exception(e.message)
1068
1069     def tearDown(self):
1070         """
1071         Cleans the created objects
1072         """
1073         if self.inst_creator:
1074             try:
1075                 self.inst_creator.clean()
1076             except Exception as e:
1077                 logger.error('Unexpected exception cleaning VM instance with message - ' + e.message)
1078
1079         if self.keypair_creator:
1080             try:
1081                 self.keypair_creator.clean()
1082             except Exception as e:
1083                 logger.error('Unexpected exception cleaning keypair with message - ' + e.message)
1084
1085         if os.path.isfile(self.keypair_pub_filepath):
1086             os.remove(self.keypair_pub_filepath)
1087
1088         if os.path.isfile(self.keypair_priv_filepath):
1089             os.remove(self.keypair_priv_filepath)
1090
1091         if self.flavor_creator:
1092             try:
1093                 self.flavor_creator.clean()
1094             except Exception as e:
1095                 logger.error('Unexpected exception cleaning flavor with message - ' + e.message)
1096
1097         for router_creator in self.router_creators:
1098             try:
1099                 router_creator.clean()
1100             except Exception as e:
1101                 logger.error('Unexpected exception cleaning router with message - ' + e.message)
1102
1103         for network_creator in self.network_creators:
1104             try:
1105                 network_creator.clean()
1106             except Exception as e:
1107                 logger.error('Unexpected exception cleaning network with message - ' + e.message)
1108
1109         if self.image_creator:
1110             try:
1111                 self.image_creator.clean()
1112             except Exception as e:
1113                 logger.error('Unexpected exception cleaning image with message - ' + e.message)
1114
1115         super(self.__class__, self).__clean__()
1116
1117     def test_dual_ports_dhcp(self):
1118         """
1119         Tests the creation of an OpenStack instance with a dual ports/NICs with a DHCP assigned IP.
1120         NOTE: This test and any others that call ansible will most likely fail unless you do one of
1121         two things:
1122         1. Have a ~/.ansible.cfg (or alternate means) to set host_key_checking = False
1123         2. Set the following environment variable in your executing shell: ANSIBLE_HOST_KEY_CHECKING=False
1124         Should this not be performed, the creation of the host ssh key will cause your ansible calls to fail.
1125         """
1126         # Create ports/NICs for instance
1127         ports_settings = []
1128         ctr = 1
1129         for network_creator in self.network_creators:
1130             ports_settings.append(PortSettings(
1131                 name=self.guid + '-port-' + str(ctr),
1132                 network_name=network_creator.network_settings.name))
1133             ctr += 1
1134
1135         # Create instance
1136         instance_settings = VmInstanceSettings(
1137             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=ports_settings,
1138             floating_ip_settings=[FloatingIpSettings(
1139                 name=self.floating_ip_name, port_name=self.port_1_name,
1140                 router_name=self.pub_net_config.router_settings.name)])
1141
1142         self.inst_creator = OpenStackVmInstance(
1143             self.os_creds, instance_settings, self.image_creator.image_settings,
1144             keypair_settings=self.keypair_creator.keypair_settings)
1145
1146         vm_inst = self.inst_creator.create(block=True)
1147
1148         self.assertEquals(vm_inst, self.inst_creator.get_vm_inst())
1149
1150         # Effectively blocks until VM has been properly activated
1151         self.assertTrue(self.inst_creator.vm_active(block=True))
1152
1153         # Effectively blocks until VM's ssh port has been opened
1154         self.assertTrue(self.inst_creator.vm_ssh_active(block=True))
1155
1156         self.inst_creator.config_nics()
1157
1158         # TODO - *** ADD VALIDATION HERE ***
1159         # TODO - Add validation that both floating IPs work
1160         # TODO - Add tests where only one NIC has a floating IP
1161         # TODO - Add tests where one attempts to place a floating IP on a network/router without an external gateway
1162
1163
1164 class InstanceSecurityGroupTests(OSIntegrationTestCase):
1165     """
1166     Tests that include, add, and remove security groups from VM instances
1167     """
1168     def setUp(self):
1169         """
1170         Instantiates the CreateImage object that is responsible for downloading and creating an OS image file
1171         within OpenStack
1172         """
1173         super(self.__class__, self).__start__()
1174
1175         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1176         self.vm_inst_name = self.guid + '-inst'
1177         self.nova = nova_utils.nova_client(self.os_creds)
1178         self.os_image_settings = openstack_tests.cirros_url_image(
1179             name=self.guid + '-image', image_metadata=self.image_metadata)
1180
1181         self.vm_inst_name = self.guid + '-inst'
1182         self.port_1_name = self.guid + 'port-1'
1183         self.port_2_name = self.guid + 'port-2'
1184         self.floating_ip_name = self.guid + 'fip1'
1185
1186         net_config = openstack_tests.get_priv_net_config(
1187             net_name=self.guid + '-pub-net', subnet_name=self.guid + '-pub-subnet',
1188             router_name=self.guid + '-pub-router', external_net=self.ext_net_name)
1189
1190         # Initialize for tearDown()
1191         self.image_creator = None
1192         self.flavor_creator = None
1193         self.network_creator = None
1194         self.router_creator = None
1195         self.inst_creator = None
1196         self.sec_grp_creators = list()
1197
1198         try:
1199             # Create Image
1200             self.image_creator = OpenStackImage(self.os_creds, self.os_image_settings)
1201             self.image_creator.create()
1202
1203             # Create Network
1204             self.network_creator = OpenStackNetwork(self.os_creds, net_config.network_settings)
1205             self.network_creator.create()
1206
1207             # Create Flavor
1208             self.flavor_creator = OpenStackFlavor(
1209                 self.admin_os_creds,
1210                 FlavorSettings(name=self.guid + '-flavor-name', ram=128, disk=10, vcpus=2,
1211                                metadata=self.flavor_metadata))
1212             self.flavor_creator.create()
1213
1214             self.port_settings = PortSettings(name=self.guid + '-port',
1215                                               network_name=net_config.network_settings.name)
1216         except Exception as e:
1217             self.tearDown()
1218             raise e
1219
1220     def tearDown(self):
1221         """
1222         Cleans the created object
1223         """
1224         if self.inst_creator:
1225             try:
1226                 self.inst_creator.clean()
1227             except Exception as e:
1228                 logger.error('Unexpected exception cleaning VM instance with message - ' + e.message)
1229
1230         for sec_grp_creator in self.sec_grp_creators:
1231             try:
1232                 sec_grp_creator.clean()
1233             except Exception as e:
1234                 logger.error('Unexpected exception cleaning security group with message - ' + e.message)
1235
1236         if self.flavor_creator:
1237             try:
1238                 self.flavor_creator.clean()
1239             except Exception as e:
1240                 logger.error('Unexpected exception cleaning flavor with message - ' + e.message)
1241
1242         if self.network_creator:
1243             try:
1244                 self.network_creator.clean()
1245             except Exception as e:
1246                 logger.error('Unexpected exception cleaning network with message - ' + e.message)
1247
1248         if self.image_creator:
1249             try:
1250                 self.image_creator.clean()
1251             except Exception as e:
1252                 logger.error('Unexpected exception cleaning image with message - ' + e.message)
1253
1254         super(self.__class__, self).__clean__()
1255
1256     def test_add_security_group(self):
1257         """
1258         Tests the addition of a security group created after the instance.
1259         """
1260         # Create instance
1261         instance_settings = VmInstanceSettings(
1262             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[self.port_settings])
1263         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings,
1264                                                 self.image_creator.image_settings)
1265         vm_inst = self.inst_creator.create(block=True)
1266         self.assertIsNotNone(vm_inst)
1267
1268         # Create security group object to add to instance
1269         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name', description='hello group')
1270         sec_grp_creator = OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
1271         sec_grp = sec_grp_creator.create()
1272         self.sec_grp_creators.append(sec_grp_creator)
1273
1274         # Check that group has not been added
1275         self.assertFalse(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1276
1277         # Add security group to instance after activated
1278         self.inst_creator.add_security_group(sec_grp)
1279
1280         # Validate that security group has been added
1281         self.assertTrue(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1282
1283     def test_add_invalid_security_group(self):
1284         """
1285         Tests the addition of a security group that no longer exists.
1286         """
1287         # Create instance
1288         instance_settings = VmInstanceSettings(
1289             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[self.port_settings])
1290         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings,
1291                                                 self.image_creator.image_settings)
1292         vm_inst = self.inst_creator.create(block=True)
1293         self.assertIsNotNone(vm_inst)
1294
1295         # Create security group object to add to instance
1296         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name', description='hello group')
1297         sec_grp_creator = OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
1298         sec_grp = sec_grp_creator.create()
1299         sec_grp_creator.clean()
1300         self.sec_grp_creators.append(sec_grp_creator)
1301
1302         # Check that group has not been added
1303         self.assertFalse(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1304
1305         # Add security group to instance after activated
1306         self.assertFalse(self.inst_creator.add_security_group(sec_grp))
1307
1308         # Validate that security group has been added
1309         self.assertFalse(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1310
1311     def test_remove_security_group(self):
1312         """
1313         Tests the removal of a security group created before and added to the instance.
1314         """
1315         # Create security group object to add to instance
1316         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name', description='hello group')
1317         sec_grp_creator = OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
1318         sec_grp = sec_grp_creator.create()
1319         self.sec_grp_creators.append(sec_grp_creator)
1320
1321         # Create instance
1322         instance_settings = VmInstanceSettings(
1323             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name,
1324             security_group_names=[sec_grp_settings.name], port_settings=[self.port_settings])
1325         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings,
1326                                                 self.image_creator.image_settings)
1327         vm_inst = self.inst_creator.create(block=True)
1328         self.assertIsNotNone(vm_inst)
1329
1330         # Check that group has been added
1331         self.assertTrue(inst_has_sec_grp(vm_inst, sec_grp_settings.name))
1332
1333         # Add security group to instance after activated
1334         self.assertTrue(self.inst_creator.remove_security_group(sec_grp))
1335
1336         # Validate that security group has been added
1337         self.assertFalse(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1338
1339     def test_remove_security_group_never_added(self):
1340         """
1341         Tests the removal of a security group that was never added in the first place.
1342         """
1343         # Create security group object to add to instance
1344         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name', description='hello group')
1345         sec_grp_creator = OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
1346         sec_grp = sec_grp_creator.create()
1347         self.sec_grp_creators.append(sec_grp_creator)
1348
1349         # Create instance
1350         instance_settings = VmInstanceSettings(
1351             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[self.port_settings])
1352         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings,
1353                                                 self.image_creator.image_settings)
1354         vm_inst = self.inst_creator.create(block=True)
1355         self.assertIsNotNone(vm_inst)
1356
1357         # Check that group has been added
1358         self.assertFalse(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1359
1360         # Add security group to instance after activated
1361         self.assertFalse(self.inst_creator.remove_security_group(sec_grp))
1362
1363         # Validate that security group has been added
1364         self.assertFalse(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1365
1366     def test_add_same_security_group(self):
1367         """
1368         Tests the addition of a security group created before add added to the instance.
1369         """
1370         # Create security group object to add to instance
1371         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name', description='hello group')
1372         sec_grp_creator = OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
1373         sec_grp = sec_grp_creator.create()
1374         self.sec_grp_creators.append(sec_grp_creator)
1375
1376         # Create instance
1377         instance_settings = VmInstanceSettings(
1378             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name,
1379             security_group_names=[sec_grp_settings.name], port_settings=[self.port_settings])
1380         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings,
1381                                                 self.image_creator.image_settings)
1382         vm_inst = self.inst_creator.create(block=True)
1383         self.assertIsNotNone(vm_inst)
1384
1385         # Check that group has been added
1386         self.assertTrue(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1387
1388         # Add security group to instance after activated
1389         self.assertTrue(self.inst_creator.add_security_group(sec_grp))
1390
1391         # Validate that security group has been added
1392         self.assertTrue(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1393
1394
1395 def inst_has_sec_grp(vm_inst, sec_grp_name):
1396     """
1397     Returns true if instance has a security group of a given name
1398     :return:
1399     """
1400     if not hasattr(vm_inst, 'security_groups'):
1401         return False
1402
1403     found = False
1404     for sec_grp_dict in vm_inst.security_groups:
1405         if sec_grp_name in sec_grp_dict['name']:
1406             found = True
1407             break
1408     return found
1409
1410
1411 def validate_ssh_client(instance_creator):
1412     """
1413     Returns True if instance_creator returns an SSH client that is valid
1414     :param instance_creator: the object responsible for creating the VM instance
1415     :return: T/F
1416     """
1417     ssh_active = instance_creator.vm_ssh_active(block=True)
1418
1419     if ssh_active:
1420         ssh_client = instance_creator.ssh_client()
1421         if ssh_client:
1422             out = ssh_client.exec_command('pwd')[1]
1423         else:
1424             return False
1425
1426         channel = out.channel
1427         in_buffer = channel.in_buffer
1428         pwd_out = in_buffer.read(1024)
1429         if not pwd_out or len(pwd_out) < 10:
1430             return False
1431         return True
1432
1433     return False
1434
1435
1436 class CreateInstanceFromThreePartImage(OSIntegrationTestCase):
1437     """
1438     Test for the CreateInstance class for creating an image from a 3-part image
1439     """
1440
1441     def setUp(self):
1442         """
1443         Instantiates the CreateImage object that is responsible for downloading and creating an OS image file
1444         within OpenStack
1445         """
1446         super(self.__class__, self).__start__()
1447
1448         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1449         self.image_name = guid
1450         self.vm_inst_name = guid + '-inst'
1451         self.nova = nova_utils.nova_client(self.os_creds)
1452
1453         net_config = openstack_tests.get_priv_net_config(
1454             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
1455             router_name=guid + '-pub-router', external_net=self.ext_net_name)
1456
1457         # Initialize for tearDown()
1458         self.image_creator = None
1459         self.network_creator = None
1460         self.flavor_creator = None
1461         self.inst_creator = None
1462
1463         try:
1464             image_settings = openstack_tests.cirros_url_image(
1465                 name=self.image_name,
1466                 image_metadata={'disk_url': 'http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-disk.img',
1467                                 'kernel_url': 'http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-kernel',
1468                                 'ramdisk_url': 'http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-initramfs'})
1469
1470             self.image_creator = OpenStackImage(self.os_creds, image_settings)
1471             self.image_creator.create()
1472
1473             # Create Flavor
1474             self.flavor_creator = OpenStackFlavor(
1475                 self.admin_os_creds,
1476                 FlavorSettings(name=guid + '-flavor-name', ram=128, disk=10, vcpus=2, metadata=self.flavor_metadata))
1477             self.flavor_creator.create()
1478
1479             # Create Network
1480             self.network_creator = OpenStackNetwork(self.os_creds, net_config.network_settings)
1481             self.network_creator.create()
1482
1483             self.port_settings = PortSettings(name=guid + '-port',
1484                                               network_name=net_config.network_settings.name)
1485         except Exception as e:
1486             self.tearDown()
1487             raise e
1488
1489     def tearDown(self):
1490         """
1491         Cleans the created object
1492         """
1493         if self.inst_creator:
1494             try:
1495                 self.inst_creator.clean()
1496             except Exception as e:
1497                 logger.error('Unexpected exception cleaning VM instance with message - ' + e.message)
1498
1499         if self.flavor_creator:
1500             try:
1501                 self.flavor_creator.clean()
1502             except Exception as e:
1503                 logger.error('Unexpected exception cleaning flavor with message - ' + e.message)
1504
1505         if self.network_creator:
1506             try:
1507                 self.network_creator.clean()
1508             except Exception as e:
1509                 logger.error('Unexpected exception cleaning network with message - ' + e.message)
1510
1511         if self.image_creator:
1512             try:
1513                self.image_creator.clean()
1514             except Exception as e:
1515                 logger.error('Unexpected exception cleaning image with message - ' + e.message)
1516
1517         super(self.__class__, self).__clean__()
1518
1519     def test_create_instance_from_three_part_image(self):
1520         """
1521         Tests the creation of an OpenStack instance from a 3-part image.
1522         """
1523         instance_settings = VmInstanceSettings(name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name,
1524                                                port_settings=[self.port_settings])
1525
1526         # The last created image is the main image from which we create the instance
1527         self.inst_creator = OpenStackVmInstance(
1528             self.os_creds, instance_settings, self.image_creator.image_settings)
1529
1530         vm_inst = self.inst_creator.create()
1531         self.assertIsNotNone(vm_inst)
1532         self.assertTrue(self.inst_creator.vm_active(block=True))