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