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