Add check that SSH validate returns true
[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_creators = list()
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         # set the default image settings, then set any custom parameters sent from the app
257         self.os_image_settings = openstack_tests.cirros_url_image(name=guid + '-image')
258
259         if self.image_metadata:
260             if self.image_metadata['disk_url']:
261                 self.os_image_settings.url = self.image_metadata['disk_url']
262             if self.image_metadata['extra_properties']:
263                 self.os_image_settings.extra_properties = self.image_metadata['extra_properties']
264
265         try:
266             # Create Image; if this is a 3-part image create the kernel and ramdisk images first
267             if self.image_metadata:
268                 if self.image_metadata['kernel_url']:
269                     kernel_image_settings = openstack_tests.cirros_url_image(
270                         name=self.os_image_settings.name+'_kernel', url=self.image_metadata['kernel_url'])
271                     self.image_creators.append(OpenStackImage(self.os_creds, kernel_image_settings))
272                     kernel_image = self.image_creators[-1].create()
273                     self.os_image_settings.extra_properties['kernel_id'] = kernel_image.id
274
275                 if self.image_metadata['ramdisk_url']:
276                     ramdisk_image_settings = openstack_tests.cirros_url_image(
277                         name=self.os_image_settings.name+'_ramdisk', url=self.image_metadata['ramdisk_url'])
278                     self.image_creators.append(OpenStackImage(self.os_creds, ramdisk_image_settings))
279                     ramdisk_image = self.image_creators[-1].create()
280                     self.os_image_settings.extra_properties['ramdisk_id'] = ramdisk_image.id
281
282             self.image_creators.append(OpenStackImage(self.os_creds, self.os_image_settings))
283             self.image_creators[-1].create()
284
285             # Create Network
286             self.network_creator = OpenStackNetwork(self.os_creds, self.priv_net_config.network_settings)
287             self.network_creator.create()
288
289             # Create Flavor
290             self.flavor_creator = OpenStackFlavor(
291                 self.admin_os_creds,
292                 FlavorSettings(name=guid + '-flavor-name', ram=1024, disk=10, vcpus=1, metadata=self.flavor_metadata))
293             self.flavor_creator.create()
294         except Exception as e:
295             self.tearDown()
296             raise e
297
298     def tearDown(self):
299         """
300         Cleans the created object
301         """
302         if self.inst_creator:
303             try:
304                 self.inst_creator.clean()
305             except Exception as e:
306                 logger.error('Unexpected exception cleaning VM instance with message - ' + e.message)
307
308         if os.path.isfile(self.keypair_pub_filepath):
309             os.remove(self.keypair_pub_filepath)
310
311         if os.path.isfile(self.keypair_priv_filepath):
312             os.remove(self.keypair_priv_filepath)
313
314         if self.flavor_creator:
315             try:
316                 self.flavor_creator.clean()
317             except Exception as e:
318                 logger.error('Unexpected exception cleaning network with message - ' + e.message)
319
320         if self.image_creators:
321             try:
322                 while self.image_creators:
323                     self.image_creators[-1].clean()
324                     self.image_creators.pop()
325             except Exception as e:
326                 logger.error('Unexpected exception cleaning image with message - ' + e.message)
327
328         super(self.__class__, self).__clean__()
329
330     def test_check_vm_ip_dhcp(self):
331         """
332         Tests the creation of an OpenStack instance with a single port and ensures that it's assigned IP address is
333         the actual.
334         """
335         instance_settings = VmInstanceSettings(
336             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[self.port_settings])
337
338         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creators[-1].image_settings)
339         vm = self.inst_creator.create()
340
341         ip = self.inst_creator.get_port_ip(self.port_settings.name)
342         self.assertIsNotNone(ip)
343
344         self.assertTrue(self.inst_creator.vm_active(block=True))
345
346         found = False
347         timeout = 160
348         start_time = time.time()
349         match_value = 'Lease of.*obtained'
350
351         logger.info("Looking for expression %s in the console log" % match_value)
352         while timeout > time.time() - start_time:
353             output = vm.get_console_output()
354             if re.search(match_value, output):
355                 logger.info('DHCP lease obtained logged in console')
356                 if ip in output:
357                     logger.info('With correct IP address')
358                     found = True
359                 else:
360                     logger.error('With incorrect IP address')
361                 break
362
363         self.assertTrue(found)
364
365
366 class CreateInstanceSimpleTests(OSIntegrationTestCase):
367     """
368     Simple instance creation tests without any other objects
369     """
370     def setUp(self):
371         """
372         Instantiates the CreateImage object that is responsible for downloading and creating an OS image file
373         within OpenStack
374         """
375         super(self.__class__, self).__start__()
376
377         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
378         self.vm_inst_name = guid + '-inst'
379         self.nova = nova_utils.nova_client(self.os_creds)
380         self.os_image_settings = openstack_tests.cirros_url_image(name=guid + '-image')
381
382         net_config = openstack_tests.get_priv_net_config(
383             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
384             router_name=guid + '-pub-router', external_net=self.ext_net_name)
385
386         # Initialize for tearDown()
387         self.image_creator = None
388         self.flavor_creator = None
389
390         self.net_creator = None
391         self.inst_creator = None
392
393         try:
394             # Create Image
395             self.image_creator = OpenStackImage(self.os_creds, self.os_image_settings)
396             self.image_creator.create()
397
398             # Create Flavor
399             self.flavor_creator = OpenStackFlavor(
400                 self.admin_os_creds,
401                 FlavorSettings(name=guid + '-flavor-name', ram=2048, disk=10, vcpus=2, metadata=self.flavor_metadata))
402             self.flavor_creator.create()
403
404             # Create Network
405             self.network_creator = OpenStackNetwork(self.os_creds, net_config.network_settings)
406             self.network_creator.create()
407
408             self.port_settings = PortSettings(name=guid + '-port',
409                                               network_name=net_config.network_settings.name)
410
411         except Exception as e:
412             self.tearDown()
413             raise e
414
415     def tearDown(self):
416         """
417         Cleans the created object
418         """
419         if self.inst_creator:
420             try:
421                 self.inst_creator.clean()
422             except Exception as e:
423                 logger.error('Unexpected exception cleaning VM instance with message - ' + e.message)
424
425         if self.flavor_creator:
426             try:
427                 self.flavor_creator.clean()
428             except Exception as e:
429                 logger.error('Unexpected exception cleaning flavor with message - ' + e.message)
430
431         if self.net_creator:
432             try:
433                 self.net_creator.clean()
434             except Exception as e:
435                 logger.error('Unexpected exception cleaning network with message - ' + e.message)
436
437         if self.image_creator:
438             try:
439                 self.image_creator.clean()
440             except Exception as e:
441                 logger.error('Unexpected exception cleaning image with message - ' + e.message)
442
443         super(self.__class__, self).__clean__()
444
445     def test_create_delete_instance(self):
446         """
447         Tests the creation of an OpenStack instance with a single port with a static IP without a Floating IP.
448         """
449         instance_settings = VmInstanceSettings(name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name,
450                                                port_settings=[self.port_settings])
451
452         self.inst_creator = OpenStackVmInstance(
453             self.os_creds, instance_settings, self.image_creator.image_settings)
454
455         vm_inst = self.inst_creator.create()
456         self.assertEquals(1, len(nova_utils.get_servers_by_name(self.nova, instance_settings.name)))
457
458         # Delete instance
459         nova_utils.delete_vm_instance(self.nova, vm_inst)
460
461         self.assertTrue(self.inst_creator.vm_deleted(block=True))
462         self.assertEquals(0, len(nova_utils.get_servers_by_name(self.nova, instance_settings.name)))
463
464         # Exception should not be thrown
465         self.inst_creator.clean()
466
467
468 class CreateInstanceSingleNetworkTests(OSIntegrationTestCase):
469     """
470     Test for the CreateInstance class with a single NIC/Port with Floating IPs
471     """
472
473     def setUp(self):
474         """
475         Instantiates the CreateImage object that is responsible for downloading and creating an OS image file
476         within OpenStack
477         """
478         super(self.__class__, self).__start__()
479
480         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
481         self.keypair_priv_filepath = 'tmp/' + guid
482         self.keypair_pub_filepath = self.keypair_priv_filepath + '.pub'
483         self.keypair_name = guid + '-kp'
484         self.vm_inst_name = guid + '-inst'
485         self.port_1_name = guid + 'port-1'
486         self.port_2_name = guid + 'port-2'
487         self.floating_ip_name = guid + 'fip1'
488
489         # Initialize for tearDown()
490         self.image_creator = None
491         self.network_creator = None
492         self.router_creator = None
493         self.flavor_creator = None
494         self.keypair_creator = None
495         self.inst_creators = list()
496
497         self.pub_net_config = openstack_tests.get_pub_net_config(
498             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
499             router_name=guid + '-pub-router', external_net=self.ext_net_name)
500         self.os_image_settings = openstack_tests.cirros_url_image(name=guid + '-image')
501
502         try:
503             # Create Image
504             self.image_creator = OpenStackImage(self.os_creds, self.os_image_settings)
505             self.image_creator.create()
506
507             # Create Network
508             self.network_creator = OpenStackNetwork(self.os_creds, self.pub_net_config.network_settings)
509             self.network_creator.create()
510
511             # Create Router
512             self.router_creator = OpenStackRouter(self.os_creds, self.pub_net_config.router_settings)
513             self.router_creator.create()
514
515             # Create Flavor
516             self.flavor_creator = OpenStackFlavor(
517                 self.admin_os_creds,
518                 FlavorSettings(name=guid + '-flavor-name', ram=2048, disk=10, vcpus=2, metadata=self.flavor_metadata))
519             self.flavor_creator.create()
520
521             self.keypair_creator = OpenStackKeypair(
522                 self.os_creds, KeypairSettings(
523                     name=self.keypair_name, public_filepath=self.keypair_pub_filepath,
524                     private_filepath=self.keypair_priv_filepath))
525             self.keypair_creator.create()
526         except Exception as e:
527             self.tearDown()
528             raise e
529
530     def tearDown(self):
531         """
532         Cleans the created object
533         """
534         for inst_creator in self.inst_creators:
535             try:
536                 inst_creator.clean()
537             except Exception as e:
538                 logger.error('Unexpected exception cleaning VM instance with message - ' + e.message)
539
540         if self.keypair_creator:
541             try:
542                 self.keypair_creator.clean()
543             except Exception as e:
544                 logger.error('Unexpected exception cleaning keypair with message - ' + e.message)
545
546         if os.path.isfile(self.keypair_pub_filepath):
547             os.remove(self.keypair_pub_filepath)
548
549         if os.path.isfile(self.keypair_priv_filepath):
550             os.remove(self.keypair_priv_filepath)
551
552         if self.flavor_creator:
553             try:
554                 self.flavor_creator.clean()
555             except Exception as e:
556                 logger.error('Unexpected exception cleaning flavor with message - ' + e.message)
557
558         if self.router_creator:
559             try:
560                 self.router_creator.clean()
561             except Exception as e:
562                 logger.error('Unexpected exception cleaning router with message - ' + e.message)
563
564         if self.network_creator:
565             try:
566                 self.network_creator.clean()
567             except Exception as e:
568                 logger.error('Unexpected exception cleaning network with message - ' + e.message)
569
570         if self.image_creator:
571             try:
572                 self.image_creator.clean()
573             except Exception as e:
574                 logger.error('Unexpected exception cleaning image with message - ' + e.message)
575
576         super(self.__class__, self).__clean__()
577
578     def test_single_port_static(self):
579         """
580         Tests the creation of an OpenStack instance with a single port with a static IP without a Floating IP.
581         """
582         ip_1 = '10.55.1.100'
583
584         port_settings = PortSettings(
585             name=self.port_1_name, network_name=self.pub_net_config.network_settings.name,
586             ip_addrs=[{'subnet_name': self.pub_net_config.network_settings.subnet_settings[0].name, 'ip': ip_1}])
587
588         instance_settings = VmInstanceSettings(
589             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings],
590             floating_ip_settings=[FloatingIpSettings(
591                 name=self.floating_ip_name, port_name=self.port_1_name,
592                 router_name=self.pub_net_config.router_settings.name)])
593
594         inst_creator = OpenStackVmInstance(
595             self.os_creds, instance_settings, self.image_creator.image_settings,
596             keypair_settings=self.keypair_creator.keypair_settings)
597         self.inst_creators.append(inst_creator)
598         vm_inst = inst_creator.create()
599
600         self.assertEquals(ip_1, inst_creator.get_port_ip(self.port_1_name))
601         self.assertTrue(inst_creator.vm_active(block=True))
602         self.assertEquals(vm_inst, inst_creator.get_vm_inst())
603
604     def test_ssh_client_fip_before_active(self):
605         """
606         Tests the ability to access a VM via SSH and a floating IP when it has been assigned prior to being active.
607         """
608         port_settings = PortSettings(
609             name=self.port_1_name, network_name=self.pub_net_config.network_settings.name)
610
611         instance_settings = VmInstanceSettings(
612             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings],
613             floating_ip_settings=[FloatingIpSettings(
614                 name=self.floating_ip_name, port_name=self.port_1_name,
615                 router_name=self.pub_net_config.router_settings.name)])
616
617         inst_creator = OpenStackVmInstance(
618             self.os_creds, instance_settings, self.image_creator.image_settings,
619             keypair_settings=self.keypair_creator.keypair_settings)
620         self.inst_creators.append(inst_creator)
621         vm_inst = inst_creator.create()
622         self.assertIsNotNone(vm_inst)
623
624         self.assertTrue(inst_creator.vm_active(block=True))
625         self.assertEquals(vm_inst, inst_creator.get_vm_inst())
626
627         self.assertTrue(validate_ssh_client(inst_creator))
628
629     def test_ssh_client_fip_after_active(self):
630         """
631         Tests the ability to access a VM via SSH and a floating IP when it has been assigned prior to being active.
632         """
633         port_settings = PortSettings(
634             name=self.port_1_name, network_name=self.pub_net_config.network_settings.name)
635
636         instance_settings = VmInstanceSettings(
637             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings],
638             floating_ip_settings=[FloatingIpSettings(
639                 name=self.floating_ip_name, port_name=self.port_1_name,
640                 router_name=self.pub_net_config.router_settings.name)])
641
642         inst_creator = OpenStackVmInstance(
643             self.os_creds, instance_settings, self.image_creator.image_settings,
644             keypair_settings=self.keypair_creator.keypair_settings)
645         self.inst_creators.append(inst_creator)
646
647         # block=True will force the create() method to block until the
648         vm_inst = inst_creator.create(block=True)
649         self.assertIsNotNone(vm_inst)
650
651         self.assertTrue(inst_creator.vm_active(block=True))
652         self.assertEquals(vm_inst, inst_creator.get_vm_inst())
653
654         self.assertTrue(validate_ssh_client(inst_creator))
655
656     # TODO - Determine how allowed_address_pairs is supposed to operate before continuing this test
657     # see http://docs.openstack.org/developer/dragonflow/specs/allowed_address_pairs.html for a functional description
658     # def test_allowed_address_port_access(self):
659     #     """
660     #     Tests to ensure that setting allowed_address_pairs on a port functions as designed
661     #     """
662     #     port_settings_1 = PortSettings(
663     #         name=self.port_1_name + '-1', network_name=self.pub_net_config.network_settings.name)
664     #
665     #     instance_settings_1 = VmInstanceSettings(
666     #         name=self.vm_inst_name + '-1', flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings_1],
667     #         floating_ip_settings=[FloatingIpSettings(
668     #             name=self.floating_ip_name + '-1', port_name=port_settings_1.name,
669     #             router_name=self.pub_net_config.router_settings.name)])
670     #
671     #     inst_creator_1 = OpenStackVmInstance(
672     #         self.os_creds, instance_settings_1, self.image_creator.image_settings,
673     #         keypair_settings=self.keypair_creator.keypair_settings)
674     #     self.inst_creators.append(inst_creator_1)
675     #
676     #     # block=True will force the create() method to block until the
677     #     vm_inst_1 = inst_creator_1.create(block=True)
678     #     self.assertIsNotNone(vm_inst_1)
679     #
680     #     port_settings_1 = PortSettings(
681     #         name=self.port_1_name + '-1', network_name=self.pub_net_config.network_settings.name)
682     #
683     #     instance_settings_1 = VmInstanceSettings(
684     #         name=self.vm_inst_name + '-1', flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings_1],
685     #         floating_ip_settings=[FloatingIpSettings(
686     #             name=self.floating_ip_name + '-1', port_name=port_settings_1.name,
687     #             router_name=self.pub_net_config.router_settings.name)])
688     #
689     #     inst_creator_1 = OpenStackVmInstance(
690     #         self.os_creds, instance_settings_1, self.image_creator.image_settings,
691     #         keypair_settings=self.keypair_creator.keypair_settings)
692     #     self.inst_creators.append(inst_creator_1)
693     #     inst_creator_1.create(block=True)
694     #
695     #     ip = inst_creator_1.get_port_ip(port_settings_1.name,
696     #                                     subnet_name=self.pub_net_config.network_settings.subnet_settings[0].name)
697     #     self.assertIsNotNone(ip)
698     #     mac_addr = inst_creator_1.get_port_mac(port_settings_1.name)
699     #     self.assertIsNotNone(mac_addr)
700     #
701     #     allowed_address_pairs = [{'ip_address': ip, 'mac_address': mac_addr}]
702     #
703     #     # Create VM that can be accessed by vm_inst_1
704     #     port_settings_2 = PortSettings(
705     #         name=self.port_1_name + '-2', network_name=self.pub_net_config.network_settings.name,
706     #         allowed_address_pairs=allowed_address_pairs)
707     #
708     #     instance_settings_2 = VmInstanceSettings(
709     #         name=self.vm_inst_name + '-2', flavor=self.flavor_creator.flavor_settings.name,
710     #         port_settings=[port_settings_2])
711     #
712     #     inst_creator_2 = OpenStackVmInstance(
713     #         self.os_creds, instance_settings_2, self.image_creator.image_settings)
714     #     self.inst_creators.append(inst_creator_2)
715     #     inst_creator_2.create(block=True)
716     #
717     #     # Create VM that cannot be accessed by vm_inst_1
718     #     ip = '10.55.0.101'
719     #     mac_addr = '0a:1b:2c:3d:4e:5f'
720     #     invalid_address_pairs = [{'ip_address': ip, 'mac_address': mac_addr}]
721     #
722     #     port_settings_3 = PortSettings(
723     #         name=self.port_1_name + '-3', network_name=self.pub_net_config.network_settings.name,
724     #         allowed_address_pairs=invalid_address_pairs)
725     #
726     #     instance_settings_3 = VmInstanceSettings(
727     #         name=self.vm_inst_name + '-3', flavor=self.flavor_creator.flavor_settings.name,
728     #         port_settings=[port_settings_3])
729     #
730     #     inst_creator_3 = OpenStackVmInstance(
731     #         self.os_creds, instance_settings_3, self.image_creator.image_settings)
732     #     self.inst_creators.append(inst_creator_3)
733     #     inst_creator_3.create(block=True)
734     #
735     #     print 'foo'
736     # I expected that this feature would block/allow traffic from specific endpoints (VMs). In this case, I would expect
737     # inst_1 to be able to access inst_2 but not inst_3; however, they all can access each other.
738     # TODO - Add validation
739
740
741 class CreateInstancePortManipulationTests(OSIntegrationTestCase):
742     """
743     Test for the CreateInstance class with a single NIC/Port where mac and IP values are manually set
744     """
745
746     def setUp(self):
747         """
748         Instantiates the CreateImage object that is responsible for downloading and creating an OS image file
749         within OpenStack
750         """
751         super(self.__class__, self).__start__()
752
753         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
754         self.vm_inst_name = guid + '-inst'
755         self.port_1_name = guid + 'port-1'
756         self.port_2_name = guid + 'port-2'
757         self.floating_ip_name = guid + 'fip1'
758
759         # Initialize for tearDown()
760         self.image_creator = None
761         self.network_creator = None
762         self.flavor_creator = None
763         self.inst_creator = None
764
765         self.net_config = openstack_tests.get_priv_net_config(
766             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
767             router_name=guid + '-pub-router', external_net=self.ext_net_name)
768         self.os_image_settings = openstack_tests.cirros_url_image(name=guid + '-image')
769
770         try:
771             # Create Image
772             self.image_creator = OpenStackImage(self.os_creds, self.os_image_settings)
773             self.image_creator.create()
774
775             # Create Network
776             self.network_creator = OpenStackNetwork(self.os_creds, self.net_config.network_settings)
777             self.network_creator.create()
778
779             # Create Flavor
780             self.flavor_creator = OpenStackFlavor(
781                 self.admin_os_creds,
782                 FlavorSettings(name=guid + '-flavor-name', ram=2048, disk=10, vcpus=2, metadata=self.flavor_metadata))
783             self.flavor_creator.create()
784         except Exception as e:
785             self.tearDown()
786             raise e
787
788     def tearDown(self):
789         """
790         Cleans the created object
791         """
792         if self.inst_creator:
793             try:
794                 self.inst_creator.clean()
795             except Exception as e:
796                 logger.error('Unexpected exception cleaning VM instance with message - ' + e.message)
797
798         if self.flavor_creator:
799             try:
800                 self.flavor_creator.clean()
801             except Exception as e:
802                 logger.error('Unexpected exception cleaning flavor with message - ' + e.message)
803
804         if self.network_creator:
805             try:
806                 self.network_creator.clean()
807             except Exception as e:
808                 logger.error('Unexpected exception cleaning network with message - ' + e.message)
809
810         if self.image_creator:
811             try:
812                 self.image_creator.clean()
813             except Exception as e:
814                 logger.error('Unexpected exception cleaning image with message - ' + e.message)
815
816         super(self.__class__, self).__clean__()
817
818     def test_set_custom_valid_ip_one_subnet(self):
819         """
820         Tests the creation of an OpenStack instance with a single port with a static IP on a network with one subnet.
821         """
822         ip = '10.55.0.101'
823         port_settings = PortSettings(
824             name=self.port_1_name, network_name=self.net_config.network_settings.name,
825             ip_addrs=[{'subnet_name': self.net_config.network_settings.subnet_settings[0].name, 'ip': ip}])
826
827         instance_settings = VmInstanceSettings(
828             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
829
830         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
831         self.inst_creator.create()
832
833         self.assertEquals(ip, self.inst_creator.get_port_ip(
834             self.port_1_name, subnet_name=self.net_config.network_settings.subnet_settings[0].name))
835
836     def test_set_custom_invalid_ip_one_subnet(self):
837         """
838         Tests the creation of an OpenStack instance with a single port with a static IP on a network with one subnet.
839         """
840         ip = '10.66.0.101'
841         port_settings = PortSettings(
842             name=self.port_1_name, network_name=self.net_config.network_settings.name,
843             ip_addrs=[{'subnet_name': self.net_config.network_settings.subnet_settings[0].name, 'ip': ip}])
844
845         instance_settings = VmInstanceSettings(
846             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
847
848         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
849
850         with self.assertRaises(Exception):
851             self.inst_creator.create()
852
853     def test_set_custom_valid_mac(self):
854         """
855         Tests the creation of an OpenStack instance with a single port where the MAC address is assigned.
856         """
857         mac_addr = '0a:1b:2c:3d:4e:5f'
858         port_settings = PortSettings(
859             name=self.port_1_name, network_name=self.net_config.network_settings.name, mac_address=mac_addr)
860
861         instance_settings = VmInstanceSettings(
862             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
863
864         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
865         self.inst_creator.create()
866
867         self.assertEquals(mac_addr, self.inst_creator.get_port_mac(self.port_1_name))
868
869     def test_set_custom_invalid_mac(self):
870         """
871         Tests the creation of an OpenStack instance with a single port where an invalid MAC address value is being
872         assigned. This should raise an Exception
873         """
874         port_settings = PortSettings(
875             name=self.port_1_name, network_name=self.net_config.network_settings.name, mac_address='foo')
876
877         instance_settings = VmInstanceSettings(
878             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
879
880         self.inst_creator = OpenStackVmInstance(
881             self.os_creds, instance_settings, self.image_creator.image_settings)
882
883         with self.assertRaises(Exception):
884             self.inst_creator.create()
885
886     def test_set_custom_mac_and_ip(self):
887         """
888         Tests the creation of an OpenStack instance with a single port where the IP and MAC address is assigned.
889         """
890         ip = '10.55.0.101'
891         mac_addr = '0a:1b:2c:3d:4e:5f'
892         port_settings = PortSettings(
893             name=self.port_1_name, network_name=self.net_config.network_settings.name, mac_address=mac_addr,
894             ip_addrs=[{'subnet_name': self.net_config.network_settings.subnet_settings[0].name, 'ip': ip}])
895
896         instance_settings = VmInstanceSettings(
897             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
898
899         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
900         self.inst_creator.create()
901
902         self.assertEquals(ip, self.inst_creator.get_port_ip(
903             self.port_1_name, subnet_name=self.net_config.network_settings.subnet_settings[0].name))
904         self.assertEquals(mac_addr, self.inst_creator.get_port_mac(self.port_1_name))
905
906     def test_set_allowed_address_pairs(self):
907         """
908         Tests the creation of an OpenStack instance with a single port where max_allowed_address_pair is set.
909         """
910         ip = '10.55.0.101'
911         mac_addr = '0a:1b:2c:3d:4e:5f'
912         pair = {'ip_address': ip, 'mac_address': mac_addr}
913         port_settings = PortSettings(
914             name=self.port_1_name, network_name=self.net_config.network_settings.name, allowed_address_pairs=[pair])
915
916         instance_settings = VmInstanceSettings(
917             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
918
919         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
920         self.inst_creator.create()
921
922         port = self.inst_creator.get_port_by_name(port_settings.name)
923         self.assertIsNotNone(port)
924         self.assertIsNotNone(port['port'].get('allowed_address_pairs'))
925         self.assertEquals(1, len(port['port']['allowed_address_pairs']))
926         validation_utils.objects_equivalent(pair, port['port']['allowed_address_pairs'][0])
927
928     def test_set_allowed_address_pairs_bad_mac(self):
929         """
930         Tests the creation of an OpenStack instance with a single port where max_allowed_address_pair is set with an
931         invalid MAC address.
932         """
933         ip = '10.55.0.101'
934         mac_addr = 'foo'
935         pair = {'ip_address': ip, 'mac_address': mac_addr}
936         pairs = set()
937         pairs.add((ip, mac_addr))
938         port_settings = PortSettings(
939             name=self.port_1_name, network_name=self.net_config.network_settings.name, allowed_address_pairs=[pair])
940
941         instance_settings = VmInstanceSettings(
942             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
943
944         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
945         with self.assertRaises(Exception):
946             self.inst_creator.create()
947
948     def test_set_allowed_address_pairs_bad_ip(self):
949         """
950         Tests the creation of an OpenStack instance with a single port where max_allowed_address_pair is set with an
951         invalid MAC address.
952         """
953         ip = 'foo'
954         mac_addr = '0a:1b:2c:3d:4e:5f'
955         pair = {'ip_address': ip, 'mac_address': mac_addr}
956         pairs = set()
957         pairs.add((ip, mac_addr))
958         port_settings = PortSettings(
959             name=self.port_1_name, network_name=self.net_config.network_settings.name, allowed_address_pairs=[pair])
960
961         instance_settings = VmInstanceSettings(
962             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[port_settings])
963
964         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
965         with self.assertRaises(Exception):
966             self.inst_creator.create()
967
968
969 class CreateInstanceOnComputeHost(OSIntegrationTestCase):
970     """
971     Test for the CreateInstance where one VM is deployed to each compute node
972     """
973
974     def setUp(self):
975         """
976         Instantiates the CreateImage object that is responsible for downloading and creating an OS image file
977         within OpenStack
978         """
979         super(self.__class__, self).__start__()
980
981         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
982         self.vm_inst_name = guid + '-inst'
983         self.port_base_name = guid + 'port'
984
985         # Initialize for tearDown()
986         self.image_creator = None
987         self.flavor_creator = None
988         self.network_creator = None
989         self.inst_creators = list()
990
991         self.priv_net_config = openstack_tests.get_priv_net_config(
992             net_name=guid + '-priv-net', subnet_name=guid + '-priv-subnet')
993
994         self.os_image_settings = openstack_tests.cirros_url_image(name=guid + '-image')
995
996         try:
997             # Create Network
998             self.network_creator = OpenStackNetwork(self.admin_os_creds, self.priv_net_config.network_settings)
999             self.network_creator.create()
1000
1001             # Create Flavor
1002             self.flavor_creator = OpenStackFlavor(
1003                 self.admin_os_creds,
1004                 FlavorSettings(name=guid + '-flavor-name', ram=512, disk=1, vcpus=1, metadata=self.flavor_metadata))
1005             self.flavor_creator.create()
1006
1007             # Create Image
1008             self.image_creator = OpenStackImage(self.admin_os_creds, self.os_image_settings)
1009             self.image_creator.create()
1010
1011         except Exception as e:
1012             self.tearDown()
1013             raise e
1014
1015     def tearDown(self):
1016         """
1017         Cleans the created object
1018         """
1019         for inst_creator in self.inst_creators:
1020             try:
1021                 inst_creator.clean()
1022             except Exception as e:
1023                 logger.error('Unexpected exception cleaning VM instance with message - ' + e.message)
1024
1025         if self.flavor_creator:
1026             try:
1027                 self.flavor_creator.clean()
1028             except Exception as e:
1029                 logger.error('Unexpected exception cleaning flavor with message - ' + e.message)
1030
1031         if self.network_creator:
1032             try:
1033                 self.network_creator.clean()
1034             except Exception as e:
1035                 logger.error('Unexpected exception cleaning network with message - ' + e.message)
1036
1037         if self.image_creator:
1038             try:
1039                 self.image_creator.clean()
1040             except Exception as e:
1041                 logger.error('Unexpected exception cleaning image with message - ' + e.message)
1042
1043         super(self.__class__, self).__clean__()
1044
1045     def test_deploy_vm_to_each_compute_node(self):
1046         """
1047         Tests the creation of OpenStack VM instances to each compute node.
1048         """
1049         from snaps.openstack.utils import nova_utils
1050         nova = nova_utils.nova_client(self.admin_os_creds)
1051         zones = nova_utils.get_nova_availability_zones(nova)
1052
1053         # Create Instance on each server/zone
1054         ctr = 0
1055         for zone in zones:
1056             inst_name = self.vm_inst_name + '-' + zone
1057             ctr += 1
1058             port_settings = PortSettings(name=self.port_base_name + '-' + str(ctr),
1059                                          network_name=self.priv_net_config.network_settings.name)
1060
1061             instance_settings = VmInstanceSettings(
1062                 name=inst_name, flavor=self.flavor_creator.flavor_settings.name, availability_zone=zone,
1063                 port_settings=[port_settings])
1064             inst_creator = OpenStackVmInstance(
1065                 self.admin_os_creds, instance_settings, self.image_creator.image_settings)
1066             self.inst_creators.append(inst_creator)
1067             inst_creator.create()
1068
1069         # Validate instances to ensure they've been deployed to the correct server
1070         index = 0
1071         for zone in zones:
1072             creator = self.inst_creators[index]
1073             self.assertTrue(creator.vm_active(block=True))
1074             vm = creator.get_vm_inst()
1075             deployed_zone = vm._info['OS-EXT-AZ:availability_zone']
1076             deployed_host = vm._info['OS-EXT-SRV-ATTR:host']
1077             self.assertEquals(zone, deployed_zone + ':' + deployed_host)
1078             index += 1
1079
1080
1081 class CreateInstancePubPrivNetTests(OSIntegrationTestCase):
1082     """
1083     Test for the CreateInstance class with two NIC/Ports, eth0 with floating IP and eth1 w/o
1084     These tests require a Centos image
1085     """
1086
1087     def setUp(self):
1088         """
1089         Instantiates the CreateImage object that is responsible for downloading and creating an OS image file
1090         within OpenStack
1091         """
1092         super(self.__class__, self).__start__()
1093
1094         # Initialize for tearDown()
1095         self.image_creator = None
1096         self.network_creators = list()
1097         self.router_creators = list()
1098         self.flavor_creator = None
1099         self.keypair_creator = None
1100         self.inst_creator = None
1101
1102         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1103         self.keypair_priv_filepath = 'tmp/' + self.guid
1104         self.keypair_pub_filepath = self.keypair_priv_filepath + '.pub'
1105         self.keypair_name = self.guid + '-kp'
1106         self.vm_inst_name = self.guid + '-inst'
1107         self.port_1_name = self.guid + '-port-1'
1108         self.port_2_name = self.guid + '-port-2'
1109         self.floating_ip_name = self.guid + 'fip1'
1110         self.priv_net_config = openstack_tests.get_priv_net_config(
1111             net_name=self.guid + '-priv-net', subnet_name=self.guid + '-priv-subnet',
1112             router_name=self.guid + '-priv-router', external_net=self.ext_net_name)
1113         self.pub_net_config = openstack_tests.get_pub_net_config(
1114             net_name=self.guid + '-pub-net', subnet_name=self.guid + '-pub-subnet',
1115             router_name=self.guid + '-pub-router', external_net=self.ext_net_name)
1116         image_name = self.__class__.__name__ + '-' + str(uuid.uuid4())
1117         self.os_image_settings = openstack_tests.centos_url_image(name=image_name)
1118
1119         try:
1120             # Create Image
1121             self.image_creator = OpenStackImage(self.os_creds, self.os_image_settings)
1122             self.image_creator.create()
1123
1124             # First network is public
1125             self.network_creators.append(OpenStackNetwork(self.os_creds, self.pub_net_config.network_settings))
1126             # Second network is private
1127             self.network_creators.append(OpenStackNetwork(self.os_creds, self.priv_net_config.network_settings))
1128             for network_creator in self.network_creators:
1129                 network_creator.create()
1130
1131             self.router_creators.append(OpenStackRouter(self.os_creds, self.pub_net_config.router_settings))
1132             self.router_creators.append(OpenStackRouter(self.os_creds, self.priv_net_config.router_settings))
1133
1134             # Create Routers
1135             for router_creator in self.router_creators:
1136                 router_creator.create()
1137
1138             # Create Flavor
1139             self.flavor_creator = OpenStackFlavor(
1140                 self.admin_os_creds,
1141                 FlavorSettings(name=self.guid + '-flavor-name', ram=2048, disk=10, vcpus=2,
1142                                metadata=self.flavor_metadata))
1143             self.flavor_creator.create()
1144
1145             # Create Keypair
1146             self.keypair_creator = OpenStackKeypair(
1147                 self.os_creds, KeypairSettings(
1148                     name=self.keypair_name, public_filepath=self.keypair_pub_filepath,
1149                     private_filepath=self.keypair_priv_filepath))
1150             self.keypair_creator.create()
1151         except Exception as e:
1152             self.tearDown()
1153             raise Exception(e.message)
1154
1155     def tearDown(self):
1156         """
1157         Cleans the created objects
1158         """
1159         if self.inst_creator:
1160             try:
1161                 self.inst_creator.clean()
1162             except Exception as e:
1163                 logger.error('Unexpected exception cleaning VM instance with message - ' + e.message)
1164
1165         if self.keypair_creator:
1166             try:
1167                 self.keypair_creator.clean()
1168             except Exception as e:
1169                 logger.error('Unexpected exception cleaning keypair with message - ' + e.message)
1170
1171         if os.path.isfile(self.keypair_pub_filepath):
1172             os.remove(self.keypair_pub_filepath)
1173
1174         if os.path.isfile(self.keypair_priv_filepath):
1175             os.remove(self.keypair_priv_filepath)
1176
1177         if self.flavor_creator:
1178             try:
1179                 self.flavor_creator.clean()
1180             except Exception as e:
1181                 logger.error('Unexpected exception cleaning flavor with message - ' + e.message)
1182
1183         for router_creator in self.router_creators:
1184             try:
1185                 router_creator.clean()
1186             except Exception as e:
1187                 logger.error('Unexpected exception cleaning router with message - ' + e.message)
1188
1189         for network_creator in self.network_creators:
1190             try:
1191                 network_creator.clean()
1192             except Exception as e:
1193                 logger.error('Unexpected exception cleaning network with message - ' + e.message)
1194
1195         if self.image_creator:
1196             try:
1197                 self.image_creator.clean()
1198             except Exception as e:
1199                 logger.error('Unexpected exception cleaning image with message - ' + e.message)
1200
1201         super(self.__class__, self).__clean__()
1202
1203     def test_dual_ports_dhcp(self):
1204         """
1205         Tests the creation of an OpenStack instance with a dual ports/NICs with a DHCP assigned IP.
1206         NOTE: This test and any others that call ansible will most likely fail unless you do one of
1207         two things:
1208         1. Have a ~/.ansible.cfg (or alternate means) to set host_key_checking = False
1209         2. Set the following environment variable in your executing shell: ANSIBLE_HOST_KEY_CHECKING=False
1210         Should this not be performed, the creation of the host ssh key will cause your ansible calls to fail.
1211         """
1212         # Create ports/NICs for instance
1213         ports_settings = []
1214         ctr = 1
1215         for network_creator in self.network_creators:
1216             ports_settings.append(PortSettings(
1217                 name=self.guid + '-port-' + str(ctr),
1218                 network_name=network_creator.network_settings.name))
1219             ctr += 1
1220
1221         # Create instance
1222         instance_settings = VmInstanceSettings(
1223             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=ports_settings,
1224             floating_ip_settings=[FloatingIpSettings(
1225                 name=self.floating_ip_name, port_name=self.port_1_name,
1226                 router_name=self.pub_net_config.router_settings.name)])
1227
1228         self.inst_creator = OpenStackVmInstance(
1229             self.os_creds, instance_settings, self.image_creator.image_settings,
1230             keypair_settings=self.keypair_creator.keypair_settings)
1231
1232         vm_inst = self.inst_creator.create(block=True)
1233
1234         self.assertEquals(vm_inst, self.inst_creator.get_vm_inst())
1235
1236         # Effectively blocks until VM has been properly activated
1237         self.assertTrue(self.inst_creator.vm_active(block=True))
1238
1239         # Effectively blocks until VM's ssh port has been opened
1240         self.assertTrue(self.inst_creator.vm_ssh_active(block=True))
1241
1242         self.inst_creator.config_nics()
1243
1244         # TODO - *** ADD VALIDATION HERE ***
1245         # TODO - Add validation that both floating IPs work
1246         # TODO - Add tests where only one NIC has a floating IP
1247         # TODO - Add tests where one attempts to place a floating IP on a network/router without an external gateway
1248
1249
1250 class InstanceSecurityGroupTests(OSIntegrationTestCase):
1251     """
1252     Tests that include, add, and remove security groups from VM instances
1253     """
1254     def setUp(self):
1255         """
1256         Instantiates the CreateImage object that is responsible for downloading and creating an OS image file
1257         within OpenStack
1258         """
1259         super(self.__class__, self).__start__()
1260
1261         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1262         self.vm_inst_name = self.guid + '-inst'
1263         self.nova = nova_utils.nova_client(self.os_creds)
1264         self.os_image_settings = openstack_tests.cirros_url_image(name=self.guid + '-image')
1265
1266         self.vm_inst_name = self.guid + '-inst'
1267         self.port_1_name = self.guid + 'port-1'
1268         self.port_2_name = self.guid + 'port-2'
1269         self.floating_ip_name = self.guid + 'fip1'
1270
1271         net_config = openstack_tests.get_priv_net_config(
1272             net_name=self.guid + '-pub-net', subnet_name=self.guid + '-pub-subnet',
1273             router_name=self.guid + '-pub-router', external_net=self.ext_net_name)
1274
1275         # Initialize for tearDown()
1276         self.image_creator = None
1277         self.flavor_creator = None
1278         self.network_creator = None
1279         self.router_creator = None
1280         self.inst_creator = None
1281         self.sec_grp_creators = list()
1282
1283         try:
1284             # Create Image
1285             self.image_creator = OpenStackImage(self.os_creds, self.os_image_settings)
1286             self.image_creator.create()
1287
1288             # Create Network
1289             self.network_creator = OpenStackNetwork(self.os_creds, net_config.network_settings)
1290             self.network_creator.create()
1291
1292             # Create Flavor
1293             self.flavor_creator = OpenStackFlavor(
1294                 self.admin_os_creds,
1295                 FlavorSettings(name=self.guid + '-flavor-name', ram=2048, disk=10, vcpus=2,
1296                                metadata=self.flavor_metadata))
1297             self.flavor_creator.create()
1298
1299             self.port_settings = PortSettings(name=self.guid + '-port',
1300                                               network_name=net_config.network_settings.name)
1301         except Exception as e:
1302             self.tearDown()
1303             raise e
1304
1305     def tearDown(self):
1306         """
1307         Cleans the created object
1308         """
1309         if self.inst_creator:
1310             try:
1311                 self.inst_creator.clean()
1312             except Exception as e:
1313                 logger.error('Unexpected exception cleaning VM instance with message - ' + e.message)
1314
1315         for sec_grp_creator in self.sec_grp_creators:
1316             try:
1317                 sec_grp_creator.clean()
1318             except Exception as e:
1319                 logger.error('Unexpected exception cleaning security group with message - ' + e.message)
1320
1321         if self.flavor_creator:
1322             try:
1323                 self.flavor_creator.clean()
1324             except Exception as e:
1325                 logger.error('Unexpected exception cleaning flavor with message - ' + e.message)
1326
1327         if self.network_creator:
1328             try:
1329                 self.network_creator.clean()
1330             except Exception as e:
1331                 logger.error('Unexpected exception cleaning network with message - ' + e.message)
1332
1333         if self.image_creator:
1334             try:
1335                 self.image_creator.clean()
1336             except Exception as e:
1337                 logger.error('Unexpected exception cleaning image with message - ' + e.message)
1338
1339         super(self.__class__, self).__clean__()
1340
1341     def test_add_security_group(self):
1342         """
1343         Tests the addition of a security group created after the instance.
1344         """
1345         # Create instance
1346         instance_settings = VmInstanceSettings(
1347             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[self.port_settings])
1348         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
1349         vm_inst = self.inst_creator.create(block=True)
1350         self.assertIsNotNone(vm_inst)
1351
1352         # Create security group object to add to instance
1353         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name', description='hello group')
1354         sec_grp_creator = OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
1355         sec_grp = sec_grp_creator.create()
1356         self.sec_grp_creators.append(sec_grp_creator)
1357
1358         # Check that group has not been added
1359         self.assertFalse(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1360
1361         # Add security group to instance after activated
1362         self.inst_creator.add_security_group(sec_grp)
1363
1364         # Validate that security group has been added
1365         self.assertTrue(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1366
1367     def test_add_invalid_security_group(self):
1368         """
1369         Tests the addition of a security group that no longer exists.
1370         """
1371         # Create instance
1372         instance_settings = VmInstanceSettings(
1373             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[self.port_settings])
1374         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
1375         vm_inst = self.inst_creator.create(block=True)
1376         self.assertIsNotNone(vm_inst)
1377
1378         # Create security group object to add to instance
1379         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name', description='hello group')
1380         sec_grp_creator = OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
1381         sec_grp = sec_grp_creator.create()
1382         sec_grp_creator.clean()
1383         self.sec_grp_creators.append(sec_grp_creator)
1384
1385         # Check that group has not been added
1386         self.assertFalse(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.assertFalse(self.inst_creator.add_security_group(sec_grp))
1390
1391         # Validate that security group has been added
1392         self.assertFalse(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1393
1394     def test_remove_security_group(self):
1395         """
1396         Tests the removal of a security group created before and added to the instance.
1397         """
1398         # Create security group object to add to instance
1399         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name', description='hello group')
1400         sec_grp_creator = OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
1401         sec_grp = sec_grp_creator.create()
1402         self.sec_grp_creators.append(sec_grp_creator)
1403
1404         # Create instance
1405         instance_settings = VmInstanceSettings(
1406             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name,
1407             security_group_names=[sec_grp_settings.name], port_settings=[self.port_settings])
1408         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
1409         vm_inst = self.inst_creator.create(block=True)
1410         self.assertIsNotNone(vm_inst)
1411
1412         # Check that group has been added
1413         self.assertTrue(inst_has_sec_grp(vm_inst, sec_grp_settings.name))
1414
1415         # Add security group to instance after activated
1416         self.assertTrue(self.inst_creator.remove_security_group(sec_grp))
1417
1418         # Validate that security group has been added
1419         self.assertFalse(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1420
1421     def test_remove_security_group_never_added(self):
1422         """
1423         Tests the removal of a security group that was never added in the first place.
1424         """
1425         # Create security group object to add to instance
1426         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name', description='hello group')
1427         sec_grp_creator = OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
1428         sec_grp = sec_grp_creator.create()
1429         self.sec_grp_creators.append(sec_grp_creator)
1430
1431         # Create instance
1432         instance_settings = VmInstanceSettings(
1433             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name, port_settings=[self.port_settings])
1434         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
1435         vm_inst = self.inst_creator.create(block=True)
1436         self.assertIsNotNone(vm_inst)
1437
1438         # Check that group has been added
1439         self.assertFalse(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1440
1441         # Add security group to instance after activated
1442         self.assertFalse(self.inst_creator.remove_security_group(sec_grp))
1443
1444         # Validate that security group has been added
1445         self.assertFalse(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1446
1447     def test_add_same_security_group(self):
1448         """
1449         Tests the addition of a security group created before add added to the instance.
1450         """
1451         # Create security group object to add to instance
1452         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name', description='hello group')
1453         sec_grp_creator = OpenStackSecurityGroup(self.os_creds, sec_grp_settings)
1454         sec_grp = sec_grp_creator.create()
1455         self.sec_grp_creators.append(sec_grp_creator)
1456
1457         # Create instance
1458         instance_settings = VmInstanceSettings(
1459             name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name,
1460             security_group_names=[sec_grp_settings.name], port_settings=[self.port_settings])
1461         self.inst_creator = OpenStackVmInstance(self.os_creds, instance_settings, self.image_creator.image_settings)
1462         vm_inst = self.inst_creator.create(block=True)
1463         self.assertIsNotNone(vm_inst)
1464
1465         # Check that group has been added
1466         self.assertTrue(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1467
1468         # Add security group to instance after activated
1469         self.assertTrue(self.inst_creator.add_security_group(sec_grp))
1470
1471         # Validate that security group has been added
1472         self.assertTrue(inst_has_sec_grp(self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1473
1474
1475 def inst_has_sec_grp(vm_inst, sec_grp_name):
1476     """
1477     Returns true if instance has a security group of a given name
1478     :return:
1479     """
1480     if not hasattr(vm_inst, 'security_groups'):
1481         return False
1482
1483     found = False
1484     for sec_grp_dict in vm_inst.security_groups:
1485         if sec_grp_name in sec_grp_dict['name']:
1486             found = True
1487             break
1488     return found
1489
1490
1491 def validate_ssh_client(instance_creator):
1492     """
1493     Returns True if instance_creator returns an SSH client that is valid
1494     :param instance_creator: the object responsible for creating the VM instance
1495     :return: T/F
1496     """
1497     ssh_active = instance_creator.vm_ssh_active(block=True)
1498
1499     if ssh_active:
1500         ssh_client = instance_creator.ssh_client()
1501         if ssh_client:
1502             out = ssh_client.exec_command('pwd')[1]
1503         else:
1504             return False
1505
1506         channel = out.channel
1507         in_buffer = channel.in_buffer
1508         pwd_out = in_buffer.read(1024)
1509         if not pwd_out or len(pwd_out) < 10:
1510             return False
1511         return True
1512
1513     return False
1514
1515
1516 class CreateInstanceFromThreePartImage(OSIntegrationTestCase):
1517     """
1518     Test for the CreateInstance class for creating an image from a 3-part image
1519     """
1520
1521     def setUp(self):
1522         """
1523         Instantiates the CreateImage object that is responsible for downloading and creating an OS image file
1524         within OpenStack
1525         """
1526         super(self.__class__, self).__start__()
1527
1528         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1529         self.image_name = guid
1530         self.vm_inst_name = guid + '-inst'
1531         self.nova = nova_utils.nova_client(self.os_creds)
1532
1533         net_config = openstack_tests.get_priv_net_config(
1534             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
1535             router_name=guid + '-pub-router', external_net=self.ext_net_name)
1536
1537         # Initialize for tearDown()
1538         self.image_creators = list()
1539         self.network_creator = None
1540         self.flavor_creator = None
1541         self.inst_creator = None
1542
1543         try:
1544             # Create Images
1545             # Create the kernel image
1546             kernel_image_settings = openstack_tests.cirros_url_image(
1547                 name=self.image_name+'_kernel',
1548                 url='http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-kernel')
1549             self.image_creators.append(OpenStackImage(self.os_creds, kernel_image_settings))
1550             kernel_image = self.image_creators[-1].create()
1551
1552             # Create the ramdisk image
1553             ramdisk_image_settings = openstack_tests.cirros_url_image(
1554                 name=self.image_name+'_ramdisk',
1555                 url='http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-initramfs')
1556             self.image_creators.append(OpenStackImage(self.os_creds, ramdisk_image_settings))
1557             ramdisk_image = self.image_creators[-1].create()
1558             self.assertIsNotNone(ramdisk_image)
1559
1560             # Create the main image
1561             os_image_settings = openstack_tests.cirros_url_image(
1562                 name=self.image_name,
1563                 url='http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-disk.img')
1564             properties = dict()
1565             properties['kernel_id'] = kernel_image.id
1566             properties['ramdisk_id'] = ramdisk_image.id
1567             os_image_settings.extra_properties = properties
1568             self.image_creators.append(OpenStackImage(self.os_creds, os_image_settings))
1569             created_image = self.image_creators[-1].create()
1570             self.assertIsNotNone(created_image)
1571
1572             # Create Flavor
1573             self.flavor_creator = OpenStackFlavor(
1574                 self.admin_os_creds,
1575                 FlavorSettings(name=guid + '-flavor-name', ram=2048, disk=10, vcpus=2, metadata=self.flavor_metadata))
1576             self.flavor_creator.create()
1577
1578             # Create Network
1579             self.network_creator = OpenStackNetwork(self.os_creds, net_config.network_settings)
1580             self.network_creator.create()
1581
1582             self.port_settings = PortSettings(name=guid + '-port',
1583                                               network_name=net_config.network_settings.name)
1584         except Exception as e:
1585             self.tearDown()
1586             raise e
1587
1588     def tearDown(self):
1589         """
1590         Cleans the created object
1591         """
1592         if self.inst_creator:
1593             try:
1594                 self.inst_creator.clean()
1595             except Exception as e:
1596                 logger.error('Unexpected exception cleaning VM instance with message - ' + e.message)
1597
1598         if self.flavor_creator:
1599             try:
1600                 self.flavor_creator.clean()
1601             except Exception as e:
1602                 logger.error('Unexpected exception cleaning flavor with message - ' + e.message)
1603
1604         if self.network_creator:
1605             try:
1606                 self.network_creator.clean()
1607             except Exception as e:
1608                 logger.error('Unexpected exception cleaning network with message - ' + e.message)
1609
1610         if self.image_creators:
1611             try:
1612                 while self.image_creators:
1613                     self.image_creators[0].clean()
1614                     self.image_creators.pop(0)
1615             except Exception as e:
1616                 logger.error('Unexpected exception cleaning image with message - ' + e.message)
1617
1618         super(self.__class__, self).__clean__()
1619
1620     def test_create_delete_instance_from_three_part_image(self):
1621         """
1622         Tests the creation of an OpenStack instance from a 3-part image.
1623         """
1624         instance_settings = VmInstanceSettings(name=self.vm_inst_name, flavor=self.flavor_creator.flavor_settings.name,
1625                                                port_settings=[self.port_settings])
1626
1627         # The last created image is the main image from which we create the instance
1628         self.inst_creator = OpenStackVmInstance(
1629             self.os_creds, instance_settings, self.image_creators[-1].image_settings)
1630
1631         vm_inst = self.inst_creator.create()
1632         self.assertEquals(1, len(nova_utils.get_servers_by_name(self.nova, instance_settings.name)))
1633
1634         # Delete instance
1635         nova_utils.delete_vm_instance(self.nova, vm_inst)
1636
1637         self.assertTrue(self.inst_creator.vm_deleted(block=True))
1638         self.assertEquals(0, len(nova_utils.get_servers_by_name(self.nova, instance_settings.name)))
1639
1640         # Exception should not be thrown
1641         self.inst_creator.clean()