Created custom exceptions for VM instance creation.
[snaps.git] / snaps / openstack / tests / create_instance_tests.py
1 # Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs")
2 #                    and others.  All rights reserved.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 import logging
16 import re
17 import shutil
18 import time
19 import unittest
20 import uuid
21
22 import os
23 from neutronclient.common.exceptions import InvalidIpForSubnetClient
24
25 from snaps import file_utils
26 from snaps.openstack.create_flavor import OpenStackFlavor, FlavorSettings
27 from snaps.openstack.create_image import OpenStackImage, ImageSettings
28 from snaps.openstack.create_instance import (
29     VmInstanceSettings, OpenStackVmInstance, FloatingIpSettings,
30     VmInstanceSettingsError, FloatingIpSettingsError)
31 from snaps.openstack.create_keypairs import OpenStackKeypair, KeypairSettings
32 from snaps.openstack.create_network import OpenStackNetwork, PortSettings
33 from snaps.openstack.create_router import OpenStackRouter
34 from snaps.openstack.create_security_group import (
35     SecurityGroupSettings, OpenStackSecurityGroup, SecurityGroupRuleSettings,
36     Direction, Protocol)
37 from snaps.openstack.tests import openstack_tests, validation_utils
38 from snaps.openstack.tests.os_source_file_test import (
39     OSIntegrationTestCase, OSComponentTestCase)
40 from snaps.openstack.utils import nova_utils
41
42 __author__ = 'spisarski'
43
44 VM_BOOT_TIMEOUT = 600
45
46 logger = logging.getLogger('create_instance_tests')
47
48
49 class VmInstanceSettingsUnitTests(unittest.TestCase):
50     """
51     Tests the construction of the VmInstanceSettings class
52     """
53
54     def test_no_params(self):
55         with self.assertRaises(VmInstanceSettingsError):
56             VmInstanceSettings()
57
58     def test_empty_config(self):
59         with self.assertRaises(VmInstanceSettingsError):
60             VmInstanceSettings(config=dict())
61
62     def test_name_only(self):
63         with self.assertRaises(VmInstanceSettingsError):
64             VmInstanceSettings(name='foo')
65
66     def test_config_with_name_only(self):
67         with self.assertRaises(VmInstanceSettingsError):
68             VmInstanceSettings(config={'name': 'foo'})
69
70     def test_name_flavor_only(self):
71         with self.assertRaises(VmInstanceSettingsError):
72             VmInstanceSettings(name='foo', flavor='bar')
73
74     def test_config_with_name_flavor_only(self):
75         with self.assertRaises(VmInstanceSettingsError):
76             VmInstanceSettings(config={'name': 'foo', 'flavor': 'bar'})
77
78     def test_name_flavor_port_only(self):
79         port_settings = PortSettings(name='foo-port', network_name='bar-net')
80         settings = VmInstanceSettings(name='foo', flavor='bar',
81                                       port_settings=[port_settings])
82         self.assertEqual('foo', settings.name)
83         self.assertEqual('bar', settings.flavor)
84         self.assertEqual(1, len(settings.port_settings))
85         self.assertEqual('foo-port', settings.port_settings[0].name)
86         self.assertEqual('bar-net', settings.port_settings[0].network_name)
87         self.assertEqual(0, len(settings.security_group_names))
88         self.assertEqual(0, len(settings.floating_ip_settings))
89         self.assertIsNone(settings.sudo_user)
90         self.assertEqual(900, settings.vm_boot_timeout)
91         self.assertEqual(300, settings.vm_delete_timeout)
92         self.assertEqual(180, settings.ssh_connect_timeout)
93         self.assertIsNone(settings.availability_zone)
94
95     def test_config_with_name_flavor_port_only(self):
96         port_settings = PortSettings(name='foo-port', network_name='bar-net')
97         settings = VmInstanceSettings(
98             **{'name': 'foo', 'flavor': 'bar', 'ports': [port_settings]})
99         self.assertEqual('foo', settings.name)
100         self.assertEqual('bar', settings.flavor)
101         self.assertEqual(1, len(settings.port_settings))
102         self.assertEqual('foo-port', settings.port_settings[0].name)
103         self.assertEqual('bar-net', settings.port_settings[0].network_name)
104         self.assertEqual(0, len(settings.security_group_names))
105         self.assertEqual(0, len(settings.floating_ip_settings))
106         self.assertIsNone(settings.sudo_user)
107         self.assertEqual(900, settings.vm_boot_timeout)
108         self.assertEqual(300, settings.vm_delete_timeout)
109         self.assertEqual(180, settings.ssh_connect_timeout)
110         self.assertIsNone(settings.availability_zone)
111
112     def test_all(self):
113         port_settings = PortSettings(name='foo-port', network_name='bar-net')
114         fip_settings = FloatingIpSettings(name='foo-fip', port_name='bar-port',
115                                           router_name='foo-bar-router')
116
117         settings = VmInstanceSettings(name='foo', flavor='bar',
118                                       port_settings=[port_settings],
119                                       security_group_names=['sec_grp_1'],
120                                       floating_ip_settings=[fip_settings],
121                                       sudo_user='joe', vm_boot_timeout=999,
122                                       vm_delete_timeout=333,
123                                       ssh_connect_timeout=111,
124                                       availability_zone='server name')
125         self.assertEqual('foo', settings.name)
126         self.assertEqual('bar', settings.flavor)
127         self.assertEqual(1, len(settings.port_settings))
128         self.assertEqual('foo-port', settings.port_settings[0].name)
129         self.assertEqual('bar-net', settings.port_settings[0].network_name)
130         self.assertEqual(1, len(settings.security_group_names))
131         self.assertEqual('sec_grp_1', settings.security_group_names[0])
132         self.assertEqual(1, len(settings.floating_ip_settings))
133         self.assertEqual('foo-fip', settings.floating_ip_settings[0].name)
134         self.assertEqual('bar-port',
135                          settings.floating_ip_settings[0].port_name)
136         self.assertEqual('foo-bar-router',
137                          settings.floating_ip_settings[0].router_name)
138         self.assertEqual('joe', settings.sudo_user)
139         self.assertEqual(999, settings.vm_boot_timeout)
140         self.assertEqual(333, settings.vm_delete_timeout)
141         self.assertEqual(111, settings.ssh_connect_timeout)
142         self.assertEqual('server name', settings.availability_zone)
143
144     def test_config_all(self):
145         port_settings = PortSettings(name='foo-port', network_name='bar-net')
146         fip_settings = FloatingIpSettings(name='foo-fip', port_name='bar-port',
147                                           router_name='foo-bar-router')
148
149         settings = VmInstanceSettings(
150             **{'name': 'foo', 'flavor': 'bar', 'ports': [port_settings],
151                'security_group_names': ['sec_grp_1'],
152                'floating_ips': [fip_settings], 'sudo_user': 'joe',
153                'vm_boot_timeout': 999, 'vm_delete_timeout': 333,
154                'ssh_connect_timeout': 111, 'availability_zone': 'server name'})
155         self.assertEqual('foo', settings.name)
156         self.assertEqual('bar', settings.flavor)
157         self.assertEqual(1, len(settings.port_settings))
158         self.assertEqual('foo-port', settings.port_settings[0].name)
159         self.assertEqual('bar-net', settings.port_settings[0].network_name)
160         self.assertEqual(1, len(settings.security_group_names))
161         self.assertEqual(1, len(settings.floating_ip_settings))
162         self.assertEqual('foo-fip', settings.floating_ip_settings[0].name)
163         self.assertEqual('bar-port',
164                          settings.floating_ip_settings[0].port_name)
165         self.assertEqual('foo-bar-router',
166                          settings.floating_ip_settings[0].router_name)
167         self.assertEqual('joe', settings.sudo_user)
168         self.assertEqual(999, settings.vm_boot_timeout)
169         self.assertEqual(333, settings.vm_delete_timeout)
170         self.assertEqual(111, settings.ssh_connect_timeout)
171         self.assertEqual('server name', settings.availability_zone)
172
173
174 class FloatingIpSettingsUnitTests(unittest.TestCase):
175     """
176     Tests the construction of the FloatingIpSettings class
177     """
178
179     def test_no_params(self):
180         with self.assertRaises(FloatingIpSettingsError):
181             FloatingIpSettings()
182
183     def test_empty_config(self):
184         with self.assertRaises(FloatingIpSettingsError):
185             FloatingIpSettings(**dict())
186
187     def test_name_only(self):
188         with self.assertRaises(FloatingIpSettingsError):
189             FloatingIpSettings(name='foo')
190
191     def test_config_with_name_only(self):
192         with self.assertRaises(FloatingIpSettingsError):
193             FloatingIpSettings(**{'name': 'foo'})
194
195     def test_name_port_only(self):
196         with self.assertRaises(FloatingIpSettingsError):
197             FloatingIpSettings(name='foo', port_name='bar')
198
199     def test_config_with_name_port_only(self):
200         with self.assertRaises(FloatingIpSettingsError):
201             FloatingIpSettings(**{'name': 'foo', 'port_name': 'bar'})
202
203     def test_name_router_only(self):
204         with self.assertRaises(FloatingIpSettingsError):
205             FloatingIpSettings(name='foo', router_name='bar')
206
207     def test_config_with_name_router_only(self):
208         with self.assertRaises(FloatingIpSettingsError):
209             FloatingIpSettings(**{'name': 'foo', 'router_name': 'bar'})
210
211     def test_name_port_router_only(self):
212         settings = FloatingIpSettings(name='foo', port_name='foo-port',
213                                       router_name='bar-router')
214         self.assertEqual('foo', settings.name)
215         self.assertEqual('foo-port', settings.port_name)
216         self.assertEqual('bar-router', settings.router_name)
217         self.assertIsNone(settings.subnet_name)
218         self.assertTrue(settings.provisioning)
219
220     def test_config_with_name_port_router_only(self):
221         settings = FloatingIpSettings(
222             **{'name': 'foo', 'port_name': 'foo-port',
223                'router_name': 'bar-router'})
224         self.assertEqual('foo', settings.name)
225         self.assertEqual('foo-port', settings.port_name)
226         self.assertEqual('bar-router', settings.router_name)
227         self.assertIsNone(settings.subnet_name)
228         self.assertTrue(settings.provisioning)
229
230     def test_all(self):
231         settings = FloatingIpSettings(name='foo', port_name='foo-port',
232                                       router_name='bar-router',
233                                       subnet_name='bar-subnet',
234                                       provisioning=False)
235         self.assertEqual('foo', settings.name)
236         self.assertEqual('foo-port', settings.port_name)
237         self.assertEqual('bar-router', settings.router_name)
238         self.assertEqual('bar-subnet', settings.subnet_name)
239         self.assertFalse(settings.provisioning)
240
241     def test_config_all(self):
242         settings = FloatingIpSettings(
243             **{'name': 'foo', 'port_name': 'foo-port',
244                'router_name': 'bar-router', 'subnet_name': 'bar-subnet',
245                'provisioning': False})
246         self.assertEqual('foo', settings.name)
247         self.assertEqual('foo-port', settings.port_name)
248         self.assertEqual('bar-router', settings.router_name)
249         self.assertEqual('bar-subnet', settings.subnet_name)
250         self.assertFalse(settings.provisioning)
251
252
253 class SimpleHealthCheck(OSIntegrationTestCase):
254     """
255     Test for the CreateInstance class with a single NIC/Port with Floating IPs
256     """
257
258     def setUp(self):
259         """
260         Instantiates the CreateImage object that is responsible for downloading
261         and creating an OS image file
262         within OpenStack
263         """
264         super(self.__class__, self).__start__()
265
266         self.nova = nova_utils.nova_client(self.os_creds)
267         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
268         self.vm_inst_name = guid + '-inst'
269         self.port_1_name = guid + 'port-1'
270
271         # Initialize for tearDown()
272         self.image_creator = None
273         self.network_creator = None
274         self.flavor_creator = None
275         self.inst_creator = None
276
277         self.priv_net_config = openstack_tests.get_priv_net_config(
278             net_name=guid + '-priv-net', subnet_name=guid + '-priv-subnet')
279         self.port_settings = PortSettings(
280             name=self.port_1_name,
281             network_name=self.priv_net_config.network_settings.name)
282
283         # Create Image
284         # Set the default image settings, then set any custom parameters sent
285         # from the app
286         os_image_settings = openstack_tests.cirros_image_settings(
287             name=guid + '-image', image_metadata=self.image_metadata)
288
289         try:
290             self.image_creator = OpenStackImage(self.os_creds,
291                                                 os_image_settings)
292             self.image_creator.create()
293
294             # Create Network
295             self.network_creator = OpenStackNetwork(
296                 self.os_creds, self.priv_net_config.network_settings)
297             self.network_creator.create()
298
299             # Create Flavor
300             self.flavor_creator = OpenStackFlavor(
301                 self.admin_os_creds,
302                 FlavorSettings(name=guid + '-flavor-name', ram=128, disk=10,
303                                vcpus=1, metadata=self.flavor_metadata))
304             self.flavor_creator.create()
305         except Exception as e:
306             self.tearDown()
307             raise e
308
309     def tearDown(self):
310         """
311         Cleans the created object
312         """
313         if self.inst_creator:
314             try:
315                 self.inst_creator.clean()
316             except Exception as e:
317                 logger.error(
318                     'Unexpected exception cleaning VM instance with message'
319                     ' - %s', e)
320
321         if self.network_creator:
322             try:
323                 self.network_creator.clean()
324             except Exception as e:
325                 logger.error(
326                     'Unexpected exception cleaning network with message - %s',
327                     e)
328
329         if self.flavor_creator:
330             try:
331                 self.flavor_creator.clean()
332             except Exception as e:
333                 logger.error(
334                     'Unexpected exception cleaning flavor with message - %s',
335                     e)
336
337         if self.image_creator and not self.image_creator.image_settings.exists:
338             try:
339                 self.image_creator.clean()
340             except Exception as e:
341                 logger.error(
342                     'Unexpected exception cleaning image with message - %s',
343                     e)
344
345         super(self.__class__, self).__clean__()
346
347     def test_check_vm_ip_dhcp(self):
348         """
349         Tests the creation of an OpenStack instance with a single port and
350         ensures that it's assigned IP address is the actual.
351         """
352         instance_settings = VmInstanceSettings(
353             name=self.vm_inst_name,
354             flavor=self.flavor_creator.flavor_settings.name,
355             port_settings=[self.port_settings])
356
357         self.inst_creator = OpenStackVmInstance(
358             self.os_creds, instance_settings,
359             self.image_creator.image_settings)
360         self.inst_creator.create()
361
362         ip = self.inst_creator.get_port_ip(self.port_settings.name)
363         self.assertIsNotNone(ip)
364
365         self.assertTrue(self.inst_creator.vm_active(block=True))
366
367         self.assertTrue(check_dhcp_lease(self.inst_creator, ip))
368
369
370 class CreateInstanceSimpleTests(OSIntegrationTestCase):
371     """
372     Simple instance creation tests without any other objects
373     """
374
375     def setUp(self):
376         """
377         Instantiates the CreateImage object that is responsible for downloading
378         and creating an OS image file
379         within OpenStack
380         """
381         super(self.__class__, self).__start__()
382
383         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
384         self.vm_inst_name = guid + '-inst'
385         self.nova = nova_utils.nova_client(self.os_creds)
386         os_image_settings = openstack_tests.cirros_image_settings(
387             name=guid + '-image', image_metadata=self.image_metadata)
388
389         net_config = openstack_tests.get_priv_net_config(
390             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
391             router_name=guid + '-pub-router', external_net=self.ext_net_name)
392
393         # Initialize for tearDown()
394         self.image_creator = None
395         self.flavor_creator = None
396
397         self.network_creator = None
398         self.inst_creator = None
399
400         try:
401             # Create Image
402             self.image_creator = OpenStackImage(self.os_creds,
403                                                 os_image_settings)
404             self.image_creator.create()
405
406             # Create Flavor
407             self.flavor_creator = OpenStackFlavor(
408                 self.admin_os_creds,
409                 FlavorSettings(name=guid + '-flavor-name', ram=128, disk=10,
410                                vcpus=2, metadata=self.flavor_metadata))
411             self.flavor_creator.create()
412
413             # Create Network
414             self.network_creator = OpenStackNetwork(
415                 self.os_creds, net_config.network_settings)
416             self.network_creator.create()
417
418             self.port_settings = PortSettings(
419                 name=guid + '-port',
420                 network_name=net_config.network_settings.name)
421
422         except Exception as e:
423             self.tearDown()
424             raise e
425
426     def tearDown(self):
427         """
428         Cleans the created object
429         """
430         if self.inst_creator:
431             try:
432                 self.inst_creator.clean()
433             except Exception as e:
434                 logger.error(
435                     'Unexpected exception cleaning VM instance with message '
436                     '- %s', e)
437
438         if self.flavor_creator:
439             try:
440                 self.flavor_creator.clean()
441             except Exception as e:
442                 logger.error(
443                     'Unexpected exception cleaning flavor with message - %s',
444                     e)
445
446         if self.network_creator:
447             try:
448                 self.network_creator.clean()
449             except Exception as e:
450                 logger.error(
451                     'Unexpected exception cleaning network with message - %s',
452                     e)
453
454         if self.image_creator and not self.image_creator.image_settings.exists:
455             try:
456                 self.image_creator.clean()
457             except Exception as e:
458                 logger.error(
459                     'Unexpected exception cleaning image with message - %s', e)
460
461         super(self.__class__, self).__clean__()
462
463     def test_create_delete_instance(self):
464         """
465         Tests the creation of an OpenStack instance with a single port with a
466         static IP without a Floating IP.
467         """
468         instance_settings = VmInstanceSettings(
469             name=self.vm_inst_name,
470             flavor=self.flavor_creator.flavor_settings.name,
471             port_settings=[self.port_settings])
472
473         self.inst_creator = OpenStackVmInstance(
474             self.os_creds, instance_settings,
475             self.image_creator.image_settings)
476
477         vm_inst = self.inst_creator.create()
478         self.assertEqual(1, len(
479             nova_utils.get_servers_by_name(self.nova, instance_settings.name)))
480
481         # Delete instance
482         nova_utils.delete_vm_instance(self.nova, vm_inst)
483
484         self.assertTrue(self.inst_creator.vm_deleted(block=True))
485         self.assertEqual(0, len(
486             nova_utils.get_servers_by_name(self.nova, instance_settings.name)))
487
488         # Exception should not be thrown
489         self.inst_creator.clean()
490
491
492 class CreateInstanceSingleNetworkTests(OSIntegrationTestCase):
493     """
494     Test for the CreateInstance class with a single NIC/Port with Floating IPs
495     """
496
497     def setUp(self):
498         """
499         Instantiates the CreateImage object that is responsible for downloading
500         and creating an OS image file within OpenStack
501         """
502         super(self.__class__, self).__start__()
503
504         self.nova = nova_utils.nova_client(self.os_creds)
505         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
506         self.keypair_priv_filepath = 'tmp/' + guid
507         self.keypair_pub_filepath = self.keypair_priv_filepath + '.pub'
508         self.keypair_name = guid + '-kp'
509         self.vm_inst_name = guid + '-inst'
510         self.port_1_name = guid + 'port-1'
511         self.port_2_name = guid + 'port-2'
512         self.floating_ip_name = guid + 'fip1'
513
514         # Initialize for tearDown()
515         self.image_creator = None
516         self.network_creator = None
517         self.router_creator = None
518         self.flavor_creator = None
519         self.keypair_creator = None
520         self.sec_grp_creator = None
521         self.inst_creators = list()
522
523         self.pub_net_config = openstack_tests.get_pub_net_config(
524             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
525             router_name=guid + '-pub-router', external_net=self.ext_net_name)
526         os_image_settings = openstack_tests.cirros_image_settings(
527             name=guid + '-image', image_metadata=self.image_metadata)
528         try:
529             # Create Image
530             self.image_creator = OpenStackImage(self.os_creds,
531                                                 os_image_settings)
532             self.image_creator.create()
533
534             # Create Network
535             self.network_creator = OpenStackNetwork(
536                 self.os_creds, self.pub_net_config.network_settings)
537             self.network_creator.create()
538
539             # Create Router
540             self.router_creator = OpenStackRouter(
541                 self.os_creds, self.pub_net_config.router_settings)
542             self.router_creator.create()
543
544             # Create Flavor
545             self.flavor_creator = OpenStackFlavor(
546                 self.admin_os_creds,
547                 FlavorSettings(name=guid + '-flavor-name', ram=128, disk=10,
548                                vcpus=2, metadata=self.flavor_metadata))
549             self.flavor_creator.create()
550
551             self.keypair_creator = OpenStackKeypair(
552                 self.os_creds, KeypairSettings(
553                     name=self.keypair_name,
554                     public_filepath=self.keypair_pub_filepath,
555                     private_filepath=self.keypair_priv_filepath))
556             self.keypair_creator.create()
557
558             sec_grp_name = guid + '-sec-grp'
559             rule1 = SecurityGroupRuleSettings(sec_grp_name=sec_grp_name,
560                                               direction=Direction.ingress,
561                                               protocol=Protocol.icmp)
562             rule2 = SecurityGroupRuleSettings(sec_grp_name=sec_grp_name,
563                                               direction=Direction.ingress,
564                                               protocol=Protocol.tcp,
565                                               port_range_min=22,
566                                               port_range_max=22)
567             self.sec_grp_creator = OpenStackSecurityGroup(
568                 self.os_creds,
569                 SecurityGroupSettings(name=sec_grp_name,
570                                       rule_settings=[rule1, rule2]))
571             self.sec_grp_creator.create()
572         except Exception as e:
573             self.tearDown()
574             raise e
575
576     def tearDown(self):
577         """
578         Cleans the created object
579         """
580         for inst_creator in self.inst_creators:
581             try:
582                 inst_creator.clean()
583             except Exception as e:
584                 logger.error(
585                     'Unexpected exception cleaning VM instance with message '
586                     '- %s', e)
587
588         if self.keypair_creator:
589             try:
590                 self.keypair_creator.clean()
591             except Exception as e:
592                 logger.error(
593                     'Unexpected exception cleaning keypair with message - %s',
594                     e)
595
596         if os.path.isfile(self.keypair_pub_filepath):
597             os.remove(self.keypair_pub_filepath)
598
599         if os.path.isfile(self.keypair_priv_filepath):
600             os.remove(self.keypair_priv_filepath)
601
602         if self.flavor_creator:
603             try:
604                 self.flavor_creator.clean()
605             except Exception as e:
606                 logger.error(
607                     'Unexpected exception cleaning flavor with message - %s',
608                     e)
609
610         if self.sec_grp_creator:
611             try:
612                 self.sec_grp_creator.clean()
613             except Exception as e:
614                 logger.error(
615                     'Unexpected exception cleaning security group with message'
616                     ' - %s', e)
617
618         if self.router_creator:
619             try:
620                 self.router_creator.clean()
621             except Exception as e:
622                 logger.error(
623                     'Unexpected exception cleaning router with message - %s',
624                     e)
625
626         if self.network_creator:
627             try:
628                 self.network_creator.clean()
629             except Exception as e:
630                 logger.error(
631                     'Unexpected exception cleaning network with message - %s',
632                     e)
633
634         if self.image_creator and not self.image_creator.image_settings.exists:
635             try:
636                 self.image_creator.clean()
637             except Exception as e:
638                 logger.error(
639                     'Unexpected exception cleaning image with message - %s', e)
640
641         super(self.__class__, self).__clean__()
642
643     def test_single_port_static(self):
644         """
645         Tests the creation of an OpenStack instance with a single port with a
646         static IP without a Floating IP.
647         """
648         ip_1 = '10.55.1.100'
649         sub_settings = self.pub_net_config.network_settings.subnet_settings
650         port_settings = PortSettings(
651             name=self.port_1_name,
652             network_name=self.pub_net_config.network_settings.name,
653             ip_addrs=[
654                 {'subnet_name': sub_settings[0].name, 'ip': ip_1}])
655
656         instance_settings = VmInstanceSettings(
657             name=self.vm_inst_name,
658             flavor=self.flavor_creator.flavor_settings.name,
659             port_settings=[port_settings],
660             floating_ip_settings=[FloatingIpSettings(
661                 name=self.floating_ip_name, port_name=self.port_1_name,
662                 router_name=self.pub_net_config.router_settings.name)])
663
664         inst_creator = OpenStackVmInstance(
665             self.os_creds, instance_settings,
666             self.image_creator.image_settings,
667             keypair_settings=self.keypair_creator.keypair_settings)
668         self.inst_creators.append(inst_creator)
669         vm_inst = inst_creator.create()
670
671         self.assertEqual(ip_1, inst_creator.get_port_ip(self.port_1_name))
672         self.assertTrue(inst_creator.vm_active(block=True))
673         self.assertEqual(vm_inst, inst_creator.get_vm_inst())
674
675     def test_ssh_client_fip_before_active(self):
676         """
677         Tests the ability to access a VM via SSH and a floating IP when it has
678         been assigned prior to being active.
679         """
680         port_settings = PortSettings(
681             name=self.port_1_name,
682             network_name=self.pub_net_config.network_settings.name)
683
684         instance_settings = VmInstanceSettings(
685             name=self.vm_inst_name,
686             flavor=self.flavor_creator.flavor_settings.name,
687             port_settings=[port_settings],
688             floating_ip_settings=[FloatingIpSettings(
689                 name=self.floating_ip_name, port_name=self.port_1_name,
690                 router_name=self.pub_net_config.router_settings.name)])
691
692         inst_creator = OpenStackVmInstance(
693             self.os_creds, instance_settings,
694             self.image_creator.image_settings,
695             keypair_settings=self.keypair_creator.keypair_settings)
696         self.inst_creators.append(inst_creator)
697         vm_inst = inst_creator.create()
698         self.assertIsNotNone(vm_inst)
699
700         self.assertTrue(inst_creator.vm_active(block=True))
701
702         ip = inst_creator.get_port_ip(port_settings.name)
703         self.assertTrue(check_dhcp_lease(inst_creator, ip))
704
705         inst_creator.add_security_group(
706             self.sec_grp_creator.get_security_group())
707         self.assertEqual(vm_inst, inst_creator.get_vm_inst())
708
709         self.assertTrue(validate_ssh_client(inst_creator))
710
711     def test_ssh_client_fip_after_active(self):
712         """
713         Tests the ability to access a VM via SSH and a floating IP when it has
714         been assigned prior to being active.
715         """
716         port_settings = PortSettings(
717             name=self.port_1_name,
718             network_name=self.pub_net_config.network_settings.name)
719
720         instance_settings = VmInstanceSettings(
721             name=self.vm_inst_name,
722             flavor=self.flavor_creator.flavor_settings.name,
723             port_settings=[port_settings],
724             floating_ip_settings=[FloatingIpSettings(
725                 name=self.floating_ip_name, port_name=self.port_1_name,
726                 router_name=self.pub_net_config.router_settings.name)])
727
728         inst_creator = OpenStackVmInstance(
729             self.os_creds, instance_settings,
730             self.image_creator.image_settings,
731             keypair_settings=self.keypair_creator.keypair_settings)
732         self.inst_creators.append(inst_creator)
733
734         # block=True will force the create() method to block until the
735         vm_inst = inst_creator.create(block=True)
736         self.assertIsNotNone(vm_inst)
737
738         self.assertTrue(inst_creator.vm_active(block=True))
739
740         ip = inst_creator.get_port_ip(port_settings.name)
741         self.assertTrue(check_dhcp_lease(inst_creator, ip))
742
743         inst_creator.add_security_group(
744             self.sec_grp_creator.get_security_group())
745         self.assertEqual(vm_inst, inst_creator.get_vm_inst())
746
747         self.assertTrue(validate_ssh_client(inst_creator))
748
749
750 class CreateInstancePortManipulationTests(OSIntegrationTestCase):
751     """
752     Test for the CreateInstance class with a single NIC/Port where mac and IP
753     values are manually set
754     """
755
756     def setUp(self):
757         """
758         Instantiates the CreateImage object that is responsible for downloading
759         and creating an OS image file within OpenStack
760         """
761         super(self.__class__, self).__start__()
762
763         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
764         self.vm_inst_name = guid + '-inst'
765         self.port_1_name = guid + 'port-1'
766         self.port_2_name = guid + 'port-2'
767         self.floating_ip_name = guid + 'fip1'
768
769         # Initialize for tearDown()
770         self.image_creator = None
771         self.network_creator = None
772         self.flavor_creator = None
773         self.inst_creator = None
774
775         self.net_config = openstack_tests.get_priv_net_config(
776             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
777             router_name=guid + '-pub-router', external_net=self.ext_net_name)
778         os_image_settings = openstack_tests.cirros_image_settings(
779             name=guid + '-image', image_metadata=self.image_metadata)
780
781         try:
782             # Create Image
783             self.image_creator = OpenStackImage(self.os_creds,
784                                                 os_image_settings)
785             self.image_creator.create()
786
787             # Create Network
788             self.network_creator = OpenStackNetwork(
789                 self.os_creds, self.net_config.network_settings)
790             self.network_creator.create()
791
792             # Create Flavor
793             self.flavor_creator = OpenStackFlavor(
794                 self.admin_os_creds,
795                 FlavorSettings(name=guid + '-flavor-name', ram=128, disk=10,
796                                vcpus=2, metadata=self.flavor_metadata))
797             self.flavor_creator.create()
798         except Exception as e:
799             self.tearDown()
800             raise e
801
802     def tearDown(self):
803         """
804         Cleans the created object
805         """
806         if self.inst_creator:
807             try:
808                 self.inst_creator.clean()
809             except Exception as e:
810                 logger.error(
811                     'Unexpected exception cleaning VM instance with message '
812                     '- %s', e)
813
814         if self.flavor_creator:
815             try:
816                 self.flavor_creator.clean()
817             except Exception as e:
818                 logger.error(
819                     'Unexpected exception cleaning flavor with message - %s',
820                     e)
821
822         if self.network_creator:
823             try:
824                 self.network_creator.clean()
825             except Exception as e:
826                 logger.error(
827                     'Unexpected exception cleaning network with message - %s',
828                     e)
829
830         if self.image_creator and not self.image_creator.image_settings.exists:
831             try:
832                 self.image_creator.clean()
833             except Exception as e:
834                 logger.error(
835                     'Unexpected exception cleaning image with message - %s', e)
836
837         super(self.__class__, self).__clean__()
838
839     def test_set_custom_valid_ip_one_subnet(self):
840         """
841         Tests the creation of an OpenStack instance with a single port with a
842         static IP on a network with one subnet.
843         """
844         ip = '10.55.0.101'
845         sub_settings = self.net_config.network_settings.subnet_settings
846         port_settings = PortSettings(
847             name=self.port_1_name,
848             network_name=self.net_config.network_settings.name,
849             ip_addrs=[{'subnet_name': sub_settings[0].name, 'ip': ip}])
850
851         instance_settings = VmInstanceSettings(
852             name=self.vm_inst_name,
853             flavor=self.flavor_creator.flavor_settings.name,
854             port_settings=[port_settings])
855
856         self.inst_creator = OpenStackVmInstance(
857             self.os_creds, instance_settings,
858             self.image_creator.image_settings)
859         self.inst_creator.create(block=True)
860
861         self.assertEqual(ip, self.inst_creator.get_port_ip(
862             self.port_1_name,
863             subnet_name=self.net_config.network_settings.subnet_settings[
864                 0].name))
865
866     def test_set_custom_invalid_ip_one_subnet(self):
867         """
868         Tests the creation of an OpenStack instance with a single port with a
869         static IP on a network with one subnet.
870         """
871         ip = '10.66.0.101'
872         sub_settings = self.net_config.network_settings.subnet_settings
873         port_settings = PortSettings(
874             name=self.port_1_name,
875             network_name=self.net_config.network_settings.name,
876             ip_addrs=[{'subnet_name': sub_settings[0].name, 'ip': ip}])
877
878         instance_settings = VmInstanceSettings(
879             name=self.vm_inst_name,
880             flavor=self.flavor_creator.flavor_settings.name,
881             port_settings=[port_settings])
882
883         self.inst_creator = OpenStackVmInstance(
884             self.os_creds, instance_settings,
885             self.image_creator.image_settings)
886
887         with self.assertRaises(InvalidIpForSubnetClient):
888             self.inst_creator.create()
889
890     def test_set_custom_valid_mac(self):
891         """
892         Tests the creation of an OpenStack instance with a single port where
893         the MAC address is assigned.
894         """
895         mac_addr = '0a:1b:2c:3d:4e:5f'
896         port_settings = PortSettings(
897             name=self.port_1_name,
898             network_name=self.net_config.network_settings.name,
899             mac_address=mac_addr)
900
901         instance_settings = VmInstanceSettings(
902             name=self.vm_inst_name,
903             flavor=self.flavor_creator.flavor_settings.name,
904             port_settings=[port_settings])
905
906         self.inst_creator = OpenStackVmInstance(
907             self.os_creds, instance_settings,
908             self.image_creator.image_settings)
909         self.inst_creator.create(block=True)
910
911         self.assertEqual(mac_addr,
912                          self.inst_creator.get_port_mac(self.port_1_name))
913
914     def test_set_custom_invalid_mac(self):
915         """
916         Tests the creation of an OpenStack instance with a single port where an
917         invalid MAC address value is being
918         assigned. This should raise an Exception
919         """
920         port_settings = PortSettings(
921             name=self.port_1_name,
922             network_name=self.net_config.network_settings.name,
923             mac_address='foo')
924
925         instance_settings = VmInstanceSettings(
926             name=self.vm_inst_name,
927             flavor=self.flavor_creator.flavor_settings.name,
928             port_settings=[port_settings])
929
930         self.inst_creator = OpenStackVmInstance(
931             self.os_creds, instance_settings,
932             self.image_creator.image_settings)
933
934         with self.assertRaises(Exception):
935             self.inst_creator.create()
936
937     def test_set_custom_mac_and_ip(self):
938         """
939         Tests the creation of an OpenStack instance with a single port where
940         the IP and MAC address is assigned.
941         """
942         ip = '10.55.0.101'
943         mac_addr = '0a:1b:2c:3d:4e:5f'
944         sub_settings = self.net_config.network_settings.subnet_settings
945         port_settings = PortSettings(
946             name=self.port_1_name,
947             network_name=self.net_config.network_settings.name,
948             mac_address=mac_addr,
949             ip_addrs=[{'subnet_name': sub_settings[0].name, 'ip': ip}])
950
951         instance_settings = VmInstanceSettings(
952             name=self.vm_inst_name,
953             flavor=self.flavor_creator.flavor_settings.name,
954             port_settings=[port_settings])
955
956         self.inst_creator = OpenStackVmInstance(
957             self.os_creds, instance_settings,
958             self.image_creator.image_settings)
959         self.inst_creator.create(block=True)
960
961         self.assertEqual(ip, self.inst_creator.get_port_ip(
962             self.port_1_name,
963             subnet_name=self.net_config.network_settings.subnet_settings[
964                 0].name))
965         self.assertEqual(mac_addr,
966                          self.inst_creator.get_port_mac(self.port_1_name))
967
968     def test_set_allowed_address_pairs(self):
969         """
970         Tests the creation of an OpenStack instance with a single port where
971         max_allowed_address_pair is set.
972         """
973         ip = '10.55.0.101'
974         mac_addr = '0a:1b:2c:3d:4e:5f'
975         pair = {'ip_address': ip, 'mac_address': mac_addr}
976         port_settings = PortSettings(
977             name=self.port_1_name,
978             network_name=self.net_config.network_settings.name,
979             allowed_address_pairs=[pair])
980
981         instance_settings = VmInstanceSettings(
982             name=self.vm_inst_name,
983             flavor=self.flavor_creator.flavor_settings.name,
984             port_settings=[port_settings])
985
986         self.inst_creator = OpenStackVmInstance(
987             self.os_creds, instance_settings,
988             self.image_creator.image_settings)
989         self.inst_creator.create(block=True)
990
991         port = self.inst_creator.get_port_by_name(port_settings.name)
992         self.assertIsNotNone(port)
993         self.assertIsNotNone(port.allowed_address_pairs)
994         self.assertEqual(1, len(port.allowed_address_pairs))
995         validation_utils.objects_equivalent(pair,
996                                             port.allowed_address_pairs[0])
997
998     def test_set_allowed_address_pairs_bad_mac(self):
999         """
1000         Tests the creation of an OpenStack instance with a single port where
1001         max_allowed_address_pair is set with an invalid MAC address.
1002         """
1003         ip = '10.55.0.101'
1004         mac_addr = 'foo'
1005         pair = {'ip_address': ip, 'mac_address': mac_addr}
1006         pairs = set()
1007         pairs.add((ip, mac_addr))
1008         port_settings = PortSettings(
1009             name=self.port_1_name,
1010             network_name=self.net_config.network_settings.name,
1011             allowed_address_pairs=[pair])
1012
1013         instance_settings = VmInstanceSettings(
1014             name=self.vm_inst_name,
1015             flavor=self.flavor_creator.flavor_settings.name,
1016             port_settings=[port_settings])
1017
1018         self.inst_creator = OpenStackVmInstance(
1019             self.os_creds, instance_settings,
1020             self.image_creator.image_settings)
1021         with self.assertRaises(Exception):
1022             self.inst_creator.create()
1023
1024     def test_set_allowed_address_pairs_bad_ip(self):
1025         """
1026         Tests the creation of an OpenStack instance with a single port where
1027         max_allowed_address_pair is set with an invalid MAC address.
1028         """
1029         ip = 'foo'
1030         mac_addr = '0a:1b:2c:3d:4e:5f'
1031         pair = {'ip_address': ip, 'mac_address': mac_addr}
1032         pairs = set()
1033         pairs.add((ip, mac_addr))
1034         port_settings = PortSettings(
1035             name=self.port_1_name,
1036             network_name=self.net_config.network_settings.name,
1037             allowed_address_pairs=[pair])
1038
1039         instance_settings = VmInstanceSettings(
1040             name=self.vm_inst_name,
1041             flavor=self.flavor_creator.flavor_settings.name,
1042             port_settings=[port_settings])
1043
1044         self.inst_creator = OpenStackVmInstance(
1045             self.os_creds, instance_settings,
1046             self.image_creator.image_settings)
1047         with self.assertRaises(Exception):
1048             self.inst_creator.create()
1049
1050
1051 class CreateInstanceOnComputeHost(OSIntegrationTestCase):
1052     """
1053     Test for the CreateInstance where one VM is deployed to each compute node
1054     """
1055
1056     def setUp(self):
1057         """
1058         Instantiates the CreateImage object that is responsible for downloading
1059         and creating an OS image file within OpenStack
1060         """
1061         super(self.__class__, self).__start__()
1062
1063         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1064         self.vm_inst_name = guid + '-inst'
1065         self.port_base_name = guid + 'port'
1066
1067         # Initialize for tearDown()
1068         self.image_creator = None
1069         self.flavor_creator = None
1070         self.network_creator = None
1071         self.inst_creators = list()
1072
1073         self.priv_net_config = openstack_tests.get_priv_net_config(
1074             net_name=guid + '-priv-net', subnet_name=guid + '-priv-subnet')
1075
1076         os_image_settings = openstack_tests.cirros_image_settings(
1077             name=guid + '-image', image_metadata=self.image_metadata)
1078
1079         try:
1080             # Create Network
1081             self.network_creator = OpenStackNetwork(
1082                 self.admin_os_creds, self.priv_net_config.network_settings)
1083             self.network_creator.create()
1084
1085             # Create Flavor
1086             self.flavor_creator = OpenStackFlavor(
1087                 self.admin_os_creds,
1088                 FlavorSettings(name=guid + '-flavor-name', ram=512, disk=1,
1089                                vcpus=1, metadata=self.flavor_metadata))
1090             self.flavor_creator.create()
1091
1092             # Create Image
1093             self.image_creator = OpenStackImage(self.os_creds,
1094                                                 os_image_settings)
1095             self.image_creator.create()
1096
1097         except Exception as e:
1098             self.tearDown()
1099             raise e
1100
1101     def tearDown(self):
1102         """
1103         Cleans the created object
1104         """
1105         for inst_creator in self.inst_creators:
1106             try:
1107                 inst_creator.clean()
1108             except Exception as e:
1109                 logger.error(
1110                     'Unexpected exception cleaning VM instance with message '
1111                     '- %s', e)
1112
1113         if self.flavor_creator:
1114             try:
1115                 self.flavor_creator.clean()
1116             except Exception as e:
1117                 logger.error(
1118                     'Unexpected exception cleaning flavor with message - %s',
1119                     e)
1120
1121         if self.network_creator:
1122             try:
1123                 self.network_creator.clean()
1124             except Exception as e:
1125                 logger.error(
1126                     'Unexpected exception cleaning network with message - %s',
1127                     e)
1128
1129         if self.image_creator and not self.image_creator.image_settings.exists:
1130             try:
1131                 self.image_creator.clean()
1132             except Exception as e:
1133                 logger.error(
1134                     'Unexpected exception cleaning image with message - %s', e)
1135
1136         super(self.__class__, self).__clean__()
1137
1138     def test_deploy_vm_to_each_compute_node(self):
1139         """
1140         Tests the creation of OpenStack VM instances to each compute node.
1141         """
1142         from snaps.openstack.utils import nova_utils
1143         nova = nova_utils.nova_client(self.admin_os_creds)
1144         zones = nova_utils.get_nova_availability_zones(nova)
1145
1146         # Create Instance on each server/zone
1147         ctr = 0
1148         for zone in zones:
1149             inst_name = self.vm_inst_name + '-' + zone
1150             ctr += 1
1151             port_settings = PortSettings(
1152                 name=self.port_base_name + '-' + str(ctr),
1153                 network_name=self.priv_net_config.network_settings.name)
1154
1155             instance_settings = VmInstanceSettings(
1156                 name=inst_name,
1157                 flavor=self.flavor_creator.flavor_settings.name,
1158                 availability_zone=zone,
1159                 port_settings=[port_settings])
1160             inst_creator = OpenStackVmInstance(
1161                 self.admin_os_creds, instance_settings,
1162                 self.image_creator.image_settings)
1163             self.inst_creators.append(inst_creator)
1164             inst_creator.create()
1165
1166         # Validate instances to ensure they've been deployed to the correct
1167         # server
1168         index = 0
1169         for zone in zones:
1170             creator = self.inst_creators[index]
1171             self.assertTrue(creator.vm_active(block=True))
1172             info = creator.get_vm_info()
1173             deployed_zone = info['OS-EXT-AZ:availability_zone']
1174             deployed_host = info['OS-EXT-SRV-ATTR:host']
1175             self.assertEqual(zone, deployed_zone + ':' + deployed_host)
1176             index += 1
1177
1178
1179 class CreateInstancePubPrivNetTests(OSIntegrationTestCase):
1180     """
1181     Test for the CreateInstance class with two NIC/Ports, eth0 with floating IP
1182     and eth1 w/o.
1183     These tests require a Centos image
1184     """
1185
1186     def setUp(self):
1187         """
1188         Instantiates the CreateImage object that is responsible for downloading
1189         and creating an OS image file within OpenStack
1190         """
1191         super(self.__class__, self).__start__()
1192
1193         self.nova = nova_utils.nova_client(self.os_creds)
1194
1195         # Initialize for tearDown()
1196         self.image_creator = None
1197         self.network_creators = list()
1198         self.router_creators = list()
1199         self.flavor_creator = None
1200         self.keypair_creator = None
1201         self.sec_grp_creator = None
1202         self.inst_creator = None
1203
1204         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1205         self.keypair_priv_filepath = 'tmp/' + self.guid
1206         self.keypair_pub_filepath = self.keypair_priv_filepath + '.pub'
1207         self.keypair_name = self.guid + '-kp'
1208         self.vm_inst_name = self.guid + '-inst'
1209         self.port_1_name = self.guid + '-port-1'
1210         self.port_2_name = self.guid + '-port-2'
1211         self.floating_ip_name = self.guid + 'fip1'
1212         self.priv_net_config = openstack_tests.get_priv_net_config(
1213             net_name=self.guid + '-priv-net',
1214             subnet_name=self.guid + '-priv-subnet',
1215             router_name=self.guid + '-priv-router',
1216             external_net=self.ext_net_name)
1217         self.pub_net_config = openstack_tests.get_pub_net_config(
1218             net_name=self.guid + '-pub-net',
1219             subnet_name=self.guid + '-pub-subnet',
1220             router_name=self.guid + '-pub-router',
1221             external_net=self.ext_net_name)
1222
1223         image_name = self.__class__.__name__ + '-' + str(uuid.uuid4())
1224         os_image_settings = openstack_tests.centos_image_settings(
1225             name=image_name, image_metadata=self.image_metadata)
1226
1227         try:
1228             # Create Image
1229             self.image_creator = OpenStackImage(self.os_creds,
1230                                                 os_image_settings)
1231             self.image_creator.create()
1232
1233             # First network is public
1234             self.network_creators.append(OpenStackNetwork(
1235                 self.os_creds, self.pub_net_config.network_settings))
1236             # Second network is private
1237             self.network_creators.append(OpenStackNetwork(
1238                 self.os_creds, self.priv_net_config.network_settings))
1239             for network_creator in self.network_creators:
1240                 network_creator.create()
1241
1242             self.router_creators.append(OpenStackRouter(
1243                 self.os_creds, self.pub_net_config.router_settings))
1244             self.router_creators.append(OpenStackRouter(
1245                 self.os_creds, self.priv_net_config.router_settings))
1246
1247             # Create Routers
1248             for router_creator in self.router_creators:
1249                 router_creator.create()
1250
1251             # Create Flavor
1252             self.flavor_creator = OpenStackFlavor(
1253                 self.admin_os_creds,
1254                 FlavorSettings(name=self.guid + '-flavor-name', ram=512,
1255                                disk=10, vcpus=2,
1256                                metadata=self.flavor_metadata))
1257             self.flavor_creator.create()
1258
1259             # Create Keypair
1260             self.keypair_creator = OpenStackKeypair(
1261                 self.os_creds, KeypairSettings(
1262                     name=self.keypair_name,
1263                     public_filepath=self.keypair_pub_filepath,
1264                     private_filepath=self.keypair_priv_filepath))
1265             self.keypair_creator.create()
1266
1267             sec_grp_name = self.guid + '-sec-grp'
1268             rule1 = SecurityGroupRuleSettings(sec_grp_name=sec_grp_name,
1269                                               direction=Direction.ingress,
1270                                               protocol=Protocol.icmp)
1271             rule2 = SecurityGroupRuleSettings(sec_grp_name=sec_grp_name,
1272                                               direction=Direction.ingress,
1273                                               protocol=Protocol.tcp,
1274                                               port_range_min=22,
1275                                               port_range_max=22)
1276             self.sec_grp_creator = OpenStackSecurityGroup(
1277                 self.os_creds,
1278                 SecurityGroupSettings(name=sec_grp_name,
1279                                       rule_settings=[rule1, rule2]))
1280             self.sec_grp_creator.create()
1281         except:
1282             self.tearDown()
1283             raise
1284
1285     def tearDown(self):
1286         """
1287         Cleans the created objects
1288         """
1289         if self.inst_creator:
1290             try:
1291                 self.inst_creator.clean()
1292             except Exception as e:
1293                 logger.error(
1294                     'Unexpected exception cleaning VM instance with message '
1295                     '- %s', e)
1296
1297         if self.keypair_creator:
1298             try:
1299                 self.keypair_creator.clean()
1300             except Exception as e:
1301                 logger.error(
1302                     'Unexpected exception cleaning keypair with message - %s',
1303                     e)
1304
1305         if os.path.isfile(self.keypair_pub_filepath):
1306             os.remove(self.keypair_pub_filepath)
1307
1308         if os.path.isfile(self.keypair_priv_filepath):
1309             os.remove(self.keypair_priv_filepath)
1310
1311         if self.flavor_creator:
1312             try:
1313                 self.flavor_creator.clean()
1314             except Exception as e:
1315                 logger.error(
1316                     'Unexpected exception cleaning flavor with message - %s',
1317                     e)
1318
1319         for router_creator in self.router_creators:
1320             try:
1321                 router_creator.clean()
1322             except Exception as e:
1323                 logger.error(
1324                     'Unexpected exception cleaning router with message - %s',
1325                     e)
1326
1327         for network_creator in self.network_creators:
1328             try:
1329                 network_creator.clean()
1330             except Exception as e:
1331                 logger.error(
1332                     'Unexpected exception cleaning network with message - %s',
1333                     e)
1334
1335         if self.sec_grp_creator:
1336             try:
1337                 self.sec_grp_creator.clean()
1338             except Exception as e:
1339                 logger.error(
1340                     'Unexpected exception cleaning security group with message'
1341                     ' - %s', e)
1342
1343         if self.image_creator and not self.image_creator.image_settings.exists:
1344             try:
1345                 self.image_creator.clean()
1346             except Exception as e:
1347                 logger.error(
1348                     'Unexpected exception cleaning image with message - %s', e)
1349
1350         super(self.__class__, self).__clean__()
1351
1352     def test_dual_ports_dhcp(self):
1353         """
1354         Tests the creation of an OpenStack instance with a dual ports/NICs with
1355         a DHCP assigned IP.
1356         NOTE: This test and any others that call ansible will most likely fail
1357         unless you do one of two things:
1358         1. Have a ~/.ansible.cfg (or alternate means) to
1359            set host_key_checking = False
1360         2. Set the following environment variable in your executing shell:
1361            ANSIBLE_HOST_KEY_CHECKING=False
1362         Should this not be performed, the creation of the host ssh key will
1363         cause your ansible calls to fail.
1364         """
1365         # Create ports/NICs for instance
1366         ports_settings = []
1367         ctr = 1
1368         for network_creator in self.network_creators:
1369             ports_settings.append(PortSettings(
1370                 name=self.guid + '-port-' + str(ctr),
1371                 network_name=network_creator.network_settings.name))
1372             ctr += 1
1373
1374         # Create instance
1375         instance_settings = VmInstanceSettings(
1376             name=self.vm_inst_name,
1377             flavor=self.flavor_creator.flavor_settings.name,
1378             port_settings=ports_settings,
1379             floating_ip_settings=[FloatingIpSettings(
1380                 name=self.floating_ip_name, port_name=self.port_1_name,
1381                 router_name=self.pub_net_config.router_settings.name)])
1382
1383         self.inst_creator = OpenStackVmInstance(
1384             self.os_creds, instance_settings,
1385             self.image_creator.image_settings,
1386             keypair_settings=self.keypair_creator.keypair_settings)
1387
1388         vm_inst = self.inst_creator.create(block=True)
1389
1390         self.assertEqual(vm_inst, self.inst_creator.get_vm_inst())
1391
1392         # Effectively blocks until VM has been properly activated
1393         self.assertTrue(self.inst_creator.vm_active(block=True))
1394
1395         ip = self.inst_creator.get_port_ip(ports_settings[0].name)
1396         self.assertTrue(check_dhcp_lease(self.inst_creator, ip))
1397
1398         # Add security group to VM
1399         self.inst_creator.add_security_group(
1400             self.sec_grp_creator.get_security_group())
1401
1402         # Effectively blocks until VM's ssh port has been opened
1403         self.assertTrue(self.inst_creator.vm_ssh_active(block=True))
1404
1405         self.assertEqual(0, self.inst_creator.config_nics())
1406
1407
1408 class InstanceSecurityGroupTests(OSIntegrationTestCase):
1409     """
1410     Tests that include, add, and remove security groups from VM instances
1411     """
1412
1413     def setUp(self):
1414         """
1415         Instantiates the CreateImage object that is responsible for downloading
1416         and creating an OS image file within OpenStack
1417         """
1418         super(self.__class__, self).__start__()
1419
1420         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1421         self.vm_inst_name = self.guid + '-inst'
1422         self.nova = nova_utils.nova_client(self.os_creds)
1423         os_image_settings = openstack_tests.cirros_image_settings(
1424             name=self.guid + '-image', image_metadata=self.image_metadata)
1425
1426         self.vm_inst_name = self.guid + '-inst'
1427         self.port_1_name = self.guid + 'port-1'
1428         self.port_2_name = self.guid + 'port-2'
1429         self.floating_ip_name = self.guid + 'fip1'
1430
1431         net_config = openstack_tests.get_priv_net_config(
1432             net_name=self.guid + '-pub-net',
1433             subnet_name=self.guid + '-pub-subnet',
1434             router_name=self.guid + '-pub-router',
1435             external_net=self.ext_net_name)
1436
1437         # Initialize for tearDown()
1438         self.image_creator = None
1439         self.flavor_creator = None
1440         self.network_creator = None
1441         self.router_creator = None
1442         self.inst_creator = None
1443         self.sec_grp_creators = list()
1444
1445         try:
1446             # Create Image
1447             self.image_creator = OpenStackImage(self.os_creds,
1448                                                 os_image_settings)
1449             self.image_creator.create()
1450
1451             # Create Network
1452             self.network_creator = OpenStackNetwork(
1453                 self.os_creds, net_config.network_settings)
1454             self.network_creator.create()
1455
1456             # Create Flavor
1457             self.flavor_creator = OpenStackFlavor(
1458                 self.admin_os_creds,
1459                 FlavorSettings(name=self.guid + '-flavor-name', ram=128,
1460                                disk=10, vcpus=2,
1461                                metadata=self.flavor_metadata))
1462             self.flavor_creator.create()
1463
1464             self.port_settings = PortSettings(
1465                 name=self.guid + '-port',
1466                 network_name=net_config.network_settings.name)
1467         except Exception as e:
1468             self.tearDown()
1469             raise e
1470
1471     def tearDown(self):
1472         """
1473         Cleans the created object
1474         """
1475         if self.inst_creator:
1476             try:
1477                 self.inst_creator.clean()
1478             except Exception as e:
1479                 logger.error(
1480                     'Unexpected exception cleaning VM instance with message -'
1481                     ' %s', e)
1482
1483         for sec_grp_creator in self.sec_grp_creators:
1484             try:
1485                 sec_grp_creator.clean()
1486             except Exception as e:
1487                 logger.error(
1488                     'Unexpected exception cleaning security group with message'
1489                     ' - %s', e)
1490
1491         if self.flavor_creator:
1492             try:
1493                 self.flavor_creator.clean()
1494             except Exception as e:
1495                 logger.error(
1496                     'Unexpected exception cleaning flavor with message - %s',
1497                     e)
1498
1499         if self.network_creator:
1500             try:
1501                 self.network_creator.clean()
1502             except Exception as e:
1503                 logger.error(
1504                     'Unexpected exception cleaning network with message - %s',
1505                     e)
1506
1507         if self.image_creator and not self.image_creator.image_settings.exists:
1508             try:
1509                 self.image_creator.clean()
1510             except Exception as e:
1511                 logger.error(
1512                     'Unexpected exception cleaning image with message - %s', e)
1513
1514         super(self.__class__, self).__clean__()
1515
1516     def test_add_security_group(self):
1517         """
1518         Tests the addition of a security group created after the instance.
1519         """
1520         # Create instance
1521         instance_settings = VmInstanceSettings(
1522             name=self.vm_inst_name,
1523             flavor=self.flavor_creator.flavor_settings.name,
1524             port_settings=[self.port_settings])
1525         self.inst_creator = OpenStackVmInstance(
1526             self.os_creds, instance_settings,
1527             self.image_creator.image_settings)
1528         vm_inst = self.inst_creator.create(block=True)
1529         self.assertIsNotNone(vm_inst)
1530
1531         # Create security group object to add to instance
1532         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name',
1533                                                  description='hello group')
1534         sec_grp_creator = OpenStackSecurityGroup(self.os_creds,
1535                                                  sec_grp_settings)
1536         sec_grp = sec_grp_creator.create()
1537         self.sec_grp_creators.append(sec_grp_creator)
1538
1539         # Check that group has not been added
1540         self.assertFalse(inst_has_sec_grp(
1541             self.nova, self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1542
1543         # Add security group to instance after activated
1544         self.inst_creator.add_security_group(sec_grp)
1545
1546         # Validate that security group has been added
1547         self.assertTrue(inst_has_sec_grp(
1548             self.nova, self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1549
1550     def test_add_invalid_security_group(self):
1551         """
1552         Tests the addition of a security group that no longer exists.
1553         """
1554         # Create instance
1555         instance_settings = VmInstanceSettings(
1556             name=self.vm_inst_name,
1557             flavor=self.flavor_creator.flavor_settings.name,
1558             port_settings=[self.port_settings])
1559         self.inst_creator = OpenStackVmInstance(
1560             self.os_creds, instance_settings,
1561             self.image_creator.image_settings)
1562         vm_inst = self.inst_creator.create(block=True)
1563         self.assertIsNotNone(vm_inst)
1564
1565         # Create security group object to add to instance
1566         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name',
1567                                                  description='hello group')
1568         sec_grp_creator = OpenStackSecurityGroup(self.os_creds,
1569                                                  sec_grp_settings)
1570         sec_grp = sec_grp_creator.create()
1571         sec_grp_creator.clean()
1572         self.sec_grp_creators.append(sec_grp_creator)
1573
1574         # Check that group has not been added
1575         self.assertFalse(inst_has_sec_grp(
1576             self.nova, self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1577
1578         # Add security group to instance after activated
1579         self.assertFalse(self.inst_creator.add_security_group(sec_grp))
1580
1581         # Validate that security group has been added
1582         self.assertFalse(inst_has_sec_grp(
1583             self.nova, self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1584
1585     def test_remove_security_group(self):
1586         """
1587         Tests the removal of a security group created before and added to the
1588         instance.
1589         """
1590         # Create security group object to add to instance
1591         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name',
1592                                                  description='hello group')
1593         sec_grp_creator = OpenStackSecurityGroup(self.os_creds,
1594                                                  sec_grp_settings)
1595         sec_grp = sec_grp_creator.create()
1596         self.sec_grp_creators.append(sec_grp_creator)
1597
1598         # Create instance
1599         instance_settings = VmInstanceSettings(
1600             name=self.vm_inst_name,
1601             flavor=self.flavor_creator.flavor_settings.name,
1602             security_group_names=[sec_grp_settings.name],
1603             port_settings=[self.port_settings])
1604         self.inst_creator = OpenStackVmInstance(
1605             self.os_creds, instance_settings,
1606             self.image_creator.image_settings)
1607         vm_inst = self.inst_creator.create(block=True)
1608         self.assertIsNotNone(vm_inst)
1609
1610         # Check that group has been added
1611         self.assertTrue(inst_has_sec_grp(
1612             self.nova, vm_inst, sec_grp_settings.name))
1613
1614         # Add security group to instance after activated
1615         self.assertTrue(self.inst_creator.remove_security_group(sec_grp))
1616
1617         # Validate that security group has been added
1618         self.assertFalse(inst_has_sec_grp(
1619             self.nova, self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1620
1621     def test_remove_security_group_never_added(self):
1622         """
1623         Tests the removal of a security group that was never added in the first
1624         place.
1625         """
1626         # Create security group object to add to instance
1627         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name',
1628                                                  description='hello group')
1629         sec_grp_creator = OpenStackSecurityGroup(self.os_creds,
1630                                                  sec_grp_settings)
1631         sec_grp = sec_grp_creator.create()
1632         self.sec_grp_creators.append(sec_grp_creator)
1633
1634         # Create instance
1635         instance_settings = VmInstanceSettings(
1636             name=self.vm_inst_name,
1637             flavor=self.flavor_creator.flavor_settings.name,
1638             port_settings=[self.port_settings])
1639         self.inst_creator = OpenStackVmInstance(
1640             self.os_creds, instance_settings,
1641             self.image_creator.image_settings)
1642         vm_inst = self.inst_creator.create(block=True)
1643         self.assertIsNotNone(vm_inst)
1644
1645         # Check that group has been added
1646         self.assertFalse(inst_has_sec_grp(
1647             self.nova, self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1648
1649         # Add security group to instance after activated
1650         self.assertFalse(self.inst_creator.remove_security_group(sec_grp))
1651
1652         # Validate that security group has been added
1653         self.assertFalse(inst_has_sec_grp(
1654             self.nova, self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1655
1656     def test_add_same_security_group(self):
1657         """
1658         Tests the addition of a security group created before add added to the
1659         instance.
1660         """
1661         # Create security group object to add to instance
1662         sec_grp_settings = SecurityGroupSettings(name=self.guid + '-name',
1663                                                  description='hello group')
1664         sec_grp_creator = OpenStackSecurityGroup(self.os_creds,
1665                                                  sec_grp_settings)
1666         sec_grp = sec_grp_creator.create()
1667         self.sec_grp_creators.append(sec_grp_creator)
1668
1669         # Create instance
1670         instance_settings = VmInstanceSettings(
1671             name=self.vm_inst_name,
1672             flavor=self.flavor_creator.flavor_settings.name,
1673             security_group_names=[sec_grp_settings.name],
1674             port_settings=[self.port_settings])
1675         self.inst_creator = OpenStackVmInstance(
1676             self.os_creds, instance_settings,
1677             self.image_creator.image_settings)
1678         vm_inst = self.inst_creator.create(block=True)
1679         self.assertIsNotNone(vm_inst)
1680
1681         # Check that group has been added
1682         self.assertTrue(inst_has_sec_grp(
1683             self.nova, self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1684
1685         # Add security group to instance after activated
1686         self.assertTrue(self.inst_creator.add_security_group(sec_grp))
1687
1688         # Validate that security group has been added
1689         self.assertTrue(inst_has_sec_grp(
1690             self.nova, self.inst_creator.get_vm_inst(), sec_grp_settings.name))
1691
1692
1693 def inst_has_sec_grp(nova, vm_inst, sec_grp_name):
1694     """
1695     Returns true if instance has a security group of a given name
1696     :param nova: the nova client
1697     :param vm_inst: the VmInst domain object
1698     :param sec_grp_name: the name of the security group to validate
1699     :return: T/F
1700     """
1701     sec_grp_names = nova_utils.get_server_security_group_names(nova, vm_inst)
1702     for name in sec_grp_names:
1703         if sec_grp_name == name:
1704             return True
1705     return False
1706
1707
1708 def validate_ssh_client(instance_creator):
1709     """
1710     Returns True if instance_creator returns an SSH client that is valid
1711     :param instance_creator: the object responsible for creating the VM
1712                              instance
1713     :return: T/F
1714     """
1715     ssh_active = instance_creator.vm_ssh_active(block=True)
1716
1717     if ssh_active:
1718         ssh_client = instance_creator.ssh_client()
1719         if ssh_client:
1720             out = ssh_client.exec_command('pwd')[1]
1721         else:
1722             return False
1723
1724         channel = out.channel
1725         in_buffer = channel.in_buffer
1726         pwd_out = in_buffer.read(1024)
1727         if not pwd_out or len(pwd_out) < 10:
1728             return False
1729         return True
1730
1731     return False
1732
1733
1734 class CreateInstanceFromThreePartImage(OSIntegrationTestCase):
1735     """
1736     Test for the CreateInstance class for creating an image from a 3-part image
1737     """
1738
1739     def setUp(self):
1740         """
1741         Instantiates the CreateImage object that is responsible for downloading
1742         and creating an OS image file within OpenStack
1743         """
1744         super(self.__class__, self).__start__()
1745
1746         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1747         self.image_name = guid
1748         self.vm_inst_name = guid + '-inst'
1749         self.nova = nova_utils.nova_client(self.os_creds)
1750
1751         net_config = openstack_tests.get_priv_net_config(
1752             net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
1753             router_name=guid + '-pub-router', external_net=self.ext_net_name)
1754
1755         # Initialize for tearDown()
1756         self.image_creator = None
1757         self.network_creator = None
1758         self.flavor_creator = None
1759         self.inst_creator = None
1760
1761         try:
1762             if self.image_metadata and 'disk_file' in self.image_metadata:
1763                 metadata = self.image_metadata
1764             elif self.image_metadata and 'cirros' in self.image_metadata \
1765                     and 'disk_file' in self.image_metadata['cirros']:
1766                 metadata = self.image_metadata['cirros']
1767             else:
1768                 metadata = {
1769                     'disk_url': openstack_tests.CIRROS_DEFAULT_IMAGE_URL,
1770                     'kernel_url':
1771                         openstack_tests.CIRROS_DEFAULT_KERNEL_IMAGE_URL,
1772                     'ramdisk_url':
1773                         openstack_tests.CIRROS_DEFAULT_RAMDISK_IMAGE_URL}
1774
1775             image_settings = openstack_tests.cirros_image_settings(
1776                 name=self.image_name,
1777                 image_metadata=metadata)
1778
1779             if not image_settings.ramdisk_image_settings or not \
1780                     image_settings.kernel_image_settings:
1781                 logger.warn(
1782                     '3 Part image will not be tested. Image metadata has '
1783                     'overridden this functionality')
1784
1785             self.image_creator = OpenStackImage(self.os_creds, image_settings)
1786             self.image_creator.create()
1787
1788             # Create Flavor
1789             self.flavor_creator = OpenStackFlavor(
1790                 self.admin_os_creds,
1791                 FlavorSettings(name=guid + '-flavor-name', ram=128, disk=10,
1792                                vcpus=2, metadata=self.flavor_metadata))
1793             self.flavor_creator.create()
1794
1795             # Create Network
1796             self.network_creator = OpenStackNetwork(
1797                 self.os_creds, net_config.network_settings)
1798             self.network_creator.create()
1799
1800             self.port_settings = PortSettings(
1801                 name=guid + '-port',
1802                 network_name=net_config.network_settings.name)
1803         except Exception as e:
1804             self.tearDown()
1805             raise e
1806
1807     def tearDown(self):
1808         """
1809         Cleans the created object
1810         """
1811         if self.inst_creator:
1812             try:
1813                 self.inst_creator.clean()
1814             except Exception as e:
1815                 logger.error(
1816                     'Unexpected exception cleaning VM instance with message -'
1817                     ' %s', e)
1818
1819         if self.flavor_creator:
1820             try:
1821                 self.flavor_creator.clean()
1822             except Exception as e:
1823                 logger.error(
1824                     'Unexpected exception cleaning flavor with message - %s',
1825                     e)
1826
1827         if self.network_creator:
1828             try:
1829                 self.network_creator.clean()
1830             except Exception as e:
1831                 logger.error(
1832                     'Unexpected exception cleaning network with message - %s',
1833                     e)
1834
1835         if self.image_creator and not self.image_creator.image_settings.exists:
1836             try:
1837                 self.image_creator.clean()
1838             except Exception as e:
1839                 logger.error(
1840                     'Unexpected exception cleaning image with message - %s', e)
1841
1842         super(self.__class__, self).__clean__()
1843
1844     def test_create_instance_from_three_part_image(self):
1845         """
1846         Tests the creation of an OpenStack instance from a 3-part image.
1847         """
1848         instance_settings = VmInstanceSettings(
1849             name=self.vm_inst_name,
1850             flavor=self.flavor_creator.flavor_settings.name,
1851             port_settings=[self.port_settings])
1852
1853         # The last created image is the main image from which we create the
1854         # instance
1855         self.inst_creator = OpenStackVmInstance(
1856             self.os_creds, instance_settings,
1857             self.image_creator.image_settings)
1858
1859         vm_inst = self.inst_creator.create()
1860         self.assertIsNotNone(vm_inst)
1861         self.assertTrue(self.inst_creator.vm_active(block=True))
1862
1863
1864 class CreateInstanceMockOfflineTests(OSComponentTestCase):
1865     """
1866     Tests the custom image_metadata that can be set by clients for handling
1867     images differently than the default behavior of the existing tests
1868     primarily for offline testing
1869     """
1870
1871     def setUp(self):
1872         """
1873         Instantiates the CreateImage object that is responsible for downloading
1874         and creating an OS image file within OpenStack
1875         """
1876         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1877
1878         self.tmpDir = 'tmp/' + str(self.guid)
1879         if not os.path.exists(self.tmpDir):
1880             os.makedirs(self.tmpDir)
1881
1882         self.image_name = self.guid + '-image'
1883         self.vm_inst_name = self.guid + '-inst'
1884         self.port_1_name = self.guid + 'port-1'
1885
1886         # Initialize for tearDown()
1887         self.image_creator = None
1888         self.network_creator = None
1889         self.flavor_creator = None
1890         self.inst_creator = None
1891
1892         self.priv_net_config = openstack_tests.get_priv_net_config(
1893             net_name=self.guid + '-priv-net',
1894             subnet_name=self.guid + '-priv-subnet')
1895         self.port_settings = PortSettings(
1896             name=self.port_1_name,
1897             network_name=self.priv_net_config.network_settings.name)
1898
1899         try:
1900             # Download image file
1901             self.image_file = file_utils.download(
1902                 openstack_tests.CIRROS_DEFAULT_IMAGE_URL, self.tmpDir)
1903
1904             # Create Network
1905             self.network_creator = OpenStackNetwork(
1906                 self.os_creds, self.priv_net_config.network_settings)
1907             self.network_creator.create()
1908
1909             # Create Flavor
1910             self.flavor_creator = OpenStackFlavor(
1911                 self.os_creds,
1912                 FlavorSettings(
1913                     name=self.guid + '-flavor-name', ram=128, disk=10,
1914                     vcpus=1))
1915             self.flavor_creator.create()
1916         except Exception as e:
1917             self.tearDown()
1918             raise e
1919
1920     def tearDown(self):
1921         """
1922         Cleans the created object
1923         """
1924         if self.inst_creator:
1925             try:
1926                 self.inst_creator.clean()
1927             except Exception as e:
1928                 logger.error(
1929                     'Unexpected exception cleaning VM instance with message - '
1930                     '%s', e)
1931
1932         if self.network_creator:
1933             try:
1934                 self.network_creator.clean()
1935             except Exception as e:
1936                 logger.error(
1937                     'Unexpected exception cleaning network with message - %s',
1938                     e)
1939
1940         if self.flavor_creator:
1941             try:
1942                 self.flavor_creator.clean()
1943             except Exception as e:
1944                 logger.error(
1945                     'Unexpected exception cleaning flavor with message - %s',
1946                     e)
1947
1948         if self.image_creator:
1949             try:
1950                 self.image_creator.clean()
1951             except Exception as e:
1952                 logger.error(
1953                     'Unexpected exception cleaning image with message - %s', e)
1954
1955         if os.path.exists(self.tmpDir) and os.path.isdir(self.tmpDir):
1956             shutil.rmtree(self.tmpDir)
1957
1958     def test_inst_from_file_image_simple_flat(self):
1959         """
1960         Creates a VM instance from a locally sourced file image using simply
1961         the 'disk_file' attribute vs. using the 'config' option which
1962         completely overrides all image settings
1963         :return: 
1964         """
1965         metadata = {'disk_file': self.image_file.name}
1966
1967         os_image_settings = openstack_tests.cirros_image_settings(
1968             name=self.image_name, image_metadata=metadata)
1969         self.assertEqual(self.image_file.name, os_image_settings.image_file)
1970         self.assertEqual(openstack_tests.CIRROS_USER,
1971                          os_image_settings.image_user)
1972         self.assertIsNone(os_image_settings.url)
1973         self.assertFalse(os_image_settings.exists)
1974         self.assertEqual(openstack_tests.DEFAULT_IMAGE_FORMAT,
1975                          os_image_settings.format)
1976
1977         self.assertIsNone(os_image_settings.kernel_image_settings)
1978         self.assertIsNone(os_image_settings.ramdisk_image_settings)
1979
1980         self.image_creator = OpenStackImage(self.os_creds, os_image_settings)
1981         self.image_creator.create()
1982
1983         instance_settings = VmInstanceSettings(
1984             name=self.vm_inst_name,
1985             flavor=self.flavor_creator.flavor_settings.name,
1986             port_settings=[self.port_settings])
1987         self.inst_creator = OpenStackVmInstance(
1988             self.os_creds, instance_settings,
1989             self.image_creator.image_settings)
1990         self.inst_creator.create()
1991
1992         self.assertTrue(self.inst_creator.vm_active(block=True))
1993
1994     def test_inst_from_file_image_simple_nested(self):
1995         """
1996         Creates a VM instance from a locally sourced file image using simply
1997         the 'disk_file' attribute under 'cirros' vs. using the 'config' option
1998         which completely overrides all image settings
1999         :return: 
2000         """
2001         metadata = {'cirros': {'disk_file': self.image_file.name}}
2002
2003         os_image_settings = openstack_tests.cirros_image_settings(
2004             name=self.image_name, image_metadata=metadata)
2005         self.assertEqual(self.image_file.name, os_image_settings.image_file)
2006         self.assertEqual(openstack_tests.CIRROS_USER,
2007                          os_image_settings.image_user)
2008         self.assertIsNone(os_image_settings.url)
2009         self.assertFalse(os_image_settings.exists)
2010         self.assertEqual(openstack_tests.DEFAULT_IMAGE_FORMAT,
2011                          os_image_settings.format)
2012
2013         self.assertIsNone(os_image_settings.kernel_image_settings)
2014         self.assertIsNone(os_image_settings.ramdisk_image_settings)
2015
2016         self.image_creator = OpenStackImage(self.os_creds, os_image_settings)
2017         self.image_creator.create()
2018
2019         instance_settings = VmInstanceSettings(
2020             name=self.vm_inst_name,
2021             flavor=self.flavor_creator.flavor_settings.name,
2022             port_settings=[self.port_settings])
2023         self.inst_creator = OpenStackVmInstance(
2024             self.os_creds, instance_settings,
2025             self.image_creator.image_settings)
2026         self.inst_creator.create()
2027
2028         self.assertTrue(self.inst_creator.vm_active(block=True))
2029
2030     def test_inst_from_existing(self):
2031         """
2032         Creates a VM instance from a image creator that has been configured to
2033         use an existing image
2034         :return: 
2035         """
2036         os_image_settings = openstack_tests.cirros_image_settings(
2037             name=self.image_name)
2038         self.image_creator = OpenStackImage(self.os_creds, os_image_settings)
2039         self.image_creator.create()
2040
2041         image_settings = self.image_creator.image_settings
2042         test_image_creator = OpenStackImage(
2043             self.os_creds,
2044             ImageSettings(name=image_settings.name,
2045                           image_user=image_settings.image_user,
2046                           exists=True))
2047         test_image_creator.create()
2048         self.assertEqual(self.image_creator.get_image().id,
2049                          test_image_creator.get_image().id)
2050
2051         instance_settings = VmInstanceSettings(
2052             name=self.vm_inst_name,
2053             flavor=self.flavor_creator.flavor_settings.name,
2054             port_settings=[self.port_settings])
2055         self.inst_creator = OpenStackVmInstance(
2056             self.os_creds, instance_settings,
2057             test_image_creator.image_settings)
2058         self.inst_creator.create()
2059
2060         self.assertTrue(self.inst_creator.vm_active(block=True))
2061
2062     def test_inst_from_file_image_complex(self):
2063         """
2064         Creates a VM instance from a locally sourced file image by overriding
2065         the default settings by using a dict() that can be read in by
2066         ImageSettings
2067         :return: 
2068         """
2069
2070         os_image_settings = openstack_tests.cirros_image_settings(
2071             name=self.image_name)
2072         self.image_creator = OpenStackImage(self.os_creds, os_image_settings)
2073         self.image_creator.create()
2074
2075         metadata = {
2076             'cirros': {
2077                 'config': {
2078                     'name': os_image_settings.name,
2079                     'image_user': os_image_settings.image_user,
2080                     'exists': True}}}
2081         test_image_settings = openstack_tests.cirros_image_settings(
2082             image_metadata=metadata)
2083         test_image = OpenStackImage(self.os_creds, test_image_settings)
2084         test_image.create()
2085
2086         instance_settings = VmInstanceSettings(
2087             name=self.vm_inst_name,
2088             flavor=self.flavor_creator.flavor_settings.name,
2089             port_settings=[self.port_settings])
2090         self.inst_creator = OpenStackVmInstance(self.os_creds,
2091                                                 instance_settings,
2092                                                 test_image_settings)
2093         self.inst_creator.create()
2094
2095         self.assertTrue(self.inst_creator.vm_active(block=True))
2096
2097     def test_inst_from_file_3part_image_complex(self):
2098         """
2099         Creates a VM instance from a locally sourced file image by overriding
2100         the default settings by using a dict() that can be read in by
2101         ImageSettings
2102         :return: 
2103         """
2104
2105         kernel_file = file_utils.download(
2106             openstack_tests.CIRROS_DEFAULT_KERNEL_IMAGE_URL, self.tmpDir)
2107         ramdisk_file = file_utils.download(
2108             openstack_tests.CIRROS_DEFAULT_RAMDISK_IMAGE_URL, self.tmpDir)
2109
2110         metadata = {
2111             'cirros': {
2112                 'config': {
2113                     'name': self.image_name,
2114                     'image_user': openstack_tests.CIRROS_USER,
2115                     'image_file': self.image_file.name,
2116                     'format': openstack_tests.DEFAULT_IMAGE_FORMAT,
2117                     'kernel_image_settings': {
2118                         'name': self.image_name + '-kernel',
2119                         'image_user': openstack_tests.CIRROS_USER,
2120                         'image_file': kernel_file.name,
2121                         'format': openstack_tests.DEFAULT_IMAGE_FORMAT},
2122                     'ramdisk_image_settings': {
2123                         'name': self.image_name + '-ramdisk',
2124                         'image_user': openstack_tests.CIRROS_USER,
2125                         'image_file': ramdisk_file.name,
2126                         'format': openstack_tests.DEFAULT_IMAGE_FORMAT}}}}
2127
2128         os_image_settings = openstack_tests.cirros_image_settings(
2129             name=self.image_name, image_metadata=metadata)
2130         self.assertEqual(self.image_name, os_image_settings.name)
2131         self.assertEqual(self.image_file.name, os_image_settings.image_file)
2132         self.assertEqual(openstack_tests.CIRROS_USER,
2133                          os_image_settings.image_user)
2134         self.assertIsNone(os_image_settings.url)
2135         self.assertFalse(os_image_settings.exists)
2136         self.assertEqual(openstack_tests.DEFAULT_IMAGE_FORMAT,
2137                          os_image_settings.format)
2138
2139         self.assertIsNotNone(os_image_settings.kernel_image_settings)
2140         self.assertEqual(self.image_name + '-kernel',
2141                          os_image_settings.kernel_image_settings.name)
2142         self.assertEqual(kernel_file.name,
2143                          os_image_settings.kernel_image_settings.image_file)
2144         self.assertEqual(openstack_tests.CIRROS_USER,
2145                          os_image_settings.kernel_image_settings.image_user)
2146         self.assertIsNone(os_image_settings.kernel_image_settings.url)
2147         self.assertFalse(os_image_settings.kernel_image_settings.exists)
2148         self.assertEqual(openstack_tests.DEFAULT_IMAGE_FORMAT,
2149                          os_image_settings.kernel_image_settings.format)
2150
2151         self.assertIsNotNone(os_image_settings.ramdisk_image_settings)
2152         self.assertEqual(self.image_name + '-ramdisk',
2153                          os_image_settings.ramdisk_image_settings.name)
2154         self.assertEqual(ramdisk_file.name,
2155                          os_image_settings.ramdisk_image_settings.image_file)
2156         self.assertEqual(openstack_tests.CIRROS_USER,
2157                          os_image_settings.ramdisk_image_settings.image_user)
2158         self.assertIsNone(os_image_settings.ramdisk_image_settings.url)
2159         self.assertFalse(os_image_settings.ramdisk_image_settings.exists)
2160         self.assertEqual(openstack_tests.DEFAULT_IMAGE_FORMAT,
2161                          os_image_settings.ramdisk_image_settings.format)
2162
2163         self.image_creator = OpenStackImage(self.os_creds, os_image_settings)
2164         self.image_creator.create()
2165
2166         instance_settings = VmInstanceSettings(
2167             name=self.vm_inst_name,
2168             flavor=self.flavor_creator.flavor_settings.name,
2169             port_settings=[self.port_settings])
2170         self.inst_creator = OpenStackVmInstance(
2171             self.os_creds, instance_settings,
2172             self.image_creator.image_settings)
2173         self.inst_creator.create()
2174
2175         self.assertTrue(self.inst_creator.vm_active(block=True))
2176
2177     def test_inst_from_file_3part_image_simple_flat(self):
2178         """
2179         Creates a VM instance from a 3-part image locally sourced from file
2180         images using simply the 'disk_file', 'kernel_file', and 'ramdisk_file'
2181         attributes vs. using the 'config' option which completely overrides all
2182         image settings
2183         :return: 
2184         """
2185         kernel_file = file_utils.download(
2186             openstack_tests.CIRROS_DEFAULT_KERNEL_IMAGE_URL, self.tmpDir)
2187         ramdisk_file = file_utils.download(
2188             openstack_tests.CIRROS_DEFAULT_RAMDISK_IMAGE_URL, self.tmpDir)
2189
2190         metadata = {'disk_file': self.image_file.name,
2191                     'kernel_file': kernel_file.name,
2192                     'ramdisk_file': ramdisk_file.name}
2193
2194         os_image_settings = openstack_tests.cirros_image_settings(
2195             name=self.image_name, image_metadata=metadata)
2196
2197         self.assertEqual(self.image_name, os_image_settings.name)
2198         self.assertEqual(self.image_file.name, os_image_settings.image_file)
2199         self.assertEqual(openstack_tests.CIRROS_USER,
2200                          os_image_settings.image_user)
2201         self.assertIsNone(os_image_settings.url)
2202         self.assertFalse(os_image_settings.exists)
2203         self.assertEqual(openstack_tests.DEFAULT_IMAGE_FORMAT,
2204                          os_image_settings.format)
2205
2206         self.assertIsNotNone(os_image_settings.kernel_image_settings)
2207         self.assertEqual(self.image_name + '-kernel',
2208                          os_image_settings.kernel_image_settings.name)
2209         self.assertEqual(kernel_file.name,
2210                          os_image_settings.kernel_image_settings.image_file)
2211         self.assertEqual(openstack_tests.CIRROS_USER,
2212                          os_image_settings.kernel_image_settings.image_user)
2213         self.assertIsNone(os_image_settings.kernel_image_settings.url)
2214         self.assertFalse(os_image_settings.kernel_image_settings.exists)
2215         self.assertEqual(openstack_tests.DEFAULT_IMAGE_FORMAT,
2216                          os_image_settings.kernel_image_settings.format)
2217
2218         self.assertIsNotNone(os_image_settings.ramdisk_image_settings)
2219         self.assertEqual(self.image_name + '-ramdisk',
2220                          os_image_settings.ramdisk_image_settings.name)
2221         self.assertEqual(ramdisk_file.name,
2222                          os_image_settings.ramdisk_image_settings.image_file)
2223         self.assertEqual(openstack_tests.CIRROS_USER,
2224                          os_image_settings.ramdisk_image_settings.image_user)
2225         self.assertIsNone(os_image_settings.ramdisk_image_settings.url)
2226         self.assertFalse(os_image_settings.ramdisk_image_settings.exists)
2227         self.assertEqual(openstack_tests.DEFAULT_IMAGE_FORMAT,
2228                          os_image_settings.ramdisk_image_settings.format)
2229
2230         self.image_creator = OpenStackImage(self.os_creds, os_image_settings)
2231         self.image_creator.create()
2232
2233         self.assertIsNotNone(self.image_creator.get_kernel_image())
2234         self.assertIsNotNone(self.image_creator.get_ramdisk_image())
2235
2236         instance_settings = VmInstanceSettings(
2237             name=self.vm_inst_name,
2238             flavor=self.flavor_creator.flavor_settings.name,
2239             port_settings=[self.port_settings])
2240         self.inst_creator = OpenStackVmInstance(
2241             self.os_creds, instance_settings,
2242             self.image_creator.image_settings)
2243         self.inst_creator.create()
2244
2245         self.assertTrue(self.inst_creator.vm_active(block=True))
2246
2247     def test_inst_from_file_3part_image_simple_nested(self):
2248         """
2249         Creates a VM instance from a 3-part image locally sourced from file
2250         images using simply the 'disk_file', 'kernel_file', and 'ramdisk_file'
2251         attributes under 'cirros' vs. using the 'config' option which
2252         completely overrides all image settings
2253         :return: 
2254         """
2255         kernel_file = file_utils.download(
2256             openstack_tests.CIRROS_DEFAULT_KERNEL_IMAGE_URL, self.tmpDir)
2257         ramdisk_file = file_utils.download(
2258             openstack_tests.CIRROS_DEFAULT_RAMDISK_IMAGE_URL, self.tmpDir)
2259
2260         metadata = {'cirros': {'disk_file': self.image_file.name,
2261                                'kernel_file': kernel_file.name,
2262                                'ramdisk_file': ramdisk_file.name}}
2263
2264         os_image_settings = openstack_tests.cirros_image_settings(
2265             name=self.image_name, image_metadata=metadata)
2266
2267         self.assertEqual(self.image_name, os_image_settings.name)
2268         self.assertEqual(self.image_file.name, os_image_settings.image_file)
2269         self.assertEqual(openstack_tests.CIRROS_USER,
2270                          os_image_settings.image_user)
2271         self.assertIsNone(os_image_settings.url)
2272         self.assertFalse(os_image_settings.exists)
2273         self.assertEqual(openstack_tests.DEFAULT_IMAGE_FORMAT,
2274                          os_image_settings.format)
2275
2276         self.assertIsNotNone(os_image_settings.kernel_image_settings)
2277         self.assertEqual(self.image_name + '-kernel',
2278                          os_image_settings.kernel_image_settings.name)
2279         self.assertEqual(kernel_file.name,
2280                          os_image_settings.kernel_image_settings.image_file)
2281         self.assertEqual(openstack_tests.CIRROS_USER,
2282                          os_image_settings.kernel_image_settings.image_user)
2283         self.assertIsNone(os_image_settings.kernel_image_settings.url)
2284         self.assertFalse(os_image_settings.kernel_image_settings.exists)
2285         self.assertEqual(openstack_tests.DEFAULT_IMAGE_FORMAT,
2286                          os_image_settings.kernel_image_settings.format)
2287
2288         self.assertIsNotNone(os_image_settings.ramdisk_image_settings)
2289         self.assertEqual(self.image_name + '-ramdisk',
2290                          os_image_settings.ramdisk_image_settings.name)
2291         self.assertEqual(ramdisk_file.name,
2292                          os_image_settings.ramdisk_image_settings.image_file)
2293         self.assertEqual(openstack_tests.CIRROS_USER,
2294                          os_image_settings.ramdisk_image_settings.image_user)
2295         self.assertIsNone(os_image_settings.ramdisk_image_settings.url)
2296         self.assertFalse(os_image_settings.ramdisk_image_settings.exists)
2297         self.assertEqual(openstack_tests.DEFAULT_IMAGE_FORMAT,
2298                          os_image_settings.ramdisk_image_settings.format)
2299
2300         self.image_creator = OpenStackImage(self.os_creds, os_image_settings)
2301         self.image_creator.create()
2302
2303         self.assertIsNotNone(self.image_creator.get_kernel_image())
2304         self.assertIsNotNone(self.image_creator.get_ramdisk_image())
2305
2306         instance_settings = VmInstanceSettings(
2307             name=self.vm_inst_name,
2308             flavor=self.flavor_creator.flavor_settings.name,
2309             port_settings=[self.port_settings])
2310         self.inst_creator = OpenStackVmInstance(
2311             self.os_creds, instance_settings,
2312             self.image_creator.image_settings)
2313         self.inst_creator.create()
2314
2315         self.assertTrue(self.inst_creator.vm_active(block=True))
2316
2317     def test_inst_from_file_3part_image_existing(self):
2318         """
2319         Creates a VM instance from a 3-part image that is existing
2320         :return: 
2321         """
2322         kernel_file = file_utils.download(
2323             openstack_tests.CIRROS_DEFAULT_KERNEL_IMAGE_URL, self.tmpDir)
2324         ramdisk_file = file_utils.download(
2325             openstack_tests.CIRROS_DEFAULT_RAMDISK_IMAGE_URL, self.tmpDir)
2326
2327         metadata = {'cirros': {'disk_file': self.image_file.name,
2328                                'kernel_file': kernel_file.name,
2329                                'ramdisk_file': ramdisk_file.name}}
2330
2331         os_image_settings = openstack_tests.cirros_image_settings(
2332             name=self.image_name, image_metadata=metadata)
2333         self.image_creator = OpenStackImage(self.os_creds, os_image_settings)
2334         self.image_creator.create()
2335
2336         image_settings = self.image_creator.image_settings
2337         test_image_creator = OpenStackImage(
2338             self.os_creds,
2339             ImageSettings(name=image_settings.name,
2340                           image_user=image_settings.image_user,
2341                           exists=True))
2342         test_image_creator.create()
2343         self.assertEqual(self.image_creator.get_image().id,
2344                          test_image_creator.get_image().id)
2345
2346         instance_settings = VmInstanceSettings(
2347             name=self.vm_inst_name,
2348             flavor=self.flavor_creator.flavor_settings.name,
2349             port_settings=[self.port_settings])
2350         self.inst_creator = OpenStackVmInstance(
2351             self.os_creds, instance_settings,
2352             test_image_creator.image_settings)
2353         self.inst_creator.create()
2354
2355         self.assertTrue(self.inst_creator.vm_active(block=True))
2356
2357
2358 def check_dhcp_lease(inst_creator, ip, timeout=160):
2359     """
2360     Returns true if the expected DHCP lease has been acquired
2361     :param inst_creator: the SNAPS OpenStackVmInstance object
2362     :param ip: the IP address to look for
2363     :param timeout: how long to query for IP address
2364     :return:
2365     """
2366     found = False
2367     start_time = time.time()
2368
2369     logger.info("Looking for IP %s in the console log" % ip)
2370     full_log = ''
2371     while timeout > time.time() - start_time:
2372         output = inst_creator.get_console_output()
2373         full_log = full_log + output
2374         if re.search(ip, output):
2375             logger.info('DHCP lease obtained logged in console')
2376             found = True
2377             break
2378
2379     if not found:
2380         logger.error('Full console output -\n' + full_log)
2381     else:
2382         logger.debug('Full console output -\n' + full_log)
2383
2384     return found